summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Kistner <tom@duncanthrax.net>2008-12-04 11:24:17 +0100
committerAndreas Unterkircher <unki@netshadow.at>2008-12-12 23:18:56 +0100
commitf8a8bc98f9a77d24e0fce2abd73c9512bcf26f2d (patch)
tree84af841fdb450b60d54e590ec02b9ddb0e671cba
parenta35e1469841bfbc7e58b66dcefb108993bc4b494 (diff)
downloadexilog-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-xagent/exilog_agent.pl4
-rwxr-xr-xcgi/exilog_cgi.pl37
-rw-r--r--cgi/exilog_cgi_html.pm223
-rw-r--r--cgi/exilog_cgi_messages.pm69
-rw-r--r--cgi/exilog_cgi_param.pm10
-rw-r--r--cgi/exilog_cgi_queues.pm323
-rw-r--r--doc/mysql-db-script.sql10
-rw-r--r--htdocs/exilog_jscript.js111
-rw-r--r--htdocs/exilog_stylesheet.css31
-rw-r--r--lib/exilog_parse.pm6
-rw-r--r--lib/exilog_sql.pm77
-rw-r--r--lib/exilog_util.pm40
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' => '&middot;' } : 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/\&/&amp;/g;
+ $headers =~ s/\</&lt;/g;
+ $headers =~ s/\>/&gt;/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).'&darr;)' : "" ) } )
+ )
+ ),
+ $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%"},
- "&nbsp;"
- ),
- $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>&nbsp;</td></tr>';
- };
- $num++;
- if (edt($config->{servers}->{$server},'group')) {
- $groups->{$config->{servers}->{$server}->{group}} = '{'.$config->{servers}->{$server}->{group}.'}';
- };
- };
- if (($num % 4) != 0) {
- $html .= '<td>&nbsp;</td>' x ((4-($num % 4))*2);
- $html .= '<td>&nbsp;</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>&nbsp;</td></tr>';
+ }
+ $num++;
+ if (edt($config->{servers}->{$server},'group')) {
+ $groups->{$config->{servers}->{$server}->{group}} = '{'.$config->{servers}->{$server}->{group}.'}';
+ }
+ }
+ if (($num % 4) != 0) {
+ $html .= '<td>&nbsp;</td>' x ((4-($num % 4))*2);
+ $html .= '<td>&nbsp;</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') {