1package Board::System; 2################################################################ 3# Board::System 4 5# 2002/01/27 Yoichi Imai <yoichi@silver-forest.com> 6 7# Copyright (C) 2002 Yoichi Imai <yoichi@silver-forest.com> 8 9# This program is free software; you can redistribute it and/or 10# modify it under the terms of the GNU General Public License 11# as published by the Free Software Foundation; either version 2 12# of the License, or (at your option) any later version. 13 14# This program is distributed in the hope that it will be useful, 15# but WITHOUT ANY WARRANTY; without even the implied warranty of 16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17# GNU General Public License for more details. 18 19# You should have received a copy of the GNU General Public License 20# along with this program; if not, write to the Free Software 21# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 22 23# $Id: System.pm,v 1.6 2003/05/28 04:52:53 togawa Exp $ 24################################################################ 25 26=head1 NAME 27 28Board::System - Board�����ƥ�Υ饤�֥����ʬ 29 30=head1 SYNOPSIS 31 32 my $board = new Board::System; 33 $board->Load(); 34 foreach my $article (@{$board->article_list}) { ... } 35 36=head1 DESCRIPTION 37Board�����ƥ�δ����� 38 39=cut 40################################################################ 41 42 43use strict; 44use Fcntl ':flock'; 45use ObjectTemplate; 46use Exporter; 47use DateTime::Format; 48use CodeConv; 49use Board::Article; 50use vars qw(@ISA @EXPORT); 51@ISA = qw(ObjectTemplate); 52@EXPORT = qw(attributes); 53 54attributes qw(article_list msgid_hash refid_hash); 55 56sub Error($$) 57{ 58 my ($self, $msg) = @_; 59 die "Error: $self, $msg\n"; 60 exit 1; 61} 62 63sub Load 64{ 65 my $self = shift; 66 67 my @article_list; 68 unless(open(FH, $Board::BoardData)) { 69 $self->Error("cannot open : '$Board::BoardData'"); 70 return; 71 } 72 73 eval 'flock(FH, LOCK_EX)'; 74 foreach my $line (<FH>) { 75 chomp($line); 76 my @list = split("\t", $line); 77 next if $#list == -1; # remove nothing line 78 my $article = new Board::Article; 79 $article->Set(@list); 80 push(@article_list, $article); 81 } 82 eval 'flock(FH, LOCK_UN)'; 83 close(FH); 84 $self->article_list(\@article_list); 85} 86 87# this function doesn't read deleted or fake_root message 88sub LoadLightly 89{ 90 my $self = shift; 91 my @article_list; 92 93 unless(open(FH, $Board::BoardData)) { 94 $self->Error("cannot open : '$Board::BoardData'"); 95 return; 96 } 97 98 eval 'flock(FH, LOCK_EX)'; 99 foreach my $line (<FH>) { 100 chomp($line); 101 my @list = split("\t", $line); 102 next if ($#list == -1); # remove nothing line 103 next if ($list[0] eq ''); # deleted message 104 next if ($list[2] eq 'root' && $list[3] ne ''); # fake root message 105 my $article = new Board::Article; 106 $article->Set(@list); 107 push(@article_list, $article); 108 } 109 eval 'flock(FH, LOCK_UN)'; 110 close(FH); 111 112 $self->article_list(\@article_list); 113} 114sub Save 115{ 116 my $self = shift; 117 my %skip_msgids; 118 119 my @article_list = @{$self->article_list}; 120 121 if(@article_list > $Board::MaxArticle) { 122 for(my $i = 0; $i < @article_list - $Board::MaxArticle; $i++) { 123 unless ($article_list[$i]->IsFakeRoot()) { 124 $article_list[$i]->Delete(); 125 } 126 } 127 } 128 129 $self->CreateMsgidHash(); 130 $self->CreateRefidHash(); 131 132 # remove blank tree 133 foreach my $root_article (@{$self->refid_hash->{'root'}}) { 134 if($self->IsDeletedTree($root_article)) { 135 foreach my $msgid ($self->GetTreeMemberMsgids($root_article, ())) { 136 $skip_msgids{$msgid} = 1; 137 } 138 } 139 } 140 141 unless(open(FH, '>' . $Board::BoardData)) { 142 $self->Error("cannot open(write) : '$Board::BoardData'"); 143 return; 144 } 145 eval 'flock(FH, LOCK_EX)'; 146 foreach my $article (@article_list) { 147 print FH $article->GetStr() if $article && !($skip_msgids{$article->msgid} == 1); 148 } 149 eval 'flock(FH, LOCK_UN)'; 150 close(FH); 151} 152 153sub Add 154{ 155 my ($self, $article) = @_; 156 push(@{$self->article_list}, $article); 157} 158 159sub CreateMsgidHash 160{ 161 my $self = shift; 162 $self->msgid_hash({}); 163 foreach my $article (@{$self->article_list}) { 164 $self->msgid_hash->{$article->msgid} = $article; 165 } 166} 167sub CreateRefidHash 168{ 169 my $self = shift; 170 my $refid_hash = {}; 171 foreach my $article (@{$self->article_list}) { 172 $refid_hash->{$article->refid} = [] unless (defined($refid_hash->{$article->refid})); 173 push(@{$refid_hash->{$article->refid}}, $article); 174 } 175 $self->refid_hash($refid_hash); 176} 177sub GetNewMsgid 178{ 179 my $self = shift; 180 my $new_id; 181 182 foreach my $article (@{$self->article_list}) { 183 $new_id = $article->msgid if ($new_id < $article->msgid); 184 } 185 return $new_id + 1; 186} 187sub AddNewMsg 188{ 189 my ($self, $delete_key, $refid, $diary, $ruri_code, $subject, $name, $email, $site, $host, $body) = @_; 190 my $ref; 191 192 my $article = new Board::Article; 193 194 CodeConv::toeuc(\$subject); 195 CodeConv::toeuc(\$name); 196 CodeConv::toeuc(\$email); 197 CodeConv::toeuc(\$site); 198 CodeConv::toeuc(\$body); 199 200 $article->Set($delete_key, 201 $self->GetNewMsgid, 202 $refid, 203 $diary, 204 $ruri_code, 205 time(), 206 $subject, 207 $name, 208 $email, 209 $site, 210 $host, 211 $body); 212 213 $self->Add($article); 214 215 return $article; 216} 217sub SearchFakeRoot 218{ 219 my ($self, $diary) = @_; 220 my $fake_root; 221 222 foreach my $article (@{$self->article_list}) { 223 $fake_root = $article if ($article->IsRoot() && $article->ref_diary == $diary); 224 } 225 return $fake_root; 226} 227sub IsDeletedTree 228{ 229 my ($self, $root_article) = @_; 230 231 return 0 if ($root_article->delete_key ne '' && !($root_article->IsFakeRoot())); 232 foreach my $article (@{$self->refid_hash->{$root_article->msgid}}) { 233 if ($self->IsDeletedTree($article) == 0) { 234 return 0; 235 } 236 } 237 return 1; 238} 239sub GetTreeMemberMsgids 240{ 241 my ($self, $root_article, @list) = @_; 242 243 return @list unless ($root_article); 244 245 push(@list, $root_article->msgid); 246 foreach my $article (@{$self->refid_hash->{$root_article->msgid}}) { 247 push(@list, $self->GetTreeMemberMsgids($article, @list)); 248 } 249 250 return @list; 251} 252# not instance method 253sub get_diary_title 254{ 255 my $diary = shift; 256 my ($title, $new_count); 257 258 die "diary_title_error" unless $diary =~ /(\d{4})(\d{2})(\d{2})(\d+)/; 259 260 my ($year, $month, $day, $section) = ($1, $2, $3, $4); 261 my $file = "${HNS::System::DiaryDir}/${year}/d${year}${month}${day}.hnf"; 262 unless(open(FH, $file)) { 263 die ("cannot open hnf : '$file'"); 264 return; 265 } 266 267 $new_count = 1; 268 eval 'flock(FH, LOCK_EX)'; 269 foreach my $line (<FH>) { 270 if ($line =~ /^NEW (.*)/) { 271 $title = $1; 272 } elsif ($line =~ /^LNEW [^ ]* (.*)/) { 273 $title = $1; 274 } elsif ($line =~ /^RLNEW [^ ]* [^ ]* (.*)/) { 275 $title = $1; 276 } 277 278 $new_count -= 1 if ($line =~ /^GRP/); 279 if ($line =~ /^R?L?NEW /) { 280 last if ($new_count == $section); 281 $new_count++; 282 } 283 } 284 eval 'flock(FH, LOCK_UN)'; 285 close(FH); 286 287 CodeConv::toeuc(\$title); 288 return $title; 289} 2901; 291