nottoomuch-addresses-1.6.sh nottoomuch-addresses-2.0.sh
1#!/bin/sh1#!/bin/sh
2# -*- cperl -*-2# -*- cperl -*-
33
4case $* in ''|--*) exec perl -x "$0" "$@" ;;4case $* in (''|--*) exec perl -x "$0" "$@" ;; (???*) ;; (*) exit 0 ;; esac
5 ???*)
6 grep -aiF "$*" "${XDG_CONFIG_HOME:-$HOME/.config}/nottoomuch/addresses"5grep -aiF "$*" "${XDG_CONFIG_HOME:-$HOME/.config}/nottoomuch/addresses.active"
7esac
8case $? in 0|1) exit 0; esac6case $? in 0|1) exit 0; esac
9exit $?7exit $?
108
11# $ nottoomuch-addresses.sh $9# $ nottoomuch-addresses.sh $
12#10#
13# Created: Thu 27 Oct 2011 17:38:46 EEST too11# Created: Thu 27 Oct 2011 17:38:46 EEST too
14# Last modified: Thu 29 Dec 2011 08:42:42 EET too12# Last modified: Sat 14 Jan 2012 05:45:00 EET too
1513
16# Add this to your notmuch elisp configuration file:14# Add this to your notmuch elisp configuration file:
17#15#
22# Documentation at the end. Encoding: utf-8.20# Documentation at the end. Encoding: utf-8.
2321
24#!perl22#!perl
25# line 2623# line 24
2624
27# HISTORY25# HISTORY
26#
27# Version 2.0 2012-01-14 03:45:00 UTC
28# * Added regexp-based igrores using /regexp/[i] syntax in ignore file.
29# * Changed addresses file header to v4; 'addresses' file now contains all
30# found addresses plus some metainformation added at the end of the file.
31# Filtered (by ignores) address list is now in new 'addresses.active'
32# file and the fgrep code at the beginning now uses this "active" file.
33# Addresses file with header v2 and v3 are supported for reading.
34# * Encoded address content is now recursively decoded.
28#35#
29# Version 1.6 2011-12-29 06:42:42 UTC36# Version 1.6 2011-12-29 06:42:42 UTC
30# * Fixed 'encoded-text' regognization and concatenations, and underscore37# * Fixed 'encoded-text' regognization and concatenations, and underscore
71my $configdir = ($ENV{XDG_CONFIG_HOME}||$ENV{HOME}.'/.config').'/nottoomuch';78my $configdir = ($ENV{XDG_CONFIG_HOME}||$ENV{HOME}.'/.config').'/nottoomuch';
72my $adbpath = $configdir . '/addresses';79my $adbpath = $configdir . '/addresses';
73my $ignpath = $configdir . '/addresses.ignore';80my $ignpath = $configdir . '/addresses.ignore';
81my $actpath = $configdir . '/addresses.active';
7482
75unless (@ARGV)83unless (@ARGV)
76{84{
118 if (-s $adbpath) {126 if (-s $adbpath) {
119 die "Cannot open '$adbpath': $!\n" unless open I, '<', $adbpath;127 die "Cannot open '$adbpath': $!\n" unless open I, '<', $adbpath;
120 sysread I, $_, 18;128 sysread I, $_, 18;
121 # new header: "v3/dd/dd/dd/dd/dd\n" where / == '\t' (but match also v2)129 # new header: "v4/dd/dd/dd/dd/dd\n" where / == '\t' (but match also v2)
122 if (/^v[23]\s(\d\d)\s(\d\d)\s(\d\d)\s(\d\d)\s(\d\d)\n$/) {130 if (/^v[234]\s(\d\d)\s(\d\d)\s(\d\d)\s(\d\d)\s(\d\d)\n$/) {
123 $sstr = "$1$2$3$4$5" - 86400 * 7; # one week extra to (re)look.131 $sstr = "$1$2$3$4$5" - 86400 * 7; # one week extra to (re)look.
124 $sstr = 0 if $sstr < 0;132 $sstr = 0 if $sstr < 0;
125 }133 }
133 print "Creating '$adbpath'. This may take some time...\n";141 print "Creating '$adbpath'. This may take some time...\n";
134 $sstr = '*';142 $sstr = '*';
135 }143 }
136 my %hash;144 my (%ign_hash, @ign_relist);
137 if (-f $ignpath) {145 if (-f $ignpath) {
138 die "Cannot open '$ignpath': $!\n" unless open J, '<', $ignpath;146 die "Cannot open '$ignpath': $!\n" unless open J, '<', $ignpath;
139 while (<J>) {147 while (<J>) {
148 next if /^\s*#/;
149 if (m|^/(.*)/(\w*)\s*$|) {
150 if ($2 eq 'i') {
151 push @ign_relist, qr/$1/i;
152 }
153 else {
154 push @ign_relist, qr/$1/;
155 }
140 chomp;156 }
157 else {
158 s/\s+$/\n/;
141 $hash{$_} = 1;159 $ign_hash{$_} = 1;
160 }
142 }161 }
143 close J;162 close J;
144 }163 }
145164
146 my $sometime = time;165 my $sometime = time;
147 die "Cannot open '$adbpath.new': $!\n" unless open O, '>', $adbpath.'.new';166 die "Cannot open '$adbpath.new': $!\n" unless open O, '>', $adbpath.'.new';
167 die "Cannot open '$actpath.new': $!\n" unless open A, '>', $actpath.'.new';
148 $_ = $sometime; s/(..)\B/$1\t/g;168 $_ = $sometime; s/(..)\B/$1\t/g;
149 print O "v3\t$_\n";169 print O "v4\t$_\n";
150170
151 # The following code block is from Email::Address, almost verbatim.171 # The following code block is from Email::Address, almost verbatim.
152 # The reasons to snip code I instead of just 'use Email::Address' are:172 # The reasons to snip code I instead of just 'use Email::Address' are:
220240
221 # In this particular purpose the cache code used in...241 # In this particular purpose the cache code used in...
222 my %seen; # ...Email::Address is "replaced" by %seen & %hash.242 my %seen; # ...Email::Address is "replaced" by %seen & %hash.
243 my %hash;
223244
224 my $ptime = $sometime + 5;245 my $ptime = $sometime + 5;
225 my $new = 0;246 my $addrcount = 0;
226 $| = 1;247 $| = 1;
227 open P, '-|', qw/notmuch search --sort=newest-first --output=files/, $sstr;248 open P, '-|', qw/notmuch search --sort=newest-first --output=files/, $sstr;
228 while (<P>) {249 while (<P>) {
248269
249 if (time > $ptime) {270 if (time > $ptime) {
250 my $c = qw(/ - \ |)[int ($ptime / 5) % 4];271 my $c = qw(/ - \ |)[int ($ptime / 5) % 4];
251 print "$c addresses gathered: ", $new, "\r";272 print $c, ' active addresses gathered: ', $addrcount, "\r";
252 $ptime += 5;273 $ptime += 5;
253 }274 }
254275
259 s/[ \t]+/ /g;280 s/[ \t]+/ /g;
260 s/\?= =\?/\?==\?/g;281 s/\?= =\?/\?==\?/g;
261 my (@mailboxes) = (/$mailbox/go);282 my (@mailboxes) = (/$mailbox/go);
262 foreach (@mailboxes) {283 L: foreach (@mailboxes) {
263 next if $seen{$_};284 next if $seen{$_};
264 $seen{$_} = 1;285 $seen{$_} = 1;
265286
291 }312 }
292313
293 my @phrase = /($display_name)/o;314 my @phrase = /($display_name)/o;
315 foreach (@phrase) {
294 $phrase[0]=~ s/=\?([^?]+)\?(\w)\?(.*?)\?=/decode_data/ge if @phrase;316 while ( s/=\?([^?]+)\?(\w)\?(.*?)\?=/decode_data/ge ) {};
317 }
295318
296 for ( @phrase, $host, $user, @comments ) {319 for ( @phrase, $host, $user, @comments ) {
297 next unless defined $_;320 next unless defined $_;
321 next if defined $hash{$_};344 next if defined $hash{$_};
322 print O $_;345 print O $_;
323 $hash{$_} = 1;346 $hash{$_} = 1;
347 next if defined $ign_hash{$_};
348 foreach my $re (@ign_relist) {
349 next L if $_ =~ $re;
350 }
351 print A $_;
324 $new++;352 $addrcount++;
325 }353 }
326 # --8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<--354 # --8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<--
327 }355 }
329 }357 }
330 undef %seen;358 undef %seen;
331 close P;359 close P;
332 my $all = $new;360 my $oldaddrcount = 0;
333 if ($sstr ne '*') {361 if ($sstr ne '*') {
334 my $dropped = 0;362 L: while (<I>) {
363 last if /^---/;
364 next if defined $hash{$_};
365 print O $_;
366 next if defined $ign_hash{$_};
367 foreach my $re (@ign_relist) {
368 next L if $_ =~ $re;
369 }
370 print A $_;
371 $addrcount++;
372 }
335 while (<I>) {373 while (<I>) {
336 $dropped++, next unless /@/ and ! defined $hash{$_};374 $oldaddrcount = ($1 + 0), next if /^active:\s+(\d+)\s*$/;
337 $all++;
338 print O $_;
339 }375 }
340 close I;376 close I;
341 $new -= $dropped;
342 }377 }
378 print O "---\n";
379 print O "active: ", $addrcount, "\n";
343 close O;380 close O;
381 close A;
344 undef %hash;382 undef %hash;
345 #link $adbpath, $adbpath . '.' . $sometime;383 #link $adbpath, $adbpath . '.' . $sometime;
346 rename $adbpath . '.new', $adbpath or384 rename $adbpath . '.new', $adbpath or
347 die "Cannot rename '$adbpath.new' to '$adbpath': $!\n";385 die "Cannot rename '$adbpath.new' to '$adbpath': $!\n";
386 rename $actpath . '.new', $actpath or
387 die "Cannot rename '$actpath.new' to '$actpath': $!\n";
388 if ($oldaddrcount or $sstr eq '*') {
348 $sometime = time - $sometime;389 $sometime = time - $sometime;
390 my $new = $addrcount - $oldaddrcount;
349 print "Added $new addresses in $sometime seconds. ";391 print "Added $new active addresses in $sometime seconds.\n";
392 }
350 print "Total number of addresses: $all.\n";393 print "Total number of active addresses: $addrcount.\n";
351 exit 0;394 exit 0;
352}395}
353396
369412
370=head1 VERSION413=head1 VERSION
371414
3721.6 (2011-12-29)4152.0 (2011-01-14)
373416
374=head1 OPTIONS417=head1 OPTIONS
375418
415saving these 2 files the moved addresses will not reappear in458saving these 2 files the moved addresses will not reappear in
416B<addresses> file again.459B<addresses> file again.
417460
461Version 2.0 of nottoomuch-addresses.sh supports regular expressions in
462ignore file. Lines in format I</regexp/> or I</regexp/i> defines (perl)
463I<regexp>s which are used to match email addresses for ignoring. The
464I</i> format makes regular expression case-insensitive -- although this
465is only applied to characters in ranges I<A-Z> and I<a-z>. Remember that
466I</^.*regexp.*$/> and I</regexp/> provides same set of matching lines.
467
418=head1 LICENSE468=head1 LICENSE
419469
420This program uses code from Email::Address perl module. Inclusion of470This program uses code from Email::Address perl module. Inclusion of

Generated by htmldiff.sh