# -*-Perl-*-
################################################################
###
### History.pm
###
### Author: Internet Message Group
### Created: Jul 6, 1997
### Revised: Jul 4, 2004
###
my $PM_VERSION = "IM::History.pm version 20031028(IM146)";
package IM::History;
require 5.003;
require Exporter;
use Fcntl;
use IM::Config qw(msg_mode msgdbfile msgdbtype db_type);
use IM::Util;
use integer;
use strict;
use vars qw(@ISA @EXPORT);
@ISA = qw(Exporter);
@EXPORT = qw(
LookUpAll LookUpMsg
history_open history_close
history_store history_lookup history_delete history_dump
history_rename history_link
);
use vars qw($DBtype $locked $nodbfile $DB_HASH %History);
sub LOCK_SH { 1 }
sub LOCK_EX { 2 }
sub LOCK_NB { 4 }
sub LOCK_UN { 8 }
sub LookUpAll { -1 }
sub LookUpMsg { 0 }
#sub LookUpDate { 1 }
sub history_open($) {
my($with_lock) = @_;
$DBtype = msgdbtype(); # package global
unless ($DBtype) {
$DBtype = db_type();
}
$locked = 0;
my $dbfile = msgdbfile();
if ($dbfile eq '') {
$nodbfile = 1;
return -2;
}
if ($DBtype eq 'DB') {
require DB_File && import DB_File;
$DB_HASH->{'cachesize'} = 100000 ;
} elsif ($DBtype eq 'NDBM') {
require NDBM_File && import NDBM_File;
} elsif ($DBtype eq 'SDBM') {
require SDBM_File && import SDBM_File;
} elsif ($DBtype eq '') {
im_err("no DB type defined.\n");
return -2;
} else {
im_err("DB type $DBtype is not supported.\n");
return -2;
}
im_debug("history database: $dbfile\n") if (&debug('history'));
my($db, $fd);
if ($DBtype eq 'DB') {
$db = tie %History, 'DB_File', $dbfile, O_CREAT()|O_RDWR(), &msg_mode(0);
} elsif ($DBtype eq 'NDBM') {
$db = tie %History, 'NDBM_File', $dbfile, O_CREAT()|O_RDWR(), &msg_mode(0);
} elsif ($DBtype eq 'SDBM') {
if (&win95p || &os2p) {
$db = tie %History, 'SDBM_File', $dbfile, O_CREAT()|O_RDWR()|O_BINARY(), &msg_mode(0);
} else {
$db = tie %History, 'SDBM_File', $dbfile, O_CREAT()|O_RDWR(), &msg_mode(0);
}
}
unless ($db) {
im_err "history: can not access $dbfile ($!)\n";
return -1;
}
if ($DBtype eq 'DB') {
$fd = $db->fd;
if ($fd < 0) {
im_err "history: can not access $dbfile (fd = $fd)\n";
return -1;
}
}
return 0 unless ($with_lock);
if ($DBtype eq 'DB') {
unless (im_open(\*HIST_FH, "+<&=$fd")) {
im_err "history: dup $fd ($!)\n";
return -1;
}
} elsif ($DBtype eq 'NDBM' or $DBtype eq 'SDBM') {
unless (im_open(\*HIST_FH, "+<$dbfile.pag")) {
im_err "history: open $dbfile.pag ($!)\n";
return -1;
}
}
if (! &win95p) {
unless (flock (HIST_FH, LOCK_EX | LOCK_NB)) {
im_warn "history: waiting for write lock ($!)\n";
unless (flock (HIST_FH, LOCK_EX)) {
im_err "history: flock ($!)\n";
return -1;
}
}
}
$locked = 1;
return 0;
}
sub history_close() {
if ($nodbfile) {
im_err("no database specified.\n");
return;
}
if (! &win95p) {
if ($locked) {
flock(HIST_FH, LOCK_UN);
}
}
untie %History;
if ($locked) {
close(HIST_FH);
}
$locked = 0;
}
sub history_lookup($$) {
if ($nodbfile) {
im_err("no database specified.\n");
return ();
}
my($msgid, $field) = @_;
$msgid =~ s/^<(.*)>$/$1/;
if (defined($History{$msgid})) {
if ($field == LookUpAll) {
return split("\t", $History{$msgid});
} else {
my @flds = split("\t", $History{$msgid});
return $flds[$field];
}
} else {
if ($field == LookUpAll) {
return ();
} else {
return '';
}
}
}
sub history_store($$) {
if ($nodbfile) {
im_err("no database specified.\n");
return -1;
}
my($msgid, $folder) = @_;
$msgid =~ s/^<(.*)>$/$1/;
im_notice("add to history: $msgid\t$folder\n");
if (defined($History{$msgid})) {
my($ofolder) = split("\t", $History{$msgid});
if (scalar(grep($folder eq $_, split(',', $ofolder)))) {
return;
}
$folder = "$ofolder,$folder";
}
$History{$msgid} = $folder;
}
sub history_delete($$) {
if ($nodbfile) {
im_err("no database specified.\n");
return -1;
}
my($msgid, $folder) = @_;
$msgid =~ s/^<(.*)>$/$1/;
if (defined($History{$msgid})) {
if ($folder ne '') {
my($f) = split("\t", $History{$msgid});
my(@list, $found);
foreach (split(',', $f)) {
if ($_ eq $folder) {
$found = 1;
} else {
push(@list, $_)
}
}
return -1 unless ($found);
if ($#list < 0) {
delete $History{$msgid};
return 0;
} else {
$History{$msgid} = join(',', @list);
return ($#list + 1);
}
} else {
delete $History{$msgid};
return 0;
}
} else {
return -1;
}
}
sub history_dump() {
if ($nodbfile) {
im_err("no database specified.\n");
return;
}
my($key, $val);
while (($key, $val) = each(%History)) {
print "$key\t$val\n";
}
}
sub history_rename($$$) {
if ($nodbfile) {im_err("no database specified.\n"); return;}
my($id, $m1, $m2) = @_;
$id =~ s/<(.*)>/$1/;
my $h;
if (defined $History{$id}) {
$h = $History{$id};
$h =~ s/^([^\t]+)(.*)//;
$h = join(',', grep($_ ne $m1, split(',', $1)), $m2) . $2;
} else {
$h = $m2;
im_warn("no entry for $id, create it.\n");
}
$History{$id} = $h if ($History{$id} ne $h);
return 0;
}
sub history_link($$$) {
if ($nodbfile) {im_err("no database specified.\n"); return;}
my($id, $m1, $m2) = @_;
$id =~ s/<(.*)>/$1/;
my $h;
if (defined $History{$id}) {
$h = $History{$id};
$h =~ s/^([^\t]+)(.*)//;
$h = join(',', grep($_ ne $m2, split(',', $1)), $m2) . $2;
} else {
$h = $m1 . ',' . $m2;
im_warn("no entry for $id, create it.\n");
}
$History{$id} = $h if ($History{$id} ne $h);
return 0;
}
sub history_unlink($$) {
if ($nodbfile) {im_err("no database specified.\n"); return;}
my($id, $m1) = @_;
$id =~ s/<(.*)>/$1/;
if (defined $History{$id}) {
my $h = $History{$id};
$h =~ s/^([^\t]+)(.*)//;
$h = join(',', grep($_ ne $m1, split(',', $1))) . $2;
if ($History{$id} =~ /^\t/ || !$m1) {
delete $History{$id};
} elsif ($History{$id} ne $h) {
$History{$id} = $h;
}
return 0;
}
im_warn("no message id in $m1\n");
return -1;
}
1;
__END__
=head1 NAME
IM::History - mail/news history database handler
=head1 SYNOPSIS
use IM::History;
history_open($with_lock);
history_dump();
history_store($msgid, $folder);
history_lookup($msgid, LookUpAll);
history_lookup($msgid, LookUpMsg);
history_delete($msgid, $folder);
history_rename($id, $m1, $m2);
history_link($id, $m1, $m2);
history_close();
=head1 DESCRIPTION
The I module handles mail/news database.
This modules is provided by IM (Internet Message).
=head1 COPYRIGHT
IM (Internet Message) is copyrighted by IM developing team.
You can redistribute it and/or modify it under the modified BSD
license. See the copyright file for more details.
=cut
### Copyright (C) 1997, 1998, 1999 IM developing team
### All rights reserved.
###
### Redistribution and use in source and binary forms, with or without
### modification, are permitted provided that the following conditions
### are met:
###
### 1. Redistributions of source code must retain the above copyright
### notice, this list of conditions and the following disclaimer.
### 2. Redistributions in binary form must reproduce the above copyright
### notice, this list of conditions and the following disclaimer in the
### documentation and/or other materials provided with the distribution.
### 3. Neither the name of the team nor the names of its contributors
### may be used to endorse or promote products derived from this software
### without specific prior written permission.
###
### THIS SOFTWARE IS PROVIDED BY THE TEAM AND CONTRIBUTORS ``AS IS'' AND
### ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
### IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
### PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TEAM OR CONTRIBUTORS BE
### LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
### CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
### SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
### BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
### WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
### OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
### IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.