<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="http://www.theoldmonk.net/blog/"?>
<rss version="2.0" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:admin="http://webns.net/mvcb/" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Filed under: code | The Old Monk</title>
<atom:link href="http://www.theoldmonk.net/blog/archives/code/index-rss.xml" rel="self" type="application/rss+xml" />
<link>http://www.theoldmonk.net/blog</link>
<description>high wisdom</description>
<dc:language>en-us</dc:language>
<dc:creator>gera</dc:creator>
<dc:date>2010-05-25T17:36:37+05:30</dc:date>
<admin:generatorAgent rdf:resource="http://nanoblogger.sourceforge.net" />
<item>
<link>http://www.theoldmonk.net/blog/archives/2010/03/14/more_git-bugzilla_fun_-_gitzilla_1_9/</link>
<guid isPermaLink="true">http://www.theoldmonk.net/blog/archives/2010/03/14/more_git-bugzilla_fun_-_gitzilla_1_9/</guid>
<title>More Git-Bugzilla fun - GitZilla 1.9</title>
<dc:date>2010-03-14T03:58:15+05:30</dc:date>
<dc:creator>gera</dc:creator>
<dc:subject>code</dc:subject>
<description>
<![CDATA[<p>
<a href="http://www.theoldmonk.net/gitzilla/">GitZilla</a> version 1.9 is out.
This is a RC for version 2.0, which comes after this gets some wider testing.
If you're using it and have a problem, use the issues page at github.
</p>
<p>New features and changes:<br />
<ul>
  <li>User specific auth can now be mandatory, optional or denied
altogether</li>
  <li>User specific auth can now work with a cookie file (no need to store
passwords - a problem when you have single-sign-on or common passwords)</li>
  <li>Utility scripts to generate cookie files</li>
  <li>More auth options for custom hooks. You can now pass a callback for
pybugz initialization and go wild with it.</li>
  <li>The update hook now checks for valid Bugzilla auth even if bug status
checking is not enabled.</li>
</ul>
</p>]]>
</description>
</item>
<item>
<link>http://www.theoldmonk.net/blog/archives/2010/03/08/gitzilla_-_git-bugzilla_integration_done_right/</link>
<guid isPermaLink="true">http://www.theoldmonk.net/blog/archives/2010/03/08/gitzilla_-_git-bugzilla_integration_done_right/</guid>
<title>GitZilla - Git-Bugzilla integration done right</title>
<dc:date>2010-03-08T04:34:49+05:30</dc:date>
<dc:creator>gera</dc:creator>
<dc:subject>code</dc:subject>
<description>
<![CDATA[<p>
My old git-bugzilla integration scripts were more of a one-off attempt at some
glue code and was very hackish. No wonder it accumulated bitrot.
</p>
<p>
So now, there's <a href="http://www.theoldmonk.net/gitzilla/">GitZilla</a>!
It's hosted on GitHub and there's a .deb available. Note that (for now at
least), you would have to install the pybugz module separately, even if you
install the GitZilla .deb.
</p>
<p>
Using GitZilla is extremely easy. You can get started by symlinking (or
copying) a couple of files and creating a 4 line configuration file. (See the
'simple ready scripts' usage mode).
</p>]]>
</description>
</item>
<item>
<link>http://www.theoldmonk.net/blog/archives/2009/04/10/couchdb_document_update_notifications/</link>
<guid isPermaLink="true">http://www.theoldmonk.net/blog/archives/2009/04/10/couchdb_document_update_notifications/</guid>
<title>CouchDB document update notifications</title>
<dc:date>2009-04-10T11:02:00+05:30</dc:date>
<dc:creator>gera</dc:creator>
<dc:subject>technology, code</dc:subject>
<description>
<![CDATA[<a href="http://couchdb.apache.org/">CouchDB</a> is a very cool document store which uses JavaScript map/reduce views. It is schema free and the docs are JSON. It also has an HTTP API which makes it possible to write purely JavaScript apps with persistence via CouchDB.
<br /><br />
Couch has a concept of DB update notifications. A process is launched (and relaunched if it crashes, via an Erlang/OTP supervisor) and is notified of any updates (adds, deletes and changes) to the DBs. That's nice, but not sufficiently useful in all cases.
<br /><br />
So I added a "document update notification" mechanism on the lines of db update notifications, which not only tells which document changed, but also what changed in the document. This makes it possible to write various kinds of "triggers" (or even "stored procedures" if you squint just right). The document update notification process gets the type of change (add/delete/update), the db name, the doc id and the bodies of the old and the new doc on each update. It can then use these to determine if something interesting changed and decide whether to take action or not.
<br /><br />
The patch was offered upstream (<a href="http://mail-archives.apache.org/mod_mbox/couchdb-dev/200904.mbox/%3C20090408110546.GA26996@gera-laptop%3E">annoucement</a>) but wouldn't land up in the trunk because a feature superseding this functionality is already planned (comet notifications). However, I will maintain the patches out-of-tree till the superseding functionality lands in the trunk. The patches are fairly simple and non intrusive, and are available for both 0.8.1 and 0.9.
<br /><br />
<a href="http://www.theoldmonk.net/couchdb_docnotifications.0.9.patch">DocUpdateNotifications patch for CouchDB 0.9</a>
<br /><br />
<a href="http://www.theoldmonk.net/couchdb_docnotifications.0.8.1.patch">DocUpdateNotifications patch for CouchDB 0.8.1</a>
<br /><br />
These patches were developed as part of my work for <a href="http://www.basecase.com">BaseCase</a>. BaseCase thinks open source is cool and has gladly agreed to the release of these patches.]]>
</description>
</item>
<item>
<link>http://www.theoldmonk.net/blog/archives/2009/02/16/whatthefuck/</link>
<guid isPermaLink="true">http://www.theoldmonk.net/blog/archives/2009/02/16/whatthefuck/</guid>
<title>whatthefuck</title>
<dc:date>2009-02-16T15:08:16+05:30</dc:date>
<dc:creator>gera</dc:creator>
<dc:subject>code, hacks</dc:subject>
<description>
<![CDATA[I'm back from hibernation! Now that I've quit work and have a little free time, I'm back to making my life easier.
<br /><br />
Step one, in that direction is <em>whatthefuck</em>. It's a wrapper around the excellent <em>wtf</em> utility, available via the <em><a href="http://packages.debian.org/search?keywords=bsdgames&searchon=names&suite=stable&section=all">bsdgames</a></em> package in Debian (and <a href="http://packages.ubuntu.com/search?keywords=bsdgames&searchon=names&suite=intrepid&section=all">Ubuntu</a>). <em>wtf</em> is nice, but has some annoyances like :
<pre>
gera@gera-laptop:~$ wtf is 3whs
Gee...  I don't know what 3whs means...
gera@gera-laptop:~$ wtf -t comp is 3whs
3WHS: three-way handshake
</pre>
That's because the term exists in the 'comp' list and not the regular one. Well, chances are that if I don't know wtf it means, I wouldn't know that it's a computing term either. And what about terms which aren't in _any_ list?
<br /><br />
Enter <a href="/whatthefuck">whatthefuck</a>. It's a wrapper around <em>wtf</em>. It does the following, in order:
<ul>
        <li>looks for the term in the default wtf list</li>
        <li>if that doesn't work, looks for it in the comp list</li>
        <li>failing that, gets the wikipedia page for that term</li>
        <li>failing even that, launches a Google search for the term in a browser</li>
</ul>
It detects screen size and then intelligently pages the output via the default pager. For parsing wikipedia HTML, it needs <em>html2text</em>, and for querying the wtf lists, it needs wtf. If it doesn't find wtf, it'll just act as a lookup tool for wikipedia. It launches 'gnome-www-browser' by default, but will use the BROWSER environment variable if that's set. It also ignores the optional 'is', just like <em>wtf</em>:
<pre>
gera@gera-laptop:~$ whatthefuck perl
perl: perl (1) - Practical Extraction and Report Language
gera@gera-laptop:~$ whatthefuck is perl
perl: perl (1) - Practical Extraction and Report Language
</pre>
I alias it to 'wtf' so that I can make this completely transparent.
<pre>
gera@gera-laptop:~$ alias wtf=`which whatthefuck`
gera@gera-laptop:~$ wtf is perl
perl: perl (1) - Practical Extraction and Report Language
</pre>
It's a trivial script and not rocket science. But it's tremendously useful.
<br /><br />
<b>update (21 Feb 2009)</b>: The newer version (available at the same link) checks the uppercased term on wikipedia as well.]]>
</description>
</item>
<item>
<link>http://www.theoldmonk.net/blog/archives/2008/03/08/git-bugzilla_integration/</link>
<guid isPermaLink="true">http://www.theoldmonk.net/blog/archives/2008/03/08/git-bugzilla_integration/</guid>
<title>Git-Bugzilla integration</title>
<dc:date>2008-03-08T19:47:35+05:30</dc:date>
<dc:creator>gera</dc:creator>
<dc:subject>tricks, perl, code, hacks</dc:subject>
<description>
<![CDATA[<p>
<em>UPDATE: See my <a
href="http://www.theoldmonk.net/blog/archives/2010/03/08/gitzilla_-_git-bugzilla_integration_done_right/">blog
post</a> about <a href="http://www.theoldmonk.net/gitzilla/">GitZilla</a> - git-bugzilla
integration done right. The stuff below is bitrotten and outdated now.</em>
</p>

<p>There's always <a href="http://www.mkgnu.net/?q=scmbug">SCMBug</a>, but you can cook your own Git-Bugzilla integration very easily. SCMBug's fine, but it's a lot of code if all you want is simple cross-linking between Git, Bugzilla and <a href="http://trac.edgewall.org/">Trac</a> (btw - <a href="http://trac-hacks.org/wiki/GitPlugin">GitPlugin</a> for Trac would throw up an error unless you have at least *two* commits in your repository - talk about undocumented easter bugs!).</p>

<p>Anyhoo - here's what I want : <br />
1. Git should disallow any commit where the commit message does not have a bug number. <br />
2. Git should add a comment to the corresponding bug on a commit, mentioning the author, the Trac changeset link, the commit message and the list of files which changed.</p>

<p>And here's the code to do it. First, the post-receive hook :</p>
<pre>
#!/usr/bin/perl -w
use strict;

# A hook script which integrates with bugzilla. It looks for bug IDs in
# commit messages and adds the commit message as well as a link to the
# changeset as a comment on the bug.

# This program is released under the terms of the GNU General Public License
# version 2. A copy of the license may be obtained by emailing the author,
# or at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
#
# The absolute lack of warranty and other disclaimers as per the license
# apply.
#
# Copyright 2008, Devendra Gera. All rights reserved.
#
# Author : Devendra Gera <gera@theoldmonk.net>

### user configurable section

# The bugzilla has contains the server, username and password for the targeted
# bugzilla installation. There's NO 'http://' in the server line.
my $bugzilla = {
        server          => "10.147.251.90/bugzilla",
        user            => "demonuser",
        password        => "daemonuserspassword",
};

# __PATH__ and __REVISION__ are replaced in $browser->{changeset} and
# $browser->{revision} to get the changeset and revision URLs respectively. 
my $browser = {
        changeset       =>
        "http://10.147.251.90/projname/changeset/__REVISION__",
        revision        =>
        "http://10.147.251.90/projname/browser/__PATH__?rev=__REVISION__",
};

# The bug_regex should extract the bug id from the commit message and place
# it in $1
my $bug_regex = 'bug #(\d+)';


##### End user configurable section

use WWW::Bugzilla;

my $input = <>;
chomp $input;

my ($oldrev, $newrev, $refname) = split /\s+/, $input;
my $commit_msg = `git-whatchanged $oldrev..$newrev`;

# prepare the changeset URL
my $changeset_url = $browser->{ changeset };
$changeset_url =~ s/__REVISION__/$newrev/g;

# author
my ($author) = ( $commit_msg =~ /^Author:\s+(.*)$/m );

# files
my @filelist = grep ( /^:/, split( /\n/, $commit_msg ) );

# prepare comment
$commit_msg =~ s/^.*?Date://s;  # eat everything till the Date: heder
$commit_msg =~ s/^.*?\n//m;     # eat the date line completely
$commit_msg =~ s/^:.*?$//mg;    # eat the file list from the msg.
chomp $commit_msg;
my ($bug_number) = ( $commit_msg =~ /$bug_regex/ );

my $comment = &lt;&lt;END_COMMENT;

------------------------------------
changeset $newrev [ $changeset_url ]
    by $author :

$commit_msg
------------------------------------

Files changed :
END_COMMENT

$comment .= join("", @filelist) . "\n";

my $bz = WWW::Bugzilla->new(
        server          => $bugzilla->{ server },
        email           => $bugzilla->{ user },
        password        => $bugzilla->{ password },
        bug_number      => $bug_number
);

die "cannot connect to bugzilla" unless defined $bz;

$bz->additional_comments( $comment );

$bz->commit;
</pre>

<p>And here's the update hook :</p>
<pre>
#!/usr/bin/perl -w
use strict;

my $refname = shift;
my $oldrev = shift;
my $newrev = shift;

my $commit_msg = `git-whatchanged $oldrev..$newrev`;

# check if the commit message contains a bug number
if($commit_msg !~ /bug #\d+/) {
        exit -1;
}

exit 0;
</pre>

<p>The TODO : <br />
1. Push every configurable thing to git's config file and access it via git-config. <br />
2. Code cleanups. One definition of the bug regex (which is hardcoded in the update for now).</p>

<p><em>edit</em> : the here doc in the code was causing a problem with formatting, eating up some of the code. Fixed now.</p>]]>
</description>
</item>
<item>
<link>http://www.theoldmonk.net/blog/archives/2008/01/29/datemanip_remind_and_remindme/</link>
<guid isPermaLink="true">http://www.theoldmonk.net/blog/archives/2008/01/29/datemanip_remind_and_remindme/</guid>
<title>Date::Manip, remind and remindme</title>
<dc:date>2008-01-29T17:00:44+05:30</dc:date>
<dc:creator>gera</dc:creator>
<dc:subject>tricks, perl, code</dc:subject>
<description>
<![CDATA[<p>I use <a href="http://www.roaringpenguin.com/products/remind">remind</a>(<a href="http://lifehacker.com/software/top/geek-to-live--keep-your-calendar-in-plain-text-with-remind-186661.php">short howto</a>) to keep my calendar of events and reminders. Its a wonderful utility - and all commandline. I split up the birthdays, anniversaries, personally important days, and the usual stuff into different files, and include them in my ~/.reminders file. Here's what my .reminders looks like :</p>

<pre>
gera@gera-laptop:~$ cat .reminders 
include /home/gera/reminders/birthdays
include /home/gera/reminders/anniversaries
include /home/gera/reminders/impdates
include /home/gera/reminders/stuff
</pre>

<p>All this works well, except for a small issue. It takes too much time for me to add reminders for my day-to-day tasks. Firing up an editor and typing all that remind syntax is something that can be avoided. Also, it really hurts to look at the calendar to figure out fuzzy dates like "tomorrow", or "sat". I was planning to write this big Perl script which would do the heavy lifting for me. Instead, I found Date::Manip which already does the heavy lifting. It understands stuff like "tomorrow" and "sun". I just needed a small 'remindme' script then :</p>

<pre>
#!/usr/bin/perl -w
use strict;

use Date::Manip;
use Fcntl qw(:flock);

my $reminders = "$ENV{HOME}/reminders/stuff";

my $argstring = join (" ", @ARGV);
my ($when, $what);

(undef, $when, $what) = ($argstring =~ /^(on |)(.*?) to (.*)$/);
quit("what?") unless $what;
quit("when?") unless $when;

# form the line to be appended
my $date = ParseDate($when);
quit("cannot parse date") unless $date;

my $line = UnixDate($date, "REM %b %e %Y +1 MSG");
$line .= " $what %b.%\n";

# write in file

# open lock file
open LOCK, ">$reminders.lock" or quit("cannot open $reminders.lock : $!");
flock LOCK, LOCK_EX or quit("cannot obtain lock : $!");

# open data file, write and close data file
open REMINDERS, ">>$reminders" or quit("cannot open $reminders : $!");
print REMINDERS $line;
close REMINDERS;

# release locks
flock LOCK, LOCK_UN;
close LOCK;

exit (0);

sub quit
{
        my $msg = shift;
        print STDERR $msg, "\n";
        exit (-1);
}
</pre>

<p>Now, I can use it like this :</p>

<pre>
$ remindme on sat to eat everything I can
$ remindme tomorrow to pay the phone bill
$ remindme next week to think up of something useful to say
$ remindme next thursday to find something better to do
</pre>

<br />
nifty, eh?

<p><em>update</em>: bugfixed the script. An extra space creeped up between the '+' and the '1'. Thanks to <a href="http://www.amitu.com/blog/">AmitU</a> for pointing that out.
<br />
<em>update 2</em>: added the capability to get reminded n days in advance - a feature suggested by AmitU in the comments, but with a different syntax ("remindme next week to do this <em>for 2 days</em>"). Also, remindme's <a href="http://repo.or.cz/w/remindme.git">git repository</a> and <a href="http://www.theoldmonk.net/remindme/">home page</a>. The repository contains the bash-completion script as well.</p>]]>
</description>
</item>
<item>
<link>http://www.theoldmonk.net/blog/archives/2008/01/28/commandline_gtd_with_gtdo/</link>
<guid isPermaLink="true">http://www.theoldmonk.net/blog/archives/2008/01/28/commandline_gtd_with_gtdo/</guid>
<title>Commandline GTD with gtdo</title>
<dc:date>2008-01-28T15:17:57+05:30</dc:date>
<dc:creator>gera</dc:creator>
<dc:subject>tricks, perl, code, hacks</dc:subject>
<description>
<![CDATA[I was introduced to <a href="http://en.wikipedia.org/wiki/Getting_Things_Done">GTD</a> around a year ago, but wanted to manage mine using a commandline. I discovered <a href="http://www.todotxt.com/">todotxt.com</a> and modified a <a href="http://www.todotxt.com/download.php?p=%2Flibrary%2Ftodo.sh%2F&f=todo.py">todo.py</a> to suit my needs (removed priorities, added some commands, bash-completion etc).
<br /><br />
But I stopped doing it.
<br /><br />
Because I had nothing to manage my "projects" (tasks with multiple action items). I maintained a list of projects out-of-band, as a directory structure, which required me to identify the next task for a project and move it to my todo list. Of course it didn't work!
<br /><br />
So I wrote gtdo. gtdo has a similar interface - todo.py was the inspiration - but in addition to the contexts (marked by a '@'), it supports groups (or "projects" - marked by a '/'). So, you might have a project about starting using GNUcash. Of course, the first step is to install/set-up GNUcash. Adding your portfolio comes later. If you have both these items in your todo list, the second one does nothing but adds noise and makes the list longer. The answer is to add them in a group /gnucash. If there are multiple tasks in a group, only the first one is displayed - till its marked done. By default, new tasks are added at the end of the queue in a group, but may be added at a specific position.
<br /><br />
An example would be better than the ramble above (gtdo being aliased to 't'):
<pre>
$ t add /gnucash @online install gnucash
$ t add /frames @errands buy wood
$ t add /email @online set up spamassassin
$ t add /gnucash @online add portfolio to gnucash
<br /><br />
# only the immediate next task is displayed when you 'ls'
$ t ls
1 : /gnucash @online install gnucash
2 : /frames @errands buy wood
3 : /email @online set up spamassassin
<br /><br />
$ t ls @online
1 : /gnucash @online install gnucash
3 : /email @online set up spamassassin
<br /><br />
# except when you specifically ask for a group
$ t ls /gnucash
1 : /gnucash @online install gnucash
4 : /gnucash @online add portfolio to gnucash
<br /><br />
# well, we need to fix F::Q::IndiaMutual before we add our portfolio
# we'll try adding that as the second step in the /gnucash group
$ t add /gnucash.2 fix F::Q::IndiaMutual
<br /><br />
$ t ls /gnucash
1 : /gnucash @online install gnucash
4 : /gnucash fix F::Q::IndiaMutual
5 : /gnucash @online add portfolio to gnucash
</pre>
Comes with standard todo.sh style bash-completion. The Git repository is available at <a href="http://repo.or.cz/w/gtdo.git">http://repo.or.cz/w/gtdo.git</a>. You can obtain a tarball by clicking <a href="http://repo.or.cz/w/gtdo.git?a=snapshot;h=HEAD;sf=tgz">here</a>.]]>
</description>
</item>
<item>
<link>http://www.theoldmonk.net/blog/archives/2008/01/23/configd__the_configuration_daemon/</link>
<guid isPermaLink="true">http://www.theoldmonk.net/blog/archives/2008/01/23/configd__the_configuration_daemon/</guid>
<title>configd : the configuration daemon</title>
<dc:date>2008-01-23T13:31:40+05:30</dc:date>
<dc:creator>gera</dc:creator>
<dc:subject>perl, code</dc:subject>
<description>
<![CDATA[Reading configuration items is a task that almost every application/utility does. Writing code for all those is stupid. Even writing code once and linking it in leaves the language binding issues open. What encouraged me to write this is a frequently invoked piece of (network) code which ideally would check its configuration for each invocation. The disk I/O seemed unnecessary.
<br /><br />
Enter configd - the configuration daemon. Reads configuration items (key=value pairs) for "domains" (applications), and gives them out to anyone who cares to ask over HTTP. Supports HTTP GET/HEAD, with the "domain" and "key" headers, handing out the value as the "value" header in the response. Returns a <a href="http://en.wikipedia.org/wiki/HTTP_404">404 Not Found</a> if it can't find a value, or a <a href="http://en.wikipedia.org/wiki/HTTP_400#4xx_Client_Error">400 Bad Request</a> if the request is malformed. A SIGHUP to configd makes it re-read the (possibly changed) values from the configuration.
<br /><br />
configd is consistent with the <a href="http://en.wikipedia.org/wiki/Unix_philosophy#McIlroy:_A_Quarter_Century_of_Unix">Unix Philosophy</a>. A simple tool that does only one job, and does it well.
<br /><br />
Although configd advertises configurations, it doesn't stop anyone from using it as a trivial key=value "database" (for a stretched definition of the term). It's HTTP - something that's very well understood and supported, and can scale extremely well behind a load balancer, offering caching and remote configuration.
<br /><br />
PUT requests for storing values, and some form of authentication are something that might be added some day, although I don't have the need for them right now.
<br /><br />
<s>The <a href="http://en.wikipedia.org/wiki/Git_%28software%29">Git</a> repository will shortly be online.</s>
<br /><br />
<em>Edit:</em> The <a href="http://repo.or.cz/w/configd.git">configd repository</a> is now online.
<br /><br />
<em>Something that I thought just now</em>: On the trivial database thread, configd can present a consistent interface, once it implements PUT. Reads are cached, load balanced, yadda yadda. And writes are PUT requests. The backend doesn't matter to the application. One can take out the flat files, and replace it with MySQL (with some type checking at the configd/application end), and the application wouldn't know better. A connection can be equated to a transaction. All PUT requests over a connection are rolled as a transaction. How cool is that?
<br /><br />
<em>Also</em>: If you use it as a "database", you cleanly separate the scale layer from the business logic layer. Right now, even prototypes use an SQL backend because people want to scale in the future. There's a lot of DBI/SQL where it doesn't belong. Engineers who write prototypes also write SQL instead of a DBA ("its just a prototype"), which they have to maintain as legacy code/design. All these problems vanish away when you use the simple approach. Engineers don't have to worry about SQL or scale. They can be up and running with a flat file backend which can be changed to SQL without the app noticing. If and when you swap in a real database behind it, SQL queries can be written for the engine by real DBAs (you're scaling this up - its no longer a prototype - it makes sense to assign a DBA for this). To top it all, your *hardware* can do sharding. HTTP load balancers can load balance based on headers - and domains/keys are headers here. The applications need not worry about scaling the database _at_all_.]]>
</description>
</item>
<item>
<link>http://www.theoldmonk.net/blog/archives/2008/01/18/mutt_addressbook_collector/</link>
<guid isPermaLink="true">http://www.theoldmonk.net/blog/archives/2008/01/18/mutt_addressbook_collector/</guid>
<title>mutt addressbook collector</title>
<dc:date>2008-01-18T15:13:02+05:30</dc:date>
<dc:creator>gera</dc:creator>
<dc:subject>tricks, perl, code, hacks</dc:subject>
<description>
<![CDATA[I have a tiny helper script to collect addresses from my outgoing emails, and add them to my .aliases file. I only care about people who I send out email to, and I've noticed that collecting addresses from incoming emails leads to too much noise. Although I could set it up to *not* pick up addresses from spam and mails which have my firstname (ecommerce stuff which is NOT spam). But that's for later.

<p />
Here's the helper (I use msmtp for sending out email as evindent in my <a href="http://www.theoldmonk.net/blog/archives/2008/01/16/email_setup/">mutt config</a>) :
<p />
<pre>
#!/usr/bin/perl -w
use strict;

my $home = "/home/gera";
my $msmtp = "/usr/bin/msmtp";
my $aliasfile = "/home/gera/.aliases";

open ALIASES, "<$aliasfile" or quit("cannot open $aliasfile : $!");
my %aliases = ();
my %collected = ();
while(<ALIASES>) {
        s/#.*$//;
        chomp;
        next unless $_;
        my ($nick, $name, $email) = ($_ =~ /^alias\t+(\S+)\t+(.+?)\t+<(\S+)>/);
        quit("cannot parse $_") unless ($nick && $name && $email);
        $aliases{$email} = {
                "nick"  => $nick,
                "name"  => $name,
        };
}
close ALIASES;

# now read the email contents and try to figure out the addresses
local $/ = undef;       # slurp mode

my $email = <STDIN>;
my ($to) = ($email =~ /^To:(.*)$/m);
my ($cc) = ($email =~ /^Cc:(.*)$/m);
my @addresses = split( /,/, "$to,$cc");
foreach my $address (@addresses) {
        chomp;
        next unless $address;
        # the address is of the form of "Firstname Lastname <email@address>"
        # or "<email@address>" or "email@address"
        my ($name, undef, $email) = ($address =~ /^(.*?)\s*(<|)([^<>]*?)(>|)$/);
        quit("cannot parse $address") unless $email;
        next if exists $aliases{$email};
        # else, add it to the aliases.
        # See if everything is populated. We'll have to invent a nickname here
        if(! $name) {
                ($name = $email) =~ s/\@.*//;
        }
        my $nick;
        ($nick = lc $name) =~ tr/ //d;
        $collected{$email} = {
                "nick"  => $nick,
                "name"  => $name,
        };
}

if(scalar(keys %collected) != 0) {
        # save to tmp file
        open ALIASES, ">$aliasfile.new.$$" or quit("cannot open $aliasfile.new.$$ : $!");
        foreach my $email (sort keys %aliases) {
                my $nick = $aliases{$email}->{nick};
                my $name = $aliases{$email}->{name};
                print ALIASES "alias    $nick   $name   <$email>\n";
        }
        print ALIASES "\n\n#collected email addresses\n\n";
        foreach my $email (sort keys %collected) {
                my $nick = $collected{$email}->{nick};
                my $name = $collected{$email}->{name};
                print ALIASES "alias    $nick   $name   <$email>\n";
        }
        close ALIASES;

        # move tmp file to $aliasfile
        rename("$aliasfile.new.$$", $aliasfile);
}

# send mail onward
open(MSMTP, "|$msmtp @ARGV") or quit("cannot open pipe to $msmtp @ARGV : $!");
print MSMTP $email;
close(MSMTP) or quit("cannot close pipe to MSMTP : $!");

exit(0);


sub quit
{
        my $msg = shift;
        open LOGFILE, ">$home/.msmtp_helper.log" || die "cannot open log file : $!";
        print LOGFILE "$msg\n";
        close LOGFILE;
        exit(127);
}
</pre>
<p />
Edit : fixed formatting.]]>
</description>
</item>
<item>
<link>http://www.theoldmonk.net/blog/archives/2008/01/17/financequoteindiamutual_bugfix/</link>
<guid isPermaLink="true">http://www.theoldmonk.net/blog/archives/2008/01/17/financequoteindiamutual_bugfix/</guid>
<title>Finance::Quote::IndiaMutual bugfix</title>
<dc:date>2008-01-17T22:25:39+05:30</dc:date>
<dc:creator>gera</dc:creator>
<dc:subject>perl, code, hacks</dc:subject>
<description>
<![CDATA[I used GnuCash for a while and maybe I'll start using it again. A neat thing that one can do with it is to track one's portfolio. Stocks are easy (GnuCash can use Finance::Quote::Yahoo where NSE stocks have symbols ending in '.NS', and BSE stocks are numbers). Mutual funds in India do not have ticker symbols, but prices/NAV etc. can be obtained via the <a href="http://search.cpan.org/~hampton/Finance-Quote-1.13/lib/Finance/Quote/IndiaMutual.pm">Finance::Quote::IndiaMutual</a> module, which fetches them from the <a href="http://amfiindia.com/">AMFI</a> website.
<br /><br />
To use the module, one can grab the code corresponding to the fund from the table at <a href="http://amfiindia.com/downloadnavopen.asp">http://amfiindia.com/downloadnavopen.asp</a> and supply that to the module.
<br /><br />
All that is fine, but there's a tiny regex bug in the module which chokes on many rows. The fix is trivially simple and the diff totals to 
<pre>
74c74
<       my ($symbol, @data) = split /\;/;
---
>       my ($symbol, @data) = split /\s*\;\s*/;
</pre>
I hope that helps someone.]]>
</description>
</item>
</channel>
</rss>
