home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
FAQ
/
cgi-bin
/
discus4_00
/
source
/
adm-dr.pl
< prev
next >
Wrap
Text File
|
2009-11-06
|
49KB
|
1,349 lines
# FILE: adm-dr.pl
# DESCRIPTION: Data Recovery Interfaces and functions
#-------------------------------------------------------------------------------
# DISCUS COPYRIGHT NOTICE
#
# Discus is copyright (c) 2002 by DiscusWare, LLC, all rights reserved.
# The use of Discus is governed by the Discus License Agreement which is
# available from the Discus WWW site at:
# http://www.discusware.com/discus/license
#
# Pursuant to the Discus License Agreement, this copyright notice may not be
# removed or altered in any way.
#-------------------------------------------------------------------------------
use strict;
use vars qw($GLOBAL_OPTIONS $DCONF $PARAMS);
###
### DR_admin
###
### Controls the Data Recovery utility
###
sub DR_admin {
my ($FORMref) = @_;
my $result = check_password($FORMref->{username}, undef, { type_required => 'moderator' }, $FORMref->{'COOKIE'});
bad_login( { bad_username => 1 } ) if scalar(@{ $result }) == 0;
bad_login( { superuser_required => 1 } ) if $result->[0]->{user} ne $DCONF->{superuser};
if ($FORMref->{action} eq "dr_tpc") {
topic_recovery($FORMref, $result);
$FORMref->{action} = "data_recovery";
}
if ($FORMref->{'action'} eq "dr_reindex") {
if ($DCONF->{pro} && $DCONF->{tree_as_sql} && $GLOBAL_OPTIONS->{database}) {
dreq("sql-trem-PRO");
return sql_reindex_main($FORMref, $result);
}
dreq("fcn-indx");
INDEXING_main({ menuaction => $FORMref->{menu}, position => "start", topic => $FORMref->{topic}, username => $result->[0]->{user} });
}
if ($FORMref->{'action'} eq "dr_indexing") {
dreq("fcn-indx");
INDEXING_main({ menuaction => $FORMref->{menu}, username => $result->[0]->{user}, position => "continue", tempfile => $FORMref->{tempfile}, counter => $FORMref->{counter} });
}
if ($FORMref->{'action'} eq "dr_sorting") {
dreq("fcn-indx");
INDEXING_main({ menuaction => $FORMref->{menu}, username => $result->[0]->{user}, position => "sort", counter => $FORMref->{counter} });
if ($FORMref->{menu} == 1) {
$FORMref->{spot} = 1;
page_recovery_master($FORMref, $result);
}
$FORMref->{action} = "data_recovery";
$FORMref->{menu} = 2;
}
if ($FORMref->{'action'} eq "dr_sindxfin") {
dreq("fcn-indx");
INDEXING_main({ username => $result->[0]->{user}, position => "search", counter => $FORMref->{counter} });
$FORMref->{action} = "data_recovery";
$FORMref->{menu} = 3;
}
if ($FORMref->{'action'} eq "data_recovery") {
my $subst = {};
$subst->{general}->{username} = $result->[0]->{user};
$subst->{general}->{menu} = defined $FORMref->{menu} ? $FORMref->{menu} : -1;
$subst->{general}->{url} = "$PARAMS->{cgiurl}?username=$result->[0]->{user}&action=data_recovery";
$subst->{topics} = board_topics(undef, undef, undef, 1, 1);
if ($FORMref->{menu} == 1) {
opendir(DIR, "$DCONF->{admin_dir}/backups");
my @d = grep { /^\d+MP\.TMP$/ } map { $_ } readdir(DIR);
closedir(DIR);
my @x = ();
foreach my $d (@d) {
$d =~ /^(\d+)MP\.TMP$/;
my $i = {};
$i->{file} = $1;
my $l = readfile("$DCONF->{admin_dir}/backups/$d", "DR_admin", { no_lock => 1, no_unlock => 1, zero_ok => 1 });
$i->{unmoved_count} = ref $l eq 'ARRAY' ? scalar @{$l} : 0;
$i->{date_started} = (stat "$DCONF->{admin_dir}/backups/$d")[9];
push @x, $i;
}
$subst->{movedpages} = \@x;
}
if ($FORMref->{menu} == 2 && $FORMref->{topic} != 0) {
$subst->{general}->{flag_reindex} = 0 + $FORMref->{topic};
}
if ($FORMref->{menu} == 5) {
for (my $i = 2; $i <= 10; $i++) {
my $x = join("", "status", $i);
$subst->{status}->{$x} = $GLOBAL_OPTIONS->{$x};
}
}
screen_out("dr_main", $subst);
}
if ($FORMref->{action} eq "dr_pgr") {
page_recovery_master($FORMref, $result);
}
if ($FORMref->{action} eq "dr_pgs") {
specific_page_recovery_master($FORMref, $result);
}
if ($FORMref->{action} eq "dr_log") {
log_recovery_master($FORMref, $result);
}
if ($FORMref->{action} eq "dr_thumb") {
dreq("dr_thumb-PRO");
thumbnail_recovery_master($FORMref, $result);
}
if ($FORMref->{action} eq "dr_profiles") {
dreq("dr_thumb-PRO");
profile_recovery_master($FORMref, $result);
}
if ($FORMref->{action} eq "dr_posts") {
dreq("dr_posts-PRO");
post_counter_master($FORMref, $result);
}
if ($FORMref->{action} eq "dr_enh") {
dreq("dr_posts-PRO");
enhanced_profile_cleaner($FORMref, $result);
}
if ($FORMref->{action} eq "dr_mvp") {
page_move_recovery_master($FORMref, $result);
}
if ($FORMref->{'action'} eq "dr_perm_reset") {
my $subst = {};
$subst->{topics} = postread_privilege_reset();
$subst->{general}->{username} = $result->[0]->{user};
$subst->{general}->{menu} = $FORMref->{menu};
$subst->{general}->{url} = "$PARAMS->{cgiurl}?username=$result->[0]->{user}&action=data_recovery";
screen_out("dr_main", $subst);
}
}
###
### topic_recovery
###
### Recovers the list of board topics and other information
###
sub topic_recovery {
my ($FORMref, $result) = @_;
dreq("topic-pg");
my $Q = undef;
my @topics = ();
my %t = undef;
my @added = ();
if ($FORMref->{topic_rec_type} == 2) {
$Q = read_topic_page();
@topics = @{ $Q->{topics} };
%t = map { $_->{number}, 1 } @topics;
}
my @d = @{ directory_list($DCONF->{message_dir}, '/\d+$', 0) };
push @d, @{ directory_list($DCONF->{secdir}, '/\d+$', 0) } if $DCONF->{pro};
foreach my $d (@d) {
if ($d =~ m|/(\d+)$|) {
next if ! -e "$d/$1.$DCONF->{ext}";
next if $t{$1};
push @topics, { number => $1, type => 1 };
push @added, $1;
}
}
$Q->{topics} = \@topics;
write_topic_page($Q);
if (scalar(@added)) {
dreq("fcn-indx");
INDEXING_main({ menuaction => 2, position => "start", topic => join(",", @added), username => $result->[0]->{user} });
}
}
###
### log_recovery_master
###
### Operates the log recovery system
###
sub log_recovery_master {
my ($FORMref, $result) = @_;
my $subst = {};
$subst->{general}->{username} = $result->[0]->{user};
$FORMref->{tempfile} =~ s/[^\w\-]//g;
$FORMref->{action} = "dr_log";
$subst->{general}->{tempfile} = $FORMref->{tempfile};
log_recovery_0($FORMref, $subst) if $FORMref->{spot} == 0;
log_recovery_1($FORMref, $subst) if $FORMref->{spot} == 1;
log_recovery_2($FORMref, $subst) if $FORMref->{spot} == 2;
log_recovery_3($FORMref, $subst) if $FORMref->{spot} == 3;
log_recovery_4($FORMref, $subst) if $FORMref->{spot} == 4;
$subst->{general}->{menu} = 5;
$subst->{general}->{url} = "$PARAMS->{cgiurl}?username=$result->[0]->{user}&action=data_recovery";
$subst->{topics} = board_topics();
screen_out("dr_main", $subst);
}
###
### log_recovery_0
###
### Build file lists
###
sub log_recovery_0 {
my ($FORMref, $subst) = @_;
dreq("fcn-regn");
my $X = incremental({ operation => 'build', suffix => 'logr' });
$subst->{general}->{tempfile} = $X->{tempfile};
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$X->{tempfile}&spot=1&done=0&total=$X->{count}";
$subst->{'gauge'}->{'operation'} = 16;
$subst->{'gauge'}->{'description'} = 1601;
$subst->{'gauge'}->{'percent'} = 0;
screen_out("gauge", $subst);
}
###
### log_recovery_1
###
### Build all posts into a summary file
###
sub log_recovery_1 {
my ($FORMref, $subst) = @_;
dreq("fcn-regn");
my $i = incremental({ tempfile => $FORMref->{tempfile}, operation => "read" });
my $R = regeneration_resource_init();
my $out = join("/", $DCONF->{admin_dir}, "backups", "$FORMref->{tempfile}OUT");
my $old_topic = 0;
my $preview_storage = defined $DCONF->{log_preview_length} ? $DCONF->{log_preview_length} : 25;
lock("*");
while (my $f = shift @{ $i->{data} }) {
chomp $f;
my ($topic, $page) = ($f =~ m|^(\d+)/(\d+)|);
if ($old_topic == 0) {
open (OUT, ">> $out-$topic.TMP");
$old_topic = $topic;
} elsif ($topic != $old_topic) {
unshift @{ $i->{data} }, "$f\n";
last;
}
my $pinfo = GetPage($topic, $page, { no_error => 1 });
next if $pinfo->{head}->{me_number} != $page;
next if ref $pinfo->{messages} ne 'ARRAY';
next if scalar @{ $pinfo->{messages} } == 0;
foreach my $message (@{ $pinfo->{messages} }) {
my $firstfew = escape(substr(remove_html($message->{text}), 0, $preview_storage));
my $postby = escape($message->{author});
my $uid = $message->{email} =~ m|profile=(.*?)-(\w+)| ? join(":", $1, $2) : "";
print OUT join("\t", $topic, $page, $message->{number}, $message->{'time'}, $uid, $postby, "$firstfew\n");
}
$R = regeneration_resource_estimate($R, 1, $pinfo->{general}->{'length'});
$FORMref->{done}++;
last if regeneration_reset_trigger($R);
}
unlock("*");
close (OUT);
my $iw = incremental({ operation => 3, data => $i->{data}, tempfile => $FORMref->{tempfile} });
if ($iw->{'continue'}) {
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$FORMref->{tempfile}&spot=1&done=$FORMref->{done}&total=$FORMref->{total}";
$subst->{'gauge'}->{'operation'} = 16;
$subst->{'gauge'}->{'description'} = 1602;
$subst->{'gauge'}->{'percent'} = $FORMref->{total} > 0 ? (int(100*$FORMref->{done}/$FORMref->{total})) : 0;
screen_out("gauge", $subst);
}
unlink "$DCONF->{admin_dir}/backups/$FORMref->{tempfile}.TMP";
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$FORMref->{tempfile}&spot=2";
$subst->{'gauge'}->{'operation'} = 16;
$subst->{'gauge'}->{'description'} = 1603;
$subst->{'gauge'}->{'percent'} = 0;
screen_out("gauge", $subst);
}
###
### log_recovery_2
###
### Compare existing posts to logs
###
sub log_recovery_2 {
my ($FORMref, $subst) = @_;
opendir(DIR, "$DCONF->{admin_dir}/backups");
my @u = grep { /^$FORMref->{tempfile}OUT-(\d+)\.TMP$/ } readdir(DIR);
closedir(DIR);
$FORMref->{total} = scalar(@u) if ! $FORMref->{total};
if ($u[0] ne "") {
if ($DCONF->{pro} && $GLOBAL_OPTIONS->{database}) {
dreq("sql-logr-PRO");
sql_log_recovery_2($FORMref, $subst, $u[0]);
} else {
dreq("fcn-logs");
my $inlog = {};
my $repair = {};
my $postchars = {};
my $topic_save = 0;
open (FILEU, "< $DCONF->{admin_dir}/backups/$u[0]");
while (my $z = <FILEU>) {
chomp $z;
my ($topic, $page, $postnum, $posttime, $uid, $author, $chars) = split(/\t/, $z);
if ($postnum > 0) {
$topic_save = $topic;
if (! scalar keys %{$inlog}) {
$inlog->{fileread} = 1;
open (LOG, "< $DCONF->{admin_dir}/msg_index/$topic-log.txt");
while (my $j = <LOG>) {
my ($post, $who, $when, $where, $ip, $host, $chars, $author) = split(/;/, $j, 8);
$inlog->{post}->{$post} = 1;
$postchars->{$post} = $chars;
}
close (LOG);
}
if ($inlog->{post}->{$postnum} && ! $inlog->{done}->{$postnum}) {
$inlog->{done}->{$postnum} = 1;
if ($postchars->{$postnum} ne $chars) {
$repair->{$postnum}->{type} = "fix";
$repair->{$postnum}->{postindex} = $postnum;
$repair->{$postnum}->{topic} = $topic;
$repair->{$postnum}->{page} = $page;
$repair->{$postnum}->{firstchars} = $chars;
}
} elsif ($inlog->{post}->{$postnum} && $inlog->{done}->{$postnum}) {
dreq("posting");
my $m = get_postindex();
$repair->{$postnum}->{type} = "change";
$repair->{$postnum}->{postindex} = $m;
$repair->{$postnum}->{topic} = $topic;
$repair->{$postnum}->{page} = $page;
$repair->{$postnum}->{firstchars} = $chars;
} else {
$repair->{$postnum}->{type} = "add";
$repair->{$postnum}->{where} = join("/", $topic, $page);
$repair->{$postnum}->{'time'} = $posttime;
$repair->{$postnum}->{'username'} = $uid;
$repair->{$postnum}->{'remote_addr'} = "";
$repair->{$postnum}->{'remote_host'} = "";
$repair->{$postnum}->{'firstchars'} = $chars;
$repair->{$postnum}->{'poststr'} = $author;
$repair->{$postnum}->{'postindex'} = $postnum;
}
$inlog->{done}->{$postnum} = 1;
}
}
close (FILEU);
foreach my $x (keys %{$inlog->{post}}) {
$repair->{$x}->{type} = "delete" if ! $inlog->{done}->{$x};
}
unlink "$DCONF->{admin_dir}/msg_index/$topic_save-log.out";
if (scalar keys %{$repair}) {
my $dp = {};
my $seen = {};
my $size = 0;
open (LOG_IN, "< $DCONF->{admin_dir}/msg_index/$topic_save-log.txt");
open (LOG_OUT, "> $DCONF->{admin_dir}/msg_index/$topic_save-log.out");
while (<LOG_IN>) {
my ($x) = split(/;/, $_, 2);
if (ref $repair->{$x} ne 'HASH' || $repair->{$x} eq "") {
$size += length($_);
print LOG_OUT $_;
next;
}
if ($repair->{$x}->{type} eq "fix") {
my $hh = log_line_to_hash($_);
$hh->{postindex} = $repair->{$x}->{postindex};
$hh->{firstchars} = $repair->{$x}->{firstchars} if defined $repair->{$x}->{firstchars};
my $line = log_hash_to_line($hh);
print LOG_OUT $line;
$size += length($line);
}
if ($repair->{$x}->{type} eq "change") {
if (! $seen->{$x}) {
$seen->{$x} = 1;
print LOG_OUT $_;
$size += length($_);
next;
}
my $hh = log_line_to_hash($_);
$hh->{postindex} = $repair->{$x}->{postindex};
$hh->{firstchars} = $repair->{$x}->{firstchars} if defined $repair->{$x}->{firstchars};
my $line = log_hash_to_line($hh);
print LOG_OUT $line;
$size += length($line);
next if $dp->{$repair->{$x}->{page}};
$dp->{$repair->{$x}->{page}} = 1;
my $p = GetPage($repair->{$x}->{topic}, $repair->{$x}->{page});
foreach my $m (@{ $p->{messages} }) {
if (defined $repair->{$m->{number}}->{postindex}) {
$m->{number} = $repair->{$m->{number}}->{postindex};
}
}
SetPage($p);
}
}
foreach my $x (keys %{$repair}) {
next if $repair->{$x}->{type} ne "add";
my $line = log_hash_to_line($repair->{$x});
print LOG_OUT $line;
$size += length($line);
}
close (LOG_IN);
close (LOG_OUT);
rename_file("$DCONF->{admin_dir}/msg_index/$topic_save-log.out", $size, "$DCONF->{admin_dir}/msg_index/$topic_save-log.txt");
}
}
unlink "$DCONF->{admin_dir}/backups/$u[0]";
$FORMref->{done}++;
}
if ($u[0] ne "" && $u[1] ne "") {
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$FORMref->{tempfile}&spot=2&done=$FORMref->{done}&total=$FORMref->{total}";
$subst->{'gauge'}->{'operation'} = 16;
$subst->{'gauge'}->{'description'} = 1603;
$subst->{'gauge'}->{'percent'} = $FORMref->{total} > 0 ? (int(100*$FORMref->{done}/$FORMref->{total})) : 0;
screen_out("gauge", $subst);
}
if ($DCONF->{pro} && $GLOBAL_OPTIONS->{database}) {
return 0;
}
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$FORMref->{tempfile}&spot=3";
$subst->{'gauge'}->{'operation'} = 16;
$subst->{'gauge'}->{'description'} = 1604;
$subst->{'gauge'}->{'percent'} = 0;
screen_out("gauge", $subst);
}
###
### log_recovery_3
###
### Mini-log maintenance/recovery
###
sub log_recovery_3 {
my ($FORMref, $subst, $kick) = @_;
my $M = board_topics();
return if ref $M ne 'ARRAY';
my @t = grep { $_->{type} == 1 } @{$M};
return if scalar @t == 0;
my $tmp = join("", $$, time, "MINI");
$tmp = $FORMref->{tempfile} if defined $FORMref->{tempfile};
$tmp =~ s/\W//g;
open (TF, "> $DCONF->{admin_dir}/backups/$tmp.TMP");
print TF map { join("", $_->{number}, "\n") } @t;
close (TF);
my $ttl = scalar(@t);
return $ttl if $kick;
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$tmp&spot=4&total=$ttl";
$subst->{'gauge'}->{'operation'} = 16;
$subst->{'gauge'}->{'description'} = 1605;
$subst->{'gauge'}->{'percent'} = 0;
screen_out("gauge", $subst);
}
###
### log_recovery_4
###
### Mini-log maintenance/recovery action
###
sub log_recovery_4 {
my ($FORMref, $subst, $kick, $from_upgrade) = @_;
my $z = readfile("$DCONF->{admin_dir}/backups/$FORMref->{tempfile}.TMP", "log_recovery_4", { zero_ok => 1, no_lock => 1, no_unlock => 1 });
if (ref $z eq 'ARRAY' && scalar @{$z}) {
my $i = shift @{$z};
dreq("fcn-logs");
chomp $i;
create_minilog($i);
$FORMref->{done}++;
}
if (ref $z ne 'ARRAY' || scalar @{$z} == 0) {
unlink "$DCONF->{admin_dir}/backups/$FORMref->{tempfile}.TMP";
return (1, 1) if $from_upgrade;
return undef;
}
writefile("$DCONF->{admin_dir}/backups/$FORMref->{tempfile}.TMP", $z, "log_recovery_4", { zero_ok => 1, no_lock => 1, no_unlock => 1 });
return ($FORMref->{done}, 0) if $from_upgrade;
return $FORMref->{done} if $kick;
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$FORMref->{tempfile}&total=$FORMref->{total}&done=$FORMref->{done}&spot=4";
$subst->{'gauge'}->{'operation'} = 16;
$subst->{'gauge'}->{'description'} = 1605;
$subst->{'gauge'}->{'percent'} = $FORMref->{total} > 0 ? (int(100*$FORMref->{done}/$FORMref->{total})) : 0;
screen_out("gauge", $subst);
}
###
### specific_page_recovery_master
###
### Operates the specific page recovery system
###
sub specific_page_recovery_master {
my ($FORMref, $result) = @_;
my $subst = {};
$subst->{general}->{username} = $result->[0]->{user};
$FORMref->{tempfile} =~ s/\D//g;
$FORMref->{action} = "dr_pgs";
specific_page_recovery_0($FORMref, $subst) if $FORMref->{spot} == 0;
specific_page_recovery_1($FORMref, $subst) if $FORMref->{spot} == 1;
specific_page_recovery_2($FORMref, $subst) if $FORMref->{spot} == 2;
error_message("Undefined Error", "Contact DiscusWare support, code 'specific_page_recovery_master'", 0, 1);
}
###
### page_recovery_master
###
### Operates the page recovery system
###
sub page_recovery_master {
my ($FORMref, $result) = @_;
my $subst = {};
$subst->{general}->{username} = $result->[0]->{user};
$FORMref->{tempfile} =~ s/\D//g;
$FORMref->{action} = "dr_pgr";
page_recovery_0($FORMref, $subst) if $FORMref->{spot} == 0;
page_recovery_1($FORMref, $subst) if $FORMref->{spot} == 1;
page_recovery_2($FORMref, $subst) if $FORMref->{spot} == 2;
page_recovery_3($FORMref, $subst) if $FORMref->{spot} == 3;
page_recovery_4($FORMref, $subst) if $FORMref->{spot} == 4;
page_recovery_5($FORMref, $subst) if $FORMref->{spot} == 5;
page_recovery_6($FORMref, $subst) if $FORMref->{spot} == 6;
page_recovery_7($FORMref, $subst) if $FORMref->{spot} == 7;
$subst->{general}->{menu} = 0;
$subst->{general}->{url} = "$PARAMS->{cgiurl}?username=$result->[0]->{user}&action=data_recovery";
$subst->{topics} = board_topics();
screen_out("dr_main", $subst);
}
###
### page_move_recovery_master
###
### Continues a page move recovery operation
###
sub page_move_recovery_master {
my ($FORMref, $result) = @_;
my $subst = {};
$subst->{general}->{username} = $result->[0]->{user};
$FORMref->{tempfile} =~ s/\D//g;
if (-e "$DCONF->{admin_dir}/backups/$FORMref->{tempfile}MP.TMP") {
my $chgfile = "";
my $L = readfile("$DCONF->{admin_dir}/backups/$FORMref->{tempfile}MP.TMP", "page_move_recovery_master", { no_lock => 1, no_unlock => 1, zero_ok => 1 });
my $P = substr($FORMref->{tempfile}, 0, 12);
opendir(DIR, "$DCONF->{admin_dir}/backups");
my @d = grep { /^CHG$P\d+\.TMP$/ } map { $_ } readdir(DIR);
if (scalar @d != 1) {
error_message("Data Recovery Error", "Could not find change file (1)", 0, 1);
}
$chgfile = $` if $d[0] =~ /\W/;
if ($chgfile eq "") {
error_message("Data Recovery Error", "Could not find change file (2)", 0, 1);
}
dreq("fcn-regn");
regenerate_board({ esc => 0, operation => 6, description => 601, tempfile => "$FORMref->{tempfile}MP", done => 0, total => scalar(@{$L}), action => "regen7", username => $result->[0]->{user}, changefile => $chgfile });
}
$subst->{general}->{menu} = 0;
$subst->{general}->{url} = "$PARAMS->{cgiurl}?username=$result->[0]->{user}&action=data_recovery";
$subst->{topics} = board_topics();
screen_out("dr_main", $subst);
}
###
### page_recovery_0
###
### Handles first input to initiate process
###
sub page_recovery_0 {
my ($FORMref, $subst) = @_;
if ($FORMref->{maint}) {
dreq("adm-opts");
$GLOBAL_OPTIONS = options_save({ maintenance => 1 });
}
if ($FORMref->{reindex}) {
dreq("fcn-indx");
my $bt = board_topics();
my %h = map {$_->{number}, 1} grep($_->{type}==1,@{$bt});
INDEXING_main({ topic => \%h, menuaction => 1, position => "start", username => $subst->{general}->{username} });
}
page_recovery_1($FORMref, $subst);
}
###
### specific_page_recovery_0
###
### Initialize temporary files
###
sub specific_page_recovery_0 {
my ($FORMref, $subst) = @_;
my $tcache = time;
my $topic = $FORMref->{topic}; $topic =~ s/\D//g;
my $path = get_message_path($topic);
error_message("Invalid Topic", "Selected topic number is not valid", 0, 1) if ! -e $path;
my $tfname = join("", $$, substr($tcache, length($tcache)-5, 5), substr($ENV{REMOTE_ADDR}, length($ENV{REMOTE_ADDR})-8, 8));
$tfname =~ s/\D//g;
dreq("fcn-regn");
my $filelist = incremental({ tempfile => $tfname, operation => 1, topic => $topic });
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&topic=$topic&page=$FORMref->{page}&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$filelist->{tempfile}&spot=1&done=0&total=$filelist->{count}";
$subst->{'gauge'}->{'operation'} = 9;
$subst->{'gauge'}->{'description'} = 950;
$subst->{'gauge'}->{'percent'} = 0;
screen_out("gauge", $subst);
}
###
### specific_page_recovery_1
###
### Analyze files to see if they are children of the selected page or not
###
sub specific_page_recovery_1 {
my ($FORMref, $subst) = @_;
my $done = $FORMref->{done};
dreq("fcn-regn");
my $tempfile = incremental({ operation => "read", tempfile => $FORMref->{tempfile} });
my $R = regeneration_resource_init();
open (TFOUT, ">> $DCONF->{admin_dir}/backups/$FORMref->{tempfile}-RES.TMP");
while (my $f = shift @{ $tempfile->{data} }) {
chomp $f;
my ($topic, $page) = ($f =~ m|^(\d+)/(\d+)|);
$done += 1;
next if $page == $FORMref->{page};
next if $topic == $page;
my $K = GetPage($topic, $page);
if ($K->{head}->{parent} == $FORMref->{page}) {
print TFOUT "$page\n";
}
$R = regeneration_resource_estimate($R, 1, $K->{general}->{length});
last if regeneration_reset_trigger($R);
}
close (TFOUT);
if (ref $tempfile->{data} eq 'ARRAY' && scalar @{ $tempfile->{data} } > 0) {
incremental({ operation => 3, data => $tempfile->{data}, tempfile => $FORMref->{tempfile} });
$FORMref->{done} = $done;
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&topic=$FORMref->{topic}&page=$FORMref->{page}&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$FORMref->{tempfile}&spot=1&done=$done&total=$FORMref->{total}";
$subst->{'gauge'}->{'operation'} = 9;
$subst->{'gauge'}->{'description'} = 951;
$subst->{'gauge'}->{'percent'} = $FORMref->{total} == 0 ? 0 : int(100 * $FORMref->{done} / $FORMref->{total});
screen_out("gauge", $subst);
} else {
unlink "$DCONF->{admin_dir}/backups/$FORMref->{tempfile}.TMP";
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&topic=$FORMref->{topic}&page=$FORMref->{page}&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$FORMref->{tempfile}&spot=2";
$subst->{'gauge'}->{'operation'} = 9;
$subst->{'gauge'}->{'description'} = 952;
$subst->{'gauge'}->{'percent'} = 0;
screen_out("gauge", $subst);
}
}
###
### specific_page_recovery_2
###
### Analyze a certain page and put the links back onto that page if needed
###
sub specific_page_recovery_2 {
my ($FORMref, $subst) = @_;
my $K = readfile("$DCONF->{admin_dir}/backups/$FORMref->{tempfile}-RES.TMP", "specific_page_recovery_2", { zero_ok => 1, no_lock => 1, no_unlock => 1 });
unlink "$DCONF->{admin_dir}/backups/$FORMref->{tempfile}-RES.TMP";
my $L = GetPage($FORMref->{topic}, $FORMref->{page}, { zero_ok => 1, lock => 1, no_error => 1 });
my %z1 = map { $_->{number}, 1 } grep { $_->{islink} == 0 } @{$L->{sublist}};
my %z2 = map { chomp; $_, 1 } grep { /^\d+/ } @{$K};
my %z3 = map { $_, 1 } grep { $z1{$_} != 1 } keys %z2;
my %z4 = map { $_, 1 } grep { $z2{$_} != 1 } keys %z1;
if (! scalar keys %z3 && ! scalar keys %z4) {
my ($topic, $page) = (0 + $FORMref->{topic}, 0 + $FORMref->{page});
$subst->{general}->{change} = 0;
my $q = get_message_path($topic);
my $filename = join("/", $q, "$page.$DCONF->{ext}");
unlock("$filename");
} else {
if (! $L->{head}->{topic_number}) {
$L->{head}->{topic_number} = 0 + $FORMref->{topic};
$L->{head}->{me_number} = 0 + $FORMref->{page};
$L->{sublist} = [];
$L->{head}->{param} = "Sublist";
$L->{head}->{me_name} = "Recovered Page";
}
my @x = @{expand_sublist($L->{sublist}, $L->{head}->{topic_number})};
@x = grep { $z4{$_->{number}} == 0 } @x;
foreach my $q (keys %z3) {
push @x, { type => 0, number => $q, name => 'Recovered', icon => 'tree_k' };
}
$L->{sublist} = \@x;
$L->{general}->{subtopic_raw} = 0;
SetPage($L, { unlock => 1 });
$subst->{general}->{count} = 0 + scalar @{$K};
$subst->{general}->{change} = 1;
$subst->{general}->{removed} = scalar keys %z4;
$subst->{general}->{added} = scalar keys %z3;
$subst->{general}->{topic} = $FORMref->{topic};
}
$subst->{general}->{menu} = 100;
$subst->{general}->{username} = $FORMref->{username};
$subst->{general}->{url} = "$PARAMS->{cgiurl}?username=$FORMref->{username}&action=data_recovery";
screen_out("dr_main", $subst);
}
###
### page_recovery_1
###
### Initialize temporary files
###
sub page_recovery_1 {
my ($FORMref, $subst) = @_;
my $tcache = time;
my $tfname = join("", $$, substr($tcache, length($tcache)-5, 5), substr($ENV{REMOTE_ADDR}, length($ENV{REMOTE_ADDR})-8, 8));
$tfname =~ s/\D//g;
my $budir = join("/", $DCONF->{admin_dir}, "backups");
dreq("fcn-regn");
my $bt = board_topics();
my %h = map {$_->{number}, 1} grep($_->{type}==1,@{$bt});
foreach my $T (keys(%h)) {
touch_createfile("$budir/$tfname-$T.TMP") || error_message("Page Recovery Error", "Could not create temporary file!");
}
my $filelist = incremental( { tempfile => $tfname, topic => \%h, operation => "build"} );
writefile("$budir/$tfname-C2.TMP", $filelist->{data}, "page_recovery_1", { no_lock => 1, no_unlock => 1, create => 1 });
writefile("$budir/$tfname-FP.TMP", $filelist->{data}, "page_recovery_1", { no_lock => 1, no_unlock => 1, create => 1 });
writefile("$budir/$tfname-FL.TMP", $filelist->{data}, "page_recovery_1", { no_lock => 1, no_unlock => 1, create => 1 });
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$filelist->{tempfile}&spot=2&done=0&total=$filelist->{count}";
$subst->{'gauge'}->{'operation'} = 9;
$subst->{'gauge'}->{'description'} = 901;
$subst->{'gauge'}->{'percent'} = 0;
screen_out("gauge", $subst);
}
###
### page_recovery_2
###
### Check to see if pages link to themselves, parents, etc.
###
sub page_recovery_2 {
my ($FORMref, $subst) = @_;
dreq("fcn-regn");
my $tf = join("-", $FORMref->{tempfile}, "C2");
if (-e "$DCONF->{admin_dir}/backups/$tf.TMP") {
my $tempfile = incremental({ operation => "read", tempfile => $tf });
my $R = regeneration_resource_init();
lock("*");
my @d = ();
my $done = $FORMref->{done};
while (my $f = shift @{ $tempfile->{data} }) {
chomp $f;
my ($topic, $page) = ($f =~ m|^(\d+)/(\d+)|);
my $K = GetPage($topic, $page);
push @d, join("", join("\t", $topic, $page, join(",", map {$_->{number}} grep($_->{islink} == 0, @{$K->{sublist}}))), "\n");
$R = regeneration_resource_estimate($R, 1, 3 * $K->{general}->{length});
$done++;
last if regeneration_reset_trigger($R);
}
unlock("*");
appendfile("$DCONF->{admin_dir}/backups/$FORMref->{tempfile}-TD.TMP", \@d);
my $iw = incremental({ operation => 3, data => $tempfile->{data}, tempfile => $tf });
my $total = $FORMref->{total};
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$FORMref->{tempfile}&spot=2&done=$done&total=$total";
$subst->{'gauge'}->{'operation'} = 9;
$subst->{'gauge'}->{'description'} = 901;
$subst->{'gauge'}->{'percent'} = $total > 0 ? int(100 * $done / $total) : 0;
screen_out("gauge", $subst);
}
my $bt = board_topics();
my %h = map {$_->{number}, 1} grep($_->{type}==1,@{$bt});
my $Q = readfile("$DCONF->{admin_dir}/backups/$FORMref->{tempfile}-TD.TMP", "page_recovery_2", { no_lock => 1, no_unlock => 1, create => 1 });
unlink "$DCONF->{admin_dir}/backups/$FORMref->{tempfile}-TD.TMP";
my $S = {};
foreach my $line (@{$Q}) {
my ($topic, $page, $subs) = split(/\s+/, $line);
foreach my $s (split(/,/, $subs)) {
$S->{$topic}->{$page}->{$s}++;
}
}
my $seen = {}; my $err = {};
foreach my $t (keys %h) {
my ($sn, $er) = _page_recovery_2_dig($t, $t, -1, $S, $seen, $err);
hash_merge($seen, $sn);
hash_merge($err, $er);
}
if (scalar(keys(%{$err}))) {
my @k = ();
foreach my $t (keys(%{$err})) {
foreach my $p (keys(%{$err->{$t}})) {
my @q = ();
foreach my $k (keys(%{$err->{$t}->{$p}})) {
push @q, "$k" if $err->{$t}->{$p}->{$k} == 1;
}
push @k, join("", join("\t", $t, $p, join(",", @q), "\n"));
}
}
writefile("$DCONF->{admin_dir}/backups/$FORMref->{tempfile}-BL.TMP", \@k, "page_recovery_2", { create => 1, no_lock => 1, no_unlock => 1 });
my $sck = scalar(@k);
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$FORMref->{tempfile}&spot=3&done=0&total=$sck";
$subst->{'gauge'}->{'operation'} = 9;
$subst->{'gauge'}->{'description'} = 902;
$subst->{'gauge'}->{'percent'} = 0;
screen_out("gauge", $subst);
}
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$FORMref->{tempfile}&spot=4";
$subst->{'gauge'}->{'operation'} = 9;
$subst->{'gauge'}->{'description'} = 903;
$subst->{'gauge'}->{'percent'} = 0;
screen_out("gauge", $subst);
}
sub _page_recovery_2_dig {
my ($topic, $page, $par, $S, $seen, $err) = @_;
$seen->{$topic}->{$page} = $par;
foreach my $Z (keys %{$S->{$topic}->{$page}}) {
if ($S->{$topic}->{$page}->{$Z} > 1) {
$err->{$topic}->{$page}->{$Z} = 2;
} elsif ($seen->{$topic}->{$Z} != 0) {
$err->{$topic}->{$page}->{$Z} = 1;
} else {
($seen, $err) = _page_recovery_2_dig($topic, $Z, $page, $S, $seen, $err);
}
}
return ($seen, $err);
}
###
### page_recovery_3
###
### Kills bad links (to page itself or to parents or multiple links) within pages
###
sub page_recovery_3 {
my ($FORMref, $subst) = @_;
my $bldf = readfile("$DCONF->{admin_dir}/backups/$FORMref->{tempfile}-BL.TMP", "page_recovery_3", { no_lock => 1, no_unlock => 1 });
my $k = shift @{$bldf};
my ($topic, $page, $links) = split(/\s+/, $k);
my $GF = GetPage($topic, $page, { lock => 1 });
my @u = split(/\n/, $GF->{sublist_raw});
my %l = map { $_, 1 } split(/,/, $links);
my @n = ();
my $flag = 0;
foreach my $q (@u) {
if ($q =~ /^<!--Top: (\d+)-->(.*)/) {
my $num = $1;
$flag = 0;
if ($l{$num}) {
my $t = $2;
$flag = 1 if $t =~ /^\s*$/;
} else {
push @n, $q;
$l{$num} = 1;
}
} elsif ($q =~ m|<!--/Top-->|) {
push @n, $q if ! $flag;
$flag = 0;
} elsif ($q =~ m|<!--URL: (\d+)-->|) {
push @n, $q;
$flag = 0;
} elsif ($q =~ /\S/) {
push @n, $q;
}
}
$GF->{sublist_raw} = join("\n", @n); $GF->{sublist_raw} .= "\n";
SetPage($GF, { unlock => 1 });
if (scalar(@{$bldf}) == 0) {
unlink "$DCONF->{admin_dir}/backups/$FORMref->{tempfile}-BL.TMP";
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$FORMref->{tempfile}&spot=4";
$subst->{'gauge'}->{'operation'} = 9;
$subst->{'gauge'}->{'description'} = 902;
$subst->{'gauge'}->{'percent'} = 100;
screen_out("gauge", $subst);
}
writefile("$DCONF->{admin_dir}/backups/$FORMref->{tempfile}-BL.TMP", $bldf, "page_recovery_3", { no_lock => 1, no_unlock => 1 });
$FORMref->{done}++;
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$FORMref->{tempfile}&spot=3&total=$FORMref->{total}&done=$FORMref->{done}";
$subst->{'gauge'}->{'operation'} = 9;
$subst->{'gauge'}->{'description'} = 902;
$subst->{'gauge'}->{'percent'} = $FORMref->{total} == 0 ? 0 : int(100 * $FORMref->{done} / $FORMref->{total});
screen_out("gauge", $subst);
}
###
### page_recovery_4
###
### Check for duplicates in file list
###
sub page_recovery_4 {
my ($FORMref, $subst) = @_;
dreq("fcn-regn");
my $tempfile = incremental({ operation => "read", tempfile => $FORMref->{tempfile} });
my $budir = join("/", $DCONF->{admin_dir}, "backups");
my $dupe = {};
foreach my $entry (@{$tempfile->{data}}) {
if ($entry =~ /^(\d+)\/(\d+)\./) {
my ($topic, $page) = ($1, $2);
push @{ $dupe->{$page} }, $topic;
}
}
my @Z = grep { scalar(@{ $dupe->{$_} }) > 1 } keys(%{$dupe});
if (scalar(@Z) == 0) {
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$FORMref->{tempfile}&spot=6";
$subst->{'gauge'}->{'operation'} = 9;
$subst->{'gauge'}->{'description'} = 903;
$subst->{'gauge'}->{'percent'} = 100;
screen_out("gauge", $subst);
}
touch_createfile("$budir/$FORMref->{tempfile}-DUPE.TMP") || error_message("Page Recovery Error", "Could not create temporary file!");
my @d = ();
foreach my $z (@Z) {
push @d, join("", join("\t", $z, join(",", @{$dupe->{$z}})), "\n");
}
appendfile("$budir/$FORMref->{tempfile}-DUPE.TMP", \@d, "page_recovery_2", { no_lock => 1, no_unlock => 1 });
my $td = scalar(@d);
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$FORMref->{tempfile}&spot=5&total=$td";
$subst->{'gauge'}->{'operation'} = 9;
$subst->{'gauge'}->{'description'} = 904;
$subst->{'gauge'}->{'percent'} = 0;
screen_out("gauge", $subst);
}
###
### page_recovery_5
###
### Fix all duplicates in file list by removing unwanted files
###
sub page_recovery_5 {
my ($FORMref, $subst) = @_;
my $dupefile = readfile("$DCONF->{admin_dir}/backups/$FORMref->{tempfile}-DUPE.TMP", "page_recovery_3", { no_lock => 1, no_unlock => 1 });
my $U = shift @{$dupefile} or return page_recovery_6($FORMref, $subst);
my ($pagenum, $topics, $pass) = split(/\s+/, $U);
my @T = split(/,/, $topics);
my $pgref = {};
foreach my $topic (@T) {
$pgref->{$topic} = GetPage($topic, $pagenum, { no_error => 1 });
}
my $R = _page_recovery_5($pgref, \@T, $pagenum, $pass);
if (ref $R eq 'HASH') {
my $topic = (keys(%{$R}))[0];
foreach my $TN (@T) {
next if $TN == $topic;
my $tdir = get_message_path($TN);
my $Z = $R->{$topic};
unlink "$tdir/$pagenum.$DCONF->{ext}";
my $pnt = GetPage($TN, $Z->{head}->{parent}, { no_error => 1 });
if ($pnt->{head}->{topic_number} == $TN) {
my @u = split(/\n/, $pnt->{sublist_raw});
my @n = ();
my $flag = 0;
foreach my $q (@u) {
if ($q =~ /^<!--Top: (\d+)-->(.*)/) {
my ($o, $t) = ($1, $2);
if ($o == $pagenum) {
$flag = 1 if $t =~ /^\s*$/;
next;
}
push @n, $q;
} elsif ($q =~ m%<!--/Top-->%) {
push @n, $q if $flag == 0;
$flag = 0;
} elsif ($q =~ /\S/ && $flag != 0) {
push @n, $q;
}
}
$pnt->{sublist_raw} = join("\n", @n); $pnt->{sublist_raw} .= "\n";
SetPage($pnt, { });
}
}
if (scalar(@{$dupefile}) == 0) {
unlink "$DCONF->{admin_dir}/backups/$FORMref->{tempfile}-DUPE.TMP";
return page_recovery_6($FORMref, $subst);
} else {
foreach my $q (@{$dupefile}) {
my ($pagenums, $topicsnum, $pass) = split(/\s+/, $q);
$q = join("", join("\t", $pagenums, $topicsnum), "\n");
log_error("adm-dr.pl", "page_recovery_5", "Note: duplicated file $pagenums in topics $topicsnum");
}
writefile("$DCONF->{admin_dir}/backups/$FORMref->{tempfile}-DUPE.TMP", $dupefile, "page_recovery_5");
$FORMref->{done}++;
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$FORMref->{tempfile}&spot=5&total=$FORMref->{total}&done=$FORMref->{done}";
$subst->{'gauge'}->{'operation'} = 9;
$subst->{'gauge'}->{'description'} = 904;
$subst->{'gauge'}->{'percent'} = $FORMref->{total} == 0 ? 0 : int(100 * $FORMref->{done} / $FORMref->{total});
screen_out("gauge", $subst);
}
} else {
push @{$dupefile}, join("", join("\t", $pagenum, $topics, 1 + $pass), "\n");
writefile("$DCONF->{admin_dir}/backups/$FORMref->{tempfile}-DUPE.TMP", $dupefile, "page_recovery_5");
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$FORMref->{tempfile}&spot=5&total=$FORMref->{total}&done=$FORMref->{done}";
$subst->{'gauge'}->{'operation'} = 9;
$subst->{'gauge'}->{'description'} = 904 + $pass;
$subst->{'gauge'}->{'percent'} = $FORMref->{total} == 0 ? 0 : int(100 * $FORMref->{done} / $FORMref->{total});
screen_out("gauge", $subst);
}
}
sub _page_recovery_5 {
my ($pgref, $topicref, $pagenum, $pass) = @_;
my %pg = %{$pgref}; my @T = @{$topicref};
# Zap corrupted files - those who do not know who they are
foreach my $topic (@T) {
if ($pg{$topic}->{head}->{me_number} != $pagenum) {
log_error("adm-dr.pl", "_page_recovery_5", "Note: $pagenum in $topic deleted due to corruption");
delete $pg{$topic};
}
}
return \%pg if scalar(keys(%pg)) <= 1;
# Zap topics that are in the wrong topic directory
foreach my $topic (@T) {
if (grep($_ == $pagenum, @T) && $pagenum != $topic) {
log_error("adm-dr.pl", "_page_recovery_5", "Note: $pagenum in $topic deleted due to wrong location");
delete $pg{$topic};
}
}
return \%pg if scalar(keys(%pg)) <= 1;
# Zap pages in the wrong topic directory, if one is in the right directory
my %rightdir = {};
foreach my $topic (@T) {
$rightdir{$topic} = 1 if $pg{$topic}->{head}->{topic_number} == $topic;
}
if (scalar(keys %rightdir) == 1) {
foreach my $topic (@T) {
if (! $rightdir{$topic}) {
log_error("adm-dr.pl", "_page_recovery_5", "Note: $pagenum in $topic deleted due to wrong location when one found in right location");
delete $pg{$topic};
}
}
return \%pg;
}
# Re-calculate the parent page from the headers & read parent pages
my %parents = {};
foreach my $topic (@T) {
my $self = $pg{$topic};
my @l = @{$self->{head}->{levels}};
my $parent = $self->{head}->{topic_number};
$parent = $l[scalar(@l)-1]->{level_number} if scalar(@l) > 1;
$self->{head}->{parent} = $parent;
$parents{$topic} = GetPage($topic, $parent, { no_error => 1 });
$pg{$topic} = $self;
}
# See how many of the parent pages exist -- if only 1 we're done
if (scalar(grep ( $parents{$_}->{head}->{me_number} > 0, keys %parents)) == 1) {
foreach my $topic (@T) {
if ($parents{$topic}->{head}->{me_number} <= 0) {
log_error("adm-dr.pl", "_page_recovery_5", "Note: $pagenum in $topic deleted due to only one parent remaining");
delete $pg{$topic};
}
}
return \%pg;
}
# SECOND PASS -- see if parents claim this page
if ($pass >= 1) {
my $claims = {};
foreach my $topic (@T) {
$claims->{$topic} = 1 if grep ( $_->{number} == $pagenum , @{$parents{$topic}->{sublist}});
}
if (scalar(keys %{$claims}) == 1) {
foreach my $topic (@T) {
if (! $claims->{$topic}) {
log_error("adm-dr.pl", "_page_recovery_5", "Note: $pagenum in $topic deleted due to no claims");
delete $pg{$topic};
}
}
return \%pg;
}
}
# THIRD PASS -- see if the content is different among the pages
if ($pass >= 2) {
my %content = {};
foreach my $topic (@T) {
my @q = map {$_->{number}} @{$pg{$topic}->{sublist}};
push @q, map {$_->{number}} @{$pg{$topic}->{messages}};
$content{$topic} = join("\t", @q);
}
my $same = 0;
foreach my $t1 (@T) {
foreach my $t2 (@T) {
$same++ if $content{$t1} == $content{$t2};
}
}
if ($same < scalar(@T)*scalar(@T) && $pass >= 2) {
my @O = sort {scalar(@{$pg{$a}->{sublist}}) <=> scalar(@{$pg{$b}->{sublist}}) } @T;
my @R = @T;
my $nt = pop @R;
foreach my $topic (@R) {
my $d = get_message_path($topic);
my $G = get_number();
my $P = GetPage($topic, $pagenum, { no_error => 1 });
$P->{head}->{me_number} = $G;
my @l = @{$P->{head}->{levels}};
my $parent = $P->{head}->{topic_number};
$parent = $l[scalar(@l)-2]->{level_number} if scalar(@l) > 2;
$P->{head}->{parent} = $parent;
$l[$#l]->{level_number} = $G if (scalar(@l) > 0);
$P->{head}->{levels} = \@l;
SetPage($P, { });
unlink "$d/$pagenum.$DCONF->{ext}";
unlock("$d/$pagenum.$DCONF->{ext}");
my $PAR = GetPage($topic, $parent, { no_error => 1 });
if ($PAR->{head}->{me_number} == $parent) {
$PAR->{general}->{subtopic_raw} = 1;
$PAR->{sublist_raw} =~ s/\/$topic\/$pagenum\.$DCONF->{ext}/\/$topic\/$G\.$DCONF->{ext}/g;
$PAR->{sublist_raw} =~ s/<!--Top: $pagenum-->/<!--Top: $G-->/g;
log_error("adm-dr.pl", "_page_recovery_5", "Note: $pagenum in $topic renumbered; is now $G [a]");
SetPage($PAR, { });
} else {
unlock("$d/$parent.$DCONF->{ext}");
}
# foreach my $pg (@{ $P->{sublist} }) {
# _page_recovery_5_renum($topic, $pg->{number}, scalar(@l), $G, 1, {$parent => 1, $G => 1, $pagenum => 1});
# }
delete $pg{$topic};
}
return \%pg;
}
}
# FOURTH PASS -- see if these appear in their respective tree files
if ($pass >= 3) {
my %ait = {};
O1: foreach my $topic (@T) {
my $l = read_tree($topic);
O2: foreach my $q (@{$l}) {
if ($q->{page} == $pagenum) {
$ait{$topic} = 1;
last O2;
}
}
}
if (scalar(keys %ait) == 1) {
foreach my $topic (@T) {
delete $pg{$topic} if ! $ait{$topic};
}
return \%pg;
}
}
# FIFTH PASS -- duplicated pages -- essentially random selection
if ($pass >= 4) {
delete $pg{(keys %pg)[0]} while scalar(keys(%pg)) > 1;
return \%pg;
}
return undef;
}
sub _page_recovery_5_renum {
my ($topic, $page, $level, $new_num, $flag, $done) = @_;
my $GP = GetPage($topic, $page, { no_error => 1 });
if ($GP->{head}->{me_number} == $page) {
$new_num = get_number();
$GP->{head}->{levels}->[$level]->{level_number} = $new_num;
$GP->{head}->{parent} = $new_num if $flag;
SetPage($GP);
$done->{$page} = 1;
log_error("adm-dr.pl", "_page_recovery_5_renum", "Note: $page in $topic renumbered; is now $new_num [b]");
foreach my $p (@{$GP->{sublist}}) {
next if $done->{$p->{number}};
_page_recovery_5_renum($topic, $p->{number}, $level, $new_num, 0, $done);
}
} else {
unlock("/$topic/$page.$DCONF->{ext}");
}
}
###
### page_recovery_6
###
### Fix parent numbers on any pages where they are broken
###
sub page_recovery_6 {
my ($FORMref, $subst) = @_;
dreq("fcn-regn");
my $tf = join("-", $FORMref->{tempfile}, "FP");
if (-e "$DCONF->{admin_dir}/backups/$tf.TMP") {
my $tempfile = incremental({ operation => "read", tempfile => $tf });
$FORMref->{total} = scalar(@{$tempfile->{data}}) if $FORMref->{total} == 0;
my $R = regeneration_resource_init();
my $done = $FORMref->{done};
lock("*");
while (my $f = shift @{ $tempfile->{data} }) {
chomp $f;
my ($topic, $page) = ($f =~ m|^(\d+)/(\d+)|);
my $K = GetPage($topic, $page, { no_error => 1 });
next if ref $K->{head}->{levels} ne 'ARRAY';
my @l = @{$K->{head}->{levels}};
$done++;
my $parent = $K->{head}->{topic_number};
$parent = $l[scalar(@l)-2]->{level_number} if scalar(@l) > 2;
$parent = 0 if $K->{head}->{topic_number} == $K->{head}->{me_number};
if ($parent != $K->{head}->{parent}) {
$K->{head}->{parent} = $parent;
SetPage($K);
}
$R = regeneration_resource_estimate($R, 1, 3 * $K->{general}->{length});
last if regeneration_reset_trigger($R);
}
unlock("*");
my $iw = incremental({ operation => 3, data => $tempfile->{data}, tempfile => $tf });
if ($iw->{'continue'}) {
my $total = $FORMref->{total};
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$FORMref->{tempfile}&spot=6&done=$done&total=$total";
$subst->{'gauge'}->{'operation'} = 9;
$subst->{'gauge'}->{'description'} = 908;
$subst->{'gauge'}->{'percent'} = $total > 0 ? int(100 * $done / $total) : 0;
screen_out("gauge", $subst);
}
}
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$FORMref->{tempfile}&spot=7";
$subst->{'gauge'}->{'operation'} = 9;
$subst->{'gauge'}->{'description'} = 908;
$subst->{'gauge'}->{'percent'} = 100;
screen_out("gauge", $subst);
}
###
### page_recovery_7
###
### Delete links from pages that point to non-existent destinations
###
sub page_recovery_7 {
my ($FORMref, $subst) = @_;
dreq("fcn-regn");
my $tf = join("-", $FORMref->{tempfile}, "FL");
if (-e "$DCONF->{admin_dir}/backups/$tf.TMP") {
my $tempfile = incremental({ operation => "read", tempfile => $tf });
$FORMref->{total} = scalar(@{$tempfile->{data}}) if $FORMref->{total} == 0;
my $R = regeneration_resource_init();
my $done = $FORMref->{done};
lock("*");
while (my $f = shift @{ $tempfile->{data} }) {
chomp $f;
my ($topic, $page) = ($f =~ m|^(\d+)/(\d+)|);
my $tdir = get_message_path($topic);
my $K = GetPage($topic, $page, { no_error => 1 });
next if ref $K->{head}->{levels} ne 'ARRAY';
$done++;
my @sln = ();
my %nu = undef;
foreach my $sl (@{ $K->{sublist} }) {
if ($sl->{number} > 0 && ($sl->{islink} || -e "$tdir/$sl->{number}.$DCONF->{ext}")) {
push @sln, $sl;
} else {
log_error("adm-dr.pl", "page_recovery_7", "Deleted bad subtopic $sl->{number} from $topic/$page");
}
}
$K->{sublist} = \@sln;
$K->{general}->{subtopic_raw} = 0;
SetPage($K, { unlock => 1 });
$R = regeneration_resource_estimate($R, 1, 15 * $K->{general}->{length});
last if regeneration_reset_trigger($R);
}
unlock("*");
my $iw = incremental({ operation => 3, data => $tempfile->{data}, tempfile => $tf });
if ($iw->{'continue'}) {
my $total = $FORMref->{total};
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$FORMref->{tempfile}&spot=7&done=$done&total=$total";
$subst->{'gauge'}->{'operation'} = 9;
$subst->{'gauge'}->{'description'} = 909;
$subst->{'gauge'}->{'percent'} = $total > 0 ? int(100 * $done / $total) : 0;
screen_out("gauge", $subst);
}
}
$subst->{'gauge'}->{'refresh_url'} = "$PARAMS->{cgiurl}?&action=$FORMref->{action}&username=$subst->{general}->{username}&tempfile=$FORMref->{tempfile}&spot=8";
$subst->{'gauge'}->{'operation'} = 9;
$subst->{'gauge'}->{'description'} = 909;
$subst->{'gauge'}->{'percent'} = 100;
screen_out("gauge", $subst);
}
###
### postread_privilege_reset
###
### Resets posting and reading privileges if file topicprv.txt has been reset
###
sub postread_privilege_reset {
my $topics = board_topics();
dreq("fcn-usrp");
my @u = ();
foreach my $topic (@{ $topics }) {
my $tn = $topic->{number};
my $ph = {};
$ph->{action} = "add_topic";
$ph->{type} = "p";
$ph->{topic} = $tn;
$ph->{ip} = "*";
push @u, $ph;
if ($DCONF->{pro}) {
my $rh = {};
$rh->{action} = "set_equal";
$rh->{type} = "r";
$rh->{topic} = $tn;
if (-e "$DCONF->{message_dir}/$tn") {
$rh->{ip} = "*";
} else {
$rh->{user} = "*";
$rh->{user} = "*";
}
push @u, $rh;
} else {
$ph->{type} = "r";
push @u, $ph;
}
}
write_topic_privilege_file(\@u);
return $topics;
}
###
### postindex_database_fix
###
### Fixes improper use of postindex.txt and database
###
sub postindex_database_fix {
my @max = ();
dreq("dbint");
my $sth = database_dbh()->prepare("SELECT max(postnum) FROM $PARAMS->{db_prefix}log;");
$sth->execute();
push @max, ($sth->fetchrow_array())[0];
$sth->finish();
my $fref = readfile("$DCONF->{admin_dir}/postindex.txt", "get_postindex");
push @max, trim($fref->[0]);
my $sth2 = database_dbh()->prepare("SELECT value FROM $PARAMS->{db_prefix}counters WHERE ID = 2;");
$sth2->execute();
push @max, ($sth2->fetchrow_array())[0];
$sth2->finish();
my $sth3 = database_dbh()->prepare("SELECT max(postnum) FROM $PARAMS->{db_prefix}search;");
$sth3->execute();
push @max, ($sth3->fetchrow_array())[0];
$sth3->finish();
my $maximum = 1 + _max(@max);
my $sth3 = database_dbh()->prepare("UPDATE $PARAMS->{db_prefix}counters SET value = 1+$maximum WHERE ID = 2;");
$sth3->execute();
dreq("adm-opts");
options_save({postindex_fixed => 1 });
return 1+$maximum;
}
sub _max {
my $max = undef;
foreach my $q (@_) {
$max = $q if (! defined $max || $q > $max);
}
return $max;
}
1;