#!/usr/bin/env perl

# Manage GNU Keyring database entries

use strict;
use warnings;

use Getopt::Long;
use MD5;
use Palm::PDB;
use Palm::Keyring;
use Term::ReadKey;

use Data::Dumper;

my $file = '';

sub option {
    my %opts;
    my $export= "";
    my $file= "";
    my $list = 0;
    my $name = "";
    my $password = undef;


    unless(GetOptions ("export=s" => \$export,
                       "file=s" => \$file,
                       "list" => \$list,
                       "name=s" => \$name,
                       "password=s" => \$password)) {
        print <<EOF;
Usage: $0
Dump or records from your GNU keyring database protected
by password.

--export=FILE             export readable by emacs keyring to FILE
--file=FILE               name of the keyring pdb FILE
--list                    list entries
--name=MATCH              display first entrie that matches NAME
--password=PASWORD        keyring PASSWORD
EOF
        exit;
    }
    return  ( export => $export,
              file => $file,
              list => $list,
              name => $name,
              password => $password);
}

sub getpass ($) {
    my ($opt) = @_;
    while (not defined $opt->{password}) {
        print "Enter passphrase for " . $opt->{file} . ": ";
        ReadMode 2;
        $opt->{password} = ReadLine(0);
        chomp $opt->{password};
        ReadMode 0;
        # validate password
        my $pdb = new Palm::PDB;
        $pdb->Load($opt->{file});
        my $rec = $pdb->{records}->[0];
        if (length( $rec->{data}) < 16) {
            die "Hash size is too small";
        }
        my $buffer = substr($rec->{data},0,4) . $opt->{password};
        for (my $i=0; $i<60 - length($opt->{password}); $i++) {
            $buffer .= "\000";
        }
        my $md = MD5->hash($buffer);
        if ($md ne substr($rec->{data},4)) {
            print "\nPassword incorrect\n";
            $opt->{password} = undef;
        } else {
            print "\n";
        }
    }
    return $opt->{password};
}
sub export ($) {
    my ($opt) = @_;
    my $out= $opt->{export};
    my $file = $opt->{file};
    my $pass = getpass($opt);
    my $pdb  = new Palm::PDB;
    open OUT, "> $out" or die "Can't open $out: $!";
    $pdb->Load($file);
    getpass($opt);
    print OUT "(";
    foreach (0..$#{ $pdb->{records} }) {
        # skip the password record for version 4 databases
        next if $_ == 0 && $pdb->{version} == 4;
        my $rec  = $pdb->{records}->[$_];
        my $acct = $pdb->Decrypt($rec, $pass);
        print OUT '("' . $rec->{name};
        print OUT '" "';
        print OUT $acct->{account};
        print OUT '" "';
        print OUT $acct->{password};
        print OUT '" "';
        if (defined $acct->{notes}) {
            my $notes = $acct->{notes};
            $notes =~ s/\n/\\\\n/mg;
            print OUT $notes;
        }
        print OUT '")';
        print OUT "\n";
    }
    print OUT ")";
}

sub list ($) {
    my ($opt) = @_;
    my $file = $opt->{file};
    my $pdb  = new Palm::PDB;
    $pdb->Load($file);
    foreach (0..$#{ $pdb->{records} }) {
        # skip the password record for version 4 databases
        next if $_ == 0 && $pdb->{version} == 4;
        my $rec  = $pdb->{records}->[$_];
        print $rec->{name} . "\n";
    }
}

sub name ($) {
    my ($opt) = @_;
    my $file = $opt->{file};
    my $pass = getpass($opt);
    my $name = $opt->{name};
    my $pdb  = new Palm::PDB;
    $pdb->Load($file);
    foreach (0..$#{ $pdb->{records} }) {
        # skip the password record for version 4 databases
        next if $_ == 0 && $pdb->{version} == 4;
        my $rec  = $pdb->{records}->[$_];
        if ($rec->{name} =~ m/$name/) {
            my $acct = $pdb->Decrypt($rec, $pass);
            print "Name: " . $rec->{name} . "\n";
            print "Acount: " . $acct->{account} . "\n";
            print "Password: " . $acct->{password} . "\n";
            if (defined $acct->{notes}) {
                print " \n" .  $acct->{notes} . "\n";
            }
        }
    }
}

my %option = option();
if ($option{export}) {
    export(\%option);
} elsif ($option{list}) {
    list(\%option);
} elsif ($option{name}) {
    name(\%option);
}

exit;

# Copyright (C) 2006,7  Ivan Kanis
# Author: Ivan Kanis
# 
#
# This program is free software ; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation ; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY ; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program ; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

# Local Variables:
# compile-command: "./keyring.pl"
# End:

