# $File: //depot/libOurNet/BBS/lib/OurNet/BBS/MAPLE2/Article.pm $ $Author: autrijus $
# $Revision: #6 $ $Change: 4012 $ $DateTime: 2003/01/29 11:06:24 $
package OurNet::BBS::MAPLE2::Article;
use if $OurNet::BBS::Encoding, 'open' => ":encoding($OurNet::BBS::Encoding)";
use if $OurNet::BBS::Encoding, 'encoding' => 'big5', STDIN => undef, STDOUT => undef;
use strict;
use warnings;
no warnings 'deprecated';
use fields qw/bbsroot board basepath name dir recno mtime btime _ego _hash/;
use OurNet::BBS::Base (
'ArticleGroup' => [qw/$packsize $namestring $packstring @packlist/],
'Board' => [qw/&remove_entry/],
'$HEAD_REGEX' => qr/§@ªÌ: ([^ \(]+)\s?(?:\((.+?)\) )?[^\n]*\n¼ÐÃD: (.*)\n®É¶¡: (.+)\n\n/,
);
my %chronos;
sub basedir {
my $self = shift;
return join('/', $self->{bbsroot}, $self->{basepath},
$self->{board}, $self->{dir});
}
sub new_id {
my $self = shift;
my ($id, $file);
$file = $self->basedir;
unless (-e "$file/.DIR") {
open(my $DIR, ">$file/.DIR") or die "cannot create $file/.DIR";
close $DIR;
}
my $chrono = time;
no warnings 'uninitialized';
$chronos{$self->{board}} = $chrono
if $chrono > $chronos{$self->{board}};
while ($id = "M.$chrono.A") {
last unless -e "$file/$id";
$chrono = ++$chronos{$self->{board}};
}
open(my $BODY, ">$file/$id") or die "cannot open $file/$id";
close $BODY;
$self->{_hash}{time} = $chrono;
return $id;
}
sub _refresh_body {
my $self = shift;
$self->{name} ||= $self->new_id;
my $file = join('/', $self->basedir, $self->{name});
return unless -e $file;
return if $self->filestamp($file, 'btime') and defined $self->{_hash}{body};
$self->{_hash}{date} ||=
sprintf("%2d/%02d", (localtime($self->{btime}))[4] + 1,
(localtime($self->{btime}))[3]);
local $/;
open(my $DIR, "<$file") or die "can't open DIR file for $self->{board}";
$self->{_hash}{body} = <$DIR>;
close $DIR;
my ($from, $title, $date);
if ($self->{_hash}{body} =~
s/$HEAD_REGEX//
) {
($from, $self->{_hash}{nick}, $title, $date) = ($1, $2, $3, $4);
}
else {
$self->refresh_meta;
}
$self->{_hash}{title} =~ s/^¡º //
if $self->{dir} and $self->{_hash}{title};
$self->{_hash}{header} = {
From => ($from || $self->{_hash}{author}) .
($self->{_hash}{nick} ? " ($self->{_hash}{nick})" : ''),
Subject => $title ||= $self->{_hash}{title},
Date => $date ||= scalar localtime($self->{btime}),
Board => $self->{board},
};
OurNet::BBS::Utils::set_msgid($self->{_hash}{header});
return 1;
}
sub refresh_nick {
shift->_refresh_body;
}
sub refresh_body {
shift->_refresh_body;
}
sub refresh_header {
shift->_refresh_body;
}
sub refresh_meta {
my $self = shift->ego;
$self->{name} ||= $self->new_id;
my $file = join('/', $self->basedir, $self->{name});
$self->{btime} = (stat($file))[9] if -e $file;
$file = join('/', $self->basedir, '.DIR');
return if $self->filestamp($file);
local $/ = \$packsize;
open(my $DIR, "<$file") or die "can't read DIR file for $self->{board}: $!";
binmode($DIR);
if (defined $self->{recno}) {
seek $DIR, $packsize * $self->{recno}, 0;
@{$self->{_hash}}{@packlist} = unpack($packstring, <$DIR>);
if ($self->{_hash}{id} ne $self->{name}) {
undef $self->{recno};
seek $DIR, 0, 0;
}
}
unless (defined $self->{recno}) {
$self->{recno} = 0;
while (my $data = <$DIR>) {
@{$self->{_hash}}{@packlist} = unpack($packstring, $data);
# print "$self->{_hash}{id} versus $self->{name}\n";
last if ($self->{_hash}{id} eq $self->{name});
$self->{recno}++;
}
if ($self->{_hash}{id} ne $self->{name}) {
$self->{_hash}{id} = $self->{name};
$self->{_hash}{author} ||= '(unknown).';
$self->{_hash}{date} = sprintf(
"%2d/%02d", (localtime)[4] + 1, (localtime)[3]
);
$self->{_hash}{title} =
(substr($self->{basepath}, 0, 4) eq 'man/')
? '¡º (untitled)' : '(untitled)';
$self->{_hash}{filemode} = 0;
open($DIR, "+>>$file")
or die "can't write DIR file for $self->{board}: $!";
print $DIR pack($packstring, @{$self->{_hash}}{@packlist});
close $DIR;
# print "Recno: ".$self->{recno}."\n";
}
}
return 1;
}
sub STORE {
my ($self, $key, $value) = @_;
$self = $self->ego;
$self->refresh_meta($key);
if ($key eq 'body') {
my $file = join('/', $self->basedir, $self->{name});
unless (-s $file) {
$value =
"§@ªÌ: ".($self->{_hash}{header}{From} || (
$self->{_hash}{author}." ".
(defined $self->{_hash}{nick}
? "($self->{_hash}{nick})" : "")
)) . " " .
"¬ÝªO: $self->{board} \n".
"¼ÐÃD: ".substr($self->{_hash}{title}, 0, 60)."\n".
"®É¶¡: ".localtime($self->{_hash}{time} || time).
"\n\n".
$value;
}
open(my $BODY, ">$file") or die "cannot open $file";
print $BODY $value;
close $BODY;
$self->{btime} = (stat($file))[9];
$self->{_hash}{$key} = $value;
}
else {
if ($key eq 'title' and
substr($self->{basepath}, 0, 4) eq 'man/' and
substr($value, 0, 3) ne '¡º ') {
$value = "¡º $value";
}
elsif ($key eq 'author') {
$value =~ s/(?:\.bbs)?\@.*$/./;
}
$self->{_hash}{$key} = $value;
my $file = join('/', $self->basedir, '.DIR');
open(my $DIR, "+<$file") or die "cannot open $file for writing";
binmode($DIR);
# print "seeeking to ".($packsize * $self->{recno});
seek $DIR, $packsize * $self->{recno}, 0;
print $DIR pack($packstring, @{$self->{_hash}}{@packlist});
close $DIR;
$self->filestamp($file);
}
}
sub remove {
my $self = shift;
$self->remove_entry(join('/', $self->basedir, '.DIR'));
return unlink join('/', $self->basedir, $self->{name});
}
1;
syntax highlighted by Code2HTML, v. 0.9.1