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'))
94 Usage: $0 [options] <logfile> [logfile logfile ..]
97 --config Specify alternate config file
98 --output <file> Defines the file to write the HTML to.
99 --overwrite <bool> Overwrites files without prompting.
100 --channel <channel> Defines the channel's name.
101 --logtype <type> Defines the logfile's type.
102 See 'config' for a complete list.
103 --user <name> Define's the generator's name.
105 For a full list of all options please read the onis(1) manpage.
113 if (get_config ('overwrite'))
115 my $tmp = lc (get_config ('overwrite'));
116 if ($tmp eq 'true' or $tmp eq 'yes' or $tmp eq 'on')
124 print STDERR <<MESSAGE;
126 WARNING: The output file ``$output'' already exists
128 You can set the ``overwrite'' option in the config
129 file to disable this dialog.
132 print STDERR 'Are you sure you want to overwrite it? [Y|n] ';
133 my $answer = <STDIN>;
134 exit (1) if ($answer =~ m/n/i);
138 my $logtype = 'Eggdrop';
139 if (get_config ('logtype'))
141 $logtype = ucfirst (lc (get_config ('logtype')));
144 require "Onis/Parser/$logtype.pm";
145 require Onis::Parser::Persistent;
146 require Onis::Data::Persistent;
147 import Onis::Parser (qw(parse last_date));
148 import Onis::Parser::Persistent (qw(newfile));
149 import Onis::Data::Persistent ();
151 $FileInfo = Onis::Data::Persistent->new ('FileInfo', 'inode', qw(mtime));
153 if (get_config ('purge_logs'))
155 my $temp = lc (get_config ('purge_logs'));
156 if (($temp eq 'truncate') or ($temp eq 'shorten'))
160 elsif (($temp eq 'delete') or ($temp eq 'remove')
167 for (get_config ('input'))
177 ($inode, $size, $mtime) = (stat ($file))[1,7,9];
179 print STDERR $/, $/, __FILE__, " --- New File ``$file'' ---" if ($::DEBUG & 0x200);
181 if (!defined ($mtime))
183 print STDERR $/, __FILE__, ": Unable to stat file ``$file''";
188 my ($old_mtime) = $FileInfo->get ($inode);
190 print STDERR $/, __FILE__, ": ``$file'': " if ($::DEBUG & 0x200);
192 if (defined ($old_mtime))
194 if ($old_mtime == $mtime)
196 print STDERR "File did not change. Skipping." if ($::DEBUG & 0x200);
199 elsif ($old_mtime < $mtime)
201 print STDERR "File changed. Reading it again." if ($::DEBUG & 0x200);
205 print STDERR "File ``$file'' is older than expected. There might be a problem!";
210 print STDERR "File appears to be new. Reading it." if ($::DEBUG & 0x200);
212 $FileInfo->put ($inode, $mtime);
218 unless (open ($logfile, '+< ' . $file))
220 print STDERR $/, __FILE__, ": Unable to open file ``$file'': $!";
226 unless (open ($logfile, '< ' . $file))
228 print STDERR $/, __FILE__, ": Unable to open file ``$file'': $!";
235 unless (flock ($logfile, LOCK_EX))
237 print STDERR $/, __FILE__, ": Unable to get an exclusive lock for file ``$file'': $!";
244 unless (flock ($logfile, LOCK_SH))
246 print STDERR $/, __FILE__, ": Unable to get a shared lock for file ``$file'': $!";
252 newfile ($FileInfo->{$inode});
256 $status = parse ($_);
260 # 2 == unable to parse
262 # 4 == don't have date
266 print STDERR $/, __FILE__, ": Rewinding file ``$file''" if ($::DEBUG & 0x200);
267 seek ($logfile, 0, 0);
270 elsif (($status == 1) or ($status == 2)
273 $position = tell ($logfile);
281 print STDERR $/, __FILE__, ": Parser returned unknown status code: ``$status''";
285 if ($PurgeLogs and (($status == 1)
290 #and (($position + 1) >= $size)
294 print STDERR $/, __FILE__, ": Deleting empty file ``$file''" if ($::DEBUG & 0x200);
299 unless (unlink ($file))
301 print STDERR $/, __FILE__, ": Unable to delete empty file ``$file'': $!";
303 delete ($FileInfo->{$inode});
307 print STDERR $/, __FILE__, ": Won't delete ``$file''. Set it to writeable first!";
312 seek ($logfile, 0, 0);
313 if (truncate ($logfile, 0))
315 print $logfile &last_date ();
316 print STDERR $/, __FILE__, ": Truncated ``$file''" if ($::DEBUG & 0x200);
320 print STDERR $/, __FILE__, ": Couldn't truncate file ``$file'': $!";
332 require Onis::Data::Core;
334 import Onis::Data::Core qw#print_output#;
335 import Onis::Html qw#open_file close_file#;
337 if (open_file ($output))
344 # Fail and make noise! ;)
345 print STDERR <<MESSAGE;
347 ERROR: Unable to open output file
349 The output file ``$output'' could not be opened. Please make sure to set
350 the permissions right and try again.
360 print $/ if ($::DEBUG);
369 =item B<config>: I<file>;
371 Load the config from this file. B<(command line only)>
373 =item B<users_config>: I<file>;
375 Sets the file from which to read the user configuration.
377 =item B<language_file>: I<file>;
379 Sets the language file/translation to use.
381 =item B<plugin>: I<string>;
383 Sets the plugins to load. The plugin B<Core> will always be loaded.
385 =item B<input>: I<file>;
387 Read and parse this file(s). B<(config file only)>
389 =item B<logtype>: I<string>;
391 Sets the parser to use for parsing the input file.
393 =item B<output>: I<file>;
395 Write the generated output to this file.
397 =item B<overwrite>: I<bool>;
399 Sets wether or not to overwrite the output-file if it exists.
401 =item B<purge_logs>: "I<false>" | "I<truncate>" | "I<delete>";
403 Sets wether logs should be truncated or even removes after they have been
406 =item B<user>: I<string>;
408 Sets the user that created the page. Defaults to the environment variable
409 B<USER> or "onis", if it is not set.
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 to use. This is included in the HTML-file as-is, so you
433 have to take care of absolute/relative paths yourself..
435 =item B<color_codes>: I<bool>;
437 Wether or not to print the color codes (introduced by mIRC, used by idiots and
438 ignored by the rest) in the generated HTML-file. Of course this defaults to not
441 =item B<display_images>: I<bool>;
443 Sets if user-images should be displayed.
445 =item B<default_image>: I<file>;
447 Sets the default image to use if no user-defined image is available.
449 =item B<display_lines>: "I<none>" | "I<number>" | "I<bar>" | "I<both>";
451 =item B<display_words>: "I<none>" | "I<number>" | "I<bar>" | "I<both>";
453 =item B<display_chars>: "I<none>" | "I<number>" | "I<bar>" | "I<both>";
455 Sets if and how lines, words and/or characters should be displayed.
457 =item B<sort_by>: "I<lines>" | "I<words>" | "I<chars>";
459 Sets wether to sort by lines, words or characters written.
461 =item B<display_times>: I<bool>;
463 Wether or not to display a fixed width bar that shows when a user is most
466 =item B<bar_height>: I<number>;
468 =item B<bar_width>: I<number>;
470 Sets the width of horizontal bars and the height of vertical bars.
472 =item B<horizontal_images>: I<file>, I<file>, I<file>, I<file>;
474 =item B<vertical_images>: I<file>, I<file>, I<file>, I<file>;
476 Sets the images to use for horizontal and vertical bars. This should be used in
479 =item B<encoding>: I<string>;
481 Sets the encoding to include in the HTML-file. If you don't know what this is,
484 =item B<public_page>: I<bool>;
486 Wether or not this is a public page. Public pages may be linked on the onis
487 homepage at some point in the fututre..
491 =head2 Storage / Persistency
495 =item B<storage_module>: I<string>;
497 Sets the storage-module to use.
499 =item B<storage_dir>: I<directory>;
501 Sets the directory to store persistency information under.
503 =item B<storage_file>: I<file>;
505 Sets the file to write persistency data to, if applicable by the
514 =item B<min_word_length>: I<number>;
516 Substring containing only word-characters needs to be this long to be
519 =item B<plugin_max>: I<number>;
521 Sets the number of "most referenced nicks", "most used words" and the like to
522 be displayed. This option will be removed in the future.
524 =item B<longlines>: I<number>;
526 =item B<shortlines>: I<number>;
528 The number of lines in the big and the small table. While in the big table one
529 line is dedicated for one person the small table displays six persons per line.
531 =item B<quote_cache_size>: I<number>;
533 Sets how many quotes are to be cached for each nick. At the end of the run one
534 of the quotes in the cache will be chosen at random and displayed.
536 =item B<quote_min>: I<number>;
538 =item B<quote_max>: I<number>;
540 Sets the minimum and maximum length of a quote. Too short quotes may be not
541 very typical for a person, too long quotes may clutter the layout.
543 =item B<soliloquies_count>: I<number>;
545 Sets how many lines without interruption are considered a soliloquy.
547 =item B<longterm_days>: I<number>;
549 =item B<userdetails_longterm_days>: I<number>;
551 Sets the number of days shown in the longterm-plugin (or the longter-section of
552 the userdetails-plugin).
554 =item B<ignore_words>: I<number>;
556 The Words-Plugin will ignore words with less than this characters.
562 Florian Forster E<lt>octo at verplant.orgE<gt>