--- /dev/null
+#!/bin/sh
+#
+# DESCRIPTION
+#
+# Startup init script for BackupPC for Slackware.
+#
+# Distributed with BackupPC version __VERSION__, released __RELEASEDATE__.
+#
+# Provided by Tony Nelson.
+#
+
+start() {
+ #
+ # You can set the SMB share password here is you wish. Otherwise
+ # you should put it in the config.pl script.
+ # If you put it here make sure this file has no read permissions
+ # for normal users! See the documentation for more information.
+ #
+ #BPC_SMB_PASSWD=
+ #export BPC_SMB_PASSWD
+ #
+ su backuppc -c "__INSTALLDIR__/bin/BackupPC -d"
+}
+
+stop() {
+ /usr/bin/pkill -f "__INSTALLDIR__/bin/BackupPC -d"
+}
+
+restart() {
+ stop
+ start
+}
+
+reload() {
+ /usr/bin/pkill -1 -f "__INSTALLDIR__/bin/BackupPC -d"
+}
+
+case "$1" in
+ start)
+ start
+ ;;
+ stop)
+ stop
+ ;;
+ restart)
+ restart
+ ;;
+ reload)
+ reload
+ ;;
+ *)
+ echo "Usage: $0 {start|stop|restart|reload}"
+ exit 1
+esac
+
+exit $?
--- /dev/null
+#============================================================= -*-perl-*-
+#
+# BackupPC::CGI::EditConfig package
+#
+# DESCRIPTION
+#
+# This module implements the EditConfig action for the CGI interface.
+#
+# AUTHOR
+# Craig Barratt <cbarratt@users.sourceforge.net>
+#
+# COPYRIGHT
+# Copyright (C) 2004 Craig Barratt
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+#========================================================================
+#
+# Version 2.1.0beta2pl1, released 30 May 2004.
+#
+# See http://backuppc.sourceforge.net.
+#
+#========================================================================
+
+package BackupPC::CGI::EditConfig;
+
+use strict;
+use BackupPC::CGI::Lib qw(:all);
+use BackupPC::Config::Meta qw(:all);
+use BackupPC::Storage;
+use Data::Dumper;
+
+our %ConfigMenu = (
+ server => {
+ text => "Server",
+ param => [
+ {text => "General Parameters"},
+ {name => "ServerHost"},
+ {name => "BackupPCUser"},
+ {name => "BackupPCUserVerify"},
+ {name => "MaxOldLogFiles"},
+ {name => "TrashCleanSleepSec"},
+
+ {text => "Wakeup Schedule"},
+ {name => "WakeupSchedule"},
+
+ {text => "Concurrent Jobs"},
+ {name => "MaxBackups"},
+ {name => "MaxUserBackups"},
+ {name => "MaxPendingCmds"},
+ {name => "MaxBackupPCNightlyJobs"},
+ {name => "BackupPCNightlyPeriod"},
+
+ {text => "Pool Filesystem Limits"},
+ {name => "DfCmd"},
+ {name => "DfMaxUsagePct"},
+ {name => "HardLinkMax"},
+
+ {text => "Other Parameters"},
+ {name => "UmaskMode"},
+ {name => "MyPath"},
+ {name => "DHCPAddressRanges"},
+ {name => "PerlModuleLoad"},
+ {name => "ServerInitdPath"},
+ {name => "ServerInitdStartCmd"},
+
+ {text => "Remote Apache Settings"},
+ {name => "ServerPort"},
+ {name => "ServerMesgSecret"},
+
+ {text => "Program Paths"},
+ {name => "SshPath"},
+ {name => "NmbLookupPath"},
+ {name => "PingPath"},
+ {name => "DfPath"},
+ {name => "SplitPath"},
+ {name => "ParPath"},
+ {name => "CatPath"},
+ {name => "GzipPath"},
+ {name => "Bzip2Path"},
+
+ {text => "Install Paths"},
+ {name => "CgiDir"},
+ {name => "InstallDir"},
+ ],
+ },
+ email => {
+ text => "Email",
+ param => [
+ {text => "Email settings"},
+ {name => "SendmailPath"},
+ {name => "EMailNotifyMinDays"},
+ {name => "EMailFromUserName"},
+ {name => "EMailAdminUserName"},
+ {name => "EMailUserDestDomain"},
+
+ {text => "Email User Messages"},
+ {name => "EMailNoBackupEverSubj"},
+ {name => "EMailNoBackupEverMesg"},
+ {name => "EMailNotifyOldBackupDays"},
+ {name => "EMailNoBackupRecentSubj"},
+ {name => "EMailNoBackupRecentMesg"},
+ {name => "EMailNotifyOldOutlookDays"},
+ {name => "EMailOutlookBackupSubj"},
+ {name => "EMailOutlookBackupMesg"},
+ ],
+ },
+ cgi => {
+ text => "CGI",
+ param => [
+ {text => "Admin Privileges"},
+ {name => "CgiAdminUserGroup"},
+ {name => "CgiAdminUsers"},
+
+ {text => "Config Editing"},
+ {name => "CgiUserConfigEdit"},
+
+ {text => "Page Rendering"},
+ {name => "Language"},
+ {name => "CgiNavBarAdminAllHosts"},
+ {name => "CgiSearchBoxEnable"},
+ {name => "CgiNavBarLinks"},
+ {name => "CgiStatusHilightColor"},
+ {name => "CgiDateFormatMMDD"},
+ {name => "CgiHeaders"},
+ {name => "CgiExt2ContentType"},
+ {name => "CgiCSSFile"},
+
+ {text => "Paths"},
+ {name => "CgiURL"},
+ {name => "CgiImageDir"},
+ {name => "CgiImageDirURL"},
+
+ {text => "User URLs"},
+ {name => "CgiUserHomePageCheck"},
+ {name => "CgiUserUrlCreate"},
+
+ ],
+ },
+ xfer => {
+ text => "Xfer",
+ param => [
+ {text => "Xfer Settings"},
+ {name => "XferMethod", onchangeSubmit => 1},
+ {name => "XferLogLevel"},
+
+ {text => "Smb Settings",
+ visible => sub { return $_[0]->{XferMethod} eq "smb"; } },
+ {name => "SmbShareName",
+ visible => sub { return $_[0]->{XferMethod} eq "smb"; } },
+ {name => "SmbShareUserName",
+ visible => sub { return $_[0]->{XferMethod} eq "smb"; } },
+ {name => "SmbSharePasswd",
+ visible => sub { return $_[0]->{XferMethod} eq "smb"; } },
+
+ {text => "Tar Settings",
+ visible => sub { return $_[0]->{XferMethod} eq "tar"; } },
+ {name => "TarShareName",
+ visible => sub { return $_[0]->{XferMethod} eq "tar"; } },
+
+ {text => "Rsync Settings",
+ visible => sub { return $_[0]->{XferMethod} eq "rsync"; } },
+ {text => "Rsyncd Settings",
+ visible => sub { return $_[0]->{XferMethod} eq "rsyncd"; } },
+ {name => "RsyncShareName",
+ visible => sub { return $_[0]->{XferMethod} =~ /rsync/; } },
+ {name => "RsyncdPasswd",
+ visible => sub { return $_[0]->{XferMethod} eq "rsyncd"; } },
+ {name => "RsyncdAuthRequired",
+ visible => sub { return $_[0]->{XferMethod} eq "rsyncd"; } },
+ {name => "RsyncCsumCacheVerifyProb",
+ visible => sub { return $_[0]->{XferMethod} =~ /rsync/; } },
+
+ {text => "Archive Settings",
+ visible => sub { return $_[0]->{XferMethod} eq "archive"; } },
+ {name => "ArchiveDest",
+ visible => sub { return $_[0]->{XferMethod} eq "archive"; } },
+ {name => "ArchiveComp",
+ visible => sub { return $_[0]->{XferMethod} eq "archive"; } },
+ {name => "ArchivePar",
+ visible => sub { return $_[0]->{XferMethod} eq "archive"; } },
+ {name => "ArchiveSplit",
+ visible => sub { return $_[0]->{XferMethod} eq "archive"; } },
+
+ {text => "Include/Exclude",
+ visible => sub { return $_[0]->{XferMethod} ne "archive"; } },
+ {name => "BackupFilesOnly",
+ visible => sub { return $_[0]->{XferMethod} ne "archive"; } },
+ {name => "BackupFilesExclude",
+ visible => sub { return $_[0]->{XferMethod} ne "archive"; } },
+
+ {text => "Smb Paths/Commands",
+ visible => sub { return $_[0]->{XferMethod} eq "smb"; } },
+ {name => "SmbClientPath",
+ visible => sub { return $_[0]->{XferMethod} eq "smb"; } },
+ {name => "SmbClientFullCmd",
+ visible => sub { return $_[0]->{XferMethod} eq "smb"; } },
+ {name => "SmbClientIncrCmd",
+ visible => sub { return $_[0]->{XferMethod} eq "smb"; } },
+ {name => "SmbClientRestoreCmd",
+ visible => sub { return $_[0]->{XferMethod} eq "smb"; } },
+
+ {text => "Tar Paths/Commands",
+ visible => sub { return $_[0]->{XferMethod} eq "tar"; } },
+ {name => "TarClientPath",
+ visible => sub { return $_[0]->{XferMethod} eq "tar"; } },
+ {name => "TarClientCmd",
+ visible => sub { return $_[0]->{XferMethod} eq "tar"; } },
+ {name => "TarFullArgs",
+ visible => sub { return $_[0]->{XferMethod} eq "tar"; } },
+ {name => "TarIncrArgs",
+ visible => sub { return $_[0]->{XferMethod} eq "tar"; } },
+ {name => "TarClientRestoreCmd",
+ visible => sub { return $_[0]->{XferMethod} eq "tar"; } },
+
+ {text => "Rsync Paths/Commands/Args",
+ visible => sub { return $_[0]->{XferMethod} eq "rsync"; } },
+ {text => "Rsyncd Port/Args",
+ visible => sub { return $_[0]->{XferMethod} eq "rsyncd"; } },
+ {name => "RsyncClientPath",
+ visible => sub { return $_[0]->{XferMethod} eq "rsync"; } },
+ {name => "RsyncClientCmd",
+ visible => sub { return $_[0]->{XferMethod} eq "rsync"; } },
+ {name => "RsyncClientRestoreCmd",
+ visible => sub { return $_[0]->{XferMethod} eq "rsync"; } },
+ {name => "RsyncdClientPort",
+ visible => sub { return $_[0]->{XferMethod} eq "rsyncd"; } },
+ {name => "RsyncArgs",
+ visible => sub { return $_[0]->{XferMethod} =~ /rsync/; } },
+ {name => "RsyncRestoreArgs",
+ visible => sub { return $_[0]->{XferMethod} =~ /rsync/; } },
+
+ {text => "Archive Paths/Commands",
+ visible => sub { return $_[0]->{XferMethod} eq "archive"; } },
+ {name => "ArchiveClientCmd",
+ visible => sub { return $_[0]->{XferMethod} eq "archive"; } },
+
+ ],
+ },
+ schedule => {
+ text => "Schedule",
+ param => [
+ {text => "Full Backups"},
+ {name => "FullPeriod"},
+ {name => "FullKeepCnt"},
+ {name => "FullKeepCntMin"},
+ {name => "FullAgeMax"},
+
+ {text => "Incremental Backups"},
+ {name => "IncrPeriod"},
+ {name => "IncrKeepCnt"},
+ {name => "IncrKeepCntMin"},
+ {name => "IncrAgeMax"},
+ {name => "IncrFill"},
+
+ {text => "Blackouts"},
+ {name => "BlackoutBadPingLimit"},
+ {name => "BlackoutGoodCnt"},
+ {name => "BlackoutPeriods"},
+
+ {text => "Other"},
+ {name => "PartialAgeMax"},
+ {name => "RestoreInfoKeepCnt"},
+ {name => "ArchiveInfoKeepCnt"},
+ {name => "BackupZeroFilesIsFatal"},
+ ],
+ },
+ backup => {
+ text => "Backup Settings",
+ param => [
+ {text => "Client Lookup"},
+ {name => "ClientNameAlias"},
+ {name => "NmbLookupCmd"},
+ {name => "NmbLookupFindHostCmd"},
+ {name => "FixedIPNetBiosNameCheck"},
+ {name => "PingCmd"},
+ {name => "PingMaxMsec"},
+
+ {text => "Other"},
+ {name => "ClientTimeout"},
+ {name => "MaxOldPerPCLogFiles"},
+ {name => "CompressLevel"},
+
+ {text => "User Commands"},
+ {name => "DumpPreUserCmd"},
+ {name => "DumpPostUserCmd"},
+ {name => "DumpPreShareCmd"},
+ {name => "DumpPostShareCmd"},
+ {name => "RestorePreUserCmd"},
+ {name => "RestorePostUserCmd"},
+ {name => "ArchivePreUserCmd"},
+ {name => "ArchivePostUserCmd"},
+ ],
+ },
+);
+
+sub action
+{
+ my $pc_dir = "$TopDir/pc";
+ my($content, $contentHidden, $newConf, $override, $mainConf, $hostConf);
+ my $errors = {};
+
+ my $host = $In{host};
+ my $menu = $In{menu} || "server";
+ my $hosts_path = $Hosts;
+ my $config_path = $host eq "" ? "$TopDir/conf/config.pl"
+ : "$TopDir/pc/$host/config.pl";
+
+ my $Privileged = CheckPermission();
+ my $userHost = 1 if ( $Privileged && !$PrivAdmin && defined($host) );
+
+ if ( !$Privileged ) {
+ #ErrorExit(eval("qq{$Lang->{Only_privileged_users_can_edit_config_files}}"));
+ ErrorExit("Only_privileged_users_can_edit_config_files");
+ }
+
+ if ( defined($In{menu}) || $In{editAction} eq "Save" ) {
+ $errors = errorCheck();
+ if ( %$errors ) {
+ #
+ # If there are errors, then go back to the same menu
+ #
+ $In{editAction} = "";
+ $In{newMenu} = "";
+ }
+ ($newConf, $override) = inputParse($bpc, $userHost);
+ $override = undef if ( $host eq "" );
+
+ #
+ # Copy all the orig_ input parameters
+ #
+ foreach my $var ( keys(%In) ) {
+ next if ( $var !~ /^orig_/ );
+ $contentHidden .= <<EOF;
+<input type="hidden" name="$var" value="${EscHTML($In{$var})}">
+EOF
+ }
+ } else {
+ #
+ # First time: pick up the current config settings
+ #
+ $mainConf = $bpc->ConfigDataRead();
+ if ( $host ne "" ) {
+ $hostConf = $bpc->ConfigDataRead($host);
+ $override = {};
+ foreach my $param ( keys(%$hostConf) ) {
+ $override->{$param} = 1;
+ }
+ } else {
+ $hostConf = {};
+ }
+ $newConf = { %$mainConf, %$hostConf };
+
+ #
+ # Emit all the original config settings
+ #
+ my $doneParam = {};
+ foreach my $param ( keys(%ConfigMeta) ) {
+ next if ( $doneParam->{$param} );
+ next if ( $userHost && !$bpc->{Conf}{CgiUserConfigEdit}{$param} );
+ $contentHidden .= fieldHiddenBuild($ConfigMeta{$param},
+ $param,
+ $mainConf->{$param},
+ "orig",
+ );
+ $doneParam->{$param} = 1;
+ }
+
+ }
+
+ if ( $In{editAction} ne "Save" && $In{newMenu} ne ""
+ && defined($ConfigMenu{$In{newMenu}}) ) {
+ $menu = $In{newMenu};
+ }
+
+ my %menuDisable;
+ if ( $userHost ) {
+ #
+ # For a non-admin user editing the host config, we need to
+ # figure out which subsets of the menu tree will be visible,
+ # based on what is enabled
+ #
+ foreach my $m ( keys(%ConfigMenu) ) {
+ my $enabled = 0;
+ my $text = -1;
+ my $n = 0;
+ my @mask = ();
+
+ foreach my $paramInfo ( @{$ConfigMenu{$m}{param}} ) {
+ my $param = $paramInfo->{name};
+ if ( defined($paramInfo->{text}) ) {
+ $text = $n;
+ $mask[$text] = 1;
+ } else {
+ if ( $bpc->{Conf}{CgiUserConfigEdit}{$param} ) {
+ $mask[$text] = 0 if ( $text >= 0 );
+ $mask[$n] = 0;
+ $enabled = 1;
+ } else {
+ $mask[$n] = 1;
+ }
+ }
+ $n++;
+ }
+ $menuDisable{$m}{mask} = \@mask;
+ $menuDisable{$m}{top} = !$enabled;
+ }
+ if ( $menuDisable{$menu}{top} ) {
+ #
+ # Find an enabled menu if the current menu is empty
+ #
+ foreach my $m ( sort(keys(%menuDisable)) ) {
+ if ( !$menuDisable{$m}{top} ) {
+ $menu = $m;
+ last;
+ }
+ }
+ }
+ }
+
+ my $groupText;
+ foreach my $m ( keys(%ConfigMenu) ) {
+ next if ( $menuDisable{$m}{top} );
+ my $text = $ConfigMenu{$m}{text};
+ if ( $m eq $menu ) {
+ $groupText .= <<EOF;
+<td bgcolor="grey"><a href="javascript:menuSubmit('$m')"><b>$text</b></a></td>
+EOF
+ } else {
+ $groupText .= <<EOF;
+<td><a href="javascript:menuSubmit('$m')">$text</a></td>
+EOF
+ }
+ }
+
+ if ( $host eq "" ) {
+ $content .= <<EOF;
+${h1("Main Configuration Editor")}
+EOF
+ } else {
+ $content .= <<EOF;
+${h1("Host $host Configuration Editor")}
+<p>
+Note: Check Override if you want to modify a value specific to this host.
+EOF
+ }
+
+ my $saveDisplay = "block";
+ $saveDisplay = "none" if ( !$In{modified} );
+ $content .= <<EOF;
+<table border="0" cellpadding="2">
+<tr>$groupText</tr>
+<tr>
+<form method="post" name="form1" action="$MyURL">
+<input type="hidden" name="host" value="$host">
+<input type="hidden" name="menu" value="$menu">
+<input type="hidden" name="newMenu" value="">
+<input type="hidden" name="modified" value="$In{modified}">
+<input type="hidden" name="deleteVar" value="">
+<input type="hidden" name="insertVar" value="">
+<input type="hidden" name="addVar" value="">
+<input type="hidden" name="action" value="editConfig">
+<input type="submit" style="display: $saveDisplay" name="editAction" value="Save">
+$contentHidden
+
+<script language="javascript" type="text/javascript">
+<!--
+
+ function deleteSubmit(varName)
+ {
+ document.form1.deleteVar.value = varName;
+ document.form1.modified.value = 1;
+ document.form1.submit();
+ return;
+ }
+
+ function insertSubmit(varName)
+ {
+ document.form1.insertVar.value = varName;
+ document.form1.modified.value = 1;
+ document.form1.submit();
+ return;
+ }
+
+ function addSubmit(varName, checkKey)
+ {
+ if ( checkKey && document.form1.addVarKey.value == "" ) {
+ alert("New key must be non-empty");
+ return;
+ }
+ document.form1.addVar.value = varName;
+ document.form1.modified.value = 1;
+ document.form1.submit();
+ return;
+ }
+
+ function menuSubmit(menuName)
+ {
+ document.form1.newMenu.value = menuName;
+ document.form1.submit();
+ }
+
+ function varChange(varName)
+ {
+ document.form1.editAction.style.display = "block";
+ document.form1.modified.value = 1;
+ }
+
+ function checkboxChange(varName)
+ {
+ document.form1.editAction.style.display = "block";
+ document.form1.modified.value = 1;
+ // Do nothing if the checkbox is now set
+ if ( eval("document.form1.override_" + varName + ".checked") ) {
+ return false;
+ }
+ var allVars = {};
+ var varRE = new RegExp("^v_(" + varName + ".*)");
+ var origRE = new RegExp("^orig_(" + varName + ".*)");
+ for ( var i = 0 ; i < document.form1.elements.length ; i++ ) {
+ var e = document.form1.elements[i];
+ var re;
+ if ( (re = varRE.exec(e.name)) != null ) {
+ if ( allVars[re[1]] == null ) {
+ allVars[re[1]] = 0;
+ }
+ allVars[re[1]]++;
+ //debugMsg("found v_ match with " + re[1]);
+ //debugMsg("allVars[" + re[1] + "] = " + allVars[re[1]]);
+ } else if ( (re = origRE.exec(e.name)) != null ) {
+ if ( allVars[re[1]] == null ) {
+ allVars[re[1]] = 0;
+ }
+ allVars[re[1]]--;
+ //debugMsg("allVars[" + re[1] + "] = " + allVars[re[1]]);
+ }
+ }
+ var sameShape = 1;
+ for ( v in allVars ) {
+ if ( allVars[v] != 0 ) {
+ //debugMsg("Not the same shape because of " + v);
+ sameShape = 0;
+ }
+ }
+ if ( sameShape ) {
+ for ( v in allVars ) {
+ //debugMsg("setting " + v);
+ eval("document.form1.v_" + v + ".value = document.form1.orig_" + v + ".value");
+ }
+ return true;
+ } else {
+ document.form1.submit();
+ return false;
+ }
+ }
+
+ function checkboxSet(varName)
+ {
+ document.form1.editAction.style.display = "block";
+ document.form1.modified.value = 1;
+ eval("document.form1.override_" + varName + ".checked = 1;");
+ return false;
+ }
+
+ var debugCounter = 0;
+ function debugMsg(msg)
+ {
+ debugCounter++;
+ var t = document.createTextNode(debugCounter + ": " + msg);
+ var br = document.createElement("br");
+ var debug = document.getElementById("debug");
+ debug.appendChild(t);
+ debug.appendChild(br);
+ }
+
+ function displayHelp(varName)
+ {
+ var help = document.getElementById("id_" + varName);
+ help.style.display = help.style.display == "block" ? "none" : "block";
+ }
+
+//-->
+</script>
+
+<span id="debug"></span>
+
+EOF
+
+ $content .= <<EOF;
+<table border="1" cellspacing="0">
+EOF
+
+ my $doneParam = {};
+
+ #
+ # There is a special case of the user deleting just the field
+ # that has the error(s). So if the delete variable is a match
+ # or parent to all the errors then ignore the errors.
+ #
+ if ( $In{deleteVar} ne "" && %$errors > 0 ) {
+ my $matchAll = 1;
+ foreach my $v ( keys(%$errors) ) {
+ if ( $v ne $In{deleteVar} && $v !~ /^\Q$In{deleteVar}_/ ) {
+ $matchAll = 0;
+ last;
+ }
+ }
+ $errors = {} if ( $matchAll );
+ }
+
+ my $isError = %$errors;
+
+ if ( !$isError && $In{editAction} eq "Save" ) {
+ my $mesg;
+ if ( $host ne "" ) {
+ $hostConf = $bpc->ConfigDataRead($host) if ( !defined($hostConf) );
+ $mesg = configDiffMesg($host, $hostConf, $newConf);
+ foreach my $param ( %$newConf ) {
+ $hostConf->{$param} = $newConf->{$param}
+ if ( $override->{param} );
+ }
+ $bpc->ConfigDataWrite($host, $hostConf);
+ } else {
+ $mainConf = $bpc->ConfigDataRead() if ( !defined($mainConf) );
+ $mesg = configDiffMesg(undef, $mainConf, $newConf);
+ $mainConf = { %$mainConf, %$newConf };
+ $bpc->ConfigDataWrite(undef, $mainConf);
+ }
+ if ( $mesg ne "" ) {
+ $bpc->ServerConnect();
+ foreach my $str ( split(/\n/, $mesg) ) {
+ $bpc->ServerMesg($str);
+ }
+ }
+ }
+
+ my @mask = @{$menuDisable{$menu}{mask} || []};
+
+ foreach my $paramInfo ( @{$ConfigMenu{$menu}{param}} ) {
+
+ my $param = $paramInfo->{name};
+ my $disabled = shift(@mask);
+
+ next if ( $disabled || $menuDisable{$menu}{top} );
+ if ( ref($paramInfo->{visible}) eq "CODE"
+ && !&{$paramInfo->{visible}}($newConf) ) {
+ next;
+ }
+
+ if ( defined(my $text = $paramInfo->{text}) ) {
+ $content .= <<EOF;
+<tr><td colspan="2" class="editHeader">$text</td></tr>
+EOF
+ next;
+ }
+
+ #
+ # TODO: get parameter documentation
+ #
+ my $comment = "";
+ $comment =~ s/\'//g;
+ $comment =~ s/\"//g;
+ $comment =~ s/\n/ /g;
+
+ $doneParam->{$param} = 1;
+
+ $content .= fieldEditBuild($ConfigMeta{$param},
+ $param,
+ $newConf->{$param},
+ $errors,
+ 0,
+ $comment,
+ $isError,
+ $paramInfo->{onchangeSubmit},
+ defined($override) ? $param : undef,
+ defined($override) ? $override->{$param} : undef
+ );
+ }
+
+ #
+ # Emit any remaining errors - should not happen
+ #
+ foreach my $param ( sort(keys(%$errors)) ) {
+ $content .= <<EOF;
+<tr><td colspan="2" class="border">$errors->{$param}</td></tr>
+EOF
+ delete($errors->{$param});
+ }
+
+ $content .= <<EOF;
+</table>
+EOF
+
+ #
+ # Emit all the remaining editable config settings as hidden values
+ #
+ foreach my $param ( keys(%ConfigMeta) ) {
+ next if ( $doneParam->{$param} );
+ next if ( $userHost && !$bpc->{Conf}{CgiUserConfigEdit}{$param} );
+ $content .= fieldHiddenBuild($ConfigMeta{$param},
+ $param,
+ $newConf->{$param},
+ "v"
+ );
+ if ( defined($override) ) {
+ $content .= <<EOF;
+<input type="hidden" name="override_$param" value="$override->{$param}">
+EOF
+ }
+ $doneParam->{$param} = 1;
+ }
+
+ $content .= <<EOF;
+</form>
+</tr>
+</table>
+EOF
+
+ Header("Config Edit", $content);
+ Trailer();
+}
+
+sub fieldHiddenBuild
+{
+ my($type, $varName, $varValue, $prefix) = @_;
+ my $content;
+
+ $type = { type => $type } if ( ref($type) ne "HASH" );
+
+ if ( $type->{type} eq "list" ) {
+ $varValue = [] if ( !defined($varValue) );
+ $varValue = [$varValue] if ( ref($varValue) ne "ARRAY" );
+
+ for ( my $i = 0 ; $i < @$varValue ; $i++ ) {
+ $content .= fieldHiddenBuild($type->{child}, "${varName}_$i",
+ $varValue->[$i], $prefix);
+ }
+ } elsif ( $type->{type} eq "hash" ) {
+ $varValue = {} if ( ref($varValue) ne "HASH" );
+ my(@order, $childType);
+
+ if ( defined($type->{child}) ) {
+ @order = sort(keys(%{$type->{child}}));
+ } else {
+ @order = sort(keys(%$varValue));
+ }
+
+ foreach my $fld ( @order ) {
+ if ( defined($type->{child}) ) {
+ $childType = $type->{child}{$fld};
+ } else {
+ $childType = $type->{childType};
+ #
+ # emit list of fields since they are user-defined
+ # rather than hard-coded
+ #
+ $content .= <<EOF;
+<input type="hidden" name="vflds.$varName" value="${EscHTML($fld)}">
+EOF
+ }
+ $content .= fieldHiddenBuild($childType, "${varName}_$fld",
+ $varValue->{$fld}, $prefix);
+ }
+ } elsif ( $type->{type} eq "shortlist" ) {
+ $varValue = [$varValue] if ( ref($varValue) ne "ARRAY" );
+ $varValue = join(", ", @$varValue);
+ $content .= <<EOF;
+<input type="hidden" name="${prefix}_$varName" value="${EscHTML($varValue)}">
+EOF
+ } else {
+ $content .= <<EOF;
+<input type="hidden" name="${prefix}_$varName" value="${EscHTML($varValue)}">
+EOF
+ }
+ return $content;
+}
+
+sub fieldEditBuild
+{
+ my($type, $varName, $varValue, $errors, $level, $comment, $isError,
+ $onchangeSubmit, $overrideVar, $overrideSet) = @_;
+
+ my $content;
+ my $size = 50 - 10 * $level;
+ $type = { type => $type } if ( ref($type) ne "HASH" );
+
+ if ( $level == 0 ) {
+ $content .= <<EOF;
+<tr id="id_$varName" class="optionalComment"><td colspan="2">$comment</td></tr>
+<tr><td class="border"><a href="javascript: displayHelp('$varName')">$varName</a>
+EOF
+ if ( defined($overrideVar) ) {
+ my $override_checked = "";
+ if ( !$isError && $In{deleteVar} =~ /^\Q${varName}_/
+ || !$isError && $In{insertVar} =~ /^\Q${varName}\E(_|$)/
+ || !$isError && $In{addVar} =~ /^\Q${varName}\E(_|$)/ ) {
+ $overrideSet = 1;
+ }
+ if ( $overrideSet ) {
+ $override_checked = "checked";
+ }
+ $content .= <<EOF;
+<br><input type="checkbox" name="override_$varName" $override_checked value="1" onClick="checkboxChange('$varName')">\ Override
+EOF
+ }
+ $content .= "</td>\n";
+ }
+
+ $content .= "<td class=\"border\">\n";
+ if ( $type->{type} eq "list" ) {
+ $varValue = [] if ( !defined($varValue) );
+ $varValue = [$varValue] if ( ref($varValue) ne "ARRAY" );
+ if ( !$isError && $In{deleteVar} =~ /^\Q${varName}_\E(\d+)$/
+ && $1 < @$varValue ) {
+ #
+ # User deleted entry in this array
+ #
+ splice(@$varValue, $1, 1) if ( @$varValue > 1 || $type->{emptyOk} );
+ $In{deleteVar} = "";
+ }
+ if ( !$isError && $In{insertVar} =~ /^\Q${varName}_\E(\d+)$/
+ && $1 < @$varValue ) {
+ #
+ # User inserted entry in this array
+ #
+ splice(@$varValue, $1, 0, "")
+ if ( @$varValue > 1 || $type->{emptyOk} );
+ $In{insertVar} = "";
+ }
+ if ( !$isError && $In{addVar} eq $varName ) {
+ #
+ # User added entry to this array
+ #
+ push(@$varValue, undef);
+ $In{addVar} = "";
+ }
+ $content .= "<table border=\"1\" cellspacing=\"0\">\n";
+
+ for ( my $i = 0 ; $i < @$varValue ; $i++ ) {
+ $content .= "<tr><td class=\"border\">\n";
+ if ( @$varValue > 1 || $type->{emptyOk} ) {
+ $content .= <<EOF;
+<input type="button" name="ins_${varName}_$i" value="Insert"
+ onClick="insertSubmit('${varName}_$i')">
+<input type="button" name="del_${varName}_$i" value="Delete"
+ onClick="deleteSubmit('${varName}_$i')">
+EOF
+ }
+ $content .= "</td>\n";
+ $content .= fieldEditBuild($type->{child}, "${varName}_$i",
+ $varValue->[$i], $errors, $level + 1, undef,
+ $isError, $onchangeSubmit,
+ $overrideVar, $overrideSet);
+ $content .= "</tr>\n";
+ }
+ $content .= <<EOF;
+<tr><td class="border"><input type="button" name="add_$varName" value="Add"
+ onClick="addSubmit('$varName')"></td></tr>
+</table>
+EOF
+ } elsif ( $type->{type} eq "hash" ) {
+ $content .= "<table border=\"1\" cellspacing=\"0\">\n";
+ $varValue = {} if ( ref($varValue) ne "HASH" );
+
+ if ( !$isError && !$type->{noKeyEdit}
+ && $In{deleteVar} =~ /^\Q${varName}_\E(\w+)$/ ) {
+ #
+ # User deleted entry in this array
+ #
+ delete($varValue->{$1}) if ( keys(%$varValue) > 1
+ || $type->{emptyOk} );
+ $In{deleteVar} = "";
+ }
+ if ( !$isError && !defined($type->{child})
+ && $In{addVar} eq $varName ) {
+ #
+ # User added entry to this array
+ #
+ $varValue->{$In{addVarKey}} = ""
+ if ( !defined($varValue->{$In{addVarKey}}) );
+ $In{addVar} = "";
+ }
+ my(@order, $childType);
+
+ if ( defined($type->{child}) ) {
+ @order = sort(keys(%{$type->{child}}));
+ } else {
+ @order = sort(keys(%$varValue));
+ }
+
+ foreach my $fld ( @order ) {
+ $content .= <<EOF;
+<tr><td class="border">$fld
+EOF
+ if ( !$type->{noKeyEdit}
+ && (keys(%$varValue) > 1 || $type->{emptyOk}) ) {
+ $content .= <<EOF;
+<input type="submit" name="del_${varName}_$fld" value="Delete"
+ onClick="deleteSubmit('${varName}_$fld')">
+EOF
+ }
+ if ( defined($type->{child}) ) {
+ $childType = $type->{child}{$fld};
+ } else {
+ $childType = $type->{childType};
+ #
+ # emit list of fields since they are user-defined
+ # rather than hard-coded
+ #
+ $content .= <<EOF;
+<input type="hidden" name="vflds.$varName" value="${EscHTML($fld)}">
+EOF
+ }
+ $content .= "</td>\n";
+ $content .= fieldEditBuild($childType, "${varName}_$fld",
+ $varValue->{$fld}, $errors, $level + 1, undef,
+ $isError, $onchangeSubmit,
+ $overrideVar, $overrideSet);
+ $content .= "</tr>\n";
+ }
+
+ if ( !$type->{noKeyEdit} ) {
+ $content .= <<EOF;
+<tr><td class="border" colspan="2">
+New key: <input type="text" name="addVarKey" size="20" maxlength="256" value="">
+<input type="button" name="add_$varName" value="Add" onClick="addSubmit('$varName', 1)">
+</td></tr>
+EOF
+ }
+ $content .= "</table>\n";
+ } else {
+ if ( $isError ) {
+ #
+ # If there was an error, we use the original post values
+ # in %In, rather than the parsed values in $varValue.
+ # This is so that the user's erroneous input is preserved.
+ #
+ $varValue = $In{"v_$varName"} if ( defined($In{"v_$varName"}) );
+ }
+ if ( defined($errors->{$varName}) ) {
+ $content .= <<EOF;
+$errors->{$varName}<br>
+EOF
+ delete($errors->{$varName});
+ }
+ my $onChange;
+ if ( defined($overrideVar) ) {
+ $onChange .= "checkboxSet('$overrideVar');";
+ } else {
+ $onChange .= "varChange('$overrideVar');";
+ }
+ if ( $onchangeSubmit ) {
+ $onChange .= "document.form1.submit();";
+ }
+ if ( $onChange ne "" ) {
+ $onChange = " onChange=\"$onChange\"";
+ }
+ if ( $varValue !~ /\n/ &&
+ ($type->{type} eq "integer"
+ || $type->{type} eq "string"
+ || $type->{type} eq "shortlist"
+ || $type->{type} eq "float") ) {
+ # simple input box
+ if ( $type->{type} eq "shortlist" ) {
+ $varValue = [$varValue] if ( ref($varValue) ne "ARRAY" );
+ $varValue = join(", ", @$varValue);
+ }
+ $content .= <<EOF;
+<input type="text" name="v_$varName" size="$size" maxlength="256" value="${EscHTML($varValue)}"$onChange>
+EOF
+ } elsif ( $type->{type} eq "boolean" ) {
+ # checkbox
+ my $checked = "checked" if ( $varValue );
+ $content .= <<EOF;
+<input type="checkbox" name="v_$varName" $checked value="1">
+EOF
+ } elsif ( $type->{type} eq "select" ) {
+ $content .= <<EOF;
+<select name="v_$varName"$onChange>
+EOF
+ foreach my $option ( @{$type->{values}} ) {
+ my $sel = " selected" if ( $varValue eq $option );
+ $content .= "<option$sel>$option</option>\n";
+ }
+ $content .= "</select>\n";
+ } else {
+ # multi-line text area - count number of lines
+ my $rowCnt = $varValue =~ tr/\n//;
+ $rowCnt = 1 if ( $rowCnt < 1 );
+ $content .= <<EOF;
+<textarea name="v_$varName" cols="$size" rows="$rowCnt"$onChange>${EscHTML($varValue)}</textarea>
+EOF
+ }
+ }
+ $content .= "</td>\n";
+ return $content;
+}
+
+sub errorCheck
+{
+ my $errors = {};
+
+ foreach my $param ( keys(%ConfigMeta) ) {
+ fieldErrorCheck($ConfigMeta{$param}, $param, $errors);
+ }
+ return $errors;
+}
+
+sub fieldErrorCheck
+{
+ my($type, $varName, $errors) = @_;
+
+ $type = { type => $type } if ( ref($type) ne "HASH" );
+
+ if ( $type->{type} eq "list" ) {
+ for ( my $i = 0 ; ; $i++ ) {
+ last if ( fieldErrorCheck($type->{child}, "${varName}_$i", $errors) );
+ }
+ } elsif ( $type->{type} eq "hash" ) {
+ my(@order, $childType);
+ my $ret;
+
+ if ( defined($type->{child}) ) {
+ @order = sort(keys(%{$type->{child}}));
+ } else {
+ @order = split(/\0/, $In{"vflds.$varName"});
+ }
+ foreach my $fld ( @order ) {
+ if ( defined($type->{child}) ) {
+ $childType = $type->{child}{$fld};
+ } else {
+ $childType = $type->{childType};
+ }
+ $ret ||= fieldErrorCheck($childType, "${varName}_$fld", $errors);
+ }
+ return $ret;
+ } else {
+ return 1 if ( !exists($In{"v_$varName"}) );
+
+ if ( $type->{type} eq "integer"
+ || $type->{type} eq "boolean" ) {
+ if ( $In{"v_$varName"} !~ /^-?\d+\s*$/s
+ && $In{"v_$varName"} ne "" ) {
+ $errors->{$varName} = "Error: $varName must be an integer";
+ }
+ } elsif ( $type->{type} eq "float" ) {
+ if ( $In{"v_$varName"} !~ /^-?\d*(\.\d*)?\s*$/s
+ && $In{"v_$varName"} ne "" ) {
+ $errors->{$varName}
+ = "Error: $varName must be a real-valued number";
+ }
+ } elsif ( $type->{type} eq "shortlist" ) {
+ my @vals = split(/[,\s]+/, $In{"v_$varName"});
+ for ( my $i = 0 ; $i < @vals ; $i++ ) {
+ if ( $type->{child} eq "integer"
+ && $vals[$i] !~ /^-?\d+\s*$/s
+ && $vals[$i] ne "" ) {
+ my $k = $i + 1;
+ $errors->{$varName} = "Error: $varName entry $k must"
+ . " be an integer";
+ } elsif ( $type->{child} eq "float"
+ && $vals[$i] !~ /^-?\d*(\.\d*)?\s*$/s
+ && $vals[$i] ne "" ) {
+ my $k = $i + 1;
+ $errors->{$varName} = "Error: $varName entry $k must"
+ . " be a real-valued number";
+ }
+ }
+ } elsif ( $type->{type} eq "select" ) {
+ my $match = 0;
+ foreach my $option ( @{$type->{values}} ) {
+ if ( $In{"v_$varName"} eq $option ) {
+ $match = 1;
+ last;
+ }
+ }
+ $errors->{$varName} = "Error: $varName must be a valid option"
+ if ( !$match );
+ } else {
+ #
+ # $type->{type} eq "string": no error checking
+ #
+ }
+ }
+ return 0;
+}
+
+sub inputParse
+{
+ my($bpc, $userHost) = @_;
+ my $conf = {};
+ my $override = {};
+
+ foreach my $param ( keys(%ConfigMeta) ) {
+ my $value;
+ next if ( $userHost && !$bpc->{Conf}{CgiUserConfigEdit}{$param} );
+ fieldInputParse($ConfigMeta{$param}, $param, \$value);
+ $conf->{$param} = $value;
+ $override->{$param} = $In{"override_$param"};
+}
+ return ($conf, $override);
+}
+
+sub fieldInputParse
+{
+ my($type, $varName, $value) = @_;
+
+ $type = { type => $type } if ( ref($type) ne "HASH" );
+
+ if ( $type->{type} eq "list" ) {
+ $$value = [];
+ for ( my $i = 0 ; ; $i++ ) {
+ my $val;
+ last if ( fieldInputParse($type->{child}, "${varName}_$i", \$val) );
+ push(@$$value, $val);
+ }
+ $$value = undef if ( $type->{undefIfEmpty} && @$$value == 0 );
+ } elsif ( $type->{type} eq "hash" ) {
+ my(@order, $childType);
+ my $ret;
+ $$value = {};
+
+ if ( defined($type->{child}) ) {
+ @order = sort(keys(%{$type->{child}}));
+ } else {
+ @order = split(/\0/, $In{"vflds.$varName"});
+ }
+
+ foreach my $fld ( @order ) {
+ my $val;
+ if ( defined($type->{child}) ) {
+ $childType = $type->{child}{$fld};
+ } else {
+ $childType = $type->{childType};
+ }
+ $ret ||= fieldInputParse($childType, "${varName}_$fld", \$val);
+ last if ( $ret );
+ $$value->{$fld} = $val;
+ }
+ return $ret;
+ } else {
+ if ( $type->{type} eq "boolean" ) {
+ $$value = 0 + $In{"v_$varName"};
+ } elsif ( !exists($In{"v_$varName"}) ) {
+ return 1;
+ }
+
+ if ( $type->{type} eq "integer" ) {
+ $$value = 0 + $In{"v_$varName"};
+ } elsif ( $type->{type} eq "float" ) {
+ $$value = 0 + $In{"v_$varName"};
+ } elsif ( $type->{type} eq "shortlist" ) {
+ $$value = [split(/[,\s]+/, $In{"v_$varName"})];
+ if ( $type->{child} eq "float"
+ || $type->{child} eq "integer"
+ || $type->{child} eq "boolean" ) {
+ foreach ( @$$value ) {
+ $_ += 0;
+ }
+ }
+ } else {
+ $$value = $In{"v_$varName"};
+ }
+ $$value = undef if ( $type->{undefIfEmpty} && $$value eq "" );
+ }
+ return 0;
+}
+
+sub configDiffMesg
+{
+ my($host, $oldConf, $newConf) = @_;
+ my $mesg;
+ my $conf;
+
+ if ( $host ne "" ) {
+ $conf = "host $host config";
+ } else {
+ $conf = "main config";
+ }
+
+ foreach my $p ( keys(%ConfigMeta) ) {
+ if ( !exists($oldConf->{$p}) && !exists($newConf->{$p}) ) {
+ next;
+ } elsif ( exists($oldConf->{$p}) && !exists($newConf->{$p}) ) {
+ $mesg .= "log Deleted $p from $conf\n";
+ } elsif ( !exists($oldConf->{$p}) && exists($newConf->{$p}) ) {
+ my $dump = Data::Dumper->new([$newConf->{$p}]);
+ $dump->Indent(0);
+ $dump->Sortkeys(1);
+ $dump->Terse(1);
+ my $value = $dump->Dump;
+ $mesg .= "log Added $p to $conf, set to $value\n";
+ } else {
+ my $dump = Data::Dumper->new([$newConf->{$p}]);
+ $dump->Indent(0);
+ $dump->Sortkeys(1);
+ $dump->Terse(1);
+ my $valueNew = $dump->Dump;
+
+ my $v = $oldConf->{$p};
+ if ( ref($newConf->{$p}) eq "ARRAY" && ref($v) eq "" ) {
+ $v = [$v];
+ }
+ $dump = Data::Dumper->new([$v]);
+ $dump->Indent(0);
+ $dump->Sortkeys(1);
+ $dump->Terse(1);
+ my $valueOld = $dump->Dump;
+
+ $mesg .= "log Changed $p in $conf to $valueNew from $valueOld\n"
+ if ( $valueOld ne $valueNew );
+ }
+ }
+ return $mesg;
+}
+
+1;
--- /dev/null
+#============================================================= -*-perl-*-
+#
+# BackupPC::Config::Meta package
+#
+# DESCRIPTION
+#
+# This library defines a BackupPC::Config::Meta class.
+#
+# AUTHOR
+# Craig Barratt <cbarratt@users.sourceforge.net>
+#
+# COPYRIGHT
+# Copyright (C) 2004 Craig Barratt
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+#========================================================================
+#
+# Version 2.1.0, released 20 Jun 2004.
+#
+# See http://backuppc.sourceforge.net.
+#
+#========================================================================
+
+package BackupPC::Config::Meta;
+
+use strict;
+
+require Exporter;
+
+use vars qw( @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS );
+
+use vars qw(%ConfigMeta);
+
+@ISA = qw(Exporter);
+
+@EXPORT = qw( );
+
+@EXPORT_OK = qw(
+ %ConfigMeta
+ );
+
+%EXPORT_TAGS = (
+ 'all' => [ @EXPORT_OK ],
+);
+
+#
+# Define the data types for all the config variables
+#
+
+%ConfigMeta = (
+
+ ######################################################################
+ # General server configuration
+ ######################################################################
+ ServerHost => "string",
+ ServerPort => "integer",
+ ServerMesgSecret => "string",
+ MyPath => {type => "string", undefIfEmpty => 1},
+ UmaskMode => "integer",
+ WakeupSchedule => {
+ type => "shortlist",
+ child => "float",
+ },
+ MaxBackups => "integer",
+ MaxUserBackups => "integer",
+ MaxPendingCmds => "integer",
+ MaxBackupPCNightlyJobs => "integer",
+ BackupPCNightlyPeriod => "integer",
+ MaxOldLogFiles => "integer",
+
+ SshPath => {type => "string", undefIfEmpty => 1},
+ NmbLookupPath => {type => "string", undefIfEmpty => 1},
+ PingPath => {type => "string", undefIfEmpty => 1},
+ DfPath => {type => "string", undefIfEmpty => 1},
+ DfCmd => "string",
+ SplitPath => {type => "string", undefIfEmpty => 1},
+ ParPath => {type => "string", undefIfEmpty => 1},
+ CatPath => {type => "string", undefIfEmpty => 1},
+ GzipPath => {type => "string", undefIfEmpty => 1},
+ Bzip2Path => {type => "string", undefIfEmpty => 1},
+ DfMaxUsagePct => "float",
+ TrashCleanSleepSec => "integer",
+ DHCPAddressRanges => {
+ type => "list",
+ emptyOk => 1,
+ child => {
+ type => "hash",
+ noKeyEdit => 1,
+ child => {
+ ipAddrBase => "string",
+ first => "integer",
+ last => "integer",
+ },
+ },
+ },
+ BackupPCUser => "string",
+ CgiDir => "string",
+ InstallDir => "string",
+ BackupPCUserVerify => "integer",
+ HardLinkMax => "integer",
+ PerlModuleLoad => {
+ type => "list",
+ emptyOk => 1,
+ undefIfEmpty => 1,
+ child => "string",
+ },
+ ServerInitdPath => {type => "string", undefIfEmpty => 1},
+ ServerInitdStartCmd => "string",
+
+ ######################################################################
+ # What to backup and when to do it
+ # (can be overridden in the per-PC config.pl)
+ ######################################################################
+ FullPeriod => "float",
+ IncrPeriod => "float",
+ FullKeepCnt => {
+ type => "shortlist",
+ child => "integer",
+ },
+ FullKeepCntMin => "integer",
+ FullAgeMax => "float",
+ IncrKeepCnt => "integer",
+ IncrKeepCntMin => "integer",
+ IncrAgeMax => "float",
+ PartialAgeMax => "float",
+ IncrFill => "integer",
+ RestoreInfoKeepCnt => "integer",
+ ArchiveInfoKeepCnt => "integer",
+
+ BackupFilesOnly => {
+ type => "list",
+ emptyOk => 1,
+ undefIfEmpty => 1,
+ child => "string",
+ },
+ BackupFilesExclude => {
+ type => "list",
+ emptyOk => 1,
+ undefIfEmpty => 1,
+ child => "string",
+ },
+
+ BlackoutBadPingLimit => "integer",
+ BlackoutGoodCnt => "integer",
+ BlackoutPeriods => {
+ type => "list",
+ emptyOk => 1,
+ child => {
+ type => "hash",
+ noKeyEdit => 1,
+ child => {
+ hourBegin => "float",
+ hourEnd => "float",
+ weekDays => {
+ type => "shortlist",
+ child => "integer",
+ },
+ },
+ },
+ },
+
+ BackupZeroFilesIsFatal => "integer",
+
+ ######################################################################
+ # How to backup a client
+ ######################################################################
+ XferMethod => {
+ type => "select",
+ values => [qw(archive rsync rsyncd smb tar)],
+ },
+ XferLogLevel => "integer",
+
+ SmbShareName => {
+ type => "list",
+ child => "string",
+ },
+ SmbShareUserName => "string",
+ SmbSharePasswd => "string",
+ SmbClientPath => {type => "string", undefIfEmpty => 1},
+ SmbClientFullCmd => "string",
+ SmbClientIncrCmd => "string",
+ SmbClientRestoreCmd => "string",
+
+ TarShareName => {
+ type => "list",
+ child => "string",
+ },
+ TarClientCmd => "string",
+ TarFullArgs => "string",
+ TarIncrArgs => "string",
+ TarClientRestoreCmd => "string",
+ TarClientPath => {type => "string", undefIfEmpty => 1},
+
+ RsyncShareName => {
+ type => "list",
+ child => "string",
+ },
+ RsyncClientPath => {type => "string", undefIfEmpty => 1},
+ RsyncClientCmd => "string",
+ RsyncClientRestoreCmd => "string",
+
+ RsyncdClientPort => "integer",
+ RsyncdPasswd => "string",
+ RsyncdAuthRequired => "integer",
+
+ RsyncCsumCacheVerifyProb => "float",
+ RsyncArgs => {
+ type => "list",
+ emptyOk => 1,
+ child => "string",
+ },
+ RsyncRestoreArgs => {
+ type => "list",
+ emptyOk => 1,
+ child => "string",
+ },
+
+ ArchiveDest => "string",
+ ArchiveComp => {
+ type => "select",
+ values => [qw(none bzip2 gzip)],
+ },
+ ArchivePar => "integer",
+ ArchiveSplit => "float",
+ ArchiveClientCmd => "string",
+
+ NmbLookupCmd => "string",
+ NmbLookupFindHostCmd => "string",
+
+ FixedIPNetBiosNameCheck => "integer",
+ PingCmd => "string",
+ PingMaxMsec => "float",
+
+ ClientTimeout => "integer",
+
+ MaxOldPerPCLogFiles => "integer",
+
+ CompressLevel => "integer",
+
+ DumpPreUserCmd => {type => "string", undefIfEmpty => 1},
+ DumpPostUserCmd => {type => "string", undefIfEmpty => 1},
+ DumpPreShareCmd => {type => "string", undefIfEmpty => 1},
+ DumpPostShareCmd => {type => "string", undefIfEmpty => 1},
+ RestorePreUserCmd => {type => "string", undefIfEmpty => 1},
+ RestorePostUserCmd => {type => "string", undefIfEmpty => 1},
+ ArchivePreUserCmd => {type => "string", undefIfEmpty => 1},
+ ArchivePostUserCmd => {type => "string", undefIfEmpty => 1},
+
+ ClientNameAlias => {type => "string", undefIfEmpty => 1},
+
+ ######################################################################
+ # Email reminders, status and messages
+ # (can be overridden in the per-PC config.pl)
+ ######################################################################
+ SendmailPath => {type => "string", undefIfEmpty => 1},
+ EMailNotifyMinDays => "float",
+ EMailFromUserName => "string",
+ EMailAdminUserName => "string",
+ EMailUserDestDomain => "string",
+ EMailNoBackupEverSubj => {type => "string", undefIfEmpty => 1},
+ EMailNoBackupEverMesg => {type => "bigstring", undefIfEmpty => 1},
+ EMailNotifyOldBackupDays => "float",
+ EMailNoBackupRecentSubj => {type => "string", undefIfEmpty => 1},
+ EMailNoBackupRecentMesg => {type => "bigstring", undefIfEmpty => 1},
+ EMailNotifyOldOutlookDays => "float",
+ EMailOutlookBackupSubj => {type => "string", undefIfEmpty => 1},
+ EMailOutlookBackupMesg => {type => "bigstring", undefIfEmpty => 1},
+
+ ######################################################################
+ # CGI user interface configuration settings
+ ######################################################################
+ CgiAdminUserGroup => "string",
+ CgiAdminUsers => "string",
+ CgiURL => "string",
+ Language => "string",
+ CgiUserHomePageCheck => "string",
+ CgiUserUrlCreate => "string",
+ CgiDateFormatMMDD => "integer",
+ CgiNavBarAdminAllHosts => "integer",
+ CgiSearchBoxEnable => "integer",
+ CgiNavBarLinks => {
+ type => "list",
+ emptyOk => 1,
+ child => {
+ type => "hash",
+ noKeyEdit => 1,
+ child => {
+ link => "string",
+ lname => {type => "string", undefIfEmpty => 1},
+ name => {type => "string", undefIfEmpty => 1},
+ },
+ },
+ },
+ CgiStatusHilightColor => {
+ type => "hash",
+ noKeyEdit => 1,
+ child => {
+ Reason_backup_failed => "string",
+ Reason_backup_done => "string",
+ Reason_no_ping => "string",
+ Reason_backup_canceled_by_user => "string",
+ Status_backup_in_progress => "string",
+ },
+ },
+ CgiHeaders => "bigstring",
+ CgiImageDir => "string",
+ CgiExt2ContentType => {
+ type => "hash",
+ emptyOk => 1,
+ childType => "string",
+ },
+ CgiImageDirURL => "string",
+ CgiCSSFile => "string",
+ CgiUserConfigEdit => {
+ type => "hash",
+ noKeyEdit => 1,
+ child => {
+ FullPeriod => "boolean",
+ IncrPeriod => "boolean",
+ FullKeepCnt => "boolean",
+ FullKeepCntMin => "boolean",
+ FullAgeMax => "boolean",
+ IncrKeepCnt => "boolean",
+ IncrKeepCntMin => "boolean",
+ IncrAgeMax => "boolean",
+ PartialAgeMax => "boolean",
+ IncrFill => "boolean",
+ RestoreInfoKeepCnt => "boolean",
+ ArchiveInfoKeepCnt => "boolean",
+ BackupFilesOnly => "boolean",
+ BackupFilesExclude => "boolean",
+ BlackoutBadPingLimit => "boolean",
+ BlackoutGoodCnt => "boolean",
+ BlackoutPeriods => "boolean",
+ BackupZeroFilesIsFatal => "boolean",
+ XferMethod => "boolean",
+ XferLogLevel => "boolean",
+ SmbShareName => "boolean",
+ SmbShareUserName => "boolean",
+ SmbSharePasswd => "boolean",
+ TarShareName => "boolean",
+ TarFullArgs => "boolean",
+ TarIncrArgs => "boolean",
+ RsyncShareName => "boolean",
+ RsyncdClientPort => "boolean",
+ RsyncdPasswd => "boolean",
+ RsyncdAuthRequired => "boolean",
+ RsyncCsumCacheVerifyProb => "boolean",
+ RsyncArgs => "boolean",
+ RsyncRestoreArgs => "boolean",
+ ArchiveDest => "boolean",
+ ArchiveComp => "boolean",
+ ArchivePar => "boolean",
+ ArchiveSplit => "boolean",
+ FixedIPNetBiosNameCheck => "boolean",
+ PingMaxMsec => "boolean",
+ ClientTimeout => "boolean",
+ MaxOldPerPCLogFiles => "boolean",
+ CompressLevel => "boolean",
+ ClientNameAlias => "boolean",
+ EMailNotifyMinDays => "boolean",
+ EMailFromUserName => "boolean",
+ EMailAdminUserName => "boolean",
+ EMailUserDestDomain => "boolean",
+ EMailNoBackupEverSubj => "boolean",
+ EMailNoBackupEverMesg => "boolean",
+ EMailNotifyOldBackupDays => "boolean",
+ EMailNoBackupRecentSubj => "boolean",
+ EMailNoBackupRecentMesg => "boolean",
+ EMailNotifyOldOutlookDays => "boolean",
+ EMailOutlookBackupSubj => "boolean",
+ EMailOutlookBackupMesg => "boolean",
+ },
+ },
+);
+
+1;
--- /dev/null
+#!/usr/bin/perl
+#
+# By Reginaldo Ferreira <reginaldo@lepper.com.br> (23.07.2004 for V2.1.10)
+#
+
+#my %lang;
+
+#use strict;
+
+# --------------------------------
+
+$Lang{Start_Archive} = "Iniciar backup";
+$Lang{Stop_Dequeue_Archive} = "Parar/anular backup";
+$Lang{Start_Full_Backup} = "Iniciar Backup Completa";
+$Lang{Start_Incr_Backup} = "Iniciar Backup Incremental";
+$Lang{Stop_Dequeue_Backup} = "Parar/Anular Backup";
+$Lang{Restore} = "Restaurar";
+
+$Lang{Type_full} = "completo";
+$Lang{Type_incr} = "incremental";
+
+# -----
+
+$Lang{Only_privileged_users_can_view_admin_options} = "Somente superusuarios podem ver as opções de administração.";
+$Lang{H_Admin_Options} = "Servidor BackupPC: Opções de administração";
+$Lang{Admin_Options} = "Opções de administração";
+$Lang{Admin_Options_Page} = <<EOF;
+\${h1(qq{$Lang{Admin_Options}})}
+<br>
+\${h2("Controle do Servidor")}
+<form action="\$MyURL" method="get">
+<table class="tableStnd">
+<!--<tr><td>Parar o servidor:<td><input type="submit" name="action" value="Stop">-->
+ <tr><td>Atualizar configurações do servidor:<td><input type="submit" name="action" value="Reload">
+</table>
+</form>
+<!--
+\${h2("Server Configuration")}
+<ul>
+ <li><i>Espaço para outras opções... e.j.,</i>
+ <li>Editar configurações do servidor
+</ul>
+-->
+EOF
+$Lang{Unable_to_connect_to_BackupPC_server} = "Impossível conectar ao servidor BackupPC",
+ "Este script CGI (\$MyURL) não pode conectar-se ao servidor BackupPC"
+ . " em \$Conf{ServerHost} porta \$Conf{ServerPort}. O erro"
+ . " foi: \$err.",
+ "Talvez o servidor BackupPC não está ativo ou existe um "
+ . " erro de configuração. Por favor informe seu administrador de sistemas.";
+$Lang{Admin_Start_Server} = <<EOF;
+\${h1(qq{$Lang{Unable_to_connect_to_BackupPC_server}})}
+<form action="\$MyURL" method="get">
+O servidor BackupPC em <tt>\$Conf{ServerHost}</tt> port <tt>\$Conf{ServerPort}</tt>
+não está iniciando (pode ter parado ou não ainda não iniciado).<br>
+Deseja inicia-lo agora?
+<input type="hidden" name="action" value="startServer">
+<input type="submit" value="Start Server" name="ignore">
+</form>
+EOF
+
+# -----
+
+$Lang{H_BackupPC_Server_Status} = "Estado do Servidor BackupPC";
+
+$Lang{BackupPC_Server_Status_General_Info}= <<EOF;
+\${h2(\"Informações Gerais do servidor\")}
+
+<ul>
+<li> O PID do servidor é \$Info{pid}, no host \$Conf{ServerHost},
+ versão \$Info{Version}, iniciado em \$serverStartTime.
+<li> Esta informação de estado foi gerada em \$now.
+<li> A última configuração foi carregada às \$configLoadTime
+<li> A fila de PCs se ativará novamente em \$nextWakeupTime.
+<li> Informações adicionais:
+ <ul>
+ <li>\$numBgQueue solicitações de backup pendentes desde a última ativação programada,
+ <li>\$numUserQueue solicitações de backup de usuarios,
+ <li>\$numCmdQueue solicitações de comandos pendentes,
+ \$poolInfo
+ <li>O sistema de arquivos estava recentemente em \$Info{DUlastValue}%
+ (\$DUlastTime), o máximo de hoje é \$Info{DUDailyMax}% (\$DUmaxTime)
+ e o máximo de ontem foi \$Info{DUDailyMaxPrev}%.
+ </ul>
+</ul>
+EOF
+
+$Lang{BackupPC_Server_Status} = <<EOF;
+\${h1(qq{$Lang{H_BackupPC_Server_Status}})}
+
+<p>
+\$generalInfo
+
+\${h2("Trabalhos em Execução")}
+<p>
+<table class="tableStnd" border cellspacing="1" cellpadding="3">
+<tr class="tableheader"><td> Host </td>
+ <td> Tipo </td>
+ <td> Usuario </td>
+ <td> Hora de Inicio </td>
+ <td> Comando </td>
+ <td align="center"> PID </td>
+ <td align="center"> Transfer. PID </td>
+ </tr>
+\$jobStr
+</table>
+<p>
+
+\${h2("Falhas que Precisam de Atenção")}
+<p>
+<table class="tableStnd" border cellspacing="1" cellpadding="3">
+<tr class="tableheader"><td align="center"> Host </td>
+ <td align="center"> Tipo </td>
+ <td align="center"> Usuario </td>
+ <td align="center"> Ultima Tentativa </td>
+ <td align="center"> Detalhes </td>
+ <td align="center"> Hora do erro </td>
+ <td> Último erro (ping não incluido) </td></tr>
+\$statusStr
+</table>
+EOF
+
+# --------------------------------
+$Lang{BackupPC__Server_Summary} = "BackupPC: Resumo do Servidor";
+$Lang{BackupPC__Archive} = "BackupPC: Archive";
+$Lang{BackupPC_Summary}=<<EOF;
+
+\${h1(qq{$Lang{BackupPC__Server_Summary}})}
+<p>
+Este status foi generado em \$now.
+</p>
+
+\${h2("Hosts com Backups Completos")}
+<p>
+Existem \$hostCntGood hosts com backup, de um total de :
+<ul>
+<li> \$fullTot backups com tamanho total de \${fullSizeTot} GB
+ (antes de agrupar e comprimir),
+<li> \$incrTot backups incrementais com tamanho total de \${incrSizeTot} GB
+ (antes de agrupar e comprimir).
+</ul>
+</p>
+<table class="tableStnd" border cellpadding="3" cellspacing="1">
+<tr class="tableheader"><td> Host </td>
+ <td align="center"> Usuario </td>
+ <td align="center"> #Completo </td>
+ <td align="center"> Completo Antig./Dias </td>
+ <td align="center"> Completo Tamanho/GB </td>
+ <td align="center"> Velocidade MB/sec </td>
+ <td align="center"> #Incrementais </td>
+ <td align="center"> Incrementais Antig/Dias </td>
+ <td align="center"> Estado </td>
+ <td align="center"> Última Tentativa </td></tr>
+\$strGood
+</table>
+<br><br>
+\${h2("Hosts Sem Backups")}
+<p>
+Existem \$hostCntNone hosts sem backups.
+<p>
+<table class="tableStnd" border cellpadding="3" cellspacing="1">
+<tr class="tableheader"><td> Host </td>
+ <td align="center"> Usuario </td>
+ <td align="center"> #Completo </td>
+ <td align="center"> Completo Antig./Dias </td>
+ <td align="center"> Completo Tamanho/GB </td>
+ <td align="center"> Velocidade MB/sec </td>
+ <td align="center"> #Incrementais </td>
+ <td align="center"> Incrementais Antig/Dias </td>
+ <td align="center"> Estado </td>
+ <td align="center"> Última tentativa </td></tr>
+\$strNone
+</table>
+EOF
+
+$Lang{BackupPC_Archive} = <<EOF;
+\${h1(qq{$Lang{BackupPC__Archive}})}
+<script language="javascript" type="text/javascript">
+<!--
+
+ function checkAll(location)
+ {
+ for (var i=0;i<document.form1.elements.length;i++)
+ {
+ var e = document.form1.elements[i];
+ if ((e.checked || !e.checked) && e.name != \'all\') {
+ if (eval("document.form1."+location+".checked")) {
+ e.checked = true;
+ } else {
+ e.checked = false;
+ }
+ }
+ }
+ }
+
+ function toggleThis(checkbox)
+ {
+ var cb = eval("document.form1."+checkbox);
+ cb.checked = !cb.checked;
+ }
+
+//-->
+</script>
+
+Hay \$hostCntGood hosts que possuem backup com tamanho total de \${fullSizeTot}GB
+<p>
+<form name="form1" method="post" action="\$MyURL">
+<input type="hidden" name="fcbMax" value="\$checkBoxCnt">
+<input type="hidden" name="type" value="1">
+<input type="hidden" name="host" value="\${EscHTML(\$archHost)}">
+<input type="hidden" name="action" value="Archive">
+<table class="tableStnd" border cellpadding="3" cellspacing="1">
+<tr class="tableheader"><td align=center> Host</td>
+ <td align="center"> Usuário </td>
+ <td align="center"> Tamanho Backup </td>
+\$strGood
+\$checkAllHosts
+</table>
+</form>
+<p>
+
+EOF
+
+$Lang{BackupPC_Archive2} = <<EOF;
+\${h1(qq{$Lang{BackupPC__Archive}})}
+Sobre o Backup dos seguintes Hosts
+<ul>
+\$HostListStr
+</ul>
+<form action="\$MyURL" method="post">
+\$hiddenStr
+<input type="hidden" name="action" value="Archive">
+<input type="hidden" name="host" value="\${EscHTML(\$archHost)}">
+<input type="hidden" name="type" value="2">
+<input type="hidden" value="0" name="archive_type">
+<table class="tableStnd" border cellspacing="1" cellpadding="3">
+\$paramStr
+<tr>
+ <td colspan=2><input type="submit" value="Iniciar Archive" name=""></td>
+</tr>
+</form>
+</table>
+EOF
+
+$Lang{BackupPC_Archive2_location} = <<EOF;
+<tr>
+ <td>Archive Localização/Dispositivo</td>
+ <td><input type="text" value="\$ArchiveDest" name="archive_device"></td>
+</tr>
+EOF
+
+$Lang{BackupPC_Archive2_compression} = <<EOF;
+<tr>
+ <td>Compression</td>
+ <td>
+ <input type="radio" value="0" name="compression" \$ArchiveCompNone>None<br>
+ <input type="radio" value="1" name="compression" \$ArchiveCompGzip>gzip<br>
+ <input type="radio" value="2" name="compression" \$ArchiveCompBzip2>bzip2
+ </td>
+</tr>
+EOF
+
+$Lang{BackupPC_Archive2_parity} = <<EOF;
+<tr>
+ <td>Porcentagem de dados de paridade (0 = desabilitado, 5 = normal)</td>
+ <td><input type="numeric" value="\$ArchivePar" name="par"></td>
+</tr>
+EOF
+
+$Lang{BackupPC_Archive2_split} = <<EOF;
+<tr>
+ <td>Dividir resultado em</td>
+ <td><input type="numeric" value="\$ArchiveSplit" name="splitsize">Megabytes</td>
+</tr>
+EOF
+
+# -----------------------------------
+$Lang{Pool_Stat} = <<EOF;
+ <li>O pool de \${poolSize}GB compreende \$info->{"\${name}FileCnt"} arquivos
+ e \$info->{"\${name}DirCnt"} diretórios (as of \$poolTime),
+ <li>O processamento do pool é de \$info->{"\${name}FileCntRep"} arquivos
+ repetidos cuja cadeia maior é \$info->{"\${name}FileRepMax"},
+ <li>O processo de limpeza noturna eliminou \$info->{"\${name}FileCntRm"} arquivos de
+ \${poolRmSize}GB (around \$poolTime),
+EOF
+
+# --------------------------------
+$Lang{BackupPC__Backup_Requested_on__host} = "BackupPC: Solicitação de Backup por \$host";
+# --------------------------------
+$Lang{REPLY_FROM_SERVER} = <<EOF;
+\${h1(\$str)}
+<p>
+A resposta do servidor foi: \$reply
+<p>
+Voltar a <a href="\$MyURL?host=\$host">\$host home page</a>.
+EOF
+# --------------------------------
+$Lang{BackupPC__Start_Backup_Confirm_on__host} = "BackupPC: Confirme inicio do backup em \$host";
+# --------------------------------
+$Lang{Are_you_sure_start} = <<EOF;
+\${h1("Tem certeza?")}
+<p>
+Iniciando Backup \$type em \$host.
+
+<form action="\$MyURL" method="get">
+<input type="hidden" name="host" value="\$host">
+<input type="hidden" name="hostIP" value="\$ipAddr">
+<input type="hidden" name="doit" value="1">
+Tem certeza desta ação?
+<input type="submit" value="\$In{action}" name="action">
+<input type="submit" value="No" name="">
+</form>
+EOF
+# --------------------------------
+$Lang{BackupPC__Stop_Backup_Confirm_on__host} = "BackupPC: Confirmação de Parada do Backup \$host";
+# --------------------------------
+$Lang{Are_you_sure_stop} = <<EOF;
+
+\${h1("Tem certeza?")}
+
+<p>
+Você está certo de parar/sair da fila de backup em \$host;
+
+<form action="\$MyURL" method="get">
+<input type="hidden" name="host" value="\$host">
+<input type="hidden" name="doit" value="1">
+Assim mesmo, por favor não impessa outro backup durante
+<input type="text" name="backoff" size="10" value="\$backoff"> horas.
+<p>
+Tem certeza de que quer fazer isto?
+<input type="submit" value="\$In{action}" name="action">
+<input type="submit" value="No" name="">
+</form>
+
+EOF
+# --------------------------------
+$Lang{Only_privileged_users_can_view_queues_} = "Somente administradores podem ver as filas.";
+# --------------------------------
+$Lang{Only_privileged_users_can_archive} = "Somente administradores podem arquivar.";
+# --------------------------------
+$Lang{BackupPC__Queue_Summary} = "BackupPC: Resumo da Fila de Backup";
+# --------------------------------
+$Lang{Backup_Queue_Summary} = <<EOF;
+\${h1("Resumo da Fila de Backup")}
+<br><br>
+\${h2("Resumo da Fila de Usuários")}
+<p>
+As seguintes solicitações de usuários estão atualmente em fila:
+</p>
+<table class="tableStnd" border cellspacing="1" cellpadding="3" width="80%">
+<tr class="tableheader"><td> Host </td>
+ <td> Hora Sol. </td>
+ <td> Usuário </td></tr>
+\$strUser
+</table>
+<br><br>
+
+\${h2("Resumo da Fila em Segundo Plano")}
+<p>
+As seguintes solicitações em segundo plano estão atualmente em fila:
+</p>
+<table class="tableStnd" border cellspacing="1" cellpadding="3" width="80%">
+<tr class="tableheader"><td> Host </td>
+ <td> Hora Sol. </td>
+ <td> Usuário </td></tr>
+\$strBg
+</table>
+<br><br>
+\${h2("Resumo da Fila de Comandos")}
+<p>
+Os seguintes comandos estão atualmente em fila:
+</p>
+<table class="tableStnd" border cellspacing="1" cellpadding="3" width="80%">
+<tr class="tableheader"><td> Host </td>
+ <td> Hora Sol. </td>
+ <td> Usuário </td>
+ <td> Comando </td></tr>
+\$strCmd
+</table>
+EOF
+
+# --------------------------------
+$Lang{Backup_PC__Log_File__file} = "BackupPC: LOG de Registro \$file";
+$Lang{Log_File__file__comment} = <<EOF;
+\${h1("Log File \$file \$comment")}
+<p>
+EOF
+# --------------------------------
+$Lang{Contents_of_log_file} = <<EOF;
+Conteúdo do log de registro <tt>\$file</tt>, modificado \$mtimeStr \$comment
+EOF
+
+# --------------------------------
+$Lang{skipped__skipped_lines} = "[ saltadas \$skipped linhas ]\n";
+# --------------------------------
+$Lang{_pre___Can_t_open_log_file__file} = "<pre>\nNão pode-se abrir o LOG de registro \$file\n";
+
+# --------------------------------
+$Lang{BackupPC__Log_File_History} = "BackupPC: Histórico dos Logs de Registro";
+$Lang{Log_File_History__hdr} = <<EOF;
+\${h1("Histórico do Log de Registro \$hdr")}
+<p>
+<table class="tableStnd" border cellspacing="1" cellpadding="3" width="80%">
+<tr class="tableheader"><td align="center"> File </td>
+ <td align="center"> Tamanho </td>
+ <td align="center"> Hora Modificação </td></tr>
+\$str
+</table>
+EOF
+
+# -------------------------------
+$Lang{Recent_Email_Summary} = <<EOF;
+\${h1("Resumo de Emails Recentes (Ordem cronológica invertida)")}
+<p>
+<table class="tableStnd" border cellspacing="1" cellpadding="3" width="80%">
+<tr class="tableheader"><td align="center"> Destinatário </td>
+ <td align="center"> Host </td>
+ <td align="center"> Hora </td>
+ <td align="center"> Assunto </td></tr>
+\$str
+</table>
+EOF
+
+
+# ------------------------------
+$Lang{Browse_backup__num_for__host} = "BackupPC: Explorar Backup \$num de \$host";
+
+# ------------------------------
+$Lang{Restore_Options_for__host} = "BackupPC: Opções de restauração para \$host";
+$Lang{Restore_Options_for__host2} = <<EOF;
+\${h1("Opções de restauração para \$host")}
+<p>
+Foi selecionado os seguintes arquivos/diretórios
+da unidade \$share, cópia número #\$num:
+<ul>
+\$fileListStr
+</ul>
+</p><p>
+Existem três opções para restaurar estes arquivos/diretórios.
+Por favor, selecione uma das seguintes opções.
+</p>
+\${h2("Opção 1: Restauração Direta")}
+<p>
+EOF
+
+$Lang{Restore_Options_for__host_Option1} = <<EOF;
+É possível iniciar um processo que restaurará estes arquivos diretamente em
+\$host.
+</p><p>
+<b>Atenção!:</b> Qualquer arquivo existente com o mesmo nome que o que está
+selecionado será sobrescrito!
+</p>
+<form action="\$MyURL" method="post" name="direct">
+<input type="hidden" name="host" value="\${EscHTML(\$host)}">
+<input type="hidden" name="num" value="\$num">
+<input type="hidden" name="type" value="3">
+\$hiddenStr
+<input type="hidden" value="\$In{action}" name="action">
+<table border="0">
+<tr>
+ <td>Restaurar os arquivos no host</td>
+ <td><!--<input type="text" size="40" value="\${EscHTML(\$host)}"
+ name="hostDest">-->
+ <select name="hostDest" onChange="document.direct.shareDest.value=''">
+ \$hostDestSel
+ </select>
+ <script language="Javascript">
+ function myOpen(URL) {
+ window.open(URL,'','width=500,height=400');
+ }
+ </script>
+ <!--<a href="javascript:myOpen('\$MyURL?action=findShares&host='+document.direct.hostDest.options.value)">Search for available shares (NOT IMPLEMENTED)</a>--></td>
+</tr><tr>
+ <td>Restaurar os arquivos na unidade</td>
+ <td><input type="text" size="40" value="\${EscHTML(\$share)}"
+ name="shareDest"></td>
+</tr><tr>
+ <td>Restaurar os arquivos abaixo no diretório<br>(relativo a unidade)</td>
+ <td valign="top"><input type="text" size="40" maxlength="256"
+ value="\${EscHTML(\$pathHdr)}" name="pathHdr"></td>
+</tr><tr>
+ <td><input type="submit" value="Iniciar Restauração" name=""></td>
+</table>
+</form>
+EOF
+
+$Lang{Restore_Options_for__host_Option1_disabled} = <<EOF;
+Se a restauração direta foi desabilitada para o host \${EscHTML(\$hostDest)}.
+Por favor selecione uma das outras opções de restauração.
+EOF
+
+# ------------------------------
+$Lang{Option_2__Download_Zip_archive} = <<EOF;
+<p>
+\${h2("Opção 2: Criar arquivo Zip")}
+<p>
+Pode-se criar um arquivo comprimido (.zip) contendo todos os arquivos e diretórios que
+foram selecionados. Depois pode-se utilizar uma aplicação local, como WinZip,
+para ver ou extrair os arquivos.
+</p><p>
+<b>Atenção!:</b> Dependendo de quais arquivos/pastas tenham sido selecionados,
+este arquivo pode ser muito grande. Poderia demorar muitos minutos para
+criar e transferir o arquivo. Também necessitará suficiente espaçio em disco
+local para armazená-lo.
+</p>
+<form action="\$MyURL" method="post">
+<input type="hidden" name="host" value="\${EscHTML(\$host)}">
+<input type="hidden" name="num" value="\$num">
+<input type="hidden" name="type" value="2">
+\$hiddenStr
+<input type="hidden" value="\$In{action}" name="action">
+<input type="checkbox" value="1" name="relative" checked> Fazer arquivo relativo
+a \${EscHTML(\$pathHdr eq "" ? "/" : \$pathHdr)}
+(caso contrário o arquivo conterá os caminhos completos).
+<br>
+Compressão (0=desativada, 1=rápida,...,9=máxima)
+<input type="text" size="6" value="5" name="compressLevel">
+<br>
+<input type="submit" value="Download Zip File" name="">
+</form>
+EOF
+
+# ------------------------------
+
+$Lang{Option_2__Download_Zip_archive2} = <<EOF;
+<p>
+\${h2("Opção 2: Criar arquivo Zip")}
+<p>
+O programa Archive::Zip não está instalado, de modo que nã poderá criar um
+arquivo comprimido zip.
+Por favor, solicite ao seu administrador de sistemas que instale Archive::Zip de
+<a href="http://www.cpan.org">www.cpan.org</a>.
+</p>
+EOF
+
+
+# ------------------------------
+$Lang{Option_3__Download_Zip_archive} = <<EOF;
+\${h2("Opción 3: Criar archivo Tar")}
+<p>
+Pode-se criar um arquivo comprimido (.Tar) contendo todos os arquivos e
+diretórios que foram selecionados. Após pode-se utilizar uma aplicação
+local, como Tar ou WinZip, para ver ou extrair os arquivos gerados.
+</p><p>
+<b>Atenção!:</b> Dependendo de quais arquivos/pastas foram selecionados,
+este arquivo pode ser muito grande. Poderia levar muitos minutos para
+criar e transferir o arquivo. Também necessitará suficiente espaço no disco
+local para armazená-lo.
+</p>
+<form action="\$MyURL" method="post">
+<input type="hidden" name="host" value="\${EscHTML(\$host)}">
+<input type="hidden" name="num" value="\$num">
+<input type="hidden" name="type" value="1">
+\$hiddenStr
+<input type="hidden" value="\$In{action}" name="action">
+<input type="checkbox" value="1" name="relative" checked> Criar um arquivo
+relativo a \${EscHTML(\$pathHdr eq "" ? "/" : \$pathHdr)}
+(caso contrário o arquivo conterá os caminhos completos).
+<br>
+<input type="submit" value="Download Tar File" name="">
+</form>
+EOF
+
+
+# ------------------------------
+$Lang{Restore_Confirm_on__host} = "BackupPC: Confirme restauração em \$host";
+
+$Lang{Are_you_sure} = <<EOF;
+\${h1("Tem certeza?")}
+<p>
+Está prestes a començar uma restauração diretamente na máquina \$In{hostDest}.
+Os seguintes arquivos serão restaurados na unidade \$In{shareDest}, a partir
+do Backup número \$num:
+<p>
+<table border>
+<tr><td>Arquivo/Dir Original </td><td>Será restaurado em</td></tr>
+\$fileListStr
+</table>
+
+<form action="\$MyURL" method="post">
+<input type="hidden" name="host" value="\${EscHTML(\$host)}">
+<input type="hidden" name="hostDest" value="\${EscHTML(\$In{hostDest})}">
+<input type="hidden" name="shareDest" value="\${EscHTML(\$In{shareDest})}">
+<input type="hidden" name="pathHdr" value="\${EscHTML(\$In{pathHdr})}">
+<input type="hidden" name="num" value="\$num">
+<input type="hidden" name="type" value="4">
+\$hiddenStr
+Tem certeza?
+<input type="submit" value="\$In{action}" name="action">
+<input type="submit" value="No" name="">
+</form>
+EOF
+
+
+# --------------------------
+$Lang{Restore_Requested_on__hostDest} = "BackupPC: Restauração solicitada em \$hostDest";
+$Lang{Reply_from_server_was___reply} = <<EOF;
+\${h1(\$str)}
+<p>
+A resposta do servidor foi: \$reply
+<p>
+voltar a <a href="\$MyURL?host=\$hostDest">\$hostDest home page</a>.
+EOF
+
+$Lang{BackupPC_Archive_Reply_from_server} = <<EOF;
+\${h1(\$str)}
+<p>
+A resposta do servidor foi: \$reply
+EOF
+
+# -------------------------
+$Lang{Host__host_Backup_Summary} = "BackupPC: Host \$host Resumo do Backup";
+
+$Lang{Host__host_Backup_Summary2} = <<EOF;
+\${h1("Host \$host Resumo do Backup")}
+<p>
+\$warnStr
+<ul>
+\$statusStr
+</ul>
+</p>
+\${h2("Ações do Usuário")}
+<p>
+<form action="\$MyURL" method="get">
+<input type="hidden" name="host" value="\$host">
+\$startIncrStr
+<input type="submit" value="$Lang{Start_Full_Backup}" name="action">
+<input type="submit" value="$Lang{Stop_Dequeue_Backup}" name="action">
+</form>
+</p>
+\${h2("Resumo do Backup")}
+<p>
+Clique no número do Backup para revisar e restaurar arquivos.
+</p>
+<table class="tableStnd" border cellspacing="1" cellpadding="3">
+<tr class="tableheader"><td align="center"> Cópia Nº </td>
+ <td align="center"> Tipo </td>
+ <td align="center"> Completo </td>
+ <td align="center"> Data Início </td>
+ <td align="center"> Duração/min </td>
+ <td align="center"> Idade/dias </td>
+ <td align="center"> Rota da Cópia no Servidor </td>
+</tr>
+\$str
+</table>
+<p>
+
+\$restoreStr
+</p>
+<br><br>
+\${h2("Resumo dos Erros de Transferência")}
+<br><br>
+<table class="tableStnd" border cellspacing="1" cellpadding="3" width="80%">
+<tr class="tableheader"><td align="center"> Copia Nº </td>
+ <td align="center"> Tipo </td>
+ <td align="center"> Ver </td>
+ <td align="center"> Nº Xfer errs </td>
+ <td align="center"> Nº erros arquivos </td>
+ <td align="center"> Nº erros unidades </td>
+ <td align="center"> Nº erros tar </td>
+</tr>
+\$errStr
+</table>
+<br><br>
+
+\${h2("Resumo do Total/Tamanho dos Arquivos Reutilizados")}
+<p>
+Os arquivos existentes são aqueles que já estão no lote; os novos são
+aqueles que serão adicionados ao lote.
+Os arquivos vazios e os erros de SMB não contam nos valores de reutilizados
+nem nos de novos.
+</p>
+<table class="tableStnd" border cellspacing="1" cellpadding="3" width="80%">
+<tr class="tableheader"><td colspan="2" bgcolor="#ffffff"></td>
+ <td align="center" colspan="3"> Totais </td>
+ <td align="center" colspan="2"> Arquivos Existentes </td>
+ <td align="center" colspan="2"> Arquivos Novos </td>
+</tr>
+<tr class="tableheader">
+ <td align="center"> Cópia Nº </td>
+ <td align="center"> Tipo </td>
+ <td align="center"> Nº Arquivos </td>
+ <td align="center"> Tamanho/MB </td>
+ <td align="center"> MB/seg </td>
+ <td align="center"> Nº Arquivos </td>
+ <td align="center"> Tamanho/MB </td>
+ <td align="center"> Nº Arquivos </td>
+ <td align="center"> Tamanho/MB </td>
+</tr>
+\$sizeStr
+</table>
+<br><br>
+
+\${h2("Resumo da Compressão")}
+<p>
+Performance de compresão para os arquivos já existentes no lote e nos
+arquivos novos comprimidos.
+</p>
+<table class="tableStnd" border cellspacing="1" cellpadding="3" width="80%">
+<tr class="tableheader"><td colspan="3" bgcolor="#ffffff"></td>
+ <td align="center" colspan="3"> Arquivos Existentes </td>
+ <td align="center" colspan="3"> Arquivos Novos </td>
+</tr>
+<tr class="tableheader"><td align="center"> Cópia Nº </td>
+ <td align="center"> Tipo </td>
+ <td align="center"> Nível Compr </td>
+ <td align="center"> Tamanho/MB </td>
+ <td align="center"> Compr/MB </td>
+ <td align="center"> Compr </td>
+ <td align="center"> Tamanho/MB </td>
+ <td align="center"> Compr/MB </td>
+ <td align="center"> Compr </td>
+</tr>
+\$compStr
+</table>
+<br><br>
+EOF
+
+$Lang{Host__host_Archive_Summary} = "BackupPC: Host \$host Archive Summary";
+$Lang{Host__host_Archive_Summary2} = <<EOF;
+\${h1("Host Archive Summary \$host")}
+<p>
+\$warnStr
+<ul>
+\$statusStr
+</ul>
+
+\${h2("Ações do usuário")}
+<p>
+<form action="\$MyURL" method="get">
+<input type="hidden" name="archivehost" value="\$host">
+<input type="hidden" name="host" value="\$host">
+<input type="submit" value="$Lang{Start_Archive}" name="action">
+<input type="submit" value="$Lang{Stop_Dequeue_Archive}" name="action">
+</form>
+
+\$ArchiveStr
+
+EOF
+
+# -------------------------
+$Lang{Error} = "BackupPC: Erro";
+$Lang{Error____head} = <<EOF;
+\${h1("Erro: \$head")}
+<p>\$mesg</p>
+EOF
+
+# -------------------------
+$Lang{NavSectionTitle_} = "Servidor";
+
+# -------------------------
+$Lang{Backup_browse_for__host} = <<EOF;
+\${h1("Revisar Backup do \$host")}
+
+<script language="javascript" type="text/javascript">
+<!--
+
+ function checkAll(location)
+ {
+ for (var i=0;i<document.form1.elements.length;i++)
+ {
+ var e = document.form1.elements[i];
+ if ((e.checked || !e.checked) && e.name != \'all\') {
+ if (eval("document.form1."+location+".checked")) {
+ e.checked = true;
+ } else {
+ e.checked = false;
+ }
+ }
+ }
+ }
+
+ function toggleThis(checkbox)
+ {
+ var cb = eval("document.form1."+checkbox);
+ cb.checked = !cb.checked;
+ }
+
+//-->
+</script>
+
+<form name="form0" method="post" action="\$MyURL">
+<input type="hidden" name="num" value="\$num">
+<input type="hidden" name="host" value="\$host">
+<input type="hidden" name="share" value="\${EscHTML(\$share)}">
+<input type="hidden" name="action" value="browse">
+<ul>
+<li> Revisando o Backup Nº\$num, que iniciou às \$backupTime
+ (faz \$backupAge dias),
+\$filledBackup
+<li> Indique o diretório: <input type="text" name="dir" size="50" maxlength="4096" value="\${EscHTML(\$dir)}"> <input type="submit" value="\$Lang->{Go}" name="Submit">
+<li> Clique em um dos diretórios abaixo para revisar seus conteúdos,
+<li> Clique em um arquivo para restaurá-lo,
+<li> Ver o Backup <a href="\$MyURL?action=dirHistory&host=\${EscURI(\$host)}&share=\$shareURI&dir=\$pathURI">history</a> do diretório atual.
+</ul>
+</form>
+
+\${h2("Conteúdo do \${EscHTML(\$dirDisplay)}")}
+<form name="form1" method="post" action="\$MyURL">
+<input type="hidden" name="num" value="\$num">
+<input type="hidden" name="host" value="\$host">
+<input type="hidden" name="share" value="\${EscHTML(\$share)}">
+<input type="hidden" name="fcbMax" value="\$checkBoxCnt">
+<input type="hidden" name="action" value="$Lang{Restore}">
+<br>
+<table width="100%">
+<tr><td valign="top">
+ <br><table align="center" border="0" cellpadding="0" cellspacing="0" bgcolor="#ffffff">
+ \$dirStr
+ </table>
+</td><td width="3%">
+</td><td valign="top">
+ <br>
+ <table border="0" width="100%" align="left" cellpadding="3" cellspacing="1">
+ \$fileHeader
+ \$topCheckAll
+ \$fileStr
+ \$checkAll
+ </table>
+ </td></tr></table>
+<br>
+<!--
+This is now in the checkAll row
+<input type="submit" name="Submit" value="Restaurar arquivos selecionados">
+-->
+</form>
+EOF
+
+# ------------------------------
+$Lang{DirHistory_backup_for__host} = "BackupPC: Histórico do Backup do diretório em \$host";
+
+#
+# These two strings are used to build the links for directories and
+# file versions. Files are appended with a version number.
+#
+$Lang{DirHistory_dirLink} = "dir";
+$Lang{DirHistory_fileLink} = "v";
+
+$Lang{DirHistory_for__host} = <<EOF;
+\${h1("Histórico do backup do diretório em \$host")}
+<p>
+Este quadro mostra cada versão única disponível nos diversos backups:
+<ul>
+<li> Clique no número do backup para voltar ao explorador de backups,
+<li> Clique no atalho do diretório (\$Lang->{DirHistory_dirLink}) para navegar
+ por esse diretório,
+<li> Clique no atalho da versão do arquivo (\$Lang->{DirHistory_fileLink}0,
+ \$Lang->{DirHistory_fileLink}1, ...) para baixar esse arquivo,
+<li> Os arquivos com conteúdos diferentes entre cópias distintas de backup tem o mesmo
+ número de verssão,
+<li> Os arquivos ou diretórios inexistentes em um determinado backup tem uma
+ caixa vazia.
+<li> Os arquivos mostrados com a mesma versão podem ter diferentes atributos.
+ Selecione o número do backup para ver os atributos do arquivo.
+</ul>
+
+\${h2("Histórico de \${EscHTML(\$dirDisplay)}")}
+
+<br>
+<table cellspacing="2" cellpadding="3">
+<tr class="fviewheader"><td>Backup numero</td>\$backupNumStr</tr>
+<tr class="fviewheader"><td>Backup time</td>\$backupTimeStr</tr>
+\$fileStr
+</table>
+EOF
+
+# ------------------------------
+$Lang{Restore___num_details_for__host} = "BackupPC: Detalhes da restauração Nº\$num de \$host";
+
+$Lang{Restore___num_details_for__host2} = <<EOF;
+\${h1("Detalhes da restauração Nº\$num de \$host")}
+<p>
+<table class="tableStnd" border cellspacing="1" cellpadding="3" width="90%">
+<tr><td class="tableheader"> Número </td><td class="border"> \$Restores[\$i]{num} </td></tr>
+<tr><td class="tableheader"> Solicitado por </td><td class="border"> \$RestoreReq{user} </td></tr>
+<tr><td class="tableheader"> Hora da Solicitação </td><td class="border"> \$reqTime </td></tr>
+<tr><td class="tableheader"> Resultado </td><td class="border"> \$Restores[\$i]{result} </td></tr>
+<tr><td class="tableheader"> Mensagem de Erro </td><td class="border"> \$Restores[\$i]{errorMsg} </td></tr>
+<tr><td class="tableheader"> Host Origem </td><td class="border"> \$RestoreReq{hostSrc} </td></tr>
+<tr><td class="tableheader"> Nº cópia origem </td><td class="border"> \$RestoreReq{num} </td></tr>
+<tr><td class="tableheader"> Unidade origem </td><td class="border"> \$RestoreReq{shareSrc} </td></tr>
+<tr><td class="tableheader"> Host destino </td><td class="border"> \$RestoreReq{hostDest} </td></tr>
+<tr><td class="tableheader"> Unidade destino </td><td class="border"> \$RestoreReq{shareDest} </td></tr>
+<tr><td class="tableheader"> Hora início </td><td class="border"> \$startTime </td></tr>
+<tr><td class="tableheader"> Duração </td><td class="border"> \$duration min </td></tr>
+<tr><td class="tableheader"> Número de arquivos </td><td class="border"> \$Restores[\$i]{nFiles} </td></tr>
+<tr><td class="tableheader"> Tamanho total </td><td class="border"> \${MB} MB </td></tr>
+<tr><td class="tableheader"> Taxa de transferência </td><td class="border"> \$MBperSec MB/sec </td></tr>
+<tr><td class="tableheader"> Erros de criação Tar </td><td class="border"> \$Restores[\$i]{tarCreateErrs} </td></tr>
+<tr><td class="tableheader"> Erros de transferência </td><td class="border"> \$Restores[\$i]{xferErrs} </td></tr>
+<tr><td class="tableheader"> Arquivo registro de transferência </td><td class="border">
+<a href="\$MyURL?action=view&type=RestoreLOG&num=\$Restores[\$i]{num}&host=\$host">View</a>,
+<a href="\$MyURL?action=view&type=RestoreErr&num=\$Restores[\$i]{num}&host=\$host">Errors</a>
+</tr></tr>
+</table>
+</p>
+\${h1("Lista de Arquivos/Diretórios")}
+<p>
+<table class="tableStnd" border cellspacing="1" cellpadding="3" width="100%">
+<tr class="tableheader"><td>Dir/arquivo original</td><td>Restaurado a</td></tr>
+\$fileListStr
+</table>
+EOF
+
+# ------------------------------
+$Lang{Archive___num_details_for__host} = "BackupPC: Archive #\$num Detalhes de \$host";
+
+$Lang{Archive___num_details_for__host2 } = <<EOF;
+\${h1("Archive #\$num Detalhes de \$host")}
+<p>
+<table class="tableStnd" border cellspacing="1" cellpadding="3" width="80%">
+<tr><td class="tableheader"> Número </td><td class="border"> \$Archives[\$i]{num} </td></tr>
+<tr><td class="tableheader"> Solicitado por </td><td class="border"> \$ArchiveReq{user} </td></tr>
+<tr><td class="tableheader"> Hora da solicitação </td><td class="border"> \$reqTime </td></tr>
+<tr><td class="tableheader"> Resultado </td><td class="border"> \$Archives[\$i]{result} </td></tr>
+<tr><td class="tableheader"> Mensagem de erro </td><td class="border"> \$Archives[\$i]{errorMsg} </td></tr>
+<tr><td class="tableheader"> Hora início </td><td class="border"> \$startTime </td></tr>
+<tr><td class="tableheader"> Duração </td><td class="border"> \$duration min </td></tr>
+<tr><td class="tableheader"> Arquivo registro Xfer </td><td class="border">
+<a href="\$MyURL?action=view&type=ArchiveLOG&num=\$Archives[\$i]{num}&host=\$host">View</a>,
+<a href="\$MyURL?action=view&type=ArchiveErr&num=\$Archives[\$i]{num}&host=\$host">Errors</a>
+</tr></tr>
+</table>
+<p>
+\${h1("Host list")}
+<p>
+<table class="tableStnd" border cellspacing="1" cellpadding="3" width="80%">
+<tr class="tableheader"><td>Host</td><td>Backup número</td></tr>
+\$HostListStr
+</table>
+EOF
+
+# -----------------------------------
+$Lang{Email_Summary} = "BackupPC: Resumo de Emails";
+
+# -----------------------------------
+# !! ERROR messages !!
+# -----------------------------------
+$Lang{BackupPC__Lib__new_failed__check_apache_error_log} = "BackupPC::Lib->nova falha: revise o error_log do apache\n";
+$Lang{Wrong_user__my_userid_is___} =
+ "Usuário inválido: meu userid é \$>, no lugar de \$uid"
+ . "(\$Conf{BackupPCUser})\n";
+# $Lang{Only_privileged_users_can_view_PC_summaries} = "Somente os usuários autorizados podem ver os resumos de PCs.";
+$Lang{Only_privileged_users_can_stop_or_start_backups} =
+ "Somente os usuários autorizados podem iniciar ou parar as cópias"
+ . " \${EscHTML(\$host)}.";
+$Lang{Invalid_number__num} = "Número inválido \$num";
+$Lang{Unable_to_open__file__configuration_problem} = "Não pode abrir \$file: problema de configuração?";
+$Lang{Only_privileged_users_can_view_log_or_config_files} = "Somente os usuários autorizados podem ver registros ou arquivos de configuração.";
+$Lang{Only_privileged_users_can_view_log_files} = "Somente os usuários autorizados podem ver arquivos de registro.";
+$Lang{Only_privileged_users_can_view_email_summaries} = "Somente os usuários autorizados podem ver resumos de email.";
+$Lang{Only_privileged_users_can_browse_backup_files} = "Somente os usuários autorizados podem revisar os arquivos de backup"
+ . " for host \${EscHTML(\$In{host})}.";
+$Lang{Empty_host_name} = "Número de host vazio.";
+$Lang{Directory___EscHTML} = "O diretório \${EscHTML(\"\$TopDir/pc/\$host/\$num\")}"
+ . " está vazio";
+$Lang{Can_t_browse_bad_directory_name2} = "Não pode mostrar um nome de diretório inválido"
+ . " \${EscHTML(\$relDir)}";
+$Lang{Only_privileged_users_can_restore_backup_files} = "Somente os usuários autorizados podem restaurar backups"
+ . " para o host \${EscHTML(\$In{host})}.";
+$Lang{Bad_host_name} = "Nome de host inválido \${EscHTML(\$host)}";
+$Lang{You_haven_t_selected_any_files__please_go_Back_to} = "Não foi selecionado nenhum arquivo; por favor, volte e"
+ . " selecione alguns arquivos.";
+$Lang{You_haven_t_selected_any_hosts} = "Não foi selecionado nenhum host; por favor volte e"
+ . " selecione algum host.";
+$Lang{Nice_try__but_you_can_t_put} = "Boa tentativa, mas não pode usar \'..\' nos nomes de arquivo";
+$Lang{Host__doesn_t_exist} = "O Host \${EscHTML(\$In{hostDest})} não existe";
+$Lang{You_don_t_have_permission_to_restore_onto_host} = "Sem autorização para restaurar neste host"
+ . " \${EscHTML(\$In{hostDest})}";
+$Lang{Can_t_open_create__openPath} = "Impossível abrir/criar "
+ . "\${EscHTML(\"\$openPath\")}";
+$Lang{Only_privileged_users_can_restore_backup_files2} = "Somente os usuários autorizados podem restaurar backups"
+ . " do host \${EscHTML(\$host)}.";
+$Lang{Empty_host_name} = "Nome de host vazio";
+$Lang{Unknown_host_or_user} = "Usuário ou host inválido \${EscHTML(\$host)}";
+$Lang{Only_privileged_users_can_view_information_about} = "Somente os usuários autorizados podem ver informações do"
+ . " host \${EscHTML(\$host)}." ;
+$Lang{Only_privileged_users_can_view_archive_information} = "Somente os administradores podem ver informações de arquivo.";
+$Lang{Only_privileged_users_can_view_restore_information} = "Somente os usuários autorizados podem ver informações de restauração.";
+$Lang{Restore_number__num_for_host__does_not_exist} = "O número de restauração \$num del host \${EscHTML(\$host)} "
+ . " não existe.";
+$Lang{Archive_number__num_for_host__does_not_exist} = "O backup \$num do host \${EscHTML(\$host)} "
+ . " não existe.";
+$Lang{Can_t_find_IP_address_for} = "Impossível encontrar o endereço do IP de \${EscHTML(\$host)}";
+$Lang{host_is_a_DHCP_host} = <<EOF;
+\$host é um host DHCP e eu não consigo seu endereço IP. Provavelmente o nome netbios de \$ENV{REMOTE_ADDR}\$tryIP, e foi verificado que essa máquina
+não é \$host.
+<p>
+Até que tenha \$host um endereço num DHCP válido, se pode
+començar este processo a partir da própria máquina cliente.
+EOF
+
+# ------------------------------------
+# !! Server Mesg !!
+# ------------------------------------
+
+$Lang{Backup_requested_on_DHCP__host} = "Solicitação de backup em DHCP \$host (\$In{hostIP}) por"
+ . " \$User desde \$ENV{REMOTE_ADDR}";
+$Lang{Backup_requested_on__host_by__User} = "Solicitação de backup em \$host por \$User";
+$Lang{Backup_stopped_dequeued_on__host_by__User} = "Backup parado/desprogramado em \$host por \$User";
+$Lang{Restore_requested_to_host__hostDest__backup___num} = "Restauração solicitada para o host \$hostDest, backup #\$num,"
+ . " por \$User desde \$ENV{REMOTE_ADDR}";
+$Lang{Archive_requested} = "Arquivo solicitado por \$User desde \$ENV{REMOTE_ADDR}";
+
+# -------------------------------------------------
+# ------- Stuff that was forgotten ----------------
+# -------------------------------------------------
+
+$Lang{Status} = "Estado";
+$Lang{PC_Summary} = "Resumo PC";
+$Lang{LOG_file} = "Arquivo de Log";
+$Lang{LOG_files} = "Arquivos de Log";
+$Lang{Old_LOGs} = "Logs antigos";
+$Lang{Email_summary} = "Resumo Email";
+$Lang{Config_file} = "Arquivo configuração";
+$Lang{Hosts_file} = "Arquivo Hosts";
+$Lang{Current_queues} = "Filas atuais";
+$Lang{Documentation} = "Documentação";
+
+#$Lang{Host_or_User_name} = "<small>Host ou usuário:</small>";
+$Lang{Go} = "Aceitar";
+$Lang{Hosts} = "Hosts";
+$Lang{Select_a_host} = "Selecione um host...";
+
+$Lang{There_have_been_no_archives} = "<h2> Não existem arquivos </h2>\n";
+$Lang{This_PC_has_never_been_backed_up} = "<h2> Nunca foi feito backup deste PC! </h2>\n";
+$Lang{This_PC_is_used_by} = "<li>Este PC é utilizado por \${UserLink(\$user)}";
+
+$Lang{Extracting_only_Errors} = "(Extraindo somente Erros)";
+$Lang{XferLOG} = "TransfLOG";
+$Lang{Errors} = "Erros";
+
+# ------------
+$Lang{Last_email_sent_to__was_at___subject} = <<EOF;
+<li>Última mensagem enviada a \${UserLink(\$user)} foi às \$mailTime, assunto "\$subj".
+EOF
+# ------------
+$Lang{The_command_cmd_is_currently_running_for_started} = <<EOF;
+<li>O comando \$cmd está executando para \$host, iniciado às \$startTime.
+EOF
+
+# -----------
+$Lang{Host_host_is_queued_on_the_background_queue_will_be_backed_up_soon} = <<EOF;
+<li>O host \$host está em fila para ser processado em segundo plano (logo o backup estará pronto!).
+EOF
+
+# ----------
+$Lang{Host_host_is_queued_on_the_user_queue__will_be_backed_up_soon} = <<EOF;
+<li>Host \$host está para ser processado na fila de usuarios (logo o backup estará pronto!).
+EOF
+
+# ---------
+$Lang{A_command_for_host_is_on_the_command_queue_will_run_soon} = <<EOF;
+<li>Uma execução para \$host estar na fila de execuções (iniciará a seguir).
+EOF
+
+# --------
+$Lang{Last_status_is_state_StatusHost_state_reason_as_of_startTime} = <<EOF;
+<li>O último estado foi \"\$Lang->{\$StatusHost{state}}\"\$reason às \$startTime.
+EOF
+
+# --------
+$Lang{Last_error_is____EscHTML_StatusHost_error} = <<EOF;
+<li>O último erro foi \"\${EscHTML(\$StatusHost{error})}\".
+EOF
+
+# ------
+$Lang{Pings_to_host_have_failed_StatusHost_deadCnt__consecutive_times} = <<EOF;
+<li>Os pings para \$host falharam \$StatusHost{deadCnt} vezes consecutivas.
+EOF
+
+# -----
+$Lang{Prior_to_that__pings} = "Antes destes, pings";
+
+# -----
+$Lang{priorStr_to_host_have_succeeded_StatusHostaliveCnt_consecutive_times} = <<EOF;
+<li>\$priorStr a \$host obtiveram êxito \$StatusHost{aliveCnt}
+ vezes consecutivas.
+EOF
+
+$Lang{Because__host_has_been_on_the_network_at_least__Conf_BlackoutGoodCnt_consecutive_times___} = <<EOF;
+<li>Dado que \$host tem estado em uso na rede pelo menos \$Conf{BlackoutGoodCnt}
+vezes consecutivas, não se realizará backup das \$blackoutStr.
+EOF
+
+$Lang{__time0_to__time1_on__days} = "\$t0 até \$t1 em \$days";
+
+$Lang{Backups_are_deferred_for_hours_hours_change_this_number} = <<EOF;
+<li>Os backups atrazaram-se durante \$hours hours
+(<a href=\"\$MyURL?action=\${EscURI(\$Lang->{Stop_Dequeue_Archive})}&host=\$host\">Troque este número</a>).
+EOF
+
+$Lang{tryIP} = " y \$StatusHost{dhcpHostIP}";
+
+#$Lang{Host_Inhost} = "Host \$In{host}";
+
+$Lang{checkAll} = <<EOF;
+<tr><td class="fviewborder">
+<input type="checkbox" name="allFiles" onClick="return checkAll('allFiles');"> Selecionar tudo
+</td><td colspan="5" align="center" class="fviewborder">
+<input type="submit" name="Submit" value="Restaurar os arquivos selecionados">
+</td></tr>
+EOF
+
+$Lang{checkAllHosts} = <<EOF;
+<tr><td class="fviewborder">
+<input type="checkbox" name="allFiles" onClick="return checkAll('allFiles');"> Selecionar tudo
+</td><td colspan="2" align="center" class="fviewborder">
+<input type="submit" name="Submit" value="Arquivar os hosts selecionados">
+</td></tr>
+EOF
+
+$Lang{fileHeader} = <<EOF;
+ <tr class="fviewheader"><td align=center> Nome</td>
+ <td align="center"> Tipo</td>
+ <td align="center"> Modo</td>
+ <td align="center"> Nº</td>
+ <td align="center"> Tamanho</td>
+ <td align="center"> Hora Mod.</td>
+ </tr>
+EOF
+
+$Lang{Home} = "Principal";
+$Lang{Browse} = "Explorar backups";
+$Lang{Last_bad_XferLOG} = "Último erro no Log de Transferência";
+$Lang{Last_bad_XferLOG_errors_only} = "Último erro no Log de transferência (erros somente)";
+
+$Lang{This_display_is_merged_with_backup} = <<EOF;
+<li> Este quadro pertence ao backup Nº\$numF.
+EOF
+
+$Lang{Visit_this_directory_in_backup} = <<EOF;
+<li> Selecione o backup que desseja ver: <select onChange="window.location=this.value">\$otherDirs </select>
+EOF
+
+$Lang{Restore_Summary} = <<EOF;
+\${h2("Resumo da Restauração")}
+<p>
+Clique no número da restauração para ver seus detalhes.
+<table class="tableStnd" border cellspacing="1" cellpadding="3" width="80%">
+<tr class="tableheader"><td align="center"> Restauração Nº </td>
+ <td align="center"> Resultado </td>
+ <td align="right"> Data Inicio</td>
+ <td align="right"> Dur/mins</td>
+ <td align="right"> Nº Arquivos </td>
+ <td align="right"> MB </td>
+ <td align="right"> Nº Err. Tar </td>
+ <td align="right"> Nº Err. Transf.#xferErrs </td>
+</tr>
+\$restoreStr
+</table>
+<p>
+EOF
+
+$Lang{Archive_Summary} = <<EOF;
+\${h2("Archive Summary")}
+<p>
+Clique no número do arquivo para mais detalhes.
+<table class="tableStnd" border cellspacing="1" cellpadding="3" width="80%">
+<tr class="tableheader"><td align="center"> Archive# </td>
+ <td align="center"> Resultado </td>
+ <td align="right"> Hora início</td>
+ <td align="right"> Dur/min</td>
+</tr>
+\$ArchiveStr
+</table>
+<p>
+EOF
+
+$Lang{BackupPC__Documentation} = "BackupPC: Documentação";
+
+$Lang{No} = "não";
+$Lang{Yes} = "sim";
+
+$Lang{The_directory_is_empty} = <<EOF;
+<tr><td bgcolor="#ffffff">O diretório \${EscHTML(\$dirDisplay)} está vazio
+</td></tr>
+EOF
+
+#$Lang{on} = "ativo";
+$Lang{off} = "inativo";
+
+$Lang{backupType_full} = "completo";
+$Lang{backupType_incr} = "incremental";
+$Lang{backupType_partial} = "parcial";
+
+$Lang{failed} = "falhado";
+$Lang{success} = "sucesso";
+$Lang{and} = "e";
+
+# ------
+# Hosts states and reasons
+$Lang{Status_idle} = "inativo";
+$Lang{Status_backup_starting} = "iniciando backup";
+$Lang{Status_backup_in_progress} = "backup em execução";
+$Lang{Status_restore_starting} = "iniciando restauração";
+$Lang{Status_restore_in_progress} = "restauração em execução";
+$Lang{Status_link_pending} = "conexão pendente";
+$Lang{Status_link_running} = "conexão em curso";
+
+$Lang{Reason_backup_done} = "backup realizado";
+$Lang{Reason_restore_done} = "restauração realizada";
+$Lang{Reason_archive_done} = "arquivamento realizado";
+$Lang{Reason_nothing_to_do} = "nada a fazer";
+$Lang{Reason_backup_failed} = "falha no backup";
+$Lang{Reason_restore_failed} = "falha na restauração";
+$Lang{Reason_archive_failed} = "falha no arquivamento";
+$Lang{Reason_no_ping} = "sem ping";
+$Lang{Reason_backup_canceled_by_user} = "backup cancelado pelo usuário";
+$Lang{Reason_restore_canceled_by_user} = "restauração cancelada pelo usuário";
+$Lang{Reason_archive_canceled_by_user} = "arquivamento cancelado pelo usuário";
+
+# ---------
+# Email messages
+
+# No backup ever
+$Lang{EMailNoBackupEverSubj} = "BackupPC: nenhum backup de \$host foi terminado com êxito";
+$Lang{EMailNoBackupEverMesg} = <<'EOF';
+To: $user$domain
+cc:
+Subject: $subj
+
+Caro $userName,
+
+Em seu PC ($host) nenhum backup foi completado por nosso programa de backup.
+Os backups deveriam ser executados automaticamente quando seu PC se conecta
+a rede. Contate seu suporte técnico se:
+
+ - Seu computador está conectado a rede com regularidade. Isto significa
+ que existe algum problema de instalação ou configuração que impessa a
+ realização dos backups.
+
+ - Não deseja realizar backups e não quer receber mais mensagens
+ como esta.
+
+Caso contrário, assegure-se de que seu PC está conectado à rede na próxima vez
+que estiver utilizando-o.
+
+Saudações:
+Agente BackupPC
+http://backuppc.sourceforge.net
+EOF
+
+# No recent backup
+$Lang{EMailNoBackupRecentSubj} = "BackupPC: não existem backups recentes de \$host";
+$Lang{EMailNoBackupRecentMesg} = <<'EOF';
+To: $user$domain
+cc:
+Subject: $subj
+
+Caro $userName,
+
+Não foi completado nenhum backup completo de seu PC ($host) durante
+$days dias.
+Seu PC tem realizado backups corretos $numBackups vezes desde
+$firstTime até $days dias.
+Os backups deveriam efetuar-se automaticamente quando seu PC estiver
+conectado a rede.
+
+Se seu PC tem estado conectado durante algumas horas a rede durante os últimos
+$days dias deveria contactar com seu suporte técnico para ver porque os backups
+não funcionam adequadamente.
+
+Por outro lado, se você não o está utilizando, não há muito o que fazer a não
+ser copiar manualmente os arquivos mais críticos para outro suporte físico.
+Deve-se estar ciente de que qualquer arquivo que tenha sido criado ou modificado
+nos últimos $days dias (incluindo todos os emails novos e arquivos anexos) não podem
+ser restaurados se seu disco danificar-se.
+
+Saudações:
+Agente BackupPC
+http://backuppc.sourceforge.net
+EOF
+
+# Old Outlook files
+$Lang{EMailOutlookBackupSubj} = "BackupPC: Oss arquivos do Outlook de \$host necessitam ser copiados";
+$Lang{EMailOutlookBackupMesg} = <<'EOF';
+To: $user$domain
+cc:
+Subject: $subj
+
+Caro $userName,
+
+Os arquivos de Outlook de seu PC tem $howLong.
+Estes arquivos contém todo seus emails, anexos, contatos e informações de
+sua agenda. Seu PC tem sido corretamente salvaguardado $numBackups vezes desde
+$firstTime até $lastTime dias. Sem fechá-lo, Outlook bloqueia todos seus
+arquivos quando estão em execução, impidindo de se fazer backup dos mesmo.
+
+Recomendamos fazer cópia de segurança dos arquivos do Outlook quando estiver
+conectado a rede fechando o Outlook e o resto das aplicações e utilizando seu
+navegador de internet. Clique neste link:
+
+ $CgiURL?host=$host
+
+Selecione "Começar backup incremental" duas vezes para começar
+um novo backup incremental.
+Pode-se selecionar "Voltar a página de $host " e clicar em "refazer"
+para ver o estado do processo de backup. Este processo deve durar
+somente alguns minutos para completar.
+
+Saudações:
+Agente BackupPC
+http://backuppc.sourceforge.net
+EOF
+
+$Lang{howLong_not_been_backed_up} = "não foi realizado nenhum backup com êxito";
+$Lang{howLong_not_been_backed_up_for_days_days} = "não foi realizado nenhum backup durante \$days dias";
+
+#end of lang_pt_BR.pm
+
+
--- /dev/null
+#============================================================= -*-perl-*-
+#
+# BackupPC::Storage package
+#
+# DESCRIPTION
+#
+# This library defines a BackupPC::Storage class for reading/writing
+# data like config, host info, backup and restore info.
+#
+# AUTHOR
+# Craig Barratt <cbarratt@users.sourceforge.net>
+#
+# COPYRIGHT
+# Copyright (C) 2004 Craig Barratt
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+#========================================================================
+#
+# Version 2.1.0, released 20 Jun 2004.
+#
+# See http://backuppc.sourceforge.net.
+#
+#========================================================================
+
+package BackupPC::Storage;
+
+use strict;
+use BackupPC::Storage::Text;
+
+sub new
+{
+ my $class = shift;
+ my($paths) = @_;
+ my $flds = {
+ BackupFields => [qw(
+ num type startTime endTime
+ nFiles size nFilesExist sizeExist nFilesNew sizeNew
+ xferErrs xferBadFile xferBadShare tarErrs
+ compress sizeExistComp sizeNewComp
+ noFill fillFromNum mangle xferMethod level
+ )],
+ RestoreFields => [qw(
+ num startTime endTime result errorMsg nFiles size
+ tarCreateErrs xferErrs
+ )],
+ ArchiveFields => [qw(
+ num startTime endTime result errorMsg
+ )],
+ };
+
+ return BackupPC::Storage::Text->new($flds, $paths, @_);
+}
+
+1;