2 ##########################################################################
3 # onis 0.8.0 2005-04-17 #
4 #---=============--------------------------------------------------------#
6 # Purpose: Generating statistics #
7 # Input: IRC-Logfiles #
8 # Output: One HTML file #
9 # Version: 0.8.0 (unstable) #
11 # Homepage: http://verplant.org/onis/ #
12 # Authors: Florian octo Forster <octo@verplant.org> #
13 # Contributions are listed in THANKS #
14 ##########################################################################
18 if ($0 =~ m#^(.*)[/\\]#) { chdir ($1); }
20 unshift (@INC, 'lib');
22 # 0x0010 Language (make not-translated lines red/yellow)
23 # 0x0020 Parser (dropped lines)
24 # 0x0040 Parser (time information)
25 # 0x0100 Data::Core (host unsharp)
26 # 0x0200 Data::Persistent
27 # 0x0400 Data::Core (dump incoming data to stderr)
28 # 0x0800 Data::Core (initializing)
35 use vars qw/$VERSION $REVISION/;
37 use Onis::Config qw/get_config parse_argv read_config/;
38 use File::Basename qw/dirname/;
43 onis - onis not irs stats
47 B<onis> [I<options>] I<logfile>...
51 onis is a script that converts IRC logfiles into an HTML statistics page. It
52 provides information about daily channel usage, user activity, and channel
53 trivia. It provides a configurable customization and supports Dancer,
54 dircproxy, eggdrop, irssi, mIRC, and XChat logs. Persistent data (history
55 files) and automatic log purging make onis applicable for a large number of
56 logfiles. It also features a powerful translation infrastructure.
61 $REVISION = '$LastChangedRevision$';
66 $VERSION =~ s/^\D*(\d+).*/r$1/;
72 print STDERR $/, __FILE__, ': $Id$' if ($::DEBUG);
75 read_config (get_config ('config') ? get_config ('config') : 'onis.conf');
76 read_config (scalar get_config ('theme')) if (get_config ('theme'));
78 my $output = get_config ('output');
81 $output = "reports/onis.html";
84 foreach ('Core', get_config ('plugin'))
86 my $module = ucfirst (lc ($_));
87 require "Onis/Plugins/$module.pm";
90 if (!get_config ('input'))
92 # TODO: Make a complete (!) lsit..
95 Usage: $0 [options] <logfile> [logfile logfile ..]
98 --config Specify alternate config file
99 --output <file> Defines the file to write the HTML to.
100 --overwrite <bool> Overwrites files without prompting.
101 --channel <channel> Defines the channel's name.
102 --logtype <type> Defines the logfile's type.
103 See 'config' for a complete list.
104 --user <name> Define's the generator's name.
106 For a full list of all options please read the ``config'' file.
114 if (get_config ('overwrite'))
116 my $tmp = lc (get_config ('overwrite'));
117 if ($tmp eq 'true' or $tmp eq 'yes' or $tmp eq 'on')
125 print STDERR <<MESSAGE;
127 WARNING: The output file ``$output'' already exists
129 You can set the ``overwrite'' option in the config
130 file to disable this dialog.
133 print STDERR 'Are you sure you want to overwrite it? [Y|n] ';
134 my $answer = <STDIN>;
135 exit (1) if ($answer =~ m/n/i);
139 my $logtype = 'Eggdrop';
140 if (get_config ('logtype'))
142 $logtype = ucfirst (lc (get_config ('logtype')));
145 require "Onis/Parser/$logtype.pm";
146 require Onis::Parser::Persistent;
147 require Onis::Data::Persistent;
148 import Onis::Parser (qw(parse last_date));
149 import Onis::Parser::Persistent (qw(newfile));
150 import Onis::Data::Persistent ();
152 $FileInfo = Onis::Data::Persistent->new ('FileInfo', 'inode', qw(mtime));
154 if (get_config ('purge_logs'))
156 my $temp = lc (get_config ('purge_logs'));
157 if (($temp eq 'truncate') or ($temp eq 'shorten'))
161 elsif (($temp eq 'delete') or ($temp eq 'remove')
168 for (get_config ('input'))
178 ($inode, $size, $mtime) = (stat ($file))[1,7,9];
180 print STDERR $/, $/, __FILE__, " --- New File ``$file'' ---" if ($::DEBUG & 0x200);
182 if (!defined ($mtime))
184 print STDERR $/, __FILE__, ": Unable to stat file ``$file''";
189 my ($old_mtime) = $FileInfo->get ($inode);
191 print STDERR $/, __FILE__, ": ``$file'': " if ($::DEBUG & 0x200);
193 if (defined ($old_mtime))
195 if ($old_mtime == $mtime)
197 print STDERR "File did not change. Skipping." if ($::DEBUG & 0x200);
200 elsif ($old_mtime < $mtime)
202 print STDERR "File changed. Reading it again." if ($::DEBUG & 0x200);
206 print STDERR "File ``$file'' is older than expected. There might be a problem!";
211 print STDERR "File appears to be new. Reading it." if ($::DEBUG & 0x200);
213 $FileInfo->put ($inode, $mtime);
219 unless (open ($logfile, '+< ' . $file))
221 print STDERR $/, __FILE__, ": Unable to open file ``$file'': $!";
227 unless (open ($logfile, '< ' . $file))
229 print STDERR $/, __FILE__, ": Unable to open file ``$file'': $!";
236 unless (flock ($logfile, LOCK_EX))
238 print STDERR $/, __FILE__, ": Unable to get an exclusive lock for file ``$file'': $!";
245 unless (flock ($logfile, LOCK_SH))
247 print STDERR $/, __FILE__, ": Unable to get a shared lock for file ``$file'': $!";
253 newfile ($FileInfo->{$inode});
257 $status = parse ($_);
261 # 2 == unable to parse
263 # 4 == don't have date
267 print STDERR $/, __FILE__, ": Rewinding file ``$file''" if ($::DEBUG & 0x200);
268 seek ($logfile, 0, 0);
271 elsif (($status == 1) or ($status == 2)
274 $position = tell ($logfile);
282 print STDERR $/, __FILE__, ": Parser returned unknown status code: ``$status''";
286 if ($PurgeLogs and (($status == 1)
291 #and (($position + 1) >= $size)
295 print STDERR $/, __FILE__, ": Deleting empty file ``$file''" if ($::DEBUG & 0x200);
300 unless (unlink ($file))
302 print STDERR $/, __FILE__, ": Unable to delete empty file ``$file'': $!";
304 delete ($FileInfo->{$inode});
308 print STDERR $/, __FILE__, ": Won't delete ``$file''. Set it to writeable first!";
313 seek ($logfile, 0, 0);
314 if (truncate ($logfile, 0))
316 print $logfile &last_date ();
317 print STDERR $/, __FILE__, ": Truncated ``$file''" if ($::DEBUG & 0x200);
321 print STDERR $/, __FILE__, ": Couldn't truncate file ``$file'': $!";
333 require Onis::Data::Core;
335 import Onis::Data::Core qw#print_output#;
336 import Onis::Html qw#open_file close_file#;
338 if (open_file ($output))
345 # Fail and make noise! ;)
346 print STDERR <<MESSAGE;
348 ERROR: Unable to open output file
350 The output file ``$output'' could not be opened. Please make sure to set
351 the permissions right and try again.
361 print $/ if ($::DEBUG);
370 =item B<config>: I<file>;
372 Load the config from this file. B<(command line only)>
374 =item B<users_config>: I<file>;
376 Sets the file from which to read the user configuration.
378 =item B<language_file>: I<file>;
380 Sets the language file/translation to use.
382 =item B<plugin>: I<string>;
384 Sets the plugins to load. The plugin B<Core> will always be loaded.
386 =item B<input>: I<file>;
388 Read and parse this file(s). B<(config file only)>
390 =item B<logtype>: I<string>;
392 Sets the parser to use for parsing the input file.
394 =item B<output>: I<file>;
396 Write the generated output to this file.
398 =item B<overwrite>: I<bool>;
400 Sets wether or not to overwrite the output-file if it exists.
402 =item B<purge_logs>: "I<false>" | "I<truncate>" | "I<delete>";
404 Sets wether logs should be truncated or even removes after they have been
407 =item B<user>: I<string>;
409 Sets the user generating the stats if it's not detected right.
411 =item B<channel>: I<string>;
413 Sets the name of the channel being parsed. Normally this is auto-detected.
415 =item B<unsharp>: "I<none>" | "I<light>" | "I<medium>" | "I<hard>";
417 Sets how to do unsharping. What each setting actually does is described in the
418 readme and in L<Onis::Data::Core>.
426 =item B<theme>: I<file>;
430 =item B<stylesheet>: I<file>;
432 Sets the stylesheet (.css file) to use. This should be set in a theme file.
434 =item B<color_codes>: I<bool>;
436 Wether to print mIRC color-codes or filter them.
438 =item B<display_images>: I<bool>;
440 Sets if user-images should be displayed.
442 =item B<default_image>: I<file>;
444 Sets the default image to use if no user-defined image is available.
446 =item B<display_lines>: "I<none>" | "I<number>" | "I<bar>" | "I<both>";
448 =item B<display_words>: "I<none>" | "I<number>" | "I<bar>" | "I<both>";
450 =item B<display_chars>: "I<none>" | "I<number>" | "I<bar>" | "I<both>";
452 Sets if and how lines, words and/or characters should be displayed.
454 =item B<sort_by>: "I<lines>" | "I<words>" | "I<chars>";
456 Sets wether to sort by lines, words or characters written.
458 =item B<display_times>: I<bool>;
460 Wether or not to display a fixed width bar that shows when a user is most
463 =item B<bar_height>: I<number>;
465 =item B<bar_width>: I<number>;
467 Sets the width of horizontal bars and the height of vertical bars.
469 =item B<horizontal_images>: I<file>, I<file>, I<file>, I<file>;
471 =item B<vertical_images>: I<file>, I<file>, I<file>, I<file>;
473 Sets the images to use for horizontal and vertical bars. This should be used in
476 =item B<encoding>: I<string>;
478 Sets the encoding for the output file. This is merely the string that will be
479 included in the generated HTML file.
481 =item B<public_page>: I<bool>;
483 Wether or not this is a public page. Public pages may be linked on the onis
484 homepage at some point in the fututre..
488 =head2 Storage / Persistency
492 =item B<storage_module>: I<string>;
494 Sets the storage-module to use.
496 =item B<storage_dir>: I<directory>;
498 Sets the directory to store persistency information under.
500 =item B<storage_file>: I<file>;
502 Sets the file to write persistency data to, if applicable by the
511 =item B<min_word_length>: I<number>;
513 Substring containing only word-characters needs to be this long to be
516 =item B<plugin_max>: I<number>;
518 Sets the number of "most referenced nicks", "most used words" and the like to
519 be displayed. This option will be removed in the future.
521 =item B<longlines>: I<number>;
523 =item B<shortlines>: I<number>;
525 The number of lines in the big and the small table. While in the big table one
526 line is dedicated for one person the small table displays six persons per line.
528 =item B<quote_cache_size>: I<number>;
530 Sets how many quotes are to be cached for each nick. At the end of the run one
531 of the quotes in the cache will be chosen at random and displayed.
533 =item B<quote_min>: I<number>;
535 =item B<quote_max>: I<number>;
537 Sets the minimum and maximum length of a quote. Too short quotes may be not
538 very typical for a person, too long quotes may clutter the layout.
540 =item B<soliloquies_count>: I<number>;
542 Sets how many lines without interruption are considered a soliloquy.
544 =item B<longterm_days>: I<number>;
546 =item B<userdetails_longterm_days>: I<number>;
548 Sets the number of days shown in the longterm-plugin (or the longter-section of
549 the userdetails-plugin).
551 =item B<ignore_words>: I<number>;
553 The Words-Plugin will ignore words with less than this characters.
559 Florian Forster E<lt>octo at verplant.orgE<gt>