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

$main_version = "0.3.5";
$scriptname = "colorize";

# Copyright (C) 2000-2017, KARASZI Istvan <github@spam.raszi.hu>
#
# 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 = ("/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

# vim: ts=4:sw=4
