]>
git.p6c8.net - selfforum.git/blob - selfforum-cgi/shared/Posting/_lib.pm
3 # ====================================================
4 # Autor: n.d.p. / 2001-01-07
5 # lm : n.d.p. / 2001-02-25
6 # ====================================================
8 # * Schnittstellen fuer den Zugriff auf Messages
10 # ====================================================
14 package Posting
::_lib
;
16 use vars
qw(@EXPORT_OK);
17 use base qw(Exporter);
19 use Encode
::Plain
; $Encode::Plain
::utf8
= 1;
23 # ====================================================
25 # ====================================================
27 @EXPORT_OK = qw(get_message_header get_message_body get_message_node parse_single_thread
28 hr_time short_hr_time long_hr_time
30 create_forum_xml_string
33 # ====================================================
35 # ====================================================
37 ###########################
38 # sub get_message_header
40 # Messageheader auslesen
41 ###########################
43 sub get_message_header
($) {
47 my $header = $node -> getElementsByTagName
('Header', 0) -> item
(0);
48 my $author = $header -> getElementsByTagName
('Author', 0) -> item
(0);
49 my $name = $author -> getElementsByTagName
('Name', 0) -> item
(0);
50 my $email = $author -> getElementsByTagName
('Email', 0) -> item
(0);
51 my $home = $author -> getElementsByTagName
('HomepageUrl', 0) -> item
(0);
52 my $image = $author -> getElementsByTagName
('ImageUrl', 0) -> item
(0);
53 my $cat = $header -> getElementsByTagName
('Category', 0) -> item
(0);
54 my $subject = $header -> getElementsByTagName
('Subject', 0) -> item
(0);
55 my $date = $header -> getElementsByTagName
('Date', 0) -> item
(0);
57 %conf = (name
=> ($name -> hasChildNodes
)?
$name -> getFirstChild
-> getData
:undef,
58 category
=> ($cat -> hasChildNodes
)?
$cat -> getFirstChild
-> getData
:undef,
59 subject
=> ($subject -> hasChildNodes
)?
$subject -> getFirstChild
-> getData
:undef,
60 email
=> (defined ($email) and $email -> hasChildNodes
)?
$email -> getFirstChild
-> getData
:undef,
61 home
=> (defined ($home) and $home -> hasChildNodes
)?
$home -> getFirstChild
-> getData
:undef,
62 image
=> (defined ($image) and $image -> hasChildNodes
)?
$image -> getFirstChild
-> getData
:undef,
63 time => $date -> getAttribute
('longSec'));
67 ###########################
68 # sub get_message_header
70 # Messagebody auslesen
71 ###########################
73 sub get_message_body
($$)
78 foreach ($xml -> getElementsByTagName
('ContentList', 1) -> item
(0) -> getElementsByTagName
('MessageContent', 0))
80 if ($_ -> getAttribute
('mid') eq $mid)
82 $body = ($_ -> hasChildNodes
)?
$_ -> getFirstChild
-> getData
:'';
90 ###########################
91 # sub get_message_header
93 # Messagenode bestimmen
94 ###########################
96 sub get_message_node
($$$) {
97 my ($xml,$tid,$mid) = @_;
100 for ( $xml -> getElementsByTagName
('Thread')) {
101 if ($_ -> getAttribute
('id') eq $tid) {
103 for ($tnode -> getElementsByTagName
('Message')) {
104 if ($_ -> getAttribute
('id') eq $mid) {
109 wantarray?
($mnode, $tnode):$mnode;
112 ###########################
113 # sub parse_single_thread
115 # einzelne Threaddatei
117 ###########################
119 sub parse_single_thread
($$;$) {
120 my ($tnode, $deleted, $sorted) = @_;
121 my ($header, @msg, %mno);
123 for ($tnode -> getElementsByTagName
('Message')) {
124 $header = get_message_header
($_);
126 push @msg,{mid
=> ($_ -> getAttribute
('id') =~ /(\d+)/)[0],
127 ip
=> $_ -> getAttribute
('ip'),
128 kids
=> [$_ -> getElementsByTagName
('Message', 0)],
129 answers
=> $_ -> getElementsByTagName
('Message') -> getLength
,
130 deleted
=> $_ -> getAttribute
('invisible'),
131 archive
=> $_ -> getAttribute
('archive'),
132 name
=> plain
($header -> {name
}),
133 cat
=> plain
($header -> {category
} or ''),
134 subject
=> plain
($header -> {subject
}),
135 time => plain
($header -> {time})};
138 # Eintraege ergaenzen und korrigieren
140 $msg[0] -> {level
} = 0;
142 $level = $_ -> {level
} + 1;
143 @
{$_ -> {kids
}} = map {$msg[$mno{$_}] -> {level
} = $level; $mno{$_}} @
{$_ -> {kids
}};}
146 # Sortieren und bei Bedarf
147 # geloeschte Messages entfernen
149 my $smsg = sort_thread
(\
@msg, $sorted);
150 delete_messages
($smsg) unless ($deleted);
155 ###########################
156 # sub create_message_xml
160 ###########################
162 sub create_message_xml
($$$) {
163 my ($xml, $msges, $num) = @_;
165 my $msg = $msges -> [$num];
167 my $message = $xml -> createElement
('Message');
168 $message -> setAttribute
('id', 'm'.$msg -> {mid
});
169 $message -> setAttribute
('invisible', '1') if ($msg -> {deleted
});
170 $message -> setAttribute
('archive', '1') if ($msg -> {archive
});
173 my $header = $xml -> createElement
('Header');
175 # alles inside of 'Header'
176 my $author = $xml -> createElement
('Author');
178 my $name = $xml -> createElement
('Name');
179 $name -> addText
(toUTF8
($msg -> {name
}));
181 my $email = $xml -> createElement
('Email');
183 my $category = $xml -> createElement
('Category');
184 $category -> addText
(toUTF8
($msg -> {cat
}));
186 my $subject = $xml -> createElement
('Subject');
187 $subject -> addText
(toUTF8
($msg -> {subject
}));
189 my $date = $xml -> createElement
('Date');
190 $date -> setAttribute
('longSec', $msg -> {time});
192 $author -> appendChild
($name);
193 $author -> appendChild
($email);
194 $header -> appendChild
($author);
195 $header -> appendChild
($category);
196 $header -> appendChild
($subject);
197 $header -> appendChild
($date);
198 $message -> appendChild
($header);
200 if ($msg -> {kids
}) {
201 for (@
{$msg -> {kids
}}) {
202 $message -> appendChild
(&create_message_xml
($xml, $msges, $_));
209 # ====================================================
210 # XML-Parsen von Hand
211 # ====================================================
213 ###########################
218 ###########################
220 sub sort_thread
($$) {
221 my ($msg, $sorted) = @_;
223 my ($z, %mhash) = (0);
225 if ($sorted) { # aelteste zuerst
227 @
$msg[@
{$_ -> {kids
}}] = sort {$a -> {mid
} <=> $b -> {mid
}} @
$msg[@
{$_ -> {kids
}}] if (@
{$_ -> {kids
}} > 1);
228 $mhash{$_ -> {mid
}} = [@
$msg[@
{$_ -> {kids
}}]];}}
230 else { # juengste zuerst
232 @
$msg[@
{$_ -> {kids
}}] = sort {$b -> {mid
} <=> $a -> {mid
}} @
$msg[@
{$_ -> {kids
}}] if (@
{$_ -> {kids
}} > 1);
233 $mhash{$_ -> {mid
}} = [@
$msg[@
{$_ -> {kids
}}]];}}
235 # Kinder wieder richtig einsortieren
236 my @smsg = ($msg -> [0]);
239 splice @smsg,$z,0,@
{$mhash{$_ -> {mid
}}} if ($_ -> {answers
});
240 delete $_ -> {kids
};}
245 ###########################
246 # sub delete_messages
248 # geoeschte Nachrichten
250 ###########################
252 sub delete_messages
($) {
255 my ($z, $oldlevel, @path) = (0,0,0);
258 if ($_ -> {deleted
}) {
259 my $n = $_ -> {answers
}+1;
260 for (@path) {$smsg -> [$_] -> {answers
} -= $n;}
261 splice @
$smsg,$z,$n;}
264 if ($_ -> {level
} > $oldlevel) {
266 $oldlevel = $_ -> {level
};}
268 elsif ($_ -> {level
} < $oldlevel) {
269 splice @path,$_ -> {level
}-$oldlevel;
270 $oldlevel = $_ -> {level
};}
272 else { $path[-1] = $z; }
279 ###########################
280 # sub get_all_threads
282 # Hauptdatei laden und
284 ###########################
286 sub get_all_threads
($$;$) {
287 my ($file, $deleted, $sorted) = @_;
288 my ($last_thread, $last_message, @unids, %threads);
291 open FILE
, $file or return undef;
292 my $xml = join '', <FILE
>;
293 close(FILE
) or return undef;
296 ($last_thread) = map {/(\d+)/} $xml =~ /<Forum.+?lastThread="([^"]+)"[^>]*>/;
297 ($last_message) = map {/(\d+)/} $xml =~ /<Forum.+?lastMessage="([^"]+)"[^>]*>/;}
299 my $reg_msg = qr
~(?
:</Message
>
300 |<Message\s
+id
="m(\d+)"\s
+unid
="([^"]*)"(?:\s+invisible="([^"]*)")?
(?
:\s
+archive
="([^"]*)")?[^>]*>\s*
301 <Header>[^<]*(?:<(?!Name>)[^<]*)*
302 <Name>([^<]+)</Name>[^<]*(?:<(?!Category>)[^<]*)*
303 <Category>([^<]*)</Category>\s*
304 <Subject>([^<]+)</Subject>\s*
305 <Date\s+longSec="(\d
+)"[^>]*>\s*
306 </Header>\s*(?:(<)/Message>|(?=(<)Message\s*)))~sx;
308 while ($xml =~ /<Thread id="t
(\d
+)">([^<]*(?:<(?!\/Thread>)[^<]*)*)<\/Thread>/g) {
310 my ($tid, $thread) = ($1, $2);
311 my ($level, $cmno, @msg, @stack) = (0);
313 while ($thread =~ m;$reg_msg;g) {
316 push @stack,$cmno if (defined $cmno);
320 push @{$msg[$cmno] -> {kids}} => $#msg;
321 push @{$msg[$cmno] -> {unids}} => $2;}
325 for (@stack) {$msg[$_] -> {answers}++}
333 $msg[-1] -> {subject},
334 $msg[-1] -> {time}) = ($1, $2, $5, $6, $7, $8);
336 $msg[-1] -> {deleted} = $3;
337 $msg[-1] -> {archive} = $4;
339 $msg[-1] -> {name} =~ s/&/&/g;
340 $msg[-1] -> {cat} =~ s/&/&/g;
341 $msg[-1] -> {subject} =~ s/&/&/g;
343 $msg[-1] -> {unids} = [];
344 $msg[-1] -> {kids} = [];
345 $msg[-1] -> {answers} = 0;
346 $msg[-1] -> {level} = $level++;}
348 elsif (defined ($9)) {
352 push @{$msg[$cmno] -> {kids}} => $#msg;
353 push @{$msg[$cmno] -> {unids}} => $2;
354 $msg[$cmno] -> {answers}++;}
358 for (@stack) {$msg[$_] -> {answers}++}
364 $msg[-1] -> {subject},
365 $msg[-1] -> {time}) = ($1, $2, $5, $6, $7, $8);
367 $msg[-1] -> {deleted} = $3;
368 $msg[-1] -> {archive} = $4;
370 $msg[-1] -> {name} =~ s/&/&/g;
371 $msg[-1] -> {cat} =~ s/&/&/g;
372 $msg[-1] -> {subject} =~ s/&/&/g;
374 $msg[-1] -> {level} = $level;
375 $msg[-1] -> {unids} = [];
376 $msg[-1] -> {kids} = [];
377 $msg[-1] -> {answers} = 0;}
380 $cmno = pop @stack; $level--;}}
383 # Sortieren und bei Bedarf
384 # geloeschte Messages entfernen
386 my $smsg = sort_thread (\@msg, $sorted);
387 delete_messages ($smsg) unless ($deleted);
389 $threads{$tid} = $smsg if (@$smsg);
392 wantarray?(\%threads, $last_thread, $last_message, \@unids): \%threads;
395 ###########################
396 # sub create_forum_xml_string
398 # Forumshauptdatei erzeugen
399 ###########################
401 sub create_forum_xml_string ($$) {
402 my ($threads, $param) = @_;
403 my ($level, $thread, $msg);
405 my $xml = '<?xml version="1.0" encoding="UTF
-8"?>'."\n"
406 .'<!DOCTYPE Forum SYSTEM "'.$param -> {dtd}.'">'."\n"
407 .'<Forum lastMessage="'.$param -> {lastMessage}.'" lastThread="'.$param -> {lastThread}.'">';
409 foreach $thread (sort {$b <=> $a} keys %$threads) {
410 $xml .= '<Thread id="t
'.$thread.'">';
413 foreach $msg (@{$threads -> {$thread}}) {
414 $xml .= '</Message>' x ($level - $msg -> {level} + 1) if ($msg -> {level} <= $level);
415 $level = $msg -> {level};
416 $xml .= '<Message id="m
'.$msg -> {mid}.'"'
417 .' unid="'.$msg -> {unid}.'"'
418 .(($msg -> {deleted})?' invisible="1"':'')
419 .(($msg -> {archive})?' archive="1"':'')
424 .plain($msg -> {name})
429 .((length $msg -> {cat})?plain($msg -> {cat}):'')
432 .plain($msg -> {subject})
439 $xml .= '</Message>' x ($level + 1);
440 $xml .= '</Thread>';}
447 ###########################
451 ###########################
454 my ($filename,$content) = @_;
457 open FILE,">$filename.temp
" or return;
459 unless (print FILE $$content) {
463 close FILE or return;
465 rename "$filename.temp
", $filename or return;
470 # ====================================================
472 # ====================================================
474 ###########################
476 # 02. Januar 2001, 12:02 Uhr
479 # 02. 01. 2001, 12:02 Uhr
482 # Dienstag, 02. Januar 2001, 12:02:01 Uhr
484 # formatierte Zeitangabe
485 ###########################
488 my @month = (qw(Januar Februar), "M\303\244rz", qw(April Mail Juni Juli August September Oktober November Dezember));
491 my (undef, $min, $hour, $day, $mon, $year) = localtime ($_[0]);
493 sprintf ('%02d. %s %04d, %02d:%02d Uhr', $day, $month[$mon], $year+1900, $hour, $min);
496 sub short_hr_time
($) {
497 my (undef, $min, $hour, $day, $mon, $year) = localtime ($_[0]);
499 sprintf ('%02d. %02d. %04d, %02d:%02d Uhr', $day, $mon+1, $year+1900, $hour, $min);
502 sub long_hr_time
($) {
503 my @month = (qw(Januar Februar), "M\303\244rz", qw(April Mail Juni Juli August September Oktober November Dezember));
506 my @wday = qw(Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag);
507 my ($sek, $min, $hour, $day, $mon, $year, $wday) = localtime ($_[0]);
509 sprintf ('%s, %02d. %s %04d, %02d:%02d:%02d Uhr', $wday[$wday], $day, $month[$mon], $year+1900, $hour, $min, $sek);
512 # ====================================================
513 # Modulinitialisierung
514 # ====================================================
516 # making require happy
519 # ====================================================
520 # end of Posting::_lib
521 # ====================================================
patrick-canterino.de