Looking for the perfect mail client

2014-10-24 Thread Sepp Tannhuber
Ian Main  schrieb am 18:02 Freitag, 24.Oktober 2014:

> Interesting, good feedback.  Is it the usage that is difficult or setup?
Installation was not a problem for me although the files ?notmuch.vim? and 
?notmuch.txt? were not found by ?make install? for some reason. So I linked
them into the notmuch-vim directory. After that ?make install? succeeded.
But the main obstacle is that new users must find by trial and error that
they must type ?s? to search, ?t? to tag files and so on. It would be very
useful to list all the key bindings and configuration options.
I still don't know how to compose a new message.

> Well like any other text based client it uses a text dump of a links or such 
> (I
> forget which one).
I think ?elinks --dump?

> We have great support for web browser viewing of the email
> though if that isn't good enough.
Yes, it's 2014. ;-)

> Let me know if you have suggestions on where it's lacking. 
Okay, thank you so far.


[PATCH v3] VIM: Add URI handling

2014-10-24 Thread Tomi Ollila
On Fri, Oct 24 2014, Ian Main  wrote:

This patch does not apply on top of notmuchmail master 
(commit 38240d106139da8).

> This patch adds URI handling to the vim client.  You can now press

Although insignificant, I'll start commenting on all sent patches
(that I look into) which talk like 'This patch adds' -- sure it is patch
when email is sent, but in repository it is not so -- so the commit message
should not mention it (but I do not require changing it).

Anyway, I suspect this change will become applicable after some other
change is committed first -- and IMO this could stay as non-stale patch
provided that SomeOne(TM) informs what is the message that contains
changes (or series those) that is required for this message to apply.

BTW: does the content of this change differ much from v1 at
id:1412281423-22441-1-git-send-email-imain at stemwinder.org
or should I re-check (carefully!) that the changes are still OK.


Tomi


> 'enter' by default and the client will parse the current line and find
> any 'Part's or URIs available for opening.  If there are more than one
> it opens the one under the cursor or else it opens the only one
> available.  It also supports mailto: URI's and will compose a new
> message when activated.
>
> By default xdg-open is used for everything but mailto: which generally
> does the right thing afaict.
>
> Note that this is now dependant on the attachment patch in order to
> make the nice 'enter' behavior work for both.
>
> Ian
> ---
>
> Fix commit message formatting.
>
>  vim/notmuch.txt |  3 ++-
>  vim/notmuch.vim | 76 
> +++--
>  2 files changed, 70 insertions(+), 9 deletions(-)
>
> diff --git a/vim/notmuch.txt b/vim/notmuch.txt
> index 838a904..5d84fde 100644
> --- a/vim/notmuch.txt
> +++ b/vim/notmuch.txt
> @@ -74,7 +74,8 @@ I   Mark as read (-unread)
>  tTag (prompted)
>  e   Extract attachment on the current 'Attachment' line or all
>   attachments if the cursor is elsewhere.
> -v   View attachment on the current 'Attachment' line.
> + View email part on the current 'Part' line, or open URI under cursor
> +or on line.
>  sSearch
>  pSave patches
>  rReply
> diff --git a/vim/notmuch.vim b/vim/notmuch.vim
> index 1466e50..2f76f55 100644
> --- a/vim/notmuch.vim
> +++ b/vim/notmuch.vim
> @@ -12,7 +12,7 @@ let g:notmuch_folders_maps = {
>   \ '':'folders_show_search()',
>   \ 's':  'folders_search_prompt()',
>   \ '=':  'folders_refresh()',
> - \ 'c':  'compose()',
> + \ 'c':  'compose("")',
>   \ }
>  
>  let g:notmuch_search_maps = {
> @@ -25,7 +25,7 @@ let g:notmuch_search_maps = {
>   \ 's':  'search_search_prompt()',
>   \ '=':  'search_refresh()',
>   \ '?':  'search_info()',
> - \ 'c':  'compose()',
> + \ 'c':  'compose("")',
>   \ }
>  
>  let g:notmuch_show_maps = {
> @@ -35,13 +35,13 @@ let g:notmuch_show_maps = {
>   \ 't':  'show_tag("")',
>   \ 'o':  'show_open_msg()',
>   \ 'e':  'show_extract_msg()',
> - \ '':'show_view_attachment()',
> + \ '':'show_view_magic()',
>   \ 's':  'show_save_msg()',
>   \ 'p':  'show_save_patches()',
>   \ 'r':  'show_reply()',
>   \ '?':  'show_info()',
>   \ '':  'show_next_msg()',
> - \ 'c':  'compose()',
> + \ 'c':  'compose("")',
>   \ }
>  
>  let g:notmuch_compose_maps = {
> @@ -63,6 +63,7 @@ let s:notmuch_view_attachment_default = 'xdg-open'
>  let s:notmuch_attachment_tmpdir_default = '~/.notmuch/tmp'
>  let s:notmuch_folders_count_threads_default = 0
>  let s:notmuch_compose_start_insert_default = 1
> +let s:notmuch_open_uri_default = 'xdg-open'
>  
>  function! s:new_file_buffer(type, fname)
>   exec printf('edit %s', a:fname)
> @@ -141,8 +142,8 @@ function! s:show_reply()
>   end
>  endfunction
>  
> -function! s:compose()
> - ruby open_compose
> +function! s:compose(to_email)
> + ruby open_compose(VIM::evaluate('a:to_email'))
>   let b:compose_done = 0
>   call s:set_map(g:notmuch_compose_maps)
>   autocmd BufDelete  call s:on_compose_delete()
> @@ -155,6 +156,22 @@ function! s:show_info()
>   ruby vim_puts get_message.inspect
>  endfunction
>  
> +function! s:show_view_magic()
> + let line = getline(".")
> +
> +ruby << EOF
> + line = VIM::evaluate('line')
> +
> + # Easiest to check for 'Part' types first..
> + match = line.match(/^Part (\d*):/)
> + if match and match.length == 2
> + VIM::command('call s:show_view_attachment()')
> + else
> + VIM::command('call s:show_open_uri()')
> + end
> +EOF
> +endfunction
> +
>  function! s:show_view_attachment()
>   let line = getline(".")
>  ruby << EOF
> @@ -226,6 +243,45 @@ ruby << EOF
>  EOF
>  endfunction
>  
> +function! s:show_open_uri()
> + 

[PATCH v2 3/3] test: Update tests for 'authors_matched' and authors_non_matched'.

2014-10-24 Thread David Edmondson
---
 test/T160-json.sh| 9 +
 test/T170-sexp.sh| 4 ++--
 test/T470-missing-headers.sh | 8 
 3 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/test/T160-json.sh b/test/T160-json.sh
index c1cf649..0a8df18 100755
--- a/test/T160-json.sh
+++ b/test/T160-json.sh
@@ -25,6 +25,10 @@ test_expect_equal_json "$output" "[{\"thread\": \"XXX\",
  \"matched\": 1,
  \"total\": 1,
  \"authors\": \"Notmuch Test Suite\",
+ \"authors_matched\": [
+ \"Notmuch Test Suite\"
+ ],
+ \"authors_non_matched\": [],
  \"subject\": \"json-search-subject\",
  \"query\": [\"id:$gen_msg_id\", null],
  \"tags\": [\"inbox\",
@@ -59,6 +63,11 @@ test_expect_equal_json "$output" "[{\"thread\": \"XXX\",
  \"matched\": 1,
  \"total\": 1,
  \"authors\": \"Notmuch Test Suite\",
+ \"authors\": \"Notmuch Test Suite\",
+ \"authors_matched\": [
+ \"Notmuch Test Suite\"
+ ],
+ \"authors_non_matched\": [],
  \"subject\": \"json-search-utf8-body-s?bj?ct\",
  \"query\": [\"id:$gen_msg_id\", null],
  \"tags\": [\"inbox\",
diff --git a/test/T170-sexp.sh b/test/T170-sexp.sh
index 667e319..f2a08bf 100755
--- a/test/T170-sexp.sh
+++ b/test/T170-sexp.sh
@@ -19,7 +19,7 @@ test_expect_equal "$output" ":id \"${gen_msg_id}\" :match 
t :excluded nil :f
 test_begin_subtest "Search message: sexp"
 add_message "[subject]=\"sexp-search-subject\"" "[date]=\"Sat, 01 Jan 2000 
12:00:00 -\"" "[body]=\"sexp-search-message\""
 output=$(notmuch search --format=sexp "sexp-search-message" | 
notmuch_search_sanitize)
-test_expect_equal "$output" "((:thread \"0002\" :timestamp 
946728000 :date_relative \"2000-01-01\" :matched 1 :total 1 :authors \"Notmuch 
Test Suite\" :subject \"sexp-search-subject\" :query (\"id:$gen_msg_id\" nil) 
:tags (\"inbox\" \"unread\")))"
+test_expect_equal "$output" "((:thread \"0002\" :timestamp 
946728000 :date_relative \"2000-01-01\" :matched 1 :total 1 :authors \"Notmuch 
Test Suite\" :authors_matched (\"Notmuch Test Suite\") :authors_non_matched () 
:subject \"sexp-search-subject\" :query (\"id:$gen_msg_id\" nil) :tags 
(\"inbox\" \"unread\")))"

 test_begin_subtest "Show message: sexp, utf-8"
 add_message "[subject]=\"sexp-show-utf8-body-s?bj?ct\"" "[date]=\"Sat, 01 Jan 
2000 12:00:00 -\"" "[body]=\"js?n-show-m?ssage\""
@@ -44,7 +44,7 @@ test_expect_equal "$output" ":id \"$id\" :match t 
:excluded nil :filename \"
 test_begin_subtest "Search message: sexp, utf-8"
 add_message "[subject]=\"sexp-search-utf8-body-s?bj?ct\"" "[date]=\"Sat, 01 
Jan 2000 12:00:00 -\"" "[body]=\"js?n-search-m?ssage\""
 output=$(notmuch search --format=sexp "js?n-search-m?ssage" | 
notmuch_search_sanitize)
-test_expect_equal "$output" "((:thread \"0005\" :timestamp 
946728000 :date_relative \"2000-01-01\" :matched 1 :total 1 :authors \"Notmuch 
Test Suite\" :subject \"sexp-search-utf8-body-s?bj?ct\" :query 
(\"id:$gen_msg_id\" nil) :tags (\"inbox\" \"unread\")))"
+test_expect_equal "$output" "((:thread \"0005\" :timestamp 
946728000 :date_relative \"2000-01-01\" :matched 1 :total 1 :authors \"Notmuch 
Test Suite\" :authors_matched (\"Notmuch Test Suite\") :authors_non_matched () 
:subject \"sexp-search-utf8-body-s?bj?ct\" :query (\"id:$gen_msg_id\" nil) 
:tags (\"inbox\" \"unread\")))"


 test_done
diff --git a/test/T470-missing-headers.sh b/test/T470-missing-headers.sh
index cb38301..250a370 100755
--- a/test/T470-missing-headers.sh
+++ b/test/T470-missing-headers.sh
@@ -34,6 +34,10 @@ test_expect_equal_json "$output" '
 [
 {
 "authors": "",
+"authors_matched": [
+""
+],
+"authors_non_matched": [],
 "date_relative": "2001-01-05",
 "matched": 1,
 "subject": "",
@@ -48,6 +52,10 @@ test_expect_equal_json "$output" '
 },
 {
 "authors": "Notmuch Test Suite",
+"authors_matched": [
+"Notmuch Test Suite"
+],
+"authors_non_matched": [],
 "date_relative": "1970-01-01",
 "matched": 1,
 "subject": "",
-- 
2.1.1



[PATCH v2 2/3] emacs: Improved display of matching/non-matching authors.

2014-10-24 Thread David Edmondson
Rather than splitting the :authors attribute, which is error prone,
use the separate :authors_matched and :authors_non_matched attributes.

This improves the display of authors should one of them include a pipe
symbol (|) in their 'from' address.
---
 emacs/notmuch.el | 64 +++-
 1 file changed, 35 insertions(+), 29 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index b44a907..688b37c 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -672,22 +672,24 @@ foreground and blue background."
;; Reverse the list so earlier entries take precedence
(reverse notmuch-search-line-faces)))

-(defun notmuch-search-author-propertize (authors)
+(defun notmuch-search-author-propertize (authors matching-length)
   "Split `authors' into matching and non-matching authors and
 propertize appropriately. If no boundary between authors and
 non-authors is found, assume that all of the authors match."
-  (if (string-match "\\(.*\\)|\\(.*\\)" authors)
-  (concat (propertize (concat (match-string 1 authors) ",")
- 'face 'notmuch-search-matching-authors)
- (propertize (match-string 2 authors)
- 'face 'notmuch-search-non-matching-authors))
-(propertize authors 'face 'notmuch-search-matching-authors)))
-
-(defun notmuch-search-insert-authors (format-string authors)
+  (let ((match-part (substring authors 0 matching-length))
+   (non-match-part (substring authors matching-length)))
+
+  (concat (propertize match-part 'face 'notmuch-search-matching-authors)
+ (propertize non-match-part 'face 
'notmuch-search-non-matching-authors
+
+(defun notmuch-search-insert-authors (format-string matching-authors 
non-matching-authors)
   ;; Save the match data to avoid interfering with
   ;; `notmuch-search-process-filter'.
   (save-match-data
-(let* ((formatted-authors (format format-string authors))
+(let* ((authors (if (string= "" non-matching-authors)
+   matching-authors
+ (concat matching-authors ", " non-matching-authors)))
+  (formatted-authors (format format-string authors))
   (formatted-sample (format format-string ""))
   (visible-string formatted-authors)
   (invisible-string "")
@@ -703,9 +705,9 @@ non-authors is found, assume that all of the authors match."
(setq visible-string (substring formatted-authors 0 visible-length)
  invisible-string (substring formatted-authors visible-length))
;; If possible, truncate the visible string at a natural
-   ;; break (comma or pipe), as incremental search doesn't
-   ;; match across the visible/invisible border.
-   (when (string-match "\\(.*\\)\\([,|] \\)\\([^,|]*\\)" 
visible-string)
+   ;; break (comma), as incremental search doesn't match
+   ;; across the visible/invisible border.
+   (when (string-match "\\(.*\\)\\(, \\)\\([^,]*\\)" visible-string)
  ;; Second clause is destructive on `visible-string', so
  ;; order is important.
  (setq invisible-string (concat (match-string 3 visible-string)
@@ -721,20 +723,23 @@ non-authors is found, assume that all of the authors 
match."
   ? 

   ;; Use different faces to show matching and non-matching authors.
-  (if (string-match "\\(.*\\)|\\(.*\\)" visible-string)
- ;; The visible string contains both matching and
- ;; non-matching authors.
- (setq visible-string (notmuch-search-author-propertize visible-string)
-   ;; The invisible string must contain only non-matching
-   ;; authors, as the visible-string contains both.
-   invisible-string (propertize invisible-string
-'face 
'notmuch-search-non-matching-authors))
-   ;; The visible string contains only matching authors.
-   (setq visible-string (propertize visible-string
-'face 'notmuch-search-matching-authors)
- ;; The invisible string may contain both matching and
- ;; non-matching authors.
- invisible-string (notmuch-search-author-propertize 
invisible-string)))
+  (let ((visible-length (length visible-string))
+   (matching-length (length matching-authors)))
+
+   (if (> visible-length matching-length)
+   ;; The visible string contains both matching and
+   ;; non-matching authors.
+   (setq visible-string (notmuch-search-author-propertize 
visible-string matching-length)
+ ;; The invisible string must contain only non-matching
+ ;; authors, as the visible-string contains both.
+ invisible-string (propertize invisible-string
+  'face 

[PATCH v2 1/3] search: Separately report matching and non-matching authors.

2014-10-24 Thread David Edmondson
In addition to the 'authors' attribute of each search result, include
'authors_matched' and 'authors_non_matched' attributes. Both
attributes are always included and are formatted as a list of
authors. If there are no matching authors, the 'authors_non_matched'
attribute is set to the empty list.
---
 notmuch-search.c | 105 +++
 1 file changed, 105 insertions(+)

diff --git a/notmuch-search.c b/notmuch-search.c
index bc9be45..18c3b20 100644
--- a/notmuch-search.c
+++ b/notmuch-search.c
@@ -22,6 +22,8 @@
 #include "sprinter.h"
 #include "string-util.h"

+#include 
+
 typedef enum {
 OUTPUT_SUMMARY,
 OUTPUT_THREADS,
@@ -69,6 +71,105 @@ get_thread_query (notmuch_thread_t *thread,
 return 0;
 }

+/* Return a more pleasent rendering of the mail address
+ * `nasty_author'. */
+static const char *
+_nice_author (void *ctx, const char *nasty_author)
+{
+const char *nice_author = NULL;
+
+InternetAddressList *list = internet_address_list_parse_string 
(nasty_author);
+if (list) {
+   InternetAddress *address = internet_address_list_get_address (list, 0);
+   if (address) {
+   nice_author = internet_address_get_name (address);
+   if (nice_author == NULL) {
+   InternetAddressMailbox *mailbox = INTERNET_ADDRESS_MAILBOX 
(address);
+   nice_author = internet_address_mailbox_get_addr (mailbox);
+   }
+   }
+   /* Duplicate the string before `g_object_unref' destroys
+* it. */
+   if (nice_author)
+   nice_author = talloc_strdup (ctx, nice_author);
+
+   g_object_unref (G_OBJECT (list));
+}
+
+if (nice_author)
+   return nice_author;
+else
+   return nasty_author;
+}
+
+static int
+_enumerate_authors (sprinter_t *format,
+notmuch_thread_t *thread)
+{
+notmuch_messages_t *messages;
+GHashTable *matched_hash = g_hash_table_new_full (g_str_hash, g_str_equal, 
NULL, NULL);
+GHashTable *unmatched_hash = g_hash_table_new_full (g_str_hash, 
g_str_equal, NULL, NULL);
+GPtrArray *matched_array = g_ptr_array_new ();
+GPtrArray *unmatched_array = g_ptr_array_new ();
+
+/* Iterate over the messages in the thread collecting matching and
+ * non-matching authors. */
+for (messages = notmuch_thread_get_messages (thread);
+notmuch_messages_valid (messages);
+notmuch_messages_move_to_next (messages))
+{
+   notmuch_message_t *message = notmuch_messages_get (messages);
+   const char *author = _nice_author (thread, notmuch_message_get_header 
(message, "from"));
+
+   if (author) {
+   GHashTable *hash;
+   GPtrArray *array;
+
+   if (notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH)) 
{
+   hash = matched_hash;
+   array = matched_array;
+   } else {
+   hash = unmatched_hash;
+   array = unmatched_array;
+   }
+
+   if (!g_hash_table_lookup_extended (hash, author, NULL, NULL)) {
+   char *copy = talloc_strdup (thread, author);
+   g_hash_table_insert (hash, copy, NULL);
+   g_ptr_array_add (array, (char *) copy);
+   }
+   }
+}
+
+/* Output the matched authors. */
+unsigned int i;
+format->map_key (format, "authors_matched");
+format->begin_list (format);
+for (i = 0; i < matched_array->len; i++)
+   format->string (format, (char *) g_ptr_array_index( matched_array, i));
+format->end (format);
+
+/* Output the non-matched authors, but not if they were seen
+ * already in the matched authors list. */
+format->map_key (format, "authors_non_matched");
+format->begin_list (format);
+for (i = 0; i < unmatched_array->len; i++) {
+   char *author = (char *) g_ptr_array_index( unmatched_array, i);
+
+   if (!g_hash_table_lookup_extended (matched_hash, author, NULL, NULL))
+   format->string (format, author);
+}
+format->end (format);
+
+g_hash_table_unref (matched_hash);
+g_hash_table_unref (unmatched_hash);
+
+g_ptr_array_free (matched_array, TRUE);
+g_ptr_array_free (unmatched_array, TRUE);
+
+return 0;
+}
+
 static int
 do_search_threads (sprinter_t *format,
   notmuch_query_t *query,
@@ -152,6 +253,10 @@ do_search_threads (sprinter_t *format,
format->integer (format, total);
format->map_key (format, "authors");
format->string (format, authors);
+   if (_enumerate_authors (format, thread) < 0) {
+   fprintf (stderr, "Out of memory\n");
+   return 1;
+   }
format->map_key (format, "subject");
format->string (format, subject);
if (notmuch_format_version >= 2) {
-- 
2.1.1



[PATCH v2 0/3] Improve the display of matching/non-matching authors.

2014-10-24 Thread David Edmondson

Improve the display of matching/non-matching authors.

Distinguishing between matching and non-matching authors in the emacs
interface is currently done by parsing the :authors attribute of a
search result. If one of the authors uses the pipe symbol (|) in their
'From' address this parsing incorrectly determines the matching and
non-matching authors.

Address this by adding explicit matching and non-matching authors
attributes to the structured output formats.

v2:
- Return the matching/non-matching authors as a list.
- More improvements to the code that renders the authors are possible
  (to improve the chosen break between visible and invisible), but a
  planned re-write of the `notmuch-search-result-format' code would
  render that irrelevant.


David Edmondson (3):
  search: Separately report matching and non-matching authors.
  emacs: Improved display of matching/non-matching authors.
  test: Update tests for 'authors_matched' and authors_non_matched'.

 emacs/notmuch.el |  64 ++
 notmuch-search.c | 105 +++
 test/T160-json.sh|   9 
 test/T170-sexp.sh|   4 +-
 test/T470-missing-headers.sh |   8 
 5 files changed, 159 insertions(+), 31 deletions(-)

-- 
2.1.1



mboxvievfs

2014-10-24 Thread Tomi Ollila
Hi

mboxviewfs is a FUSE filesystem program which shows mbox file
as a separate files under -MM directories in a mountpoint.

example usage transcript:

$ cd ~
$ mkdir notmuchmailbox
$ cd notmuchmailbox

$ wget https://raw.githubusercontent.com/domo141/nottoomuch/master/mboxviewfs.c
...
2014-10-24 17:23:33 (524 KB/s) - ?mboxviewfs.c? saved [31966/31966]

$ sh mboxviewfs.c
+ exec gcc -std=c99 -Wall -Wno-long-long -Wstrict-prototypes -pedantic 
-Wcast-align -Wpointer-arith -W -Wwrite-strings -Wcast-qual -Wshadow -O2 -o 
mboxviewfs mboxviewfs.c -D_FILE_OFFSET_BITS=64 -isystem /usr/include/fuse 
-pthread -lfuse

$ wget -c http://notmuchmail.org/archives/notmuch.mbox
$ mkdir notmuch
$ ./mboxviewfs notmuch.mbox notmuch
$ find notmuch -ls
$ find notmuch | xargs stat -c '%x %n'

$ wget -c http://notmuchmail.org/archives/notmuch.mbox
$ fusermount -u notmuch
$ ./mboxviewfs notmuch.mbox notmuch

$ mkdir bin
$ echo '#!/bin/sh' > bin/notmuch
$ echo "HOME=$HOME/notmuchmailbox; export HOME" >> bin/notmuch
$ echo "exec \"`which notmuch`\" \"\$@\"" >> bin/notmuch
$ chmod 755 bin/notmuch

$ mkdir mail
$ mkdir mail/notmuch
$ cd mail/notmuch
$ : symbolic links to mail directories
$ for d in ../../notmuch/*; do test -d "$d" || continue; ln -s "$d" .; done
$ ls -l
$ cd ../..

$ ./bin/notmuch setup ;: careful here, to run ./bin/notmuch '!!!'
$ ./bin/notmuch new

Found 19424 total files (that's not much mail).
Warning: /home/too/notmuchmailbox/mail/notmuch/2009-11/02e4 is an mbox 
containing a single message,
likely caused by misconfigured mail delivery.  Support for single-message
mboxes is deprecated and may be removed in the future.
Processed 19424 total files in 1m 21s (239 files/sec.).
Added 19414 new messages to the database.

$ ./bin/notmuch count 
19414

$ find notmuch -type f | wc
  19424   19424  485600

$ : have to look that difference later...

$ PATH=$PWD/bin:$PATH emacs -f notmuch 

  19 414 inbox   19 414 unread  40 unread-1d

C-x C-c

$ fusermount -u notmuch

$ ./bin/notmuch count
19414

$ ./bin/notmuch new
Error reading file /home/too/notmuchmailbox/mail/notmuch/2009-11: No such file 
or directory
No new mail.
Note: A fatal error was encountered: Something went wrong trying to read or 
write a file
zsh: exit 1 ./bin/notmuch new

$ wget -c http://notmuchmail.org/archives/notmuch.mbox
$ ./mboxviewfs notmuch.mbox notmuch
$ ./bin/notmuch new
Warning: /home/too/notmuchmailbox/mail/notmuch/2014-10/4be0 is an mbox 
containing a single message,
likely caused by misconfigured mail delivery.  Support for single-message
mboxes is deprecated and may be removed in the future.
Processed 1 file in almost no time.
Added 1 new message to the database.

$ ./bin/notmuch count
19415

---8<---

Next: to set nmbug to this system...


Tomi


[O] how to put into a journal info about the email sent

2014-10-24 Thread David Edmondson
On Fri, Oct 24 2014, Eric Abrahamsen wrote:
> David Belohrad  writes:
>
>> Dear All,
>>
>> i'm using org. And I'm using notmuch (that's why I address both mailing
>> lists). Now, writing an email in everyday bussiness requires a
>> non-significant time of your workhours. So I'd like to have this event
>> in my org agenda. So any time I send some email with a given subject,
>> I'd like to 'automatically' entry the information about it into
>> e.g. sentmails.org in form of a diary entry, with appropriate tag.
>
> I do something like this in Gnorb, which I'd recommend you use except
> it's mostly Gnus specific.
>
> I do it in two parts, but you could do it in one. Basically I add a
> function to the `message-header-hook' (which ensures that all the
> message headers have been generated properly).

Does `message-generate-headers-first' not do what you want for this
specific part?

> Obviously the downside is that, without a "Gcc:" header, org can't
> actually make a real link to the message. It doesn't know where it's
> going to be. However if you know that all your sent messages can be
> reached with a link that looks like "notmuch:id#Message-id", then you
> can make that yourself in your org capture template with something like

As you suggest, know the message-id should be good enough to generate a
notmuch link, though you may have to wait for the notmuch index to be
updated for the link to be valid.


how to put into a journal info about the email sent

2014-10-24 Thread David Belohrad
Dear All,

i'm using org. And I'm using notmuch (that's why I address both mailing
lists). Now, writing an email in everyday bussiness requires a
non-significant time of your workhours. So I'd like to have this event
in my org agenda. So any time I send some email with a given subject,
I'd like to 'automatically' entry the information about it into
e.g. sentmails.org in form of a diary entry, with appropriate tag.

In example:

I'm sending a mail to Tom, with subject 'dealing vme register
mapping'. 

At the moment I send this email (using smtpmail), I'd like an entry in
the sentmails.org as follows:


** 2014-10 October
*** 2014-10-02 Thursday
 dealing vme register mapping   
  :mail:
[[notmuch:id:7a97bb93e66a41878edd4c04fa764963 at cernfe03.cern.ch][dealing
vme register mapping]]


I thought that I can use following

(add-hook 'message-send-hook ')

to hook on sending and generate a capture entry. In fact this works
pretty well _EXCEPT_ the link to the mail sent. The org-store-link
cannot apparently store a link to an email, which so far was not sent
(and not received?) because it claims that

'org-gnus-store-link: Can not create link: No Gcc header found'

Hence this is pretty fatal for my diary entry. My question is: is there
any way how to link not-yet-sent/received email as an org-link? Or is
there any way to generate Gcc header before the email is sent and use
this header during sending? Or is
there any other way how to put into my agenda sent emails?

many thanks

david




Looking for the perfect mail client

2014-10-24 Thread Ian Main
Sepp Tannhuber wrote:
> Ian Main  schrieb am 18:02 Freitag, 24.Oktober 2014:
> 
> > Interesting, good feedback.  Is it the usage that is difficult or setup?
> Installation was not a problem for me although the files ?notmuch.vim? and 
> ?notmuch.txt? were not found by ?make install? for some reason. So I linked
> them into the notmuch-vim directory. After that ?make install? succeeded.
> But the main obstacle is that new users must find by trial and error that
> they must type ?s? to search, ?t? to tag files and so on. It would be very
> useful to list all the key bindings and configuration options.
> I still don't know how to compose a new message.

https://github.com/imain/notmuch-vim/blob/master/doc/notmuch.txt

Look at the 'MAPPINGS' section.  I think a tutorial might be good though.

> > Well like any other text based client it uses a text dump of a links or 
> > such (I
> > forget which one).
> I think ?elinks --dump?
> 
> > We have great support for web browser viewing of the email
> > though if that isn't good enough.
> Yes, it's 2014. ;-)

Time flies!!

> > Let me know if you have suggestions on where it's lacking. 
> Okay, thank you so far.

Thanks!




[PATCH v3 3/4] cli: Extend the search command for --output={sender, recipients}

2014-10-24 Thread Michal Sojka
Hi Mark,

I mostly agree with your points mentioned in this and other your emails.
I'll prepare v4 based on that.

On Wed, Oct 22 2014, Mark Walters wrote:
> On Sun, 12 Oct 2014, Michal Sojka  wrote:
>> The new outputs allow printing senders, recipients or both of matching
>> messages. The --output option is converted from "keyword" argument to
>> "flags" argument, which means that the user can use --output=sender and
>> --output=recipients simultaneously, to print both. Other combinations
>> produce an error.
>>
>> This code based on a patch from Jani Nikula.
>> ---
>>  completion/notmuch-completion.bash |   2 +-
>>  completion/notmuch-completion.zsh  |   3 +-
>>  doc/man1/notmuch-search.rst|  22 +++-
>>  notmuch-search.c   | 110 
>> ++---
>>  test/T090-search-output.sh |  64 +
>>  5 files changed, 189 insertions(+), 12 deletions(-)
>>
>> diff --git a/completion/notmuch-completion.bash 
>> b/completion/notmuch-completion.bash
>> index 0571dc9..cfbd389 100644
>> --- a/completion/notmuch-completion.bash
>> +++ b/completion/notmuch-completion.bash
>> @@ -294,7 +294,7 @@ _notmuch_search()
>>  return
>>  ;;
>>  --output)
>> -COMPREPLY=( $( compgen -W "summary threads messages files tags" -- 
>> "${cur}" ) )
>> +COMPREPLY=( $( compgen -W "summary threads messages files tags 
>> sender recipients" -- "${cur}" ) )
>>  return
>>  ;;
>>  --sort)
>> diff --git a/completion/notmuch-completion.zsh 
>> b/completion/notmuch-completion.zsh
>> index 67a9aba..3e52a00 100644
>> --- a/completion/notmuch-completion.zsh
>> +++ b/completion/notmuch-completion.zsh
>> @@ -52,7 +52,8 @@ _notmuch_search()
>>_arguments -s : \
>>  '--max-threads=[display only the first x threads from the search 
>> results]:number of threads to show: ' \
>>  '--first=[omit the first x threads from the search results]:number of 
>> threads to omit: ' \
>> -'--sort=[sort results]:sorting:((newest-first\:"reverse chronological 
>> order" oldest-first\:"chronological order"))'
>> +'--sort=[sort results]:sorting:((newest-first\:"reverse chronological 
>> order" oldest-first\:"chronological order"))' \
>> +'--output=[select what to output]:output:((summary threads messages 
>> files tags sender recipients))'
>>  }
>>
>>  _notmuch()
>> diff --git a/doc/man1/notmuch-search.rst b/doc/man1/notmuch-search.rst
>> index 90160f2..c9d38b1 100644
>> --- a/doc/man1/notmuch-search.rst
>> +++ b/doc/man1/notmuch-search.rst
>> @@ -35,7 +35,7 @@ Supported options for **search** include
>>  intended for programs that invoke **notmuch(1)** internally. If
>>  omitted, the latest supported version will be used.
>>
>> -``--output=(summary|threads|messages|files|tags)``
>> +``--output=(summary|threads|messages|files|tags|sender|recipients)``
>>
>>  **summary**
>>  Output a summary of each thread with any message matching
>> @@ -78,6 +78,26 @@ Supported options for **search** include
>>  by null characters (--format=text0), as a JSON array
>>  (--format=json), or as an S-Expression list (--format=sexp).
>>
>> +**sender**
>> +Output all addresses from the *From* header that appear on
>> +any message matching the search terms, either one per line
>> +(--format=text), separated by null characters
>> +(--format=text0), as a JSON array (--format=json), or as
>> +an S-Expression list (--format=sexp).
>> +
>> +Note: Searching for **sender** should be much faster than
>> +searching for **recipients**, because sender addresses are
>> +cached directly in the database whereas other addresses
>> +need to be fetched from message files.
>> +
>> +**recipients**
>> +Like **sender** but for addresses from *To*, *Cc* and
>> +*Bcc* headers.
>> +
>> +This option can be given multiple times to combine different
>> +outputs. Curently, this is only supported for **sender** and
>> +**recipients** outputs.
>> +
>>  ``--sort=``\ (**newest-first**\ \|\ **oldest-first**)
>>  This option can be used to present results in either
>>  chronological order (**oldest-first**) or reverse chronological
>> diff --git a/notmuch-search.c b/notmuch-search.c
>> index 5ac2a26..74588f8 100644
>> --- a/notmuch-search.c
>> +++ b/notmuch-search.c
>> @@ -23,11 +23,14 @@
>>  #include "string-util.h"
>>
>>  typedef enum {
>> -OUTPUT_SUMMARY,
>> -OUTPUT_THREADS,
>> -OUTPUT_MESSAGES,
>> -OUTPUT_FILES,
>> -OUTPUT_TAGS
>> +OUTPUT_SUMMARY  = 1 << 0,
>> +OUTPUT_THREADS  = 1 << 1,
>> +OUTPUT_MESSAGES = 1 << 2,
>> +OUTPUT_FILES= 1 << 3,
>> +OUTPUT_TAGS = 1 << 4,
>> +OUTPUT_SENDER   = 1 << 5,
>> +OUTPUT_RECIPIENTS   = 1 << 6,
>> +OUTPUT_ADDRESSES= OUTPUT_SENDER | 

[PATCH v2] VIM: Add URI handling

2014-10-24 Thread Tomi Ollila
On Fri, Oct 24 2014, Ian Main  wrote:

> Add URI handling to the vim client.  You can now press 'enter' by default and
> the client will parse the current line and find any 'Part's or URIs available
> for opening.  If there are more than one it opens the one under the cursor or
> else it opens the only one available.  It also supports mailto: URI's and will
> compose a new message when activated.

The lines are way too long in this commit message. 72-chars except in cases
where there is no word breaks in the text.

id:1414101891-10714-1-git-send-email-imain at stemwinder.org has also one 
75-character line (and talks about 'This patch ...' which could be changed
too (but is tolerated if not)).

Tomi

>
> By default xdg-open is used for everything but mailto: which generally
> does the right thing afaict.
>
> Note that this is now dependant on the attachment patch in order to make
> the nice 'enter' behavior work for both.
>
> Ian
> ---
>  vim/notmuch.txt |  3 ++-
>  vim/notmuch.vim | 76 
> +++--
>  2 files changed, 70 insertions(+), 9 deletions(-)
>
> diff --git a/vim/notmuch.txt b/vim/notmuch.txt
> index 838a904..5d84fde 100644
> --- a/vim/notmuch.txt
> +++ b/vim/notmuch.txt
> @@ -74,7 +74,8 @@ I   Mark as read (-unread)
>  tTag (prompted)
>  e   Extract attachment on the current 'Attachment' line or all
>   attachments if the cursor is elsewhere.
> -v   View attachment on the current 'Attachment' line.
> + View email part on the current 'Part' line, or open URI under cursor
> +or on line.
>  sSearch
>  pSave patches
>  rReply
> diff --git a/vim/notmuch.vim b/vim/notmuch.vim
> index 1466e50..2f76f55 100644
> --- a/vim/notmuch.vim
> +++ b/vim/notmuch.vim
> @@ -12,7 +12,7 @@ let g:notmuch_folders_maps = {
>   \ '':'folders_show_search()',
>   \ 's':  'folders_search_prompt()',
>   \ '=':  'folders_refresh()',
> - \ 'c':  'compose()',
> + \ 'c':  'compose("")',
>   \ }
>  
>  let g:notmuch_search_maps = {
> @@ -25,7 +25,7 @@ let g:notmuch_search_maps = {
>   \ 's':  'search_search_prompt()',
>   \ '=':  'search_refresh()',
>   \ '?':  'search_info()',
> - \ 'c':  'compose()',
> + \ 'c':  'compose("")',
>   \ }
>  
>  let g:notmuch_show_maps = {
> @@ -35,13 +35,13 @@ let g:notmuch_show_maps = {
>   \ 't':  'show_tag("")',
>   \ 'o':  'show_open_msg()',
>   \ 'e':  'show_extract_msg()',
> - \ '':'show_view_attachment()',
> + \ '':'show_view_magic()',
>   \ 's':  'show_save_msg()',
>   \ 'p':  'show_save_patches()',
>   \ 'r':  'show_reply()',
>   \ '?':  'show_info()',
>   \ '':  'show_next_msg()',
> - \ 'c':  'compose()',
> + \ 'c':  'compose("")',
>   \ }
>  
>  let g:notmuch_compose_maps = {
> @@ -63,6 +63,7 @@ let s:notmuch_view_attachment_default = 'xdg-open'
>  let s:notmuch_attachment_tmpdir_default = '~/.notmuch/tmp'
>  let s:notmuch_folders_count_threads_default = 0
>  let s:notmuch_compose_start_insert_default = 1
> +let s:notmuch_open_uri_default = 'xdg-open'
>  
>  function! s:new_file_buffer(type, fname)
>   exec printf('edit %s', a:fname)
> @@ -141,8 +142,8 @@ function! s:show_reply()
>   end
>  endfunction
>  
> -function! s:compose()
> - ruby open_compose
> +function! s:compose(to_email)
> + ruby open_compose(VIM::evaluate('a:to_email'))
>   let b:compose_done = 0
>   call s:set_map(g:notmuch_compose_maps)
>   autocmd BufDelete  call s:on_compose_delete()
> @@ -155,6 +156,22 @@ function! s:show_info()
>   ruby vim_puts get_message.inspect
>  endfunction
>  
> +function! s:show_view_magic()
> + let line = getline(".")
> +
> +ruby << EOF
> + line = VIM::evaluate('line')
> +
> + # Easiest to check for 'Part' types first..
> + match = line.match(/^Part (\d*):/)
> + if match and match.length == 2
> + VIM::command('call s:show_view_attachment()')
> + else
> + VIM::command('call s:show_open_uri()')
> + end
> +EOF
> +endfunction
> +
>  function! s:show_view_attachment()
>   let line = getline(".")
>  ruby << EOF
> @@ -226,6 +243,45 @@ ruby << EOF
>  EOF
>  endfunction
>  
> +function! s:show_open_uri()
> + let line = getline(".")
> + let pos = getpos(".")
> + let col = pos[2]
> +ruby << EOF
> + m = get_message
> + line = VIM::evaluate('line')
> + col = VIM::evaluate('col') - 1
> + uris = URI.extract(line)
> + wanted_uri = nil
> + if uris.length == 1
> + wanted_uri = uris[0]
> + else
> + uris.each do |uri|
> + # Check to see the URI is at the present cursor location
> + idx = line.index(uri)
> + if col >= idx and col <= idx + uri.length
> +  

[PATCH v3 3/4] cli: Extend the search command for --output={sender, recipients}

2014-10-24 Thread Tomi Ollila
On Thu, Oct 23 2014, Mark Walters  wrote:

> On Sun, 12 Oct 2014, Michal Sojka  wrote:
>> The new outputs allow printing senders, recipients or both of matching
>> messages. The --output option is converted from "keyword" argument to
>> "flags" argument, which means that the user can use --output=sender and
>> --output=recipients simultaneously, to print both. Other combinations
>> produce an error.
>>
>> ...
>>
>> +static void
>> +print_address_list (const search_options_t *o, InternetAddressList *list)
>> +{
>> +InternetAddress *address;
>> +int i;
>> +
>> +for (i = 0; i < internet_address_list_length (list); i++) {
>> +address = internet_address_list_get_address (list, i);
>> +if (INTERNET_ADDRESS_IS_GROUP (address)) {
>> +InternetAddressGroup *group;
>> +InternetAddressList *group_list;
>> +
>> +group = INTERNET_ADDRESS_GROUP (address);
>> +group_list = internet_address_group_get_members (group);
>> +if (group_list == NULL)
>> +continue;
>> +
>> +print_address_list (o, group_list);
>> +} else {
>> +InternetAddressMailbox *mailbox;
>> +const char *name;
>> +const char *addr;
>> +char *full_address;
>> +
>> +mailbox = INTERNET_ADDRESS_MAILBOX (address);
>> +
>> +name = internet_address_get_name (address);
>> +addr = internet_address_mailbox_get_addr (mailbox);
>> +
>> +if (name && *name)
>> +full_address = talloc_asprintf (o->format, "%s <%s>", name, 
>> addr);
>> +else
>> +full_address = talloc_strdup (o->format, addr);
>> +
>> +if (!full_address) {
>> +fprintf (stderr, "Error: out of memory\n");
>> +break;
>> +}
>> +o->format->string (o->format, full_address);
>> +o->format->separator (o->format);
>> +
>> +talloc_free (full_address);
>
> Thinking about this some more how about printing the name and address as
> a structured pair/map (at least for all cases except text/text0 output):
> something like (in JSON)
> [name: "John Doe" address: "john.doe at example.com"]
>
> It seems wrong to me to go to the effort of separating them in the C and
> then combining them in the output.
>
> This could also help with the questions about uniqueness. If the client
> can get the data ready parsed into name/address then it can deal with
> much of the uniqueness itself.

In that case client can also filter based on some substring, reducing the
memory requirements...

>
> My preference would be for the default to print one line for each
> distinct full_address, and then any filter-by options to refine from
> there.

Hmm, now I cannot decide whether this or just print out all addresses of
messages, or do this distinct full_address output -- it looks like all
other --output options prints unique lines, but there is potential of 
quite a lot of memory usage there...

... probably the memory usage is not problem there, OOM-killer eventually
does it's job if necessary (!) (but machine may be slow (and trashing) for
a while (just thinking out loud))

(!) but could we have general filter option for search to drop data before
it is even considered for caching! -- maybe later ?


> One other advantage of structuring the output is that it is extensible:
> for example, at some later stage, we could include a "count" in the map
> allowing the client can pick the most popular variant.

, and in this case notmuch cannot print any output until the full address
list is gathered... :D

>
> Best wishes
>
> Mark

Tomi

>
>
>
>
>> +}
>> +}
>> +}
>> +
>> +static void
>> +print_address_string (const search_options_t *o, const char *recipients)
>> +{
>> +InternetAddressList *list;
>> +
>> +if (recipients == NULL)
>> +return;
>> +
>> +list = internet_address_list_parse_string (recipients);
>> +if (list == NULL)
>> +return;
>> +
>> +print_address_list (o, list);
>> +}
>> +
>>  static int
>>  do_search_messages (search_options_t *o)
>>  {
>> @@ -266,11 +330,29 @@ do_search_messages (search_options_t *o)
>>  
>>  notmuch_filenames_destroy( filenames );
>>  
>> -} else { /* output == OUTPUT_MESSAGES */
>> +} else if (o->output == OUTPUT_MESSAGES) {
>>  format->set_prefix (format, "id");
>>  format->string (format,
>>  notmuch_message_get_message_id (message));
>>  format->separator (format);
>> +} else {
>> +if (o->output & OUTPUT_SENDER) {
>> +const char *addrs;
>> +
>> +addrs = notmuch_message_get_header (message, "from");
>> +print_address_string (o, addrs);
>> +}
>> +
>> +if (o->output & OUTPUT_RECIPIENTS) {
>> +const char *hdrs[] = { "to", "cc", "bcc" };
>> +const char *addrs;
>> +size_t j;
>> +
>> +for (j = 0; j < ARRAY_SIZE (hdrs); j++) {
>> +addrs = 

[PATCH] doc: add README.md especially for github

2014-10-24 Thread Tomi Ollila
On Fri, Oct 24 2014, David Bremner  wrote:

> Apparently README.md overrides README, so this will show up instead of
> our generic README on github.
>
> If the user is already on github, then clicking a link for more
> information is not a hardship.

LGTM. although I'd prefer README.rst

Tomi

> ---
>  README.md | 15 +++
>  1 file changed, 15 insertions(+)
>  create mode 100644 README.md
>
> diff --git a/README.md b/README.md
> new file mode 100644
> index 000..ce579d8
> --- /dev/null
> +++ b/README.md
> @@ -0,0 +1,15 @@
> +If you're reading this on github.com, this is a read-only mirror of
> +the notmuch project.
> +
> +For more information about the project, see
> +
> +  http://notmuchmail.org
> +
> +Please don't send us pull requests on github. If you have a feature
> +branch that you want us to look at, use `git send-email` to send to
> +notmuch at notmuchmail.org.
> +
> +For more information about contributing to the project, see
> +
> +
> +  http://notmuchmail.org/contributing/
> -- 
> 2.1.1
>
> ___
> notmuch mailing list
> notmuch at notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH] doc: add README.md especially for github

2014-10-24 Thread David Bremner
Tomi Ollila  writes:

> On Fri, Oct 24 2014, David Bremner  wrote:
>
>> Apparently README.md overrides README, so this will show up instead of
>> our generic README on github.
>>
>> If the user is already on github, then clicking a link for more
>> information is not a hardship.
>
> LGTM. although I'd prefer README.rst
>

OK, rst version pushed and shows up on github.

d


[PATCH v3 3/4] cli: Extend the search command for --output={sender, recipients}

2014-10-24 Thread David Edmondson
On Thu, Oct 23 2014, Mark Walters wrote:
> Thinking about this some more how about printing the name and address as
> a structured pair/map (at least for all cases except text/text0 output):
> something like (in JSON)
> [name: "John Doe" address: "john.doe at example.com"]
>
> It seems wrong to me to go to the effort of separating them in the C and
> then combining them in the output.

Agreed, this would be convenient.


[PATCH v1 1/3] search: Seperately report matching and non-matching authors.

2014-10-24 Thread David Edmondson
On Fri, Oct 24 2014, Mark Walters wrote:
> What about having both authors_matched and authors_not_matched as lists
> of authors (ie one string for each author)?

That's a sensible idea. I will look into it.

> Then emacs, for example, wouldn't try and parse the string back into
> authors before splitting.

It doesn't really do that other than to decide where to truncate the
visible string. That whole chunk of code is horrible.

>>  first_non_matched_author = 0;
>
> I think I would prefer to make this look like the matched case and drop
> the first_non_matched_author stuff.

Agreed, will do.


[PATCH] doc: add README.md especially for github

2014-10-24 Thread David Bremner
Apparently README.md overrides README, so this will show up instead of
our generic README on github.

If the user is already on github, then clicking a link for more
information is not a hardship.
---
 README.md | 15 +++
 1 file changed, 15 insertions(+)
 create mode 100644 README.md

diff --git a/README.md b/README.md
new file mode 100644
index 000..ce579d8
--- /dev/null
+++ b/README.md
@@ -0,0 +1,15 @@
+If you're reading this on github.com, this is a read-only mirror of
+the notmuch project.
+
+For more information about the project, see
+
+  http://notmuchmail.org
+
+Please don't send us pull requests on github. If you have a feature
+branch that you want us to look at, use `git send-email` to send to
+notmuch at notmuchmail.org.
+
+For more information about contributing to the project, see
+
+
+  http://notmuchmail.org/contributing/
-- 
2.1.1



[PATCH v1 1/3] search: Seperately report matching and non-matching authors.

2014-10-24 Thread Mark Walters

Hi

I definitely like the idea: some comments below.

On Fri, 24 Oct 2014, David Edmondson  wrote:
> In addition to the :authors attribute of each search result, include
> :authors_matched and :authors_non_matched attributes. Both attributes
> are always included. If there are no non-matching authors, the
> :authors_non_matched attribute is set to the empty string.

What about having both authors_matched and authors_not_matched as lists
of authors (ie one string for each author)? Then emacs, for example,
wouldn't try and parse the string back into authors before
splitting. And authors_non_matched could be an empty list when
appropriate which seems more natural than the empty string.

All the above is based on what a client might want in the output rather
than what is easy or sensible to implement in the C code.

> ---
>  lib/notmuch.h| 34 
>  lib/thread.cc| 60 
> +++-
>  notmuch-search.c |  6 ++
>  3 files changed, 82 insertions(+), 18 deletions(-)
>
> diff --git a/lib/notmuch.h b/lib/notmuch.h
> index dae0416..30ce6c3 100644
> --- a/lib/notmuch.h
> +++ b/lib/notmuch.h
> @@ -993,6 +993,40 @@ const char *
>  notmuch_thread_get_authors (notmuch_thread_t *thread);
>  
>  /**
> + * Get the matched authors of 'thread' as a UTF-8 string.
> + *
> + * The returned string is a comma-separated list of the names of the
> + * authors of mail messages in the query results that belong to this
> + * thread.
> + *
> + * Authors are ordered by date.
> + *
> + * The returned string belongs to 'thread' and as such, should not be
> + * modified by the caller and will only be valid for as long as the
> + * thread is valid, (which is until notmuch_thread_destroy or until
> + * the query from which it derived is destroyed).
> + */
> +const char *
> +notmuch_thread_get_authors_matched (notmuch_thread_t *thread);
> +
> +/**
> + * Get the non-matched authors of 'thread' as a UTF-8 string.
> + *
> + * The returned string is a comma-separated list of the names of the
> + * authors of mail messages in the query results that belong to this
> + * thread.
> + *
> + * Authors are ordered by date.
> + *
> + * The returned string belongs to 'thread' and as such, should not be
> + * modified by the caller and will only be valid for as long as the
> + * thread is valid, (which is until notmuch_thread_destroy or until
> + * the query from which it derived is destroyed).
> + */
> +const char *
> +notmuch_thread_get_authors_non_matched (notmuch_thread_t *thread);
> +
> +/**
>   * Get the subject of 'thread' as a UTF-8 string.
>   *
>   * The subject is taken from the first message (according to the query
> diff --git a/lib/thread.cc b/lib/thread.cc
> index 8922403..b344875 100644
> --- a/lib/thread.cc
> +++ b/lib/thread.cc
> @@ -33,6 +33,8 @@ struct visible _notmuch_thread {
>  GHashTable *matched_authors_hash;
>  GPtrArray *matched_authors_array;
>  char *authors;
> +char *authors_matched;
> +char *authors_non_matched;
>  GHashTable *tags;
>  
>  /* All messages, oldest first. */
> @@ -112,10 +114,11 @@ _thread_add_matched_author (notmuch_thread_t *thread,
>  g_ptr_array_add (thread->matched_authors_array, author_copy);
>  }
>  
> -/* Construct an authors string from matched_authors_array and
> - * authors_array. The string contains matched authors first, then
> - * non-matched authors (with the two groups separated by '|'). Within
> - * each group, authors are listed in date order. */
> +/* Construct the authors_matched, authors_non_matched and authors
> + * strings from matched_authors_array and authors_array. The authors
> + * string contains matched authors first, then non-matched authors
> + * (with the two groups separated by '|'). Within each group, authors
> + * are listed in date order. */
>  static void
>  _resolve_thread_authors_string (notmuch_thread_t *thread)
>  {
> @@ -123,36 +126,43 @@ _resolve_thread_authors_string (notmuch_thread_t 
> *thread)
>  char *author;
>  int first_non_matched_author = 1;
>  
> -/* First, list all matched authors in date order. */
> +/* List all matched authors in date order. */
>  for (i = 0; i < thread->matched_authors_array->len; i++) {
>   author = (char *) g_ptr_array_index (thread->matched_authors_array, i);
> - if (thread->authors)
> - thread->authors = talloc_asprintf (thread, "%s, %s",
> -thread->authors,
> -author);
> - else
> - thread->authors = author;
> + if (thread->authors_matched) {
> + thread->authors_matched = talloc_asprintf (thread, "%s, %s",
> +thread->authors_matched,
> +author);
> + } else {
> + thread->authors_matched = author;
> + }
>  }
>  
> -/* Next, append any non-matched 

[PATCH v3] VIM: Add URI handling

2014-10-24 Thread Ian Main
Tomi Ollila wrote:
> On Fri, Oct 24 2014, Ian Main  wrote:
> 
> This patch does not apply on top of notmuchmail master 
> (commit 38240d106139da8).
> 
> > This patch adds URI handling to the vim client.  You can now press
> 
> Although insignificant, I'll start commenting on all sent patches
> (that I look into) which talk like 'This patch adds' -- sure it is patch
> when email is sent, but in repository it is not so -- so the commit message
> should not mention it (but I do not require changing it).
> 
> Anyway, I suspect this change will become applicable after some other
> change is committed first -- and IMO this could stay as non-stale patch
> provided that SomeOne(TM) informs what is the message that contains
> changes (or series those) that is required for this message to apply.
> 
> BTW: does the content of this change differ much from v1 at
> id:1412281423-22441-1-git-send-email-imain at stemwinder.org
> or should I re-check (carefully!) that the changes are still OK.
> 
> 
> Tomi
> 

This one is almost identical minus the hotkey usage.  The attachment support
patch has changed a fair bit in that it now looks at all parts of multipart
messages, giving you the opportunity to view the original text/html message
in a web browser.

I sent them out as a series in a new thread so that it would be easier to
follow.  I have them all applied locally and there were some conflicts to
resolve.  They are simple, usually around the defaults settings for the
configuration but it's still a pain.  I'm still tempted to send out all
of the outstanding patches as a big series.  All the patches posted though
should apply to master so I may just have to rebase now and again.

Ian


[O] how to put into a journal info about the email sent

2014-10-24 Thread Eric Abrahamsen
David Edmondson  writes:

> On Fri, Oct 24 2014, Eric Abrahamsen wrote:
>> David Belohrad  writes:
>>
>>> Dear All,
>>>
>>> i'm using org. And I'm using notmuch (that's why I address both mailing
>>> lists). Now, writing an email in everyday bussiness requires a
>>> non-significant time of your workhours. So I'd like to have this event
>>> in my org agenda. So any time I send some email with a given subject,
>>> I'd like to 'automatically' entry the information about it into
>>> e.g. sentmails.org in form of a diary entry, with appropriate tag.
>>
>> I do something like this in Gnorb, which I'd recommend you use except
>> it's mostly Gnus specific.
>>
>> I do it in two parts, but you could do it in one. Basically I add a
>> function to the `message-header-hook' (which ensures that all the
>> message headers have been generated properly).
>
> Does `message-generate-headers-first' not do what you want for this
> specific part?

Yeah, I think I looked at that previously. But this thing is going in a
hook anyway, might as well use the hook that *doesn't* require me to
call that function explicitly.

>> Obviously the downside is that, without a "Gcc:" header, org can't
>> actually make a real link to the message. It doesn't know where it's
>> going to be. However if you know that all your sent messages can be
>> reached with a link that looks like "notmuch:id#Message-id", then you
>> can make that yourself in your org capture template with something like
>
> As you suggest, know the message-id should be good enough to generate a
> notmuch link, though you may have to wait for the notmuch index to be
> updated for the link to be valid.

Yup, I've got the same issue with nnimap -- you have to wait for the
next sync to get access to the message. So far it hasn't been a problem,
though.



Looking for the perfect mail client

2014-10-24 Thread Sepp Tannhuber
Ian Main  schrieb am 6:28 Freitag, 24.Oktober 2014:

> I wonder if you'd be willing to give the vim client a go.  We've done a lot
> of work to it lately and I think it would handle all you listed here.
For me, it's hard to get familiar with it because I have not found a detailed
documentation. The README file is not good enough for a stupid person.


I also doubt that it can render html properly.

Nevertheless, I would give it a try if I could find useful documentation.


[PATCH v1 3/3] test: Update tests for :authors_matched and :authors_non_matched.

2014-10-24 Thread David Edmondson
---
 test/T160-json.sh| 4 
 test/T170-sexp.sh| 4 ++--
 test/T470-missing-headers.sh | 4 
 3 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/test/T160-json.sh b/test/T160-json.sh
index c1cf649..d3cf2e7 100755
--- a/test/T160-json.sh
+++ b/test/T160-json.sh
@@ -25,6 +25,8 @@ test_expect_equal_json "$output" "[{\"thread\": \"XXX\",
  \"matched\": 1,
  \"total\": 1,
  \"authors\": \"Notmuch Test Suite\",
+ \"authors_matched\": \"Notmuch Test Suite\",
+ \"authors_non_matched\": \"\",
  \"subject\": \"json-search-subject\",
  \"query\": [\"id:$gen_msg_id\", null],
  \"tags\": [\"inbox\",
@@ -59,6 +61,8 @@ test_expect_equal_json "$output" "[{\"thread\": \"XXX\",
  \"matched\": 1,
  \"total\": 1,
  \"authors\": \"Notmuch Test Suite\",
+ \"authors_matched\": \"Notmuch Test Suite\",
+ \"authors_non_matched\": \"\",
  \"subject\": \"json-search-utf8-body-s?bj?ct\",
  \"query\": [\"id:$gen_msg_id\", null],
  \"tags\": [\"inbox\",
diff --git a/test/T170-sexp.sh b/test/T170-sexp.sh
index 667e319..8a57b74 100755
--- a/test/T170-sexp.sh
+++ b/test/T170-sexp.sh
@@ -19,7 +19,7 @@ test_expect_equal "$output" ":id \"${gen_msg_id}\" :match 
t :excluded nil :f
 test_begin_subtest "Search message: sexp"
 add_message "[subject]=\"sexp-search-subject\"" "[date]=\"Sat, 01 Jan 2000 
12:00:00 -\"" "[body]=\"sexp-search-message\""
 output=$(notmuch search --format=sexp "sexp-search-message" | 
notmuch_search_sanitize)
-test_expect_equal "$output" "((:thread \"0002\" :timestamp 
946728000 :date_relative \"2000-01-01\" :matched 1 :total 1 :authors \"Notmuch 
Test Suite\" :subject \"sexp-search-subject\" :query (\"id:$gen_msg_id\" nil) 
:tags (\"inbox\" \"unread\")))"
+test_expect_equal "$output" "((:thread \"0002\" :timestamp 
946728000 :date_relative \"2000-01-01\" :matched 1 :total 1 :authors \"Notmuch 
Test Suite\" :authors_matched \"Notmuch Test Suite\" :authors_non_matched \"\" 
:subject \"sexp-search-subject\" :query (\"id:$gen_msg_id\" nil) :tags 
(\"inbox\" \"unread\")))"

 test_begin_subtest "Show message: sexp, utf-8"
 add_message "[subject]=\"sexp-show-utf8-body-s?bj?ct\"" "[date]=\"Sat, 01 Jan 
2000 12:00:00 -\"" "[body]=\"js?n-show-m?ssage\""
@@ -44,7 +44,7 @@ test_expect_equal "$output" ":id \"$id\" :match t 
:excluded nil :filename \"
 test_begin_subtest "Search message: sexp, utf-8"
 add_message "[subject]=\"sexp-search-utf8-body-s?bj?ct\"" "[date]=\"Sat, 01 
Jan 2000 12:00:00 -\"" "[body]=\"js?n-search-m?ssage\""
 output=$(notmuch search --format=sexp "js?n-search-m?ssage" | 
notmuch_search_sanitize)
-test_expect_equal "$output" "((:thread \"0005\" :timestamp 
946728000 :date_relative \"2000-01-01\" :matched 1 :total 1 :authors \"Notmuch 
Test Suite\" :subject \"sexp-search-utf8-body-s?bj?ct\" :query 
(\"id:$gen_msg_id\" nil) :tags (\"inbox\" \"unread\")))"
+test_expect_equal "$output" "((:thread \"0005\" :timestamp 
946728000 :date_relative \"2000-01-01\" :matched 1 :total 1 :authors \"Notmuch 
Test Suite\" :authors_matched \"Notmuch Test Suite\" :authors_non_matched \"\" 
:subject \"sexp-search-utf8-body-s?bj?ct\" :query (\"id:$gen_msg_id\" nil) 
:tags (\"inbox\" \"unread\")))"


 test_done
diff --git a/test/T470-missing-headers.sh b/test/T470-missing-headers.sh
index cb38301..5d66e7e 100755
--- a/test/T470-missing-headers.sh
+++ b/test/T470-missing-headers.sh
@@ -34,6 +34,8 @@ test_expect_equal_json "$output" '
 [
 {
 "authors": "",
+"authors_matched": "",
+"authors_non_matched": "",
 "date_relative": "2001-01-05",
 "matched": 1,
 "subject": "",
@@ -48,6 +50,8 @@ test_expect_equal_json "$output" '
 },
 {
 "authors": "Notmuch Test Suite",
+"authors_matched": "Notmuch Test Suite",
+"authors_non_matched": "",
 "date_relative": "1970-01-01",
 "matched": 1,
 "subject": "",
-- 
2.1.1



[PATCH v1 2/3] emacs: Improved display of matching/non-matching authors.

2014-10-24 Thread David Edmondson
Rather than splitting the :authors attribute, which is error prone,
use the separate :authors_matched and :authors_non_matched attributes.

This improves the display of authors should one of them include a pipe
symbol (|) in their 'from' address.
---
 emacs/notmuch.el | 64 +++-
 1 file changed, 35 insertions(+), 29 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index b44a907..29b6cdc 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -672,22 +672,24 @@ foreground and blue background."
;; Reverse the list so earlier entries take precedence
(reverse notmuch-search-line-faces)))

-(defun notmuch-search-author-propertize (authors)
+(defun notmuch-search-author-propertize (authors matching-length)
   "Split `authors' into matching and non-matching authors and
 propertize appropriately. If no boundary between authors and
 non-authors is found, assume that all of the authors match."
-  (if (string-match "\\(.*\\)|\\(.*\\)" authors)
-  (concat (propertize (concat (match-string 1 authors) ",")
- 'face 'notmuch-search-matching-authors)
- (propertize (match-string 2 authors)
- 'face 'notmuch-search-non-matching-authors))
-(propertize authors 'face 'notmuch-search-matching-authors)))
-
-(defun notmuch-search-insert-authors (format-string authors)
+  (let ((match-part (substring authors 0 matching-length))
+   (non-match-part (substring authors matching-length)))
+
+  (concat (propertize match-part 'face 'notmuch-search-matching-authors)
+ (propertize non-match-part 'face 
'notmuch-search-non-matching-authors
+
+(defun notmuch-search-insert-authors (format-string matching-authors 
non-matching-authors)
   ;; Save the match data to avoid interfering with
   ;; `notmuch-search-process-filter'.
   (save-match-data
-(let* ((formatted-authors (format format-string authors))
+(let* ((authors (if (string= "" non-matching-authors)
+   matching-authors
+ (concat matching-authors ", " non-matching-authors)))
+  (formatted-authors (format format-string authors))
   (formatted-sample (format format-string ""))
   (visible-string formatted-authors)
   (invisible-string "")
@@ -703,9 +705,9 @@ non-authors is found, assume that all of the authors match."
(setq visible-string (substring formatted-authors 0 visible-length)
  invisible-string (substring formatted-authors visible-length))
;; If possible, truncate the visible string at a natural
-   ;; break (comma or pipe), as incremental search doesn't
-   ;; match across the visible/invisible border.
-   (when (string-match "\\(.*\\)\\([,|] \\)\\([^,|]*\\)" 
visible-string)
+   ;; break (comma), as incremental search doesn't match
+   ;; across the visible/invisible border.
+   (when (string-match "\\(.*\\)\\(, \\)\\([^,]*\\)" visible-string)
  ;; Second clause is destructive on `visible-string', so
  ;; order is important.
  (setq invisible-string (concat (match-string 3 visible-string)
@@ -721,20 +723,23 @@ non-authors is found, assume that all of the authors 
match."
   ? 

   ;; Use different faces to show matching and non-matching authors.
-  (if (string-match "\\(.*\\)|\\(.*\\)" visible-string)
- ;; The visible string contains both matching and
- ;; non-matching authors.
- (setq visible-string (notmuch-search-author-propertize visible-string)
-   ;; The invisible string must contain only non-matching
-   ;; authors, as the visible-string contains both.
-   invisible-string (propertize invisible-string
-'face 
'notmuch-search-non-matching-authors))
-   ;; The visible string contains only matching authors.
-   (setq visible-string (propertize visible-string
-'face 'notmuch-search-matching-authors)
- ;; The invisible string may contain both matching and
- ;; non-matching authors.
- invisible-string (notmuch-search-author-propertize 
invisible-string)))
+  (let ((visible-length (length visible-string))
+   (matching-length (length matching-authors)))
+
+   (if (> visible-length matching-length)
+   ;; The visible string contains both matching and
+   ;; non-matching authors.
+   (setq visible-string (notmuch-search-author-propertize 
visible-string matching-length)
+ ;; The invisible string must contain only non-matching
+ ;; authors, as the visible-string contains both.
+ invisible-string (propertize invisible-string
+  'face 

[PATCH v1 1/3] search: Seperately report matching and non-matching authors.

2014-10-24 Thread David Edmondson
In addition to the :authors attribute of each search result, include
:authors_matched and :authors_non_matched attributes. Both attributes
are always included. If there are no non-matching authors, the
:authors_non_matched attribute is set to the empty string.
---
 lib/notmuch.h| 34 
 lib/thread.cc| 60 +++-
 notmuch-search.c |  6 ++
 3 files changed, 82 insertions(+), 18 deletions(-)

diff --git a/lib/notmuch.h b/lib/notmuch.h
index dae0416..30ce6c3 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -993,6 +993,40 @@ const char *
 notmuch_thread_get_authors (notmuch_thread_t *thread);

 /**
+ * Get the matched authors of 'thread' as a UTF-8 string.
+ *
+ * The returned string is a comma-separated list of the names of the
+ * authors of mail messages in the query results that belong to this
+ * thread.
+ *
+ * Authors are ordered by date.
+ *
+ * The returned string belongs to 'thread' and as such, should not be
+ * modified by the caller and will only be valid for as long as the
+ * thread is valid, (which is until notmuch_thread_destroy or until
+ * the query from which it derived is destroyed).
+ */
+const char *
+notmuch_thread_get_authors_matched (notmuch_thread_t *thread);
+
+/**
+ * Get the non-matched authors of 'thread' as a UTF-8 string.
+ *
+ * The returned string is a comma-separated list of the names of the
+ * authors of mail messages in the query results that belong to this
+ * thread.
+ *
+ * Authors are ordered by date.
+ *
+ * The returned string belongs to 'thread' and as such, should not be
+ * modified by the caller and will only be valid for as long as the
+ * thread is valid, (which is until notmuch_thread_destroy or until
+ * the query from which it derived is destroyed).
+ */
+const char *
+notmuch_thread_get_authors_non_matched (notmuch_thread_t *thread);
+
+/**
  * Get the subject of 'thread' as a UTF-8 string.
  *
  * The subject is taken from the first message (according to the query
diff --git a/lib/thread.cc b/lib/thread.cc
index 8922403..b344875 100644
--- a/lib/thread.cc
+++ b/lib/thread.cc
@@ -33,6 +33,8 @@ struct visible _notmuch_thread {
 GHashTable *matched_authors_hash;
 GPtrArray *matched_authors_array;
 char *authors;
+char *authors_matched;
+char *authors_non_matched;
 GHashTable *tags;

 /* All messages, oldest first. */
@@ -112,10 +114,11 @@ _thread_add_matched_author (notmuch_thread_t *thread,
 g_ptr_array_add (thread->matched_authors_array, author_copy);
 }

-/* Construct an authors string from matched_authors_array and
- * authors_array. The string contains matched authors first, then
- * non-matched authors (with the two groups separated by '|'). Within
- * each group, authors are listed in date order. */
+/* Construct the authors_matched, authors_non_matched and authors
+ * strings from matched_authors_array and authors_array. The authors
+ * string contains matched authors first, then non-matched authors
+ * (with the two groups separated by '|'). Within each group, authors
+ * are listed in date order. */
 static void
 _resolve_thread_authors_string (notmuch_thread_t *thread)
 {
@@ -123,36 +126,43 @@ _resolve_thread_authors_string (notmuch_thread_t *thread)
 char *author;
 int first_non_matched_author = 1;

-/* First, list all matched authors in date order. */
+/* List all matched authors in date order. */
 for (i = 0; i < thread->matched_authors_array->len; i++) {
author = (char *) g_ptr_array_index (thread->matched_authors_array, i);
-   if (thread->authors)
-   thread->authors = talloc_asprintf (thread, "%s, %s",
-  thread->authors,
-  author);
-   else
-   thread->authors = author;
+   if (thread->authors_matched) {
+   thread->authors_matched = talloc_asprintf (thread, "%s, %s",
+  thread->authors_matched,
+  author);
+   } else {
+   thread->authors_matched = author;
+   }
 }

-/* Next, append any non-matched authors that haven't already appeared. */
+/* List any non-matched authors that haven't already appeared. */
 for (i = 0; i < thread->authors_array->len; i++) {
author = (char *) g_ptr_array_index (thread->authors_array, i);
if (g_hash_table_lookup_extended (thread->matched_authors_hash,
  author, NULL, NULL))
continue;
if (first_non_matched_author) {
-   thread->authors = talloc_asprintf (thread, "%s| %s",
-  thread->authors,
-  author);
+   thread->authors_non_matched = author;
} else {
-   thread->authors = talloc_asprintf (thread, "%s, %s",
-  

[PATCH v1 0/3] Improve the display of matching/non-matching authors.

2014-10-24 Thread David Edmondson

Improve the display of matching/non-matching authors.

Distinguishing between matching and non-matching authors in the emacs
interface is currently done by parsing the :authors attribute of a
search result. If one of the authors uses the pipe symbol (|) in their
'From' address this parsing incorrectly determines the matching and
non-matching authors.

Address this by adding explicit matching and non-matching authors
attributes to the structured output formats.


David Edmondson (3):
  search: Seperately report matching and non-matching authors.
  emacs: Improved display of matching/non-matching authors.
  test: Update tests for :authors_matched and :authors_non_matched.

 emacs/notmuch.el | 64 
 lib/notmuch.h| 34 +++
 lib/thread.cc| 60 -
 notmuch-search.c |  6 +
 test/T160-json.sh|  4 +++
 test/T170-sexp.sh|  4 +--
 test/T470-missing-headers.sh |  4 +++
 7 files changed, 127 insertions(+), 49 deletions(-)

-- 
2.1.1



[PATCH v4 2/2] VIM: Add URI handling

2014-10-24 Thread Ian Main
Add URI handling to the vim client.  You can now press 'enter' by
default and the client will parse the current line and find any 'Part's
or URIs available for opening.  If there are more than one it opens the
one under the cursor or else it opens the only one available.  It also
supports mailto: URI's and will compose a new message when activated.

By default xdg-open is used for everything but mailto: which generally
does the right thing afaict.

Note that this is now dependant on the attachment patch in order to
make the nice 'enter' behavior work for both.

Ian

---
Fixed commit message.

 vim/notmuch.txt |  3 ++-
 vim/notmuch.vim | 76 +++--
 2 files changed, 70 insertions(+), 9 deletions(-)

diff --git a/vim/notmuch.txt b/vim/notmuch.txt
index d5e1ad2..f51b20f 100644
--- a/vim/notmuch.txt
+++ b/vim/notmuch.txt
@@ -74,7 +74,8 @@ I Mark as read (-unread)
 t  Tag (prompted)
 e   Extract attachment on the current 'Part' line or all
attachments if the cursor is elsewhere.
- View attachment on the current 'Part' line.
+ View email part on the current 'Part' line, or open URI under cursor
+or on line.
 s  Search
 p  Save patches
 r  Reply
diff --git a/vim/notmuch.vim b/vim/notmuch.vim
index 1466e50..2f76f55 100644
--- a/vim/notmuch.vim
+++ b/vim/notmuch.vim
@@ -12,7 +12,7 @@ let g:notmuch_folders_maps = {
\ '':'folders_show_search()',
\ 's':  'folders_search_prompt()',
\ '=':  'folders_refresh()',
-   \ 'c':  'compose()',
+   \ 'c':  'compose("")',
\ }

 let g:notmuch_search_maps = {
@@ -25,7 +25,7 @@ let g:notmuch_search_maps = {
\ 's':  'search_search_prompt()',
\ '=':  'search_refresh()',
\ '?':  'search_info()',
-   \ 'c':  'compose()',
+   \ 'c':  'compose("")',
\ }

 let g:notmuch_show_maps = {
@@ -35,13 +35,13 @@ let g:notmuch_show_maps = {
\ 't':  'show_tag("")',
\ 'o':  'show_open_msg()',
\ 'e':  'show_extract_msg()',
-   \ '':'show_view_attachment()',
+   \ '':'show_view_magic()',
\ 's':  'show_save_msg()',
\ 'p':  'show_save_patches()',
\ 'r':  'show_reply()',
\ '?':  'show_info()',
\ '':  'show_next_msg()',
-   \ 'c':  'compose()',
+   \ 'c':  'compose("")',
\ }

 let g:notmuch_compose_maps = {
@@ -63,6 +63,7 @@ let s:notmuch_view_attachment_default = 'xdg-open'
 let s:notmuch_attachment_tmpdir_default = '~/.notmuch/tmp'
 let s:notmuch_folders_count_threads_default = 0
 let s:notmuch_compose_start_insert_default = 1
+let s:notmuch_open_uri_default = 'xdg-open'

 function! s:new_file_buffer(type, fname)
exec printf('edit %s', a:fname)
@@ -141,8 +142,8 @@ function! s:show_reply()
end
 endfunction

-function! s:compose()
-   ruby open_compose
+function! s:compose(to_email)
+   ruby open_compose(VIM::evaluate('a:to_email'))
let b:compose_done = 0
call s:set_map(g:notmuch_compose_maps)
autocmd BufDelete  call s:on_compose_delete()
@@ -155,6 +156,22 @@ function! s:show_info()
ruby vim_puts get_message.inspect
 endfunction

+function! s:show_view_magic()
+   let line = getline(".")
+
+ruby << EOF
+   line = VIM::evaluate('line')
+
+   # Easiest to check for 'Part' types first..
+   match = line.match(/^Part (\d*):/)
+   if match and match.length == 2
+   VIM::command('call s:show_view_attachment()')
+   else
+   VIM::command('call s:show_open_uri()')
+   end
+EOF
+endfunction
+
 function! s:show_view_attachment()
let line = getline(".")
 ruby << EOF
@@ -226,6 +243,45 @@ ruby << EOF
 EOF
 endfunction

+function! s:show_open_uri()
+   let line = getline(".")
+   let pos = getpos(".")
+   let col = pos[2]
+ruby << EOF
+   m = get_message
+   line = VIM::evaluate('line')
+   col = VIM::evaluate('col') - 1
+   uris = URI.extract(line)
+   wanted_uri = nil
+   if uris.length == 1
+   wanted_uri = uris[0]
+   else
+   uris.each do |uri|
+   # Check to see the URI is at the present cursor location
+   idx = line.index(uri)
+   if col >= idx and col <= idx + uri.length
+   wanted_uri = uri
+   break
+   end
+   end
+   end
+
+   if wanted_uri
+   uri = URI.parse(wanted_uri)
+   if uri.class == URI::MailTo
+   vim_puts("Composing new email to #{uri.to}.")
+   VIM::command("call s:compose('#{uri.to}')")
+   else
+   vim_puts("Opening #{uri.to_s}.")
+   

[PATCH v4 1/2] VIM: Add better attachment support

2014-10-24 Thread Ian Main
Change how the notmuch vim client supports attachments:

- For each message part a 'Part : ' is added to the
  header.
- You can then use 'e' to extract the attachment under the cursor or
  use it elsewhere to extract all attachments (the prior behavior)
- You can use 'v' to 'view' the attachment/part using xdg-open by
  default.
- If the message is 'text/html' we include a 'Part:' for the body of
  the message so you can easily view it in a web browser if you so
  choose.

Ian
---

- Fixed commit message
- Fixed documentation

 vim/notmuch.txt |  8 +-
 vim/notmuch.vim | 84 +++--
 2 files changed, 89 insertions(+), 3 deletions(-)

diff --git a/vim/notmuch.txt b/vim/notmuch.txt
index 4374102..d5e1ad2 100644
--- a/vim/notmuch.txt
+++ b/vim/notmuch.txt
@@ -72,6 +72,9 @@ q Quit view
 A  Archive (-inbox -unread)
 I  Mark as read (-unread)
 t  Tag (prompted)
+e   Extract attachment on the current 'Part' line or all
+   attachments if the cursor is elsewhere.
+ View attachment on the current 'Part' line.
 s  Search
 p  Save patches
 r  Reply
@@ -148,6 +151,9 @@ You can also configure your externail mail reader and 
sendemail program:
 >
let g:notmuch_reader = 'mutt -f %s'
let g:notmuch_sendmail = 'sendmail'
-<
+
+You can also configure what probram is used to view attachments:
+
+   let g:notmuch_view_attachment = 'xdg-open'

 vim:tw=78:ts=8:noet:ft=help:
diff --git a/vim/notmuch.vim b/vim/notmuch.vim
index cad9517..1466e50 100644
--- a/vim/notmuch.vim
+++ b/vim/notmuch.vim
@@ -35,6 +35,7 @@ let g:notmuch_show_maps = {
\ 't':  'show_tag("")',
\ 'o':  'show_open_msg()',
\ 'e':  'show_extract_msg()',
+   \ '':'show_view_attachment()',
\ 's':  'show_save_msg()',
\ 'p':  'show_save_patches()',
\ 'r':  'show_reply()',
@@ -58,6 +59,8 @@ let s:notmuch_date_format_default = '%d.%m.%y'
 let s:notmuch_datetime_format_default = '%d.%m.%y %H:%M:%S'
 let s:notmuch_reader_default = 'mutt -f %s'
 let s:notmuch_sendmail_default = 'sendmail'
+let s:notmuch_view_attachment_default = 'xdg-open'
+let s:notmuch_attachment_tmpdir_default = '~/.notmuch/tmp'
 let s:notmuch_folders_count_threads_default = 0
 let s:notmuch_compose_start_insert_default = 1

@@ -152,13 +155,72 @@ function! s:show_info()
ruby vim_puts get_message.inspect
 endfunction

+function! s:show_view_attachment()
+   let line = getline(".")
+ruby << EOF
+   m = get_message
+   line = VIM::evaluate('line')
+
+   match = line.match(/^Part (\d*):/)
+   if match and match.length == 2
+   # Set up the tmpdir
+   tmpdir = VIM::evaluate('g:notmuch_attachment_tmpdir')
+   tmpdir = File.expand_path(tmpdir)
+   Dir.mkdir(tmpdir) unless Dir.exists?(tmpdir)
+
+   p = m.mail.parts[match[1].to_i - 1]
+   if p == nil
+   # Not a multipart message, use the message itself.
+   p = m.mail
+   end
+   if p.filename and p.filename.length > 0
+   filename = p.filename
+   else
+   suffix = ''
+   if p.mime_type == 'text/html'
+   suffix = '.html'
+   end
+   filename = "part-#{match[1]}#{suffix}"
+   end
+
+   # Sanitize just in case..
+   filename.gsub!(/[^0-9A-Za-z.\-]/, '_')
+
+   fullpath = File.expand_path("#{tmpdir}/#{filename}")
+   vim_puts "Viewing attachment #{fullpath}"
+   File.open(fullpath, 'w') do |f|
+   f.write p.body.decoded
+   cmd = VIM::evaluate('g:notmuch_view_attachment')
+   system(cmd, fullpath)
+   end
+   else
+   vim_puts "No attachment on this line."
+   end
+EOF
+endfunction
+
 function! s:show_extract_msg()
+   let line = getline(".")
 ruby << EOF
m = get_message
-   m.mail.attachments.each do |a|
+   line = VIM::evaluate('line')
+
+   # If the user is on a line that has an 'Part'
+   # line, we just extract the one attachment.
+   match = line.match(/^Part (\d*):/)
+   if match and match.length == 2
+   a = m.mail.parts[match[1].to_i - 1]
File.open(a.filename, 'w') do |f|
f.write a.body.decoded
-   print "Extracted '#{a.filename}'"
+   vim_puts "Extracted #{a.filename}"
+   end
+   else
+   # Extract them all..
+   m.mail.attachments.each do |a|
+   File.open(a.filename, 'w') do |f|
+   f.write a.body.decoded
+   vim_puts "Extracted 

[PATCH v3] VIM: Add URI handling

2014-10-24 Thread Ian Main
This patch adds URI handling to the vim client.  You can now press
'enter' by default and the client will parse the current line and find
any 'Part's or URIs available for opening.  If there are more than one
it opens the one under the cursor or else it opens the only one
available.  It also supports mailto: URI's and will compose a new
message when activated.

By default xdg-open is used for everything but mailto: which generally
does the right thing afaict.

Note that this is now dependant on the attachment patch in order to
make the nice 'enter' behavior work for both.

Ian
---

Fix commit message formatting.

 vim/notmuch.txt |  3 ++-
 vim/notmuch.vim | 76 +++--
 2 files changed, 70 insertions(+), 9 deletions(-)

diff --git a/vim/notmuch.txt b/vim/notmuch.txt
index 838a904..5d84fde 100644
--- a/vim/notmuch.txt
+++ b/vim/notmuch.txt
@@ -74,7 +74,8 @@ I Mark as read (-unread)
 t  Tag (prompted)
 e   Extract attachment on the current 'Attachment' line or all
attachments if the cursor is elsewhere.
-v   View attachment on the current 'Attachment' line.
+ View email part on the current 'Part' line, or open URI under cursor
+or on line.
 s  Search
 p  Save patches
 r  Reply
diff --git a/vim/notmuch.vim b/vim/notmuch.vim
index 1466e50..2f76f55 100644
--- a/vim/notmuch.vim
+++ b/vim/notmuch.vim
@@ -12,7 +12,7 @@ let g:notmuch_folders_maps = {
\ '':'folders_show_search()',
\ 's':  'folders_search_prompt()',
\ '=':  'folders_refresh()',
-   \ 'c':  'compose()',
+   \ 'c':  'compose("")',
\ }

 let g:notmuch_search_maps = {
@@ -25,7 +25,7 @@ let g:notmuch_search_maps = {
\ 's':  'search_search_prompt()',
\ '=':  'search_refresh()',
\ '?':  'search_info()',
-   \ 'c':  'compose()',
+   \ 'c':  'compose("")',
\ }

 let g:notmuch_show_maps = {
@@ -35,13 +35,13 @@ let g:notmuch_show_maps = {
\ 't':  'show_tag("")',
\ 'o':  'show_open_msg()',
\ 'e':  'show_extract_msg()',
-   \ '':'show_view_attachment()',
+   \ '':'show_view_magic()',
\ 's':  'show_save_msg()',
\ 'p':  'show_save_patches()',
\ 'r':  'show_reply()',
\ '?':  'show_info()',
\ '':  'show_next_msg()',
-   \ 'c':  'compose()',
+   \ 'c':  'compose("")',
\ }

 let g:notmuch_compose_maps = {
@@ -63,6 +63,7 @@ let s:notmuch_view_attachment_default = 'xdg-open'
 let s:notmuch_attachment_tmpdir_default = '~/.notmuch/tmp'
 let s:notmuch_folders_count_threads_default = 0
 let s:notmuch_compose_start_insert_default = 1
+let s:notmuch_open_uri_default = 'xdg-open'

 function! s:new_file_buffer(type, fname)
exec printf('edit %s', a:fname)
@@ -141,8 +142,8 @@ function! s:show_reply()
end
 endfunction

-function! s:compose()
-   ruby open_compose
+function! s:compose(to_email)
+   ruby open_compose(VIM::evaluate('a:to_email'))
let b:compose_done = 0
call s:set_map(g:notmuch_compose_maps)
autocmd BufDelete  call s:on_compose_delete()
@@ -155,6 +156,22 @@ function! s:show_info()
ruby vim_puts get_message.inspect
 endfunction

+function! s:show_view_magic()
+   let line = getline(".")
+
+ruby << EOF
+   line = VIM::evaluate('line')
+
+   # Easiest to check for 'Part' types first..
+   match = line.match(/^Part (\d*):/)
+   if match and match.length == 2
+   VIM::command('call s:show_view_attachment()')
+   else
+   VIM::command('call s:show_open_uri()')
+   end
+EOF
+endfunction
+
 function! s:show_view_attachment()
let line = getline(".")
 ruby << EOF
@@ -226,6 +243,45 @@ ruby << EOF
 EOF
 endfunction

+function! s:show_open_uri()
+   let line = getline(".")
+   let pos = getpos(".")
+   let col = pos[2]
+ruby << EOF
+   m = get_message
+   line = VIM::evaluate('line')
+   col = VIM::evaluate('col') - 1
+   uris = URI.extract(line)
+   wanted_uri = nil
+   if uris.length == 1
+   wanted_uri = uris[0]
+   else
+   uris.each do |uri|
+   # Check to see the URI is at the present cursor location
+   idx = line.index(uri)
+   if col >= idx and col <= idx + uri.length
+   wanted_uri = uri
+   break
+   end
+   end
+   end
+
+   if wanted_uri
+   uri = URI.parse(wanted_uri)
+   if uri.class == URI::MailTo
+   vim_puts("Composing new email to #{uri.to}.")
+   VIM::command("call s:compose('#{uri.to}')")
+   else
+   vim_puts("Opening 

Looking for the perfect mail client

2014-10-24 Thread Ian Main
Sepp Tannhuber wrote:
> Ian Main  schrieb am 6:28 Freitag, 24.Oktober 2014:
> 
> > I wonder if you'd be willing to give the vim client a go.  We've done a lot
> > of work to it lately and I think it would handle all you listed here.
> For me, it's hard to get familiar with it because I have not found a detailed
> documentation. The README file is not good enough for a stupid person.

Interesting, good feedback.  Is it the usage that is difficult or setup?

> I also doubt that it can render html properly.

Well like any other text based client it uses a text dump of a links or such (I
forget which one).  We have great support for web browser viewing of the email
though if that isn't good enough.

> Nevertheless, I would give it a try if I could find useful documentation.

Let me know if you have suggestions on where it's lacking.  We need a better
installation guide plus a tutorial maybe?

Ian


[PATCH v3.1 3/9] lib: Introduce macros for bit operations

2014-10-24 Thread Austin Clements
These macros help clarify basic bit-twiddling code and are written to
be robust against C undefined behavior of shift operators.
---
 lib/message.cc|  6 +++---
 lib/notmuch-private.h | 11 +++
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/lib/message.cc b/lib/message.cc
index 38bc929..55d2ff6 100644
--- a/lib/message.cc
+++ b/lib/message.cc
@@ -869,7 +869,7 @@ notmuch_bool_t
 notmuch_message_get_flag (notmuch_message_t *message,
  notmuch_message_flag_t flag)
 {
-return message->flags & (1 << flag);
+return NOTMUCH_TEST_BIT (message->flags, flag);
 }

 void
@@ -877,9 +877,9 @@ notmuch_message_set_flag (notmuch_message_t *message,
  notmuch_message_flag_t flag, notmuch_bool_t enable)
 {
 if (enable)
-   message->flags |= (1 << flag);
+   NOTMUCH_SET_BIT (>flags, flag);
 else
-   message->flags &= ~(1 << flag);
+   NOTMUCH_CLEAR_BIT (>flags, flag);
 }

 time_t
diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h
index 36cc12b..b86897c 100644
--- a/lib/notmuch-private.h
+++ b/lib/notmuch-private.h
@@ -63,6 +63,17 @@ NOTMUCH_BEGIN_DECLS
 #define STRNCMP_LITERAL(var, literal) \
 strncmp ((var), (literal), sizeof (literal) - 1)

+/* Robust bit test/set/reset macros */
+#define NOTMUCH_TEST_BIT(val, bit) \
+(((bit) < 0 || (bit) >= CHAR_BIT * sizeof (unsigned long long)) ? 0
\
+ : !!((val) & (1ull << (bit
+#define NOTMUCH_SET_BIT(valp, bit) \
+(((bit) < 0 || (bit) >= CHAR_BIT * sizeof (unsigned long long)) ? *(valp) \
+ : (*(valp) |= (1ull << (bit
+#define NOTMUCH_CLEAR_BIT(valp,  bit) \
+(((bit) < 0 || (bit) >= CHAR_BIT * sizeof (unsigned long long)) ? *(valp) \
+ : (*(valp) &= ~(1ull << (bit
+
 #define unused(x) x __attribute__ ((unused))

 #ifdef __cplusplus
-- 
2.1.0



[PATCH v1 1/3] search: Seperately report matching and non-matching authors.

2014-10-24 Thread Austin Clements
Quoth Mark Walters on Oct 24 at 10:23 am:
> 
> Hi
> 
> I definitely like the idea: some comments below.

Agreed.

> On Fri, 24 Oct 2014, David Edmondson  wrote:
> > In addition to the :authors attribute of each search result, include
> > :authors_matched and :authors_non_matched attributes. Both attributes
> > are always included. If there are no non-matching authors, the
> > :authors_non_matched attribute is set to the empty string.
> 
> What about having both authors_matched and authors_not_matched as lists
> of authors (ie one string for each author)? Then emacs, for example,
> wouldn't try and parse the string back into authors before
> splitting. And authors_non_matched could be an empty list when
> appropriate which seems more natural than the empty string.
> 
> All the above is based on what a client might want in the output rather
> than what is easy or sensible to implement in the C code.

I was going to suggest exactly the same thing.

And I think there's a fairly easy way to do it in C code that will
also prevent library interface bloat: instead of introducing new
library APIs to get at this information, just use the existing
notmuch_thread_get_messages API and construct the matched and
non-matched lists in the CLI.  Doing it in the CLI wouldn't require
the library to export yet another string list structure, which is
always a huge pain (thanks C!), and wouldn't introduce more "helper"
functions into the library API.

I think the only disadvantage to doing this would be some duplication
of the {matched_,}authors_{array,hash} logic into the CLI, but those
are only there to support notmuch_thread_get_authors, which I think is
a huge hack and should go away in the long term.  (And, by doing this
list building in the CLI, we avoid further embellishing the
unnecessary "get thread authors" API).


[PATCH] VIM v2: Add a 'tag all' folder option.

2014-10-24 Thread Ian Main
This one is pretty straightforward and useful too.

Ian

Ian Main wrote:
> This adds the ability to mark an entire folder as read (or any other
> tags you like once you map it).
> 
> This update adds documentation for the command.
> 
> Ian
> ---
>  vim/notmuch.txt |  1 +
>  vim/notmuch.vim | 11 +++
>  2 files changed, 12 insertions(+)
> 
> diff --git a/vim/notmuch.txt b/vim/notmuch.txt
> index 4374102..33cbe6e 100644
> --- a/vim/notmuch.txt
> +++ b/vim/notmuch.txt
> @@ -47,6 +47,7 @@ MAPPINGS
> *notmuch-mappings*
>  Folder view~
>  
>Show selected search
> +AArchive (-inbox -unread) an entire folder
>  sEnter a new search
>  =Refresh
>  cCompose a new mail
> diff --git a/vim/notmuch.vim b/vim/notmuch.vim
> index 331e930..3f2444b 100644
> --- a/vim/notmuch.vim
> +++ b/vim/notmuch.vim
> @@ -11,6 +11,7 @@ let g:loaded_notmuch = "yep"
>  let g:notmuch_folders_maps = {
>   \ '':'folders_show_search()',
>   \ 's':  'folders_search_prompt()',
> + \ 'A':  'folders_tag_all("-inbox -unread")',
>   \ '=':  'folders_refresh()',
>   \ 'c':  'compose()',
>   \ }
> @@ -378,6 +379,16 @@ ruby << EOF
>  EOF
>  endfunction
>  
> +function! s:folders_tag_all(tags)
> +ruby << EOF
> + n = $curbuf.line_number
> + s = $searches[n - 1]
> + t = VIM::evaluate('a:tags')
> + do_tag(s, t)
> +EOF
> + call s:folders_refresh()
> +endfunction
> +
>  function! s:folders()
>   call s:new_buffer('folders')
>   ruby folders_render()
> -- 
> 1.9.3
> 




[PATCH] VIM: Automatically refresh folder screen

2014-10-24 Thread Ian Main
Can I get someone to test this one?  It's pretty simple and useful.

Ian

Ian Main wrote:
> This patch makes the folder screen refresh each time you 'enter' it.
> This way when you read a folder and mark items as read the changes are
> reflected immediately when you return to the folder view.
> 
> Ian
> ---
>  vim/notmuch.vim | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/vim/notmuch.vim b/vim/notmuch.vim
> index 331e930..eb17d57 100644
> --- a/vim/notmuch.vim
> +++ b/vim/notmuch.vim
> @@ -383,6 +383,9 @@ function! s:folders()
>   ruby folders_render()
>   call s:set_menu_buffer()
>   call s:set_map(g:notmuch_folders_maps)
> + autocmd BufEnter,WinEnter,BufWinEnter 
> + \ call s:folders_refresh()
> + augroup END
>  endfunction
>  
>  "" root
> -- 
> 1.9.3
> 




RE: [PATCH] VIM: Automatically refresh folder screen

2014-10-24 Thread Ian Main
Can I get someone to test this one?  It's pretty simple and useful.

Ian

Ian Main wrote:
 This patch makes the folder screen refresh each time you 'enter' it.
 This way when you read a folder and mark items as read the changes are
 reflected immediately when you return to the folder view.
 
 Ian
 ---
  vim/notmuch.vim | 3 +++
  1 file changed, 3 insertions(+)
 
 diff --git a/vim/notmuch.vim b/vim/notmuch.vim
 index 331e930..eb17d57 100644
 --- a/vim/notmuch.vim
 +++ b/vim/notmuch.vim
 @@ -383,6 +383,9 @@ function! s:folders()
   ruby folders_render()
   call s:set_menu_buffer()
   call s:set_map(g:notmuch_folders_maps)
 + autocmd BufEnter,WinEnter,BufWinEnter buffer
 + \ call s:folders_refresh()
 + augroup END
  endfunction
  
   root
 -- 
 1.9.3
 


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


RE: [PATCH] VIM v2: Add a 'tag all' folder option.

2014-10-24 Thread Ian Main
This one is pretty straightforward and useful too.

Ian

Ian Main wrote:
 This adds the ability to mark an entire folder as read (or any other
 tags you like once you map it).
 
 This update adds documentation for the command.
 
 Ian
 ---
  vim/notmuch.txt |  1 +
  vim/notmuch.vim | 11 +++
  2 files changed, 12 insertions(+)
 
 diff --git a/vim/notmuch.txt b/vim/notmuch.txt
 index 4374102..33cbe6e 100644
 --- a/vim/notmuch.txt
 +++ b/vim/notmuch.txt
 @@ -47,6 +47,7 @@ MAPPINGS
 *notmuch-mappings*
  Folder view~
  
  enter  Show selected search
 +AArchive (-inbox -unread) an entire folder
  sEnter a new search
  =Refresh
  cCompose a new mail
 diff --git a/vim/notmuch.vim b/vim/notmuch.vim
 index 331e930..3f2444b 100644
 --- a/vim/notmuch.vim
 +++ b/vim/notmuch.vim
 @@ -11,6 +11,7 @@ let g:loaded_notmuch = yep
  let g:notmuch_folders_maps = {
   \ 'Enter':'folders_show_search()',
   \ 's':  'folders_search_prompt()',
 + \ 'A':  'folders_tag_all(-inbox -unread)',
   \ '=':  'folders_refresh()',
   \ 'c':  'compose()',
   \ }
 @@ -378,6 +379,16 @@ ruby  EOF
  EOF
  endfunction
  
 +function! s:folders_tag_all(tags)
 +ruby  EOF
 + n = $curbuf.line_number
 + s = $searches[n - 1]
 + t = VIM::evaluate('a:tags')
 + do_tag(s, t)
 +EOF
 + call s:folders_refresh()
 +endfunction
 +
  function! s:folders()
   call s:new_buffer('folders')
   ruby folders_render()
 -- 
 1.9.3
 


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


[PATCH] doc: add README.md especially for github

2014-10-24 Thread David Bremner
Apparently README.md overrides README, so this will show up instead of
our generic README on github.

If the user is already on github, then clicking a link for more
information is not a hardship.
---
 README.md | 15 +++
 1 file changed, 15 insertions(+)
 create mode 100644 README.md

diff --git a/README.md b/README.md
new file mode 100644
index 000..ce579d8
--- /dev/null
+++ b/README.md
@@ -0,0 +1,15 @@
+If you're reading this on github.com, this is a read-only mirror of
+the notmuch project.
+
+For more information about the project, see
+
+  http://notmuchmail.org
+
+Please don't send us pull requests on github. If you have a feature
+branch that you want us to look at, use `git send-email` to send to
+notmuch@notmuchmail.org.
+
+For more information about contributing to the project, see
+
+
+  http://notmuchmail.org/contributing/
-- 
2.1.1

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


[PATCH v1 1/3] search: Seperately report matching and non-matching authors.

2014-10-24 Thread David Edmondson
In addition to the :authors attribute of each search result, include
:authors_matched and :authors_non_matched attributes. Both attributes
are always included. If there are no non-matching authors, the
:authors_non_matched attribute is set to the empty string.
---
 lib/notmuch.h| 34 
 lib/thread.cc| 60 +++-
 notmuch-search.c |  6 ++
 3 files changed, 82 insertions(+), 18 deletions(-)

diff --git a/lib/notmuch.h b/lib/notmuch.h
index dae0416..30ce6c3 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -993,6 +993,40 @@ const char *
 notmuch_thread_get_authors (notmuch_thread_t *thread);
 
 /**
+ * Get the matched authors of 'thread' as a UTF-8 string.
+ *
+ * The returned string is a comma-separated list of the names of the
+ * authors of mail messages in the query results that belong to this
+ * thread.
+ *
+ * Authors are ordered by date.
+ *
+ * The returned string belongs to 'thread' and as such, should not be
+ * modified by the caller and will only be valid for as long as the
+ * thread is valid, (which is until notmuch_thread_destroy or until
+ * the query from which it derived is destroyed).
+ */
+const char *
+notmuch_thread_get_authors_matched (notmuch_thread_t *thread);
+
+/**
+ * Get the non-matched authors of 'thread' as a UTF-8 string.
+ *
+ * The returned string is a comma-separated list of the names of the
+ * authors of mail messages in the query results that belong to this
+ * thread.
+ *
+ * Authors are ordered by date.
+ *
+ * The returned string belongs to 'thread' and as such, should not be
+ * modified by the caller and will only be valid for as long as the
+ * thread is valid, (which is until notmuch_thread_destroy or until
+ * the query from which it derived is destroyed).
+ */
+const char *
+notmuch_thread_get_authors_non_matched (notmuch_thread_t *thread);
+
+/**
  * Get the subject of 'thread' as a UTF-8 string.
  *
  * The subject is taken from the first message (according to the query
diff --git a/lib/thread.cc b/lib/thread.cc
index 8922403..b344875 100644
--- a/lib/thread.cc
+++ b/lib/thread.cc
@@ -33,6 +33,8 @@ struct visible _notmuch_thread {
 GHashTable *matched_authors_hash;
 GPtrArray *matched_authors_array;
 char *authors;
+char *authors_matched;
+char *authors_non_matched;
 GHashTable *tags;
 
 /* All messages, oldest first. */
@@ -112,10 +114,11 @@ _thread_add_matched_author (notmuch_thread_t *thread,
 g_ptr_array_add (thread-matched_authors_array, author_copy);
 }
 
-/* Construct an authors string from matched_authors_array and
- * authors_array. The string contains matched authors first, then
- * non-matched authors (with the two groups separated by '|'). Within
- * each group, authors are listed in date order. */
+/* Construct the authors_matched, authors_non_matched and authors
+ * strings from matched_authors_array and authors_array. The authors
+ * string contains matched authors first, then non-matched authors
+ * (with the two groups separated by '|'). Within each group, authors
+ * are listed in date order. */
 static void
 _resolve_thread_authors_string (notmuch_thread_t *thread)
 {
@@ -123,36 +126,43 @@ _resolve_thread_authors_string (notmuch_thread_t *thread)
 char *author;
 int first_non_matched_author = 1;
 
-/* First, list all matched authors in date order. */
+/* List all matched authors in date order. */
 for (i = 0; i  thread-matched_authors_array-len; i++) {
author = (char *) g_ptr_array_index (thread-matched_authors_array, i);
-   if (thread-authors)
-   thread-authors = talloc_asprintf (thread, %s, %s,
-  thread-authors,
-  author);
-   else
-   thread-authors = author;
+   if (thread-authors_matched) {
+   thread-authors_matched = talloc_asprintf (thread, %s, %s,
+  thread-authors_matched,
+  author);
+   } else {
+   thread-authors_matched = author;
+   }
 }
 
-/* Next, append any non-matched authors that haven't already appeared. */
+/* List any non-matched authors that haven't already appeared. */
 for (i = 0; i  thread-authors_array-len; i++) {
author = (char *) g_ptr_array_index (thread-authors_array, i);
if (g_hash_table_lookup_extended (thread-matched_authors_hash,
  author, NULL, NULL))
continue;
if (first_non_matched_author) {
-   thread-authors = talloc_asprintf (thread, %s| %s,
-  thread-authors,
-  author);
+   thread-authors_non_matched = author;
} else {
-   thread-authors = talloc_asprintf (thread, %s, %s,
-   

[PATCH v1 0/3] Improve the display of matching/non-matching authors.

2014-10-24 Thread David Edmondson

Improve the display of matching/non-matching authors.

Distinguishing between matching and non-matching authors in the emacs
interface is currently done by parsing the :authors attribute of a
search result. If one of the authors uses the pipe symbol (|) in their
'From' address this parsing incorrectly determines the matching and
non-matching authors.

Address this by adding explicit matching and non-matching authors
attributes to the structured output formats.


David Edmondson (3):
  search: Seperately report matching and non-matching authors.
  emacs: Improved display of matching/non-matching authors.
  test: Update tests for :authors_matched and :authors_non_matched.

 emacs/notmuch.el | 64 
 lib/notmuch.h| 34 +++
 lib/thread.cc| 60 -
 notmuch-search.c |  6 +
 test/T160-json.sh|  4 +++
 test/T170-sexp.sh|  4 +--
 test/T470-missing-headers.sh |  4 +++
 7 files changed, 127 insertions(+), 49 deletions(-)

-- 
2.1.1

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


[PATCH v1 2/3] emacs: Improved display of matching/non-matching authors.

2014-10-24 Thread David Edmondson
Rather than splitting the :authors attribute, which is error prone,
use the separate :authors_matched and :authors_non_matched attributes.

This improves the display of authors should one of them include a pipe
symbol (|) in their 'from' address.
---
 emacs/notmuch.el | 64 +++-
 1 file changed, 35 insertions(+), 29 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index b44a907..29b6cdc 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -672,22 +672,24 @@ foreground and blue background.
;; Reverse the list so earlier entries take precedence
(reverse notmuch-search-line-faces)))
 
-(defun notmuch-search-author-propertize (authors)
+(defun notmuch-search-author-propertize (authors matching-length)
   Split `authors' into matching and non-matching authors and
 propertize appropriately. If no boundary between authors and
 non-authors is found, assume that all of the authors match.
-  (if (string-match \\(.*\\)|\\(.*\\) authors)
-  (concat (propertize (concat (match-string 1 authors) ,)
- 'face 'notmuch-search-matching-authors)
- (propertize (match-string 2 authors)
- 'face 'notmuch-search-non-matching-authors))
-(propertize authors 'face 'notmuch-search-matching-authors)))
-
-(defun notmuch-search-insert-authors (format-string authors)
+  (let ((match-part (substring authors 0 matching-length))
+   (non-match-part (substring authors matching-length)))
+
+  (concat (propertize match-part 'face 'notmuch-search-matching-authors)
+ (propertize non-match-part 'face 
'notmuch-search-non-matching-authors
+
+(defun notmuch-search-insert-authors (format-string matching-authors 
non-matching-authors)
   ;; Save the match data to avoid interfering with
   ;; `notmuch-search-process-filter'.
   (save-match-data
-(let* ((formatted-authors (format format-string authors))
+(let* ((authors (if (string=  non-matching-authors)
+   matching-authors
+ (concat matching-authors ,  non-matching-authors)))
+  (formatted-authors (format format-string authors))
   (formatted-sample (format format-string ))
   (visible-string formatted-authors)
   (invisible-string )
@@ -703,9 +705,9 @@ non-authors is found, assume that all of the authors match.
(setq visible-string (substring formatted-authors 0 visible-length)
  invisible-string (substring formatted-authors visible-length))
;; If possible, truncate the visible string at a natural
-   ;; break (comma or pipe), as incremental search doesn't
-   ;; match across the visible/invisible border.
-   (when (string-match \\(.*\\)\\([,|] \\)\\([^,|]*\\) 
visible-string)
+   ;; break (comma), as incremental search doesn't match
+   ;; across the visible/invisible border.
+   (when (string-match \\(.*\\)\\(, \\)\\([^,]*\\) visible-string)
  ;; Second clause is destructive on `visible-string', so
  ;; order is important.
  (setq invisible-string (concat (match-string 3 visible-string)
@@ -721,20 +723,23 @@ non-authors is found, assume that all of the authors 
match.
   ? 
 
   ;; Use different faces to show matching and non-matching authors.
-  (if (string-match \\(.*\\)|\\(.*\\) visible-string)
- ;; The visible string contains both matching and
- ;; non-matching authors.
- (setq visible-string (notmuch-search-author-propertize visible-string)
-   ;; The invisible string must contain only non-matching
-   ;; authors, as the visible-string contains both.
-   invisible-string (propertize invisible-string
-'face 
'notmuch-search-non-matching-authors))
-   ;; The visible string contains only matching authors.
-   (setq visible-string (propertize visible-string
-'face 'notmuch-search-matching-authors)
- ;; The invisible string may contain both matching and
- ;; non-matching authors.
- invisible-string (notmuch-search-author-propertize 
invisible-string)))
+  (let ((visible-length (length visible-string))
+   (matching-length (length matching-authors)))
+
+   (if ( visible-length matching-length)
+   ;; The visible string contains both matching and
+   ;; non-matching authors.
+   (setq visible-string (notmuch-search-author-propertize 
visible-string matching-length)
+ ;; The invisible string must contain only non-matching
+ ;; authors, as the visible-string contains both.
+ invisible-string (propertize invisible-string
+  'face 
'notmuch-search-non-matching-authors))

Re: Looking for the perfect mail client

2014-10-24 Thread Sepp Tannhuber
Ian Main im...@redhat.com schrieb am 6:28 Freitag, 24.Oktober 2014:

 I wonder if you'd be willing to give the vim client a go.  We've done a lot
 of work to it lately and I think it would handle all you listed here.
For me, it's hard to get familiar with it because I have not found a detailed
documentation. The README file is not good enough for a stupid person.


I also doubt that it can render html properly.

Nevertheless, I would give it a try if I could find useful documentation.
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH] doc: add README.md especially for github

2014-10-24 Thread Tomi Ollila
On Fri, Oct 24 2014, David Bremner da...@tethera.net wrote:

 Apparently README.md overrides README, so this will show up instead of
 our generic README on github.

 If the user is already on github, then clicking a link for more
 information is not a hardship.

LGTM. although I'd prefer README.rst

Tomi

 ---
  README.md | 15 +++
  1 file changed, 15 insertions(+)
  create mode 100644 README.md

 diff --git a/README.md b/README.md
 new file mode 100644
 index 000..ce579d8
 --- /dev/null
 +++ b/README.md
 @@ -0,0 +1,15 @@
 +If you're reading this on github.com, this is a read-only mirror of
 +the notmuch project.
 +
 +For more information about the project, see
 +
 +  http://notmuchmail.org
 +
 +Please don't send us pull requests on github. If you have a feature
 +branch that you want us to look at, use `git send-email` to send to
 +notmuch@notmuchmail.org.
 +
 +For more information about contributing to the project, see
 +
 +
 +  http://notmuchmail.org/contributing/
 -- 
 2.1.1

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


Re: [PATCH v1 1/3] search: Seperately report matching and non-matching authors.

2014-10-24 Thread Mark Walters

Hi

I definitely like the idea: some comments below.

On Fri, 24 Oct 2014, David Edmondson d...@dme.org wrote:
 In addition to the :authors attribute of each search result, include
 :authors_matched and :authors_non_matched attributes. Both attributes
 are always included. If there are no non-matching authors, the
 :authors_non_matched attribute is set to the empty string.

What about having both authors_matched and authors_not_matched as lists
of authors (ie one string for each author)? Then emacs, for example,
wouldn't try and parse the string back into authors before
splitting. And authors_non_matched could be an empty list when
appropriate which seems more natural than the empty string.

All the above is based on what a client might want in the output rather
than what is easy or sensible to implement in the C code.

 ---
  lib/notmuch.h| 34 
  lib/thread.cc| 60 
 +++-
  notmuch-search.c |  6 ++
  3 files changed, 82 insertions(+), 18 deletions(-)

 diff --git a/lib/notmuch.h b/lib/notmuch.h
 index dae0416..30ce6c3 100644
 --- a/lib/notmuch.h
 +++ b/lib/notmuch.h
 @@ -993,6 +993,40 @@ const char *
  notmuch_thread_get_authors (notmuch_thread_t *thread);
  
  /**
 + * Get the matched authors of 'thread' as a UTF-8 string.
 + *
 + * The returned string is a comma-separated list of the names of the
 + * authors of mail messages in the query results that belong to this
 + * thread.
 + *
 + * Authors are ordered by date.
 + *
 + * The returned string belongs to 'thread' and as such, should not be
 + * modified by the caller and will only be valid for as long as the
 + * thread is valid, (which is until notmuch_thread_destroy or until
 + * the query from which it derived is destroyed).
 + */
 +const char *
 +notmuch_thread_get_authors_matched (notmuch_thread_t *thread);
 +
 +/**
 + * Get the non-matched authors of 'thread' as a UTF-8 string.
 + *
 + * The returned string is a comma-separated list of the names of the
 + * authors of mail messages in the query results that belong to this
 + * thread.
 + *
 + * Authors are ordered by date.
 + *
 + * The returned string belongs to 'thread' and as such, should not be
 + * modified by the caller and will only be valid for as long as the
 + * thread is valid, (which is until notmuch_thread_destroy or until
 + * the query from which it derived is destroyed).
 + */
 +const char *
 +notmuch_thread_get_authors_non_matched (notmuch_thread_t *thread);
 +
 +/**
   * Get the subject of 'thread' as a UTF-8 string.
   *
   * The subject is taken from the first message (according to the query
 diff --git a/lib/thread.cc b/lib/thread.cc
 index 8922403..b344875 100644
 --- a/lib/thread.cc
 +++ b/lib/thread.cc
 @@ -33,6 +33,8 @@ struct visible _notmuch_thread {
  GHashTable *matched_authors_hash;
  GPtrArray *matched_authors_array;
  char *authors;
 +char *authors_matched;
 +char *authors_non_matched;
  GHashTable *tags;
  
  /* All messages, oldest first. */
 @@ -112,10 +114,11 @@ _thread_add_matched_author (notmuch_thread_t *thread,
  g_ptr_array_add (thread-matched_authors_array, author_copy);
  }
  
 -/* Construct an authors string from matched_authors_array and
 - * authors_array. The string contains matched authors first, then
 - * non-matched authors (with the two groups separated by '|'). Within
 - * each group, authors are listed in date order. */
 +/* Construct the authors_matched, authors_non_matched and authors
 + * strings from matched_authors_array and authors_array. The authors
 + * string contains matched authors first, then non-matched authors
 + * (with the two groups separated by '|'). Within each group, authors
 + * are listed in date order. */
  static void
  _resolve_thread_authors_string (notmuch_thread_t *thread)
  {
 @@ -123,36 +126,43 @@ _resolve_thread_authors_string (notmuch_thread_t 
 *thread)
  char *author;
  int first_non_matched_author = 1;
  
 -/* First, list all matched authors in date order. */
 +/* List all matched authors in date order. */
  for (i = 0; i  thread-matched_authors_array-len; i++) {
   author = (char *) g_ptr_array_index (thread-matched_authors_array, i);
 - if (thread-authors)
 - thread-authors = talloc_asprintf (thread, %s, %s,
 -thread-authors,
 -author);
 - else
 - thread-authors = author;
 + if (thread-authors_matched) {
 + thread-authors_matched = talloc_asprintf (thread, %s, %s,
 +thread-authors_matched,
 +author);
 + } else {
 + thread-authors_matched = author;
 + }
  }
  
 -/* Next, append any non-matched authors that haven't already appeared. */
 +/* List any non-matched authors that haven't already appeared. */
 

Re: [PATCH v3 3/4] cli: Extend the search command for --output={sender, recipients}

2014-10-24 Thread Tomi Ollila
On Thu, Oct 23 2014, Mark Walters markwalters1...@gmail.com wrote:

 On Sun, 12 Oct 2014, Michal Sojka sojk...@fel.cvut.cz wrote:
 The new outputs allow printing senders, recipients or both of matching
 messages. The --output option is converted from keyword argument to
 flags argument, which means that the user can use --output=sender and
 --output=recipients simultaneously, to print both. Other combinations
 produce an error.

 ...

 +static void
 +print_address_list (const search_options_t *o, InternetAddressList *list)
 +{
 +InternetAddress *address;
 +int i;
 +
 +for (i = 0; i  internet_address_list_length (list); i++) {
 +address = internet_address_list_get_address (list, i);
 +if (INTERNET_ADDRESS_IS_GROUP (address)) {
 +InternetAddressGroup *group;
 +InternetAddressList *group_list;
 +
 +group = INTERNET_ADDRESS_GROUP (address);
 +group_list = internet_address_group_get_members (group);
 +if (group_list == NULL)
 +continue;
 +
 +print_address_list (o, group_list);
 +} else {
 +InternetAddressMailbox *mailbox;
 +const char *name;
 +const char *addr;
 +char *full_address;
 +
 +mailbox = INTERNET_ADDRESS_MAILBOX (address);
 +
 +name = internet_address_get_name (address);
 +addr = internet_address_mailbox_get_addr (mailbox);
 +
 +if (name  *name)
 +full_address = talloc_asprintf (o-format, %s %s, name, 
 addr);
 +else
 +full_address = talloc_strdup (o-format, addr);
 +
 +if (!full_address) {
 +fprintf (stderr, Error: out of memory\n);
 +break;
 +}
 +o-format-string (o-format, full_address);
 +o-format-separator (o-format);
 +
 +talloc_free (full_address);

 Thinking about this some more how about printing the name and address as
 a structured pair/map (at least for all cases except text/text0 output):
 something like (in JSON)
 [name: John Doe address: john@example.com]

 It seems wrong to me to go to the effort of separating them in the C and
 then combining them in the output.

 This could also help with the questions about uniqueness. If the client
 can get the data ready parsed into name/address then it can deal with
 much of the uniqueness itself.

In that case client can also filter based on some substring, reducing the
memory requirements...


 My preference would be for the default to print one line for each
 distinct full_address, and then any filter-by options to refine from
 there.

Hmm, now I cannot decide whether this or just print out all addresses of
messages, or do this distinct full_address output -- it looks like all
other --output options prints unique lines, but there is potential of 
quite a lot of memory usage there...

... probably the memory usage is not problem there, OOM-killer eventually
does it's job if necessary (!) (but machine may be slow (and trashing) for
a while (just thinking out loud))

(!) but could we have general filter option for search to drop data before
it is even considered for caching! -- maybe later ?


 One other advantage of structuring the output is that it is extensible:
 for example, at some later stage, we could include a count in the map
 allowing the client can pick the most popular variant.

, and in this case notmuch cannot print any output until the full address
list is gathered... :D


 Best wishes

 Mark

Tomi





 +}
 +}
 +}
 +
 +static void
 +print_address_string (const search_options_t *o, const char *recipients)
 +{
 +InternetAddressList *list;
 +
 +if (recipients == NULL)
 +return;
 +
 +list = internet_address_list_parse_string (recipients);
 +if (list == NULL)
 +return;
 +
 +print_address_list (o, list);
 +}
 +
  static int
  do_search_messages (search_options_t *o)
  {
 @@ -266,11 +330,29 @@ do_search_messages (search_options_t *o)
  
  notmuch_filenames_destroy( filenames );
  
 -} else { /* output == OUTPUT_MESSAGES */
 +} else if (o-output == OUTPUT_MESSAGES) {
  format-set_prefix (format, id);
  format-string (format,
  notmuch_message_get_message_id (message));
  format-separator (format);
 +} else {
 +if (o-output  OUTPUT_SENDER) {
 +const char *addrs;
 +
 +addrs = notmuch_message_get_header (message, from);
 +print_address_string (o, addrs);
 +}
 +
 +if (o-output  OUTPUT_RECIPIENTS) {
 +const char *hdrs[] = { to, cc, bcc };
 +const char *addrs;
 +size_t j;
 +
 +for (j = 0; j  ARRAY_SIZE (hdrs); j++) {
 +addrs = notmuch_message_get_header (message, hdrs[j]);
 +print_address_string (o, addrs);
 +}
 +}
  }
  
  notmuch_message_destroy (message);
 @@ -337,7 +419,7 @@ notmuch_search_command (notmuch_config_t 

Re: [PATCH v2] VIM: Add URI handling

2014-10-24 Thread Tomi Ollila
On Fri, Oct 24 2014, Ian Main im...@stemwinder.org wrote:

 Add URI handling to the vim client.  You can now press 'enter' by default and
 the client will parse the current line and find any 'Part's or URIs available
 for opening.  If there are more than one it opens the one under the cursor or
 else it opens the only one available.  It also supports mailto: URI's and will
 compose a new message when activated.

The lines are way too long in this commit message. 72-chars except in cases
where there is no word breaks in the text.

id:1414101891-10714-1-git-send-email-im...@stemwinder.org has also one 
75-character line (and talks about 'This patch ...' which could be changed
too (but is tolerated if not)).

Tomi


 By default xdg-open is used for everything but mailto: which generally
 does the right thing afaict.

 Note that this is now dependant on the attachment patch in order to make
 the nice 'enter' behavior work for both.

 Ian
 ---
  vim/notmuch.txt |  3 ++-
  vim/notmuch.vim | 76 
 +++--
  2 files changed, 70 insertions(+), 9 deletions(-)

 diff --git a/vim/notmuch.txt b/vim/notmuch.txt
 index 838a904..5d84fde 100644
 --- a/vim/notmuch.txt
 +++ b/vim/notmuch.txt
 @@ -74,7 +74,8 @@ I   Mark as read (-unread)
  tTag (prompted)
  e   Extract attachment on the current 'Attachment' line or all
   attachments if the cursor is elsewhere.
 -v   View attachment on the current 'Attachment' line.
 +enter View email part on the current 'Part' line, or open URI under cursor
 +or on line.
  sSearch
  pSave patches
  rReply
 diff --git a/vim/notmuch.vim b/vim/notmuch.vim
 index 1466e50..2f76f55 100644
 --- a/vim/notmuch.vim
 +++ b/vim/notmuch.vim
 @@ -12,7 +12,7 @@ let g:notmuch_folders_maps = {
   \ 'Enter':'folders_show_search()',
   \ 's':  'folders_search_prompt()',
   \ '=':  'folders_refresh()',
 - \ 'c':  'compose()',
 + \ 'c':  'compose()',
   \ }
  
  let g:notmuch_search_maps = {
 @@ -25,7 +25,7 @@ let g:notmuch_search_maps = {
   \ 's':  'search_search_prompt()',
   \ '=':  'search_refresh()',
   \ '?':  'search_info()',
 - \ 'c':  'compose()',
 + \ 'c':  'compose()',
   \ }
  
  let g:notmuch_show_maps = {
 @@ -35,13 +35,13 @@ let g:notmuch_show_maps = {
   \ 't':  'show_tag()',
   \ 'o':  'show_open_msg()',
   \ 'e':  'show_extract_msg()',
 - \ 'Enter':'show_view_attachment()',
 + \ 'Enter':'show_view_magic()',
   \ 's':  'show_save_msg()',
   \ 'p':  'show_save_patches()',
   \ 'r':  'show_reply()',
   \ '?':  'show_info()',
   \ 'Tab':  'show_next_msg()',
 - \ 'c':  'compose()',
 + \ 'c':  'compose()',
   \ }
  
  let g:notmuch_compose_maps = {
 @@ -63,6 +63,7 @@ let s:notmuch_view_attachment_default = 'xdg-open'
  let s:notmuch_attachment_tmpdir_default = '~/.notmuch/tmp'
  let s:notmuch_folders_count_threads_default = 0
  let s:notmuch_compose_start_insert_default = 1
 +let s:notmuch_open_uri_default = 'xdg-open'
  
  function! s:new_file_buffer(type, fname)
   exec printf('edit %s', a:fname)
 @@ -141,8 +142,8 @@ function! s:show_reply()
   end
  endfunction
  
 -function! s:compose()
 - ruby open_compose
 +function! s:compose(to_email)
 + ruby open_compose(VIM::evaluate('a:to_email'))
   let b:compose_done = 0
   call s:set_map(g:notmuch_compose_maps)
   autocmd BufDelete buffer call s:on_compose_delete()
 @@ -155,6 +156,22 @@ function! s:show_info()
   ruby vim_puts get_message.inspect
  endfunction
  
 +function! s:show_view_magic()
 + let line = getline(.)
 +
 +ruby  EOF
 + line = VIM::evaluate('line')
 +
 + # Easiest to check for 'Part' types first..
 + match = line.match(/^Part (\d*):/)
 + if match and match.length == 2
 + VIM::command('call s:show_view_attachment()')
 + else
 + VIM::command('call s:show_open_uri()')
 + end
 +EOF
 +endfunction
 +
  function! s:show_view_attachment()
   let line = getline(.)
  ruby  EOF
 @@ -226,6 +243,45 @@ ruby  EOF
  EOF
  endfunction
  
 +function! s:show_open_uri()
 + let line = getline(.)
 + let pos = getpos(.)
 + let col = pos[2]
 +ruby  EOF
 + m = get_message
 + line = VIM::evaluate('line')
 + col = VIM::evaluate('col') - 1
 + uris = URI.extract(line)
 + wanted_uri = nil
 + if uris.length == 1
 + wanted_uri = uris[0]
 + else
 + uris.each do |uri|
 + # Check to see the URI is at the present cursor location
 + idx = line.index(uri)
 + if col = idx and col = idx + uri.length
 + wanted_uri = uri
 + break
 + end
 + 

Re: [PATCH] doc: add README.md especially for github

2014-10-24 Thread David Bremner
Tomi Ollila tomi.oll...@iki.fi writes:

 On Fri, Oct 24 2014, David Bremner da...@tethera.net wrote:

 Apparently README.md overrides README, so this will show up instead of
 our generic README on github.

 If the user is already on github, then clicking a link for more
 information is not a hardship.

 LGTM. although I'd prefer README.rst


OK, rst version pushed and shows up on github.

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


Re: [PATCH v3 3/4] cli: Extend the search command for --output={sender, recipients}

2014-10-24 Thread David Edmondson
On Thu, Oct 23 2014, Mark Walters wrote:
 Thinking about this some more how about printing the name and address as
 a structured pair/map (at least for all cases except text/text0 output):
 something like (in JSON)
 [name: John Doe address: john@example.com]

 It seems wrong to me to go to the effort of separating them in the C and
 then combining them in the output.

Agreed, this would be convenient.
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH v1 1/3] search: Seperately report matching and non-matching authors.

2014-10-24 Thread David Edmondson
On Fri, Oct 24 2014, Mark Walters wrote:
 What about having both authors_matched and authors_not_matched as lists
 of authors (ie one string for each author)?

That's a sensible idea. I will look into it.

 Then emacs, for example, wouldn't try and parse the string back into
 authors before splitting.

It doesn't really do that other than to decide where to truncate the
visible string. That whole chunk of code is horrible.

  first_non_matched_author = 0;

 I think I would prefer to make this look like the matched case and drop
 the first_non_matched_author stuff.

Agreed, will do.
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH v3 3/4] cli: Extend the search command for --output={sender, recipients}

2014-10-24 Thread Michal Sojka
Hi Mark,

I mostly agree with your points mentioned in this and other your emails.
I'll prepare v4 based on that.

On Wed, Oct 22 2014, Mark Walters wrote:
 On Sun, 12 Oct 2014, Michal Sojka sojk...@fel.cvut.cz wrote:
 The new outputs allow printing senders, recipients or both of matching
 messages. The --output option is converted from keyword argument to
 flags argument, which means that the user can use --output=sender and
 --output=recipients simultaneously, to print both. Other combinations
 produce an error.

 This code based on a patch from Jani Nikula.
 ---
  completion/notmuch-completion.bash |   2 +-
  completion/notmuch-completion.zsh  |   3 +-
  doc/man1/notmuch-search.rst|  22 +++-
  notmuch-search.c   | 110 
 ++---
  test/T090-search-output.sh |  64 +
  5 files changed, 189 insertions(+), 12 deletions(-)

 diff --git a/completion/notmuch-completion.bash 
 b/completion/notmuch-completion.bash
 index 0571dc9..cfbd389 100644
 --- a/completion/notmuch-completion.bash
 +++ b/completion/notmuch-completion.bash
 @@ -294,7 +294,7 @@ _notmuch_search()
  return
  ;;
  --output)
 -COMPREPLY=( $( compgen -W summary threads messages files tags -- 
 ${cur} ) )
 +COMPREPLY=( $( compgen -W summary threads messages files tags 
 sender recipients -- ${cur} ) )
  return
  ;;
  --sort)
 diff --git a/completion/notmuch-completion.zsh 
 b/completion/notmuch-completion.zsh
 index 67a9aba..3e52a00 100644
 --- a/completion/notmuch-completion.zsh
 +++ b/completion/notmuch-completion.zsh
 @@ -52,7 +52,8 @@ _notmuch_search()
_arguments -s : \
  '--max-threads=[display only the first x threads from the search 
 results]:number of threads to show: ' \
  '--first=[omit the first x threads from the search results]:number of 
 threads to omit: ' \
 -'--sort=[sort results]:sorting:((newest-first\:reverse chronological 
 order oldest-first\:chronological order))'
 +'--sort=[sort results]:sorting:((newest-first\:reverse chronological 
 order oldest-first\:chronological order))' \
 +'--output=[select what to output]:output:((summary threads messages 
 files tags sender recipients))'
  }

  _notmuch()
 diff --git a/doc/man1/notmuch-search.rst b/doc/man1/notmuch-search.rst
 index 90160f2..c9d38b1 100644
 --- a/doc/man1/notmuch-search.rst
 +++ b/doc/man1/notmuch-search.rst
 @@ -35,7 +35,7 @@ Supported options for **search** include
  intended for programs that invoke **notmuch(1)** internally. If
  omitted, the latest supported version will be used.

 -``--output=(summary|threads|messages|files|tags)``
 +``--output=(summary|threads|messages|files|tags|sender|recipients)``

  **summary**
  Output a summary of each thread with any message matching
 @@ -78,6 +78,26 @@ Supported options for **search** include
  by null characters (--format=text0), as a JSON array
  (--format=json), or as an S-Expression list (--format=sexp).

 +**sender**
 +Output all addresses from the *From* header that appear on
 +any message matching the search terms, either one per line
 +(--format=text), separated by null characters
 +(--format=text0), as a JSON array (--format=json), or as
 +an S-Expression list (--format=sexp).
 +
 +Note: Searching for **sender** should be much faster than
 +searching for **recipients**, because sender addresses are
 +cached directly in the database whereas other addresses
 +need to be fetched from message files.
 +
 +**recipients**
 +Like **sender** but for addresses from *To*, *Cc* and
 +*Bcc* headers.
 +
 +This option can be given multiple times to combine different
 +outputs. Curently, this is only supported for **sender** and
 +**recipients** outputs.
 +
  ``--sort=``\ (**newest-first**\ \|\ **oldest-first**)
  This option can be used to present results in either
  chronological order (**oldest-first**) or reverse chronological
 diff --git a/notmuch-search.c b/notmuch-search.c
 index 5ac2a26..74588f8 100644
 --- a/notmuch-search.c
 +++ b/notmuch-search.c
 @@ -23,11 +23,14 @@
  #include string-util.h

  typedef enum {
 -OUTPUT_SUMMARY,
 -OUTPUT_THREADS,
 -OUTPUT_MESSAGES,
 -OUTPUT_FILES,
 -OUTPUT_TAGS
 +OUTPUT_SUMMARY  = 1  0,
 +OUTPUT_THREADS  = 1  1,
 +OUTPUT_MESSAGES = 1  2,
 +OUTPUT_FILES= 1  3,
 +OUTPUT_TAGS = 1  4,
 +OUTPUT_SENDER   = 1  5,
 +OUTPUT_RECIPIENTS   = 1  6,
 +OUTPUT_ADDRESSES= OUTPUT_SENDER | OUTPUT_RECIPIENTS,

 I think I would drop the OUTPUT_ADDRESSES enum as the parser no longer
 uses it (and replace the one use by OUTPUT_SENDER | OUTPUT_RECIPIENTS
 below).

As mentioned elsewhere, this is required to suppress the following warning.


Re: [PATCH v1 1/3] search: Seperately report matching and non-matching authors.

2014-10-24 Thread Austin Clements
Quoth Mark Walters on Oct 24 at 10:23 am:
 
 Hi
 
 I definitely like the idea: some comments below.

Agreed.

 On Fri, 24 Oct 2014, David Edmondson d...@dme.org wrote:
  In addition to the :authors attribute of each search result, include
  :authors_matched and :authors_non_matched attributes. Both attributes
  are always included. If there are no non-matching authors, the
  :authors_non_matched attribute is set to the empty string.
 
 What about having both authors_matched and authors_not_matched as lists
 of authors (ie one string for each author)? Then emacs, for example,
 wouldn't try and parse the string back into authors before
 splitting. And authors_non_matched could be an empty list when
 appropriate which seems more natural than the empty string.
 
 All the above is based on what a client might want in the output rather
 than what is easy or sensible to implement in the C code.

I was going to suggest exactly the same thing.

And I think there's a fairly easy way to do it in C code that will
also prevent library interface bloat: instead of introducing new
library APIs to get at this information, just use the existing
notmuch_thread_get_messages API and construct the matched and
non-matched lists in the CLI.  Doing it in the CLI wouldn't require
the library to export yet another string list structure, which is
always a huge pain (thanks C!), and wouldn't introduce more helper
functions into the library API.

I think the only disadvantage to doing this would be some duplication
of the {matched_,}authors_{array,hash} logic into the CLI, but those
are only there to support notmuch_thread_get_authors, which I think is
a huge hack and should go away in the long term.  (And, by doing this
list building in the CLI, we avoid further embellishing the
unnecessary get thread authors API).
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH v3.1 3/9] lib: Introduce macros for bit operations

2014-10-24 Thread Austin Clements
These macros help clarify basic bit-twiddling code and are written to
be robust against C undefined behavior of shift operators.
---
 lib/message.cc|  6 +++---
 lib/notmuch-private.h | 11 +++
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/lib/message.cc b/lib/message.cc
index 38bc929..55d2ff6 100644
--- a/lib/message.cc
+++ b/lib/message.cc
@@ -869,7 +869,7 @@ notmuch_bool_t
 notmuch_message_get_flag (notmuch_message_t *message,
  notmuch_message_flag_t flag)
 {
-return message-flags  (1  flag);
+return NOTMUCH_TEST_BIT (message-flags, flag);
 }
 
 void
@@ -877,9 +877,9 @@ notmuch_message_set_flag (notmuch_message_t *message,
  notmuch_message_flag_t flag, notmuch_bool_t enable)
 {
 if (enable)
-   message-flags |= (1  flag);
+   NOTMUCH_SET_BIT (message-flags, flag);
 else
-   message-flags = ~(1  flag);
+   NOTMUCH_CLEAR_BIT (message-flags, flag);
 }
 
 time_t
diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h
index 36cc12b..b86897c 100644
--- a/lib/notmuch-private.h
+++ b/lib/notmuch-private.h
@@ -63,6 +63,17 @@ NOTMUCH_BEGIN_DECLS
 #define STRNCMP_LITERAL(var, literal) \
 strncmp ((var), (literal), sizeof (literal) - 1)
 
+/* Robust bit test/set/reset macros */
+#define NOTMUCH_TEST_BIT(val, bit) \
+(((bit)  0 || (bit) = CHAR_BIT * sizeof (unsigned long long)) ? 0
\
+ : !!((val)  (1ull  (bit
+#define NOTMUCH_SET_BIT(valp, bit) \
+(((bit)  0 || (bit) = CHAR_BIT * sizeof (unsigned long long)) ? *(valp) \
+ : (*(valp) |= (1ull  (bit
+#define NOTMUCH_CLEAR_BIT(valp,  bit) \
+(((bit)  0 || (bit) = CHAR_BIT * sizeof (unsigned long long)) ? *(valp) \
+ : (*(valp) = ~(1ull  (bit
+
 #define unused(x) x __attribute__ ((unused))
 
 #ifdef __cplusplus
-- 
2.1.0

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


how to put into a journal info about the email sent

2014-10-24 Thread David Belohrad
Dear All,

i'm using org. And I'm using notmuch (that's why I address both mailing
lists). Now, writing an email in everyday bussiness requires a
non-significant time of your workhours. So I'd like to have this event
in my org agenda. So any time I send some email with a given subject,
I'd like to 'automatically' entry the information about it into
e.g. sentmails.org in form of a diary entry, with appropriate tag.

In example:

I'm sending a mail to Tom, with subject 'dealing vme register
mapping'. 

At the moment I send this email (using smtpmail), I'd like an entry in
the sentmails.org as follows:


** 2014-10 October
*** 2014-10-02 Thursday
 dealing vme register mapping   
  :mail:
[[notmuch:id:7a97bb93e66a41878edd4c04fa764...@cernfe03.cern.ch][dealing
vme register mapping]]


I thought that I can use following

(add-hook 'message-send-hook 'mysuperfunction)

to hook on sending and generate a capture entry. In fact this works
pretty well _EXCEPT_ the link to the mail sent. The org-store-link
cannot apparently store a link to an email, which so far was not sent
(and not received?) because it claims that

'org-gnus-store-link: Can not create link: No Gcc header found'

Hence this is pretty fatal for my diary entry. My question is: is there
any way how to link not-yet-sent/received email as an org-link? Or is
there any way to generate Gcc header before the email is sent and use
this header during sending? Or is
there any other way how to put into my agenda sent emails?

many thanks

david


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


Re: [O] how to put into a journal info about the email sent

2014-10-24 Thread David Edmondson
On Fri, Oct 24 2014, Eric Abrahamsen wrote:
 David Belohrad da...@belohrad.ch writes:

 Dear All,

 i'm using org. And I'm using notmuch (that's why I address both mailing
 lists). Now, writing an email in everyday bussiness requires a
 non-significant time of your workhours. So I'd like to have this event
 in my org agenda. So any time I send some email with a given subject,
 I'd like to 'automatically' entry the information about it into
 e.g. sentmails.org in form of a diary entry, with appropriate tag.

 I do something like this in Gnorb, which I'd recommend you use except
 it's mostly Gnus specific.

 I do it in two parts, but you could do it in one. Basically I add a
 function to the `message-header-hook' (which ensures that all the
 message headers have been generated properly).

Does `message-generate-headers-first' not do what you want for this
specific part?

 Obviously the downside is that, without a Gcc: header, org can't
 actually make a real link to the message. It doesn't know where it's
 going to be. However if you know that all your sent messages can be
 reached with a link that looks like notmuch:id#Message-id, then you
 can make that yourself in your org capture template with something like

As you suggest, know the message-id should be good enough to generate a
notmuch link, though you may have to wait for the notmuch index to be
updated for the link to be valid.
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: Looking for the perfect mail client

2014-10-24 Thread Ian Main
Sepp Tannhuber wrote:
 Ian Main im...@redhat.com schrieb am 6:28 Freitag, 24.Oktober 2014:
 
  I wonder if you'd be willing to give the vim client a go.  We've done a lot
  of work to it lately and I think it would handle all you listed here.
 For me, it's hard to get familiar with it because I have not found a detailed
 documentation. The README file is not good enough for a stupid person.

Interesting, good feedback.  Is it the usage that is difficult or setup?

 I also doubt that it can render html properly.

Well like any other text based client it uses a text dump of a links or such (I
forget which one).  We have great support for web browser viewing of the email
though if that isn't good enough.

 Nevertheless, I would give it a try if I could find useful documentation.

Let me know if you have suggestions on where it's lacking.  We need a better
installation guide plus a tutorial maybe?

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


[PATCH v3] VIM: Add URI handling

2014-10-24 Thread Ian Main
This patch adds URI handling to the vim client.  You can now press
'enter' by default and the client will parse the current line and find
any 'Part's or URIs available for opening.  If there are more than one
it opens the one under the cursor or else it opens the only one
available.  It also supports mailto: URI's and will compose a new
message when activated.

By default xdg-open is used for everything but mailto: which generally
does the right thing afaict.

Note that this is now dependant on the attachment patch in order to
make the nice 'enter' behavior work for both.

Ian
---

Fix commit message formatting.

 vim/notmuch.txt |  3 ++-
 vim/notmuch.vim | 76 +++--
 2 files changed, 70 insertions(+), 9 deletions(-)

diff --git a/vim/notmuch.txt b/vim/notmuch.txt
index 838a904..5d84fde 100644
--- a/vim/notmuch.txt
+++ b/vim/notmuch.txt
@@ -74,7 +74,8 @@ I Mark as read (-unread)
 t  Tag (prompted)
 e   Extract attachment on the current 'Attachment' line or all
attachments if the cursor is elsewhere.
-v   View attachment on the current 'Attachment' line.
+enter View email part on the current 'Part' line, or open URI under cursor
+or on line.
 s  Search
 p  Save patches
 r  Reply
diff --git a/vim/notmuch.vim b/vim/notmuch.vim
index 1466e50..2f76f55 100644
--- a/vim/notmuch.vim
+++ b/vim/notmuch.vim
@@ -12,7 +12,7 @@ let g:notmuch_folders_maps = {
\ 'Enter':'folders_show_search()',
\ 's':  'folders_search_prompt()',
\ '=':  'folders_refresh()',
-   \ 'c':  'compose()',
+   \ 'c':  'compose()',
\ }
 
 let g:notmuch_search_maps = {
@@ -25,7 +25,7 @@ let g:notmuch_search_maps = {
\ 's':  'search_search_prompt()',
\ '=':  'search_refresh()',
\ '?':  'search_info()',
-   \ 'c':  'compose()',
+   \ 'c':  'compose()',
\ }
 
 let g:notmuch_show_maps = {
@@ -35,13 +35,13 @@ let g:notmuch_show_maps = {
\ 't':  'show_tag()',
\ 'o':  'show_open_msg()',
\ 'e':  'show_extract_msg()',
-   \ 'Enter':'show_view_attachment()',
+   \ 'Enter':'show_view_magic()',
\ 's':  'show_save_msg()',
\ 'p':  'show_save_patches()',
\ 'r':  'show_reply()',
\ '?':  'show_info()',
\ 'Tab':  'show_next_msg()',
-   \ 'c':  'compose()',
+   \ 'c':  'compose()',
\ }
 
 let g:notmuch_compose_maps = {
@@ -63,6 +63,7 @@ let s:notmuch_view_attachment_default = 'xdg-open'
 let s:notmuch_attachment_tmpdir_default = '~/.notmuch/tmp'
 let s:notmuch_folders_count_threads_default = 0
 let s:notmuch_compose_start_insert_default = 1
+let s:notmuch_open_uri_default = 'xdg-open'
 
 function! s:new_file_buffer(type, fname)
exec printf('edit %s', a:fname)
@@ -141,8 +142,8 @@ function! s:show_reply()
end
 endfunction
 
-function! s:compose()
-   ruby open_compose
+function! s:compose(to_email)
+   ruby open_compose(VIM::evaluate('a:to_email'))
let b:compose_done = 0
call s:set_map(g:notmuch_compose_maps)
autocmd BufDelete buffer call s:on_compose_delete()
@@ -155,6 +156,22 @@ function! s:show_info()
ruby vim_puts get_message.inspect
 endfunction
 
+function! s:show_view_magic()
+   let line = getline(.)
+
+ruby  EOF
+   line = VIM::evaluate('line')
+
+   # Easiest to check for 'Part' types first..
+   match = line.match(/^Part (\d*):/)
+   if match and match.length == 2
+   VIM::command('call s:show_view_attachment()')
+   else
+   VIM::command('call s:show_open_uri()')
+   end
+EOF
+endfunction
+
 function! s:show_view_attachment()
let line = getline(.)
 ruby  EOF
@@ -226,6 +243,45 @@ ruby  EOF
 EOF
 endfunction
 
+function! s:show_open_uri()
+   let line = getline(.)
+   let pos = getpos(.)
+   let col = pos[2]
+ruby  EOF
+   m = get_message
+   line = VIM::evaluate('line')
+   col = VIM::evaluate('col') - 1
+   uris = URI.extract(line)
+   wanted_uri = nil
+   if uris.length == 1
+   wanted_uri = uris[0]
+   else
+   uris.each do |uri|
+   # Check to see the URI is at the present cursor location
+   idx = line.index(uri)
+   if col = idx and col = idx + uri.length
+   wanted_uri = uri
+   break
+   end
+   end
+   end
+
+   if wanted_uri
+   uri = URI.parse(wanted_uri)
+   if uri.class == URI::MailTo
+   vim_puts(Composing new email to #{uri.to}.)
+   VIM::command(call s:compose('#{uri.to}'))
+   else
+   

Re: [PATCH v3] VIM: Add URI handling

2014-10-24 Thread Tomi Ollila
On Fri, Oct 24 2014, Ian Main im...@stemwinder.org wrote:

This patch does not apply on top of notmuchmail master 
(commit 38240d106139da8).

 This patch adds URI handling to the vim client.  You can now press

Although insignificant, I'll start commenting on all sent patches
(that I look into) which talk like 'This patch adds' -- sure it is patch
when email is sent, but in repository it is not so -- so the commit message
should not mention it (but I do not require changing it).

Anyway, I suspect this change will become applicable after some other
change is committed first -- and IMO this could stay as non-stale patch
provided that SomeOne(TM) informs what is the message that contains
changes (or series those) that is required for this message to apply.

BTW: does the content of this change differ much from v1 at
id:1412281423-22441-1-git-send-email-im...@stemwinder.org
or should I re-check (carefully!) that the changes are still OK.


Tomi


 'enter' by default and the client will parse the current line and find
 any 'Part's or URIs available for opening.  If there are more than one
 it opens the one under the cursor or else it opens the only one
 available.  It also supports mailto: URI's and will compose a new
 message when activated.

 By default xdg-open is used for everything but mailto: which generally
 does the right thing afaict.

 Note that this is now dependant on the attachment patch in order to
 make the nice 'enter' behavior work for both.

 Ian
 ---

 Fix commit message formatting.

  vim/notmuch.txt |  3 ++-
  vim/notmuch.vim | 76 
 +++--
  2 files changed, 70 insertions(+), 9 deletions(-)

 diff --git a/vim/notmuch.txt b/vim/notmuch.txt
 index 838a904..5d84fde 100644
 --- a/vim/notmuch.txt
 +++ b/vim/notmuch.txt
 @@ -74,7 +74,8 @@ I   Mark as read (-unread)
  tTag (prompted)
  e   Extract attachment on the current 'Attachment' line or all
   attachments if the cursor is elsewhere.
 -v   View attachment on the current 'Attachment' line.
 +enter View email part on the current 'Part' line, or open URI under cursor
 +or on line.
  sSearch
  pSave patches
  rReply
 diff --git a/vim/notmuch.vim b/vim/notmuch.vim
 index 1466e50..2f76f55 100644
 --- a/vim/notmuch.vim
 +++ b/vim/notmuch.vim
 @@ -12,7 +12,7 @@ let g:notmuch_folders_maps = {
   \ 'Enter':'folders_show_search()',
   \ 's':  'folders_search_prompt()',
   \ '=':  'folders_refresh()',
 - \ 'c':  'compose()',
 + \ 'c':  'compose()',
   \ }
  
  let g:notmuch_search_maps = {
 @@ -25,7 +25,7 @@ let g:notmuch_search_maps = {
   \ 's':  'search_search_prompt()',
   \ '=':  'search_refresh()',
   \ '?':  'search_info()',
 - \ 'c':  'compose()',
 + \ 'c':  'compose()',
   \ }
  
  let g:notmuch_show_maps = {
 @@ -35,13 +35,13 @@ let g:notmuch_show_maps = {
   \ 't':  'show_tag()',
   \ 'o':  'show_open_msg()',
   \ 'e':  'show_extract_msg()',
 - \ 'Enter':'show_view_attachment()',
 + \ 'Enter':'show_view_magic()',
   \ 's':  'show_save_msg()',
   \ 'p':  'show_save_patches()',
   \ 'r':  'show_reply()',
   \ '?':  'show_info()',
   \ 'Tab':  'show_next_msg()',
 - \ 'c':  'compose()',
 + \ 'c':  'compose()',
   \ }
  
  let g:notmuch_compose_maps = {
 @@ -63,6 +63,7 @@ let s:notmuch_view_attachment_default = 'xdg-open'
  let s:notmuch_attachment_tmpdir_default = '~/.notmuch/tmp'
  let s:notmuch_folders_count_threads_default = 0
  let s:notmuch_compose_start_insert_default = 1
 +let s:notmuch_open_uri_default = 'xdg-open'
  
  function! s:new_file_buffer(type, fname)
   exec printf('edit %s', a:fname)
 @@ -141,8 +142,8 @@ function! s:show_reply()
   end
  endfunction
  
 -function! s:compose()
 - ruby open_compose
 +function! s:compose(to_email)
 + ruby open_compose(VIM::evaluate('a:to_email'))
   let b:compose_done = 0
   call s:set_map(g:notmuch_compose_maps)
   autocmd BufDelete buffer call s:on_compose_delete()
 @@ -155,6 +156,22 @@ function! s:show_info()
   ruby vim_puts get_message.inspect
  endfunction
  
 +function! s:show_view_magic()
 + let line = getline(.)
 +
 +ruby  EOF
 + line = VIM::evaluate('line')
 +
 + # Easiest to check for 'Part' types first..
 + match = line.match(/^Part (\d*):/)
 + if match and match.length == 2
 + VIM::command('call s:show_view_attachment()')
 + else
 + VIM::command('call s:show_open_uri()')
 + end
 +EOF
 +endfunction
 +
  function! s:show_view_attachment()
   let line = getline(.)
  ruby  EOF
 @@ -226,6 +243,45 @@ ruby  EOF
  EOF
  endfunction
  
 +function! s:show_open_uri()
 + let line = getline(.)
 + let pos = getpos(.)
 + let col = pos[2]
 +ruby  EOF
 +

[PATCH v4 2/2] VIM: Add URI handling

2014-10-24 Thread Ian Main
Add URI handling to the vim client.  You can now press 'enter' by
default and the client will parse the current line and find any 'Part's
or URIs available for opening.  If there are more than one it opens the
one under the cursor or else it opens the only one available.  It also
supports mailto: URI's and will compose a new message when activated.

By default xdg-open is used for everything but mailto: which generally
does the right thing afaict.

Note that this is now dependant on the attachment patch in order to
make the nice 'enter' behavior work for both.

Ian

---
Fixed commit message.

 vim/notmuch.txt |  3 ++-
 vim/notmuch.vim | 76 +++--
 2 files changed, 70 insertions(+), 9 deletions(-)

diff --git a/vim/notmuch.txt b/vim/notmuch.txt
index d5e1ad2..f51b20f 100644
--- a/vim/notmuch.txt
+++ b/vim/notmuch.txt
@@ -74,7 +74,8 @@ I Mark as read (-unread)
 t  Tag (prompted)
 e   Extract attachment on the current 'Part' line or all
attachments if the cursor is elsewhere.
-enter View attachment on the current 'Part' line.
+enter View email part on the current 'Part' line, or open URI under cursor
+or on line.
 s  Search
 p  Save patches
 r  Reply
diff --git a/vim/notmuch.vim b/vim/notmuch.vim
index 1466e50..2f76f55 100644
--- a/vim/notmuch.vim
+++ b/vim/notmuch.vim
@@ -12,7 +12,7 @@ let g:notmuch_folders_maps = {
\ 'Enter':'folders_show_search()',
\ 's':  'folders_search_prompt()',
\ '=':  'folders_refresh()',
-   \ 'c':  'compose()',
+   \ 'c':  'compose()',
\ }
 
 let g:notmuch_search_maps = {
@@ -25,7 +25,7 @@ let g:notmuch_search_maps = {
\ 's':  'search_search_prompt()',
\ '=':  'search_refresh()',
\ '?':  'search_info()',
-   \ 'c':  'compose()',
+   \ 'c':  'compose()',
\ }
 
 let g:notmuch_show_maps = {
@@ -35,13 +35,13 @@ let g:notmuch_show_maps = {
\ 't':  'show_tag()',
\ 'o':  'show_open_msg()',
\ 'e':  'show_extract_msg()',
-   \ 'Enter':'show_view_attachment()',
+   \ 'Enter':'show_view_magic()',
\ 's':  'show_save_msg()',
\ 'p':  'show_save_patches()',
\ 'r':  'show_reply()',
\ '?':  'show_info()',
\ 'Tab':  'show_next_msg()',
-   \ 'c':  'compose()',
+   \ 'c':  'compose()',
\ }
 
 let g:notmuch_compose_maps = {
@@ -63,6 +63,7 @@ let s:notmuch_view_attachment_default = 'xdg-open'
 let s:notmuch_attachment_tmpdir_default = '~/.notmuch/tmp'
 let s:notmuch_folders_count_threads_default = 0
 let s:notmuch_compose_start_insert_default = 1
+let s:notmuch_open_uri_default = 'xdg-open'
 
 function! s:new_file_buffer(type, fname)
exec printf('edit %s', a:fname)
@@ -141,8 +142,8 @@ function! s:show_reply()
end
 endfunction
 
-function! s:compose()
-   ruby open_compose
+function! s:compose(to_email)
+   ruby open_compose(VIM::evaluate('a:to_email'))
let b:compose_done = 0
call s:set_map(g:notmuch_compose_maps)
autocmd BufDelete buffer call s:on_compose_delete()
@@ -155,6 +156,22 @@ function! s:show_info()
ruby vim_puts get_message.inspect
 endfunction
 
+function! s:show_view_magic()
+   let line = getline(.)
+
+ruby  EOF
+   line = VIM::evaluate('line')
+
+   # Easiest to check for 'Part' types first..
+   match = line.match(/^Part (\d*):/)
+   if match and match.length == 2
+   VIM::command('call s:show_view_attachment()')
+   else
+   VIM::command('call s:show_open_uri()')
+   end
+EOF
+endfunction
+
 function! s:show_view_attachment()
let line = getline(.)
 ruby  EOF
@@ -226,6 +243,45 @@ ruby  EOF
 EOF
 endfunction
 
+function! s:show_open_uri()
+   let line = getline(.)
+   let pos = getpos(.)
+   let col = pos[2]
+ruby  EOF
+   m = get_message
+   line = VIM::evaluate('line')
+   col = VIM::evaluate('col') - 1
+   uris = URI.extract(line)
+   wanted_uri = nil
+   if uris.length == 1
+   wanted_uri = uris[0]
+   else
+   uris.each do |uri|
+   # Check to see the URI is at the present cursor location
+   idx = line.index(uri)
+   if col = idx and col = idx + uri.length
+   wanted_uri = uri
+   break
+   end
+   end
+   end
+
+   if wanted_uri
+   uri = URI.parse(wanted_uri)
+   if uri.class == URI::MailTo
+   vim_puts(Composing new email to #{uri.to}.)
+   VIM::command(call s:compose('#{uri.to}'))
+   else
+   vim_puts(Opening #{uri.to_s}.)
+

[PATCH v4 1/2] VIM: Add better attachment support

2014-10-24 Thread Ian Main
Change how the notmuch vim client supports attachments:

- For each message part a 'Part number: filename' is added to the
  header.
- You can then use 'e' to extract the attachment under the cursor or
  use it elsewhere to extract all attachments (the prior behavior)
- You can use 'v' to 'view' the attachment/part using xdg-open by
  default.
- If the message is 'text/html' we include a 'Part:' for the body of
  the message so you can easily view it in a web browser if you so
  choose.

Ian
---

- Fixed commit message
- Fixed documentation

 vim/notmuch.txt |  8 +-
 vim/notmuch.vim | 84 +++--
 2 files changed, 89 insertions(+), 3 deletions(-)

diff --git a/vim/notmuch.txt b/vim/notmuch.txt
index 4374102..d5e1ad2 100644
--- a/vim/notmuch.txt
+++ b/vim/notmuch.txt
@@ -72,6 +72,9 @@ q Quit view
 A  Archive (-inbox -unread)
 I  Mark as read (-unread)
 t  Tag (prompted)
+e   Extract attachment on the current 'Part' line or all
+   attachments if the cursor is elsewhere.
+enter View attachment on the current 'Part' line.
 s  Search
 p  Save patches
 r  Reply
@@ -148,6 +151,9 @@ You can also configure your externail mail reader and 
sendemail program:
 
let g:notmuch_reader = 'mutt -f %s'
let g:notmuch_sendmail = 'sendmail'
-
+
+You can also configure what probram is used to view attachments:
+
+   let g:notmuch_view_attachment = 'xdg-open'
 
 vim:tw=78:ts=8:noet:ft=help:
diff --git a/vim/notmuch.vim b/vim/notmuch.vim
index cad9517..1466e50 100644
--- a/vim/notmuch.vim
+++ b/vim/notmuch.vim
@@ -35,6 +35,7 @@ let g:notmuch_show_maps = {
\ 't':  'show_tag()',
\ 'o':  'show_open_msg()',
\ 'e':  'show_extract_msg()',
+   \ 'Enter':'show_view_attachment()',
\ 's':  'show_save_msg()',
\ 'p':  'show_save_patches()',
\ 'r':  'show_reply()',
@@ -58,6 +59,8 @@ let s:notmuch_date_format_default = '%d.%m.%y'
 let s:notmuch_datetime_format_default = '%d.%m.%y %H:%M:%S'
 let s:notmuch_reader_default = 'mutt -f %s'
 let s:notmuch_sendmail_default = 'sendmail'
+let s:notmuch_view_attachment_default = 'xdg-open'
+let s:notmuch_attachment_tmpdir_default = '~/.notmuch/tmp'
 let s:notmuch_folders_count_threads_default = 0
 let s:notmuch_compose_start_insert_default = 1
 
@@ -152,13 +155,72 @@ function! s:show_info()
ruby vim_puts get_message.inspect
 endfunction
 
+function! s:show_view_attachment()
+   let line = getline(.)
+ruby  EOF
+   m = get_message
+   line = VIM::evaluate('line')
+
+   match = line.match(/^Part (\d*):/)
+   if match and match.length == 2
+   # Set up the tmpdir
+   tmpdir = VIM::evaluate('g:notmuch_attachment_tmpdir')
+   tmpdir = File.expand_path(tmpdir)
+   Dir.mkdir(tmpdir) unless Dir.exists?(tmpdir)
+
+   p = m.mail.parts[match[1].to_i - 1]
+   if p == nil
+   # Not a multipart message, use the message itself.
+   p = m.mail
+   end
+   if p.filename and p.filename.length  0
+   filename = p.filename
+   else
+   suffix = ''
+   if p.mime_type == 'text/html'
+   suffix = '.html'
+   end
+   filename = part-#{match[1]}#{suffix}
+   end
+
+   # Sanitize just in case..
+   filename.gsub!(/[^0-9A-Za-z.\-]/, '_')
+
+   fullpath = File.expand_path(#{tmpdir}/#{filename})
+   vim_puts Viewing attachment #{fullpath}
+   File.open(fullpath, 'w') do |f|
+   f.write p.body.decoded
+   cmd = VIM::evaluate('g:notmuch_view_attachment')
+   system(cmd, fullpath)
+   end
+   else
+   vim_puts No attachment on this line.
+   end
+EOF
+endfunction
+
 function! s:show_extract_msg()
+   let line = getline(.)
 ruby  EOF
m = get_message
-   m.mail.attachments.each do |a|
+   line = VIM::evaluate('line')
+
+   # If the user is on a line that has an 'Part'
+   # line, we just extract the one attachment.
+   match = line.match(/^Part (\d*):/)
+   if match and match.length == 2
+   a = m.mail.parts[match[1].to_i - 1]
File.open(a.filename, 'w') do |f|
f.write a.body.decoded
-   print Extracted '#{a.filename}'
+   vim_puts Extracted #{a.filename}
+   end
+   else
+   # Extract them all..
+   m.mail.attachments.each do |a|
+   File.open(a.filename, 'w') do |f|
+   f.write a.body.decoded
+   vim_puts Extracted 

Re: [O] how to put into a journal info about the email sent

2014-10-24 Thread Eric Abrahamsen
David Edmondson d...@dme.org writes:

 On Fri, Oct 24 2014, Eric Abrahamsen wrote:
 David Belohrad da...@belohrad.ch writes:

 Dear All,

 i'm using org. And I'm using notmuch (that's why I address both mailing
 lists). Now, writing an email in everyday bussiness requires a
 non-significant time of your workhours. So I'd like to have this event
 in my org agenda. So any time I send some email with a given subject,
 I'd like to 'automatically' entry the information about it into
 e.g. sentmails.org in form of a diary entry, with appropriate tag.

 I do something like this in Gnorb, which I'd recommend you use except
 it's mostly Gnus specific.

 I do it in two parts, but you could do it in one. Basically I add a
 function to the `message-header-hook' (which ensures that all the
 message headers have been generated properly).

 Does `message-generate-headers-first' not do what you want for this
 specific part?

Yeah, I think I looked at that previously. But this thing is going in a
hook anyway, might as well use the hook that *doesn't* require me to
call that function explicitly.

 Obviously the downside is that, without a Gcc: header, org can't
 actually make a real link to the message. It doesn't know where it's
 going to be. However if you know that all your sent messages can be
 reached with a link that looks like notmuch:id#Message-id, then you
 can make that yourself in your org capture template with something like

 As you suggest, know the message-id should be good enough to generate a
 notmuch link, though you may have to wait for the notmuch index to be
 updated for the link to be valid.

Yup, I've got the same issue with nnimap -- you have to wait for the
next sync to get access to the message. So far it hasn't been a problem,
though.

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


[PATCH v2 1/3] search: Separately report matching and non-matching authors.

2014-10-24 Thread David Edmondson
In addition to the 'authors' attribute of each search result, include
'authors_matched' and 'authors_non_matched' attributes. Both
attributes are always included and are formatted as a list of
authors. If there are no matching authors, the 'authors_non_matched'
attribute is set to the empty list.
---
 notmuch-search.c | 105 +++
 1 file changed, 105 insertions(+)

diff --git a/notmuch-search.c b/notmuch-search.c
index bc9be45..18c3b20 100644
--- a/notmuch-search.c
+++ b/notmuch-search.c
@@ -22,6 +22,8 @@
 #include sprinter.h
 #include string-util.h
 
+#include glib.h
+
 typedef enum {
 OUTPUT_SUMMARY,
 OUTPUT_THREADS,
@@ -69,6 +71,105 @@ get_thread_query (notmuch_thread_t *thread,
 return 0;
 }
 
+/* Return a more pleasent rendering of the mail address
+ * `nasty_author'. */
+static const char *
+_nice_author (void *ctx, const char *nasty_author)
+{
+const char *nice_author = NULL;
+
+InternetAddressList *list = internet_address_list_parse_string 
(nasty_author);
+if (list) {
+   InternetAddress *address = internet_address_list_get_address (list, 0);
+   if (address) {
+   nice_author = internet_address_get_name (address);
+   if (nice_author == NULL) {
+   InternetAddressMailbox *mailbox = INTERNET_ADDRESS_MAILBOX 
(address);
+   nice_author = internet_address_mailbox_get_addr (mailbox);
+   }
+   }
+   /* Duplicate the string before `g_object_unref' destroys
+* it. */
+   if (nice_author)
+   nice_author = talloc_strdup (ctx, nice_author);
+
+   g_object_unref (G_OBJECT (list));
+}
+
+if (nice_author)
+   return nice_author;
+else
+   return nasty_author;
+}
+
+static int
+_enumerate_authors (sprinter_t *format,
+notmuch_thread_t *thread)
+{
+notmuch_messages_t *messages;
+GHashTable *matched_hash = g_hash_table_new_full (g_str_hash, g_str_equal, 
NULL, NULL);
+GHashTable *unmatched_hash = g_hash_table_new_full (g_str_hash, 
g_str_equal, NULL, NULL);
+GPtrArray *matched_array = g_ptr_array_new ();
+GPtrArray *unmatched_array = g_ptr_array_new ();
+
+/* Iterate over the messages in the thread collecting matching and
+ * non-matching authors. */
+for (messages = notmuch_thread_get_messages (thread);
+notmuch_messages_valid (messages);
+notmuch_messages_move_to_next (messages))
+{
+   notmuch_message_t *message = notmuch_messages_get (messages);
+   const char *author = _nice_author (thread, notmuch_message_get_header 
(message, from));
+
+   if (author) {
+   GHashTable *hash;
+   GPtrArray *array;
+
+   if (notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH)) 
{
+   hash = matched_hash;
+   array = matched_array;
+   } else {
+   hash = unmatched_hash;
+   array = unmatched_array;
+   }
+
+   if (!g_hash_table_lookup_extended (hash, author, NULL, NULL)) {
+   char *copy = talloc_strdup (thread, author);
+   g_hash_table_insert (hash, copy, NULL);
+   g_ptr_array_add (array, (char *) copy);
+   }
+   }
+}
+
+/* Output the matched authors. */
+unsigned int i;
+format-map_key (format, authors_matched);
+format-begin_list (format);
+for (i = 0; i  matched_array-len; i++)
+   format-string (format, (char *) g_ptr_array_index( matched_array, i));
+format-end (format);
+
+/* Output the non-matched authors, but not if they were seen
+ * already in the matched authors list. */
+format-map_key (format, authors_non_matched);
+format-begin_list (format);
+for (i = 0; i  unmatched_array-len; i++) {
+   char *author = (char *) g_ptr_array_index( unmatched_array, i);
+
+   if (!g_hash_table_lookup_extended (matched_hash, author, NULL, NULL))
+   format-string (format, author);
+}
+format-end (format);
+
+g_hash_table_unref (matched_hash);
+g_hash_table_unref (unmatched_hash);
+
+g_ptr_array_free (matched_array, TRUE);
+g_ptr_array_free (unmatched_array, TRUE);
+
+return 0;
+}
+
 static int
 do_search_threads (sprinter_t *format,
   notmuch_query_t *query,
@@ -152,6 +253,10 @@ do_search_threads (sprinter_t *format,
format-integer (format, total);
format-map_key (format, authors);
format-string (format, authors);
+   if (_enumerate_authors (format, thread)  0) {
+   fprintf (stderr, Out of memory\n);
+   return 1;
+   }
format-map_key (format, subject);
format-string (format, subject);
if (notmuch_format_version = 2) {
-- 
2.1.1

___
notmuch mailing list
notmuch@notmuchmail.org

[PATCH v2 0/3] Improve the display of matching/non-matching authors.

2014-10-24 Thread David Edmondson

Improve the display of matching/non-matching authors.

Distinguishing between matching and non-matching authors in the emacs
interface is currently done by parsing the :authors attribute of a
search result. If one of the authors uses the pipe symbol (|) in their
'From' address this parsing incorrectly determines the matching and
non-matching authors.

Address this by adding explicit matching and non-matching authors
attributes to the structured output formats.

v2:
- Return the matching/non-matching authors as a list.
- More improvements to the code that renders the authors are possible
  (to improve the chosen break between visible and invisible), but a
  planned re-write of the `notmuch-search-result-format' code would
  render that irrelevant.


David Edmondson (3):
  search: Separately report matching and non-matching authors.
  emacs: Improved display of matching/non-matching authors.
  test: Update tests for 'authors_matched' and authors_non_matched'.

 emacs/notmuch.el |  64 ++
 notmuch-search.c | 105 +++
 test/T160-json.sh|   9 
 test/T170-sexp.sh|   4 +-
 test/T470-missing-headers.sh |   8 
 5 files changed, 159 insertions(+), 31 deletions(-)

-- 
2.1.1

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


[PATCH v2 3/3] test: Update tests for 'authors_matched' and authors_non_matched'.

2014-10-24 Thread David Edmondson
---
 test/T160-json.sh| 9 +
 test/T170-sexp.sh| 4 ++--
 test/T470-missing-headers.sh | 8 
 3 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/test/T160-json.sh b/test/T160-json.sh
index c1cf649..0a8df18 100755
--- a/test/T160-json.sh
+++ b/test/T160-json.sh
@@ -25,6 +25,10 @@ test_expect_equal_json $output [{\thread\: \XXX\,
  \matched\: 1,
  \total\: 1,
  \authors\: \Notmuch Test Suite\,
+ \authors_matched\: [
+ \Notmuch Test Suite\
+ ],
+ \authors_non_matched\: [],
  \subject\: \json-search-subject\,
  \query\: [\id:$gen_msg_id\, null],
  \tags\: [\inbox\,
@@ -59,6 +63,11 @@ test_expect_equal_json $output [{\thread\: \XXX\,
  \matched\: 1,
  \total\: 1,
  \authors\: \Notmuch Test Suite\,
+ \authors\: \Notmuch Test Suite\,
+ \authors_matched\: [
+ \Notmuch Test Suite\
+ ],
+ \authors_non_matched\: [],
  \subject\: \json-search-utf8-body-sübjéct\,
  \query\: [\id:$gen_msg_id\, null],
  \tags\: [\inbox\,
diff --git a/test/T170-sexp.sh b/test/T170-sexp.sh
index 667e319..f2a08bf 100755
--- a/test/T170-sexp.sh
+++ b/test/T170-sexp.sh
@@ -19,7 +19,7 @@ test_expect_equal $output :id \${gen_msg_id}\ :match 
t :excluded nil :f
 test_begin_subtest Search message: sexp
 add_message [subject]=\sexp-search-subject\ [date]=\Sat, 01 Jan 2000 
12:00:00 -\ [body]=\sexp-search-message\
 output=$(notmuch search --format=sexp sexp-search-message | 
notmuch_search_sanitize)
-test_expect_equal $output ((:thread \0002\ :timestamp 
946728000 :date_relative \2000-01-01\ :matched 1 :total 1 :authors \Notmuch 
Test Suite\ :subject \sexp-search-subject\ :query (\id:$gen_msg_id\ nil) 
:tags (\inbox\ \unread\)))
+test_expect_equal $output ((:thread \0002\ :timestamp 
946728000 :date_relative \2000-01-01\ :matched 1 :total 1 :authors \Notmuch 
Test Suite\ :authors_matched (\Notmuch Test Suite\) :authors_non_matched () 
:subject \sexp-search-subject\ :query (\id:$gen_msg_id\ nil) :tags 
(\inbox\ \unread\)))
 
 test_begin_subtest Show message: sexp, utf-8
 add_message [subject]=\sexp-show-utf8-body-sübjéct\ [date]=\Sat, 01 Jan 
2000 12:00:00 -\ [body]=\jsön-show-méssage\
@@ -44,7 +44,7 @@ test_expect_equal $output :id \$id\ :match t 
:excluded nil :filename \
 test_begin_subtest Search message: sexp, utf-8
 add_message [subject]=\sexp-search-utf8-body-sübjéct\ [date]=\Sat, 01 
Jan 2000 12:00:00 -\ [body]=\jsön-search-méssage\
 output=$(notmuch search --format=sexp jsön-search-méssage | 
notmuch_search_sanitize)
-test_expect_equal $output ((:thread \0005\ :timestamp 
946728000 :date_relative \2000-01-01\ :matched 1 :total 1 :authors \Notmuch 
Test Suite\ :subject \sexp-search-utf8-body-sübjéct\ :query 
(\id:$gen_msg_id\ nil) :tags (\inbox\ \unread\)))
+test_expect_equal $output ((:thread \0005\ :timestamp 
946728000 :date_relative \2000-01-01\ :matched 1 :total 1 :authors \Notmuch 
Test Suite\ :authors_matched (\Notmuch Test Suite\) :authors_non_matched () 
:subject \sexp-search-utf8-body-sübjéct\ :query (\id:$gen_msg_id\ nil) 
:tags (\inbox\ \unread\)))
 
 
 test_done
diff --git a/test/T470-missing-headers.sh b/test/T470-missing-headers.sh
index cb38301..250a370 100755
--- a/test/T470-missing-headers.sh
+++ b/test/T470-missing-headers.sh
@@ -34,6 +34,10 @@ test_expect_equal_json $output '
 [
 {
 authors: ,
+authors_matched: [
+
+],
+authors_non_matched: [],
 date_relative: 2001-01-05,
 matched: 1,
 subject: ,
@@ -48,6 +52,10 @@ test_expect_equal_json $output '
 },
 {
 authors: Notmuch Test Suite,
+authors_matched: [
+Notmuch Test Suite
+],
+authors_non_matched: [],
 date_relative: 1970-01-01,
 matched: 1,
 subject: ,
-- 
2.1.1

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


[PATCH v2 2/3] emacs: Improved display of matching/non-matching authors.

2014-10-24 Thread David Edmondson
Rather than splitting the :authors attribute, which is error prone,
use the separate :authors_matched and :authors_non_matched attributes.

This improves the display of authors should one of them include a pipe
symbol (|) in their 'from' address.
---
 emacs/notmuch.el | 64 +++-
 1 file changed, 35 insertions(+), 29 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index b44a907..688b37c 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -672,22 +672,24 @@ foreground and blue background.
;; Reverse the list so earlier entries take precedence
(reverse notmuch-search-line-faces)))
 
-(defun notmuch-search-author-propertize (authors)
+(defun notmuch-search-author-propertize (authors matching-length)
   Split `authors' into matching and non-matching authors and
 propertize appropriately. If no boundary between authors and
 non-authors is found, assume that all of the authors match.
-  (if (string-match \\(.*\\)|\\(.*\\) authors)
-  (concat (propertize (concat (match-string 1 authors) ,)
- 'face 'notmuch-search-matching-authors)
- (propertize (match-string 2 authors)
- 'face 'notmuch-search-non-matching-authors))
-(propertize authors 'face 'notmuch-search-matching-authors)))
-
-(defun notmuch-search-insert-authors (format-string authors)
+  (let ((match-part (substring authors 0 matching-length))
+   (non-match-part (substring authors matching-length)))
+
+  (concat (propertize match-part 'face 'notmuch-search-matching-authors)
+ (propertize non-match-part 'face 
'notmuch-search-non-matching-authors
+
+(defun notmuch-search-insert-authors (format-string matching-authors 
non-matching-authors)
   ;; Save the match data to avoid interfering with
   ;; `notmuch-search-process-filter'.
   (save-match-data
-(let* ((formatted-authors (format format-string authors))
+(let* ((authors (if (string=  non-matching-authors)
+   matching-authors
+ (concat matching-authors ,  non-matching-authors)))
+  (formatted-authors (format format-string authors))
   (formatted-sample (format format-string ))
   (visible-string formatted-authors)
   (invisible-string )
@@ -703,9 +705,9 @@ non-authors is found, assume that all of the authors match.
(setq visible-string (substring formatted-authors 0 visible-length)
  invisible-string (substring formatted-authors visible-length))
;; If possible, truncate the visible string at a natural
-   ;; break (comma or pipe), as incremental search doesn't
-   ;; match across the visible/invisible border.
-   (when (string-match \\(.*\\)\\([,|] \\)\\([^,|]*\\) 
visible-string)
+   ;; break (comma), as incremental search doesn't match
+   ;; across the visible/invisible border.
+   (when (string-match \\(.*\\)\\(, \\)\\([^,]*\\) visible-string)
  ;; Second clause is destructive on `visible-string', so
  ;; order is important.
  (setq invisible-string (concat (match-string 3 visible-string)
@@ -721,20 +723,23 @@ non-authors is found, assume that all of the authors 
match.
   ? 
 
   ;; Use different faces to show matching and non-matching authors.
-  (if (string-match \\(.*\\)|\\(.*\\) visible-string)
- ;; The visible string contains both matching and
- ;; non-matching authors.
- (setq visible-string (notmuch-search-author-propertize visible-string)
-   ;; The invisible string must contain only non-matching
-   ;; authors, as the visible-string contains both.
-   invisible-string (propertize invisible-string
-'face 
'notmuch-search-non-matching-authors))
-   ;; The visible string contains only matching authors.
-   (setq visible-string (propertize visible-string
-'face 'notmuch-search-matching-authors)
- ;; The invisible string may contain both matching and
- ;; non-matching authors.
- invisible-string (notmuch-search-author-propertize 
invisible-string)))
+  (let ((visible-length (length visible-string))
+   (matching-length (length matching-authors)))
+
+   (if ( visible-length matching-length)
+   ;; The visible string contains both matching and
+   ;; non-matching authors.
+   (setq visible-string (notmuch-search-author-propertize 
visible-string matching-length)
+ ;; The invisible string must contain only non-matching
+ ;; authors, as the visible-string contains both.
+ invisible-string (propertize invisible-string
+  'face 
'notmuch-search-non-matching-authors))

Re: Looking for the perfect mail client

2014-10-24 Thread Sepp Tannhuber
Ian Main im...@stemwinder.org schrieb am 18:02 Freitag, 24.Oktober 2014:

 Interesting, good feedback.  Is it the usage that is difficult or setup?
Installation was not a problem for me although the files »notmuch.vim« and 
»notmuch.txt« were not found by »make install« for some reason. So I linked
them into the notmuch-vim directory. After that »make install« succeeded.
But the main obstacle is that new users must find by trial and error that
they must type »s« to search, »t« to tag files and so on. It would be very
useful to list all the key bindings and configuration options.
I still don't know how to compose a new message.

 Well like any other text based client it uses a text dump of a links or such 
 (I
 forget which one).
I think »elinks --dump«

 We have great support for web browser viewing of the email
 though if that isn't good enough.
Yes, it's 2014. ;-)

 Let me know if you have suggestions on where it's lacking. 
Okay, thank you so far.
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: Looking for the perfect mail client

2014-10-24 Thread Ian Main
Sepp Tannhuber wrote:
 Ian Main im...@stemwinder.org schrieb am 18:02 Freitag, 24.Oktober 2014:
 
  Interesting, good feedback.  Is it the usage that is difficult or setup?
 Installation was not a problem for me although the files »notmuch.vim« and 
 »notmuch.txt« were not found by »make install« for some reason. So I linked
 them into the notmuch-vim directory. After that »make install« succeeded.
 But the main obstacle is that new users must find by trial and error that
 they must type »s« to search, »t« to tag files and so on. It would be very
 useful to list all the key bindings and configuration options.
 I still don't know how to compose a new message.

https://github.com/imain/notmuch-vim/blob/master/doc/notmuch.txt

Look at the 'MAPPINGS' section.  I think a tutorial might be good though.

  Well like any other text based client it uses a text dump of a links or 
  such (I
  forget which one).
 I think »elinks --dump«
 
  We have great support for web browser viewing of the email
  though if that isn't good enough.
 Yes, it's 2014. ;-)

Time flies!!

  Let me know if you have suggestions on where it's lacking. 
 Okay, thank you so far.

Thanks!


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