From: Adam Spiers <orgmode@adamspiers.org>
To: emacs-orgmode@gnu.org
Subject: Integration of Org mode and mairix (was: ... and Gnus)
Date: Fri, 20 Jul 2007 17:08:33 +0100 [thread overview]
Message-ID: <20070720160833.GD28297@atlantic.linksys.moosehall> (raw)
In-Reply-To: <m3lkdec8ej.fsf@cerebro.fsfeurope.org>
[-- Attachment #1: Type: text/plain, Size: 2765 bytes --]
On Wed, Jul 18, 2007 at 12:29:08PM +0200, Georg C. F. Greve wrote:
> Since I know which group I am asking to move things to, being able to
> link to the message ID directly would definitely solve the problem, and
> maybe even more elegantly, as it should be robust against resorting the
> mail group.
Funnily enough, I implemented exactly this idea about 15 months ago,
except that my implementation uses mairix (the mail indexer), and is
mode-agnostic. I use mutt as my mail reader, so the usage workflow is
this:
1. Read a mail which requires a TODO action
2. Hit a keypress combo which triggers a Perl script acting on the
mail to extract the Message-ID and dump it to a predictably-named
temporary file, which can be considered as a dedicated clipboard.
3. In emacs, hit another keypress combo to yank the contents of the
clipboard into a new item in my TODO.org file as a link, e.g.:
* NEXTACTION [#B] read this email about blah blah
<mairix://m:4679BAC0.4057103@spiers.net>
4. Archive the mail anywhere, safe in the knowledge that later on,
moving the point over this mairix:// link within emacs and
pressing another keypress combo will perform a mairix search for
this Message-ID, and launch a mutt window displaying the mail,
regardless of wherever it's been archived.
At first I thought that this was just a cute little trick, but it's
proved itself to be an absolute god-send:
- emails can be converted into TODO items and cleared out of my
inbox within seconds. Anyone trying to follow GTD already knows
the huge value of being able to quickly process an inbox.
- Having mail linked to like this (and in general having it indexed
and instantly searchable) means that I no longer have to make sure
mails are carefully archived in the right folder according to
topic. This used to be very time-consuming, and didn't always
work, e.g. when a single mail covered more than one topic. These
days, I simply have one archive folder per month to keep folder
sizes manageable.
- The URL-like syntax allows me to store hyperlinks which trigger
more complex queries rather than just searching for a single
message id, e.g.
<mairix://s:orgmode>
would find all mails with 'orgmode' in the subject.
I made it mode-agnostic because I also wanted to be able to link to
mails from within source code comments, log files, muse-mode, etc.
Having said that, if there is a generic mode-agnostic hyperlinking
framework in emacs, I really should have my wrist slapped for
reinventing the wheel. In particular, I do wish that org-mode and
muse-mode had the same hyperlinking syntax ...
Anyway, source code for my hacks attached.
Cheers,
Adam
[-- Attachment #2: as-gtd.el --]
[-- Type: text/plain, Size: 2258 bytes --]
;; Things to help me with Getting Things Done.
(defvar as-mairix-links-clipboard "~/.clip-mairix"
"Pseudo-clipboard file where mairix URLs get copied to.")
(defvar as-mairix-results-folder "~/mail/mairix"
"Folder where mairix writes results.")
(defvar as-mairix-link-viewer-command "mairix '%search%' && xterm -title 'mairix search: %search%' -e 'unset COLUMNS; mutt -F ~/.mutt/work -f %folder% -e \"push <display-message>\"' &"
"Command to view messages linked to by 'mairix://...' links.")
(defun as-mairix-yank-links ()
"Yank from file defined by `as-mairix-links-clipboard'."
(interactive)
(let ((bytes (cadr (insert-file-contents
(expand-file-name as-mairix-links-clipboard)))))
(forward-char bytes)
(save-excursion
(forward-char -1)
(if (looking-at "\n")
(delete-char 1)))))
(defun as-mairix-search-at-point ()
"Return the start and end points of a mairix link at the current
point. The result is a paired list of character positions for a
mairix link located at the current point in the current buffer."
(save-excursion
(if (looking-at "<mairix://")
(forward-char 1)
(skip-chars-backward "^<"))
(if (looking-at "mairix://\\([^>]+?\\)>")
(match-string 1)
nil)))
(defun as-mairix-view-link-at-point (show-async-buf)
"View the 'mairix://...' link at the point using the shell command
defined by `as-mairix-link-viewer-command'."
(interactive "P")
(let ((message-id (as-mairix-search-at-point)))
(or message-id (error "No mairix URL found at point"))
(let ((cmd as-mairix-link-viewer-command))
(while (string-match "%search%" cmd)
(setq cmd (replace-match message-id 'fixedcase 'literal cmd)))
(while (string-match "%folder%" cmd)
(setq cmd (replace-match as-mairix-results-folder 'fixedcase 'literal cmd)))
;; By default, async shell-command invocations display the temp
;; buffer, which is annoying here. We choose a deterministic
;; buffer name so we can hide it again immediately.,
(let ((tmpbufname (generate-new-buffer-name " *mairix-view*")))
(shell-command cmd tmpbufname)
(or show-async-buf
(delete-windows-on (get-buffer tmpbufname)))))))
[-- Attachment #3: mairix-copy-message --]
[-- Type: text/plain, Size: 1741 bytes --]
#!/usr/bin/perl
#
# extract headers from mail stream on STDIN.
# For use with mutt, .e.g
#
# macro index "\em" ":set pipe_decode=no\n<pipe-message>mairix-copy-message ids\n:set pipe_decode\n"
use strict;
use warnings;
use Getopt::Long;
use Mairix;
my %opts;
GetOptions(
\%opts,
'help',
'ids', 'threads',
) or usage();
usage() if @ARGV or $opts{help};
sub usage {
warn @_, "\n" if @_;
(my $me = $0) =~ s,.*/,,;
die <<EOUSAGE;
Usage: cat mail1 [mail2 ...] | $me [--ids] [--threads]
Options:
-h, --help Show this help
--ids Extract Message-ID header(s)
--threads Extract thread subject(s)
EOUSAGE
}
my @found;
my $subject;
while (<STDIN>) {
chomp;
if ($opts{ids} && /^message-id:\s+(.+)\s*$/i) {
my $value = $1;
if ($value =~ /^<(.+)>$/) {
push @found, "m:$1";
}
else {
warn "WARNING: Message-ID '$value' violates RFC.\n";
push @found, "m:$value";
}
next;
}
if ($opts{threads}) {
if ($subject) {
if (/^\s+(.+)/) {
# continuation line
$subject .= " " . $1;
next;
}
# next header
push @found, join ' ', Mairix::subject_query($subject);
undef $subject;
next;
}
elsif (/^Subject:\s+(.+)\s*$/i) {
$subject = $1;
}
}
}
# xclip doesn't work :-(
if (! @found) {
warn "No Message-ID header found! Press a key...\n";
my $read_key = <STDIN>;
exit 1;
}
open(FAKECLIP, ">$ENV{HOME}/.clip-mairix")
or die "Couldn't open($ENV): $!\n";
foreach (@found) {
my $URL = "<mairix://$_>";
print FAKECLIP "$URL\n";
print "$URL\n";
}
close(FAKECLIP);
# print "Press enter to continue ... ";
# my $read_key = <STDIN>;
sleep 1;
exit 0; # for mutt wait_key
[-- Attachment #4: Mairix.pm --]
[-- Type: text/plain, Size: 1289 bytes --]
package Mairix;
=head1 NAME
Mairix - helpers for mairix CLI utilities
=head1 SYNOPSIS
TODO
=head1 DESCRIPTION
TODO
=cut
use strict;
use warnings;
=head2 subject_query
Turn a subject into a mairix query to retrieve mail's with related
subjects.
=cut
sub subject_query {
my ($subject) = @_;
my $query = normalize_subject($subject);
$query =~ s/^\s+//g;
$query =~ s/\s+$//g;
my @tokens = split /\s+|[^\w]+/, $query;
# return map "s:$_", grep { length($_) && /\w/ } @tokens;
return 's:' . join ",", grep { length($_) && /\w/ } @tokens;
}
=head2 normalize_subject
Trim a subject of cruft accumulated as a result of replying
to/forwarding the message etc.
=cut
sub normalize_subject {
my ($original) = @_;
my $new = $original;
1 while $new =~ s/^\s+//
or $new =~ s/\s+$//
or $new =~ s/^((Re|Fwd|Aw|Antw|Svar):|\(Fwd\))\s*//i
or $new =~ s/^\[Fwd:\s*(.+)\s*\]$/$1/i
or $new =~ s/\(Fwd\)$//i
or $new =~ s/^(FYI|FYEO|FCP|AHOD|F)(:|\b)//i
or $new =~ s/^\s*\[[\w -]+\]\s+//i
or $new =~ s/\bv\d+(\.\d+)*(\b|$)//i;
if ($new ne $original) {
warn "Normalized '$original' to '$new'\n";
}
return $new;
}
=head1 BUGS
None, zero, nada etc.
=head1 SEE ALSO
L<mairix-wrapper>, L<mairix-copy-message>
=cut
1;
[-- Attachment #5: Type: text/plain, Size: 149 bytes --]
_______________________________________________
Emacs-orgmode mailing list
Emacs-orgmode@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-orgmode
next prev parent reply other threads:[~2007-07-20 16:08 UTC|newest]
Thread overview: 65+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-07-17 19:22 Integration of Org mode and Gnus Georg C. F. Greve
2007-07-18 0:22 ` Jason F. McBrayer
2007-07-18 8:03 ` Georg C. F. Greve
2007-07-18 10:04 ` Bastien
2007-07-18 10:29 ` Georg C. F. Greve
2007-07-20 16:08 ` Adam Spiers [this message]
2007-07-22 23:15 ` Integration of Org mode and mairix Georg C. F. Greve
2007-07-23 2:24 ` Is it any function similar to appoinment alert in the planner mode? brianjiang
2007-07-23 12:38 ` Bernt Hansen
2007-07-25 19:15 ` Bastien Guerry
2007-07-26 7:23 ` Bastien
2007-07-27 5:17 ` brianjiang
2007-08-07 0:05 ` Bastien
2007-08-07 17:13 ` Bastien
2007-08-21 2:37 ` william
2007-07-24 14:38 ` Integration of Org mode and mairix Bastien
2007-07-30 14:02 ` Georg C. F. Greve
2007-07-30 16:02 ` Bastien
2007-07-30 16:31 ` Leo
2007-07-30 17:26 ` Bastien
2007-08-05 1:32 ` Xiao-Yong Jin
2007-07-31 15:52 ` Jason F. McBrayer
2007-07-31 16:56 ` Xiao-Yong Jin
2007-07-31 17:19 ` Georg C. F. Greve
2007-08-05 1:40 ` Xiao-Yong Jin
2007-07-31 18:43 ` Bastien
2007-08-01 14:52 ` Jason F. McBrayer
2007-08-01 16:59 ` Bastien
2007-08-05 1:44 ` Xiao-Yong Jin
2007-08-05 10:20 ` Georg C. F. Greve
2007-08-07 17:54 ` Bastien
2007-08-10 6:56 ` Carsten Dominik
2007-08-14 11:29 ` Adam Spiers
2007-08-15 17:46 ` Carsten Dominik
2007-08-21 12:38 ` Carsten Dominik
2007-08-14 22:54 ` Steven Lumos
2007-08-15 17:46 ` Carsten Dominik
2007-08-16 18:48 ` Steven Lumos
2007-09-23 15:44 ` Georg C. F. Greve
2007-09-23 18:12 ` Carsten Dominik
2007-09-23 21:50 ` Georg C. F. Greve
2007-09-23 22:05 ` Carsten Dominik
2007-09-24 17:38 ` Georg C. F. Greve
2007-09-25 14:41 ` Carsten Dominik
2007-09-25 22:25 ` Georg C. F. Greve
2007-09-25 22:38 ` Carsten Dominik
2007-07-18 11:04 ` Integration of Org mode and Gnus Jason F. McBrayer
2007-07-18 12:01 ` Bastien
2007-07-18 12:57 ` Jason F. McBrayer
2007-07-18 13:08 ` Georg C. F. Greve
2007-07-18 15:39 ` Bastien
2007-07-18 19:39 ` Georg C. F. Greve
2007-07-18 22:06 ` Bastien
2007-07-19 15:29 ` Georg C. F. Greve
2007-07-18 21:54 ` Carsten Dominik
2007-07-19 15:41 ` Bastien
2007-07-18 10:20 ` Tassilo Horn
2007-07-18 10:35 ` Georg C. F. Greve
2007-07-18 11:55 ` Tassilo Horn
2007-07-18 12:25 ` Georg C. F. Greve
2007-07-18 12:54 ` Tassilo Horn
2007-07-18 13:18 ` Georg C. F. Greve
2007-07-18 13:32 ` Tassilo Horn
2007-07-18 0:55 ` Bastien
2007-07-18 7:53 ` Georg C. F. Greve
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.orgmode.org/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20070720160833.GD28297@atlantic.linksys.moosehall \
--to=orgmode@adamspiers.org \
--cc=emacs-orgmode@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).