#!/usr/local/bin/perl
# view_table.cgi
# Display all data in some table

require './mysql-lib.pl';
if ($ENV{'REQUEST_METHOD'} eq 'GET') {
	&ReadParse();
	}
else {
	&ReadParseMime();
	}
&can_edit_db($in{'db'}) || &error($text{'dbase_ecannot'});
@str = &table_structure($in{'db'}, $in{'table'});
foreach $s (@str) {
	$keyed++ if ($s->{'key'} eq 'PRI');
	}
if ($in{'field'}) {
	$search = "where ".&quotestr($in{'field'})." ".
		($in{'match'} == 0 ? "like \"%$in{'for'}%\"" :
		 $in{'match'} == 1 ? "like \"$in{'for'}\"" :
		 $in{'match'} == 2 ? "not like \"%$in{'for'}%\"" :
		 $in{'match'} == 3 ? "not like \"$in{'for'}\"" : " = \"\"");
	}

if ($in{'delete'}) {
	# Deleting selected rows
	$d = &execute_sql($in{'db'}, "select * from ".&quotestr($in{'table'}).
			 " $search limit ".$in{'start'}.",".$config{'perpage'});
	@t = @{$d->{'titles'}};
	$count = 0;
	foreach $r (split(/\0/, $in{'row'})) {
		local @where;
		local @r = @{$d->{'data'}->[$r]};
		for($i=0; $i<@t; $i++) {
			if ($str[$i]->{'key'} eq 'PRI') {
				if ($r[$i] eq 'NULL') {
					push(@where,
					    &quotestr($t[$i])." is null");
					}
				else {
					$r[$i] =~ s/'/''/g;
					push(@where,
					    &quotestr($t[$i])." = '$r[$i]'");
					}
				}
			}
		&execute_sql_logged($in{'db'},
				    "delete from ".&quotestr($in{'table'}).
				    " where ".join(" and ", @where));
		$count++;
		}
	&webmin_log("delete", "data", $count, \%in);
	&redirect("view_table.cgi?db=$in{'db'}&".
		  "table=$in{'table'}&start=$in{'start'}&field=$in{'field'}&".
		  "for=".&urlize($in{'for'})."&match=$in{'match'}");
	}
elsif ($in{'save'}) {
	# Update edited rows
	$d = &execute_sql($in{'db'}, "select * from ".&quotestr($in{'table'})." $search limit ".$in{'start'}.",".$config{'perpage'});
	@t = @{$d->{'titles'}};
	$count = 0;
	for($j=0; $j<$config{'perpage'}; $j++) {
		next if (!defined($in{"${j}_$t[0]"}));
		local (@where, @set);
		local @r = @{$d->{'data'}->[$j]};
		for($i=0; $i<@t; $i++) {
			$r[$i] =~ s/'/''/g;
			if ($str[$i]->{'key'} eq 'PRI') {
				if ($r[$i] eq 'NULL') {
					push(@where,
					     &quotestr($t[$i])." is null");
					}
				else {
					push(@where,
					     &quotestr($t[$i])." = '$r[$i]'");
					}
				}
			local $ij = $in{"${j}_$t[$i]"};
			$ij =~ s/'/''/g;
			$ij =~ s/\r//g;
			if ($ij eq '') {
				push(@set, &quotestr($t[$i])." = NULL");
				}
			else {
				push(@set, &quotestr($t[$i])." = '$ij'");
				}
			}
		&execute_sql_logged($in{'db'},
				    "update ".&quotestr($in{'table'})." set ".
				    join(" , ", @set)." where ".
				    join(" and ", @where));
		$count++;
		}
	&webmin_log("modify", "data", $count, \%in);
	&redirect("view_table.cgi?db=$in{'db'}&".
		  "table=$in{'table'}&start=$in{'start'}&field=$in{'field'}&".
		  "for=".&urlize($in{'for'})."&match=$in{'match'}");
	}
elsif ($in{'savenew'}) {
	# Adding a new row
	for($j=0; defined($in{$j}); $j++) {
		$in{$j} =~ s/'/''/g;
		$in{$j} =~ s/\r//g;
		push(@set, $in{$j} eq '' ? 'NULL' : "'$in{$j}'");
		}
	&execute_sql_logged($in{'db'}, "insert into ".&quotestr($in{'table'}).
			    " values (".join(" , ", @set).")");
	&redirect("view_table.cgi?db=$in{'db'}&".
		  "table=$in{'table'}&start=$in{'start'}&field=$in{'field'}&".
		  "for=".&urlize($in{'for'})."&match=$in{'match'}");
	&webmin_log("create", "data", undef, \%in);
	}
elsif ($in{'cancel'} || $in{'new'}) {
	undef($in{'row'});
	}

&header($text{'view_title'}, "");
print "<center><font size=+2>",&text('table_header', "<tt>$in{'table'}</tt>",
				     "<tt>$in{'db'}</tt>"),"</font></center>\n";
print "<hr><p>\n";

$d = &execute_sql($in{'db'},
	"select count(*) from ".&quotestr($in{'table'})." $search");
$total = int($d->{'data'}->[0]->[0]);
if ($in{'jump'} > 0) {
	$in{'start'} = int($in{'jump'} / $config{'perpage'}) *
		       $config{'perpage'};
	if ($in{'start'} >= $total) {
		$in{'start'} = $total - $config{'perpage'};
		$in{'start'} = int(($in{'start'} / $config{'perpage'}) + 1) *
			       $config{'perpage'};
		}
	}
else {
	$in{'start'} = int($in{'start'});
	}
if ($in{'new'} && $total > $config{'perpage'}) {
	# go to the last screen for adding a row
	$in{'start'} = $total - $config{'perpage'};
	$in{'start'} = int(($in{'start'} / $config{'perpage'}) + 1) *
		       $config{'perpage'};
	}
if ($in{'start'} || $total > $config{'perpage'}) {
	print "<center>\n";
	if ($in{'start'}) {
		printf "<a href='view_table.cgi?db=%s&table=%s&start=%s&".
		       "field=%s&for=%s&match=%s'>".
		       "<img src=/images/left.gif border=0 align=middle></a>\n",
			$in{'db'}, $in{'table'},
			$in{'start'} - $config{'perpage'},
			$in{'field'}, $in{'for'}, $in{'match'};
		}
	print "<font size=+1>",&text('view_pos', $in{'start'}+1,
	      $in{'start'}+$config{'perpage'} > $total ? $total :
	      $in{'start'}+$config{'perpage'}, $total),"</font>\n";
	if ($in{'start'}+$config{'perpage'} < $total) {
		printf "<a href='view_table.cgi?db=%s&table=%s&start=%s&".
		       "field=%s&for=%s&match=%s'>".
		       "<img src=/images/right.gif border=0 align=middle></a> ",
			$in{'db'}, $in{'table'},
			$in{'start'} + $config{'perpage'},
			$in{'field'}, $in{'for'}, $in{'match'};
		}
	print "</center>\n";
	}

if ($in{'field'}) {
	print "<table width=100% cellspacing=0 cellpadding=0><tr>\n";
	print "<td><b>",&text('view_searchhead', "<tt>$in{'for'}</tt>",
			   "<tt>$in{'field'}</tt>"),"</b></td>\n";
	print "<td align=right><a href='view_table.cgi?db=$in{'db'}&",
	      "table=$in{'table'}'>$text{'view_searchreset'}</a></td>\n";
	print "</tr></table>\n";
	}

print "<form action=view_table.cgi method=post enctype=multipart/form-data>\n";
print "<input type=hidden name=db value='$in{'db'}'>\n";
print "<input type=hidden name=table value='$in{'table'}'>\n";
print "<input type=hidden name=start value='$in{'start'}'>\n";
if ($in{'field'}) {
	print "<input type=hidden name=field value='$in{'field'}'>\n";
	print "<input type=hidden name=for value='$in{'for'}'>\n";
	print "<input type=hidden name=match value='$in{'match'}'>\n";
	}
$check = !defined($in{'row'}) && !$in{'new'} && $keyed;
if ($total || $in{'new'}) {
	$d = &execute_sql($in{'db'},
		"select * from ".&quotestr($in{'table'})." $search limit ".
		$in{'start'}.",".$config{'perpage'});
	@data = @{$d->{'data'}};
	print "<table border width=100%>\n";
	print "<tr $tb>\n";
	print "<td>&nbsp;</td>\n" if ($check);
	foreach $t (@str) {
		print "<td><b>$t->{'field'}</b></td>\n";
		$has_blob++ if ($t->{'type'} =~ /(text|blob)$/);
		}
	print "</tr>\n";

	map { $row{$_}++ } split(/\0/, $in{'row'});
	$w = int(100 / scalar(@str));
	$w = 10 if ($w < 10);
	for($i=0; $i<@data; $i++) {
		local @d = map { $_ eq "NULL" ? undef : $_ } @{$data[$i]};
		print "<tr $cb>\n";
		if ($row{$i} && ($config{'add_mode'} || $has_blob)) {
			# Show multi-line row editor
			printf "<td colspan=%d>\n", scalar(@d);
			print "<table border>\n";
			print "<tr $tb> <td><b>$text{'view_field'}</b></td> ",
			      "<td><b>$text{'view_data'}</b></td> </tr>\n";
			for($j=0; $j<@str; $j++) {
				local $nm = "${i}_$str[$j]->{'field'}";
				print "<tr $cb> <td><b>$str[$j]->{'field'}</b></td>\n";
				$d[$j] = &html_escape($d[$j]);
				if ($str[$j]->{'type'} =~ /\((\d+)\)/) {
					local $nw = $1 > 70 ? 70 : $1;
					print "<td><input name=$nm size=$nw value=\"$d[$j]\"></td>\n";
					}
				elsif ($str[$j]->{'type'} =~ /(text|blob)$/) {
					print "<td><textarea name=$nm rows=5 cols=70>$d[$j]",
					      "</textarea></td>\n";
					}
				else {
					print "<td><input name=$nm size=30 value=\"$d[$j]\"></td>\n";
					}
				print "</tr>\n";
				}
			print "</table></td>\n";
			}
		elsif ($row{$i}) {
			# Show simple row-editor
			for($j=0; $j<@d; $j++) {
				$d[$j] = &html_escape($d[$j]);
				printf "<td width=$w%%><input name=${i}_$d->{'titles'}->[$j] size=$w value=\"$d[$j]\"></td>\n";
				}
			}
		else {
			# Show row contents
			print "<td><input type=checkbox name=row ",
			      "value=$i></td>\n" if ($check);
			foreach $c (@{$data[$i]}) {
				printf "<td width=$w%%>%s</td>\n",
					$c =~ /\S/ ? &html_escape($c) : "<br>";
				}
			}
		print "</tr>\n";
		}
	if ($in{'new'} && ($config{'add_mode'} || $has_blob)) {
		# Show new fields in longer format
		print "</table> <br> <table border>\n";
		print "<tr $tb> <td><b>$text{'view_field'}</b></td> ",
		      "<td><b>$text{'view_data'}</b></td> </tr>\n";
		for($j=0; $j<@str; $j++) {
			print "<tr $cb> <td><b>$str[$j]->{'field'}</b></td>\n";
			if ($str[$j]->{'type'} =~ /\((\d+)\)/) {
				local $nw = $1 > 70 ? 70 : $1;
				print "<td><input name=$j size=$nw></td>\n";
				}
			elsif ($str[$j]->{'type'} =~ /enum\((.*)\)/) {
				local @nc = map { /^'(.*)'$/ ? $1 : $_ }
						split(/,/, $1);
				print "<td><select name=$j>\n";
				foreach $nc (@nc) {
					print "<option>$nc\n";
					}
				print "</select></td>\n";
				}
			elsif ($str[$j]->{'type'} =~ /(text|blob)$/) {
				print "<td><textarea name=$j rows=5 cols=70>",
				      "</textarea></td>\n";
				}
			else {
				print "<td><input name=$j size=30></td>\n";
				}
			print "</tr>\n";
			}
		}
	elsif ($in{'new'}) {
		# Show new fields in a row below table
		print "<tr $cb>\n";
		for($j=0; $j<@str; $j++) {
			print "<td width=$w%><input name=$j size=$w></td>\n";
			}
		print "</tr>\n";
		}
	print "</table>\n";
	if ($check) {
		print "<a href='' onClick='document.forms[0].row.checked = true; for(i=0; i<document.forms[0].row.length; i++) { document.forms[0].row[i].checked = true; } return false'>$text{'view_all'}</a>&nbsp;\n";
		print "<a href='' onClick='document.forms[0].row.checked = !document.forms[0].row.checked; for(i=0; i<document.forms[0].row.length; i++) { document.forms[0].row[i].checked = !document.forms[0].row[i].checked; } return false'>$text{'view_invert'}</a><br>\n";
		}
	}
else {
	print "<b>$text{'view_none'}</b> <p>\n";
	}

print "<table width=100%><tr>\n";
if (!$keyed) {
	print "<tr> <td><b>$text{'view_nokey'}</b></td> </tr>\n";
	}
elsif (!$check) {
	if ($in{'new'}) {
		print "<td><input type=submit name=savenew ",
		      "value='$text{'save'}'></td>\n";
		}
	else {
		print "<td><input type=submit name=save ",
		      "value='$text{'save'}'></td>\n";
		}
	print "<td align=right><input type=submit name=cancel ",
	      "value='$text{'cancel'}'></td>\n";
	}
else {
	print "<td><input type=submit name=edit ",
	      "value='$text{'view_edit'}'></td>\n";
	print "<td align=middle><input type=submit name=new ",
	      "value='$text{'view_new'}'></td>\n";
	print "<td align=right><input type=submit name=delete ",
	      "value='$text{'view_delete'}'></td>\n";
	}
print "</tr></table></form>\n";

if (!$in{'field'} && $total > $config{'perpage'}) {
	print "<hr>\n";
	print "<table width=100%><tr>\n";
	print "<form action=view_table.cgi>\n";
	print "<input type=hidden name=search value=1>\n";
	print "<input type=hidden name=db value='$in{'db'}'>\n";
	print "<input type=hidden name=table value='$in{'table'}'>\n";
	$sel = "<select name=field>\n";
	foreach $f (@str) {
		$sel .= "<option>$f->{'field'}\n";
		}
	$sel .= "</select>";
	$match = "<select name=match>\n";
	$match .= "<option value=0 selected>$text{'view_match0'}\n";
	$match .= "<option value=1>$text{'view_match1'}\n";
	$match .= "<option value=2>$text{'view_match2'}\n";
	$match .= "<option value=3>$text{'view_match3'}\n";
	$match .= "</select>";
	print "<td>",&text('view_search2', "<input name=for size=20>", $sel,
			   $match);
	print "&nbsp;&nbsp;",
	      "<input type=submit value='$text{'view_searchok'}'></td>\n";
	print "</form>\n";

	print "<form action=view_table.cgi>\n";
	print "<input type=hidden name=db value='$in{'db'}'>\n";
	print "<input type=hidden name=table value='$in{'table'}'>\n";
	print "<td align=right><input type=submit value='$text{'view_jump'}'> ";
	print "<input name=jump size=6></td></form>\n";
	print "</tr> </table>\n";
	}

print "<hr>\n";
if ($access{'edonly'}) {
	&footer("edit_dbase.cgi?db=$in{'db'}",$text{'dbase_return'},
		"", $text{'index_return'});
	}
else {
	&footer("edit_table.cgi?db=$in{'db'}&table=$in{'table'}",
		$text{'table_return'},
		"edit_dbase.cgi?db=$in{'db'}", $text{'dbase_return'},
		"", $text{'index_return'});
	}

