package Admin::Backup;
use strict;
#################################################################################
# Ikonboard v3 by Jarvis Entertainment Group, Inc.
#
# No part of this script can be used outside Ikonboard without prior consent.
#
# More information available from <ib-license@jarvisgroup.net>
# (c)2001-2002 Jarvis Entertainment Group, Inc.
# 
# http://www.ikonboard.com | http://www.jarvisgroup.net
#
# Please read the license for more information
#
# 
#
#################################################################################

BEGIN {
    require 'Lib/FUNC.pm';
    require 'Lib/ADMIN.pm';
    require 'Admin/SKIN.pm';
    require 'Boardinfo.pm' or die "Cannot load Module: $!";
}

use File::Path;
use File::Copy;
use Archive::Tar;

my $SKIN  = Admin::SKIN->new();
my $std   = FUNC::STD->new();
my $ADMIN = FUNC::ADMIN->new();
my $INFO  = Boardinfo->new();


my $TABLES = {
                0  => 'attachments',
                1  => 'active_sessions',
                2  => 'authorisation',
                3  => 'address_books',
                4  => 'categories',
                5  => 'email_templates',
                6  => 'forum_info',
                7  => 'forum_moderators',
                8  => 'forum_polls',
                9  => 'forum_poll_voters',
                10 => 'forum_rules',
                11 => 'forum_subscriptions',
                12 => 'help',
                13 => 'member_profiles',
                14 => 'member_titles',
                15 => 'mem_groups',
                16 => 'message_data',
                17 => 'message_stats',
                18 => 'mod_email',
                19 => 'mod_posts',
                20 => 'ssi_templates',
                21 => 'templates',
                22 => 'calendar',
                
            };

                  

sub new {
    my $pkg = shift;
    my $obj = {};
    bless $obj, $pkg;
    return $obj;
}


sub splash {
    my ($obj, $db) = @_;

    my $html  = $SKIN->title( TITLE => 'Export Settings', TEXT => 'Please double check all the data before submitting the changes.' );
       $html .= $SKIN->begin_table();
       $html .= $SKIN->form_start();
       $html .= $SKIN->hidden_fields( { act   => 'bak',
                                        CODE  => 'dobak'
                                      } );

    $html .= $SKIN->section_header( TITLE => "Export Settings", TEXT => "Please specify your preferences");

    $html .= $SKIN->td_select( TEXT     => "Create '.tar' file?",
                               NAME     => 'pack',
                               REQ      => 1,
                               VALUES   => 'gz',
                               DATA     => [ { NAME => 'Create .tar file (Uncompressed)'      , VALUE => 'tar' },
                                             #{ NAME => 'Leave unarchived files'               , VALUE => 'none' },
                                           ],
                             );
    $html .= $SKIN->td_input ( TEXT => 'No. Topics to export at a time',   NAME => 'TOPICS', VALUE=> ""    , REQ => 1 );

    $html .= $SKIN->td_submit(   NAME => '', VALUE => 'EXPORT NOW!' );

    $html .= $SKIN->form_end();
    $html .= $SKIN->end_table();

    $ADMIN->Output( WHERE => 'DATABASE', NAV_ONE => "Export Options", PRINT => $html);

}

sub do_forums {
    my ($obj, $db) = @_;

    # Cap the max topics at 500

    my $max = $iB::IN{TOPICS} || 500;
    my $st  = $iB::IN{st} || 0;
    my $end = $max + ($st - 1);
    my $id  = $iB::IN{fid};

    # Which forum are we on?
    my $fids  = {};
    my $fcnt;
    my $string;
    {
        # Parse the config file
        local $/ = undef;
        open FORUMS, "$obj->{'this_dir'}/tmp_forums" or die "Cannot read the forums config file ($!)";
        $string = <FORUMS>;
        close FORUMS;
        chomp $string;
    }
    for ( split /;/, $string ) {
        my ($k, $v) = split /\:/;
        $fids->{ $k } = $v;
        ++$fcnt;
    }


    # If we've done...

    if ($fids->{ $id } eq '!!END!!') {

        # We are all done, simply tar up the database if that's what we
        # intend to do.

        if ($iB::IN{'pack'} eq 'tar') {
            $obj->do_tar('EXPORT-'.$obj->{'time'});
            rmtree $obj->{'this_dir'};
        }
    
        $ADMIN->static_screen( URL   => "act=backup",
                               TITLE => "Export Completed",
                               TEXT  => "The database has been successfully exported. Your exported database is in the Back-ups directory"
                             );
    }




    # Correct the total forum count.
    --$fcnt;
    my $rcnt = 0;
    # Get the topics to export...

    my $topics = $db->query( TABLE  => 'forum_topics',
                             ID     => $fids->{$id},
                             RANGE  => "$st to $end",
                             WHERE  => "FORUM_ID == $fids->{$id}",
                           );

    if (scalar (@{$topics}) > 0) {
        # Start the exporting

        # Open the topic file
        open THETOPICS, ">>$obj->{'this_dir'}/tmp_topics-$fids->{ $id }";
        for my $t (@{$topics}) {
            my $record = $db->join_record( TABLE => 'forum_topics', VALUES => $t );
            print THETOPICS $record."\n";
            ++$rcnt;
            # Get the posts..
            my $posts = $db->query( TABLE => 'forum_posts',
                                    DBID  => 'f'.$fids->{$id},
                                    ID    => $t->{TOPIC_ID},
                                    WHERE => "FORUM_ID == $fids->{$id} and TOPIC_ID == $t->{TOPIC_ID}",
                                  );

            # Open the posts file
            open THEPOSTS, ">$obj->{'this_dir'}/tmp_fposts-$fids->{ $id }-$t->{TOPIC_ID}";
            for my $p (@{$posts}) {
                my $post = $db->join_record( TABLE => 'forum_posts', VALUES => $p );
                print THEPOSTS $post."\n";
            }
            # close the posts file
            close THEPOSTS;
        }
        # Close the topics file
        close THETOPICS;

        # Redirect to the new screen
        my $next = $end + 1;

        my $Url = "?AD=1&s=$iB::SESSION&act=bak&CODE=dobak&time=".$obj->{'time'}."&pack=$iB::IN{'pack'}&TOPICS=$iB::IN{TOPICS}&forums=1&fid=$id&st=$next";
        $obj->_redirect( "Exported $rcnt topics of forum unique ID $fids->{$id} so far, processing next batch....", $Url);
    }

    else {
        # We must have completed the export on that forum, lets move onto the next...
        ++$id;
        my $Url = "?AD=1&s=$iB::SESSION&act=bak&CODE=dobak&time=".$obj->{'time'}."&pack=$iB::IN{'pack'}&TOPICS=$iB::IN{TOPICS}&forums=1&fid=$id&st=0";
        $obj->_redirect( "Completed forum unique ID $fids->{$id}, processing next forum....", $Url);
    }
}




sub do_back {
    my ($obj, $db) = @_;

    # Do some set up work

    $INFO->{'BACKUP_DIR'} ||= $iB::INFO->{'IKON_DIR'}."BACK_UP";
    $obj->{'time'}     = $iB::IN{'time'} || time;
    $obj->{'this_dir'} = $INFO->{'BACKUP_DIR'}.'/'.'EXPORT-'.$obj->{'time'};
    $obj->{'real_dir'} = $INFO->{'BACKUP_DIR'}.'/'.'EXPORT-'.$obj->{'time'};
    

    if ($iB::IN{forums}) {
        if ($iB::IN{fid}) {
            $obj->do_forums($db);
        }
        else {
            my $forums = $db->query( TABLE    => 'forum_info',
                                     SORT_KEY => 'FORUM_ID',
                                     SORT_BY  => 'A-Z',
                                   );
    
            my $first;
            my $cnt = 1;
            # Open up the temp forum info file
            open TEMP, ">$obj->{'this_dir'}/tmp_forums" or die "Cannot save out the forums config file ($!)";
            for my $f (@{$forums}) {
                print TEMP "$cnt:$f->{FORUM_ID};";
                ++$cnt;
            }
            print TEMP "$cnt:!!END!!";
            close TEMP;

            # Forward to start exporting the first batch of topics from this forum
            $iB::IN{fid} = 1;
            $obj->do_forums($db);
        }
    }

    else {

        # This is where we just export a table that is contained in a single
        # database table.

        $obj->_do_tables($db);
    }
        
}



# Export a single table with no DBID or ID

sub _do_tables {
    my ($obj, $db) = @_;

    my $id    = $iB::IN{'id'} || 0;
    my $table = $TABLES->{ $id };

    unless ($id) {
        unless ( mkpath ($obj->{'this_dir'}) ) {
            $ADMIN->Error( DB=>$db, STD=>$std, MSG=>"I don't have permissions to create a new directory inside the back-ups directory. Please ensure that the Back-Ups directory has a sufficient CHMOD value to enable me to create a new directory");
        }
        chmod (0777, $obj->{'this_dir'});
    }

    $db->back_up( TABLE       => $table,
                  DESTINATION => $obj->{'this_dir'},
                );

    # Increment the id number for the next iteration
    ++$id;
    my $tmp = 0;
    # Get the highest possible legal id number
    for (keys %{$TABLES}) {
        $tmp = $_ if $_ > $tmp;
    }
    
    my $Url = "?AD=1&s=$iB::SESSION&act=bak&CODE=dobak&time=".$obj->{'time'}."&pack=$iB::IN{'pack'}&TOPICS=$iB::IN{TOPICS}&";
    $Url .= $id > $tmp ? 'forums=1' : "id=$id";

    $obj->_redirect( "Exporting table \"$table\"....", $Url);
 

}





sub _redirect {
    my ($obj, $text, $Url) = @_;

    my $html = qq~
    <html>
    <head>
    <title>iB::Exporting Database - Please Stand by...</title>
    <meta http-equiv="refresh" content="1; url=$iB::INFO->{'BOARD_URL'}/ikonboard.$iB::INFO->{'CGI_EXT'}$Url">
    <style type="text/css">
    #t        { font-family: Arial; font-size: 12px; color: #000003 }
    #large    { font-family: Arial; font-size: 14px; font-weight: bold; color: #000000 }
    </style>
    </head>
    <body bgcolor='#FFFFFFF'>

    <table cellpadding='0' cellspacing='0' border='0' width="$iB::SKIN->{'TABLE_WIDTH'}" align='center' height='85%'>
    <tr align='center' valign='middle'>
        <td>
        <table cellpadding='10' cellspacing='0' border='0' width="80%" align='center'>
        <tr>
            <td valign='middle' align='center' bgcolor='$iB::SKIN->{'MISCBACK_ONE'}' id='t'>
            <span id='large'>$text</span>
            <br><br>Continuing to export the database...
            <br><br>
            (<a href='$iB::INFO->{'BOARD_URL'}/ikonboard.$iB::INFO->{'CGI_EXT'}$Url' >Click here if you do not wish to wait</a>)
            </td>
        </tr>
        </table>
        </td>
    </tr>
    </table>
    </body>
    </html>
    ~;

    $ADMIN->Print( OUTPUT => $html );
}



sub process {
    my ($obj, $db) = @_;

    # Only allow super admins access...

    #unless ($iB::MEMBER->{'MEMBER_GROUP'} == $iB::INFO->{'SUPAD_GROUP'}) {
    #    $ADMIN->Error( DB => $db, STD => $std, MSG => "Sorry, only the board owners have access to this part");
    #}

    my $CodeNo = $iB::IN{'CODE'};

    my %Mode = ( 'dobak'        => \&do_back, );

    $Mode{$CodeNo} ? $Mode{$CodeNo}->($obj,$db) : splash($obj,$db);
} 



sub do_tar {
    my ($obj, $file_path) = @_;
    my $cwd  = $iB::INFO->{'IKON_DIR'};

    chdir $INFO->{'BACKUP_DIR'};

    my $tar      = Archive::Tar->new();
    my @filelist = $obj->Find_Files($file_path);

    $tar->add_files(@filelist)    or ($obj->{'ERROR'} = $Archive::Tar::error and chdir $cwd and return);
    $tar->write("$file_path.tar") or ($obj->{'ERROR'} = $Archive::Tar::error and chdir $cwd and return);
    chdir $cwd;
    return 1;
}

sub Find_Files {
    my ($obj, $file_path) = @_;

    my @filelist;

    opendir (DIR, "$INFO->{'BACKUP_DIR'}/$file_path");
    my @list = readdir(DIR);
    closedir(DIR);

    foreach my $file (@list) {
        next if ($file =~ /^\.\.?$/);
        if (-d "$INFO->{'BACKUP_DIR'}/$file_path/$file") {
            push(@filelist, $obj->Find_Files($file_path.'/'.$file) );
        } else {
            push(@filelist, $file_path.'/'.$file);
            chmod(0777, "$INFO->{'BACKUP_DIR'}/$file_path/$file");
        }
    }
    return @filelist;
}



1;
