#!/usr/pkg/bin/perl -w
use Term::ANSIColor;
use POSIX qw(strftime);
use Getopt::Long;
Getopt::Long::Configure("no_ignore_case");

$main_version = "0.3.4";
$scriptname = "colorize";

# Copyright (C) 2000-2003, KARASZI 'raszi' Istvan
#                          <colorize@spam.raszi.hu>
#                          http://colorize.raszi.hu/
#                          http://freshmeat.net/colorize.pl/
#
# Released under GPL version 2 or higher,
# http://www.gnu.org/copyleft/gpl.html
#
# Thanks: #linux.hu@ircnet, Andras, fu, Szilva (the Perl book ;)
#         HoFi, mhp for many ideas. [drewie] for packing it into
#         Debian GNU/Linux.

# Words, that we like or hate
@good_words = ("activ", "start", "ready", "online", "load", "ok", "register", "detected", "configured", "enable", "listen", "open", "complete", "attempt", "done", "check");
@bad_words = ("warn", "restart", "exit", "stop", "end", "shutting", "down", "close", "unreach", "can't", "cannot", "skip", "deny", "disable", "ignored", "miss", "oops", "su", "not", "backdoor", "blocking", "ignoring", "unable", "readonly", "offline", "bad");
@error_words = ("error", "crit", "invalid", "fail", "false");
@system_words = ("ext2-fs", "reiserfs", "vfs", "iso", "isofs", "cslip", "ppp", "bsd", "linux", "ip", "tcp/ip", "mtrr", "pci", "isa", "scsi", "ide", "atapi", "bios", "cpu", "fpu");
# build regexps on the above words
my $tmp = "^(?:" . join("|", @good_words) . ")";
my $good_words_match = qr/$tmp/;
$tmp = "^(?:" . join("|", @bad_words) . ")";
my $bad_words_match = qr/$tmp/;
$tmp = "^(?:" . join("|", @error_words) . ")";
my $error_words_match = qr/$tmp/;
$tmp = "^(?:" . join("|", @system_words) . ")";
my $system_words_match = qr/$tmp/;

# build caches for get{serv|proto|pw}ent results
my %_protocols = ();
while (my @ent = getprotoent) {
	foreach (map { lc } @ent) {
		# ignore numbers
		next if /^(?:\d+)?$/;
		$_protocols{$_} = 1;
	}
}
my %_services = ();
while (my @ent = getservent) {
	foreach (map { lc } @ent) {
		# ignore numbers or protocols
		next if /^(?:\d+)?$/ or exists $_protocols{$_};
		foreach (split / /) {
			$_services{$_} = 1;
		}
	}
}
my %_users = ();
while (my $ent = getpwent) {
	$_users{lc($ent)} = 1;
}

# Item names
@items = ("default", "unknown", "date", "host", "mac", "pid", "pid-sqbr", "get", "post", "head", "put", "connect", "httpcodes", "ftpcodes", "gettime", "getsize", "debug", "error", "warning", "bad", "good", "repeat", "process", "dir", "prot", "service", "email", "size", "version", "address", "uri", "miss", "parent", "direct", "hit", "deny", "ident", "refresh", "swapfail", "ctype", "clength", "create", "swapin", "swapout", "release", "swapnum", "hdate", "lmdate", "expired", "incoming", "outgoing", "user", "proxyfunction", "numbers", "system", "subject");

# Default output
$default_output = "STDOUT";

# Default color
$default_color = "white";

# Config file places (order is important, we will override the previous values of config)
@config_files = ("/usr/pkg/etc/colorizerc");
if (defined($ENV{HOME})) {
	push(@config_files, "$ENV{HOME}/.colorizerc");
}

# Set all item to a default value
sub setdefaults {
	my($item);

	foreach $item(@items) {
		$color{$item} = $default_color;
	}
}

# Read configuration from a file
sub readconfig {
	my($file, $item, $value, $i, $unknown);

	$file = shift;
	if (-e $file) {
		if (!open(CONF, "< $file")) {
			print(STDERR "Can't open config file '$file': $!!"."\n");
			return(1);
		} else {
			while(<CONF>) {
				if (/^([^#]\S+)\s+([^#]+)/) {
					$item = $1;
					$value = $2;

					$unknown = 1;

					# cut spaces from end
					$value =~ s/\s+$//;

					if ($value =~ /^'([^']+)'$/) {
						$value = $1;
						if (defined($color{$value})) {
							$color{$item} = $color{$value};
							$unknown = 0;
						} else {
							$unknown = 2;
						}
					} else {
						foreach $i(@items) {
							if ($i eq $item) {
								$unknown = 0;
								$color{$item} = $value;
							}
						}
					}
					print(STDERR "Undefined value in '$file': $item = $value."."\n") if ($unknown == 2);
					print(STDERR "Unknown item in '$file': $item = $value."."\n") if ($unknown == 1);
				}
			}
			close(CONF);
			return(0);
		}
	} else { return(2); }
}

# Print html's head with or without 'Cascading style sheets'
sub printhtmlheader {
	my($ccolor, $pre, $col, $back);

	&printout('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">'."\n");
	&printout("<html><head>"."\n");
	&printout("<title>Generated by $scriptname $main_version</title>"."\n");
 	&printout('<style type="text/css">'."\n") if (!$nocss);

	foreach $ccolor(keys %color) {
		&printout(".$ccolor { ") if (!$nocss);

		$color{$ccolor} =~ /^(((bold)|(underline)|(underscore)|(blink)|(reverse)|(concealed))\s+)?(\w+)(\s+on_(\w+))?$/;
		$pre = $2;
		$col = $9;
		$back = $11;

		# some rewrite here, 'cause ANSIColor's colors are not equal to colors of css
		if ($col) {
			$col =~ s/cyan/teal/;
			$col =~ s/magenta/purple/;
		}
		if ($back) {
			$back =~ s/cyan/teal/;
			$back =~ s/magenta/purple/;
		}

		if ($nocss) {
			if ($pre) {
				$color_attrs{$ccolor}{"bold"} = (($pre =~ /bold/) ? 1:0);
				$color_attrs{$ccolor}{"underline"} = (($pre =~ /underline/ || $pre =~ /underscore/) ? 1:0);
				$color_attrs{$ccolor}{"blink"} = (($pre =~ /blink/) ? 1:0);
				if ($pre =~ /reverse/) {
					my $x = $col;
					$col = $back;
					$back = $x;
				}
			}

			$color_attrs{$ccolor}{"bgcolor"} = $back if ($back);
			$color{$ccolor} = $col;
		} else {
			&printout(".$ccolor { ");
			if ($pre) {
				&printout("font-weight: bold;") if ($pre =~ /bold/);
				&printout("text-decoration: underline;") if($pre =~ /underline/ || $pre =~ /underscore/);
				&printout("text-decoration: blink;") if ($pre =~ /blink/);
				if ($pre =~ /reverse/) {
					my $x = $col;
					$col = $back;
					$back = $x;
				}
			}

			&printout("background-color: $back;") if ($back);
			&printout("color: $col;") if ($col);

			&printout("}"."\n");
		}
	}

	if (!$nocss) {
		&printout("body { background-color: ".$bgcolor."; }"."\n");
		&printout('</style>'."\n");
	}

	&printout("</head>"."\n");

	if ($nocss) {
		&printout('<body bgcolor="'.$bgcolor.'">'."\n");
	} else {
		&printout("<body>"."\n");
	}
}

sub endfont {
	&printout("</font>");
	&printout("</blink>") if ($blink);
	&printout("</ul>") if ($underline);
	&printout("</b>") if ($bold);
	$font = 0;
	$bold = 0;
	$blink = 0;
	$underline = 0;
}

sub printenter {
	if (!$html) {
		&printout("\n");
	} else {
		&printout("<br>"."\n");
	}
}

sub printcolor {
	my($ncolor, $getcolor, %attr);

	$getcolor = shift(@_);

	# Just a debug
	$ncolor = $color{$getcolor};
	print(STDERR "BUG, unknown color: $getcolor!"."\n") if (!defined($ncolor) or !$ncolor);
	
	if (!$html) {
		print(FILE color $ncolor);
	} else {
		%attr = %{$color_attrs{$getcolor}} if (defined ($color_attrs{$getcolor}) && $nocss);
		&endfont if ($font);
		if ($nocss) {
			if ($attr{"bold"}) {
				&printout('<b>');
				$bold = 1;
			}
			if ($attr{"underline"}) {
				&printout('<ul>');
				$underline = 1;
			}
			if ($attr{"blink"}) {
				&printout('<blink>');
				$blink = 1;
			}
			&printout('<font color="'.$ncolor.'">');
		}
		else {
			&printout('<font class="'.$getcolor.'">');
		}	

		$font = 1;
	}
}

sub fileopen {
	# Try to open output

	if (($file eq "STDOUT") or ($file eq "STDERR")) {
		open(FILE, ">&".$file) or &error("Can't open output for write: ".$file.", $!!"."\n");
	} else {
		open(FILE, ">> $file") or &error("Can't open output for write: ".$file.", $!!"."\n");
	}

	select(FILE);
	$| = 1;
}

sub isexists {
	# Check the file is exists or not
	# FIXME: if the file name is STDOUT or STDERR isexists return with 0
	if (($file ne "STDOUT") and ($file ne "STDERR") and -e $file) { return(1); } else { return(0); }
}

sub fileclose {
	close(FILE);
}

sub printout {
	print FILE $_[0];
}

sub error {
	my $line = shift;

	print(STDERR $line);
	exit;
}

sub quit {
	if (!$html) {
		&clearcol;
	} else {
		&endfont if ($font);

# Removed, 'cause append to an html is bogus, when we close the body and html tag
#		&printout("</body></html>");

	}
	&fileclose;
	exit;
}

sub clearcol {
	print(FILE color 'reset') if (!$html);
}

sub resetcol {
	if (!$html) {
		print(FILE color 'reset'); # Just reset the color
		&printcolor("default"); # Set to default color
	} else {
		&printcolor("default");
	}
}
sub space {
	my $spaces = shift;

	&resetcol(); # Reset the color, and write a space
	if (defined($spaces)) {
		&printout($spaces);
	} else {
		&printout(" ");
	}
}

sub printdate {
	my $line = shift;

	&printcolor("date");
	&printout($line);
	&space();
}

sub http_action {
	$_ = shift(@_);

	if    (/GET/)      { &printcolor("get"); }
	elsif (/POST/)     { &printcolor("post"); }
	elsif (/HEAD/)     { &printcolor("head"); }
	elsif (/PUT/)      { &printcolor("put"); }
	elsif (/CONNECT/)  { &printcolor("connect"); }
	else               { &printcolor("unknown"); }
}

sub proxy_hierarchy {
	$_ = shift(@_);

	if    (/^NO/)    { &printcolor("warning"); }
	elsif (/DIRECT/) { &printcolor("direct"); }
	elsif (/PARENT/) { &printcolor("parent"); }
	elsif (/MISS/)   { &printcolor("miss"); }
	else             { &printcolor("unknown"); }
}

sub oops_message {
	$_ = shift(@_);

	if (/^([^(]+)(\([^)]*\):)(.*)$/) {
		&printcolor("proxyfunction");
		&printout($1);
		&message($2);
		&message($3);
	} else {
		&message($_);
	}
}

sub message {
	my(@line, $word, $post, $pre, $original_word, $j, $color);

	$_ = shift(@_);
	if (/^((last message repeated \d+ times)|(-- MARK --))$/) {
		&printcolor("repeat");
		&printout($_);
	}
	else {
		@line = split (/ /);
		for($j = 0;$j <= $#line; $j++) {
			$word = $line[$j];

			# Cut start and end characters (like '," etc)
		 	if ($word =~ /^([`'".,!?:;(\[{<]+)([^`'".,!?:;(\[{<]+)$/) {
				$pre = $1;
				$word = $2;
			}
			if ($word =~ /^([^`'".,!?:;)\]}>]+)([`'".,!?:;)\]}>]+)$/) {
				$word = $1;
				$post = $2;
			}

			if (defined($pre)) {
				&resetcol();
				&printout($pre);
				undef $pre;
			}

			$original_word = $word;
			$word = lc($word);

			$color = "";

			if ($word =~ /^(((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|(([a-z0-9-_]+\.)+[a-z]{2,3})|(localhost)|(\w*::\w+)+)(:\d{1,5})?)$/) { $color = "host"; }
			elsif ($word =~ /^([0-9a-f]{2}:){5}[0-9a-f]{2}$/) { $color = "mac"; }
			elsif ($word =~ /^\/\S+$/) { $color = "dir"; }
			elsif ($word =~ /^[a-z0-9-_]+@[a-z0-9-_.]+(\.[a-z]{2,3})?$/) { $color = "email"; }
			elsif ($word =~ /^\w{2,}:\/\/(\S+\/?)+$/) { $color = "uri"; }
			elsif ($word =~ /^\d+(\.\d+)?[kmg]b?(ytes?)?$/) { $color = "size"; }
			elsif ($word =~ /^v?\d+\.([0-9a-z]+\.)*[0-9a-z]+$/) { $color = "version"; }
			elsif ($word =~ /^0x[0-9a-f]+$/) { $color = "address"; }
			elsif (exists $_services{$word}) { $color = "service"; }
			elsif (exists $_protocols{$word}) { $color = "prot"; }
			elsif (exists $_users{$word}) { $color = "user"; }
			elsif ($word =~ /^-?\d+$/) { $color = "numbers"; }
			elsif ($word =~ $good_words_match) { $color = "good"; }
			elsif ($word =~ $bad_words_match) { $color = "bad"; }
			elsif ($word =~ $error_words_match) { $color = "error"; }
			elsif ($word =~ $system_words_match) { $color = "system"; }

			if ($color) {
				&printcolor($color);
			} else {
				&printcolor("unknown");
			}

			&printout($original_word);

			if (defined($post)) {
				&resetcol();
				&printout($post);
				undef $post;
			}
			&space() if ($j !=  $#line);
		}
	}
}

## Main program ##

# Constants
$html = "";
$nocss = "";
$bgcolor = "#000000";
$file = $default_output;
$SIG{'TERM'} = "quit";
$SIG{'KILL'} = "quit";


GetOptions('file|f=s' => \$file, 'html|h' => \$html, 'bgcolor|b=s' => \$bgcolor, 'nocss' => \$nocss, 'help|?' => \$help, 'version|V' => \$version, 'rcfile|F=s' => \$rcfile, 'convert-date|C' => \$convert_date, 'remove-facility|r' => \$remove_facility);
	if ($version) {
		print("Version: ".$main_version."\n");
		exit;
	} elsif ($help) {
		print("$scriptname version ".$main_version."\n");
		print("Usage: $scriptname [OPTION]"."\n");
 		print("  -f, --file [file]      print output to a [file]"."\n");
 		print("  -h, --html             generate html output"."\n");
		print("      --nocss            don't use css"."\n");
		print("  -b  --bgcolor [color]  background color for html output"."\n");
 		print("  -F, --rcfile [file]    read config file from [file]"."\n");
 		print("  -C, --convert-date     convert unix timestamp to readable format"."\n");
 		print("  -r, --remove-facility  remove syslog-ng's facility from start of the lines"."\n");
		print("\n");
 		print("  -?, --help             display this help and exit"."\n");
 		print("  -V, --version          output version information and exit"."\n");
		exit;
	} elsif ($rcfile) {
		@config_files = ($rcfile);
		undef($rcfile);
	}

$fileexists = &isexists($file);

# Open output
&fileopen;

# Set default colors
&setdefaults;

# Read all of config files
my $noconfig = 1;
foreach my $config (@config_files) {
	$noconfig = 0 if (!&readconfig ($config));
}
undef(@config_files);

print(STDERR "Can't read any configuration!"."\n") if ($noconfig);
undef($noconfig);

# Print out html header if file is not exists and html switch is on
&printhtmlheader() if (!$fileexists && $html);
undef($fileexists);

# main loop
while(<STDIN>) {
	if ($remove_facility) {
		# syslog-ng paste the facility level before log messages, we hate this, cut it off!
		s/^<[0-9]+>//;
	}

	if (/^(From)\s(\S+)(\s+)(.*)$/) {
		# procmail log (from field)
		$header = $1;
		$mail = $2;
		$space = $3;
		$date = $4;

		&printcolor("default");
		&printout($header);
		
		&space();
		
		&printcolor("email");
		&printout($mail);
		
		&space($space);
		
		&printdate($date);
	}
	elsif (/^\s(Subject:)\s(.*)$/) {
		# procmail log (subject field)
		$header = $1;
		$subject = $2;

		&space();
		
		&printcolor("default");
		&printout($header);

		&space();

		&printcolor("subject");
		&printout($subject);
	}
	elsif (/^(\s+)(Folder:)\s(\S+)(\s+)(\d+)$/) {
		# procmail log (folder field)
		$space1 = $1;
		$header = $2;
		$folder = $3;
		$space2 = $4;
		$size = $5;

		&space($space1);

		&printcolor("default");
		&printout($header);

		&space();

		&printcolor("dir");
		&printout($folder);

		&space($space2);

		&printcolor("size");
		&printout($size);
	}
	elsif (/^(\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2})\s(.*)$/) {
	# Exim main log
		my($date, $msg, $action, $uniqn, $color);

		$date = $1;
		$msg = $2;

		if ($msg =~ /^(\S{16})\s(<=)\s(\S+.*)$/) {
			$color = 'incoming';
			$uniqn = $1;
			$action = $2;
			$msg = $3;
		}
		elsif ($msg =~ /^(\S{16})\s(=>)\s(\S+.*)$/) {
			$color = 'outgoing';
			$uniqn = $1;
			$action = $2;
			$msg = $3;
		}
		elsif ($msg =~ /^(\S{16})\s(==)\s(\S+.*)$/) {
			$color = 'error';
			$uniqn = $1;
			$action = $2;
			$msg = $3;
		}
		elsif ($msg =~ /^(\S{16})\s(.*)$/) {
			$uniqn = $1;
			$msg = $2;
		}

		# If we know last message id then we know what is the type of last message
		# (it's send or received or something else)
		if (defined($exim_last_uniqn) && defined($uniqn)) {
			if ($exim_last_uniqn eq $uniqn) {
				$color = $exim_last_color;
			}
		}

		$color = "unknown" if (! defined($color));

		&printdate($date);

		if (defined($uniqn)) {
			&printcolor($color);
			&printout($uniqn);

			$exim_last_uniqn = $uniqn;
			$exim_last_color = $color;

			&space();
		}

		if (defined($action)) {
			&printout($action);
			&space();
		}

		&message($msg);
	}
	elsif (/^(\d+\.\d{3})(\s+)(\d+)\s(\S+)\s(\w+)\/(\d{3})\s(\d+)\s(\w+)\s(\S+)\s(\S+)\s(\w+)\/(\S+)\s(\S*)$/) {
		# Proxy access.log
		my($date, $space, $elaps, $host, $action, $httpc, $gsize, $method, $uri, $ident, $hierar, $fhost, $content);

		$date = $1;		# timestamp
		$space = $2;		# space between time and elapsed time
		$elaps = $3;		# elapsed time
		$host = $4;		# client
		$action = $5;		# action/code
		$httpc = $6;		# http code
		$gsize = $7;		# get size
		$method = $8;		# method
		$uri = $9;		# requested uri
		$ident = $10;		# ident (disabled default, it's logged as "-")
		$hierar = $11;		# hierarchy
		$fhost = $12;		# from host
		$content = $13;		# Content-type

		if ($convert_date) {
			my $mydate = strftime("%b %e %T", gmtime($date));
			&printdate($mydate);
		} else {
			&printdate($date);
		}

		&printcolor("gettime");
		&printout($elaps);
		&space();

		&printcolor("host");
		&printout($host);
		&space();

		if ($action =~ /^ERR/)        { &printcolor("error"); }
		elsif ($action =~ /MISS/)     { &printcolor("miss"); }
		elsif ($action =~ /HIT/)      { &printcolor("hit"); }
		elsif ($action =~ /DENIED/)   { &printcolor("deny"); }
		elsif ($action =~ /REFRESH/)  { &printcolor("refresh"); }
		elsif ($action =~ /SWAPFAIL/) { &printcolor("swapfail"); }
		elsif ($action =~ /NONE/)     { &printcolor("debug"); }
		else                          { &printcolor("unknown"); }
		&printout($action);
		&resetcol();
		&printout("/");
		&printcolor("httpcodes");
		&printout($httpc);
		&space();

		&printcolor("getsize");
		&printout($gsize);
		&space();

		&http_action($method);
		&printout($method);
		&space();

		&printcolor("uri");
		&printout($uri);
		&space();

		&printcolor("ident");
		&printout($ident);
		&space();

		&proxy_hierarchy($hierar);
		&printout($hierar);
		&resetcol();
		&printout("/");
		&printcolor("host");
		&printout($fhost);
		&space();

		&printcolor("ctype");
		&printout($content);
	}
	elsif (/^(\d+\.\d{3})\s(\w+)\s(\w+)(\s+)\s(\d{3})\s(\d{9}|-1)(\s+)(\d{9}|-1)(\s+)(\d{9}|-1)\s(\S+)\s(-1|\d+)\/(\d+)\s(\w+)\s(\S+)$/) {
		# Proxy store.log
		my($date, $tag, $swapnum, $space1, $status, $hdate, $space2, $lmdate, $space3, $expire, $content, $length, $gsize, $method, $uri);

		$date = $1;		# date of the event
		$tag = $2;		# the event :)
		$swapnum = $3;		# swap number
		$space1 = $4;		# space between swap number and http reply code
		$status = $5;		# http reply code
		$hdate = $6;		# Time from the HTTP Date reply header
		$space2 = $7;		# space between hdate and lmdate
		$lmdate = $8;		# last modification date
		$space3 = $9;		# space between lmdate and expire
		$expire = $10;		# expire date
		$content = $11;		# Content-type
		$length = $12;		# Content-Length
		$gsize = $13;		# actually readed bytes
		$method = $14;		# the request method (GET, POST, etc).
		$uri = $15;		# requested uri

		if ($convert_date) {
			my $mydate = strftime("%b %e %T", gmtime($date));
			&printdate($mydate);
		} else {
			&printdate($date);
		}

		if ($tag =~ /CREATE/)     { &printcolor("create"); }
		elsif ($tag =~ /SWAPIN/)  { &printcolor("swapin"); }
		elsif ($tag =~ /SWAPOUT/) { &printcolor("swapout"); }
		elsif ($tag =~ /RELEASE/) { &printcolor("release"); }
		else { &printcolor("unknown"); }
		&printout($tag);
		&space();

		&printcolor("swapnum");
		&printout($swapnum);
		&resetcol();
		&printout($space1);

		&printcolor("httpcodes");
		&printout($status);
		&space();

		&printcolor("hdate");
		&printout($hdate);
		&resetcol();
		&printout($space2);

		&printcolor("lmdate");
		&printout($lmdate);
		&resetcol();
		&printout($space3);

		&printcolor("expired");
		&printout($expire);
		&space();

		&printcolor("ctype");
		&printout($content);
		&space();

		&printcolor("clength");
		&printout($length);
		&resetcol();
		&printout("/");
		&printcolor("getsize");
		&printout($gsize);
		&space();

		&http_action($method);
		&printout($method);
		&space();

		&printcolor("uri"); # I dunno', maybe it must be same color with method (please FIXME with ideas)
		&printout($uri);
	}
	elsif (/^(\d{4}\/\d{2}\/\d{2}\s(\d{2}:){2}\d{2}\|)\s(.*)$/) {
		# Proxy cache.log
		my($date, $msg);

		$date = $1;
		$msg = $3;

		if ($convert_date) {
			my $mydate = strftime("%b %e %T", gmtime($date));
			&printdate($mydate);
		} else {
			&printdate($date);
		}

		&printcolor("debug"); # I think all cache.log messages are debug level message
		&printout($msg);
	}
	elsif (/^(\w{3}\s\w{3}\s+\d+\s\d{2}:\d{2}:\d{2}\s\d{4})(\s+)(\[[^\]]+\])(.*)$/) {
		# oops.log
		$date = $1;
		$space = $2;
		$status = $3;
		$msg = $4;

		&printdate($date);
		&space($space);

		&message($status);
		&oops_message($msg);
	}
	elsif (/^(\S*)\s-\s(\S+)\s(\[\d{1,2}\/\S*\/\d{4}:\d{2}:\d{2}:\d{2}.{0,6}\])\s("([A-Z]{3,})\s[^"]+")\s(\d{3})\s(\d+|-)\s(.*)$/) {
		# httpd access.log format found
		my($host, $user, $date, $msg, $method, $full_action, $http_code, $gsize);

		$host = $1;
		$user = $2;
		$date = $3;
		$full_action = $4;
		$method = $5;
		$http_code = $6;
		$gsize = $7;
		$other = $8;

		&printcolor("host");
		&printout($host);
		&space();

		&printout("-");
		&space();

		&printcolor("user");
		&printout($user);
		&space();

		&printdate($date);


		&http_action($method);
		&printout($full_action);
		&space();

		&printcolor("httpcodes");
		&printout($http_code);
		&space();

		&printcolor("getsize");
		&printout($gsize);
		&space();

		&printcolor("default");
		&printout($other);
	}
	elsif (/^(\[\w{3}\s\w{3}\s{1,2}\d{1,2}\s\d{2}:\d{2}:\d{2}\s\d{4}\])\s(\[\w*\])\s(.*)$/) {
		# httpd error.log format
		my($date, $level, $msg, $color);

		$date = $1;
		$level = $2;
		$msg = $3;

		&printdate($date);

		if ($level =~ /(debug|info|notice)/)         { $color = "debug"; }
		elsif ($level =~ /warn/)                     { $color = "warning"; }
		elsif ($level =~ /(error|crit|alert|emerg)/) { $color = "error"; }
		else { $color = "unknown"; }

		&printcolor($color);
		&printout($level);
		&space();

		&printcolor($color);
		&printout($msg);
	}
	elsif (/^(\S{3}\s\S{3}\s{1,2}\S{1,2}\s\d{2}:\d{2}:\d{2}\s\d{4})\s(\d+)\s(\S+)\s(\d+)\s(\S+)\s(.*)/) {
		# xferlog format
		my($date, $time, $host, $gsiz, $gdir, $ftpc);

		$date = $1;
		$time = $2;
		$host = $3;
		$gsiz = $4;
		$gdir = $5;
		$ftpc = $6;

		&printdate($date);

		&printcolor("gettime");
		&printout($time);
		&space();

		&printcolor("host");
		&printout($host);
		&space();

		&printcolor("getsize");
		&printout($gsiz);
		&space();

		&printcolor("dir");
		&printout($gdir);
		&space();

		&printcolor("ftpcodes");
		&printout($ftpc);
	}
	elsif (/^(\S*\s{1,2}\d{1,2}\s\d\d:\d\d:\d\d)\s(\S+)\s((\S+:?)\s(.*))$/) {
		# It's a system log
		my($date, $host, $send, $process, $msg, $pid);

		$date = $1;
		$host = $2;
		$send = $3;

		# Repeat color
		if ($send !~ /((last message repeated \d+ times)|(-- MARK --))/) {
			$process = $4;
			$msg = $5;
		} else { $msg = $send; }

		&printdate($date);
		&printcolor("host");
		&printout($host);
		&space();

		if (defined($process)) {
			if ($process =~ /\[(\d+)\]/) {
				$pid = $1;
				$process = substr($process, 0, index($process, "[$pid]"));
			}
		&printcolor("process");
		&printout($process);
		if (defined($pid)) {
			&printcolor("pid-sqbr");
			&printout("[");
			&printcolor("pid");
			&printout($pid);
			&printcolor("pid-sqbr");
			&printout("]");
			undef($pid);
			&resetcol();
			&printcolor("process");
			&printout(":");
		}

		undef($process);

	&space();
	}

	&message($msg);
	}
	else {
		# Print the unknown messages too
		chomp($_);
		&printcolor("unknown");
		&printout($_);
	}

	&clearcol;
	&printenter;
}

&quit; # just reset color and quit
