# vim: set cindent expandtab ts=4 sw=4:
#
# Copyright (c) 1998-2005 Chi-Keung Ho. All rights reserved.
#
# This programe 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.
#
# Extmail - a high-performance webmail to maildir
# $Id$
package Ext::Abook;
use Exporter;
use Ext::CSV;
use Fcntl qw(:flock);
use vars qw(@ISA @ABOOK $REF);
@ISA = qw(Exporter);
undef @ABOOK;
$REF = undef;
sub new {
my $class = shift;
my %opt = @_;
my $self = {
file => $opt{file} ? $opt{file} : 'abook.cf',
lock => $opt{lock} ? 1:0,
sort => $opt{sort} ? $opt{sort} : 'by_mailaddr',
};
bless $self, $class;
$REF = new Ext::CSV unless($REF);
$self->parse; # XXX auto
$self;
}
sub parse {
my $self = shift;
my $file = $self->{file};
my $count = 0;
open(FD, "< $file") or
warn "$file not exists, abort\n" and return "";
while(<FD>) {
chomp;
if ($REF->parse($_)) {
my @field = $REF->fields;
$ABOOK[$count] = \@field;
$count ++;
}else {
warn $REF->error_input;
}
}
close FD;
}
# CSV format:
#
# 'ID', 'Name', 'Email', 'Company', 'Mobile'
# 0 1 2 3 4
sub by_name {
$a->[1] cmp $b->[1];
}
sub by_mailaddr {
$a->[2] cmp $b->[2];
}
sub by_mobile {
$a->[4] <=> $b->[4];
}
sub by_company {
$a->[3] cmp $b->[4];
}
sub dump {
shift;
return \@ABOOK;
}
sub sort {
my $self = shift;
my @mybuf = @ABOOK; # deep copy
for (0...scalar @mybuf-1) {
$mybuf[$_] = [$_, @{$mybuf[$_]}];
}
shift @mybuf; # ignore the first line
# sort it now
my $method = $self->{sort};
eval { @mybuf = sort $method @mybuf; };
if ($@) {
# default sort method
@mybuf = sort by_mailaddr @mybuf;
}
unshift @mybuf, [0, 'Name', 'Email', 'Company', 'Mobile'];
\@mybuf; # sorted array
}
sub search {
my $self = shift;
my $key = $_[0];
my @id;
my $ref = $self->sort;
foreach(my $k=1; $k < scalar @$ref; $k++) {
# join to a big string
my $lid = $ref->[$k]->[0]; # line ID
my $s = join('', splice(@{$ref->[$k]}, 1)); # ignore the first id
if($s=~/$key/i) {
push @id, $lid;# return $k only?
}
}
@id;
}
# Schema: field0,1,2,3,4 => id, name, mailaddr, company, mobile
sub lookup {
my $self = shift;
return $ABOOK[$_[0]] if($ABOOK[$_[0]]);
"";
}
sub delete {
my $self = shift;
my @id = @_;
my @tarray;
my $newid = 0;
foreach(my $k=0; $k < scalar @ABOOK; $k++) {
my $del = 0;
for(@id) {
if($k eq $_) { $del = 1; last; }
}
unless($del) {
$tarray[$newid] = $ABOOK[$k];
$newid++;
}
}
@ABOOK = @tarray;
undef @tarray;
}
sub append {
my $self = shift;
my $ref = $_[0]; # ARRAY ref
my $id = scalar @ABOOK;
$ABOOK[$id] = $ref; # add into it
}
sub update {
my $self = shift;
my ($id,$ref) = @_; # ref => ARRAY ref
$ABOOK[$id] = $ref;# if not present, will auto
# append it
}
sub save {
my $self = shift;
my $file = $self->{file} || 'abook.cf';
my $addhdr = 0;
$addhdr = 1 if(!-r $file);
open(FD, "> $file") or die "Write to $file error: $!\n";
flock(FD, LOCK_EX);
if($addhdr) {
$REF->combine(('Name', 'Email', 'Company', 'Mobile'));
print FD $REF->string,"\n";
}
foreach(my $k=0; $k< scalar @ABOOK; $k++) {
my $val = $ABOOK[$k];
$val = $REF->combine(@$val);
$val = $REF->string($val);
print FD $val,"\n";
}
flock(FD, LOCK_UN);
close FD;
1;
}
sub DESTROY {
undef $REF;
undef @ABOOK;
}
1;
syntax highlighted by Code2HTML, v. 0.9.1