]> git.madduck.net Git - etc/mutt.git/blob - .mutt/mutt-notmuch

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

a5b339abca1b3c7696d928f19539a9db079eb130
[etc/mutt.git] / .mutt / mutt-notmuch
1 #!/usr/bin/perl -w
2 #
3 # mutt-notmuch - notmuch (of a) helper for Mutt
4 #
5 # Copyright: © 2011 Stefano Zacchiroli <zack@upsilon.cc> 
6 # License: GNU General Public License (GPL), version 3 or above
7 #
8 # See the bottom of this file for more documentation.
9 # A manpage can be obtained by running "pod2man mutt-notmuch > mutt-notmuch.1"
10
11 use strict;
12 use warnings;
13
14 use File::Path;
15 use Getopt::Long;
16 use Mail::Internet;
17 use Mail::Box::Maildir;
18 use Pod::Usage;
19
20
21 # create an empty maildir (if missing) or empty an existing maildir"
22 sub empty_maildir($) {
23     my ($maildir) = (@_);
24     rmtree($maildir) if (-d $maildir);
25     my $folder = new Mail::Box::Maildir(folder => $maildir,
26                                         create => 1);
27     $folder->close();
28 }
29
30 # search($maildir, $query)
31 # search mails according to $query with notmuch; store results in $maildir
32 sub search($$) {
33     my ($maildir, $query) = @_;
34
35     empty_maildir($maildir);
36     system("notmuch search --output=files $query"
37            . " | sed -e 's: :\\\\ :g'"
38            . " | xargs --no-run-if-empty ln -s -t $maildir/cur/");
39 }
40
41 sub search_action($$@) {
42     my ($interactive, $results_dir, @params) = @_;
43
44     if (! $interactive) {
45         search($results_dir, join(' ', @params));
46     } else {
47         my $query = "";
48         my $done = 0;
49         while (! $done) {
50             print "search ('?' for man): ";
51             chomp($query = <STDIN>);
52             if ($query eq "?") {
53                 system("man notmuch");
54             } elsif ($query eq "") {
55                 $done = 1;      # quit doing nothing
56             } else {
57                 search($results_dir, $query);
58                 $done = 1;
59             }
60         }
61     }
62 }
63
64 sub thread_action(@) {
65     my ($results_dir, @params) = @_;
66
67     my $mail = Mail::Internet->new(\*STDIN);
68     $mail->head->get('message-id') =~ /^<(.*)>$/;       # get message-id
69     my $mid = $1;
70     my $tid = `notmuch search --output=threads id:$mid`;# get thread id
71     chomp($tid);
72
73     search($results_dir, $tid);
74 }
75
76 sub die_usage() {
77     my %podflags = ( "verbose" => 1,
78                     "exitval" => 2 );
79     pod2usage(%podflags);
80 }
81
82 sub main() {
83     my $results_dir = "$ENV{HOME}/.cache/mutt_results";
84     my $interactive = 0;
85     my $help_needed = 0;
86
87     my $getopt = GetOptions(
88         "h|help" => \$help_needed,
89         "o|output-dir=s" => \$results_dir,
90         "p|prompt" => \$interactive);
91     if (! $getopt || $#ARGV < 0) { die_usage() };
92     my ($action, @params) = ($ARGV[0], @ARGV[1..$#ARGV]);
93
94     if ($help_needed) {
95         die_usage();
96     } elsif ($action eq "search" && $#ARGV == 0 && ! $interactive) {
97         print STDERR "Error: no search term provided\n\n";
98         die_usage();
99     } elsif ($action eq "search") {
100         search_action($interactive, $results_dir, @params);
101     } elsif ($action eq "thread") {
102         thread_action($results_dir, @params);
103     } else {
104         die_usage();
105     }
106 }
107
108 main();
109
110 __END__
111
112 =head1 NAME
113
114 mutt-notmuch - notmuch (of a) helper for Mutt
115
116 =head1 SYNOPSIS
117
118 =over
119
120 =item B<mutt-notmuch> [I<OPTION>]... search [I<SEARCH-TERM>]...
121
122 =item B<mutt-notmuch> [I<OPTION>]... thread < I<MAIL>
123
124 =back
125
126 =head1 DESCRIPTION
127
128 mutt-notmuch is a frontend to the notmuch mail indexer capable of populating
129 maildir with search results.
130
131 =head1 OPTIONS
132
133 =over 4
134
135 =item -o DIR
136
137 =item --output-dir DIR
138
139 Store search results as (symlink) messages under maildir DIR. Beware: DIR will
140 be overwritten. (Default: F<~/.cache/mutt_results/>)
141
142 =item -p
143
144 =item --prompt
145
146 Instead of using command line search terms, prompt the user for them (only for
147 "search").
148
149 =item -h
150
151 =item --help
152
153 Show usage information and exit.
154
155 =back
156
157 =head1 INTEGRATION WITH MUTT
158
159 mutt-notmuch can be used to integrate notmuch with the Mutt mail user agent
160 (unsurprisingly, given the name). To that end, you should define the following
161 macros in your F<~/.muttrc> (replacing F<~/bin/mutt-notmuch> for the actual
162 location of mutt-notmuch on your system):
163
164     macro index <F8> \
165           "<enter-command>unset wait_key<enter><shell-escape>~/bin/mutt-notmuch --prompt search<enter><change-folder-readonly>~/.cache/mutt_results<enter>" \
166           "search mail (using notmuch)"
167     macro index <F9> \
168           "<enter-command>unset wait_key<enter><pipe-message>~/bin/mutt-notmuch thread<enter><change-folder-readonly>~/.cache/mutt_results<enter><enter-command>set wait_key<enter>" \
169           "search and reconstruct owning thread (using notmuch)"
170
171 The first macro (activated by <F8>) will prompt the user for notmuch search
172 terms and then jump to a temporary maildir showing search results. The second
173 macro (activated by <F9>) will reconstruct the thread corresponding to the
174 current mail and show it as search results.
175
176 To keep notmuch index current you should then periodically run C<notmuch
177 new>. Depending on your local mail setup, you might want to do that via cron,
178 as a hook triggered by mail retrieval, etc.
179
180 =head1 SEE ALSO
181
182 mutt(1), notmuch(1)
183
184 =head1 AUTHOR
185
186 Copyright: (C) 2011 Stefano Zacchiroli <zack@upsilon.cc>
187
188 License: GNU General Public License (GPL), version 3 or higher
189
190 =cut