diff options
author | Tom Kistner <tom@duncanthrax.net> | 2008-12-04 11:24:17 +0100 |
---|---|---|
committer | Andreas Unterkircher <unki@netshadow.at> | 2008-12-12 23:18:56 +0100 |
commit | f8a8bc98f9a77d24e0fce2abd73c9512bcf26f2d (patch) | |
tree | 84af841fdb450b60d54e590ec02b9ddb0e671cba | |
parent | a35e1469841bfbc7e58b66dcefb108993bc4b494 (diff) | |
download | exilog-f8a8bc98f9a77d24e0fce2abd73c9512bcf26f2d.zip exilog-f8a8bc98f9a77d24e0fce2abd73c9512bcf26f2d.tar.gz exilog-f8a8bc98f9a77d24e0fce2abd73c9512bcf26f2d.tar.bz2 |
Forward unreleased changes
- IPv6 address parsing
- Some queue management
- Better SQL quoting
- More misc stuff
Signed-off-by: Tom Kistner <tom@duncanthrax.net>
-rwxr-xr-x | agent/exilog_agent.pl | 4 | ||||
-rwxr-xr-x | cgi/exilog_cgi.pl | 37 | ||||
-rw-r--r-- | cgi/exilog_cgi_html.pm | 223 | ||||
-rw-r--r-- | cgi/exilog_cgi_messages.pm | 69 | ||||
-rw-r--r-- | cgi/exilog_cgi_param.pm | 10 | ||||
-rw-r--r-- | cgi/exilog_cgi_queues.pm | 323 | ||||
-rw-r--r-- | doc/mysql-db-script.sql | 10 | ||||
-rw-r--r-- | htdocs/exilog_jscript.js | 111 | ||||
-rw-r--r-- | htdocs/exilog_stylesheet.css | 31 | ||||
-rw-r--r-- | lib/exilog_parse.pm | 6 | ||||
-rw-r--r-- | lib/exilog_sql.pm | 77 | ||||
-rw-r--r-- | lib/exilog_util.pm | 40 |
12 files changed, 695 insertions, 246 deletions
diff --git a/agent/exilog_agent.pl b/agent/exilog_agent.pl index e09dce9..bd256ab 100755 --- a/agent/exilog_agent.pl +++ b/agent/exilog_agent.pl @@ -47,6 +47,7 @@ unless ($foreground) { setsid(); # dup STDOUT/ERR + open(STDIN, "< /dev/null"); open(STDOUT, ">&LOG"); open(STDERR, ">&LOG"); } @@ -139,7 +140,8 @@ sub _queue_actions { 'action' => 'delete' } ); foreach (@{$deliver}) { - system("$exim -qff $_->{message_id} &"); + system("$exim -Mt $_->{message_id}"); + system("$exim -Mc $_->{message_id} &"); sql_queue_clear_action($config->{agent}->{server},$_->{message_id}); } diff --git a/cgi/exilog_cgi.pl b/cgi/exilog_cgi.pl index f8b6867..6c3afb8 100755 --- a/cgi/exilog_cgi.pl +++ b/cgi/exilog_cgi.pl @@ -23,10 +23,23 @@ use exilog_sql; # Put user name into global variable my $user = $ENV{'REMOTE_USER'} || 'anonymous'; +# XMLHTTP requests are handled here. +# We only return short result statements +# in text/plain format for those. +if ($param->{'xmlhttp'} == 1) { + print $q->header(-expires=>'Thursday, 01-Jan-1970 00:00:01 GMT', + -Expires=>'now', + -Content-Type=>'text/plain', + -Cache-Control=>'no-cache', + -Cache-Control=>'no-store', + -Pragma=>'no-cache'); + print _do_xmlhttp_actions(); + exit(0); +} + _print_cgi_headers(); _print_html_header(); _print_html_tabs(); -_do_global_actions(); print '<div class="display" align="center">'; if ($param->{tab} eq 'queues') { @@ -48,23 +61,19 @@ _print_html_footer(); # -- Private functions --------------------------------------------------------- -sub _do_global_actions { - +sub _do_xmlhttp_actions { # queue actions my $valid_actions = [ 'deliver', 'cancel', 'delete' ]; my $restricted_actions = [ 'cancel', 'delete' ]; - foreach my $p (keys %{ $param }) { - if ($p =~ /^ac_([A-Za-z0-9_.-]+?)_([A-Za-z0-9]{6}\-[A-Za-z0-9]{6}-[A-Za-z0-9]{2})$/) { - my $server = $1; - my $message_id = $2; - my $action = $param->{$p}; - if (ina($valid_actions,$action)) { - next if (ina($restricted_actions,$action) && ina($config->{web}->{restricted_users},$main::user)); - sql_queue_set_action($server,$message_id,$action); - } - } + my $action_text = { 'deliver' => 'Forcing', 'cancel' => 'Cancelling', 'delete' => 'Deleting' }; + + if ( ina($valid_actions,$param->{'action'}) && + !(ina($restricted_actions,$param->{'action'}) && ina($config->{web}->{restricted_users},$main::user)) ) { + sql_queue_set_action($param->{'server'},$param->{'message_id'},$param->{'action'}); + return $action_text->{$param->{'action'}}; } + return 0; }; @@ -95,7 +104,7 @@ sub _print_html_header { sub _print_html_tabs { my $tabs = { 'servers' => "Servers", 'messages' => "Messages", - #'queues' => "Queues", # Queue manager is still unfinished ... + 'queues' => "Queues", 'messages' => "Messages" }; my $html; diff --git a/cgi/exilog_cgi_html.pm b/cgi/exilog_cgi_html.pm index 9011369..bfb207c 100644 --- a/cgi/exilog_cgi_html.pm +++ b/cgi/exilog_cgi_html.pm @@ -30,7 +30,6 @@ BEGIN { &render_server &render_queue_table $q - ); %EXPORT_TAGS = (); @@ -281,16 +280,20 @@ sub _titlebar_html { ( (edv($h,'queue') && defined(@{$h->{queue}}[0])) ? { 'text' => '·' } : undef ), ( (edv($h,'queue') && - defined(@{$h->{queue}}[0])) ? { 'html' => $q->popup_menu({ - -name => 'ac_'.$h->{server}.'_'.$h->{'message_id'}, - -values => $actions, - -default => 0, - -labels => { 0 => ':: Please select action ::', - 'deliver' => 'Force delivery', - 'cancel' => 'Cancel (bounce)', - 'delete' => 'Delete' }, - -override => 1 - }).$q->submit({-name=>'Go'}) + defined(@{$h->{queue}}[0])) ? { 'html' => + + $q->div({ -id=>'ac_'.$h->{server}.'_'.$h->{'message_id'}.'_div', + -style=>"margin:0; padding:0; border:0; width: 110px; color: red;" }, + $q->popup_menu({ -values => $actions, + -default => 0, + -onChange=>"javascript:message_action('$h->{server}','$h->{message_id}',this,'ac_$h->{server}_$h->{message_id}_div');", + -labels => { 0 => ':: Select action ::', + 'deliver' => 'Force delivery', + 'cancel' => 'Cancel (bounce)', + 'delete' => 'Delete' }, + -override => 1 } ) + ) + } : undef ) ) ), (exists($h->{size}) ? @@ -802,64 +805,126 @@ sub render_queue_table { my $rows = ""; foreach my $message (@{ $messages }) { + + my $actions = [ 0, 'deliver' ]; + unless (ina($config->{web}->{restricted_users}, $main::user)) { + if ($message->{mailfrom} ne '<>') { + push @{$actions}, 'cancel'; + } + push @{$actions}, 'delete'; + } + my $row_id = $message->{server}.'_'.$message->{message_id}; my @rcpts_delivered = split / /,$message->{recipients_delivered}; my @rcpts_pending = split / /,$message->{recipients_pending}; + my $rcpts_html = ""; + foreach my $rcpt (@rcpts_pending) { + $rcpts_html .= + _item( { 'icon' => 'icons/deferred.png' }, + { 'text' => $rcpt } ); + } + foreach my $rcpt (@rcpts_delivered) { + $rcpts_html .= + _item( { 'icon' => 'icons/delivered.png' }, + { 'text' => $rcpt } ); + } + my $headers = $message->{headers}; + $headers =~ s/\&/&/g; + $headers =~ s/\</</g; + $headers =~ s/\>/>/g; + $rows .= $q->Tr( - $q->td({-class=>"queue"}, - # Actions - ), - $q->td({-class=>"queue"}, - $message->{server} - ), - $q->td({-class=>"queue"}, - edt($message,'timestamp') ? - _timespan($now - $message->{timestamp}) - : - '?' - ), - $q->td({-class=>"queue"}, - _shorten_addr($message->{mailfrom},40) - ), - $q->td({-class=>"queue", - -onMouseOver=>"javascript:document.getElementById('$row_id' + '_pending').style.visibility = 'visible';", - -onMouseOut=>"javascript:document.getElementById('$row_id' + '_pending').style.visibility = 'hidden';"}, - _shorten_addr($rcpts_pending[0],40) - ), - $q->td({-class=>"queue"}, - (defined($rcpts_pending[0]) ? - $q->div({-id=>$row_id.'_pending', -class=>"rcpts_pending_popup"},"Test<br>Test2<br>Test3") - : - ''). - _shorten_string($message->{subject},60) + $q->td( + $q->table({-class=>"queue_entry_table",-cellpadding=>2,-cellspacing=>1,-border=>0}, + $q->Tr( + $q->td({ -class=>"queue", + -width=>32, + -rowspan=>2}, + ( edt($message,'frozen') ? + png("icons/queue_frozen.png",32,32,"Frozen at ".stamp_to_date($message->{frozen})) + : + png("icons/queue_deferred.png",32,32,"") + ) + ), + $q->td({-class=>"queue"}, + _item( { 'icon' => "icons/server.png" }, + { 'text' => $message->{server} } ) + ), + $q->td({-class=>"queue", -align=>"center"}, + _item( { 'icon' => "icons/timerange.png" }, + { 'text' => (edt($message,'timestamp') ? + _timespan($now - $message->{timestamp},2) + : + '?' ) } ) + ), + $q->td({ -class=>"queue", + -width=>"300" }, + _item( { 'icon' => "icons/arrival.png" }, + { 'text' => _shorten_addr($message->{mailfrom},40) } ) + ), + $q->td({-class=>"queue", + -onMouseOver=>"javascript:document.getElementById('$row_id' + '_rcpts').style.visibility = 'visible';", + -onMouseOut=>"javascript:document.getElementById('$row_id' + '_rcpts').style.visibility = 'hidden';" }, + $q->div({-class=>"popup_container"}, + $q->div({-id=>$row_id.'_rcpts', + -class=>"popup", + -style=>"width:326px;"}, + $rcpts_html + ) + ). + _item( { 'icon' => "icons/deferred.png" }, + { 'html' => _shorten_addr($rcpts_pending[0],40). + ( ((scalar @rcpts_pending) + (scalar @rcpts_delivered) > 1) ? + ' (+'.((scalar @rcpts_pending)+(scalar @rcpts_delivered)-1).'↓)' : "" ) } ) + ) + ), + $q->Tr( + $q->td({ -class=>"queue", + -width=>120, + -nowrap=>"nowrap", + -align=>"center"}, + $message->{message_id} + ), + $q->td({ -class=>"queue", + -style=>"padding: 0px;", + -width=>110, + -align=>"center"}, + $q->div({ -id=>'ac_'.$message->{server}.'_'.$message->{'message_id'}.'_div', + -style=>"margin:0; padding:0; border:0; width: 110px; color: red;" }, + $q->popup_menu({ -values => $actions, + -style=>"width: 110px;", + -default => 0, + -onChange=>"javascript:message_action('$message->{server}','$message->{message_id}',this,'ac_$message->{server}_$message->{message_id}_div');", + -labels => { 0 => ':: Select action ::', + 'deliver' => 'Force delivery', + 'cancel' => 'Cancel (bounce)', + 'delete' => 'Delete' }, + -override => 1 }) ) + ), + $q->td({-class=>"queue", + -onMouseDown=>"javascript:document.getElementById('$row_id' + '_headers').style.visibility = 'visible';", + -style=>"font-family: Arial, Helvetica, Sans-Serif;",colspan=>2}, + $q->div({-class=>"popup_container"}, + $q->div({-id=>$row_id.'_headers', + -class=>"popup", + -onDblClick=>"javascript:document.getElementById('$row_id' + '_headers').style.visibility = 'hidden';", + -style=>"width:635px;"}, + '<pre style="font-size: 12px;">'. + $headers. + '</pre>' + ) + ). + _shorten_string($message->{subject},100) + ) + ) + ) ) ); }; $q->div({-class=>"top_spacer"}, - $q->table({-class=>"queue_table",-cellpadding=>0,-cellspacing=>1,border=>0}, - $q->Tr( - # Table header - $q->td({-class=>"queue_header",-width=>"1%"}, - " " - ), - $q->td({-class=>"queue_header",-width=>"1%"}, - "Server" - ), - $q->td({-class=>"queue_header",-width=>"1%"}, - "Age" - ), - $q->td({-class=>"queue_header",-width=>"1%"}, - "Sender" - ), - $q->td({-class=>"queue_header",-width=>"1%"}, - "Recipient(s)" - ), - $q->td({-class=>"queue_header"}, - "Subject" - ) - ), + $q->table({-class=>"queue_frame_table",-cellpadding=>0,-cellspacing=>0,border=>0}, $rows ) ); @@ -888,15 +953,15 @@ sub _item { if (exists($part->{icon})) { $html .= - $q->td({-class=>"item_icon",-style=>(exists($part->{style}) ? $part->{style} : "")}, - $q->img({ -src=>$part->{icon}, - -title=>(exists($part->{title}) ? $part->{title} : "" ), - -border=>0 }) + $q->td({ -class=>"item_icon", + -style=>(exists($part->{style}) ? $part->{style} : "")}, + png($part->{icon},16,16,(exists($part->{title}) ? $part->{title} : "" )) ); next; } elsif (exists($part->{html})) { - $html .= $q->td({-class=>"item_text"}, $part->{html}); + $html .= $q->td({ -class=>"item_text", + }, $part->{html}); } elsif (exists($part->{text})) { # HTML-quote angle brackets @@ -965,18 +1030,26 @@ sub _shorten_string { sub _timespan { my $amnt = shift; - my @steps = (1,60,60,24,7,999999999); - my @units = ('s','m','h','d','wk'); - - my $str = ""; - while ($amnt > $steps[1]) { - my $rest = $amnt % $steps[1]; - $str = $rest.$units[0]." ".$str; - $amnt = int($amnt/$steps[1]); + my $cutoff = shift || 999; + my $str = ''; + my @units = ('wk','d','h','m','s'); + my @quantums = ( (7*24*60*60*1), + ( 24*60*60*1), + ( 60*60*1), + ( 60*1), + ( 1) ); + + foreach my $quantum (@quantums) { + if (int($amnt/$quantum) > 0) { + $str .= int($amnt/$quantum).$units[0]." "; + $amnt = $amnt%$quantum; + last unless (--$cutoff); + } shift @units; - shift @steps; - }; - $str = $amnt.$units[0]." ".$str; + last unless ($amnt); + } + # Fall-through default + $str = '0s' unless ($str); return $str; }; diff --git a/cgi/exilog_cgi_messages.pm b/cgi/exilog_cgi_messages.pm index 9556771..bbcb062 100644 --- a/cgi/exilog_cgi_messages.pm +++ b/cgi/exilog_cgi_messages.pm @@ -62,7 +62,7 @@ sub _select_ident { } my $criteria = { 'timestamp' => (edt($param,'tr') ? _make_tr() : undef), 'server' => (edt($param,'sr') ? $param->{'sr'} : undef ), - 'host_ident' => $param->{'qs'} }; + 'host_ident' => dos2sql($param->{'qs'}) }; # Only messages table return sql_select( 'messages', [ 'server','message_id','timestamp' ], $criteria ); }; @@ -72,7 +72,7 @@ sub _select_msgid { return []; } # Only messages table - return sql_select( 'messages', [ 'server','message_id','timestamp' ], { 'msgid' => $param->{'qs'} } ); + return sql_select( 'messages', [ 'server','message_id','timestamp' ], { 'msgid' => dos2sql($param->{'qs'}) } ); }; sub _select_message_id { @@ -82,13 +82,14 @@ sub _select_message_id { my @results = (); my @tables = ( 'deliveries','errors','unknown','deferrals','messages','rejects','queue' ); - my $criteria = { 'message_id' => $param->{'qs'} }; + my $criteria = { 'message_id' => dos2sql($param->{'qs'}) }; foreach my $table (@tables) { push @results, @{ sql_select( $table, [ 'server','message_id','timestamp' ], $criteria ) }; }; # check bounce parent field too - push @results, @{ sql_select( 'messages', [ 'server','message_id','timestamp' ], { 'bounce_parent' => $param->{'qs'} } ) }; + push @results, @{ sql_select( 'messages', [ 'server','message_id','timestamp' ], + { 'bounce_parent' => dos2sql($param->{'qs'}) } ) }; return \@results; }; @@ -102,25 +103,25 @@ sub _select_addr { my @queries; push @queries, { 'table' => 'messages', - 'criteria' => { 'mailfrom' => $param->{'qs'} } }, + 'criteria' => { 'mailfrom' => dos2sql($param->{'qs'}) } }, { 'table' => 'rejects', - 'criteria' => { 'mailfrom' => $param->{'qs'} } } + 'criteria' => { 'mailfrom' => dos2sql($param->{'qs'}) } } if (($p eq 'sender') || ($p eq 'all')); push @queries, { 'table' => 'rejects', - 'criteria' => { 'rcpt' => $param->{'qs'} } }, + 'criteria' => { 'rcpt' => dos2sql($param->{'qs'}) } }, { 'table' => 'deliveries', - 'criteria' => { 'rcpt' => $param->{'qs'} } }, + 'criteria' => { 'rcpt' => dos2sql($param->{'qs'}) } }, { 'table' => 'deliveries', - 'criteria' => { 'rcpt_final' => $param->{'qs'} } }, + 'criteria' => { 'rcpt_final' => dos2sql($param->{'qs'}) } }, { 'table' => 'deferrals', - 'criteria' => { 'rcpt' => $param->{'qs'} } }, + 'criteria' => { 'rcpt' => dos2sql($param->{'qs'}) } }, { 'table' => 'deferrals', - 'criteria' => { 'rcpt_final' => $param->{'qs'} } }, + 'criteria' => { 'rcpt_final' => dos2sql($param->{'qs'}) } }, { 'table' => 'errors', - 'criteria' => { 'rcpt' => $param->{'qs'} } }, + 'criteria' => { 'rcpt' => dos2sql($param->{'qs'}) } }, { 'table' => 'errors', - 'criteria' => { 'rcpt_final' => $param->{'qs'} } } + 'criteria' => { 'rcpt_final' => dos2sql($param->{'qs'}) } } if (($p eq 'rcpt') || ($p eq 'all')); @@ -145,22 +146,22 @@ sub _select_host { } my @queries; - if ($param->{'qs'} =~ /^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/) { - # IPv4 address + if ($param->{'qs'} =~ /^[0-9A-Fa-f.:]+$/) { + # IPv4 or IPv6 address push @queries, { 'table' => 'messages', - 'criteria' => { 'host_addr' => $param->{'qs'} } }, + 'criteria' => { 'host_addr' => dos2sql($param->{'qs'}) } }, { 'table' => 'rejects', - 'criteria' => { 'host_addr' => $param->{'qs'} } } + 'criteria' => { 'host_addr' => dos2sql($param->{'qs'}) } } if (($p eq 'incoming') || ($p eq 'all')); push @queries, { 'table' => 'deliveries', - 'criteria' => { 'host_addr' => $param->{'qs'} } }, + 'criteria' => { 'host_addr' => dos2sql($param->{'qs'}) } }, { 'table' => 'deferrals', - 'criteria' => { 'host_addr' => $param->{'qs'} } }, + 'criteria' => { 'host_addr' => dos2sql($param->{'qs'}) } }, { 'table' => 'errors', - 'criteria' => { 'host_addr' => $param->{'qs'} } }, + 'criteria' => { 'host_addr' => dos2sql($param->{'qs'}) } }, { 'table' => 'unknown', - 'criteria' => { 'line' => '%'.$param->{'qs'}.'%' } } + 'criteria' => { 'line' => '%'.dos2sql($param->{'qs'}).'%' } } if (($p eq 'outgoing') || ($p eq 'all')); } @@ -210,24 +211,24 @@ sub _select_host { $suffix_wc = '%' if ($param->{'qs'} !~ /\%$/); push @queries, { 'table' => 'messages', - 'criteria' => { 'host_helo' => $param->{'qs'} } }, + 'criteria' => { 'host_helo' => dos2sql($param->{'qs'}) } }, { 'table' => 'messages', - 'criteria' => { 'host_rdns' => $param->{'qs'} } }, + 'criteria' => { 'host_rdns' => dos2sql($param->{'qs'}) } }, { 'table' => 'rejects', - 'criteria' => { 'host_helo' => $param->{'qs'} } }, + 'criteria' => { 'host_helo' => dos2sql($param->{'qs'}) } }, { 'table' => 'rejects', - 'criteria' => { 'host_rdns' => $param->{'qs'} } } + 'criteria' => { 'host_rdns' => dos2sql($param->{'qs'}) } } if (($p eq 'incoming') || ($p eq 'all')); push @queries, { 'table' => 'deliveries', - 'criteria' => { 'host_dns' => $param->{'qs'} } }, + 'criteria' => { 'host_dns' => dos2sql($param->{'qs'}) } }, { 'table' => 'deferrals', - 'criteria' => { 'host_dns' => $param->{'qs'} } }, + 'criteria' => { 'host_dns' => dos2sql($param->{'qs'}) } }, { 'table' => 'errors', - 'criteria' => { 'host_dns' => $param->{'qs'} } }, + 'criteria' => { 'host_dns' => dos2sql($param->{'qs'}) } }, { 'table' => 'unknown', # the blank makes sure that we do not match domains in addresses - 'criteria' => { 'line' => $prefix_wc.' '.$param->{'qs'}.$suffix_wc } } + 'criteria' => { 'line' => $prefix_wc.' '.dos2sql($param->{'qs'}).$suffix_wc } } if (($p eq 'outgoing') || ($p eq 'all')); }; @@ -525,6 +526,16 @@ sub _print_Messages_selector { _make_tr(); + # Calendar popup DIVs + print "\n". + ' + <script language="JavaScript"> + var cal1x = new CalendarPopup("caldiv1x"); + var cal2x = new CalendarPopup("caldiv2x"); + </script> + ' + ."\n"; + print $q->div({-class=>"top_spacer"}, $q->div({-align=>"left",-style=>"padding: 10px; border: 1px solid black; background: #eeeeee;"}, diff --git a/cgi/exilog_cgi_param.pm b/cgi/exilog_cgi_param.pm index 5096ee3..5948530 100644 --- a/cgi/exilog_cgi_param.pm +++ b/cgi/exilog_cgi_param.pm @@ -57,11 +57,17 @@ sub _init_cgi_params { 'deferrals', 'rejects', 'queue' ], + 'q_qw' => [ 'frozen', + 'deferred', + 'bounce' ], 'ss' => '-all', + 'q_ss' => '-all', 'tr' => '-10m', - #'qt' => 'all', + 'q_tr' => '-5m', 'qs' => "", - 'sr' => [ keys %{ $config->{servers} } ] + 'q_qs' => "", + 'sr' => [ keys %{ $config->{servers} } ], + 'q_sr' => [ keys %{ $config->{servers} } ] }; foreach (keys %{ $defaults }) { diff --git a/cgi/exilog_cgi_queues.pm b/cgi/exilog_cgi_queues.pm index 1b1158e..4c7a61b 100644 --- a/cgi/exilog_cgi_queues.pm +++ b/cgi/exilog_cgi_queues.pm @@ -38,11 +38,76 @@ BEGIN { sub queues { _print_Queue_selector(); - my $messages = sql_select('queue',[ '*' ]); - print render_queue_table($messages); + + # Return unless the search type is set. + return unless (edt($param,'q_qt')); + + # Get all data for messages passing the filter settings. + my $criteria = { 'timestamp' => (edt($param,'q_tr') ? _make_tr() : undef), + 'server' => (edt($param,'q_sr') ? $param->{'q_sr'} : undef ) }; + + my $messages = sql_select('queue',[ '*' ], $criteria); + + my $prefiltered = []; + foreach my $message (@{ $messages }) { + next if (!ina($param->{'q_qw'},'frozen') && (edt($message,'frozen'))); + next if (!ina($param->{'q_qw'},'deferred') && (!edt($message,'frozen'))); + next if (!ina($param->{'q_qw'},'bounce') && ($message->{mailfrom} eq '<>')); + push @{$prefiltered}, $message; + } + + # Now do the most expensive filtering + my $regex = dos2rx(($param->{'q_qs'} || '*')); + my $filtered = []; + if ($param->{'q_qt'} eq 'addr') { + MESSAGE: foreach my $message (@{ $prefiltered }) { + if ($message->{'mailfrom'} =~ /$regex/i) { + push @{$filtered}, $message; + next; + } + foreach my $addr (split / /, $message->{'recipients_pending'}.' '.$message->{'recipients_delivered'}) { + if ($addr =~ /$regex/i) { + push @{$filtered}, $message; + next MESSAGE; + } + } + } + } + elsif ($param->{'q_qt'} eq 'subject') { + foreach my $message (@{ $prefiltered }) { + if ($message->{'subject'} =~ /$regex/i) { + push @{$filtered}, $message; + } + } + } + elsif ($param->{'q_qt'} eq 'headers') { + foreach my $message (@{ $prefiltered }) { + if ($message->{'headers'} =~ /$regex/smi) { + push @{$filtered}, $message; + } + } + } + else { + $filtered = $prefiltered; + } + + print render_queue_table($filtered); }; +sub _make_tr { + my $str = $q->param('q_tr') || 0; + + my $unit = chop $str; + my $now = time(); + my $units = { '0' => 0, + 'm' => 60, + 'h' => 3600, + 'd' => 86400 }; + return '0 '.($now + $units->{$unit}*$str); +} + + sub _print_Queue_selector { print @@ -51,68 +116,202 @@ sub _print_Queue_selector { $q->table({-cellspacing=>0,-cellpadding=>4,-border=>0}, $q->Tr( - $q->td({-align=>"left",-valign=>"top",-style=>"width: 16px;"}, - $q->img({-src=>$config->{web}->{webroot}."icons/server.png"}) + $q->td({-align=>"left",-style=>"width: 16px;"}, + $q->img({-src=>$config->{web}->{webroot}."icons/event_type.png"}) ), - $q->td({-align=>"left",-valign=>"top",-style=>"width: 100px;"}, - "Servers" + $q->td({-align=>"left",-style=>"width: 100px;"}, + "Search Type" ), $q->td({-align=>"left"}, - eval { - my $html =""; - my $num = 0; - my $groups = {}; - foreach my $server (sort {$a cmp $b} keys %{ $config->{servers} }) { - if (($num % 4) == 0) { - $html .= '<tr>'; - }; - $html .= $q->td({-width=>"1%",-style=>"padding-right: 4px;"}, - $q->checkbox( { -name=>"sr", - -label=>"", - -id=>(edt($config->{servers}->{$server},'group') ? $config->{servers}->{$server}->{group} : "-XXX"), - -checked=>(ina($param->{'sr'},$server) ? 'checked' : undef), - -override=>1, - -onDblClick=>"javascript:sr_off_except(this);", - -onChange=>"javascript:sr_changed();", - -value=>$server } ) - ). - $q->td({-width=>"1%",-style=>"padding-right: 10px;"}, - $server - ); - if (($num % 4) == 3) { - $html .= '<td> </td></tr>'; - }; - $num++; - if (edt($config->{servers}->{$server},'group')) { - $groups->{$config->{servers}->{$server}->{group}} = '{'.$config->{servers}->{$server}->{group}.'}'; - }; - }; - if (($num % 4) != 0) { - $html .= '<td> </td>' x ((4-($num % 4))*2); - $html .= '<td> </td></tr>'; - }; - $groups->{'-all'} = 'All servers'; - $groups->{'-custom'} = 'Custom selection'; - $q->table({-border=>0,-cellpadding=>0,-cellspacing=>0,-width=>"1%"}, - $q->Tr( - $q->td({-colspan=>9,-align=>"left",-style=>"padding-bottom: 4px;"}, - $q->popup_menu({ -name=>"ss", - -id=>"ss", - -style=>"width: 400px;", - -values=>[ sort {$a cmp $b} keys(%{$groups}) ], - -labels=>$groups, - -onChange=>"javascript:ss_changed();", - -default=>(exists($param->{'ss'}) ? ($param->{'ss'} || '-all') : '-all'), - -override=>1}) - ) - ), - $html - ); - }.($@ ? $@ : "") + $q->popup_menu({ -name=>"q_qt", + -id=>"q_qt", + -style=>"width: 400px;", + -values=>[ 'all', + 'addr', + 'subject', + 'headers' + ], + -labels=>{ 'all' => "None - show everything", + 'addr' => "Address", + 'subject' => "Subject", + 'headers' => "Headers" + }, + -default=>(exists($param->{'q_qt'}) ? ($param->{'q_qt'} || 'all') : 'all'), + -onChange=>"javascript:switch_controls(document.getElementById('q_qt').options[document.getElementById('q_qt').selectedIndex].value);", + -override=>1}) + ) + ) + ) + . + $q->span({-id=>"term"},'<!-- Dynamic content target DIV -->'). + $q->div({-id=>"term_hidden",-style=>"visibility: hidden; position: absolute;"}, + $q->table({-cellspacing=>0,-cellpadding=>4,-border=>0}, + $q->Tr( + $q->td({-align=>"left",-style=>"width: 16px;"}, + $q->img({-src=>$config->{web}->{webroot}."icons/find.png"}) + ), + $q->td({-align=>"left",-style=>"width: 100px;"}, + "Search Term" + ), + $q->td({-align=>"left"}, + $q->textfield( { -name=>"q_qs", + -style=>"width: 400px;", + -value=>(exists($param->{'q_qs'}) ? ($param->{'q_qs'} || '') : ''), + -override=>1 } ) + ) ) ) ) . + $q->span({-id=>"events"},'<!-- Dynamic content target DIV -->'). + $q->div({-id=>"events_hidden",-style=>"visibility: hidden; position: absolute;"}, + $q->table({-cellspacing=>0,-cellpadding=>4,-border=>0}, + $q->Tr( + $q->td({-align=>"left",-valign=>"top",-style=>"width: 16px;"}, + $q->img({-src=>$config->{web}->{webroot}."icons/address.png"}) + ), + $q->td({-align=>"left",-valign=>"top",-style=>"width: 100px;"}, + "Status" + ), + $q->td({-align=>"left",-style=>"padding:2px 4px 4px 4px;"}, + eval { + my @where = ( 'frozen', + 'deferred', + 'bounce' ); + + my $labels = { 'frozen' => 'Frozen', + 'deferred' => 'Deferred', + 'bounce' => 'Bounce' }; + + my $html = ""; + my $num = 0; + foreach my $w (@where) { + if (($num % 3) == 0) { + $html .= '<tr>'; + } + $html .= $q->td({-width=>"1%",-style=>"padding-right: 4px;"}, + $q->checkbox( { -name=>"q_qw", + -label=>"", + -checked=>(ina($param->{'q_qw'},$w) ? 'checked' : undef), + -onDblClick=>"javascript:q_qw_off_except(this);", + -override=>1, + -value=>$w } ) + ). + $q->td({-style=>"padding-right: 10px;"}, + $labels->{$w} + ); + if (($num % 3) == 2) { + $html .= '</tr>'; + } + $num++; + } + $q->table({-border=>0,-cellpadding=>0,-cellspacing=>0,-width=>"1%"}, + $html + ); + } + ) + ) + ) + ) + . + $q->span({-id=>"server"},'<!-- Dynamic content target DIV -->'). + $q->div({-id=>"server_hidden",-style=>"visibility: hidden; position: absolute;"}, + $q->table({-cellspacing=>0,-cellpadding=>4,-border=>0}, + $q->Tr( + $q->td({-align=>"left",-valign=>"top",-style=>"width: 16px;"}, + $q->img({-src=>$config->{web}->{webroot}."icons/server.png"}) + ), + $q->td({-align=>"left",-valign=>"top",-style=>"width: 100px;"}, + "Servers" + ), + $q->td({-align=>"left"}, + eval { + my $html =""; + my $num = 0; + my $groups = {}; + foreach my $server (sort {$a cmp $b} keys %{ $config->{servers} }) { + if (($num % 4) == 0) { + $html .= '<tr>'; + } + $html .= $q->td({-width=>"1%",-style=>"padding-right: 4px;"}, + $q->checkbox( { -name=>"q_sr", + -label=>"", + -id=>(edt($config->{servers}->{$server},'group') ? $config->{servers}->{$server}->{group} : "-XXX"), + -checked=>(ina($param->{'q_sr'},$server) ? 'checked' : undef), + -override=>1, + -onDblClick=>"javascript:q_sr_off_except(this);", + -onChange=>"javascript:q_sr_changed();", + -value=>$server } ) + ). + $q->td({-width=>"1%",-style=>"padding-right: 10px;"}, + $server + ); + if (($num % 4) == 3) { + $html .= '<td> </td></tr>'; + } + $num++; + if (edt($config->{servers}->{$server},'group')) { + $groups->{$config->{servers}->{$server}->{group}} = '{'.$config->{servers}->{$server}->{group}.'}'; + } + } + if (($num % 4) != 0) { + $html .= '<td> </td>' x ((4-($num % 4))*2); + $html .= '<td> </td></tr>'; + } + $groups->{'-all'} = 'All servers'; + $groups->{'-custom'} = 'Custom selection'; + $q->table({-border=>0,-cellpadding=>0,-cellspacing=>0,-width=>"1%"}, + $q->Tr( + $q->td({-colspan=>9,-align=>"left",-style=>"padding-bottom: 4px;"}, + $q->popup_menu({ -name=>"q_ss", + -id=>"q_ss", + -style=>"width: 400px;", + -values=>[ sort {$a cmp $b} keys(%{$groups}) ], + -labels=>$groups, + -onChange=>"javascript:q_ss_changed();", + -default=>(exists($param->{'q_ss'}) ? ($param->{'q_ss'} || '-all') : '-all'), + -override=>1}) + ) + ), + $html + ); + } + ) + ) + ) + ) + . + $q->span({-id=>"time"},'<!-- Dynamic content target DIV -->'). + $q->div({-id=>"time_hidden",-style=>"visibility: hidden; position: absolute;"}, + $q->table({-cellspacing=>0,-cellpadding=>4,-border=>0}, + $q->Tr( + $q->td({-align=>"left",-style=>"width: 16px;"}, + $q->img({-src=>$config->{web}->{webroot}."icons/timerange.png"}) + ), + $q->td({-align=>"left",-style=>"width: 100px;"}, + "Age" + ), + $q->td({-align=>"left"}, + $q->popup_menu({ -name=>"q_tr", + -id=>"q_tr", + -style=>"width: 400px;", + -values=>[ '0', + '-5m', + '-1h', + '-12h', + '-1d' ], + -labels=>{ '0' => 'Any', + '-5m' => 'Older than 5 minutes', + '-1h' => 'Older than 1 hour', + '-12h' => 'Older than 12 hours', + '-1d' => 'Older than 1 day' }, + -default=>(exists($param->{'q_tr'}) ? $param->{'q_tr'} : '-5m'), + -override=>1}) + ) + ) + ) + ) + . '<hr>' . $q->table({-cellspacing=>0,-cellpadding=>4,-border=>0,-align=>"center"}, @@ -125,6 +324,16 @@ sub _print_Queue_selector { ) ); + + print "\n". + ' + <script language="JavaScript"> + init_controls(); + switch_controls(document.getElementById("q_qt").options[document.getElementById("q_qt").selectedIndex].value); + </script> + ' + ."\n"; + }; 1; diff --git a/doc/mysql-db-script.sql b/doc/mysql-db-script.sql index 79cabfb..a38b95a 100644 --- a/doc/mysql-db-script.sql +++ b/doc/mysql-db-script.sql @@ -20,7 +20,7 @@ CREATE TABLE `deferrals` ( `rcpt` varchar(200) NOT NULL default '', `rcpt_intermediate` varchar(200) default NULL, `rcpt_final` varchar(200) NOT NULL default '', - `host_addr` varchar(15) default NULL, + `host_addr` varchar(39) default NULL, `host_dns` varchar(255) default NULL, `tls_cipher` varchar(128) default NULL, `router` varchar(128) default NULL, @@ -48,7 +48,7 @@ CREATE TABLE `deliveries` ( `rcpt` varchar(200) NOT NULL default '', `rcpt_intermediate` varchar(200) default NULL, `rcpt_final` varchar(200) NOT NULL default '', - `host_addr` varchar(15) default NULL, + `host_addr` varchar(39) default NULL, `host_dns` varchar(255) default NULL, `tls_cipher` varchar(128) default NULL, `router` varchar(128) default NULL, @@ -76,7 +76,7 @@ CREATE TABLE `errors` ( `rcpt` varchar(200) NOT NULL default '', `rcpt_intermediate` varchar(200) default NULL, `rcpt_final` varchar(200) NOT NULL default '', - `host_addr` varchar(15) default NULL, + `host_addr` varchar(39) default NULL, `host_dns` varchar(255) default NULL, `tls_cipher` varchar(128) default NULL, `router` varchar(128) default NULL, @@ -104,7 +104,7 @@ CREATE TABLE `messages` ( `msgid` varchar(255) default NULL, `completed` bigint(20) default NULL, `mailfrom` varchar(255) default NULL, - `host_addr` varchar(15) default NULL, + `host_addr` varchar(39) default NULL, `host_rdns` varchar(255) default NULL, `host_ident` varchar(255) default NULL, `host_helo` varchar(255) default NULL, @@ -164,7 +164,7 @@ CREATE TABLE `rejects` ( `server` varchar(32) NOT NULL default '', `message_id` varchar(16) binary default NULL, `timestamp` bigint(20) NOT NULL default '0', - `host_addr` varchar(15) NOT NULL default '', + `host_addr` varchar(39) NOT NULL default '', `host_rdns` varchar(255) NOT NULL default '', `host_ident` varchar(255) default NULL, `host_helo` varchar(255) default NULL, diff --git a/htdocs/exilog_jscript.js b/htdocs/exilog_jscript.js index 01aaf52..e08d79d 100644 --- a/htdocs/exilog_jscript.js +++ b/htdocs/exilog_jscript.js @@ -1,3 +1,43 @@ +// ******************************************************************** +// XMLHTTP stuff + +var xmlhttp=false; +/*@cc_on @*/ +/*@if (@_jscript_version >= 5) +// JScript gives us Conditional compilation, we can cope with old IE versions. +// and security blocked creation of the objects. + try { + xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); +} catch (e) { + try { + xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); +} catch (E) { + xmlhttp = false; +} +} +@end @*/ +if (!xmlhttp && typeof XMLHttpRequest!='undefined') { + xmlhttp = new XMLHttpRequest(); +} + +var xmlhttpparent; +function message_action(myserver,mymsgid,mycontrol,myparent) { + xmlhttpparent = myparent; + var myaction = mycontrol.options[mycontrol.selectedIndex].value; + if (myaction.length < 2) return; + xmlhttp.open("GET", "?xmlhttp=1&action="+myaction+"&server="+myserver+"&message_id="+mymsgid,true); + xmlhttp.onreadystatechange=function() { + if (xmlhttp.readyState==4) { + document.getElementById(xmlhttpparent).innerHTML = xmlhttp.responseText; + } + } + xmlhttp.send(null) +} + + +// ******************************************************************** +// Some generic functions used across the interface + function set_value(myobj,myvalue) { document.getElementById(myobj).value = myvalue; }; @@ -16,6 +56,10 @@ function link_off(myobj) { myobj.style.background = myobj.id; }; + +// ******************************************************************** +// JS Code for the picker controls on the "Messages" and "Queues" tabs + var my_controls = new Object; my_controls['term'] = new Object; my_controls['events'] = new Object; @@ -77,9 +121,12 @@ function switch_controls(myselection) { } }; -function check_group(group) -{ - var j, c=document.forms[0].elements, s=c.length; + +// ================================================================== +// "Messages" tab specific +// +function check_group(group) { + var j, c=document.forms[0].elements, s=c.length; for( j=0 ; j<s ; j++ ) { if (c[j].name == "sr") if( c[j].id == group ) @@ -127,8 +174,63 @@ function sr_changed() { }; +// ================================================================== +// "Queues" tab specific +// +function q_check_group(group) { + var j, c=document.forms[0].elements, s=c.length; + for( j=0 ; j<s ; j++ ) { + if (c[j].name == "q_sr") + if( c[j].id == group ) + c[j].checked = true; + else + c[j].checked = false; + }; +} + +function q_ss_changed() { + if (document.getElementById('q_ss').selectedIndex == 0) { + // "all" was selected, select all + var j, c=document.forms[0].elements, s=c.length; + for( j=0 ; j<s ; j++ ) + if (c[j].name == "q_sr") c[j].checked = true; + } + else if (document.getElementById('q_ss').selectedIndex == 1) { + // "custom" was selected, blank all + var j, c=document.forms[0].elements, s=c.length; + for( j=0 ; j<s ; j++ ) + if (c[j].name == "q_sr") c[j].checked = false; + } + else { + var group = document.getElementById('q_ss').options[document.getElementById('q_ss').selectedIndex].value; + q_check_group(group); + }; +}; + +function q_sr_off_except(myobj) { + var j, c=document.forms[0].elements, s=c.length; + for( j=0 ; j<s ; j++ ) + if (c[j].name == "q_sr") c[j].checked = false; + myobj.checked = true; +}; + +function q_qw_off_except(myobj) { + var j, c=document.forms[0].elements, s=c.length; + for( j=0 ; j<s ; j++ ) + if (c[j].name == "q_qw") c[j].checked = false; + myobj.checked = true; +}; + +function q_sr_changed() { + document.getElementById('q_ss').selectedIndex = 1; +}; + + +// ****************************************************************** +// JS Code for the Date picker control +// // =================================================================== // Author: Matt Kruse <matt@mattkruse.com> @@ -1227,6 +1329,3 @@ function CP_getCalendar() { return result; } - -var cal1x = new CalendarPopup("caldiv1x"); -var cal2x = new CalendarPopup("caldiv2x"); diff --git a/htdocs/exilog_stylesheet.css b/htdocs/exilog_stylesheet.css index f50ec95..e315446 100644 --- a/htdocs/exilog_stylesheet.css +++ b/htdocs/exilog_stylesheet.css @@ -91,9 +91,15 @@ select { font-size: 10px; } -table.queue_table { - background: black; +table.queue_frame_table { + border: 0; + font-size: 12px; +} +table.queue_entry_table { + background: #999999; + margin-bottom: 8px; font-size: 12px; + width: 926px; } td.queue_header { background: #cccccc; @@ -104,15 +110,26 @@ td.queue { background: #eeeeee; white-space: nowrap; padding: 2px 4px 2px 4px; + font-family: monospace; +} + +div.popup_container { + position: relative; + width:0px; + height:0px; + border:0; + margin:0; + padding:0; } -div.rcpts_pending_popup { +div.popup { position: absolute; visibility: hidden; - background: #dddddd; + background: #eeeeee; + top: -3px; + left: -5px; color: black; - padding: 4px; - border: 1px solid black; - width: 100px; + padding: 2px 4px 2px 4px; + border: 1px solid #999999; } td.table_titlebar { diff --git a/lib/exilog_parse.pm b/lib/exilog_parse.pm index 2074b13..f1d49df 100644 --- a/lib/exilog_parse.pm +++ b/lib/exilog_parse.pm @@ -40,7 +40,7 @@ sub _parse_error { $subj = _parse_delivery($subj,$h); m/()()/; - if ($subj =~ / host ([^ ]+?) \[([0-9.]+?)\]\:/) { + if ($subj =~ / host ([^ ]+?) \[([0-9A-Fa-f:.]+?)\]\:/) { $h->{host_addr} = $2; $h->{host_dns} = $1; }; @@ -58,7 +58,7 @@ sub _parse_deferral { $subj = _parse_delivery($subj,$h); - if ($subj =~ / host ([^ ]+?) \[([0-9.]+?)\]\:/) { + if ($subj =~ / host ([^ ]+?) \[([0-9A-Fa-f:.]+?)\]\:/) { $h->{host_addr} = $2; $h->{host_dns} = $1; }; @@ -138,7 +138,7 @@ sub _parse_arrival { if ($1) { my $hstr = $1; m/()/; - $hstr =~ s/\[([0-9.]+)\]$//; + $hstr =~ s/\[([0-9A-Fa-f:.]+)\]$//; $h->{host_addr} = $1 if ($1); $hstr =~ s/^ +//; diff --git a/lib/exilog_sql.pm b/lib/exilog_sql.pm index 7c116a6..8dcc348 100644 --- a/lib/exilog_sql.pm +++ b/lib/exilog_sql.pm @@ -158,7 +158,7 @@ sub _pgsql_sql_update_heartbeat { sub _pgsql_sql_queue_delete { my $spool_path = shift; - $dbh->do("DELETE FROM queue WHERE spool_path='$spool_path'"); + $dbh->do("DELETE FROM queue WHERE spool_path=".$dbh->quote($spool_path)); }; sub _pgsql_sql_queue_update { @@ -182,13 +182,12 @@ sub _pgsql_sql_queue_update { my @tmp; foreach my $item (keys %{ $hdr }) { - my $value = $hdr->{$item}; - $value =~ s/\'/\'\'/g; - $value =~ s/\n/\\n/g; - push @tmp, $item.'='."'".$value."'"; + push @tmp, $item.'='.$dbh->quote($hdr->{$item}); }; - $dbh->do("UPDATE queue SET ".join(",",@tmp)." WHERE message_id='".$message_id."' AND server='".$server."'"); + $dbh->do("UPDATE queue SET ".join(",",@tmp). + " WHERE message_id=".$dbh->quote($message_id). + " AND server=".$dbh->quote($server)); }; sub _pgsql_sql_queue_add { @@ -208,10 +207,7 @@ sub _pgsql_sql_queue_add { my @fields = sort {$a cmp $b} keys(%{$hdr}); my @vals = (); foreach (@fields) { - my $val = $hdr->{$_}; - $val =~ s/\'/\'\'/g; - $val =~ s/\n/\\n/g; - push @vals, "'".$val."'"; + push @vals, $dbh->quote($hdr->{$_}); }; $dbh->do("INSERT INTO queue (".join(',',@fields).") VALUES(".join(',',@vals).")"); @@ -281,7 +277,9 @@ sub _pgsql_write_message { # Special case: we only need to UPDATE the 'completed' field # in the messages table. if ( ($h->{table} eq 'messages') && (exists($h->{data}->{completed})) ) { - my $rc = $dbh->do("UPDATE messages SET completed='".$h->{data}->{completed}."' WHERE message_id='".$h->{data}->{message_id}."' AND server='".$server."'"); + my $rc = $dbh->do("UPDATE messages SET completed=".$dbh->quote($h->{data}->{completed}). + " WHERE message_id=".$dbh->quote($h->{data}->{message_id}). + " AND server=".$dbh->quote($server)); if (defined($rc)) { return 1; } @@ -292,15 +290,9 @@ sub _pgsql_write_message { } else { my @fields = sort {$a cmp $b} keys(%{$h->{data}}); - my @vals = ( "'".$server."'" ); - foreach (@fields) { - my $val = $h->{data}->{$_}; - $val =~ s/\'/\'\'/g; - # shorten $val to limit and remove eventual - # trailing quote and backslash characters. - $val = substr($val,0,255); - $val =~ s/[\\']+$//; - push @vals, "'".$val."'"; + my @vals = ( $dbh->quote($server) ); + foreach (@fields) { + push @vals, $dbh->quote(substr($h->{data}->{$_},0,255)); }; unshift @fields, 'server'; @@ -345,7 +337,7 @@ sub _mysql_sql_update_heartbeat { sub _mysql_sql_queue_delete { my $spool_path = shift; - $dbh->do("DELETE FROM queue WHERE spool_path='$spool_path'"); + $dbh->do("DELETE FROM queue WHERE spool_path=".$dbh->quote($spool_path)); }; sub _mysql_sql_queue_update { @@ -360,13 +352,12 @@ sub _mysql_sql_queue_update { my @tmp; foreach my $item (keys %{ $hdr }) { - my $value = $hdr->{$item}; - $value =~ s/\'/\'\'/g; - $value =~ s/\n/\\n/g; - push @tmp, $item.'='."'".$value."'"; + push @tmp, $item.'='.$dbh->quote($hdr->{$item}); }; - $dbh->do("UPDATE queue SET ".join(",",@tmp)." WHERE message_id='".$message_id."' AND server='".$server."'"); + $dbh->do("UPDATE queue SET ".join(",",@tmp). + " WHERE message_id=".$dbh->quote($message_id). + " AND server=".$dbh->quote($server)); }; sub _mysql_sql_queue_add { @@ -377,10 +368,7 @@ sub _mysql_sql_queue_add { my @fields = sort {$a cmp $b} keys(%{$hdr}); my @vals = (); foreach (@fields) { - my $val = $hdr->{$_}; - $val =~ s/\'/\'\'/g; - $val =~ s/\n/\\n/g; - push @vals, "'".$val."'"; + push @vals, $dbh->quote($hdr->{$_}); }; $dbh->do("INSERT INTO queue (".join(',',@fields).") VALUES(".join(',',@vals).")"); @@ -391,14 +379,17 @@ sub _mysql_sql_queue_set_action { my $message_id = shift; my $action = shift; - $dbh->do("UPDATE queue SET action='$action' WHERE server='$server' AND message_id='$message_id'"); + $dbh->do("UPDATE queue SET action=".$dbh->quote($action). + " WHERE server=".$dbh->quote($server). + " AND message_id=".$dbh->quote($message_id)); }; sub _mysql_sql_queue_clear_action { my $server = shift; my $message_id = shift; - $dbh->do("UPDATE queue SET action=NULL WHERE server='$server' AND message_id='$message_id'"); + $dbh->do("UPDATE queue SET action=NULL WHERE server=".$dbh->quote($server). + " AND message_id=".$dbh->quote($message_id)); }; @@ -457,7 +448,9 @@ sub _mysql_write_message { # Special case: we only need to UPDATE the 'completed' field # in the messages table. if ( ($h->{table} eq 'messages') && (exists($h->{data}->{completed})) ) { - my $rc = $dbh->do("UPDATE messages SET completed='".$h->{data}->{completed}."' WHERE message_id='".$h->{data}->{message_id}."' AND server='".$server."'"); + my $rc = $dbh->do("UPDATE messages SET completed=".$dbh->quote($h->{data}->{completed}). + " WHERE message_id=".$dbh->quote($h->{data}->{message_id}). + " AND server=".$dbh->quote($server)); if (defined($rc)) { return 1; } @@ -468,15 +461,9 @@ sub _mysql_write_message { } else { my @fields = sort {$a cmp $b} keys(%{$h->{data}}); - my @vals = ( "'".$server."'" ); + my @vals = ( $dbh->quote($server) ); foreach (@fields) { - my $val = $h->{data}->{$_}; - $val =~ s/\'/\'\'/g; - # shorten $val to limit and remove eventual - # trailing quote and backslash characters. - $val = substr($val,0,255); - $val =~ s/[\\']+$//; - push @vals, "'".$val."'"; + push @vals, $dbh->quote(substr($h->{data}->{$_},0,255)); }; unshift @fields, 'server'; @@ -543,7 +530,7 @@ sub _build_WHERE { # array ref, use exact string match with OR my $str = "( "; foreach my $entry (@{ $criteria->{$col} }) { - $str .= " ".$col." = '".$entry."' OR"; + $str .= " ".$col." = ".$dbh->quote($entry)." OR"; }; chop($str);chop($str); $str .= " )"; @@ -555,14 +542,14 @@ sub _build_WHERE { if (($criteria->{$col} =~ /\%/) || ($criteria->{$col} =~ /\_/)) { # use ILIKE for PGSQL if ($config->{sql}->{type} eq 'pgsql') { - push @set, $col." ILIKE '".$criteria->{$col}."'"; + push @set, $col." ILIKE ".$dbh->quote($criteria->{$col}); } else { - push @set, $col." LIKE '".$criteria->{$col}."'"; + push @set, $col." LIKE ".$dbh->quote($criteria->{$col}); }; } else { - push @set, $col." = '".$criteria->{$col}."'"; + push @set, $col." = ".$dbh->quote($criteria->{$col}); }; }; }; diff --git a/lib/exilog_util.pm b/lib/exilog_util.pm index c50e679..2823bf2 100644 --- a/lib/exilog_util.pm +++ b/lib/exilog_util.pm @@ -29,6 +29,9 @@ BEGIN { &date_to_stamp &stamp_to_date &human_size + &dos2rx + &dos2sql + &png ); %EXPORT_TAGS = (); @@ -36,9 +39,42 @@ BEGIN { # your exported package globals go here, # as well as any optionally exported functions @EXPORT_OK = qw(); + +} + +sub png { + my $image = shift; + my $width = shift; + my $height = shift; + my $title = shift || ""; + + return '<img src="'.$image.'" width="'.$width.'" height="'.$height.'" title="'.$title.'" border="0">'; } +# turns DOS wildcards (* and ?) into regular expressions +sub dos2rx { + my $cand = shift; + + # quote every funky character + $cand =~ s/([^A-Za-z0-9 _?*])/\\$1/g; + + $cand =~ s/\?/./g; + $cand =~ s/\*/.*?/g; + + return '^'.$cand.'$'; +}; + +# turns DOS wildcards (* and ?) into SQL wildcards (% and .) +sub dos2sql { + my $cand = shift; + + $cand =~ s/\*/%/g; + $cand =~ s/\?/./g; + + return $cand; +}; + # checks if scalar is in array sub ina { my $aref = shift || []; @@ -87,7 +123,7 @@ sub date_to_stamp { $year-=1900; $month--; - # This is for parsing timestamps that include GMT offsets + # This is for parsing timestamps that include GMT offsets if (edv($junk)) { my $hoff = ($junk =~ /[-+](\d\d)\d\d/); my $moff = ($junk =~ /[-+]\d\d(\d\d)/); @@ -98,7 +134,7 @@ sub date_to_stamp { else { $hour = $hour + $hoff; $minute = $minute + $moff; - } + } }; if ($config->{web}->{timestamps} eq 'local') { |