diff --git a/install/sql/incremental/upd_0060.sql b/install/sql/incremental/upd_0060.sql new file mode 100644 index 0000000000000000000000000000000000000000..d68d2bfdcd6f4be4d095b2d87152d1038eff5b73 --- /dev/null +++ b/install/sql/incremental/upd_0060.sql @@ -0,0 +1,14 @@ +CREATE TABLE `mail_backup` ( + `backup_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `server_id` int(10) unsigned NOT NULL, + `parent_domain_id` int(10) unsigned NOT NULL, + `mailuser_id` int(10) unsigned NOT NULL, + `backup_mode` varchar(64) NOT NULL DEFAULT '', + `tstamp` int(10) unsigned NOT NULL, + `filename` varchar(255) NOT NULL, + `filesize` VARCHAR(10) NOT NULL, + PRIMARY KEY (`backup_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +ALTER TABLE `mail_user` ADD `backup_interval` VARCHAR( 255 ) NOT NULL ; +ALTER TABLE `mail_user` ADD `backup_copies` INT NOT NULL DEFAULT '1'; diff --git a/install/sql/ispconfig3.sql b/install/sql/ispconfig3.sql index 58722c610b8979a99a08ae9b9b11826e512ec1fc..3d09f4232af035ca33f5ad6af92d42a6bf745cfe 100644 --- a/install/sql/ispconfig3.sql +++ b/install/sql/ispconfig3.sql @@ -651,6 +651,24 @@ CREATE TABLE `mail_access` ( -- -------------------------------------------------------- +-- +-- Table structure for table `mail_backup` +-- + +CREATE TABLE `mail_backup` ( + `backup_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `server_id` int(10) unsigned NOT NULL, + `parent_domain_id` int(10) unsigned NOT NULL, + `mailuser_id` int(10) unsigned NOT NULL, + `backup_mode` varchar(64) NOT NULL DEFAULT '', + `tstamp` int(10) unsigned NOT NULL, + `filename` varchar(255) NOT NULL, + `filesize` VARCHAR(10) NOT NULL, + PRIMARY KEY (`backup_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + -- -- Table structure for table `mail_content_filter` -- @@ -863,6 +881,8 @@ CREATE TABLE `mail_user` ( `disablelda` enum('n','y') NOT NULL default 'n', `disabledoveadm` enum('n','y') NOT NULL default 'n', `last_quota_notification` date NULL default NULL, + `backup_interval` VARCHAR( 255 ) NOT NULL, + `backup_copies` INT NOT NULL DEFAULT '1', PRIMARY KEY (`mailuser_id`), KEY `server_id` (`server_id`,`email`), KEY `email_access` (`email`,`access`) diff --git a/interface/lib/classes/plugin_backuplist_mail.inc.php b/interface/lib/classes/plugin_backuplist_mail.inc.php new file mode 100644 index 0000000000000000000000000000000000000000..5bef570d8d0c1b2f5ec351a0415275e933b5233c --- /dev/null +++ b/interface/lib/classes/plugin_backuplist_mail.inc.php @@ -0,0 +1,129 @@ +<?php + +/* +Copyright (c) 2013, Florian Schaal, info@schaal-24.de +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of ISPConfig nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +class plugin_backuplist_mail extends plugin_base { + + var $module; + var $form; + var $tab; + var $record_id; + var $formdef; + var $options; + + function onShow() { + global $app; + $listTpl = new tpl; + $listTpl->newTemplate('templates/mail_user_backup_list.htm'); + + //* Loading language file + $lng_file = "lib/lang/".$_SESSION["s"]["language"]."_mail_backup_list.lng"; + include($lng_file); + $listTpl->setVar($wb); + + $message = ''; + $error = ''; + + if(isset($_GET['backup_action'])) { + $backup_id = $app->functions->intval($_GET['backup_id']); +/* + if($_GET['backup_action'] == 'download' && $backup_id > 0) { + $sql = "SELECT count(action_id) as number FROM sys_remoteaction WHERE action_state = 'pending' AND action_type = 'backup_download' AND action_param = '$backup_id'"; + $tmp = $app->db->queryOneRecord($sql); + if($tmp['number'] == 0) { + $message .= $wb['download_info_txt']; + $sql = "INSERT INTO sys_remoteaction (server_id, tstamp, action_type, action_param, action_state, response) " . + "VALUES (". + (int)$this->form->dataRecord['server_id'] . ", " . + time() . ", " . + "'backup_download', " . + "'".$backup_id."', " . + "'pending', " . + "''" . + ")"; + $app->db->query($sql); + } else { + $error .= $wb['download_pending_txt']; + } + } +*/ + if($_GET['backup_action'] == 'restore' && $backup_id > 0) { + $sql = "SELECT count(action_id) as number FROM sys_remoteaction WHERE action_state = 'pending' AND action_type = 'backup_restore' AND action_param = '$backup_id'"; + $tmp = $app->db->queryOneRecord($sql); + if($tmp['number'] == 0) { + $message .= $wb['restore_info_txt']; + $sql = "INSERT INTO sys_remoteaction (server_id, tstamp, action_type, action_param, action_state, response) " . + "VALUES (". + (int)$this->form->dataRecord['server_id'] . ", " . + time() . ", " . + "'backup_restore', " . + "'".$backup_id."', " . + "'pending', " . + "''" . + ")"; + $app->db->query($sql); + } else { + $error .= $wb['restore_pending_txt']; + } + } + } + + //* Get the data + $sql = "SELECT * FROM mail_backup WHERE mailuser_id = ".$this->form->id." ORDER BY tstamp DESC"; + $records = $app->db->queryAllRecords($sql); + $bgcolor = "#FFFFFF"; + if(is_array($records)) { + foreach($records as $rec) { + // Change of color + $bgcolor = ($bgcolor == "#FFFFFF")?"#EEEEEE":"#FFFFFF"; + $rec["bgcolor"] = $bgcolor; + $rec['date'] = date($app->lng('conf_format_datetime'),$rec['tstamp']); + $rec['backup_type'] = $wb[('backup_type_'.$rec['backup_type'])]; + $records_new[] = $rec; + } + } + + $listTpl->setLoop('records',@$records_new); + + $listTpl->setVar('parent_id',$this->form->id); + $listTpl->setVar('msg',$message); + $listTpl->setVar('error',$error); + + // Setting Returnto information in the session + $list_name = 'backup_list'; + $_SESSION["s"]["list"][$list_name]["parent_id"] = $this->form->id; + $_SESSION["s"]["list"][$list_name]["parent_name"] = $app->tform->formDef["name"]; + $_SESSION["s"]["list"][$list_name]["parent_tab"] = $_SESSION["s"]["form"]["tab"]; + $_SESSION["s"]["list"][$list_name]["parent_script"] = $app->tform->formDef["action"]; + $_SESSION["s"]["form"]["return_to"] = $list_name; + return $listTpl->grab(); + } // end function +} // end class + +?> diff --git a/interface/web/mail/form/mail_user.tform.php b/interface/web/mail/form/mail_user.tform.php index 21fc51461e88b6affc10ec6d508f08023246ea76..03f458a64e8f8ddb94b18c4d4691864c17cf9b89 100644 --- a/interface/web/mail/form/mail_user.tform.php +++ b/interface/web/mail/form/mail_user.tform.php @@ -346,5 +346,39 @@ if ($_SESSION["s"]["user"]["typ"] == 'admin' && $global_config['mail']['mailbox_ ); } +//* Backup +$form["tabs"]['backup'] = array ( + 'title' => "Backup", + 'width' => 100, + 'template' => "templates/mail_user_backup.htm", + 'readonly' => false, + 'fields' => array ( + ################################## + # Begin Datatable fields + ################################## + 'backup_interval' => array ( + 'datatype' => 'VARCHAR', + 'formtype' => 'SELECT', + 'default' => '', + 'value' => array('none' => 'no_backup_txt', 'daily' => 'daily_backup_txt', 'weekly' => 'weekly_backup_txt', 'monthly' => 'monthly_backup_txt') + ), + 'backup_copies' => array ( + 'datatype' => 'INTEGER', + 'formtype' => 'SELECT', + 'default' => '', + 'value' => array('1' => '1', '2' => '2', '3' => '3', '4' => '4', '5' => '5', '6' => '6', '7' => '7', '8' => '8', '9' => '9', '10' => '10') + ), + ################################## + # ENDE Datatable fields + ################################## + ), + 'plugins' => array ( + 'backup_records' => array ( + 'class' => 'plugin_backuplist_mail', + 'options' => array( + ) + ) + ) +); ?> diff --git a/interface/web/mail/lib/lang/en_mail_backup_list.lng b/interface/web/mail/lib/lang/en_mail_backup_list.lng new file mode 100644 index 0000000000000000000000000000000000000000..320ff5023ce51d69ccbf9e85b4982a2f126ba854 --- /dev/null +++ b/interface/web/mail/lib/lang/en_mail_backup_list.lng @@ -0,0 +1,12 @@ +<?php +$wb['list_head_txt'] = 'Existing backups'; +$wb['date_txt'] = 'Date'; +$wb['backup_type_txt'] = 'Type'; +$wb['filename_txt'] = 'Backup file'; +$wb['restore_backup_txt'] = 'Restore'; +$wb['restore_info_txt'] = 'Restore of the backup has been started. This action takes several minutes to be completed.'; +$wb['restore_confirm_txt'] = 'Restoring may overwrite existing files in your mailbox. Do you really want to restore this backup?'; +$wb['download_pending_txt'] = 'There is already a pending backup download job.'; +$wb['restore_pending_txt'] = 'There is already a pending backup restore job.'; +$wb['filesize_txt'] = 'Filesize'; +?> diff --git a/interface/web/mail/lib/lang/en_mail_user.lng b/interface/web/mail/lib/lang/en_mail_user.lng index f180deea83d97e3014264fd8363e39d9cfaf3be9..c275c1a329267fa2621a6a2b57c8dc01ab080f5f 100644 --- a/interface/web/mail/lib/lang/en_mail_user.lng +++ b/interface/web/mail/lib/lang/en_mail_user.lng @@ -47,4 +47,10 @@ $wb['generate_password_txt'] = 'Generate Password'; $wb['repeat_password_txt'] = 'Repeat Password'; $wb['password_mismatch_txt'] = 'The passwords do not match.'; $wb['password_match_txt'] = 'The passwords do match.'; +$wb["backup_interval_txt"] = 'Backup interval'; +$wb["backup_copies_txt"] = 'Number of backup copies'; +$wb['no_backup_txt'] = 'No backup'; +$wb['daily_backup_txt'] = 'Daily'; +$wb['weekly_backup_txt'] = 'Weekly'; +$wb['monthly_backup_txt'] = 'Monthly'; ?> diff --git a/interface/web/mail/mail_user_edit.php b/interface/web/mail/mail_user_edit.php index f71aa7de58b960c01d18e7c9bb2aa6919014196b..61f27cb2608565dff7aa49f5d8d2d04e00764e0e 100644 --- a/interface/web/mail/mail_user_edit.php +++ b/interface/web/mail/mail_user_edit.php @@ -319,6 +319,15 @@ class page_action extends tform_actions { } // end if email addess changed + //* Change backup options when user mail backup options have been changed + if(isset($this->dataRecord['backup_interval']) && ($this->dataRecord['backup_interval'] != $this->oldDataRecord['backup_interval'] || $this->dataRecord['backup_copies'] != $this->oldDataRecord['backup_copies'])) { + $backup_interval = $this->dataRecord['backup_interval']; + $backup_copies = $this->dataRecord['backup_copies']; + $app->db->datalogUpdate('mail_user', "backup_interval = '$backup_interval', backup_copies = '$backup_copies'", 'mailuser_id', $rec['mailuser_id']); + unset($backup_copies); + unset($backup_interval); + } // end if backup options changed + } } diff --git a/interface/web/mail/templates/mail_user_backup.htm b/interface/web/mail/templates/mail_user_backup.htm new file mode 100644 index 0000000000000000000000000000000000000000..e3aa096bcceb8e5555a3c4ea36138cc7b6a811be --- /dev/null +++ b/interface/web/mail/templates/mail_user_backup.htm @@ -0,0 +1,39 @@ +<h2><tmpl_var name="list_head_txt"></h2> +<p><tmpl_var name="list_desc_txt"></p> + +<tmpl_if name="config_error_msg"> +<div style="background: #ffdfdf; border: 1px solid #df7d7d; border-width: 1px 0; margin: 1.5em 0 1.5em 0; padding: 7px;"> + <p style="font-face:bold">{tmpl_var name='configuration_error_txt'}</p> + <div> + <div style="float:left;width:150px;">{tmpl_var name='config_error_tstamp'} : </div><div style="padding-left:150px;">{tmpl_var name='config_error_msg'}</div> + </div> +</div> +</tmpl_if> + +<div class="panel panel_mail_user"> + + <div class="pnl_formsarea"> + <fieldset class="inlineLabels"><legend>Backup</legend> + <div class="ctrlHolder"> + <label for="backup_interval">{tmpl_var name='backup_interval_txt'}</label> + <select name="backup_interval" id="backup_interval" class="selectInput"> + {tmpl_var name='backup_interval'} + </select> + </div> + <div class="ctrlHolder"> + <label for="backup_copies">{tmpl_var name='backup_copies_txt'}</label> + <select name="backup_copies" id="backup_copies" class="selectInput"> + {tmpl_var name='backup_copies'} + </select> + </div> + </fieldset> + {tmpl_var name='backup_records'} + <input type="hidden" name="id" value="{tmpl_var name='id'}"> + + <div class="buttonHolder buttons"> + <button class="positive iconstxt icoPositive" type="button" value="{tmpl_var name='btn_save_txt'}" onclick="submitForm('pageForm','mail/mail_user_edit.php');"><span>{tmpl_var name='btn_save_txt'}</span></button> + <button class="negative iconstxt icoNegative" type="button" value="{tmpl_var name='btn_cancel_txt'}" onclick="loadContent('mail/mail_user_list.php');"><span>{tmpl_var name='btn_cancel_txt'}</span></button> + </div> + </div> + +</div> diff --git a/interface/web/mail/templates/mail_user_backup_list.htm b/interface/web/mail/templates/mail_user_backup_list.htm new file mode 100644 index 0000000000000000000000000000000000000000..7fc61fd098c561c2b0183d62ddd295029928d303 --- /dev/null +++ b/interface/web/mail/templates/mail_user_backup_list.htm @@ -0,0 +1,47 @@ +<tmpl_if name="msg"> + <div id="OKMsg"><p><tmpl_var name="msg"></p></div> +</tmpl_if> +<tmpl_if name="error"> + <div id="errorMsg"><h3>ERROR</h3><ol><tmpl_var name="error"></ol></div> +</tmpl_if> +<h3><tmpl_var name="list_head_txt"></h3> + +<div class="panel panel_list_mail_backup"> + + <div class="pnl_listarea"> + <fieldset><legend><tmpl_var name="list_head_txt"></legend> + <table class="list"> + <thead> + <tr class="caption"> + <th class="tbl_col_date" scope="col"><tmpl_var name="date_txt"></th> + <th class="tbl_col_filename" scope="col"><tmpl_var name="filename_txt"></th> + <th class="tbl_col_filename" scope="col"><tmpl_var name="filesize_txt"></th> + <th class="tbl_col_limit" scope="col">{tmpl_var name='search_limit'}</th> + </tr> + </thead> + <tbody> + <tmpl_loop name="records"> + <tr class="tbl_row_<tmpl_if name='__EVEN__'}even<tmpl_else>uneven</tmpl_if>"> + <td class="tbl_col_date">{tmpl_var name="date"}</td> + <td class="tbl_col_filename">{tmpl_var name="filename"}</td> + <td class="tbl_col_filesize">{tmpl_var name="filesize"}</td> + <td class="tbl_col_buttons"> + <div class="buttons"> + <button class="button iconstxt icoRestore" type="button" onclick="confirm_action('mail/mail_user_edit.php?id={tmpl_var name='parent_id'}&next_tab=backup&backup_action=restore&backup_id={tmpl_var name='backup_id'}','{tmpl_var name='restore_confirm_txt'}');"><span>{tmpl_var name="restore_backup_txt"}</span></button> +<!-- <button class="button iconstxt icoDownload" type="button" onclick="loadContent('mail/mail_user_edit.php?id={tmpl_var name='parent_id'}&next_tab=backup&backup_action=download&backup_id={tmpl_var name='backup_id'}');"><span>{tmpl_var name="download_backup_txt"}</span></button> +--> + </div> + </td> + </tr> + </tmpl_loop> + <tmpl_unless name="records"> + <tr class="tbl_row_noresults tbl_row_<tmpl_if name='__EVEN__'}even<tmpl_else>uneven</tmpl_if>"> + <td colspan="4">{tmpl_var name='globalsearch_noresults_text_txt'}</td> + </tr> + </tmpl_unless> + </tbody> + </table> + </fieldset> + </div> + +</div> diff --git a/server/lib/classes/cron.d/500-backup.inc.php b/server/lib/classes/cron.d/500-backup.inc.php index 4b2fd101c4e2136c28bb4f84b0e12e29a749a2e9..df5523967a58842a20398d6f7e3fe10007e41ff5 100644 --- a/server/lib/classes/cron.d/500-backup.inc.php +++ b/server/lib/classes/cron.d/500-backup.inc.php @@ -72,7 +72,7 @@ class cronjob_backup extends cronjob { chmod(escapeshellcmd($backup_dir), $backup_dir_permissions); } - $sql = "SELECT * FROM web_domain WHERE server_id = '".$conf['server_id']."' AND (type = 'vhost' OR type = 'vhostsubdomain') AND backup_interval != 'none'"; + $sql = "SELECT * FROM web_domain WHERE server_id = '".$conf['server_id']."' AND (type = 'vhost' OR type = 'vhostsubdomain')"; $records = $app->db->queryAllRecords($sql); if(is_array($records)) { foreach($records as $rec) { diff --git a/server/lib/classes/cron.d/500-backup_mail.inc.php b/server/lib/classes/cron.d/500-backup_mail.inc.php new file mode 100644 index 0000000000000000000000000000000000000000..40addb2754df3d43e33781fcebaf1023c6d87860 --- /dev/null +++ b/server/lib/classes/cron.d/500-backup_mail.inc.php @@ -0,0 +1,179 @@ +<?php +/* +Copyright (c) 2013, Florian Schaal, info@schaal-24.de +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of ISPConfig nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +class cronjob_backup extends cronjob { + + // job schedule + protected $_schedule = '0 0 * * *'; + + /* this function is optional if it contains no custom code */ + public function onPrepare() { + global $app; + + parent::onPrepare(); + } + + /* this function is optional if it contains no custom code */ + public function onBeforeRun() { + global $app; + + return parent::onBeforeRun(); + } + + public function onRunJob() { + global $app, $conf; + + $server_config = $app->getconf->get_server_config($conf['server_id'], 'server'); + $backup_dir = $server_config['backup_dir']; + $backup_mode = $server_config['backup_mode']; + if($backup_mode == '') $backup_mode = 'userzip'; + $backup_dir_permissions =0750; + + if($backup_dir != '') { +/* + //* mount backup directory, if necessary + $run_backups = true; + $server_config['backup_dir_mount_cmd'] = trim($server_config['backup_dir_mount_cmd']); + if($server_config['backup_dir_is_mount'] == 'y' && $server_config['backup_dir_mount_cmd'] != ''){ + if(!$app->system->is_mounted($backup_dir)){ + exec(escapeshellcmd($server_config['backup_dir_mount_cmd'])); + sleep(1); + if(!$app->system->is_mounted($backup_dir)) $run_backups = false; + } + } +*/ + + $mail_config = $app->getconf->get_server_config($conf['server_id'], 'mail'); + + if(!is_dir($backup_dir)) { + mkdir(escapeshellcmd($backup_dir), $backup_dir_permissions, true); + } else { + chmod(escapeshellcmd($backup_dir), $backup_dir_permissions); + } + + $sql = "SELECT * FROM mail_user WHERE server_id = '".$conf['server_id']."' AND maildir <> ''"; + $records = $app->db->queryAllRecords($sql); +/* + if(is_array($records) && $run_backups) { +*/ + if(is_array($records)) { + foreach($records as $rec) { + //* Do the mailbox backup + if($rec['backup_interval'] == 'daily' or ($rec['backup_interval'] == 'weekly' && date('w') == 0) or ($rec['backup_interval'] == 'monthly' && date('d') == '01')) { + $sql="SELECT * FROM mail_domain WHERE domain = '".$app->db->quote(explode("@",$rec['email'])[1])."'"; + $domain_rec=$app->db->queryOneRecord($sql); + $mail_backup_dir = $backup_dir.'/mail'.$domain_rec['domain_id']; + + if(!is_dir($mail_backup_dir)) mkdir($mail_backup_dir, 0750); + chmod($mail_backup_dir, $backup_dir_permissions); + + $domain_dir=explode('/',$rec['maildir']); + $_temp=array_pop($domain_dir);unset($_temp); + $domain_dir=implode('/',$domain_dir); + $source_dir=array_pop(explode('/',$rec['maildir'])); + + $mail_backup_file = 'mail'.$rec['mailuser_id'].'_'.date('Y-m-d_H-i'); + + if($backup_mode == 'userzip') { + $mail_backup_file.='.zip'; + exec('cd '.$rec['homedir'].' && zip -b /tmp -r '.$mail_backup_dir.'/'.$mail_backup_file.' '.$source_dir.' > /dev/nul'); + } else { + /* Create a tar.gz backup */ + $mail_backup_file.='.tar.gz'; + exec(escapeshellcmd('tar pczf '.$mail_backup_dir.'/'.$mail_backup_file.' --directory '.$domain_dir.' '.$source_dir), $tmp_output, $retval); + } + if($retval == 0){ + chown($mail_backup_dir.'/'.$mail_backup_file, 'root'); + chgrp($mail_backup_dir.'/'.$mail_backup_file, 'root'); + chmod($mail_backup_dir.'/'.$mail_backup_file, 0640); + /* Insert mail backup record in database */ + $sql = "INSERT INTO mail_backup (server_id,parent_domain_id,mailuser_id,backup_mode,tstamp,filename,filesize) VALUES (".$conf['server_id'].",".$domain_rec['domain_id'].",".$rec['mailuser_id'].",'".$backup_mode."',".time().",'".$app->db->quote($mail_backup_file)."','".$app->functions->formatBytes(filesize($mail_backup_dir.'/'.$mail_backup_file))."')"; + $app->db->query($sql); + if($app->db->dbHost != $app->dbmaster->dbHost) $app->dbmaster->query($sql); + } else { + /* Backup failed - remove archive */ + if(is_file($mail_backup_dir.'/'.$mail_backup_file)) unlink($mail_backup_dir.'/'.$mail_backup_file); + $app->log($mail_backup_file.' NOK:'.implode('',$tmp_output), LOGLEVEL_DEBUG); + } + /* Remove old backups */ + $backup_copies = intval($rec['backup_copies']); + $dir_handle = dir($mail_backup_dir); + $files = array(); + while (false !== ($entry = $dir_handle->read())) { + if($entry != '.' && $entry != '..' && substr($entry,0,4+strlen($rec['mailuser_id'])) == 'mail'.$rec['mailuser_id'] && is_file($mail_backup_dir.'/'.$entry)) { + $files[] = $entry; + } + } + $dir_handle->close(); + rsort($files); + for ($n = $backup_copies; $n <= 10; $n++) { + if(isset($files[$n]) && is_file($mail_backup_dir.'/'.$files[$n])) { + unlink($mail_backup_dir.'/'.$files[$n]); + $sql = "DELETE FROM mail_backup WHERE server_id = ".$conf['server_id']." AND parent_domain_id = ".$domain_rec['domain_id']." AND filename = '".$app->db->quote($files[$n])."'"; + $app->db->query($sql); + if($app->db->dbHost != $app->dbmaster->dbHost) $app->dbmaster->query($sql); + } + } + unset($files); + unset($dir_handle); + } + /* Remove inactive backups */ + if($rec['backup_interval'] == 'none') { + $sql="SELECT * FROM mail_domain WHERE domain = '".$app->db->quote(explode("@",$rec['email'])[1])."'"; + $domain_rec=$app->db->queryOneRecord($sql); + /* remove backups from db */ + $sql = "DELETE FROM mail_backup WHERE server_id = ".$conf['server_id']." AND parent_domain_id = ".$domain_rec['domain_id']." AND mailuser_id = ".$rec['mailuser_id']; + $app->db->query($sql); + if($app->db->dbHost != $app->dbmaster->dbHost) $app->dbmaster->query($sql); + /* remove archives */ + $mail_backup_dir = $backup_dir.'/mail'.$domain_rec['domain_id']; + $mail_backup_file = 'mail'.$rec['mailuser_id'].'_*'; + if(is_dir($mail_backup_dir)) { + foreach (glob($mail_backup_dir.'/'.$mail_backup_file) as $filename) { + unlink($filename); + } + } + } + } + } + } + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/plugins-available/backup_plugin.inc.php b/server/plugins-available/backup_plugin.inc.php index 6c6ef1452003fc8d37476eb1c64f887d04da69f3..d2590b48f0914fc088a5ec863bf1baa59d392cda 100644 --- a/server/plugins-available/backup_plugin.inc.php +++ b/server/plugins-available/backup_plugin.inc.php @@ -62,6 +62,7 @@ class backup_plugin { $backup_id = intval($data); $backup = $app->dbmaster->queryOneRecord("SELECT * FROM web_backup WHERE backup_id = $backup_id"); + $mail_backup = $app->dbmaster->queryOneRecord("SELECT * FROM mail_backup WHERE backup_id = $backup_id"); if(is_array($backup)) { @@ -149,9 +150,49 @@ class backup_plugin { } } } + //* Restore a mail backup - florian@schaal-24.de + } elseif (is_array($mail_backup) && $action_name == 'backup_restore') { + $app->uses('ini_parser,file,getconf'); + $server_config = $app->getconf->get_server_config($conf['server_id'], 'server'); + $mail_config = $app->getconf->get_server_config($conf['server_id'], 'mail'); + + $domain_rec = $app->db->queryOneRecord("SELECT * FROM mail_domain WHERE domain_id = ".intval($mail_backup['parent_domain_id'])); + + $backup_dir = $server_config['backup_dir'].'/mail'.$domain_rec['domain_id']; + $mail_backup_file = $backup_dir.'/'.$mail_backup['filename']; + + $sql = "SELECT * FROM mail_user WHERE server_id = '".$conf['server_id']."' AND mailuser_id = ".intval($mail_backup['mailuser_id']); + $record = $app->db->queryOneRecord($sql); + + //* strip mailbox from maildir + $domain_dir=explode('/',$record['maildir']); + $_temp=array_pop($domain_dir);unset($_temp); + $domain_dir=implode('/',$domain_dir); + if(file_exists($mail_backup_file) && $record['homedir'] != '' && $record['homedir'] != '/' && !stristr($mail_backup_file,'..') && !stristr($mail_backup_file,'etc') && $mail_config['homedir_path'] == $record['homedir'] && is_dir($domain_dir)) { + if($mail_backup['backup_mode'] == 'userzip') { + $command = 'sudo -u '.$mail_config['mailuser_name'].' unzip -qq -o '.escapeshellarg($mail_backup_file).' -d '.escapeshellarg($domain_dir).' 2> /dev/null'; + exec($command,$tmp_output, $retval); + if($retval == 0){ + $app->log('Restored Mail backup '.$mail_backup_file,LOGLEVEL_DEBUG); + } else { + $app->log('Unable to restore Mail backup '.$mail_backup_file.' '.$tmp_output,LOGLEVEL_ERROR); + } + } + if($mail_backup['backup_mode'] == 'rootgz') { + $command='tar xfz '.escapeshellarg($mail_backup_file).' --directory '.escapeshellarg($domain_dir); + exec($command,$tmp_output, $retval); + if($retval == 0){ + $app->log('Restored Mail backup '.$mail_backup_file,LOGLEVEL_DEBUG); + } else { + $app->log('Unable to restore Mail backup '.$mail_backup_file.' '.$tmp_output,LOGLEVEL_ERROR); + } + } + } else { + $app->log('Unable to restore Mail backup '.$mail_backup_file.' due to misconfiguration',LOGLEVEL_ERROR); + } } else { - $app->log('No backup with ID '.$backup_id.' found.', LOGLEVEL_DEBUG); + $app->log('No backup with ID '.$backup_id.' found.',LOGLEVEL_DEBUG); } return 'ok'; @@ -159,4 +200,5 @@ class backup_plugin { } // end class -?> +?> +