1 package Onis::Plugins::Core;
6 use Onis::Config qw/get_config/;
7 use Onis::Html qw/html_escape get_filehandle/;
8 use Onis::Language qw/translate/;
9 use Onis::Users qw/get_name get_link get_image nick_to_username/;
10 use Onis::Data::Core qw#all_nicks nick_to_ident ident_to_nick get_main_nick register_plugin#;
11 use Onis::Data::Persistent qw#init#;
14 our $QUOTE_CACHE = init ('$QUOTE_CACHE', 'hash');
16 our @H_IMAGES = qw#dark-theme/h-red.png dark-theme/h-blue.png dark-theme/h-yellow.png dark-theme/h-green.png#;
17 our $QUOTE_CACHE_SIZE = 10;
21 our $SORT_BY = 'LINES';
22 our $DISPLAY_LINES = 'BOTH';
23 our $DISPLAY_WORDS = 'NONE';
24 our $DISPLAY_CHARS = 'NONE';
25 our $DISPLAY_TIMES = 0;
26 our $DISPLAY_IMAGES = 0;
27 our $DEFAULT_IMAGE = '';
28 our $BAR_HEIGHT = 130;
33 if (get_config ('quote_cache_size'))
35 my $tmp = get_config ('quote_cache_size');
37 $QUOTE_CACHE_SIZE = $tmp if ($tmp);
39 if (get_config ('quote_min'))
41 my $tmp = get_config ('quote_min');
43 $QUOTE_MIN = $tmp if ($tmp);
45 if (get_config ('quote_max'))
47 my $tmp = get_config ('quote_max');
49 $QUOTE_MAX = $tmp if ($tmp);
51 if (get_config ('min_word_length'))
53 my $tmp = get_config ('min_word_length');
55 $WORD_LENGTH = $tmp if ($tmp);
57 if (get_config ('display_lines'))
59 my $tmp = get_config ('display_lines');
62 if (($tmp eq 'NONE') or ($tmp eq 'BAR') or ($tmp eq 'NUMBER') or ($tmp eq 'BOTH'))
64 $DISPLAY_LINES = $tmp;
68 $tmp = get_config ('display_lines');
69 print STDERR $/, __FILE__, ": ``display_lines'' has been set to the invalid value ``$tmp''. ",
70 $/, __FILE__, ": Valid values are ``none'', ``bar'', ``number'' and ``both''. Using default value ``both''.";
73 if (get_config ('display_words'))
75 my $tmp = get_config ('display_words');
78 if (($tmp eq 'NONE') or ($tmp eq 'BAR') or ($tmp eq 'NUMBER') or ($tmp eq 'BOTH'))
80 $DISPLAY_WORDS = $tmp;
84 $tmp = get_config ('display_words');
85 print STDERR $/, __FILE__, ": ``display_words'' has been set to the invalid value ``$tmp''. ",
86 $/, __FILE__, ": Valid values are ``none'', ``bar'', ``number'' and ``both''. Using default value ``none''.";
89 if (get_config ('display_chars'))
91 my $tmp = get_config ('display_chars');
94 if (($tmp eq 'NONE') or ($tmp eq 'BAR') or ($tmp eq 'NUMBER') or ($tmp eq 'BOTH'))
96 $DISPLAY_CHARS = $tmp;
100 $tmp = get_config ('display_chars');
101 print STDERR $/, __FILE__, ": ``display_chars'' has been set to the invalid value ``$tmp''. ",
102 $/, __FILE__, ": Valid values are ``none'', ``bar'', ``number'' and ``both''. Using default value ``none''.";
105 if (get_config ('display_times'))
107 my $tmp = get_config ('display_times');
109 if ($tmp =~ m/true|on|yes/i)
113 elsif ($tmp =~ m/false|off|no/i)
119 print STDERR $/, __FILE__, ": ``display_times'' has been set to the invalid value ``$tmp''. ",
120 $/, __FILE__, ": Valid values are ``true'' and ``false''. Using default value ``false''.";
123 if (get_config ('display_images'))
125 my $tmp = get_config ('display_images');
127 if ($tmp =~ m/true|on|yes/i)
131 elsif ($tmp =~ m/false|off|no/i)
137 print STDERR $/, __FILE__, ": ``display_times'' has been set to the invalid value ``$tmp''. ",
138 $/, __FILE__, ": Valid values are ``true'' and ``false''. Using default value ``false''.";
141 if (get_config ('default_image'))
143 $DEFAULT_IMAGE = get_config ('default_image');
145 if (get_config ('sort_by'))
147 my $tmp = get_config ('sort_by');
150 if (($tmp eq 'LINES') or ($tmp eq 'WORDS') or ($tmp eq 'CHARS'))
156 $tmp = get_config ('sort_by');
157 print STDERR $/, __FILE__, ": ``sort_by'' has been set to the invalid value ``$tmp''. ",
158 $/, __FILE__, ": Valid values are ``lines'' and ``words''. Using default value ``lines''.";
161 if (get_config ('horizontal_images'))
163 my @tmp = get_config ('horizontal_images');
166 if (scalar (@tmp) != 4)
168 print STDERR $/, __FILE__, ": The number of horizontal images is not four. The output might look weird.", $/;
171 for ($i = 0; $i < 4; $i++)
173 if (!defined ($tmp[$i]))
178 $H_IMAGES[$i] = $tmp[$i];
181 if (get_config ('bar_height'))
183 my $tmp = get_config ('bar_height');
185 $BAR_HEIGHT = $tmp if ($tmp >= 10);
187 if (get_config ('bar_width'))
189 my $tmp = get_config ('bar_width');
191 $BAR_WIDTH = $tmp if ($tmp >= 10);
193 if (get_config ('longlines'))
195 my $tmp = get_config ('longlines');
197 $LONGLINES = $tmp if ($tmp);
199 if (get_config ('shortlines'))
201 my $tmp = get_config ('shortlines');
203 if ($tmp or ($tmp == 0))
209 $DATA = register_plugin ('TEXT', \&add);
210 $DATA = register_plugin ('ACTION', \&add);
211 $DATA = register_plugin ('OUTPUT', \&output);
213 if (!defined ($DATA->{'byhour'}))
215 $DATA->{'byhour'} = [];
218 my $VERSION = '$Id: Core.pm,v 1.12 2004/04/30 06:56:13 octo Exp $';
219 print STDERR $/, __FILE__, ": $VERSION" if ($::DEBUG);
227 my $nick = $data->{'nick'};
228 my $ident = $data->{'ident'};
229 my $hour = int ($data->{'hour'});
230 my $host = $data->{'host'};
231 my $text = $data->{'text'};
232 my $type = $data->{'type'};
234 my $words = scalar (@{$data->{'words'}});
235 my $chars = length ($text);
236 if ($type eq 'ACTION')
238 $chars -= (length ($nick) + 3);
241 $DATA->{'byident'}{$ident}{'lines'}++;
242 $DATA->{'byident'}{$ident}{'words'} += $words;
243 $DATA->{'byident'}{$ident}{'chars'} += $chars;
244 $DATA->{'byident'}{$ident}{'lines_time'}{$hour}++;
245 $DATA->{'byident'}{$ident}{'words_time'}{$hour} += $words;
246 $DATA->{'byident'}{$ident}{'chars_time'}{$hour} += $chars;
248 $DATA->{'byhour'}[$hour] += $chars;
250 if ((length ($text) >= $QUOTE_MIN)
251 and (length ($text) <= $QUOTE_MAX))
253 if (!defined ($QUOTE_CACHE->{$nick}))
255 $QUOTE_CACHE->{$nick} = [];
257 push (@{$QUOTE_CACHE->{$nick}}, $text);
260 if (defined ($QUOTE_CACHE->{$nick}))
262 while (scalar (@{$QUOTE_CACHE->{$nick}}) > $QUOTE_CACHE_SIZE)
264 shift (@{$QUOTE_CACHE->{$nick}});
277 # this subroutines doesn't take any arguments either (stupid me). It prints the
278 # daily usage to the file.
281 my $max = 0; # the most lines that were written in one hour..
282 my $total = 0; # the total amount of lines we wrote..
283 my ($i, $j); # used in for-loops
284 my $factor = 0; # used to find a bar's height
285 my $newline = ''; # buffer variable..
287 my @data = @{$DATA->{'byhour'}};
289 my @img_urls = get_config ('vertical_images');
292 @img_urls = qw#images/ver0n.png images/ver1n.png images/ver2n.png images/ver3n.png#;
295 my $fh = get_filehandle () or die;
297 # this for loop looks for the most amount of lines in one hour and sets
299 for ($i = 0; $i < 24; $i++)
301 if (!defined ($data[$i]))
308 if ($data[$i] > $max)
320 $factor = (($BAR_HEIGHT - 1) / $max);
322 my $header = translate ('When do we actually talk here?');
323 print $fh "<h2>$header</h2>\n",
324 qq#<table class="hours_of_day">\n#,
327 # this for circles through the four colors. Each color represents six hours.
328 # (4 * 6 hours = 24 hours)
329 for ($i = 0; $i <= 3; $i++)
331 for ($j = 0; $j <= 5; $j++)
333 my $hour = (($i * 6) + $j);
334 if (!defined ($data[$hour]))
339 my $percent = 100 * ($data[$hour] / $total);
340 my $height = int ($data[$hour] * $factor) + 1;
341 my $img_url = $img_urls[$i];
343 print $fh ' <td>', sprintf ("%2.1f", $percent),
344 qq#%<br /><img src="$img_url" style="height: $height#,
345 qq#px;" alt="" /></td>\n#;
349 print $fh " </tr>\n",
350 qq# <tr class="hour_row">\n#;
351 print $fh map { " <td>$_</td>\n" } (0 .. 23);
352 print $fh " </tr>\n",
362 defined ($DATA->{'byname'}{$_}{'words'})
363 } (keys (%{$DATA->{'byname'}}));
371 my $fh = get_filehandle () or die;
373 my $sort_field = lc ($SORT_BY);
378 ($tmp) = sort { $DATA->{'byname'}{$b}{'lines'} <=> $DATA->{'byname'}{$a}{'lines'} } (@names);
379 $max_lines = $DATA->{'byname'}{$tmp}{'lines'} || 0;
381 ($tmp) = sort { $DATA->{'byname'}{$b}{'words'} <=> $DATA->{'byname'}{$a}{'words'} } (@names);
382 $max_words = $DATA->{'byname'}{$tmp}{'words'} || 0;
384 ($tmp) = sort { $DATA->{'byname'}{$b}{'chars'} <=> $DATA->{'byname'}{$a}{'chars'} } (@names);
385 $max_chars = $DATA->{'byname'}{$tmp}{'chars'} || 0;
387 $trans = translate ('Most active nicks');
389 print $fh "<h2>$trans</h2>\n";
390 if ($SORT_BY eq 'LINES')
392 $trans = translate ('Nicks sorted by numbers of lines written');
394 elsif ($SORT_BY eq 'WORDS')
396 $trans = translate ('Nicks sorted by numbers of words written');
398 else # ($SORT_BY eq 'CHARS')
400 $trans = translate ('Nicks sorted by numbers of characters written');
402 print $fh "<p>($trans)</p>\n";
406 <table class="big_ranking">
408 <td class="invis"> </td>
412 $trans = translate ('Image');
413 print $fh " <th>$trans</th>\n";
417 $trans = translate ('Nick');
418 print $fh " <th>$trans</th>\n";
420 if ($DISPLAY_LINES ne 'NONE')
422 $trans = translate ('Number of Lines');
423 print $fh " <th>$trans</th>\n";
425 if ($DISPLAY_WORDS ne 'NONE')
427 $trans = translate ('Number of Words');
428 print $fh " <th>$trans</th>\n";
430 if ($DISPLAY_CHARS ne 'NONE')
432 $trans = translate ('Number of Characters');
433 print $fh " <th>$trans</th>\n";
437 $trans = translate ('When?');
438 print $fh " <th>$trans</th>\n";
441 $trans = translate ('Random Quote');
442 print $fh " <th>$trans</th>\n",
447 $DATA->{'byname'}{$b}{$sort_field} <=> $DATA->{'byname'}{$a}{$sort_field}
454 if (ident_to_nick ($name))
456 $nick = ident_to_nick ($name);
460 $ident = nick_to_ident ($name);
465 # As long as we didn't hit the
466 # $LONGLINES-limit we continue
468 if ($linescount <= $LONGLINES)
470 my $quote = translate ('-- no quote available --');
472 if (defined ($QUOTE_CACHE->{$nick}))
474 my $num = scalar (@{$QUOTE_CACHE->{$nick}});
475 my $rand = int (rand ($num));
476 $quote = html_escape ($QUOTE_CACHE->{$nick}[$rand]);
484 $link = get_link ($name);
485 $image = get_image ($name);
486 $title = get_name ($name);
490 qq# <td class="numeration"># . $linescount . "</td>\n";
494 if ($DEFAULT_IMAGE and !$image)
496 $image = $DEFAULT_IMAGE;
499 print $fh qq# <td class="image">#;
504 print $fh qq#<a href="$link">#;
506 print $fh qq#<img src="$image" alt="$name" />#;
521 $title = "Ident: $ident";
523 print $fh qq# <td class="nick" title="$title">#;
527 print $fh qq#<a href="$link">$name</a></td>\n#
531 print $fh qq#$name</td>\n#;
534 if ($DISPLAY_LINES ne 'NONE')
536 print $fh qq# <td class="bar">#;
537 if (($DISPLAY_LINES eq 'BOTH') or ($DISPLAY_LINES eq 'BAR'))
539 my $code = bar ($max_lines, $DATA->{'byname'}{$name}{'lines_time'});
542 print $fh ' ' if ($DISPLAY_LINES eq 'BOTH');
543 if (($DISPLAY_LINES eq 'BOTH') or ($DISPLAY_LINES eq 'NUMBER'))
545 print $fh $DATA->{'byname'}{$name}{'lines'};
550 if ($DISPLAY_WORDS ne 'NONE')
552 print $fh qq# <td class="bar">#;
553 if (($DISPLAY_WORDS eq 'BOTH') or ($DISPLAY_WORDS eq 'BAR'))
555 my $code = bar ($max_words, $DATA->{'byname'}{$name}{'words_time'});
558 print $fh ' ' if ($DISPLAY_WORDS eq 'BOTH');
559 if (($DISPLAY_WORDS eq 'BOTH') or ($DISPLAY_WORDS eq 'NUMBER'))
561 print $fh $DATA->{'byname'}{$name}{'words'};
566 if ($DISPLAY_CHARS ne 'NONE')
568 print $fh qq# <td class="bar">#;
569 if (($DISPLAY_CHARS eq 'BOTH') or ($DISPLAY_CHARS eq 'BAR'))
571 my $code = bar ($max_chars, $DATA->{'byname'}{$name}{'chars_time'});
574 print $fh ' ' if ($DISPLAY_CHARS eq 'BOTH');
575 if (($DISPLAY_CHARS eq 'BOTH') or ($DISPLAY_CHARS eq 'NUMBER'))
577 print $fh $DATA->{'byname'}{$name}{'chars'};
584 my $chars = $DATA->{'byname'}{$name}{'chars'};
585 my $code = bar ($chars, $DATA->{'byname'}{$name}{'chars_time'});
587 print $fh qq# <td class="bar">$code</td>\n#;
590 print $fh qq# <td class="quote">$quote</td>\n#,
593 if ($linescount == $LONGLINES)
595 print $fh "</table>\n\n";
599 # Ok, we have too many people to
600 # list them all so we start a
601 # smaller table and just list the
602 # names.. (Six names per line..)
603 elsif ($linescount <= ($LONGLINES + 6 * $SHORTLINES))
605 my $row_in_this_table = int (($linescount - $LONGLINES - 1) / 6);
606 my $col_in_this_table = ($linescount - $LONGLINES - 1) % 6;
609 if ($SORT_BY eq 'LINES')
611 $total = $DATA->{'byname'}{$name}{'lines'};
613 elsif ($SORT_BY eq 'WORDS')
615 $total = $DATA->{'byname'}{$name}{'words'};
617 else # ($SORT_BY eq 'CHARS')
619 $total = $DATA->{'byname'}{$name}{'chars'};
622 if ($row_in_this_table == 0 and $col_in_this_table == 0)
624 $trans = translate ("They didn't write so much");
625 print $fh "<h2>$trans</h2>\n",
626 qq#<table class="small_ranking">\n#,
630 if ($col_in_this_table == 0 and $row_in_this_table != 0)
632 print $fh " </tr>\n",
636 print $fh " <td>$name ($total)</td>\n";
638 if ($row_in_this_table == $SHORTLINES and $col_in_this_table == 5)
640 print $fh " </tr>\n",
645 # There is no else. There are
646 # just too many people around.
647 # I might add a "There are xyz
648 # unmentioned nicks"-line..
651 if (($linescount > $LONGLINES)
652 and ($linescount <= ($LONGLINES + 6 * $SHORTLINES)))
654 my $col = ($linescount - $LONGLINES - 1) % 6;
658 print $fh qq# <td> </td>\n#;
662 print $fh " </tr>\n";
665 if ($linescount != $LONGLINES)
667 print $fh "</table>\n\n";
671 # this is called by "&ranking ();" and prints the horizontal usage-bar in the
672 # detailed nick-table
679 # BAR_WIDTH is a least 10
680 my $max_width = $BAR_WIDTH - 4;
687 if (!$max_num) { return ($retval); }
688 $factor = $max_width / $max_num;
690 for ($i = 0; $i < 4; $i++)
694 my $img = $H_IMAGES[$i];
696 for ($j = 0; $j < 6; $j++)
698 my $hour = ($i * 6) + $j;
700 if (defined ($source->{$hour}))
702 $sum += $source->{$hour};
706 $width += int (0.5 + ($sum * $factor));
708 $retval .= qq#<img src="$img" style="width: # . $width . q#px"#;
709 if ($i == 0) { $retval .= qq# class="first"#; }
710 elsif ($i == 3) { $retval .= qq# class="last"#; }
711 $retval .= ' alt="" />';
722 my @keys = keys (%$source);
727 my $val = $source->{$key};
729 if (!defined ($target->{$key}))
731 $target->{$key} = $val;
738 print STDERR $/, __FILE__, ": ``$key'' = ``$val''" if ($::DEBUG);
742 $target->{$key} += $val;
745 elsif (ref ($val) eq "HASH")
747 merge_hashes ($target->{$key}, $val);
749 elsif (ref ($val) eq "ARRAY")
751 print STDERR $/, __FILE__, ": There is an array ``$key''";
752 push (@{$target->{$key}}, @$val);
756 my $type = ref ($val);
757 print STDERR $/, __FILE__, ": Reference type ``$type'' is not supported!", $/;