diff --git a/install/sql/ispconfig3.sql b/install/sql/ispconfig3.sql
index 8480e764481b16a4b88b2cea4a5c0aa60d4096b9..c562c0755b9ac37a68266130a5d7768dfe4c2aa6 100644
--- a/install/sql/ispconfig3.sql
+++ b/install/sql/ispconfig3.sql
@@ -1429,6 +1429,22 @@ CREATE TABLE `sys_config` (
   `value` varchar(255) NOT NULL
 ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `sys_cron`
+--
+
+CREATE TABLE IF NOT EXISTS `sys_cron` (
+  `name` varchar(50) NOT NULL,
+  `last_run` datetime NULL DEFAULT NULL,
+  `next_run` datetime NULL DEFAULT NULL,
+  `running` tinyint(1) UNSIGNED NOT NULL DEFAULT '0',
+  PRIMARY KEY (`name`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+
 -- --------------------------------------------------------
 
 --
diff --git a/server/cron.php b/server/cron.php
new file mode 100644
index 0000000000000000000000000000000000000000..ce7a26fad6ba15da6ef74099eebf7ce11d223c44
--- /dev/null
+++ b/server/cron.php
@@ -0,0 +1,90 @@
+<?php
+
+/*
+Copyright (c) 2007-2012, Till Brehm, projektfarm Gmbh
+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.
+*/
+
+define('SCRIPT_PATH', dirname($_SERVER["SCRIPT_FILENAME"]));
+require(SCRIPT_PATH."/lib/config.inc.php");
+require(SCRIPT_PATH."/lib/app.inc.php");
+
+set_time_limit(0);
+ini_set('error_reporting', E_ALL & ~E_NOTICE);
+
+// make sure server_id is always an int
+$conf['server_id'] = intval($conf['server_id']);
+
+
+// Load required base-classes
+$app->uses('ini_parser,file,services,getconf,system,cron,functions');
+$app->load('libdatetime,cronjob');
+
+
+// read all cron jobs
+$path = SCRIPT_PATH . '/lib/classes/cron.d';
+if(!is_dir($path)) die('Cron path missing!');
+$files = array();
+$d = opendir($path);
+while($f = readdir($d)) {
+    $file_path = $path . '/' . $f;
+    if($f === '.' || $f === '..' || !is_file($file_path)) continue;
+    if(substr($f, strrpos($f, '.')) !== '.php') continue;
+    $files[] = $f;
+}
+closedir($d);
+
+// sort in alphabetical order, so we can use prefixes like 000-xxx
+sort($files);
+    
+foreach($files as $f) {
+    $name = substr($f, 0, strpos($f, '.'));
+    if(preg_match('/^\d+\-(.*)$/', $name, $match)) $name = $match[1]; // strip numerical prefix from file name
+    
+    include($path . '/' . $f);
+    $class_name = 'cronjob_' . $name;
+    
+    if(class_exists($class_name, false)) {
+        $cronjob = new $class_name();
+        if(get_parent_class($cronjob) !== 'cronjob') {
+            print 'Invalid class ' . $class_name . ' not extending class cronjob (' . get_parent_class($cronjob) . ')!' . "\n";
+            unset($cronjob);
+            continue;
+        }
+        print 'Included ' . $class_name . ' from ' . $file_path . ' -> will now run job.' . "\n";
+        
+        $cronjob->run();
+        
+        print 'run job (' . $class_name . ') done.' . "\n";
+        
+        unset($cronjob);
+    }
+}
+unset($files);
+
+die("finished.\n");
+
+?>
diff --git a/server/cron.sh b/server/cron.sh
new file mode 100644
index 0000000000000000000000000000000000000000..281bb13afeb17ab4866ec357ff2e430e1288ebbd
--- /dev/null
+++ b/server/cron.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/X11R6/bin
+
+if [ -f /usr/local/ispconfig/server/lib/php.ini ]; then
+        PHPINIOWNER=`stat -c %U /usr/local/ispconfig/server/lib/php.ini`
+        if [ $PHPINIOWNER == 'root' ] || [ $PHPINIOWNER == 'ispconfig'  ]; then
+                export PHPRC=/usr/local/ispconfig/server/lib
+        fi
+fi
+
+/usr/bin/php -q /usr/local/ispconfig/server/cron.php
diff --git a/server/cron_daily.php b/server/cron_daily.php
deleted file mode 100644
index 029c4f30fb2b020227dc0b7ec1348937bf7321d8..0000000000000000000000000000000000000000
--- a/server/cron_daily.php
+++ /dev/null
@@ -1,1346 +0,0 @@
-<?php
-
-/*
-Copyright (c) 2007-2012, Till Brehm, projektfarm Gmbh
-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.
-*/
-
-define('SCRIPT_PATH', dirname($_SERVER["SCRIPT_FILENAME"]));
-require(SCRIPT_PATH."/lib/config.inc.php");
-require(SCRIPT_PATH."/lib/app.inc.php");
-
-set_time_limit(0);
-ini_set('error_reporting', E_ALL & ~E_NOTICE);
-
-// make sure server_id is always an int
-$conf['server_id'] = intval($conf['server_id']);
-
-
-// Load required base-classes
-$app->uses('ini_parser,file,services,getconf,system');
-
-
-#######################################################################################################
-// store the mailbox statistics in the database
-#######################################################################################################
-
-$parse_mail_log = false;
-$sql = "SELECT mailuser_id,maildir FROM mail_user WHERE server_id = ".$conf['server_id'];
-$records = $app->db->queryAllRecords($sql);
-if(count($records) > 0) $parse_mail_log = true;
-
-foreach($records as $rec) {
-	if(@is_file($rec['maildir'].'/ispconfig_mailsize')) {
-        $parse_mail_log = false;
-
-		// rename file
-		rename($rec['maildir'].'/ispconfig_mailsize',$rec['maildir'].'/ispconfig_mailsize_save');
-
-		// Read the file
-		$lines = file($rec['maildir'].'/ispconfig_mailsize_save');
-		$mail_traffic = 0;
-		foreach($lines as $line) {
-			$mail_traffic += intval($line);
-		}
-		unset($lines);
-
-		// Delete backup file
-		if(@is_file($rec['maildir'].'/ispconfig_mailsize_save')) unlink($rec['maildir'].'/ispconfig_mailsize_save');
-
-		// Save the traffic stats in the sql database
-		$tstamp = date('Y-m');
-
-		$sql = "SELECT * FROM mail_traffic WHERE month = '$tstamp' AND mailuser_id = ".$rec['mailuser_id'];
-		$tr = $app->dbmaster->queryOneRecord($sql);
-
-		$mail_traffic += $tr['traffic'];
-		if($tr['traffic_id'] > 0) {
-			$sql = "UPDATE mail_traffic SET traffic = $mail_traffic WHERE traffic_id = ".$tr['traffic_id'];
-		} else {
-			$sql = "INSERT INTO mail_traffic (month,mailuser_id,traffic) VALUES ('$tstamp',".$rec['mailuser_id'].",$mail_traffic)";
-		}
-		$app->dbmaster->query($sql);
-		//echo $sql;
-
-	}
-
-}
-
-if($parse_mail_log == true) {
-    $mailbox_traffic = array();
-    $mail_boxes = array();
-    $mail_rewrites = array(); // we need to read all mail aliases and forwards because the address in amavis is not always the mailbox address
-
-    function parse_mail_log_line($line) {
-        //Oct 31 17:35:48 mx01 amavis[32014]: (32014-05) Passed CLEAN, [IPv6:xxxxx] [IPv6:xxxxx] <xxx@yyyy> -> <aaaa@bbbb>, Message-ID: <xxxx@yyyyy>, mail_id: xxxxxx, Hits: -1.89, size: 1591, queued_as: xxxxxxx, 946 ms
-
-        if(preg_match('/^(\w+\s+\d+\s+\d+:\d+:\d+)\s+[^ ]+\s+amavis.* <([^>]+)>\s+->\s+((<[^>]+>,)+) .*Message-ID:\s+<([^>]+)>.* size:\s+(\d+),.*$/', $line, $matches) == false) return false;
-
-        $timestamp = strtotime($matches[1]);
-        if(!$timestamp) return false;
-
-        $to = array();
-        $recipients = explode(',', $matches[3]);
-        foreach($recipients as $recipient) {
-            $recipient = substr($recipient, 1, -1);
-            if(!$recipient || $recipient == $matches[2]) continue;
-            $to[] = $recipient;
-        }
-
-        return array('line' => $line, 'timestamp' => $timestamp, 'size' => $matches[6], 'from' => $matches[2], 'to' => $to, 'message-id' => $matches[5]);
-    }
-
-    function add_mailbox_traffic(&$traffic_array, $address, $traffic) {
-        global $mail_boxes, $mail_rewrites;
-
-        $address = strtolower($address);
-
-        if(in_array($address, $mail_boxes) == true) {
-            if(!isset($traffic_array[$address])) $traffic_array[$address] = 0;
-            $traffic_array[$address] += $traffic;
-        } elseif(array_key_exists($address, $mail_rewrites)) {
-            foreach($mail_rewrites[$address] as $address) {
-                if(!isset($traffic_array[$address])) $traffic_array[$address] = 0;
-                $traffic_array[$address] += $traffic;
-            }
-        } else {
-            // this is not a local address - skip it
-        }
-    }
-
-    $sql = "SELECT email FROM mail_user WHERE server_id = ".$conf['server_id'];
-    $records = $app->db->queryAllRecords($sql);
-    foreach($records as $record) {
-        $mail_boxes[] = $record['email'];
-    }
-    $sql = "SELECT source, destination FROM mail_forwarding WHERE server_id = ".$conf['server_id'];
-    $records = $app->db->queryAllRecords($sql);
-    foreach($records as $record) {
-        $targets = preg_split('/[\n,]+/', $record['destination']);
-        foreach($targets as $target) {
-            if(in_array($target, $mail_boxes)) {
-                if(isset($mail_rewrites[$record['source']])) $mail_rewrites[$record['source']][] = $target;
-                else $mail_rewrites[$record['source']] = array($target);
-            }
-        }
-    }
-
-    $state_file = dirname(__FILE__) . '/mail_log_parser.state';
-    $prev_line = false;
-    $last_line = false;
-    $cur_line = false;
-
-    if(file_exists($state_file)) {
-        $prev_line = parse_mail_log_line(trim(file_get_contents($state_file)));
-        //if($prev_line) echo "continuing from previous run, log position: " . $prev_line['message-id'] . " at " . strftime('%d.%m.%Y %H:%M:%S', $prev_line['timestamp']) . "\n";
-    }
-
-    if(file_exists('/var/log/mail.log')) {
-        $fp = fopen('/var/log/mail.log', 'r');
-        //echo "Parsing mail.log...\n";
-        $l = 0;
-        while($line = fgets($fp, 8192)) {
-            $l++;
-            //if($l % 1000 == 0) echo "\rline $l";
-            $cur_line = parse_mail_log_line($line);
-            if(!$cur_line) continue;
-
-            if($prev_line) {
-                // check if this line has to be processed
-                if($cur_line['timestamp'] < $prev_line['timestamp']) {
-                    $parse_mail_log = false; // we do not need to parse the second file!
-                    continue; // already processed
-                } elseif($cur_line['timestamp'] == $prev_line['timestamp'] && $cur_line['message-id'] == $prev_line['message-id']) {
-                    $parse_mail_log = false; // we do not need to parse the second file!
-                    $prev_line = false; // this line has already been processed but the next one has to be!
-                    continue;
-                }
-            }
-
-            add_mailbox_traffic($mailbox_traffic, $cur_line['from'], $cur_line['size']);
-            foreach($cur_line['to'] as $to) {
-                add_mailbox_traffic($mailbox_traffic, $to, $cur_line['size']);
-            }
-            $last_line = $line; // store for the state file
-        }
-        fclose($fp);
-        //echo "\n";
-    }
-
-    if($parse_mail_log == true && file_exists('/var/log/mail.log.1')) {
-        $fp = fopen('/var/log/mail.log.1', 'r');
-        //echo "Parsing mail.log.1...\n";
-        $l = 0;
-        while($line = fgets($fp, 8192)) {
-            $l++;
-            //if($l % 1000 == 0) echo "\rline $l";
-            $cur_line = parse_mail_log_line($line);
-            if(!$cur_line) continue;
-
-            if($prev_line) {
-                // check if this line has to be processed
-                if($cur_line['timestamp'] < $prev_line['timestamp']) continue; // already processed
-                if($cur_line['timestamp'] == $prev_line['timestamp'] && $cur_line['message-id'] == $prev_line['message-id']) {
-                    $prev_line = false; // this line has already been processed but the next one has to be!
-                    continue;
-                }
-            }
-
-            add_mailbox_traffic($mailbox_traffic, $cur_line['from'], $cur_line['size']);
-            foreach($cur_line['to'] as $to) {
-                add_mailbox_traffic($mailbox_traffic, $to, $cur_line['size']);
-            }
-        }
-        fclose($fp);
-        //echo "\n";
-    }
-    unset($mail_rewrites);
-    unset($mail_boxes);
-
-    // Save the traffic stats in the sql database
-    $tstamp = date('Y-m');
-    $sql = "SELECT mailuser_id,email FROM mail_user WHERE server_id = ".$conf['server_id'];
-    $records = $app->db->queryAllRecords($sql);
-    foreach($records as $rec) {
-        if(array_key_exists($rec['email'], $mailbox_traffic)) {
-            $sql = "SELECT * FROM mail_traffic WHERE month = '$tstamp' AND mailuser_id = ".$rec['mailuser_id'];
-            $tr = $app->dbmaster->queryOneRecord($sql);
-
-            $mail_traffic = $tr['traffic'] + $mailbox_traffic[$rec['email']];
-            if($tr['traffic_id'] > 0) {
-                $sql = "UPDATE mail_traffic SET traffic = $mail_traffic WHERE traffic_id = ".$tr['traffic_id'];
-            } else {
-                $sql = "INSERT INTO mail_traffic (month,mailuser_id,traffic) VALUES ('$tstamp',".$rec['mailuser_id'].",$mail_traffic)";
-            }
-            $app->dbmaster->query($sql);
-            //echo $sql;
-        }
-    }
-
-    unset($mailbox_traffic);
-    if($last_line) file_put_contents($state_file, $last_line);
-}
-
-#######################################################################################################
-// Create webalizer statistics
-#######################################################################################################
-
-function setConfigVar( $filename, $varName, $varValue, $append = 0 ) {
-	if($lines = @file($filename)) {
-		$out = '';
-		$found = 0;
-		foreach($lines as $line) {
-			@list($key, $value) = preg_split('/[\t= ]+/', $line, 2);
-			if($key == $varName) {
-				$out .= $varName.' '.$varValue."\n";
-				$found = 1;
-			} else {
-				$out .= $line;
-			}
-		}
-		if($found == 0) {
-			//* add \n if the last line does not end with \n or \r
-			if(substr($out,-1) != "\n" && substr($out,-1) != "\r") $out .= "\n";
-			//* add the new line at the end of the file
-			if($append == 1) $out .= $varName.' '.$varValue."\n";
-		}
-
-		file_put_contents($filename,$out);
-	}
-}
-
-
-$sql = "SELECT domain_id, domain, document_root, web_folder, type, parent_domain_id FROM web_domain WHERE (type = 'vhost' or type = 'vhostsubdomain') and stats_type = 'webalizer' AND server_id = ".$conf['server_id'];
-$records = $app->db->queryAllRecords($sql);
-
-foreach($records as $rec) {
-	//$yesterday = date('Ymd',time() - 86400);
-	$yesterday = date('Ymd',strtotime("-1 day", time()));
-
-    $log_folder = 'log';
-    if($rec['type'] == 'vhostsubdomain') {
-        $tmp = $app->db->queryOneRecord('SELECT `domain` FROM web_domain WHERE domain_id = '.intval($rec['parent_domain_id']));
-        $subdomain_host = preg_replace('/^(.*)\.' . preg_quote($tmp['domain'], '/') . '$/', '$1', $rec['domain']);
-        if($subdomain_host == '') $subdomain_host = 'web'.$rec['domain_id'];
-        $log_folder .= '/' . $subdomain_host;
-        unset($tmp);
-    }
-    $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$yesterday.'-access.log');
-	if(!@is_file($logfile)) {
-		$logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$yesterday.'-access.log.gz');
-		if(!@is_file($logfile)) {
-			continue;
-		}
-	}
-
-	$domain = escapeshellcmd($rec['domain']);
-	$statsdir = escapeshellcmd($rec['document_root'].'/'.($rec['type'] == 'vhostsubdomain' ? $rec['web_folder'] : 'web').'/stats');
-	$webalizer = '/usr/bin/webalizer';
-	$webalizer_conf_main = '/etc/webalizer/webalizer.conf';
-	$webalizer_conf = escapeshellcmd($rec['document_root'].'/log/webalizer.conf');
-
-	if(is_file($statsdir.'/index.php')) unlink($statsdir.'/index.php');
-
-	if(!@is_file($webalizer_conf)) {
-		copy($webalizer_conf_main,$webalizer_conf);
-	}
-
-	if(@is_file($webalizer_conf)) {
-		setConfigVar($webalizer_conf, 'Incremental', 'yes');
-		setConfigVar($webalizer_conf, 'IncrementalName', $statsdir.'/webalizer.current');
-		setConfigVar($webalizer_conf, 'HistoryName', $statsdir.'/webalizer.hist');
-	}
-
-
-	if(!@is_dir($statsdir)) mkdir($statsdir);
-	exec("$webalizer -c $webalizer_conf -n $domain -s $domain -r $domain -q -T -p -o $statsdir $logfile");
-}
-
-#######################################################################################################
-// Create awstats statistics
-#######################################################################################################
-
-$sql = "SELECT domain_id, domain, document_root, web_folder, type, system_user, system_group, parent_domain_id FROM web_domain WHERE (type = 'vhost' or type = 'vhostsubdomain') and stats_type = 'awstats' AND server_id = ".$conf['server_id'];
-$records = $app->db->queryAllRecords($sql);
-
-$web_config = $app->getconf->get_server_config($conf['server_id'], 'web');
-
-foreach($records as $rec) {
-	//$yesterday = date('Ymd',time() - 86400);
-	$yesterday = date('Ymd',strtotime("-1 day", time()));
-
-    $log_folder = 'log';
-    if($rec['type'] == 'vhostsubdomain') {
-        $tmp = $app->db->queryOneRecord('SELECT `domain` FROM web_domain WHERE domain_id = '.intval($rec['parent_domain_id']));
-        $subdomain_host = preg_replace('/^(.*)\.' . preg_quote($tmp['domain'], '/') . '$/', '$1', $rec['domain']);
-        if($subdomain_host == '') $subdomain_host = 'web'.$rec['domain_id'];
-        $log_folder .= '/' . $subdomain_host;
-        unset($tmp);
-    }
-    $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$yesterday.'-access.log');
-	if(!@is_file($logfile)) {
-		$logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$yesterday.'-access.log.gz');
-		if(!@is_file($logfile)) {
-			continue;
-		}
-	}
-    $web_folder = ($rec['type'] == 'vhostsubdomain' ? $rec['web_folder'] : 'web');
-	$domain = escapeshellcmd($rec['domain']);
-	$statsdir = escapeshellcmd($rec['document_root'].'/'.$web_folder.'/stats');
-	$awstats_pl = $web_config['awstats_pl'];
-	$awstats_buildstaticpages_pl = $web_config['awstats_buildstaticpages_pl'];
-
-	$awstats_conf_dir = $web_config['awstats_conf_dir'];
-	$awstats_website_conf_file = $web_config['awstats_conf_dir'].'/awstats.'.$domain.'.conf';
-
-	if(is_file($awstats_website_conf_file)) unlink($awstats_website_conf_file);
-
-	$sql = "SELECT domain FROM web_domain WHERE (type = 'alias' OR type = 'subdomain') AND parent_domain_id = ".$rec['domain_id'];
-	$aliases = $app->db->queryAllRecords($sql);
-	$aliasdomain = '';
-
-	if(is_array($aliases)) {
-		foreach ($aliases as $alias) {
-			$aliasdomain.= ' '.$alias['domain']. ' www.'.$alias['domain'];
-		}
-	}
-
-	if(!is_file($awstats_website_conf_file)) {
-		$awstats_conf_file_content = 'Include "'.$awstats_conf_dir.'/awstats.conf"
-LogFile="/var/log/ispconfig/httpd/'.$domain.'/yesterday-access.log"
-SiteDomain="'.$domain.'"
-HostAliases="www.'.$domain.' localhost 127.0.0.1'.$aliasdomain.'"';
-		file_put_contents($awstats_website_conf_file,$awstats_conf_file_content);
-	}
-
-	if(!@is_dir($statsdir)) mkdir($statsdir);
-	if(is_link('/var/log/ispconfig/httpd/'.$domain.'/yesterday-access.log')) unlink('/var/log/ispconfig/httpd/'.$domain.'/yesterday-access.log');
-	symlink($logfile,'/var/log/ispconfig/httpd/'.$domain.'/yesterday-access.log');
-
-	$awmonth = date("n");
-	$awyear = date("Y");
-
-	if (date("d") == 1) {
-		$awmonth = date("m")-1;
-		if (date("m") == 1) {
-			$awyear = date("Y")-1;
-			$awmonth = "12";
-		}
-	}
-
-	// awstats_buildstaticpages.pl -update -config=mydomain.com -lang=en -dir=/var/www/domain.com/'.$web_folder.'/stats -awstatsprog=/path/to/awstats.pl
-	// $command = "$awstats_buildstaticpages_pl -update -config='$domain' -lang=".$conf['language']." -dir='$statsdir' -awstatsprog='$awstats_pl'";
-
-	$command = "$awstats_buildstaticpages_pl -month='$awmonth' -year='$awyear' -update -config='$domain' -lang=".$conf['language']." -dir='$statsdir' -awstatsprog='$awstats_pl'";
-
-	if (date("d") == 2) {
-		$awmonth = date("m")-1;
-		if (date("m") == 1) {
-			$awyear = date("Y")-1;
-			$awmonth = "12";
-		}
-
-		$statsdirold = $statsdir."/".$awyear."-".$awmonth."/";
-		mkdir($statsdirold);
-		$files = scandir($statsdir);
-		foreach ($files as $file) {
-			if (substr($file,0,1) != "." && !is_dir("$statsdir"."/"."$file") && substr($file,0,1) != "w" && substr($file,0,1) != "i") copy("$statsdir"."/"."$file","$statsdirold"."$file");
-		}
-	}
-
-
-	if($awstats_pl != '' && $awstats_buildstaticpages_pl != '' && fileowner($awstats_pl) == 0 && fileowner($awstats_buildstaticpages_pl) == 0) {
-		exec($command);
-		if(is_file($rec['document_root'].'/'.$web_folder.'/stats/index.html')) unlink($rec['document_root'].'/'.$web_folder.'/stats/index.html');
-		rename($rec['document_root'].'/'.$web_folder.'/stats/awstats.'.$domain.'.html',$rec['document_root'].'/'.$web_folder.'/stats/awsindex.html');
-		if(!is_file($rec['document_root']."/".$web_folder."/stats/index.php")) {
-			if(file_exists("/usr/local/ispconfig/server/conf-custom/awstats_index.php.master")) {
-				copy("/usr/local/ispconfig/server/conf-custom/awstats_index.php.master",$rec['document_root']."/".$web_folder."/stats/index.php");
-			} else {
-				copy("/usr/local/ispconfig/server/conf/awstats_index.php.master",$rec['document_root']."/".$web_folder."/stats/index.php");
-			}
-		}
-
-		$app->log('Created awstats statistics with command: '.$command,LOGLEVEL_DEBUG);
-	} else {
-		$app->log("No awstats statistics created. Either $awstats_pl or $awstats_buildstaticpages_pl is not owned by root user.",LOGLEVEL_WARN);
-	}
-
-	if(is_file($rec['document_root']."/".$web_folder."/stats/index.php")) {
-		chown($rec['document_root']."/".$web_folder."/stats/index.php",$rec['system_user']);
-		chgrp($rec['document_root']."/".$web_folder."/stats/index.php",$rec['system_group']);
-	}
-
-}
-
-
-#######################################################################################################
-// Make the web logfiles directories world readable to enable ftp access
-#######################################################################################################
-
-if(is_dir('/var/log/ispconfig/httpd')) exec('chmod +r /var/log/ispconfig/httpd/*');
-
-#######################################################################################################
-// Manage and compress web logfiles and create traffic statistics
-#######################################################################################################
-
-$sql = "SELECT domain_id, domain, type, document_root, web_folder, parent_domain_id FROM web_domain WHERE (type = 'vhost' or type = 'vhostsubdomain') AND server_id = ".$conf['server_id'];
-$records = $app->db->queryAllRecords($sql);
-foreach($records as $rec) {
-
-	//* create traffic statistics based on yesterdays access log file
-	$yesterday = date('Ymd',time() - 86400);
-
-    $log_folder = 'log';
-    if($rec['type'] == 'vhostsubdomain') {
-        $tmp = $app->db->queryOneRecord('SELECT `domain` FROM web_domain WHERE domain_id = '.intval($rec['parent_domain_id']));
-        $subdomain_host = preg_replace('/^(.*)\.' . preg_quote($tmp['domain'], '/') . '$/', '$1', $rec['domain']);
-        if($subdomain_host == '') $subdomain_host = 'web'.$rec['domain_id'];
-        $log_folder .= '/' . $subdomain_host;
-        unset($tmp);
-    }
-
-    $logfile = $rec['document_root'].'/' . $log_folder . '/'.$yesterday.'-access.log';
-	$total_bytes = 0;
-
-	$handle = @fopen($logfile, "r");
-	if ($handle) {
-		while (($line = fgets($handle, 4096)) !== false) {
-			if (preg_match('/^\S+ \S+ \S+ \[.*?\] "\S+.*?" \d+ (\d+) ".*?" ".*?"/', $line, $m)) {
-				$total_bytes += intval($m[1]);
-			}
-		}
-
-		//* Insert / update traffic in master database
-		$traffic_date = date('Y-m-d',time() - 86400);
-		$tmp = $app->dbmaster->queryOneRecord("select hostname from web_traffic where hostname='".$rec['domain']."' and traffic_date='".$traffic_date."'");
-		if(is_array($tmp) && count($tmp) > 0) {
-			$sql = "update web_traffic set traffic_bytes=traffic_bytes+"
-                  . $total_bytes
-                  . " where hostname='" . $rec['domain']
-                  . "' and traffic_date='" . $traffic_date . "'";
-		} else {
-			$sql = "insert into web_traffic (hostname, traffic_date, traffic_bytes) values ('".$rec['domain']."', '".$traffic_date."', '".$total_bytes."')";
-		}
-		$app->dbmaster->query($sql);
-
-		fclose($handle);
-	}
-
-	$yesterday2 = date('Ymd',time() - 86400*2);
-	$logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$yesterday2.'-access.log');
-
-	//* Compress logfile
-	if(@is_file($logfile)) {
-		// Compress yesterdays logfile
-		exec("gzip -c $logfile > $logfile.gz");
-		unlink($logfile);
-	}
-
-	// rotate and compress the error.log when it exceeds a size of 10 MB
-	$logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/error.log');
-	if(is_file($logfile) && filesize($logfile) > 10000000) {
-		exec("gzip -c $logfile > $logfile.1.gz");
-		exec("cat /dev/null > $logfile");
-	}
-
-	// delete logfiles after 30 days
-	$month_ago = date('Ymd',time() - 86400 * 30);
-	$logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$month_ago.'-access.log.gz');
-	if(@is_file($logfile)) {
-		unlink($logfile);
-	}
-
-	//* Delete older Log files, in case that we missed them before due to serverdowntimes.
-	$datepart = date('Ym',time() - 86400 * 31 * 2);
-
-	$logfile = escapeshellcmd($rec['document_root']).'/' . $log_folder . '/'.$datepart.'*-access.log.gz';
-	exec('rm -f '.$logfile);
-
-	$logfile = escapeshellcmd($rec['document_root']).'/' . $log_folder . '/'.$datepart.'*-access.log';
-	exec('rm -f '.$logfile);
-}
-
-//* Delete old logfiles in /var/log/ispconfig/httpd/ that were created by vlogger for the hostname of the server
-exec('hostname -f', $tmp_hostname);
-if($tmp_hostname[0] != '' && is_dir('/var/log/ispconfig/httpd/'.$tmp_hostname[0])) {
-	exec('cd /var/log/ispconfig/httpd/'.$tmp_hostname[0]."; find . -mtime +30 -name '*.log' | xargs rm > /dev/null 2> /dev/null");
-}
-unset($tmp_hostname);
-
-#######################################################################################################
-// Rotate the ispconfig.log file
-#######################################################################################################
-
-// rotate the ispconfig.log when it exceeds a size of 10 MB
-$logfile = $conf['ispconfig_log_dir'].'/ispconfig.log';
-if(is_file($logfile) && filesize($logfile) > 10000000) {
-	exec("gzip -c $logfile > $logfile.1.gz");
-	exec("cat /dev/null > $logfile");
-}
-
-// rotate the cron.log when it exceeds a size of 10 MB
-$logfile = $conf['ispconfig_log_dir'].'/cron.log';
-if(is_file($logfile) && filesize($logfile) > 10000000) {
-	exec("gzip -c $logfile > $logfile.1.gz");
-	exec("cat /dev/null > $logfile");
-}
-
-// rotate the auth.log when it exceeds a size of 10 MB
-$logfile = $conf['ispconfig_log_dir'].'/auth.log';
-if(is_file($logfile) && filesize($logfile) > 10000000) {
-	exec("gzip -c $logfile > $logfile.1.gz");
-	exec("cat /dev/null > $logfile");
-}
-
-#######################################################################################################
-// Cleanup website tmp directories
-#######################################################################################################
-
-$sql = "SELECT domain_id, domain, document_root, system_user FROM web_domain WHERE server_id = ".$conf['server_id'];
-$records = $app->db->queryAllRecords($sql);
-$app->uses('system');
-if(is_array($records)) {
-	foreach($records as $rec){
-		$tmp_path = realpath(escapeshellcmd($rec['document_root'].'/tmp'));
-		if($tmp_path != '' && strlen($tmp_path) > 10 && is_dir($tmp_path) && $app->system->is_user($rec['system_user'])){
-			exec('cd '.$tmp_path."; find . -mtime +1 -name 'sess_*' | grep -v -w .no_delete | xargs rm > /dev/null 2> /dev/null");
-		}
-	}
-}
-
-#######################################################################################################
-// Cleanup logs in master database (only the "master-server")
-#######################################################################################################
-
-if ($app->dbmaster == $app->db) {
-	/** 7 days */
-	$tstamp = time() - (60*60*24*7);
-
-	/*
-	 *  Keep 7 days in sys_log
-	 * (we can delete the old items, because if they are OK, they don't interrest anymore
-	 * if they are NOT ok, the server will try to process them in 1 minute and so the
-	 * error appears again after 1 minute. So it is no problem to delete the old one!
-	 */
-	$sql = "DELETE FROM sys_log WHERE tstamp < " . $tstamp . " AND server_id != 0";
-	$app->dbmaster->query($sql);
-
-	/*
-	 * Delete all remote-actions "done" and older than 7 days
-	 * ATTENTION: We have the same problem as described in cleaning the datalog. We must not
-	 * delete the last entry
-	 */
-	$sql = "SELECT max(action_id) FROM sys_remoteaction";
-	$res = $app->dbmaster->queryOneRecord($sql);
-	$maxId = $res['max(action_id)'];
-	$sql =  "DELETE FROM sys_remoteaction " .
-			"WHERE tstamp < " . $tstamp . " " .
-			" AND action_state = 'ok' " .
-			" AND action_id <" . intval($maxId);
-	$app->dbmaster->query($sql);
-
-	/*
-	 * The sys_datalog is more difficult.
-	 * 1) We have to keet ALL entries with
-	 *    server_id=0, because they depend on ALL servers (even if they are not
-	 *    actually in the system (and will be insered in 3 days or so).
-	 * 2) We have to keey ALL entries which are not actually precessed by the
-	 *    server never mind how old they are!
-	 * 3) We have to keep the entry with the highest autoinc-id, because mysql calculates the
-	 *    autoinc-id as "new value = max(row) +1" and does not store this in a separate table.
-	 *    This means, if we delete to entry with the highest autoinc-value then this value is
-	 *    reused as autoinc and so there are more than one entries with the same value (over
-	 *    for example 4 Weeks). This is confusing for our system.
-	 *    ATTENTION 2) and 3) is in some case NOT the same! so we have to check both!
-	 */
-
-	/* First we need all servers and the last sys_datalog-id they processed */
-	$sql = "SELECT server_id, updated FROM server ORDER BY server_id";
-	$records = $app->dbmaster->queryAllRecords($sql);
-
-	/* Then we need the highest value ever */
-	$sql = "SELECT max(datalog_id) FROM sys_datalog";
-	$res = $app->dbmaster->queryOneRecord($sql);
-	$maxId = $res['max(datalog_id)'];
-
-	/* Then delete server by server */
-	foreach($records as $server) {
-		$tmp_server_id = intval($server['server_id']);
-		if($tmp_server_id > 0) {
-			$sql = 	"DELETE FROM sys_datalog " .
-					"WHERE tstamp < " . $tstamp .
-					" AND server_id = " . intval($server['server_id']) .
-					" AND datalog_id < " . intval($server['updated']) .
-					" AND datalog_id < " . intval($maxId);
-		}
-//		echo $sql . "\n";
-		$app->dbmaster->query($sql);
-	}
-}
-
-#########
-// function for sending notification emails
-#########
-function send_notification_email($template, $placeholders, $recipients) {
-    global $conf;
-
-    if(!is_array($recipients) || count($recipients) < 1) return false;
-    if(!is_array($placeholders)) $placeholders = array();
-
-    if(file_exists($conf['rootpath'].'/conf-custom/mail/' . $template . '_'.$conf['language'].'.txt')) {
-        $lines = file($conf['rootpath'].'/conf-custom/mail/' . $template . '_'.$conf['language'].'.txt');
-    } elseif(file_exists($conf['rootpath'].'/conf-custom/mail/' . $template . '_en.txt')) {
-        $lines = file($conf['rootpath'].'/conf-custom/mail/' . $template . '_en.txt');
-    } elseif(file_exists($conf['rootpath'].'/conf/mail/' . $template . '_'.$conf['language'].'.txt')) {
-        $lines = file($conf['rootpath'].'/conf/mail/' . $template . '_'.$conf['language'].'.txt');
-    } else {
-        $lines = file($conf['rootpath'].'/conf/mail/' . $template . '_en.txt');
-    }
-
-    //* get mail headers, subject and body
-    $mailHeaders = '';
-    $mailBody = '';
-    $mailSubject = '';
-    $inHeader = true;
-    for($l = 0; $l < count($lines); $l++) {
-        if($lines[$l] == '') {
-            $inHeader = false;
-            continue;
-        }
-        if($inHeader == true) {
-            $parts = explode(':', $lines[$l], 2);
-            if(strtolower($parts[0]) == 'subject') $mailSubject = trim($parts[1]);
-            unset($parts);
-            $mailHeaders .= trim($lines[$l]) . "\n";
-        } else {
-            $mailBody .= trim($lines[$l]) . "\n";
-        }
-    }
-    $mailBody = trim($mailBody);
-
-    //* Replace placeholders
-    $mailHeaders = strtr($mailHeaders, $placeholders);
-    $mailSubject = strtr($mailSubject, $placeholders);
-    $mailBody = strtr($mailBody, $placeholders);
-
-    for($r = 0; $r < count($recipients); $r++) {
-        mail($recipients[$r], $mailSubject, $mailBody, $mailHeaders);
-    }
-
-    unset($mailSubject);
-    unset($mailHeaders);
-    unset($mailBody);
-    unset($lines);
-
-    return true;
-}
-
-
-#######################################################################################################
-// enforce traffic quota (run only on the "master-server")
-#######################################################################################################
-
-if ($app->dbmaster == $app->db) {
-
-	$global_config = $app->getconf->get_global_config('mail');
-
-	$current_month = date('Y-m');
-
-	//* Check website traffic quota
-	$sql = "SELECT sys_groupid,domain_id,domain,traffic_quota,traffic_quota_lock FROM web_domain WHERE (traffic_quota > 0 or traffic_quota_lock = 'y') and (type = 'vhost' OR type = 'vhostsubdomain')";
-	$records = $app->db->queryAllRecords($sql);
-	if(is_array($records)) {
-		foreach($records as $rec) {
-
-			$web_traffic_quota = $rec['traffic_quota'];
-			$domain = $rec['domain'];
-
-			// get the client
-			/*
-			$client_group_id = $rec["sys_groupid"];
-			$client = $app->db->queryOneRecord("SELECT limit_traffic_quota,parent_client_id FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
-			$reseller = $app->db->queryOneRecord("SELECT limit_traffic_quota FROM client WHERE client_id = ".intval($client['parent_client_id']));
-
-			$client_traffic_quota = intval($client['limit_traffic_quota']);
-			$reseller_traffic_quota = intval($reseller['limit_traffic_quota']);
-			*/
-
-			//* get the traffic
-			$tmp = $app->db->queryOneRecord("SELECT SUM(traffic_bytes) As total_traffic_bytes FROM web_traffic WHERE traffic_date like '$current_month%' AND hostname = '$domain'");
-			$web_traffic = round($tmp['total_traffic_bytes']/1024/1024);
-
-			//* Website is over quota, we will disable it
-			/*if( ($web_traffic_quota > 0 && $web_traffic > $web_traffic_quota) ||
-				($client_traffic_quota > 0 && $web_traffic > $client_traffic_quota) ||
-				($reseller_traffic_quota > 0 && $web_traffic > $reseller_traffic_quota)) {*/
-			if($web_traffic_quota > 0 && $web_traffic > $web_traffic_quota) {
-				$app->dbmaster->datalogUpdate('web_domain', "traffic_quota_lock = 'y',active = 'n'", 'domain_id', $rec['domain_id']);
-				$app->log('Traffic quota for '.$rec['domain'].' exceeded. Disabling website.',LOGLEVEL_DEBUG);
-
-				//* Send traffic notifications
-				if($rec['traffic_quota_lock'] != 'y' && ($web_config['overtraffic_notify_admin'] == 'y' || $web_config['overtraffic_notify_client'] == 'y')) {
-                    
-					$placeholders = array('{domain}' => $rec['domain'],
-                                          '{admin_mail}' => ($global_config['admin_mail'] != ''? $global_config['admin_mail'] : 'root'));
-                    
-					$recipients = array();
-					//* send email to admin
-					if($global_config['admin_mail'] != '' && $web_config['overtraffic_notify_admin'] == 'y') {
-						$recipients[] = $global_config['admin_mail'];
-					}
-
-					//* Send email to client
-					if($web_config['overtraffic_notify_client'] == 'y') {
-						$client_group_id = $rec["sys_groupid"];
-						$client = $app->db->queryOneRecord("SELECT client.email FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
-						if($client['email'] != '') {
-							$recipients[] = $client['email'];
-						}
-					}
-
-					send_notification_email('web_traffic_notification', $placeholders, $recipients);
-				}
-
-			} else {
-				//* unlock the website, if traffic is lower then quota
-				if($rec['traffic_quota_lock'] == 'y') {
-					$app->dbmaster->datalogUpdate('web_domain', "traffic_quota_lock = 'n',active = 'y'", 'domain_id', $rec['domain_id']);
-					$app->log('Traffic quota for '.$rec['domain'].' ok again. Re-enabling website.',LOGLEVEL_DEBUG);
-				}
-			}
-		}
-	}
-
-
-}
-
-
-#######################################################################################################
-// send website quota warnings by email
-#######################################################################################################
-
-if ($app->dbmaster == $app->db) {
-
-	$global_config = $app->getconf->get_global_config('mail');
-
-	//* Check website disk quota
-	$sql = "SELECT domain_id,sys_groupid,domain,system_user,last_quota_notification,DATEDIFF(CURDATE(), last_quota_notification) as `notified_before` FROM web_domain WHERE (type = 'vhost' OR type = 'vhostsubdomain')";
-	$records = $app->db->queryAllRecords($sql);
-	if(is_array($records) && !empty($records)) {
-
-		$tmp_rec =  $app->db->queryAllRecords("SELECT data from monitor_data WHERE type = 'harddisk_quota' ORDER BY created DESC");
-		$monitor_data = array();
-		if(is_array($tmp_rec)) {
-			foreach ($tmp_rec as $tmp_mon) {
-				$monitor_data = array_merge_recursive($monitor_data,unserialize($app->db->unquote($tmp_mon['data'])));
-			}
-		}
-
-		foreach($records as $rec) {
-
-			//$web_hd_quota = $rec['hd_quota'];
-			$domain = $rec['domain'];
-
-			$username = $rec['system_user'];
-			$rec['used'] = $monitor_data['user'][$username]['used'];
-			$rec['soft'] = $monitor_data['user'][$username]['soft'];
-			$rec['hard'] = $monitor_data['user'][$username]['hard'];
-			$rec['files'] = $monitor_data['user'][$username]['files'];
-
-			if (!is_numeric($rec['used'])){
-				if ($rec['used'][0] > $rec['used'][1]){
-					$rec['used'] = $rec['used'][0];
-				} else {
-					$rec['used'] = $rec['used'][1];
-				}
-			}
-			if (!is_numeric($rec['soft'])) $rec['soft']=$rec['soft'][1];
-			if (!is_numeric($rec['hard'])) $rec['hard']=$rec['hard'][1];
-			if (!is_numeric($rec['files'])) $rec['files']=$rec['files'][1];
-
-			// used space ratio
-			if($rec['soft'] > 0){
-				$used_ratio = $rec['used']/$rec['soft'];
-			} else {
-				$used_ratio = 0;
-			}
-
-			$rec['ratio'] = number_format($used_ratio * 100, 2, '.', '').'%';
-
-			if($rec['used'] > 1024) {
-				$rec['used'] = round($rec['used'] / 1024,2).' MB';
-			} else {
-				if ($rec['used'] != '') $rec['used'] .= ' KB';
-			}
-
-			if($rec['soft'] > 1024) {
-				$rec['soft'] = round($rec['soft'] / 1024,2).' MB';
-			} elseif($rec['soft'] == 0){
-				$rec['soft'] = '----';
-			} else {
-				$rec['soft'] .= ' KB';
-			}
-
-			if($rec['hard'] > 1024) {
-				$rec['hard'] = round($rec['hard'] / 1024,2).' MB';
-			} elseif($rec['hard'] == 0){
-				$rec['hard'] = '----';
-			} else {
-				$rec['hard'] .= ' KB';
-			}
-
-			// send notifications only if 90% or more of the quota are used
-			if($used_ratio < 0.9) {
-                // reset notification date
-                if($rec['last_quota_notification']) $app->dbmaster->datalogUpdate('web_domain', "last_quota_notification = NULL", 'domain_id', $rec['domain_id']);
-
-                // send notification - everything ok again
-                if($rec['last_quota_notification'] && $web_config['overquota_notify_onok'] == 'y' && ($web_config['overquota_notify_admin'] == 'y' || $web_config['overquota_notify_client'] == 'y')) {
-                    $placeholders = array('{domain}' => $rec['domain'],
-                                          '{admin_mail}' => ($global_config['admin_mail'] != ''? $global_config['admin_mail'] : 'root'),
-                                          '{used}' => $rec['used'],
-                                          '{soft}' => $rec['soft'],
-                                          '{hard}' => $rec['hard'],
-                                          '{ratio}' => $rec['ratio']);
-
-                    $recipients = array();
-
-                    //* send email to admin
-                    if($global_config['admin_mail'] != '' && $web_config['overquota_notify_admin'] == 'y') {
-                        $recipients[] = $global_config['admin_mail'];
-                    }
-
-                    //* Send email to client
-                    if($web_config['overquota_notify_client'] == 'y') {
-                        $client_group_id = $rec["sys_groupid"];
-                        $client = $app->db->queryOneRecord("SELECT client.email FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
-                        if($client['email'] != '') {
-                            $recipients[] = $client['email'];
-                        }
-                    }
-                    send_notification_email('web_quota_ok_notification', $placeholders, $recipients);
-                }
-
-                continue;
-            }
-
-            // could a notification be sent?
-            $send_notification = false;
-            if(!$rec['last_quota_notification']) $send_notification = true; // not yet notified
-            elseif($web_config['overquota_notify_freq'] > 0 && $rec['notified_before'] >= $web_config['overquota_notify_freq']) $send_notification = true;
-
-			//* Send quota notifications
-			if(($web_config['overquota_notify_admin'] == 'y' || $web_config['overquota_notify_client'] == 'y') && $send_notification == true) {
-				$app->dbmaster->datalogUpdate('web_domain', "last_quota_notification = CURDATE()", 'domain_id', $rec['domain_id']);
-
-                $placeholders = array('{domain}' => $rec['domain'],
-                                      '{admin_mail}' => ($global_config['admin_mail'] != ''? $global_config['admin_mail'] : 'root'),
-                                      '{used}' => $rec['used'],
-                                      '{soft}' => $rec['soft'],
-                                      '{hard}' => $rec['hard'],
-                                      '{ratio}' => $rec['ratio']);
-
-                $recipients = array();
-
-                //* send email to admin
-                if($global_config['admin_mail'] != '' && $web_config['overquota_notify_admin'] == 'y') {
-                    $recipients[] = $global_config['admin_mail'];
-                }
-
-                //* Send email to client
-                if($web_config['overquota_notify_client'] == 'y') {
-                    $client_group_id = $rec["sys_groupid"];
-                    $client = $app->db->queryOneRecord("SELECT client.email FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
-                    if($client['email'] != '') {
-                        $recipients[] = $client['email'];
-                    }
-                }
-                send_notification_email('web_quota_notification', $placeholders, $recipients);
-			}
-		}
-	}
-}
-
-
-#######################################################################################################
-// send mail quota warnings by email
-#######################################################################################################
-
-if ($app->dbmaster == $app->db) {
-
-	$global_config = $app->getconf->get_global_config('mail');
-	$mail_config = $app->getconf->get_server_config($conf['server_id'], 'mail');
-
-	//* Check email quota
-	$sql = "SELECT mailuser_id,sys_groupid,email,name,quota,last_quota_notification,DATEDIFF(CURDATE(), last_quota_notification) as `notified_before` FROM mail_user";
-	$records = $app->db->queryAllRecords($sql);
-	if(is_array($records) && !empty($records)) {
-
-		$tmp_rec =  $app->db->queryAllRecords("SELECT data from monitor_data WHERE type = 'email_quota' ORDER BY created DESC");
-		$monitor_data = array();
-		if(is_array($tmp_rec)) {
-			foreach ($tmp_rec as $tmp_mon) {
-				//$monitor_data = array_merge_recursive($monitor_data,unserialize($app->db->unquote($tmp_mon['data'])));
-				$tmp_array = unserialize($app->db->unquote($tmp_mon['data']));
-				if(is_array($tmp_array)) {
-					foreach($tmp_array as $username => $data) {
-						if(@!$monitor_data[$username]['used']) $monitor_data[$username]['used'] = $data['used'];
-					}
-				}
-			}
-		}
-
-		foreach($records as $rec) {
-
-			$email = $rec['email'];
-
-			$rec['used'] = isset($monitor_data[$email]['used']) ? $monitor_data[$email]['used'] : array(1 => 0);
-
-			if (!is_numeric($rec['used'])) $rec['used']=$rec['used'][1];
-
-			// used space ratio
-			if($rec['quota'] > 0){
-				$used_ratio = $rec['used']/$rec['quota'];
-			} else {
-				$used_ratio = 0;
-			}
-
-			$rec['ratio'] = number_format($used_ratio * 100, 2, '.', '').'%';
-
-			if($rec['quota'] > 0){
-				$rec['quota'] = round($rec['quota'] / 1048576,4).' MB';
-			} else {
-				$rec['quota'] = '----';
-			}
-
-			if($rec['used'] < 1544000) {
-				$rec['used'] = round($rec['used'] / 1024,4).' KB';
-			} else {
-				$rec['used'] = round($rec['used'] / 1048576,4).' MB';
-			}
-
-			// send notifications only if 90% or more of the quota are used
-			if($used_ratio < 0.9) {
-                // reset notification date
-                if($rec['last_quota_notification']) $app->dbmaster->datalogUpdate('mail_user', "last_quota_notification = NULL", 'mailuser_id', $rec['mailuser_id']);
-
-                // send notification - everything ok again
-                if($rec['last_quota_notification'] && $mail_config['overquota_notify_onok'] == 'y' && ($mail_config['overquota_notify_admin'] == 'y' || $mail_config['overquota_notify_client'] == 'y')) {
-                    $placeholders = array('{email}' => $rec['email'],
-                              '{admin_mail}' => ($global_config['admin_mail'] != ''? $global_config['admin_mail'] : 'root'),
-                              '{used}' => $rec['used'],
-                              '{name}' => $rec['name'],
-                              '{quota}' => $rec['quota'],
-                              '{ratio}' => $rec['ratio']);
-
-                    $recipients = array();
-                    //* send email to admin
-                    if($global_config['admin_mail'] != '' && $mail_config['overquota_notify_admin'] == 'y') {
-                        $recipients[] = $global_config['admin_mail'];
-                    }
-
-                    //* Send email to client
-                    if($mail_config['overquota_notify_client'] == 'y') {
-                        $client_group_id = $rec["sys_groupid"];
-                        $client = $app->db->queryOneRecord("SELECT client.email FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
-                        if($client['email'] != '') {
-                            $recipients[] = $client['email'];
-                        }
-                    }
-
-                    send_notification_email('mail_quota_ok_notification', $placeholders, $recipients);
-                }
-
-                continue;
-            }
-
-			//* Send quota notifications
-            // could a notification be sent?
-            $send_notification = false;
-            if(!$rec['last_quota_notification']) $send_notification = true; // not yet notified
-            elseif($mail_config['overquota_notify_freq'] > 0 && $rec['notified_before'] >= $mail_config['overquota_notify_freq']) $send_notification = true;
-
-            if(($mail_config['overquota_notify_admin'] == 'y' || $mail_config['overquota_notify_client'] == 'y') && $send_notification == true) {
-				$app->dbmaster->datalogUpdate('mail_user', "last_quota_notification = CURDATE()", 'mailuser_id', $rec['mailuser_id']);
-
-                $placeholders = array('{email}' => $rec['email'],
-                          '{admin_mail}' => ($global_config['admin_mail'] != ''? $global_config['admin_mail'] : 'root'),
-                          '{used}' => $rec['used'],
-                          '{name}' => $rec['name'],
-                          '{quota}' => $rec['quota'],
-                          '{ratio}' => $rec['ratio']);
-
-                $recipients = array();
-                //* send email to admin
-                if($global_config['admin_mail'] != '' && $mail_config['overquota_notify_admin'] == 'y') {
-                    $recipients[] = $global_config['admin_mail'];
-                }
-
-                //* Send email to client
-                if($mail_config['overquota_notify_client'] == 'y') {
-                    $client_group_id = $rec["sys_groupid"];
-                    $client = $app->db->queryOneRecord("SELECT client.email FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
-                    if($client['email'] != '') {
-                        $recipients[] = $client['email'];
-                    }
-                }
-
-                send_notification_email('mail_quota_notification', $placeholders, $recipients);
-			}
-		}
-	}
-}
-
-
-#######################################################################################################
-// deactivate virtual servers (run only on the "master-server")
-#######################################################################################################
-
-if ($app->dbmaster == $app->db) {
-	$current_date = date('Y-m-d');
-
-	//* Check which virtual machines have to be deactivated
-	$sql = "SELECT * FROM openvz_vm WHERE active = 'y' AND active_until_date != '0000-00-00' AND active_until_date < '$current_date'";
-	$records = $app->db->queryAllRecords($sql);
-	if(is_array($records)) {
-		foreach($records as $rec) {
-			$app->dbmaster->datalogUpdate('openvz_vm', "active = 'n'", 'vm_id', $rec['vm_id']);
-			$app->log('Virtual machine active date expired. Disabling VM '.$rec['veid'],LOGLEVEL_DEBUG);
-		}
-	}
-
-
-}
-
-#######################################################################################################
-// Create website backups
-#######################################################################################################
-function formatBytes($size, $precision = 2) {
-	$base=log($size)/log(1024);
-	$suffixes=array('','k','M','G','T');
-    	return round(pow(1024,$base-floor($base)),$precision).$suffixes[floor($base)];
-}
-
-$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';
-
-$web_config = $app->getconf->get_server_config($conf['server_id'], 'web');
-$http_server_user = $web_config['user'];
-
-if($backup_dir != '') {
-
-	if(isset($server_config['backup_dir_ftpread']) && $server_config['backup_dir_ftpread'] == 'y') {
-		$backup_dir_permissions = 0755;
-	} else {
-		$backup_dir_permissions = 0750;
-	}
-
-	if(!is_dir($backup_dir)) {
-		mkdir(escapeshellcmd($backup_dir), $backup_dir_permissions, true);
-	} else {
-		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'";
-	$records = $app->db->queryAllRecords($sql);
-	if(is_array($records)) {
-		foreach($records as $rec) {
-
-			//* Do the website backup
-			if($rec['backup_interval'] == 'daily' or ($rec['backup_interval'] == 'weekly' && date('w') == 0) or ($rec['backup_interval'] == 'monthly' && date('d') == '01')) {
-
-				$web_path = $rec['document_root'];
-				$web_user = $rec['system_user'];
-				$web_group = $rec['system_group'];
-				$web_id = $rec['domain_id'];
-				$web_backup_dir = $backup_dir.'/web'.$web_id;
-				if(!is_dir($web_backup_dir)) mkdir($web_backup_dir, 0750);
-				chmod($web_backup_dir, 0750);
-				//if(isset($server_config['backup_dir_ftpread']) && $server_config['backup_dir_ftpread'] == 'y') {
-				chown($web_backup_dir, $rec['system_user']);
-				chgrp($web_backup_dir, $rec['system_group']);
-				/*} else {
-					chown($web_backup_dir, 'root');
-					chgrp($web_backup_dir, 'root');
-				}*/
-				if($backup_mode == 'userzip') {
-					//* Create a .zip backup as web user and include also files owned by apache / nginx user
-					$web_backup_file = 'web'.$web_id.'_'.date('Y-m-d_H-i').'.zip';
-					exec('cd '.escapeshellarg($web_path).' && sudo -u '.escapeshellarg($web_user).' find . -group '.escapeshellarg($web_group).' -print 2> /dev/null | zip -b /tmp --exclude=backup\* --symlinks '.escapeshellarg($web_backup_dir.'/'.$web_backup_file).' -@', $tmp_output, $retval);
-					if($retval == 0) exec('cd '.escapeshellarg($web_path).' && sudo -u '.escapeshellarg($web_user).' find . -user '.escapeshellarg($http_server_user).' -print 2> /dev/null | zip -b /tmp --exclude=backup\* --update --symlinks '.escapeshellarg($web_backup_dir.'/'.$web_backup_file).' -@', $tmp_output, $retval);
-				} else {
-					//* Create a tar.gz backup as root user
-					$web_backup_file = 'web'.$web_id.'_'.date('Y-m-d_H-i').'.tar.gz';
-					exec('tar pczf '.escapeshellarg($web_backup_dir.'/'.$web_backup_file).' --exclude=backup\* --directory '.escapeshellarg($web_path).' .', $tmp_output, $retval);
-				}
-				if($retval == 0){
-					chown($web_backup_dir.'/'.$web_backup_file, 'root');
-					chgrp($web_backup_dir.'/'.$web_backup_file, 'root');
-					chmod($web_backup_dir.'/'.$web_backup_file, 0750);
-
-					//* Insert web backup record in database
-					//$insert_data = "(server_id,parent_domain_id,backup_type,backup_mode,tstamp,filename) VALUES (".$conf['server_id'].",".$web_id.",'web','".$backup_mode."',".time().",'".$app->db->quote($web_backup_file)."')";
-					//$app->dbmaster->datalogInsert('web_backup', $insert_data, 'backup_id');
-					$sql = "INSERT INTO web_backup (server_id,parent_domain_id,backup_type,backup_mode,tstamp,filename) VALUES (".$conf['server_id'].",".$web_id.",'web','".$backup_mode."',".time().",'".$app->db->quote($web_backup_file)."')";
-					$app->db->query($sql);
-					if($app->db->dbHost != $app->dbmaster->dbHost) $app->dbmaster->query($sql);
-				} else {
-					if(is_file($web_backup_dir.'/'.$web_backup_file)) unlink($web_backup_dir.'/'.$web_backup_file);
-				}
-
-				//* Remove old backups
-				$backup_copies = intval($rec['backup_copies']);
-
-				$dir_handle = dir($web_backup_dir);
-				$files = array();
-				while (false !== ($entry = $dir_handle->read())) {
-					if($entry != '.' && $entry != '..' && substr($entry,0,3) == 'web' && is_file($web_backup_dir.'/'.$entry)) {
-						$files[] = $entry;
-					}
-				}
-				$dir_handle->close();
-
-				rsort($files);
-
-				for ($n = $backup_copies; $n <= 10; $n++) {
-					if(isset($files[$n]) && is_file($web_backup_dir.'/'.$files[$n])) {
-						unlink($web_backup_dir.'/'.$files[$n]);
-						//$sql = "SELECT backup_id FROM web_backup WHERE server_id = ".$conf['server_id']." AND parent_domain_id = $web_id AND filename = '".$app->db->quote($files[$n])."'";
-						//$tmp = $app->dbmaster->queryOneRecord($sql);
-						//$app->dbmaster->datalogDelete('web_backup', 'backup_id', $tmp['backup_id']);
-						//$sql = "DELETE FROM web_backup WHERE backup_id = ".intval($tmp['backup_id']);
-						$sql = "DELETE FROM web_backup WHERE server_id = ".$conf['server_id']." AND parent_domain_id = $web_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 backupdir symlink and create as directory instead
-				$app->uses('system');
-				$app->system->web_folder_protection($web_path,false);
-
-				if(is_link($web_path.'/backup')) {
-					unlink($web_path.'/backup');
-				}
-				if(!is_dir($web_path.'/backup')) {
-					mkdir($web_path.'/backup');
-					chown($web_path.'/backup', $rec['system_user']);
-					chgrp($web_path.'/backup', $rec['system_group']);
-				}
-
-				$app->system->web_folder_protection($web_path,true);
-
-			}
-
-			/* If backup_interval is set to none and we have a
-			backup directory for the website, then remove the backups */
-			if($rec['backup_interval'] == 'none') {
-				$web_id = $rec['domain_id'];
-				$web_user = $rec['system_user'];
-				$web_backup_dir = realpath($backup_dir.'/web'.$web_id);
-				if(is_dir($web_backup_dir)) {
-					exec('sudo -u '.escapeshellarg($web_user).' rm -f '.escapeshellarg($web_backup_dir.'/*'));
-				}
-			}
-		}
-	}
-
-	$sql = "SELECT * FROM web_database WHERE server_id = '".$conf['server_id']."' AND backup_interval != 'none'";
-	$records = $app->db->queryAllRecords($sql);
-	if(is_array($records)) {
-
-		include('lib/mysql_clientdb.conf');
-
-		foreach($records as $rec) {
-
-			//* Do the database backup
-			if($rec['backup_interval'] == 'daily' or ($rec['backup_interval'] == 'weekly' && date('w') == 0) or ($rec['backup_interval'] == 'monthly' && date('d') == '01')) {
-
-				$web_id = $rec['parent_domain_id'];
-				$db_backup_dir = $backup_dir.'/web'.$web_id;
-				if(!is_dir($db_backup_dir)) mkdir($db_backup_dir, 0750);
-				chmod($db_backup_dir, 0750);
-				chown($db_backup_dir, 'root');
-				chgrp($db_backup_dir, 'root');
-
-				//* Do the mysql database backup with mysqldump or mongodump
-				$db_id = $rec['database_id'];
-				$db_name = $rec['database_name'];
-
-				if ($rec['type'] == 'mysql') {
-					$db_backup_file = 'db_'.$db_name.'_'.date('Y-m-d_H-i').'.sql';
-					//$command = "mysqldump -h '".escapeshellcmd($clientdb_host)."' -u '".escapeshellcmd($clientdb_user)."' -p'".escapeshellcmd($clientdb_password)."' -c --add-drop-table --create-options --quick --result-file='".$db_backup_dir.'/'.$db_backup_file."' '".$db_name."'";
-					$command = "mysqldump -h ".escapeshellarg($clientdb_host)." -u ".escapeshellarg($clientdb_user)." -p".escapeshellarg($clientdb_password)." -c --add-drop-table --create-options --quick --result-file='".$db_backup_dir.'/'.$db_backup_file."' '".$db_name."'";
-					exec($command, $tmp_output, $retval);
-
-					//* Compress the backup with gzip
-					if($retval == 0) exec("gzip -c '".escapeshellcmd($db_backup_dir.'/'.$db_backup_file)."' > '".escapeshellcmd($db_backup_dir.'/'.$db_backup_file).".gz'", $tmp_output, $retval);
-
-					if($retval == 0){
-						chmod($db_backup_dir.'/'.$db_backup_file.'.gz', 0750);
-						chown($db_backup_dir.'/'.$db_backup_file.'.gz', fileowner($db_backup_dir));
-						chgrp($db_backup_dir.'/'.$db_backup_file.'.gz', filegroup($db_backup_dir));
-
-						//* Insert web backup record in database
-						//$insert_data = "(server_id,parent_domain_id,backup_type,backup_mode,tstamp,filename) VALUES (".$conf['server_id'].",$web_id,'mysql','sqlgz',".time().",'".$app->db->quote($db_backup_file).".gz')";
-						//$app->dbmaster->datalogInsert('web_backup', $insert_data, 'backup_id');
-						$sql = "INSERT INTO web_backup (server_id,parent_domain_id,backup_type,backup_mode,tstamp,filename) VALUES (".$conf['server_id'].",$web_id,'mysql','sqlgz',".time().",'".$app->db->quote($db_backup_file).".gz')";
-						$app->db->query($sql);
-						if($app->db->dbHost != $app->dbmaster->dbHost) $app->dbmaster->query($sql);
-
-					} else {
-						if(is_file($db_backup_dir.'/'.$db_backup_file.'.gz')) unlink($db_backup_dir.'/'.$db_backup_file.'.gz');
-					}
-					//* Remove the uncompressed file
-					if(is_file($db_backup_dir.'/'.$db_backup_file)) unlink($db_backup_dir.'/'.$db_backup_file);
-				} else if ($rec['type'] == 'mongo') {
-					$db_backup_file = 'db_'.$db_name.'_'.date('Y-m-d_H-i');
-
-					try {
-						$connection = new MongoClient("mongodb://root:123456@127.0.0.1:27017/admin");
-						$db = $connection->selectDB($db_name);
-						// exclude not supported by mongodump, only get user collections
-						$collections = $db->getCollectionNames(false);
-
-						foreach ($collections as $collection) {
-							// mongodump -h 127.0.0.1 --port 27017 -u root -p 123456 --authenticationDatabase admin -d <db> -c <table> -o /tmp/test
-							$command = "mongodump -h 127.0.0.1 --port 27017 -u root -p 123456 --authenticationDatabase admin -d ".escapeshellcmd($db_name)." -c ".escapeshellcmd($collection)." -o ".escapeshellcmd($db_backup_dir.'/'.$db_backup_file);
-							exec($command);
-						}
-
-						if (is_dir(escapeshellcmd($db_backup_dir.'/'.$db_backup_file))) {
-							//* Compress the backup with gzip
-							exec("cd ".escapeshellcmd($db_backup_dir)." && tar -pczf ".escapeshellcmd($db_backup_dir.'/'.$db_backup_file).".tar.gz ".escapeshellcmd($db_backup_file));
-							chmod($db_backup_dir.'/'.$db_backup_file.'.tar.gz', 0750);
-							chown($db_backup_dir.'/'.$db_backup_file.'.tar.gz', fileowner($db_backup_dir));
-							chgrp($db_backup_dir.'/'.$db_backup_file.'.tar.gz', filegroup($db_backup_dir));
-
-							//* Insert web backup record in database
-							$sql = "INSERT INTO web_backup (server_id,parent_domain_id,backup_type,backup_mode,tstamp,filename) VALUES (".$conf['server_id'].",$web_id,'mongodb','rootgz',".time().",'".$app->db->quote($db_backup_file).".tar.gz')";
-							$app->db->query($sql);
-
-							if ($app->db->dbHost != $app->dbmaster->dbHost) {
-								$app->dbmaster->query($sql);
-							}
-
-							//* Remove the uncompressed file
-							exec("rm -rf ".escapeshellcmd($db_backup_dir.'/'.$db_backup_file));
-						}
-					} catch (MongoConnnectionException $e) {
-						// connecting to MongoDB failed - cannot create backup
-					}
-				}
-
-				//* Remove old backups
-				$backup_copies = intval($rec['backup_copies']);
-
-				$dir_handle = dir($db_backup_dir);
-				$files = array();
-				while (false !== ($entry = $dir_handle->read())) {
-					if($entry != '.' && $entry != '..' && (preg_match('/^db_(.*?)_\d{4}-\d{2}-\d{2}_\d{2}-\d{2}\.sql.gz$/', $entry, $matches) || preg_match('/^db_(.*?)_\d{4}-\d{2}-\d{2}_\d{2}-\d{2}\.tar.gz$/', $entry, $matches)) && is_file($db_backup_dir.'/'.$entry)) {
-                        if(array_key_exists($matches[1], $files) == false) $files[$matches[1]] = array();
-						$files[$matches[1]][] = $entry;
-					}
-				}
-				$dir_handle->close();
-
-                reset($files);
-                foreach($files as $db_name => $filelist) {
-                    rsort($filelist);
-                    for ($n = $backup_copies; $n <= 10; $n++) {
-                        if(isset($filelist[$n]) && is_file($db_backup_dir.'/'.$filelist[$n])) {
-                            unlink($db_backup_dir.'/'.$filelist[$n]);
-                            //$sql = "SELECT backup_id FROM web_backup WHERE server_id = ".$conf['server_id']." AND parent_domain_id = $web_id AND filename = '".$app->db->quote($filelist[$n])."'";
-                            //$tmp = $app->dbmaster->queryOneRecord($sql);
-                            //$sql = "DELETE FROM web_backup WHERE backup_id = ".intval($tmp['backup_id']);
-							$sql = "DELETE FROM web_backup WHERE server_id = ".$conf['server_id']." AND parent_domain_id = $web_id AND filename = '".$app->db->quote($filelist[$n])."'";
-                            $app->db->query($sql);
-                            if($app->db->dbHost != $app->dbmaster->dbHost) $app->dbmaster->query($sql);
-                        }
-                    }
-                }
-
-				unset($files);
-				unset($dir_handle);
-			}
-		}
-
-		unset($clientdb_host);
-		unset($clientdb_user);
-		unset($clientdb_password);
-
-	}
-}
-
-
-die("finished.\n");
-?>
diff --git a/server/cron_daily.sh b/server/cron_daily.sh
old mode 100644
new mode 100755
index 9ffedae9ed2953b63b2786f3d7add82c6b4a12de..a96da2f0957473a12164c788679af56135c95521
--- a/server/cron_daily.sh
+++ b/server/cron_daily.sh
@@ -1,16 +1,3 @@
 #!/bin/sh
 
-PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/X11R6/bin
-
-if [ -f /usr/local/ispconfig/server/lib/php.ini ]; then
-        PHPINIOWNER=`stat -c %U /usr/local/ispconfig/server/lib/php.ini`
-        if [ $PHPINIOWNER == 'root' ] || [ $PHPINIOWNER == 'ispconfig'  ]; then
-                export PHPRC=/usr/local/ispconfig/server/lib
-        fi
-fi
-
-/usr/bin/php -q /usr/local/ispconfig/server/cron_daily.php
-
-if [ -f /usr/local/ispconfig/server/cron_daily_billing.sh ]; then
-        /usr/local/ispconfig/server/cron_daily_billing.sh
-fi
+echo "This script is no longer used. Use the cron.sh instead."
diff --git a/server/lib/classes/cron.d/100-mailbox_stats.inc.php b/server/lib/classes/cron.d/100-mailbox_stats.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..ed43e4e5743061abdc35a243a7d522fdd4307714
--- /dev/null
+++ b/server/lib/classes/cron.d/100-mailbox_stats.inc.php
@@ -0,0 +1,269 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_mailbox_stats 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;
+        
+        // cronjob code here
+        
+        #######################################################################################################
+        // store the mailbox statistics in the database
+        #######################################################################################################
+
+        $parse_mail_log = false;
+        $sql = "SELECT mailuser_id,maildir FROM mail_user WHERE server_id = ".$conf['server_id'];
+        $records = $app->db->queryAllRecords($sql);
+        if(count($records) > 0) $parse_mail_log = true;
+
+        foreach($records as $rec) {
+            if(@is_file($rec['maildir'].'/ispconfig_mailsize')) {
+                $parse_mail_log = false;
+
+                // rename file
+                rename($rec['maildir'].'/ispconfig_mailsize',$rec['maildir'].'/ispconfig_mailsize_save');
+
+                // Read the file
+                $lines = file($rec['maildir'].'/ispconfig_mailsize_save');
+                $mail_traffic = 0;
+                foreach($lines as $line) {
+                    $mail_traffic += intval($line);
+                }
+                unset($lines);
+
+                // Delete backup file
+                if(@is_file($rec['maildir'].'/ispconfig_mailsize_save')) unlink($rec['maildir'].'/ispconfig_mailsize_save');
+
+                // Save the traffic stats in the sql database
+                $tstamp = date('Y-m');
+
+                $sql = "SELECT * FROM mail_traffic WHERE month = '$tstamp' AND mailuser_id = ".$rec['mailuser_id'];
+                $tr = $app->dbmaster->queryOneRecord($sql);
+
+                $mail_traffic += $tr['traffic'];
+                if($tr['traffic_id'] > 0) {
+                    $sql = "UPDATE mail_traffic SET traffic = $mail_traffic WHERE traffic_id = ".$tr['traffic_id'];
+                } else {
+                    $sql = "INSERT INTO mail_traffic (month,mailuser_id,traffic) VALUES ('$tstamp',".$rec['mailuser_id'].",$mail_traffic)";
+                }
+                $app->dbmaster->query($sql);
+                //echo $sql;
+
+            }
+
+        }
+
+        if($parse_mail_log == true) {
+            $mailbox_traffic = array();
+            $mail_boxes = array();
+            $mail_rewrites = array(); // we need to read all mail aliases and forwards because the address in amavis is not always the mailbox address
+
+            function parse_mail_log_line($line) {
+                //Oct 31 17:35:48 mx01 amavis[32014]: (32014-05) Passed CLEAN, [IPv6:xxxxx] [IPv6:xxxxx] <xxx@yyyy> -> <aaaa@bbbb>, Message-ID: <xxxx@yyyyy>, mail_id: xxxxxx, Hits: -1.89, size: 1591, queued_as: xxxxxxx, 946 ms
+
+                if(preg_match('/^(\w+\s+\d+\s+\d+:\d+:\d+)\s+[^ ]+\s+amavis.* <([^>]+)>\s+->\s+((<[^>]+>,)+) .*Message-ID:\s+<([^>]+)>.* size:\s+(\d+),.*$/', $line, $matches) == false) return false;
+
+                $timestamp = strtotime($matches[1]);
+                if(!$timestamp) return false;
+
+                $to = array();
+                $recipients = explode(',', $matches[3]);
+                foreach($recipients as $recipient) {
+                    $recipient = substr($recipient, 1, -1);
+                    if(!$recipient || $recipient == $matches[2]) continue;
+                    $to[] = $recipient;
+                }
+
+                return array('line' => $line, 'timestamp' => $timestamp, 'size' => $matches[6], 'from' => $matches[2], 'to' => $to, 'message-id' => $matches[5]);
+            }
+
+            function add_mailbox_traffic(&$traffic_array, $address, $traffic) {
+                global $mail_boxes, $mail_rewrites;
+
+                $address = strtolower($address);
+
+                if(in_array($address, $mail_boxes) == true) {
+                    if(!isset($traffic_array[$address])) $traffic_array[$address] = 0;
+                    $traffic_array[$address] += $traffic;
+                } elseif(array_key_exists($address, $mail_rewrites)) {
+                    foreach($mail_rewrites[$address] as $address) {
+                        if(!isset($traffic_array[$address])) $traffic_array[$address] = 0;
+                        $traffic_array[$address] += $traffic;
+                    }
+                } else {
+                    // this is not a local address - skip it
+                }
+            }
+
+            $sql = "SELECT email FROM mail_user WHERE server_id = ".$conf['server_id'];
+            $records = $app->db->queryAllRecords($sql);
+            foreach($records as $record) {
+                $mail_boxes[] = $record['email'];
+            }
+            $sql = "SELECT source, destination FROM mail_forwarding WHERE server_id = ".$conf['server_id'];
+            $records = $app->db->queryAllRecords($sql);
+            foreach($records as $record) {
+                $targets = preg_split('/[\n,]+/', $record['destination']);
+                foreach($targets as $target) {
+                    if(in_array($target, $mail_boxes)) {
+                        if(isset($mail_rewrites[$record['source']])) $mail_rewrites[$record['source']][] = $target;
+                        else $mail_rewrites[$record['source']] = array($target);
+                    }
+                }
+            }
+
+            $state_file = dirname(__FILE__) . '/mail_log_parser.state';
+            $prev_line = false;
+            $last_line = false;
+            $cur_line = false;
+
+            if(file_exists($state_file)) {
+                $prev_line = parse_mail_log_line(trim(file_get_contents($state_file)));
+                //if($prev_line) echo "continuing from previous run, log position: " . $prev_line['message-id'] . " at " . strftime('%d.%m.%Y %H:%M:%S', $prev_line['timestamp']) . "\n";
+            }
+
+            if(file_exists('/var/log/mail.log')) {
+                $fp = fopen('/var/log/mail.log', 'r');
+                //echo "Parsing mail.log...\n";
+                $l = 0;
+                while($line = fgets($fp, 8192)) {
+                    $l++;
+                    //if($l % 1000 == 0) echo "\rline $l";
+                    $cur_line = parse_mail_log_line($line);
+                    if(!$cur_line) continue;
+
+                    if($prev_line) {
+                        // check if this line has to be processed
+                        if($cur_line['timestamp'] < $prev_line['timestamp']) {
+                            $parse_mail_log = false; // we do not need to parse the second file!
+                            continue; // already processed
+                        } elseif($cur_line['timestamp'] == $prev_line['timestamp'] && $cur_line['message-id'] == $prev_line['message-id']) {
+                            $parse_mail_log = false; // we do not need to parse the second file!
+                            $prev_line = false; // this line has already been processed but the next one has to be!
+                            continue;
+                        }
+                    }
+
+                    add_mailbox_traffic($mailbox_traffic, $cur_line['from'], $cur_line['size']);
+                    foreach($cur_line['to'] as $to) {
+                        add_mailbox_traffic($mailbox_traffic, $to, $cur_line['size']);
+                    }
+                    $last_line = $line; // store for the state file
+                }
+                fclose($fp);
+                //echo "\n";
+            }
+
+            if($parse_mail_log == true && file_exists('/var/log/mail.log.1')) {
+                $fp = fopen('/var/log/mail.log.1', 'r');
+                //echo "Parsing mail.log.1...\n";
+                $l = 0;
+                while($line = fgets($fp, 8192)) {
+                    $l++;
+                    //if($l % 1000 == 0) echo "\rline $l";
+                    $cur_line = parse_mail_log_line($line);
+                    if(!$cur_line) continue;
+
+                    if($prev_line) {
+                        // check if this line has to be processed
+                        if($cur_line['timestamp'] < $prev_line['timestamp']) continue; // already processed
+                        if($cur_line['timestamp'] == $prev_line['timestamp'] && $cur_line['message-id'] == $prev_line['message-id']) {
+                            $prev_line = false; // this line has already been processed but the next one has to be!
+                            continue;
+                        }
+                    }
+
+                    add_mailbox_traffic($mailbox_traffic, $cur_line['from'], $cur_line['size']);
+                    foreach($cur_line['to'] as $to) {
+                        add_mailbox_traffic($mailbox_traffic, $to, $cur_line['size']);
+                    }
+                }
+                fclose($fp);
+                //echo "\n";
+            }
+            unset($mail_rewrites);
+            unset($mail_boxes);
+
+            // Save the traffic stats in the sql database
+            $tstamp = date('Y-m');
+            $sql = "SELECT mailuser_id,email FROM mail_user WHERE server_id = ".$conf['server_id'];
+            $records = $app->db->queryAllRecords($sql);
+            foreach($records as $rec) {
+                if(array_key_exists($rec['email'], $mailbox_traffic)) {
+                    $sql = "SELECT * FROM mail_traffic WHERE month = '$tstamp' AND mailuser_id = ".$rec['mailuser_id'];
+                    $tr = $app->dbmaster->queryOneRecord($sql);
+
+                    $mail_traffic = $tr['traffic'] + $mailbox_traffic[$rec['email']];
+                    if($tr['traffic_id'] > 0) {
+                        $sql = "UPDATE mail_traffic SET traffic = $mail_traffic WHERE traffic_id = ".$tr['traffic_id'];
+                    } else {
+                        $sql = "INSERT INTO mail_traffic (month,mailuser_id,traffic) VALUES ('$tstamp',".$rec['mailuser_id'].",$mail_traffic)";
+                    }
+                    $app->dbmaster->query($sql);
+                    //echo $sql;
+                }
+            }
+
+            unset($mailbox_traffic);
+            if($last_line) file_put_contents($state_file, $last_line);
+        }
+        
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/100-monitor_clamav_log.inc.php b/server/lib/classes/cron.d/100-monitor_clamav_log.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..fc28bfbea12fa778adc9c1353df275f2e906eb02
--- /dev/null
+++ b/server/lib/classes/cron.d/100-monitor_clamav_log.inc.php
@@ -0,0 +1,179 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_monitor_clamav_log extends cronjob {
+    
+    // job schedule
+    protected $_schedule = '*/5 * * * *';
+    protected $_run_at_new = true;
+	
+    private $_tools = null;
+    
+    /* 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;
+        
+        /* used for all monitor cronjobs */
+        $app->load('monitor_tools');
+        $this->_tools = new monitor_tools();
+        /* end global section for monitor cronjobs */
+        
+		/* the id of the server as int */
+		$server_id = intval($conf['server_id']);
+
+		/** The type of the data */
+		$type = 'log_clamav';
+
+		/* Get the data of the log */
+		$data = $this->_tools->_getLogData($type);
+
+		// Todo: the state should be calculated.
+		$state = 'ok';
+
+		$res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+
+
+		/** The type of the data */
+		$type = 'log_freshclam';
+
+		/* Get the data of the log */
+		$data = $this->_tools->_getLogData($type);
+
+		/* Get the data from the LAST log-Entry.
+		 * if there can be found:
+		 * WARNING: Your ClamAV installation is OUTDATED!
+		 * then the clamav is outdated. This is a warning!
+		 */
+		$state = 'ok';
+
+		$tmp = explode("\n", $data);
+		$lastLog = array();
+		if ($tmp[sizeof($tmp) - 1] == '') {
+			/* the log ends with an empty line remove this */
+			array_pop($tmp);
+		}
+		if (strpos($tmp[sizeof($tmp) - 1], '-------------') !== false) {
+			/* the log ends with "-----..." remove this */
+			array_pop($tmp);
+		}
+		for ($i = sizeof($tmp) - 1; $i > 0; $i--) {
+			if (strpos($tmp[$i], '---------') === false) {
+				/* no delimiter found, so add this to the last-log */
+				$lastLog[] = $tmp[$i];
+			} else {
+				/* delimiter found, so there is no more line left! */
+				break;
+			}
+		}
+
+		/*
+		 * Now we have the last log in the array.
+		 * Check if the outdated-string is found...
+		 */
+		foreach ($lastLog as $line) {
+			if (strpos(strtolower($line), 'outdated') !== false) {
+				/*
+				 * Outdatet is only info, because if we set this to warning, the server is
+				 * as long in state warning, as there is a new version of ClamAv which takes
+				 * sometimes weeks!
+				 */
+				$state = $this->_tools->_setState($state, 'info');
+			}
+		}
+
+		$res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/100-monitor_cpu.inc.php b/server/lib/classes/cron.d/100-monitor_cpu.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..b75239bb22df83325ce15b6d9934a3da2e43d8fc
--- /dev/null
+++ b/server/lib/classes/cron.d/100-monitor_cpu.inc.php
@@ -0,0 +1,136 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_monitor_cpu extends cronjob {
+    
+    // job schedule
+    protected $_schedule = '*/5 * * * *';
+    protected $_run_at_new = true;
+	
+    private $_tools = null;
+    
+    /* 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;
+        
+        /* used for all monitor cronjobs */
+        $app->load('monitor_tools');
+        $this->_tools = new monitor_tools();
+        /* end global section for monitor cronjobs */
+        
+		/* the id of the server as int */
+		$server_id = intval($conf['server_id']);
+
+		/** The type of the data */
+		$type = 'cpu_info';
+
+		/*
+			Fetch the data into a array
+		 */
+		if (file_exists('/proc/cpuinfo')) {
+			$cpuData = shell_exec('cat /proc/cpuinfo');
+			$cpuInfo = explode("\n", $cpuData);
+			$processor = 0;
+
+			foreach ($cpuInfo as $line) {
+
+				$part = preg_split('/:/', $line);
+				$key = trim($part[0]);
+				$value = trim($part[1]);
+				if ($key == 'processor')
+					$processor = intval($value);
+				if ($key != '')
+					$data[$key . ' ' . $processor] = $value;
+			}
+
+			/* the cpu has no state. It is, what it is */
+			$state = 'no_state';
+		} else {
+			/*
+			 * It is not Linux, so there is no data and no state
+			 *
+			 * no_state, NOT unknown, because "unknown" is shown as state
+			 * inside the GUI. no_state is hidden.
+			 *
+			 * We have to write NO DATA inside the DB, because the GUI
+			 * could not know, if there is any dat, or not...
+			 */
+			$state = 'no_state';
+			$data['output'] = '';
+		}
+
+		$res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/100-monitor_disk_usage.inc.php b/server/lib/classes/cron.d/100-monitor_disk_usage.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..706be3d7ecf09372d0ee3d9f9e45af5988056bf5
--- /dev/null
+++ b/server/lib/classes/cron.d/100-monitor_disk_usage.inc.php
@@ -0,0 +1,166 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_monitor_disk_usage extends cronjob {
+    
+    // job schedule
+    protected $_schedule = '*/5 * * * *';
+    protected $_run_at_new = true;
+	
+    private $_tools = null;
+    
+    /* 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;
+        
+        /* used for all monitor cronjobs */
+        $app->load('monitor_tools');
+        $this->_tools = new monitor_tools();
+        /* end global section for monitor cronjobs */
+        
+		/* the id of the server as int */
+		$server_id = intval($conf['server_id']);
+
+		/** The type of the data */
+		$type = 'disk_usage';
+
+		/** The state of the disk-usage */
+		$state = 'ok';
+
+		/** Fetch the data of ALL devices into a array (needed for monitoring!) */
+		//$dfData = shell_exec('df -hT 2>/dev/null');
+		$app->uses('getconf');
+        $web_config = $app->getconf->get_server_config($conf['server_id'], 'web');
+        $dfData = shell_exec('df -hT|grep -v "'.$web_config['website_basedir'].'/" 2>/dev/null');
+
+		// split into array
+		$df = explode("\n", $dfData);
+
+		/*
+		 * ignore the first line, process the rest
+		 */
+		for ($i = 1; $i <= sizeof($df); $i++) {
+			if ($df[$i] != '') {
+				/*
+				 * Make an array of the data
+				 */
+				$s = preg_split('/[\s]+/', $df[$i]);
+				$data[$i]['fs'] = $s[0];
+				$data[$i]['type'] = $s[1];
+				$data[$i]['size'] = $s[2];
+				$data[$i]['used'] = $s[3];
+				$data[$i]['available'] = $s[4];
+				$data[$i]['percent'] = $s[5];
+				$data[$i]['mounted'] = $s[6];
+				/*
+				 * calculate the state
+				 */
+				$usePercent = floatval($data[$i]['percent']);
+
+				//* get the free memsize
+				if(substr($data[$i]['available'],-1) == 'G') {
+					$freesize = floatval($data[$i]['available'])*1024;
+				} elseif(substr($data[$i]['available'],-1) == 'T') {
+					$freesize = floatval($data[$i]['available'])*1024*1024;
+				} else {
+					$freesize = floatval($data[$i]['available']);
+				}
+
+				//* We don't want to check some filesystem which have no sensible filling levels
+				switch ($data[$i]['type']) {
+					case 'iso9660':
+					case 'cramfs':
+					case 'udf':
+					case 'tmpfs':
+					case 'devtmpfs':
+					case 'udev':
+						break;
+					default:
+						if ($usePercent > 75 && $freesize < 2000)
+							$state = $this->_tools->_setState($state, 'info');
+						if ($usePercent > 80 && $freesize < 1000)
+							$state = $this->_tools->_setState($state, 'warning');
+						if ($usePercent > 90 && $freesize < 500)
+							$state = $this->_tools->_setState($state, 'critical');
+						if ($usePercent > 95 && $freesize < 100)
+							$state = $this->_tools->_setState($state, 'error');
+						break;
+				}
+			}
+		}
+
+		$res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/100-monitor_email_quota.inc.php b/server/lib/classes/cron.d/100-monitor_email_quota.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..12bd3fed77d6b42c05c71ead39e84a63c54078d1
--- /dev/null
+++ b/server/lib/classes/cron.d/100-monitor_email_quota.inc.php
@@ -0,0 +1,149 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_monitor_email_quota extends cronjob {
+    
+    // job schedule
+    protected $_schedule = '*/15 * * * *';
+    protected $_run_at_new = true;
+	
+    private $_tools = null;
+    
+    /* 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;
+        
+		$app->uses('getconf');
+		$mail_config = $app->getconf->get_server_config($conf['server_id'], 'mail');
+		if($mail_config['mailbox_quota_stats'] == 'n') return;
+
+        /* used for all monitor cronjobs */
+        $app->load('monitor_tools');
+        $this->_tools = new monitor_tools();
+        /* end global section for monitor cronjobs */
+        
+        
+		//* Initialize data array
+		$data = array();
+
+		//* the id of the server as int
+		$server_id = intval($conf['server_id']);
+
+		//* The type of the data
+		$type = 'email_quota';
+
+		//* The state of the email_quota.
+		$state = 'ok';
+
+		$mailboxes = $app->db->queryAllRecords("SELECT email,maildir FROM mail_user WHERE server_id = $server_id");
+		if(is_array($mailboxes)) {
+			foreach($mailboxes as $mb) {
+				$email = $mb['email'];
+				$email_parts = explode('@',$mb['email']);
+				$filename = $mb['maildir'].'/.quotausage';
+				if(file_exists($filename) && !is_link($filename)) {
+					$quotafile = file($filename);
+					$data[$email]['used'] = trim($quotafile['1']);
+					unset($quotafile);
+				} else {
+					exec('du -s '.escapeshellcmd($mb['maildir']),$out);
+					$parts = explode(' ',$out[0]);
+					$data[$email]['used'] = intval($parts[0])*1024;
+					unset($out);
+					unset($parts);
+				}
+			}
+		}
+
+		unset($mailboxes);
+
+				//* Dovecot quota check Courier in progress lathama@gmail.com
+		/*
+				if($dir = opendir("/var/vmail")){
+						while (($quotafiles = readdir($dir)) !== false){
+								if(preg_match('/.\_quota$/', $quotafiles)){
+										$quotafile = (file("/var/vmail/" . $quotafiles));
+										$emailaddress = preg_replace('/_quota/',"", $quotafiles);
+										$emailaddress = preg_replace('/_/',"@", $emailaddress);
+										$data[$emailaddress]['used'] = trim($quotafile['1']);
+								}
+						}
+						closedir($dir);
+				}
+		*/
+        $res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+        /*
+         * Insert the data into the database
+         */
+        $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+                'VALUES (' .
+                $res['server_id'] . ', ' .
+                "'" . $app->dbmaster->quote($res['type']) . "', " .
+                'UNIX_TIMESTAMP(), ' .
+                "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+                "'" . $res['state'] . "'" .
+                ')';
+        $app->dbmaster->query($sql);
+
+        /* The new data is written, now we can delete the old one */
+        $this->_tools->delOldRecords($res['type'], $res['server_id']);
+
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/100-monitor_fail2ban.inc.php b/server/lib/classes/cron.d/100-monitor_fail2ban.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..6c77a076260204447288bac2a4d65586bed4f6aa
--- /dev/null
+++ b/server/lib/classes/cron.d/100-monitor_fail2ban.inc.php
@@ -0,0 +1,127 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_monitor_fail2ban extends cronjob {
+    
+    // job schedule
+    protected $_schedule = '*/5 * * * *';
+    protected $_run_at_new = true;
+	
+    private $_tools = null;
+    
+    /* 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;
+        
+        /* used for all monitor cronjobs */
+        $app->load('monitor_tools');
+        $this->_tools = new monitor_tools();
+        /* end global section for monitor cronjobs */
+        
+		/* the id of the server as int */
+		$server_id = intval($conf['server_id']);
+
+		/** The type of the data */
+		$type = 'log_fail2ban';
+
+		/* This monitoring is only available if fail2ban is installed */
+		system('which fail2ban-client', $retval); // Debian, Ubuntu, Fedora
+		if ($retval !== 0)
+			system('which fail2ban', $retval); // CentOS
+		if ($retval === 0) {
+			/*  Get the data of the log */
+			$data = $this->_tools->_getLogData($type);
+
+			/*
+			 * At this moment, there is no state (maybe later)
+			 */
+			$state = 'no_state';
+		} else {
+			/*
+			 * fail2ban is not installed, so there is no data and no state
+			 *
+			 * no_state, NOT unknown, because "unknown" is shown as state
+			 * inside the GUI. no_state is hidden.
+			 *
+			 * We have to write NO DATA inside the DB, because the GUI
+			 * could not know, if there is any dat, or not...
+			 */
+			$state = 'no_state';
+			$data = '';
+		}
+
+		$res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+        /*
+         * Insert the data into the database
+         */
+        $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+                'VALUES (' .
+                $res['server_id'] . ', ' .
+                "'" . $app->dbmaster->quote($res['type']) . "', " .
+                'UNIX_TIMESTAMP(), ' .
+                "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+                "'" . $res['state'] . "'" .
+                ')';
+        $app->dbmaster->query($sql);
+
+        /* The new data is written, now we can delete the old one */
+        $this->_tools->delOldRecords($res['type'], $res['server_id']);
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/100-monitor_hd_quota.inc.php b/server/lib/classes/cron.d/100-monitor_hd_quota.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..14f00d4c750148485a18db59bf0d4277051d5050
--- /dev/null
+++ b/server/lib/classes/cron.d/100-monitor_hd_quota.inc.php
@@ -0,0 +1,162 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_monitor_hd_quota extends cronjob {
+    
+    // job schedule
+    protected $_schedule = '*/5 * * * *';
+    protected $_run_at_new = true;
+	
+    private $_tools = null;
+    
+    /* 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;
+        
+        /* used for all monitor cronjobs */
+        $app->load('monitor_tools');
+        $this->_tools = new monitor_tools();
+        /* end global section for monitor cronjobs */
+        
+		//* Initialize data array
+		$data = array();
+
+		//* the id of the server as int
+		$server_id = intval($conf['server_id']);
+
+		//* The type of the data
+		$type = 'harddisk_quota';
+
+		//* The state of the harddisk_quota.
+		$state = 'ok';
+
+		//* Fetch the data for all users
+		$dfData = shell_exec('repquota -au 2>/dev/null');
+
+		//* Split into array
+		$df = explode("\n", $dfData);
+
+		//* ignore the first 5 lines, process the rest
+		for ($i = 5; $i <= sizeof($df); $i++) {
+			if ($df[$i] != '') {
+				//* Make a array of the data
+				$s = preg_split('/[\s]+/', $df[$i]);
+				$username = $s[0];
+				if (substr($username, 0, 3) == 'web') {
+					if (isset($data['user'][$username])) {
+						$data['user'][$username]['used'] += $s[2];
+						$data['user'][$username]['soft'] += $s[3];
+						$data['user'][$username]['hard'] += $s[4];
+						$data['user'][$username]['files'] += $s[5];
+					} else {
+						$data['user'][$username]['used'] = $s[2];
+						$data['user'][$username]['soft'] = $s[3];
+						$data['user'][$username]['hard'] = $s[4];
+						$data['user'][$username]['files'] = $s[5];
+					}
+				}
+			}
+		}
+
+		//** Fetch the data for all users
+		$dfData = shell_exec('repquota -ag 2>/dev/null');
+
+		//* split into array
+		$df = explode("\n", $dfData);
+
+		//* ignore the first 5 lines, process the rest
+		for ($i = 5; $i <= sizeof($df); $i++) {
+			if ($df[$i] != '') {
+				//* Make a array of the data
+				$s = preg_split('/[\s]+/', $df[$i]);
+				$groupname = $s[0];
+				if (substr($groupname, 0, 6) == 'client') {
+					if (isset($data['group'][$groupname])) {
+						$data['group'][$groupname]['used'] += $s[1];
+						$data['group'][$groupname]['soft'] += $s[2];
+						$data['group'][$groupname]['hard'] += $s[3];
+					} else {
+						$data['group'][$groupname]['used'] = $s[1];
+						$data['group'][$groupname]['soft'] = $s[2];
+						$data['group'][$groupname]['hard'] = $s[3];
+					}
+				}
+			}
+		}
+
+		$res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/100-monitor_iptables.inc.php b/server/lib/classes/cron.d/100-monitor_iptables.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..3b25e4c7ce200f620b4df9a45ceadd7c33f93d14
--- /dev/null
+++ b/server/lib/classes/cron.d/100-monitor_iptables.inc.php
@@ -0,0 +1,132 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_monitor_iptables extends cronjob {
+    
+    // job schedule
+    protected $_schedule = '*/5 * * * *';
+    protected $_run_at_new = true;
+	
+    private $_tools = null;
+    
+    /* 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;
+        
+        /* used for all monitor cronjobs */
+        $app->load('monitor_tools');
+        $this->_tools = new monitor_tools();
+        /* end global section for monitor cronjobs */
+        
+        /* the id of the server as int */
+        $server_id = intval($conf['server_id']);
+
+        /** The type of the data */
+        $type = 'iptables_rules';
+
+        /* This monitoring is only available if fail2ban is installed */
+        system('which iptables', $retval); // Debian, Ubuntu, Fedora
+        if ($retval === 0) {
+                /*  Get the data of the log */
+                $data['output'] = '<h2>iptables -S (ipv4)</h2>'.shell_exec('iptables -S 2>/dev/null');
+
+                /*
+                 * At this moment, there is no state (maybe later)
+                 */
+                $state = 'no_state';
+        } else {
+                $state = 'no_state';
+                $data = '';
+        }
+
+
+        /* This monitoring is only available if fail2ban is installed */
+        system('which ip6tables', $retval); // Debian, Ubuntu, Fedora
+        if ($retval === 0) {
+                /*  Get the data of the log */
+                $data['output'] .= '<br><h2>ip6tables -S (ipv6)</h2>'.shell_exec('ip6tables -S 2>/dev/null');
+
+                /*
+                 * At this moment, there is no state (maybe later)
+                 */
+                $state = 'no_state';
+        } else {
+                $state = 'no_state';
+                $data = '';
+        }
+
+        $res = array();
+        $res['server_id'] = $server_id;
+        $res['type'] = $type;
+        $res['data'] = $data;
+        $res['state'] = $state;
+
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/100-monitor_ispconfig_log.inc.php b/server/lib/classes/cron.d/100-monitor_ispconfig_log.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..50674c4e20207db50ee26f3f619660f2fd99292d
--- /dev/null
+++ b/server/lib/classes/cron.d/100-monitor_ispconfig_log.inc.php
@@ -0,0 +1,146 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_monitor_ispconfig_log extends cronjob {
+    
+    // job schedule
+    protected $_schedule = '*/5 * * * *';
+    protected $_run_at_new = true;
+	
+    private $_tools = null;
+    
+    /* 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;
+        
+        /* used for all monitor cronjobs */
+        $app->load('monitor_tools');
+        $this->_tools = new monitor_tools();
+        /* end global section for monitor cronjobs */
+        
+		/* the id of the server as int */
+		$server_id = intval($conf['server_id']);
+
+		/** The type of the data */
+		$type = 'log_ispconfig';
+
+		/* Get the data of the log */
+		$data = $this->_tools->_getLogData($type);
+
+		// Todo: the state should be calculated.
+		$state = 'ok';
+
+		$res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+        
+        
+		/** The type of the data */
+		$type = 'log_ispc_cron';
+
+		/* Get the data of the log */
+		$data = $this->_tools->_getLogData($type);
+
+		/*
+		 * actually this info has no state.
+		 * maybe someone knows better...???...
+		 */
+		$state = 'no_state';
+
+		$res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+		//* Ensure that output is encoded so that it does not break the serialize
+		if(is_array($res) && isset($res['data'])) $res['data'] = htmlentities($res['data']);
+
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/100-monitor_ispconfig_version.inc.php b/server/lib/classes/cron.d/100-monitor_ispconfig_version.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..7f4688ced5f10ada33aa8c8e8e983b8029580ccb
--- /dev/null
+++ b/server/lib/classes/cron.d/100-monitor_ispconfig_version.inc.php
@@ -0,0 +1,110 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_monitor_ispconfig_version extends cronjob {
+    
+    // job schedule
+    protected $_schedule = '*/5 * * * *';
+    protected $_run_at_new = true;
+	
+    private $_tools = null;
+    
+    /* 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;
+        
+        /* used for all monitor cronjobs */
+        $app->load('monitor_tools');
+        $this->_tools = new monitor_tools();
+        /* end global section for monitor cronjobs */
+        
+		/* the id of the server as int */
+		$server_id = intval($conf['server_id']);
+
+		/** The type of the data */
+		$type = 'ispc_info';
+
+		/*
+			Fetch the data into a array
+		 */
+		$data['name'] = ISPC_APP_TITLE;
+		$data['version'] = ISPC_APP_VERSION;
+
+		/* the ISPC-Version has no state. It is, what it is */
+		$state = 'no_state';
+
+		$res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/100-monitor_mail_log.inc.php b/server/lib/classes/cron.d/100-monitor_mail_log.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..34194a712fa66926375d0aa50ca52e1b2c702441
--- /dev/null
+++ b/server/lib/classes/cron.d/100-monitor_mail_log.inc.php
@@ -0,0 +1,181 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_monitor_mail_log extends cronjob {
+    
+    // job schedule
+    protected $_schedule = '*/5 * * * *';
+    protected $_run_at_new = true;
+	
+    private $_tools = null;
+    
+    /* 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;
+        
+        /* used for all monitor cronjobs */
+        $app->load('monitor_tools');
+        $this->_tools = new monitor_tools();
+        /* end global section for monitor cronjobs */
+        
+		/* the id of the server as int */
+		$server_id = intval($conf['server_id']);
+
+		/** The type of the data */
+		$type = 'log_mail';
+
+		/* Get the data of the log */
+		$data = $this->_tools->_getLogData($type);
+
+		/*
+		 * actually this info has no state.
+		 * maybe someone knows better...???...
+		 */
+		$state = 'no_state';
+
+		/*
+		 * Return the Result
+		 */
+        $res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+
+		/** The type of the data */
+		$type = 'log_mail_warn';
+
+		/* Get the data of the log */
+		$data = $this->_tools->_getLogData($type);
+
+		/*
+		 * actually this info has no state.
+		 * maybe someone knows better...???...
+		 */
+		$state = 'no_state';
+
+		$res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+
+		/** The type of the data */
+		$type = 'log_mail_err';
+
+		/* Get the data of the log */
+		$data = $this->_tools->_getLogData($type);
+
+		/*
+		 * actually this info has no state.
+		 * maybe someone knows better...???...
+		 */
+		$state = 'no_state';
+
+		$res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/100-monitor_mail_queue.inc.php b/server/lib/classes/cron.d/100-monitor_mail_queue.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..bda9031391afc3766de6b27bfb821de605387425
--- /dev/null
+++ b/server/lib/classes/cron.d/100-monitor_mail_queue.inc.php
@@ -0,0 +1,138 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_monitor_mail_queue extends cronjob {
+    
+    // job schedule
+    protected $_schedule = '*/5 * * * *';
+    protected $_run_at_new = true;
+	
+    private $_tools = null;
+    
+	private function _getIntArray($line) {
+		/** The array of float found */
+		$res = array();
+		/* First build a array from the line */
+		$data = explode(' ', $line);
+		/* then check if any item is a float */
+		foreach ($data as $item) {
+			if ($item . '' == (int) $item . '') {
+				$res[] = $item;
+			}
+		}
+		return $res;
+	}
+    
+    /* 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;
+        
+        /* used for all monitor cronjobs */
+        $app->load('monitor_tools');
+        $this->_tools = new monitor_tools();
+        /* end global section for monitor cronjobs */
+        
+		/* the id of the server as int */
+		$server_id = intval($conf['server_id']);
+
+		/** The type of the data */
+		$type = 'mailq';
+
+		/* Get the data from the mailq */
+		$data['output'] = shell_exec('mailq');
+
+		/*
+		 *  The last line has more informations
+		 */
+		$tmp = explode("\n", $data['output']);
+		$more = $tmp[sizeof($tmp) - 1];
+		$res = $this->_getIntArray($more);
+		$data['bytes'] = $res[0];
+		$data['requests'] = $res[1];
+
+		/** The state of the mailq. */
+		$state = 'ok';
+		if ($data['requests'] > 2000)
+			$state = 'info';
+		if ($data['requests'] > 5000)
+			$state = 'warning';
+		if ($data['requests'] > 8000)
+			$state = 'critical';
+		if ($data['requests'] > 10000)
+			$state = 'error';
+
+		$res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/100-monitor_mem_usage.inc.php b/server/lib/classes/cron.d/100-monitor_mem_usage.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..91e3d410a87e1a2b8f9926522e621b8f2f0fd7a3
--- /dev/null
+++ b/server/lib/classes/cron.d/100-monitor_mem_usage.inc.php
@@ -0,0 +1,124 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_monitor_mem_usage extends cronjob {
+    
+    // job schedule
+    protected $_schedule = '*/5 * * * *';
+    protected $_run_at_new = true;
+	
+    private $_tools = null;
+    
+    /* 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;
+        
+        /* used for all monitor cronjobs */
+        $app->load('monitor_tools');
+        $this->_tools = new monitor_tools();
+        /* end global section for monitor cronjobs */
+        
+		/* the id of the server as int */
+		$server_id = intval($conf['server_id']);
+
+		/** The type of the data */
+		$type = 'mem_usage';
+
+		/*
+			Fetch the data into a array
+		 */
+		$miData = shell_exec('cat /proc/meminfo');
+
+		$memInfo = explode("\n", $miData);
+
+		foreach ($memInfo as $line) {
+			$part = preg_split('/:/', $line);
+			$key = trim($part[0]);
+			$tmp = explode(' ', trim($part[1]));
+			$value = 0;
+			if ($tmp[1] == 'kB')
+				$value = $tmp[0] * 1024;
+			$data[$key] = $value;
+		}
+
+		/*
+		 * actually this info has no state.
+		 * maybe someone knows better...???...
+		 */
+		$state = 'no_state';
+
+		$res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/100-monitor_mongodb.inc.php b/server/lib/classes/cron.d/100-monitor_mongodb.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..a3d19c9679706461d9cf6eb9ab1512a4e99f8f5d
--- /dev/null
+++ b/server/lib/classes/cron.d/100-monitor_mongodb.inc.php
@@ -0,0 +1,127 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_monitor_mongodb extends cronjob {
+    
+    // job schedule
+    protected $_schedule = '*/5 * * * *';
+    protected $_run_at_new = true;
+	
+    private $_tools = null;
+    
+    /* 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;
+        
+        /* used for all monitor cronjobs */
+        $app->load('monitor_tools');
+        $this->_tools = new monitor_tools();
+        /* end global section for monitor cronjobs */
+        
+		/* the id of the server as int */
+		$server_id = intval($conf['server_id']);
+
+		/** The type of the data */
+		$type = 'log_mongodb';
+
+		/* This monitoring is only available if MongoDB is installed */
+		system('which mongod', $retval); // Debian, Ubuntu, Fedora
+		if ($retval !== 0)
+			system('which mongod', $retval); // CentOS
+		if ($retval === 0) {
+			/*  Get the data of the log */
+			$data = $this->_tools->_getLogData($type);
+
+			/*
+			 * At this moment, there is no state (maybe later)
+			 */
+			$state = 'no_state';
+		} else {
+			/*
+			 * MongoDB is not installed, so there is no data and no state
+			 *
+			 * no_state, NOT unknown, because "unknown" is shown as state
+			 * inside the GUI. no_state is hidden.
+			 *
+			 * We have to write NO DATA inside the DB, because the GUI
+			 * could not know, if there is any dat, or not...
+			 */
+			$state = 'no_state';
+			$data = '';
+		}
+
+		$res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+        /*
+         * Insert the data into the database
+         */
+        $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+                'VALUES (' .
+                $res['server_id'] . ', ' .
+                "'" . $app->dbmaster->quote($res['type']) . "', " .
+                'UNIX_TIMESTAMP(), ' .
+                "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+                "'" . $res['state'] . "'" .
+                ')';
+        $app->dbmaster->query($sql);
+
+        /* The new data is written, now we can delete the old one */
+        $this->_tools->delOldRecords($res['type'], $res['server_id']);
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/100-monitor_openvz.inc.php b/server/lib/classes/cron.d/100-monitor_openvz.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..2abe6ccd21ca219a81571f66149553eaa1f4ef7a
--- /dev/null
+++ b/server/lib/classes/cron.d/100-monitor_openvz.inc.php
@@ -0,0 +1,183 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_monitor_openvz extends cronjob {
+    
+    // job schedule
+    protected $_schedule = '*/5 * * * *';
+    protected $_run_at_new = true;
+	
+    private $_tools = null;
+    
+    /* 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;
+        
+        /* used for all monitor cronjobs */
+        $app->load('monitor_tools');
+        $this->_tools = new monitor_tools();
+        /* end global section for monitor cronjobs */
+        
+		/* the id of the server as int */
+		$server_id = intval($conf['server_id']);
+
+		/** The type of the data */
+		$type = 'openvz_veinfo';
+
+		/*
+			Fetch the data into a array
+		 */
+		$app->load(openvz_tools);
+		$openVzTools = new openvz_tools();
+		$data = $openVzTools->getOpenVzVeInfo();
+
+		/* the VE-Info has no state. It is, what it is */
+		$state = 'no_state';
+
+        $res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+
+		/** The type of the data */
+		$type = 'openvz_beancounter';
+
+		/*
+			Fetch the data into a array
+		 */
+		$app->load(openvz_tools);
+		$openVzTools = new openvz_tools();
+		$data = $openVzTools->getOpenVzVeBeanCounter();
+
+		/* calculate the state of the beancounter */
+		if ($data == '') {
+			$state = 'no_state';
+		} else {
+			$state = 'ok';
+
+			/* transfer this output-string into a array */
+			$test = explode("\n", $data);
+
+			/* the first list of the output is not needed */
+			array_shift($test);
+
+			/* now process all items of the rest */
+			foreach ($test as $item) {
+				/*
+				 * eliminate all doubled spaces and spaces at the beginning and end
+				 */
+				while (strpos($item, '  ') !== false) {
+					$item = str_replace('  ', ' ', $item);
+				}
+				$item = trim($item);
+
+				/*
+				 * The failcounter is the LAST
+				 */
+				if ($item != '') {
+					$tmp = explode(' ', $item);
+					$failCounter = $tmp[sizeof($tmp) - 1];
+					if ($failCounter > 0)
+						$state = 'info';
+					if ($failCounter > 50)
+						$state = 'warning';
+					if ($failCounter > 200)
+						$state = 'critical';
+					if ($failCounter > 10000)
+						$state = 'error';
+				}
+			}
+		}
+
+		$res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/100-monitor_os_version.inc.php b/server/lib/classes/cron.d/100-monitor_os_version.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..a5f213e141218e3a01ea0c3efbadcb452e46bcb8
--- /dev/null
+++ b/server/lib/classes/cron.d/100-monitor_os_version.inc.php
@@ -0,0 +1,112 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_monitor_os_version extends cronjob {
+    
+    // job schedule
+    protected $_schedule = '*/5 * * * *';
+    protected $_run_at_new = true;
+	
+    private $_tools = null;
+    
+    /* 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;
+        
+        /* used for all monitor cronjobs */
+        $app->load('monitor_tools');
+        $this->_tools = new monitor_tools();
+        /* end global section for monitor cronjobs */
+        
+		/* the id of the server as int */
+		$server_id = $app->functions->intval($conf['server_id']);
+
+		/** The type of the data */
+		$type = 'os_info';
+
+		/*
+			Fetch the data into a array
+		 */
+		$dist = $this->_tools->get_distname();
+
+		$data['name'] = $dist['name'];
+		$data['version'] = $dist['version'];
+
+		/* the OS has no state. It is, what it is */
+		$state = 'no_state';
+
+		$res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+		
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/100-monitor_raid.inc.php b/server/lib/classes/cron.d/100-monitor_raid.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..969ff24649a8d5e1da342a53d3e78a30db941ca0
--- /dev/null
+++ b/server/lib/classes/cron.d/100-monitor_raid.inc.php
@@ -0,0 +1,263 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_monitor_raid extends cronjob {
+    
+    // job schedule
+    protected $_schedule = '*/5 * * * *';
+    protected $_run_at_new = true;
+	
+    private $_tools = null;
+    
+    /* 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;
+        
+        /* used for all monitor cronjobs */
+        $app->load('monitor_tools');
+        $this->_tools = new monitor_tools();
+        /* end global section for monitor cronjobs */
+        
+		/* the id of the server as int */
+		$server_id = intval($conf['server_id']);
+
+		/** The type of the data */
+		$type = 'raid_state';
+
+		/*
+		 * We support several RAID types, but if we can't find any of them, we have no data
+		 */
+		$state = 'no_state';
+		$data['output'] = '';
+
+		/*
+		 * Check, if Software-RAID is enabled
+		 */
+		if (file_exists('/proc/mdstat')) {
+			/*
+			 * Fetch the output
+			 */
+			$data['output'] = shell_exec('cat /proc/mdstat');
+
+			/*
+			 * Then calc the state.
+			 */
+			$tmp = explode("\n", $data['output']);
+			$state = 'ok';
+			for ($i = 0; $i < sizeof($tmp); $i++) {
+				/* fetch the next line */
+				$line = $tmp[$i];
+
+				if ((strpos($line, '[U_]') !== false) || (strpos($line, '[_U]') !== false)) {
+					/* One Disk is not working.
+					 * if the next line starts with "[>" or "[=" then
+					 * recovery (resync) is in state and the state is
+					 * information instead of critical
+					 */
+					$nextLine = $tmp[$i + 1];
+					if ((strpos($nextLine, '[>') === false) && (strpos($nextLine, '[=') === false)) {
+						$state = $this->_tools->_setState($state, 'critical');
+					} else {
+						$state = $this->_tools->_setState($state, 'info');
+					}
+				}
+				if (strpos($line, '[__]') !== false) {
+					/* both Disk are not working */
+					$state = $this->_tools->_setState($state, 'error');
+				}
+				if (strpos($line, '[UU]') !== false) {
+					/* The disks are OK.
+					 * if the next line starts with "[>" or "[=" then
+					 * recovery (resync) is in state and the state is
+					 * information instead of ok
+					 */
+					$nextLine = $tmp[$i + 1];
+					if ((strpos($nextLine, '[>') === false) && (strpos($nextLine, '[=') === false)) {
+						$state = $this->_tools->_setState($state, 'ok');
+					} else {
+						$state = $this->_tools->_setState($state, 'info');
+					}
+				}
+			}
+		}
+		/*
+		 * Check, if we have mpt-status installed (LSIsoftware-raid)
+		 */
+		if (file_exists('/proc/mpt/summary')) {
+			system('which mpt-status', $retval);
+			if ($retval === 0) {
+				/*
+				 * Fetch the output
+				 */
+				$data['output'] = shell_exec('mpt-status --autoload');
+
+				/*
+				 * Then calc the state.
+				 */
+				$state = 'ok';
+				if(is_array($data['output'])) {
+					foreach ($data['output'] as $item) {
+						/*
+						* The output contains information for every RAID and every HDD.
+						* We only need the state of the RAID
+						*/
+						if (strpos($item, 'state ') !== false) {
+							/*
+							* We found a raid, process the state of it
+							*/
+							if (strpos($item, ' ONLINE ') !== false) {
+								$this->_tools->_setState($state, 'ok');
+							} elseif (strpos($item, ' OPTIMAL ') !== false) {
+								$this->_tools->_setState($state, 'ok');
+							} elseif (strpos($item, ' INITIAL ') !== false) {
+								$this->_tools->_setState($state, 'info');
+							} elseif (strpos($item, ' INACTIVE ') !== false) {
+								$this->_tools->_setState($state, 'critical');
+							} elseif (strpos($item, ' RESYNC ') !== false) {
+								$this->_tools->_setState($state, 'info');
+							} elseif (strpos($item, ' DEGRADED ') !== false) {
+								$this->_tools->_setState($state, 'critical');
+							} else {
+								/* we don't know the state. so we set the state to critical, that the
+								* admin is warned, that something is wrong
+								*/
+								$this->_tools->_setState($state, 'critical');
+							}
+						}
+					}
+				}
+			}
+		}
+
+		/*
+		* 3ware Controller
+		*/
+		system('which tw_cli', $retval);
+		if($retval === 0) {
+
+			$data['output'] = shell_exec('tw_cli info c0');
+
+			$state = 'ok';
+			if(is_array($data['output'])) {
+			foreach ($data['output'] as $item) {
+				if (strpos($item, 'RAID') !== false) {
+					if (strpos($item, ' VERIFYING ') !== false) {
+						$this->_tools->_setState($state, 'info');
+					}
+					else if (strpos($item, ' MIGRATE-PAUSED ') !== false) {
+						$this->_tools->_setState($state, 'info');
+					}
+					else if (strpos($item, ' MIGRATING ') !== false) {
+						$this->_tools->_setState($state, 'ok');
+					}
+					else if (strpos($item, ' INITIALIZING ') !== false) {
+						$this->_tools->_setState($state, 'info');
+					}
+					else if (strpos($item, ' INIT-PAUSED ') !== false) {
+						$this->_tools->_setState($state, 'info');
+					}
+					else if (strpos($item, ' REBUILDING ') !== false) {
+						$this->_tools->_setState($state, 'info');
+					}
+					else if (strpos($item, ' REBUILD-PAUSED ') !== false) {
+						$this->_tools->_setState($state, 'warning');
+					}
+					else if (strpos($item, ' RECOVERY ') !== false) {
+						$this->_tools->_setState($state, 'warning');
+					}
+					else if (strpos($item, ' DEGRADED ') !== false) {
+						$this->_tools->_setState($state, 'critical');
+					}
+					else if (strpos($item, ' UNKNOWN ') !== false) {
+						$this->_tools->_setState($state, 'critical');
+					}
+					else if (strpos($item, ' OK ') !== false) {
+						$this->_tools->_setState($state, 'ok');
+					}
+					else if (strpos($item, ' OPTIMAL ') !== false) {
+						$this->_tools->_setState($state, 'ok');
+					}
+					else {
+						$this->_tools->_setState($state, 'critical');
+					}
+				}
+			}
+			}
+		}
+
+
+		$res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/100-monitor_rkhunter.inc.php b/server/lib/classes/cron.d/100-monitor_rkhunter.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..ba992dacfc51d6d79264d14121ee1e90dd49d874
--- /dev/null
+++ b/server/lib/classes/cron.d/100-monitor_rkhunter.inc.php
@@ -0,0 +1,127 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_monitor_rkhunter extends cronjob {
+    
+    // job schedule
+    protected $_schedule = '0 0 * * *';
+    protected $_run_at_new = true;
+	
+    private $_tools = null;
+    
+    /* 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;
+        
+        /* used for all monitor cronjobs */
+        $app->load('monitor_tools');
+        $this->_tools = new monitor_tools();
+        /* end global section for monitor cronjobs */
+        
+		/* the id of the server as int */
+		$server_id = intval($conf['server_id']);
+
+		/** The type of the data */
+		$type = 'rkhunter';
+
+		/* This monitoring is only available if rkhunter is installed */
+		system('which rkhunter', $retval);
+		if ($retval === 0) {
+			/*
+			 * Fetch the output
+			 */
+			$data['output'] = shell_exec('rkhunter --update --checkall --nocolors --skip-keypress');
+
+			/*
+			 * At this moment, there is no state (maybe later)
+			 */
+			$state = 'no_state';
+		} else {
+			/*
+			 * rkhunter is not installed, so there is no data and no state
+			 *
+			 * no_state, NOT unknown, because "unknown" is shown as state
+			 * inside the GUI. no_state is hidden.
+			 *
+			 * We have to write NO DATA inside the DB, because the GUI
+			 * could not know, if there is any dat, or not...
+			 */
+			$state = 'no_state';
+			$data['output'] = '';
+		}
+
+		$res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/100-monitor_server.inc.php b/server/lib/classes/cron.d/100-monitor_server.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..b732578301f79b55704cd75c135bd676f3fc6a82
--- /dev/null
+++ b/server/lib/classes/cron.d/100-monitor_server.inc.php
@@ -0,0 +1,133 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_monitor_server extends cronjob {
+    
+    // job schedule
+    protected $_schedule = '*/5 * * * *';
+    protected $_run_at_new = true;
+	
+    private $_tools = null;
+    
+    /* 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;
+        
+        /* used for all monitor cronjobs */
+        $app->load('monitor_tools');
+        $this->_tools = new monitor_tools();
+        /* end global section for monitor cronjobs */
+        
+		/* the id of the server as int */
+		$server_id = intval($conf['server_id']);
+
+		/** The type of the data */
+		$type = 'server_load';
+
+		/*
+			Fetch the data into a array
+		 */
+		$procUptime = shell_exec("cat /proc/uptime | cut -f1 -d' '");
+		$data['up_days'] = floor($procUptime / 86400);
+		$data['up_hours'] = floor(($procUptime - $data['up_days'] * 86400) / 3600);
+		$data['up_minutes'] = floor(($procUptime - $data['up_days'] * 86400 - $data['up_hours'] * 3600) / 60);
+
+		$data['uptime'] = shell_exec('uptime');
+
+		$tmp = explode(',', $data['uptime'], 4);
+		$tmpUser = explode(' ', trim($tmp[2]));
+		$data['user_online'] = intval($tmpUser[0]);
+
+		//* New Load Average code to fix "always zero" bug in non-english distros. NEEDS TESTING
+		$loadTmp = shell_exec("cat /proc/loadavg | cut -f1-3 -d' '");
+		$load = explode(' ', $loadTmp);
+		$data['load_1'] = floatval(str_replace(',', '.', $load[0]));
+		$data['load_5'] = floatval(str_replace(',', '.', $load[1]));
+		$data['load_15'] = floatval(str_replace(',', '.', $load[2]));
+
+		/** The state of the server-load. */
+		$state = 'ok';
+		if ($data['load_1'] > 20)
+			$state = 'info';
+		if ($data['load_1'] > 50)
+			$state = 'warning';
+		if ($data['load_1'] > 100)
+			$state = 'critical';
+		if ($data['load_1'] > 150)
+			$state = 'error';
+
+		$res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/100-monitor_services.inc.php b/server/lib/classes/cron.d/100-monitor_services.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..f3e9e72f2d046384b5805bf1fb25195e2b541e63
--- /dev/null
+++ b/server/lib/classes/cron.d/100-monitor_services.inc.php
@@ -0,0 +1,94 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_monitor_services extends cronjob {
+    
+    // job schedule
+    protected $_schedule = '*/5 * * * *';
+    protected $_run_at_new = true;
+	
+    private $_tools = null;
+    
+    /* 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;
+        
+        /* used for all monitor cronjobs */
+        $app->load('monitor_tools');
+        $this->_tools = new monitor_tools();
+        /* end global section for monitor cronjobs */
+        
+		/*
+		 * First we get the Monitoring-data from the tools
+		 */
+		$res = $this->_tools->monitorServices();
+
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/100-monitor_syslog.inc.php b/server/lib/classes/cron.d/100-monitor_syslog.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..8aa87451982c925692eef6c7b60689950b1281c3
--- /dev/null
+++ b/server/lib/classes/cron.d/100-monitor_syslog.inc.php
@@ -0,0 +1,153 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_monitor_syslog extends cronjob {
+    
+    // job schedule
+    protected $_schedule = '*/5 * * * *';
+    protected $_run_at_new = true;
+	
+    private $_tools = null;
+    
+    /* 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;
+        
+        /* used for all monitor cronjobs */
+        $app->load('monitor_tools');
+        $this->_tools = new monitor_tools();
+        /* end global section for monitor cronjobs */
+        
+		/* the id of the server as int */
+		$server_id = intval($conf['server_id']);
+
+		/** The type of the data */
+		$type = 'sys_log';
+
+		/*
+		 * is there any warning or error for this server?
+		 */
+		$state = 'ok';
+		$dbData = $app->dbmaster->queryAllRecords('SELECT loglevel FROM sys_log WHERE server_id = ' . $server_id . ' AND loglevel > 0');
+		if (is_array($dbData)) {
+			foreach ($dbData as $item) {
+				if ($item['loglevel'] == 1)
+					$state = $this->_tools->_setState($state, 'warning');
+				if ($item['loglevel'] == 2)
+					$state = $this->_tools->_setState($state, 'error');
+			}
+		}
+
+		/** There is no monitor-data because the data is in the sys_log table */
+		$data['output'] = '';
+
+		$res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+
+		/** The type of the data */
+		$type = 'log_messages';
+
+		/* Get the data of the log */
+		$data = $this->_tools->_getLogData($type);
+
+		/*
+		 * actually this info has no state.
+		 * maybe someone knows better...???...
+		 */
+		$state = 'no_state';
+
+		$res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/100-monitor_system_update.inc.php b/server/lib/classes/cron.d/100-monitor_system_update.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..022d667154ea6e295585f40774da7da745e6189b
--- /dev/null
+++ b/server/lib/classes/cron.d/100-monitor_system_update.inc.php
@@ -0,0 +1,208 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_monitor_system_update extends cronjob {
+    
+    // job schedule
+    protected $_schedule = '0 * * * *';
+    protected $_run_at_new = true;
+	
+    private $_tools = null;
+    
+    /* 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;
+        
+        /* used for all monitor cronjobs */
+        $app->load('monitor_tools');
+        $this->_tools = new monitor_tools();
+        /* end global section for monitor cronjobs */
+        
+		/* the id of the server as int */
+		$server_id = intval($conf['server_id']);
+
+		/** The type of the data */
+		$type = 'system_update';
+
+		/* This monitoring is only available on Debian or Ubuntu */
+		if (file_exists('/etc/debian_version')) {
+
+			/*
+			 * first update the "apt database"
+			 */
+			shell_exec('apt-get update');
+
+			/*
+			 * Then test the upgrade.
+			 * if there is any output, then there is a needed update
+			 */
+			$aptData = shell_exec('apt-get -s -qq dist-upgrade');
+			if ($aptData == '') {
+				/* There is nothing to update! */
+				$state = 'ok';
+			} else {
+				/*
+				 * There is something to update! this is in most cases not critical, so we can
+				 * do a system-update once a month or so...
+				 */
+				$state = 'info';
+			}
+
+			/*
+			 * Fetch the output
+			 */
+			$data['output'] = $aptData;
+		} elseif (file_exists('/etc/gentoo-release')) {
+
+			/*
+			 * first update the portage tree
+			 */
+
+			// In keeping with gentoo's rsync policy, don't update to frequently (every four hours - taken from http://www.gentoo.org/doc/en/source_mirrors.xml)
+			$do_update = true;
+			if (file_exists('/usr/portage/metadata/timestamp.chk')) {
+				$datetime = file_get_contents('/usr/portage/metadata/timestamp.chk');
+				$datetime = trim($datetime);
+
+				$dstamp = strtotime($datetime);
+				if ($dstamp) {
+					$checkat = $dstamp + 14400; // + 4hours
+					if (mktime() < $checkat) {
+						$do_update = false;
+					}
+				}
+			}
+
+			if ($do_update) {
+				shell_exec('emerge --sync --quiet');
+			}
+
+			/*
+			 * Then test the upgrade.
+			 * if there is any output, then there is a needed update
+			 */
+			$emergeData = shell_exec('glsa-check -t affected');
+			if ($emergeData == '') {
+				/* There is nothing to update! */
+				$state = 'ok';
+				$data['output'] = 'No unapplied GLSA\'s found on the system.';
+			} else {
+				/* There is something to update! */
+				$state = 'info';
+				$data['output'] = shell_exec('glsa-check -pv --nocolor affected 2>/dev/null');
+			}
+		} elseif (file_exists('/etc/SuSE-release')) {
+
+			/*
+			 * update and find the upgrade.
+			 * if there is any output, then there is a needed update
+			 */
+			$aptData = shell_exec('zypper -q lu');
+			if ($aptData == '') {
+				/* There is nothing to update! */
+				$state = 'ok';
+			} else {
+				/*
+				 * There is something to update! this is in most cases not critical, so we can
+				 * do a system-update once a month or so...
+				 */
+				$state = 'info';
+			}
+
+			/*
+			 * Fetch the output
+			 */
+			$data['output'] = shell_exec('zypper lu');
+		} else {
+			/*
+			 * It is not Debian/Ubuntu, so there is no data and no state
+			 *
+			 * no_state, NOT unknown, because "unknown" is shown as state
+			 * inside the GUI. no_state is hidden.
+			 *
+			 * We have to write NO DATA inside the DB, because the GUI
+			 * could not know, if there is any dat, or not...
+			 */
+			$state = 'no_state';
+			$data['output'] = '';
+		}
+
+		$res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = $type;
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+		//* Ensure that output is encoded so that it does not break the serialize
+		//$res['data']['output'] = htmlentities($res['data']['output']);
+		$res['data']['output'] = htmlentities($res['data']['output'],ENT_QUOTES,'UTF-8');
+
+		/*
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+				'VALUES (' .
+				$res['server_id'] . ', ' .
+				"'" . $app->dbmaster->quote($res['type']) . "', " .
+				'UNIX_TIMESTAMP(), ' .
+				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
+				"'" . $res['state'] . "'" .
+				')';
+		$app->dbmaster->query($sql);
+
+		/* The new data is written, now we can delete the old one */
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/150-awstats.inc.php b/server/lib/classes/cron.d/150-awstats.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..0638f0973851518921c8f247e5b65593a67e82f6
--- /dev/null
+++ b/server/lib/classes/cron.d/150-awstats.inc.php
@@ -0,0 +1,183 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_awstats 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;
+        
+        #######################################################################################################
+        // Create awstats statistics
+        #######################################################################################################
+
+        $sql = "SELECT domain_id, domain, document_root, web_folder, type, system_user, system_group, parent_domain_id FROM web_domain WHERE (type = 'vhost' or type = 'vhostsubdomain') and stats_type = 'awstats' AND server_id = ".$conf['server_id'];
+        $records = $app->db->queryAllRecords($sql);
+
+        $web_config = $app->getconf->get_server_config($conf['server_id'], 'web');
+
+        foreach($records as $rec) {
+            //$yesterday = date('Ymd',time() - 86400);
+            $yesterday = date('Ymd',strtotime("-1 day", time()));
+
+            $log_folder = 'log';
+            if($rec['type'] == 'vhostsubdomain') {
+                $tmp = $app->db->queryOneRecord('SELECT `domain` FROM web_domain WHERE domain_id = '.intval($rec['parent_domain_id']));
+                $subdomain_host = preg_replace('/^(.*)\.' . preg_quote($tmp['domain'], '/') . '$/', '$1', $rec['domain']);
+                if($subdomain_host == '') $subdomain_host = 'web'.$rec['domain_id'];
+                $log_folder .= '/' . $subdomain_host;
+                unset($tmp);
+            }
+            $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$yesterday.'-access.log');
+            if(!@is_file($logfile)) {
+                $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$yesterday.'-access.log.gz');
+                if(!@is_file($logfile)) {
+                    continue;
+                }
+            }
+            $web_folder = ($rec['type'] == 'vhostsubdomain' ? $rec['web_folder'] : 'web');
+            $domain = escapeshellcmd($rec['domain']);
+            $statsdir = escapeshellcmd($rec['document_root'].'/'.$web_folder.'/stats');
+            $awstats_pl = $web_config['awstats_pl'];
+            $awstats_buildstaticpages_pl = $web_config['awstats_buildstaticpages_pl'];
+
+            $awstats_conf_dir = $web_config['awstats_conf_dir'];
+            $awstats_website_conf_file = $web_config['awstats_conf_dir'].'/awstats.'.$domain.'.conf';
+
+            if(is_file($awstats_website_conf_file)) unlink($awstats_website_conf_file);
+
+            $sql = "SELECT domain FROM web_domain WHERE (type = 'alias' OR type = 'subdomain') AND parent_domain_id = ".$rec['domain_id'];
+            $aliases = $app->db->queryAllRecords($sql);
+            $aliasdomain = '';
+
+            if(is_array($aliases)) {
+                foreach ($aliases as $alias) {
+                    $aliasdomain.= ' '.$alias['domain']. ' www.'.$alias['domain'];
+                }
+            }
+
+            if(!is_file($awstats_website_conf_file)) {
+                $awstats_conf_file_content = 'Include "'.$awstats_conf_dir.'/awstats.conf"
+        LogFile="/var/log/ispconfig/httpd/'.$domain.'/yesterday-access.log"
+        SiteDomain="'.$domain.'"
+        HostAliases="www.'.$domain.' localhost 127.0.0.1'.$aliasdomain.'"';
+                file_put_contents($awstats_website_conf_file,$awstats_conf_file_content);
+            }
+
+            if(!@is_dir($statsdir)) mkdir($statsdir);
+            if(is_link('/var/log/ispconfig/httpd/'.$domain.'/yesterday-access.log')) unlink('/var/log/ispconfig/httpd/'.$domain.'/yesterday-access.log');
+            symlink($logfile,'/var/log/ispconfig/httpd/'.$domain.'/yesterday-access.log');
+
+            $awmonth = date("n");
+            $awyear = date("Y");
+
+            if (date("d") == 1) {
+                $awmonth = date("m")-1;
+                if (date("m") == 1) {
+                    $awyear = date("Y")-1;
+                    $awmonth = "12";
+                }
+            }
+
+            // awstats_buildstaticpages.pl -update -config=mydomain.com -lang=en -dir=/var/www/domain.com/'.$web_folder.'/stats -awstatsprog=/path/to/awstats.pl
+            // $command = "$awstats_buildstaticpages_pl -update -config='$domain' -lang=".$conf['language']." -dir='$statsdir' -awstatsprog='$awstats_pl'";
+
+            $command = "$awstats_buildstaticpages_pl -month='$awmonth' -year='$awyear' -update -config='$domain' -lang=".$conf['language']." -dir='$statsdir' -awstatsprog='$awstats_pl'";
+
+            if (date("d") == 2) {
+                $awmonth = date("m")-1;
+                if (date("m") == 1) {
+                    $awyear = date("Y")-1;
+                    $awmonth = "12";
+                }
+
+                $statsdirold = $statsdir."/".$awyear."-".$awmonth."/";
+                mkdir($statsdirold);
+                $files = scandir($statsdir);
+                foreach ($files as $file) {
+                    if (substr($file,0,1) != "." && !is_dir("$statsdir"."/"."$file") && substr($file,0,1) != "w" && substr($file,0,1) != "i") copy("$statsdir"."/"."$file","$statsdirold"."$file");
+                }
+            }
+
+
+            if($awstats_pl != '' && $awstats_buildstaticpages_pl != '' && fileowner($awstats_pl) == 0 && fileowner($awstats_buildstaticpages_pl) == 0) {
+                exec($command);
+                if(is_file($rec['document_root'].'/'.$web_folder.'/stats/index.html')) unlink($rec['document_root'].'/'.$web_folder.'/stats/index.html');
+                rename($rec['document_root'].'/'.$web_folder.'/stats/awstats.'.$domain.'.html',$rec['document_root'].'/'.$web_folder.'/stats/awsindex.html');
+                if(!is_file($rec['document_root']."/".$web_folder."/stats/index.php")) {
+                    if(file_exists("/usr/local/ispconfig/server/conf-custom/awstats_index.php.master")) {
+                        copy("/usr/local/ispconfig/server/conf-custom/awstats_index.php.master",$rec['document_root']."/".$web_folder."/stats/index.php");
+                    } else {
+                        copy("/usr/local/ispconfig/server/conf/awstats_index.php.master",$rec['document_root']."/".$web_folder."/stats/index.php");
+                    }
+                }
+
+                $app->log('Created awstats statistics with command: '.$command,LOGLEVEL_DEBUG);
+            } else {
+                $app->log("No awstats statistics created. Either $awstats_pl or $awstats_buildstaticpages_pl is not owned by root user.",LOGLEVEL_WARN);
+            }
+
+            if(is_file($rec['document_root']."/".$web_folder."/stats/index.php")) {
+                chown($rec['document_root']."/".$web_folder."/stats/index.php",$rec['system_user']);
+                chgrp($rec['document_root']."/".$web_folder."/stats/index.php",$rec['system_group']);
+            }
+
+        }
+        
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/150-webalizer.inc.php b/server/lib/classes/cron.d/150-webalizer.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..ba75b8b95aa3afc02ff83e0e431d345ab10b13db
--- /dev/null
+++ b/server/lib/classes/cron.d/150-webalizer.inc.php
@@ -0,0 +1,142 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_webalizer 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;
+        
+        #######################################################################################################
+        // Create webalizer statistics
+        #######################################################################################################
+
+        function setConfigVar( $filename, $varName, $varValue, $append = 0 ) {
+            if($lines = @file($filename)) {
+                $out = '';
+                $found = 0;
+                foreach($lines as $line) {
+                    @list($key, $value) = preg_split('/[\t= ]+/', $line, 2);
+                    if($key == $varName) {
+                        $out .= $varName.' '.$varValue."\n";
+                        $found = 1;
+                    } else {
+                        $out .= $line;
+                    }
+                }
+                if($found == 0) {
+                    //* add \n if the last line does not end with \n or \r
+                    if(substr($out,-1) != "\n" && substr($out,-1) != "\r") $out .= "\n";
+                    //* add the new line at the end of the file
+                    if($append == 1) $out .= $varName.' '.$varValue."\n";
+                }
+
+                file_put_contents($filename,$out);
+            }
+        }
+
+
+        $sql = "SELECT domain_id, domain, document_root, web_folder, type, parent_domain_id FROM web_domain WHERE (type = 'vhost' or type = 'vhostsubdomain') and stats_type = 'webalizer' AND server_id = ".$conf['server_id'];
+        $records = $app->db->queryAllRecords($sql);
+
+        foreach($records as $rec) {
+            //$yesterday = date('Ymd',time() - 86400);
+            $yesterday = date('Ymd',strtotime("-1 day", time()));
+
+            $log_folder = 'log';
+            if($rec['type'] == 'vhostsubdomain') {
+                $tmp = $app->db->queryOneRecord('SELECT `domain` FROM web_domain WHERE domain_id = '.intval($rec['parent_domain_id']));
+                $subdomain_host = preg_replace('/^(.*)\.' . preg_quote($tmp['domain'], '/') . '$/', '$1', $rec['domain']);
+                if($subdomain_host == '') $subdomain_host = 'web'.$rec['domain_id'];
+                $log_folder .= '/' . $subdomain_host;
+                unset($tmp);
+            }
+            $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$yesterday.'-access.log');
+            if(!@is_file($logfile)) {
+                $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$yesterday.'-access.log.gz');
+                if(!@is_file($logfile)) {
+                    continue;
+                }
+            }
+
+            $domain = escapeshellcmd($rec['domain']);
+            $statsdir = escapeshellcmd($rec['document_root'].'/'.($rec['type'] == 'vhostsubdomain' ? $rec['web_folder'] : 'web').'/stats');
+            $webalizer = '/usr/bin/webalizer';
+            $webalizer_conf_main = '/etc/webalizer/webalizer.conf';
+            $webalizer_conf = escapeshellcmd($rec['document_root'].'/log/webalizer.conf');
+
+            if(is_file($statsdir.'/index.php')) unlink($statsdir.'/index.php');
+
+            if(!@is_file($webalizer_conf)) {
+                copy($webalizer_conf_main,$webalizer_conf);
+            }
+
+            if(@is_file($webalizer_conf)) {
+                setConfigVar($webalizer_conf, 'Incremental', 'yes');
+                setConfigVar($webalizer_conf, 'IncrementalName', $statsdir.'/webalizer.current');
+                setConfigVar($webalizer_conf, 'HistoryName', $statsdir.'/webalizer.hist');
+            }
+
+
+            if(!@is_dir($statsdir)) mkdir($statsdir);
+            exec("$webalizer -c $webalizer_conf -n $domain -s $domain -r $domain -q -T -p -o $statsdir $logfile");
+        }
+
+        
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/200-logfiles.inc.php b/server/lib/classes/cron.d/200-logfiles.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..862f0f4ef32c2a4859ff36f60c42ef59c7459129
--- /dev/null
+++ b/server/lib/classes/cron.d/200-logfiles.inc.php
@@ -0,0 +1,271 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_logfiles 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;
+        
+        #######################################################################################################
+        // Make the web logfiles directories world readable to enable ftp access
+        #######################################################################################################
+
+        if(is_dir('/var/log/ispconfig/httpd')) exec('chmod +r /var/log/ispconfig/httpd/*');
+
+        #######################################################################################################
+        // Manage and compress web logfiles and create traffic statistics
+        #######################################################################################################
+
+        $sql = "SELECT domain_id, domain, type, document_root, web_folder, parent_domain_id FROM web_domain WHERE (type = 'vhost' or type = 'vhostsubdomain') AND server_id = ".$conf['server_id'];
+        $records = $app->db->queryAllRecords($sql);
+        foreach($records as $rec) {
+
+            //* create traffic statistics based on yesterdays access log file
+            $yesterday = date('Ymd',time() - 86400);
+
+            $log_folder = 'log';
+            if($rec['type'] == 'vhostsubdomain') {
+                $tmp = $app->db->queryOneRecord('SELECT `domain` FROM web_domain WHERE domain_id = '.intval($rec['parent_domain_id']));
+                $subdomain_host = preg_replace('/^(.*)\.' . preg_quote($tmp['domain'], '/') . '$/', '$1', $rec['domain']);
+                if($subdomain_host == '') $subdomain_host = 'web'.$rec['domain_id'];
+                $log_folder .= '/' . $subdomain_host;
+                unset($tmp);
+            }
+
+            $logfile = $rec['document_root'].'/' . $log_folder . '/'.$yesterday.'-access.log';
+            $total_bytes = 0;
+
+            $handle = @fopen($logfile, "r");
+            if ($handle) {
+                while (($line = fgets($handle, 4096)) !== false) {
+                    if (preg_match('/^\S+ \S+ \S+ \[.*?\] "\S+.*?" \d+ (\d+) ".*?" ".*?"/', $line, $m)) {
+                        $total_bytes += intval($m[1]);
+                    }
+                }
+
+                //* Insert / update traffic in master database
+                $traffic_date = date('Y-m-d',time() - 86400);
+                $tmp = $app->dbmaster->queryOneRecord("select hostname from web_traffic where hostname='".$rec['domain']."' and traffic_date='".$traffic_date."'");
+                if(is_array($tmp) && count($tmp) > 0) {
+                    $sql = "update web_traffic set traffic_bytes=traffic_bytes+"
+                          . $total_bytes
+                          . " where hostname='" . $rec['domain']
+                          . "' and traffic_date='" . $traffic_date . "'";
+                } else {
+                    $sql = "insert into web_traffic (hostname, traffic_date, traffic_bytes) values ('".$rec['domain']."', '".$traffic_date."', '".$total_bytes."')";
+                }
+                $app->dbmaster->query($sql);
+
+                fclose($handle);
+            }
+
+            $yesterday2 = date('Ymd',time() - 86400*2);
+            $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$yesterday2.'-access.log');
+
+            //* Compress logfile
+            if(@is_file($logfile)) {
+                // Compress yesterdays logfile
+                exec("gzip -c $logfile > $logfile.gz");
+                unlink($logfile);
+            }
+
+            // rotate and compress the error.log when it exceeds a size of 10 MB
+            $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/error.log');
+            if(is_file($logfile) && filesize($logfile) > 10000000) {
+                exec("gzip -c $logfile > $logfile.1.gz");
+                exec("cat /dev/null > $logfile");
+            }
+
+            // delete logfiles after 30 days
+            $month_ago = date('Ymd',time() - 86400 * 30);
+            $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$month_ago.'-access.log.gz');
+            if(@is_file($logfile)) {
+                unlink($logfile);
+            }
+
+            //* Delete older Log files, in case that we missed them before due to serverdowntimes.
+            $datepart = date('Ym',time() - 86400 * 31 * 2);
+
+            $logfile = escapeshellcmd($rec['document_root']).'/' . $log_folder . '/'.$datepart.'*-access.log.gz';
+            exec('rm -f '.$logfile);
+
+            $logfile = escapeshellcmd($rec['document_root']).'/' . $log_folder . '/'.$datepart.'*-access.log';
+            exec('rm -f '.$logfile);
+        }
+
+        //* Delete old logfiles in /var/log/ispconfig/httpd/ that were created by vlogger for the hostname of the server
+        exec('hostname -f', $tmp_hostname);
+        if($tmp_hostname[0] != '' && is_dir('/var/log/ispconfig/httpd/'.$tmp_hostname[0])) {
+            exec('cd /var/log/ispconfig/httpd/'.$tmp_hostname[0]."; find . -mtime +30 -name '*.log' | xargs rm > /dev/null 2> /dev/null");
+        }
+        unset($tmp_hostname);
+
+        #######################################################################################################
+        // Rotate the ispconfig.log file
+        #######################################################################################################
+
+        // rotate the ispconfig.log when it exceeds a size of 10 MB
+        $logfile = $conf['ispconfig_log_dir'].'/ispconfig.log';
+        if(is_file($logfile) && filesize($logfile) > 10000000) {
+            exec("gzip -c $logfile > $logfile.1.gz");
+            exec("cat /dev/null > $logfile");
+        }
+
+        // rotate the cron.log when it exceeds a size of 10 MB
+        $logfile = $conf['ispconfig_log_dir'].'/cron.log';
+        if(is_file($logfile) && filesize($logfile) > 10000000) {
+            exec("gzip -c $logfile > $logfile.1.gz");
+            exec("cat /dev/null > $logfile");
+        }
+
+        // rotate the auth.log when it exceeds a size of 10 MB
+        $logfile = $conf['ispconfig_log_dir'].'/auth.log';
+        if(is_file($logfile) && filesize($logfile) > 10000000) {
+            exec("gzip -c $logfile > $logfile.1.gz");
+            exec("cat /dev/null > $logfile");
+        }
+
+        #######################################################################################################
+        // Cleanup website tmp directories
+        #######################################################################################################
+
+        $sql = "SELECT domain_id, domain, document_root, system_user FROM web_domain WHERE server_id = ".$conf['server_id'];
+        $records = $app->db->queryAllRecords($sql);
+        $app->uses('system');
+        if(is_array($records)) {
+            foreach($records as $rec){
+                $tmp_path = realpath(escapeshellcmd($rec['document_root'].'/tmp'));
+                if($tmp_path != '' && strlen($tmp_path) > 10 && is_dir($tmp_path) && $app->system->is_user($rec['system_user'])){
+                    exec('cd '.$tmp_path."; find . -mtime +1 -name 'sess_*' | grep -v -w .no_delete | xargs rm > /dev/null 2> /dev/null");
+                }
+            }
+        }
+
+        #######################################################################################################
+        // Cleanup logs in master database (only the "master-server")
+        #######################################################################################################
+
+        if ($app->dbmaster == $app->db) {
+            /** 7 days */
+            $tstamp = time() - (60*60*24*7);
+
+            /*
+             *  Keep 7 days in sys_log
+             * (we can delete the old items, because if they are OK, they don't interrest anymore
+             * if they are NOT ok, the server will try to process them in 1 minute and so the
+             * error appears again after 1 minute. So it is no problem to delete the old one!
+             */
+            $sql = "DELETE FROM sys_log WHERE tstamp < " . $tstamp . " AND server_id != 0";
+            $app->dbmaster->query($sql);
+
+            /*
+             * Delete all remote-actions "done" and older than 7 days
+             * ATTENTION: We have the same problem as described in cleaning the datalog. We must not
+             * delete the last entry
+             */
+            $sql = "SELECT max(action_id) FROM sys_remoteaction";
+            $res = $app->dbmaster->queryOneRecord($sql);
+            $maxId = $res['max(action_id)'];
+            $sql =  "DELETE FROM sys_remoteaction " .
+                    "WHERE tstamp < " . $tstamp . " " .
+                    " AND action_state = 'ok' " .
+                    " AND action_id <" . intval($maxId);
+            $app->dbmaster->query($sql);
+
+            /*
+             * The sys_datalog is more difficult.
+             * 1) We have to keet ALL entries with
+             *    server_id=0, because they depend on ALL servers (even if they are not
+             *    actually in the system (and will be insered in 3 days or so).
+             * 2) We have to keey ALL entries which are not actually precessed by the
+             *    server never mind how old they are!
+             * 3) We have to keep the entry with the highest autoinc-id, because mysql calculates the
+             *    autoinc-id as "new value = max(row) +1" and does not store this in a separate table.
+             *    This means, if we delete to entry with the highest autoinc-value then this value is
+             *    reused as autoinc and so there are more than one entries with the same value (over
+             *    for example 4 Weeks). This is confusing for our system.
+             *    ATTENTION 2) and 3) is in some case NOT the same! so we have to check both!
+             */
+
+            /* First we need all servers and the last sys_datalog-id they processed */
+            $sql = "SELECT server_id, updated FROM server ORDER BY server_id";
+            $records = $app->dbmaster->queryAllRecords($sql);
+
+            /* Then we need the highest value ever */
+            $sql = "SELECT max(datalog_id) FROM sys_datalog";
+            $res = $app->dbmaster->queryOneRecord($sql);
+            $maxId = $res['max(datalog_id)'];
+
+            /* Then delete server by server */
+            foreach($records as $server) {
+                $tmp_server_id = intval($server['server_id']);
+                if($tmp_server_id > 0) {
+                    $sql = 	"DELETE FROM sys_datalog " .
+                            "WHERE tstamp < " . $tstamp .
+                            " AND server_id = " . intval($server['server_id']) .
+                            " AND datalog_id < " . intval($server['updated']) .
+                            " AND datalog_id < " . intval($maxId);
+                }
+        //		echo $sql . "\n";
+                $app->dbmaster->query($sql);
+            }
+        }
+        
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/300-quota_notify.inc.php b/server/lib/classes/cron.d/300-quota_notify.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..c2ce89527f30407705d7e930fd6cf78bde870c22
--- /dev/null
+++ b/server/lib/classes/cron.d/300-quota_notify.inc.php
@@ -0,0 +1,479 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_quota_notify 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;
+        
+        #########
+        // function for sending notification emails
+        #########
+        function send_notification_email($template, $placeholders, $recipients) {
+            global $conf;
+
+            if(!is_array($recipients) || count($recipients) < 1) return false;
+            if(!is_array($placeholders)) $placeholders = array();
+
+            if(file_exists($conf['rootpath'].'/conf-custom/mail/' . $template . '_'.$conf['language'].'.txt')) {
+                $lines = file($conf['rootpath'].'/conf-custom/mail/' . $template . '_'.$conf['language'].'.txt');
+            } elseif(file_exists($conf['rootpath'].'/conf-custom/mail/' . $template . '_en.txt')) {
+                $lines = file($conf['rootpath'].'/conf-custom/mail/' . $template . '_en.txt');
+            } elseif(file_exists($conf['rootpath'].'/conf/mail/' . $template . '_'.$conf['language'].'.txt')) {
+                $lines = file($conf['rootpath'].'/conf/mail/' . $template . '_'.$conf['language'].'.txt');
+            } else {
+                $lines = file($conf['rootpath'].'/conf/mail/' . $template . '_en.txt');
+            }
+
+            //* get mail headers, subject and body
+            $mailHeaders = '';
+            $mailBody = '';
+            $mailSubject = '';
+            $inHeader = true;
+            for($l = 0; $l < count($lines); $l++) {
+                if($lines[$l] == '') {
+                    $inHeader = false;
+                    continue;
+                }
+                if($inHeader == true) {
+                    $parts = explode(':', $lines[$l], 2);
+                    if(strtolower($parts[0]) == 'subject') $mailSubject = trim($parts[1]);
+                    unset($parts);
+                    $mailHeaders .= trim($lines[$l]) . "\n";
+                } else {
+                    $mailBody .= trim($lines[$l]) . "\n";
+                }
+            }
+            $mailBody = trim($mailBody);
+
+            //* Replace placeholders
+            $mailHeaders = strtr($mailHeaders, $placeholders);
+            $mailSubject = strtr($mailSubject, $placeholders);
+            $mailBody = strtr($mailBody, $placeholders);
+
+            for($r = 0; $r < count($recipients); $r++) {
+                mail($recipients[$r], $mailSubject, $mailBody, $mailHeaders);
+            }
+
+            unset($mailSubject);
+            unset($mailHeaders);
+            unset($mailBody);
+            unset($lines);
+
+            return true;
+        }
+
+
+        #######################################################################################################
+        // enforce traffic quota (run only on the "master-server")
+        #######################################################################################################
+
+        if ($app->dbmaster == $app->db) {
+
+            $global_config = $app->getconf->get_global_config('mail');
+
+            $current_month = date('Y-m');
+
+            //* Check website traffic quota
+            $sql = "SELECT sys_groupid,domain_id,domain,traffic_quota,traffic_quota_lock FROM web_domain WHERE (traffic_quota > 0 or traffic_quota_lock = 'y') and (type = 'vhost' OR type = 'vhostsubdomain')";
+            $records = $app->db->queryAllRecords($sql);
+            if(is_array($records)) {
+                foreach($records as $rec) {
+
+                    $web_traffic_quota = $rec['traffic_quota'];
+                    $domain = $rec['domain'];
+
+                    // get the client
+                    /*
+                    $client_group_id = $rec["sys_groupid"];
+                    $client = $app->db->queryOneRecord("SELECT limit_traffic_quota,parent_client_id FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
+                    $reseller = $app->db->queryOneRecord("SELECT limit_traffic_quota FROM client WHERE client_id = ".intval($client['parent_client_id']));
+
+                    $client_traffic_quota = intval($client['limit_traffic_quota']);
+                    $reseller_traffic_quota = intval($reseller['limit_traffic_quota']);
+                    */
+
+                    //* get the traffic
+                    $tmp = $app->db->queryOneRecord("SELECT SUM(traffic_bytes) As total_traffic_bytes FROM web_traffic WHERE traffic_date like '$current_month%' AND hostname = '$domain'");
+                    $web_traffic = round($tmp['total_traffic_bytes']/1024/1024);
+
+                    //* Website is over quota, we will disable it
+                    /*if( ($web_traffic_quota > 0 && $web_traffic > $web_traffic_quota) ||
+                        ($client_traffic_quota > 0 && $web_traffic > $client_traffic_quota) ||
+                        ($reseller_traffic_quota > 0 && $web_traffic > $reseller_traffic_quota)) {*/
+                    if($web_traffic_quota > 0 && $web_traffic > $web_traffic_quota) {
+                        $app->dbmaster->datalogUpdate('web_domain', "traffic_quota_lock = 'y',active = 'n'", 'domain_id', $rec['domain_id']);
+                        $app->log('Traffic quota for '.$rec['domain'].' exceeded. Disabling website.',LOGLEVEL_DEBUG);
+
+                        //* Send traffic notifications
+                        if($rec['traffic_quota_lock'] != 'y' && ($web_config['overtraffic_notify_admin'] == 'y' || $web_config['overtraffic_notify_client'] == 'y')) {
+                            
+                            $placeholders = array('{domain}' => $rec['domain'],
+                                                  '{admin_mail}' => ($global_config['admin_mail'] != ''? $global_config['admin_mail'] : 'root'));
+                            
+                            $recipients = array();
+                            //* send email to admin
+                            if($global_config['admin_mail'] != '' && $web_config['overtraffic_notify_admin'] == 'y') {
+                                $recipients[] = $global_config['admin_mail'];
+                            }
+
+                            //* Send email to client
+                            if($web_config['overtraffic_notify_client'] == 'y') {
+                                $client_group_id = $rec["sys_groupid"];
+                                $client = $app->db->queryOneRecord("SELECT client.email FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
+                                if($client['email'] != '') {
+                                    $recipients[] = $client['email'];
+                                }
+                            }
+
+                            send_notification_email('web_traffic_notification', $placeholders, $recipients);
+                        }
+
+                    } else {
+                        //* unlock the website, if traffic is lower then quota
+                        if($rec['traffic_quota_lock'] == 'y') {
+                            $app->dbmaster->datalogUpdate('web_domain', "traffic_quota_lock = 'n',active = 'y'", 'domain_id', $rec['domain_id']);
+                            $app->log('Traffic quota for '.$rec['domain'].' ok again. Re-enabling website.',LOGLEVEL_DEBUG);
+                        }
+                    }
+                }
+            }
+
+
+        }
+
+
+        #######################################################################################################
+        // send website quota warnings by email
+        #######################################################################################################
+
+        if ($app->dbmaster == $app->db) {
+
+            $global_config = $app->getconf->get_global_config('mail');
+
+            //* Check website disk quota
+            $sql = "SELECT domain_id,sys_groupid,domain,system_user,last_quota_notification,DATEDIFF(CURDATE(), last_quota_notification) as `notified_before` FROM web_domain WHERE (type = 'vhost' OR type = 'vhostsubdomain')";
+            $records = $app->db->queryAllRecords($sql);
+            if(is_array($records) && !empty($records)) {
+
+                $tmp_rec =  $app->db->queryAllRecords("SELECT data from monitor_data WHERE type = 'harddisk_quota' ORDER BY created DESC");
+                $monitor_data = array();
+                if(is_array($tmp_rec)) {
+                    foreach ($tmp_rec as $tmp_mon) {
+                        $monitor_data = array_merge_recursive($monitor_data,unserialize($app->db->unquote($tmp_mon['data'])));
+                    }
+                }
+
+                foreach($records as $rec) {
+
+                    //$web_hd_quota = $rec['hd_quota'];
+                    $domain = $rec['domain'];
+
+                    $username = $rec['system_user'];
+                    $rec['used'] = $monitor_data['user'][$username]['used'];
+                    $rec['soft'] = $monitor_data['user'][$username]['soft'];
+                    $rec['hard'] = $monitor_data['user'][$username]['hard'];
+                    $rec['files'] = $monitor_data['user'][$username]['files'];
+
+                    if (!is_numeric($rec['used'])){
+                        if ($rec['used'][0] > $rec['used'][1]){
+                            $rec['used'] = $rec['used'][0];
+                        } else {
+                            $rec['used'] = $rec['used'][1];
+                        }
+                    }
+                    if (!is_numeric($rec['soft'])) $rec['soft']=$rec['soft'][1];
+                    if (!is_numeric($rec['hard'])) $rec['hard']=$rec['hard'][1];
+                    if (!is_numeric($rec['files'])) $rec['files']=$rec['files'][1];
+
+                    // used space ratio
+                    if($rec['soft'] > 0){
+                        $used_ratio = $rec['used']/$rec['soft'];
+                    } else {
+                        $used_ratio = 0;
+                    }
+
+                    $rec['ratio'] = number_format($used_ratio * 100, 2, '.', '').'%';
+
+                    if($rec['used'] > 1024) {
+                        $rec['used'] = round($rec['used'] / 1024,2).' MB';
+                    } else {
+                        if ($rec['used'] != '') $rec['used'] .= ' KB';
+                    }
+
+                    if($rec['soft'] > 1024) {
+                        $rec['soft'] = round($rec['soft'] / 1024,2).' MB';
+                    } elseif($rec['soft'] == 0){
+                        $rec['soft'] = '----';
+                    } else {
+                        $rec['soft'] .= ' KB';
+                    }
+
+                    if($rec['hard'] > 1024) {
+                        $rec['hard'] = round($rec['hard'] / 1024,2).' MB';
+                    } elseif($rec['hard'] == 0){
+                        $rec['hard'] = '----';
+                    } else {
+                        $rec['hard'] .= ' KB';
+                    }
+
+                    // send notifications only if 90% or more of the quota are used
+                    if($used_ratio < 0.9) {
+                        // reset notification date
+                        if($rec['last_quota_notification']) $app->dbmaster->datalogUpdate('web_domain', "last_quota_notification = NULL", 'domain_id', $rec['domain_id']);
+
+                        // send notification - everything ok again
+                        if($rec['last_quota_notification'] && $web_config['overquota_notify_onok'] == 'y' && ($web_config['overquota_notify_admin'] == 'y' || $web_config['overquota_notify_client'] == 'y')) {
+                            $placeholders = array('{domain}' => $rec['domain'],
+                                                  '{admin_mail}' => ($global_config['admin_mail'] != ''? $global_config['admin_mail'] : 'root'),
+                                                  '{used}' => $rec['used'],
+                                                  '{soft}' => $rec['soft'],
+                                                  '{hard}' => $rec['hard'],
+                                                  '{ratio}' => $rec['ratio']);
+
+                            $recipients = array();
+
+                            //* send email to admin
+                            if($global_config['admin_mail'] != '' && $web_config['overquota_notify_admin'] == 'y') {
+                                $recipients[] = $global_config['admin_mail'];
+                            }
+
+                            //* Send email to client
+                            if($web_config['overquota_notify_client'] == 'y') {
+                                $client_group_id = $rec["sys_groupid"];
+                                $client = $app->db->queryOneRecord("SELECT client.email FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
+                                if($client['email'] != '') {
+                                    $recipients[] = $client['email'];
+                                }
+                            }
+                            send_notification_email('web_quota_ok_notification', $placeholders, $recipients);
+                        }
+
+                        continue;
+                    }
+
+                    // could a notification be sent?
+                    $send_notification = false;
+                    if(!$rec['last_quota_notification']) $send_notification = true; // not yet notified
+                    elseif($web_config['overquota_notify_freq'] > 0 && $rec['notified_before'] >= $web_config['overquota_notify_freq']) $send_notification = true;
+
+                    //* Send quota notifications
+                    if(($web_config['overquota_notify_admin'] == 'y' || $web_config['overquota_notify_client'] == 'y') && $send_notification == true) {
+                        $app->dbmaster->datalogUpdate('web_domain', "last_quota_notification = CURDATE()", 'domain_id', $rec['domain_id']);
+
+                        $placeholders = array('{domain}' => $rec['domain'],
+                                              '{admin_mail}' => ($global_config['admin_mail'] != ''? $global_config['admin_mail'] : 'root'),
+                                              '{used}' => $rec['used'],
+                                              '{soft}' => $rec['soft'],
+                                              '{hard}' => $rec['hard'],
+                                              '{ratio}' => $rec['ratio']);
+
+                        $recipients = array();
+
+                        //* send email to admin
+                        if($global_config['admin_mail'] != '' && $web_config['overquota_notify_admin'] == 'y') {
+                            $recipients[] = $global_config['admin_mail'];
+                        }
+
+                        //* Send email to client
+                        if($web_config['overquota_notify_client'] == 'y') {
+                            $client_group_id = $rec["sys_groupid"];
+                            $client = $app->db->queryOneRecord("SELECT client.email FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
+                            if($client['email'] != '') {
+                                $recipients[] = $client['email'];
+                            }
+                        }
+                        send_notification_email('web_quota_notification', $placeholders, $recipients);
+                    }
+                }
+            }
+        }
+
+
+        #######################################################################################################
+        // send mail quota warnings by email
+        #######################################################################################################
+
+        if ($app->dbmaster == $app->db) {
+
+            $global_config = $app->getconf->get_global_config('mail');
+            $mail_config = $app->getconf->get_server_config($conf['server_id'], 'mail');
+
+            //* Check email quota
+            $sql = "SELECT mailuser_id,sys_groupid,email,name,quota,last_quota_notification,DATEDIFF(CURDATE(), last_quota_notification) as `notified_before` FROM mail_user";
+            $records = $app->db->queryAllRecords($sql);
+            if(is_array($records) && !empty($records)) {
+
+                $tmp_rec =  $app->db->queryAllRecords("SELECT data from monitor_data WHERE type = 'email_quota' ORDER BY created DESC");
+                $monitor_data = array();
+                if(is_array($tmp_rec)) {
+                    foreach ($tmp_rec as $tmp_mon) {
+                        //$monitor_data = array_merge_recursive($monitor_data,unserialize($app->db->unquote($tmp_mon['data'])));
+                        $tmp_array = unserialize($app->db->unquote($tmp_mon['data']));
+                        if(is_array($tmp_array)) {
+                            foreach($tmp_array as $username => $data) {
+                                if(@!$monitor_data[$username]['used']) $monitor_data[$username]['used'] = $data['used'];
+                            }
+                        }
+                    }
+                }
+
+                foreach($records as $rec) {
+
+                    $email = $rec['email'];
+
+                    $rec['used'] = isset($monitor_data[$email]['used']) ? $monitor_data[$email]['used'] : array(1 => 0);
+
+                    if (!is_numeric($rec['used'])) $rec['used']=$rec['used'][1];
+
+                    // used space ratio
+                    if($rec['quota'] > 0){
+                        $used_ratio = $rec['used']/$rec['quota'];
+                    } else {
+                        $used_ratio = 0;
+                    }
+
+                    $rec['ratio'] = number_format($used_ratio * 100, 2, '.', '').'%';
+
+                    if($rec['quota'] > 0){
+                        $rec['quota'] = round($rec['quota'] / 1048576,4).' MB';
+                    } else {
+                        $rec['quota'] = '----';
+                    }
+
+                    if($rec['used'] < 1544000) {
+                        $rec['used'] = round($rec['used'] / 1024,4).' KB';
+                    } else {
+                        $rec['used'] = round($rec['used'] / 1048576,4).' MB';
+                    }
+
+                    // send notifications only if 90% or more of the quota are used
+                    if($used_ratio < 0.9) {
+                        // reset notification date
+                        if($rec['last_quota_notification']) $app->dbmaster->datalogUpdate('mail_user', "last_quota_notification = NULL", 'mailuser_id', $rec['mailuser_id']);
+
+                        // send notification - everything ok again
+                        if($rec['last_quota_notification'] && $mail_config['overquota_notify_onok'] == 'y' && ($mail_config['overquota_notify_admin'] == 'y' || $mail_config['overquota_notify_client'] == 'y')) {
+                            $placeholders = array('{email}' => $rec['email'],
+                                      '{admin_mail}' => ($global_config['admin_mail'] != ''? $global_config['admin_mail'] : 'root'),
+                                      '{used}' => $rec['used'],
+                                      '{name}' => $rec['name'],
+                                      '{quota}' => $rec['quota'],
+                                      '{ratio}' => $rec['ratio']);
+
+                            $recipients = array();
+                            //* send email to admin
+                            if($global_config['admin_mail'] != '' && $mail_config['overquota_notify_admin'] == 'y') {
+                                $recipients[] = $global_config['admin_mail'];
+                            }
+
+                            //* Send email to client
+                            if($mail_config['overquota_notify_client'] == 'y') {
+                                $client_group_id = $rec["sys_groupid"];
+                                $client = $app->db->queryOneRecord("SELECT client.email FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
+                                if($client['email'] != '') {
+                                    $recipients[] = $client['email'];
+                                }
+                            }
+
+                            send_notification_email('mail_quota_ok_notification', $placeholders, $recipients);
+                        }
+
+                        continue;
+                    }
+
+                    //* Send quota notifications
+                    // could a notification be sent?
+                    $send_notification = false;
+                    if(!$rec['last_quota_notification']) $send_notification = true; // not yet notified
+                    elseif($mail_config['overquota_notify_freq'] > 0 && $rec['notified_before'] >= $mail_config['overquota_notify_freq']) $send_notification = true;
+
+                    if(($mail_config['overquota_notify_admin'] == 'y' || $mail_config['overquota_notify_client'] == 'y') && $send_notification == true) {
+                        $app->dbmaster->datalogUpdate('mail_user', "last_quota_notification = CURDATE()", 'mailuser_id', $rec['mailuser_id']);
+
+                        $placeholders = array('{email}' => $rec['email'],
+                                  '{admin_mail}' => ($global_config['admin_mail'] != ''? $global_config['admin_mail'] : 'root'),
+                                  '{used}' => $rec['used'],
+                                  '{name}' => $rec['name'],
+                                  '{quota}' => $rec['quota'],
+                                  '{ratio}' => $rec['ratio']);
+
+                        $recipients = array();
+                        //* send email to admin
+                        if($global_config['admin_mail'] != '' && $mail_config['overquota_notify_admin'] == 'y') {
+                            $recipients[] = $global_config['admin_mail'];
+                        }
+
+                        //* Send email to client
+                        if($mail_config['overquota_notify_client'] == 'y') {
+                            $client_group_id = $rec["sys_groupid"];
+                            $client = $app->db->queryOneRecord("SELECT client.email FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
+                            if($client['email'] != '') {
+                                $recipients[] = $client['email'];
+                            }
+                        }
+
+                        send_notification_email('mail_quota_notification', $placeholders, $recipients);
+                    }
+                }
+            }
+        }
+        
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/400-openvz.inc.php b/server/lib/classes/cron.d/400-openvz.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..daee5c44aa7ac065da985db1740ed34e0686ad8e
--- /dev/null
+++ b/server/lib/classes/cron.d/400-openvz.inc.php
@@ -0,0 +1,83 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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_openvz 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;
+        
+        #######################################################################################################
+        // deactivate virtual servers (run only on the "master-server")
+        #######################################################################################################
+
+        if ($app->dbmaster == $app->db) {
+            $current_date = date('Y-m-d');
+
+            //* Check which virtual machines have to be deactivated
+            $sql = "SELECT * FROM openvz_vm WHERE active = 'y' AND active_until_date != '0000-00-00' AND active_until_date < '$current_date'";
+            $records = $app->db->queryAllRecords($sql);
+            if(is_array($records)) {
+                foreach($records as $rec) {
+                    $app->dbmaster->datalogUpdate('openvz_vm', "active = 'n'", 'vm_id', $rec['vm_id']);
+                    $app->log('Virtual machine active date expired. Disabling VM '.$rec['veid'],LOGLEVEL_DEBUG);
+                }
+            }
+        }
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.d/500-backup.inc.php b/server/lib/classes/cron.d/500-backup.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..39c721c9fdada93dba61329fc49c1ee9b60349b7
--- /dev/null
+++ b/server/lib/classes/cron.d/500-backup.inc.php
@@ -0,0 +1,330 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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;
+        
+        #######################################################################################################
+        // Create website backups
+        #######################################################################################################
+        function formatBytes($size, $precision = 2) {
+            $base=log($size)/log(1024);
+            $suffixes=array('','k','M','G','T');
+                return round(pow(1024,$base-floor($base)),$precision).$suffixes[floor($base)];
+        }
+
+        $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';
+
+        $web_config = $app->getconf->get_server_config($conf['server_id'], 'web');
+        $http_server_user = $web_config['user'];
+
+        if($backup_dir != '') {
+
+            if(isset($server_config['backup_dir_ftpread']) && $server_config['backup_dir_ftpread'] == 'y') {
+                $backup_dir_permissions = 0755;
+            } else {
+                $backup_dir_permissions = 0750;
+            }
+
+            if(!is_dir($backup_dir)) {
+                mkdir(escapeshellcmd($backup_dir), $backup_dir_permissions, true);
+            } else {
+                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'";
+            $records = $app->db->queryAllRecords($sql);
+            if(is_array($records)) {
+                foreach($records as $rec) {
+
+                    //* Do the website backup
+                    if($rec['backup_interval'] == 'daily' or ($rec['backup_interval'] == 'weekly' && date('w') == 0) or ($rec['backup_interval'] == 'monthly' && date('d') == '01')) {
+
+                        $web_path = $rec['document_root'];
+                        $web_user = $rec['system_user'];
+                        $web_group = $rec['system_group'];
+                        $web_id = $rec['domain_id'];
+                        $web_backup_dir = $backup_dir.'/web'.$web_id;
+                        if(!is_dir($web_backup_dir)) mkdir($web_backup_dir, 0750);
+                        chmod($web_backup_dir, 0750);
+                        //if(isset($server_config['backup_dir_ftpread']) && $server_config['backup_dir_ftpread'] == 'y') {
+                        chown($web_backup_dir, $rec['system_user']);
+                        chgrp($web_backup_dir, $rec['system_group']);
+                        /*} else {
+                            chown($web_backup_dir, 'root');
+                            chgrp($web_backup_dir, 'root');
+                        }*/
+                        if($backup_mode == 'userzip') {
+                            //* Create a .zip backup as web user and include also files owned by apache / nginx user
+                            $web_backup_file = 'web'.$web_id.'_'.date('Y-m-d_H-i').'.zip';
+                            exec('cd '.escapeshellarg($web_path).' && sudo -u '.escapeshellarg($web_user).' find . -group '.escapeshellarg($web_group).' -print 2> /dev/null | zip -b /tmp --exclude=backup\* --symlinks '.escapeshellarg($web_backup_dir.'/'.$web_backup_file).' -@', $tmp_output, $retval);
+                            if($retval == 0) exec('cd '.escapeshellarg($web_path).' && sudo -u '.escapeshellarg($web_user).' find . -user '.escapeshellarg($http_server_user).' -print 2> /dev/null | zip -b /tmp --exclude=backup\* --update --symlinks '.escapeshellarg($web_backup_dir.'/'.$web_backup_file).' -@', $tmp_output, $retval);
+                        } else {
+                            //* Create a tar.gz backup as root user
+                            $web_backup_file = 'web'.$web_id.'_'.date('Y-m-d_H-i').'.tar.gz';
+                            exec('tar pczf '.escapeshellarg($web_backup_dir.'/'.$web_backup_file).' --exclude=backup\* --directory '.escapeshellarg($web_path).' .', $tmp_output, $retval);
+                        }
+                        if($retval == 0){
+                            chown($web_backup_dir.'/'.$web_backup_file, 'root');
+                            chgrp($web_backup_dir.'/'.$web_backup_file, 'root');
+                            chmod($web_backup_dir.'/'.$web_backup_file, 0750);
+
+                            //* Insert web backup record in database
+                            //$insert_data = "(server_id,parent_domain_id,backup_type,backup_mode,tstamp,filename) VALUES (".$conf['server_id'].",".$web_id.",'web','".$backup_mode."',".time().",'".$app->db->quote($web_backup_file)."')";
+                            //$app->dbmaster->datalogInsert('web_backup', $insert_data, 'backup_id');
+                            $sql = "INSERT INTO web_backup (server_id,parent_domain_id,backup_type,backup_mode,tstamp,filename) VALUES (".$conf['server_id'].",".$web_id.",'web','".$backup_mode."',".time().",'".$app->db->quote($web_backup_file)."')";
+                            $app->db->query($sql);
+                            if($app->db->dbHost != $app->dbmaster->dbHost) $app->dbmaster->query($sql);
+                        } else {
+                            if(is_file($web_backup_dir.'/'.$web_backup_file)) unlink($web_backup_dir.'/'.$web_backup_file);
+                        }
+
+                        //* Remove old backups
+                        $backup_copies = intval($rec['backup_copies']);
+
+                        $dir_handle = dir($web_backup_dir);
+                        $files = array();
+                        while (false !== ($entry = $dir_handle->read())) {
+                            if($entry != '.' && $entry != '..' && substr($entry,0,3) == 'web' && is_file($web_backup_dir.'/'.$entry)) {
+                                $files[] = $entry;
+                            }
+                        }
+                        $dir_handle->close();
+
+                        rsort($files);
+
+                        for ($n = $backup_copies; $n <= 10; $n++) {
+                            if(isset($files[$n]) && is_file($web_backup_dir.'/'.$files[$n])) {
+                                unlink($web_backup_dir.'/'.$files[$n]);
+                                //$sql = "SELECT backup_id FROM web_backup WHERE server_id = ".$conf['server_id']." AND parent_domain_id = $web_id AND filename = '".$app->db->quote($files[$n])."'";
+                                //$tmp = $app->dbmaster->queryOneRecord($sql);
+                                //$app->dbmaster->datalogDelete('web_backup', 'backup_id', $tmp['backup_id']);
+                                //$sql = "DELETE FROM web_backup WHERE backup_id = ".intval($tmp['backup_id']);
+                                $sql = "DELETE FROM web_backup WHERE server_id = ".$conf['server_id']." AND parent_domain_id = $web_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 backupdir symlink and create as directory instead
+                        $app->uses('system');
+                        $app->system->web_folder_protection($web_path,false);
+
+                        if(is_link($web_path.'/backup')) {
+                            unlink($web_path.'/backup');
+                        }
+                        if(!is_dir($web_path.'/backup')) {
+                            mkdir($web_path.'/backup');
+                            chown($web_path.'/backup', $rec['system_user']);
+                            chgrp($web_path.'/backup', $rec['system_group']);
+                        }
+
+                        $app->system->web_folder_protection($web_path,true);
+
+                    }
+
+                    /* If backup_interval is set to none and we have a
+                    backup directory for the website, then remove the backups */
+                    if($rec['backup_interval'] == 'none') {
+                        $web_id = $rec['domain_id'];
+                        $web_user = $rec['system_user'];
+                        $web_backup_dir = realpath($backup_dir.'/web'.$web_id);
+                        if(is_dir($web_backup_dir)) {
+                            exec('sudo -u '.escapeshellarg($web_user).' rm -f '.escapeshellarg($web_backup_dir.'/*'));
+                        }
+                    }
+                }
+            }
+
+            $sql = "SELECT * FROM web_database WHERE server_id = '".$conf['server_id']."' AND backup_interval != 'none'";
+            $records = $app->db->queryAllRecords($sql);
+            if(is_array($records)) {
+
+                include('lib/mysql_clientdb.conf');
+
+                foreach($records as $rec) {
+
+                    //* Do the database backup
+                    if($rec['backup_interval'] == 'daily' or ($rec['backup_interval'] == 'weekly' && date('w') == 0) or ($rec['backup_interval'] == 'monthly' && date('d') == '01')) {
+
+                        $web_id = $rec['parent_domain_id'];
+                        $db_backup_dir = $backup_dir.'/web'.$web_id;
+                        if(!is_dir($db_backup_dir)) mkdir($db_backup_dir, 0750);
+                        chmod($db_backup_dir, 0750);
+                        chown($db_backup_dir, 'root');
+                        chgrp($db_backup_dir, 'root');
+
+                        //* Do the mysql database backup with mysqldump or mongodump
+                        $db_id = $rec['database_id'];
+                        $db_name = $rec['database_name'];
+
+                        if ($rec['type'] == 'mysql') {
+                            $db_backup_file = 'db_'.$db_name.'_'.date('Y-m-d_H-i').'.sql';
+                            //$command = "mysqldump -h '".escapeshellcmd($clientdb_host)."' -u '".escapeshellcmd($clientdb_user)."' -p'".escapeshellcmd($clientdb_password)."' -c --add-drop-table --create-options --quick --result-file='".$db_backup_dir.'/'.$db_backup_file."' '".$db_name."'";
+                            $command = "mysqldump -h ".escapeshellarg($clientdb_host)." -u ".escapeshellarg($clientdb_user)." -p".escapeshellarg($clientdb_password)." -c --add-drop-table --quote-names --routines --events --triggers --hex-blob --create-options --quick --result-file='".$db_backup_dir.'/'.$db_backup_file."' '".$db_name."'";
+                            exec($command, $tmp_output, $retval);
+
+                            //* Compress the backup with gzip
+                            if($retval == 0) exec("gzip -c '".escapeshellcmd($db_backup_dir.'/'.$db_backup_file)."' > '".escapeshellcmd($db_backup_dir.'/'.$db_backup_file).".gz'", $tmp_output, $retval);
+
+                            if($retval == 0){
+                                chmod($db_backup_dir.'/'.$db_backup_file.'.gz', 0750);
+                                chown($db_backup_dir.'/'.$db_backup_file.'.gz', fileowner($db_backup_dir));
+                                chgrp($db_backup_dir.'/'.$db_backup_file.'.gz', filegroup($db_backup_dir));
+
+                                //* Insert web backup record in database
+                                //$insert_data = "(server_id,parent_domain_id,backup_type,backup_mode,tstamp,filename) VALUES (".$conf['server_id'].",$web_id,'mysql','sqlgz',".time().",'".$app->db->quote($db_backup_file).".gz')";
+                                //$app->dbmaster->datalogInsert('web_backup', $insert_data, 'backup_id');
+                                $sql = "INSERT INTO web_backup (server_id,parent_domain_id,backup_type,backup_mode,tstamp,filename) VALUES (".$conf['server_id'].",$web_id,'mysql','sqlgz',".time().",'".$app->db->quote($db_backup_file).".gz')";
+                                $app->db->query($sql);
+                                if($app->db->dbHost != $app->dbmaster->dbHost) $app->dbmaster->query($sql);
+
+                            } else {
+                                if(is_file($db_backup_dir.'/'.$db_backup_file.'.gz')) unlink($db_backup_dir.'/'.$db_backup_file.'.gz');
+                            }
+                            //* Remove the uncompressed file
+                            if(is_file($db_backup_dir.'/'.$db_backup_file)) unlink($db_backup_dir.'/'.$db_backup_file);
+                        } else if ($rec['type'] == 'mongo') {
+                            $db_backup_file = 'db_'.$db_name.'_'.date('Y-m-d_H-i');
+
+                            try {
+                                $connection = new MongoClient("mongodb://root:123456@127.0.0.1:27017/admin");
+                                $db = $connection->selectDB($db_name);
+                                // exclude not supported by mongodump, only get user collections
+                                $collections = $db->getCollectionNames(false);
+
+                                foreach ($collections as $collection) {
+                                    // mongodump -h 127.0.0.1 --port 27017 -u root -p 123456 --authenticationDatabase admin -d <db> -c <table> -o /tmp/test
+                                    $command = "mongodump -h 127.0.0.1 --port 27017 -u root -p 123456 --authenticationDatabase admin -d ".escapeshellcmd($db_name)." -c ".escapeshellcmd($collection)." -o ".escapeshellcmd($db_backup_dir.'/'.$db_backup_file);
+                                    exec($command);
+                                }
+
+                                if (is_dir(escapeshellcmd($db_backup_dir.'/'.$db_backup_file))) {
+                                    //* Compress the backup with gzip
+                                    exec("cd ".escapeshellcmd($db_backup_dir)." && tar -pczf ".escapeshellcmd($db_backup_dir.'/'.$db_backup_file).".tar.gz ".escapeshellcmd($db_backup_file));
+                                    chmod($db_backup_dir.'/'.$db_backup_file.'.tar.gz', 0750);
+                                    chown($db_backup_dir.'/'.$db_backup_file.'.tar.gz', fileowner($db_backup_dir));
+                                    chgrp($db_backup_dir.'/'.$db_backup_file.'.tar.gz', filegroup($db_backup_dir));
+
+                                    //* Insert web backup record in database
+                                    $sql = "INSERT INTO web_backup (server_id,parent_domain_id,backup_type,backup_mode,tstamp,filename) VALUES (".$conf['server_id'].",$web_id,'mongodb','rootgz',".time().",'".$app->db->quote($db_backup_file).".tar.gz')";
+                                    $app->db->query($sql);
+
+                                    if ($app->db->dbHost != $app->dbmaster->dbHost) {
+                                        $app->dbmaster->query($sql);
+                                    }
+
+                                    //* Remove the uncompressed file
+                                    exec("rm -rf ".escapeshellcmd($db_backup_dir.'/'.$db_backup_file));
+                                }
+                            } catch (MongoConnnectionException $e) {
+                                // connecting to MongoDB failed - cannot create backup
+                            }
+                        }
+
+                        //* Remove old backups
+                        $backup_copies = intval($rec['backup_copies']);
+
+                        $dir_handle = dir($db_backup_dir);
+                        $files = array();
+                        while (false !== ($entry = $dir_handle->read())) {
+                            if($entry != '.' && $entry != '..' && (preg_match('/^db_(.*?)_\d{4}-\d{2}-\d{2}_\d{2}-\d{2}\.sql.gz$/', $entry, $matches) || preg_match('/^db_(.*?)_\d{4}-\d{2}-\d{2}_\d{2}-\d{2}\.tar.gz$/', $entry, $matches)) && is_file($db_backup_dir.'/'.$entry)) {
+                                if(array_key_exists($matches[1], $files) == false) $files[$matches[1]] = array();
+                                $files[$matches[1]][] = $entry;
+                            }
+                        }
+                        $dir_handle->close();
+
+                        reset($files);
+                        foreach($files as $db_name => $filelist) {
+                            rsort($filelist);
+                            for ($n = $backup_copies; $n <= 10; $n++) {
+                                if(isset($filelist[$n]) && is_file($db_backup_dir.'/'.$filelist[$n])) {
+                                    unlink($db_backup_dir.'/'.$filelist[$n]);
+                                    //$sql = "SELECT backup_id FROM web_backup WHERE server_id = ".$conf['server_id']." AND parent_domain_id = $web_id AND filename = '".$app->db->quote($filelist[$n])."'";
+                                    //$tmp = $app->dbmaster->queryOneRecord($sql);
+                                    //$sql = "DELETE FROM web_backup WHERE backup_id = ".intval($tmp['backup_id']);
+                                    $sql = "DELETE FROM web_backup WHERE server_id = ".$conf['server_id']." AND parent_domain_id = $web_id AND filename = '".$app->db->quote($filelist[$n])."'";
+                                    $app->db->query($sql);
+                                    if($app->db->dbHost != $app->dbmaster->dbHost) $app->dbmaster->query($sql);
+                                }
+                            }
+                        }
+
+                        unset($files);
+                        unset($dir_handle);
+                    }
+                }
+
+                unset($clientdb_host);
+                unset($clientdb_user);
+                unset($clientdb_password);
+
+            }
+        }
+        
+        parent::onRunJob();
+    }
+    
+    /* this function is optional if it contains no custom code */
+    public function onAfterRun() {
+        global $app;
+        
+        parent::onAfterRun();
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/cron.inc.php b/server/lib/classes/cron.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..c7bea321ce89009f56063bef47a9595774248078
--- /dev/null
+++ b/server/lib/classes/cron.inc.php
@@ -0,0 +1,271 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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 cron {
+    
+    /**#@+
+     * @access private
+     */
+    private $_sMinute = '';
+    private $_sHour = '';
+    private $_sDay = '';
+    private $_sMonth = '';
+    private $_sWDay = '';
+    private $_bParsed = false;
+    private $_iNextRun = null;
+    private $_aValidValues;
+    
+    public function __construct() {
+        // empty
+        $this->_sMinute = '';
+        $this->_sHour = '';
+        $this->_sDay = '';
+        $this->_sMonth = '';
+        $this->_sWDay = '';
+        $this->_bParsed = false;
+        $this->_aValidValues = array('minute' => array(),
+                                     'hour' => array(),
+                                     'day' => array(),
+                                     'month' => array(),
+                                     'weekday' => array());
+    }
+    
+    private function _calcValidValues() {
+        // minute field
+        $this->_aValidValues['minute'] = $this->_calcFieldValues('minute', $this->_sMinute);
+        $this->_aValidValues['hour'] = $this->_calcFieldValues('hour', $this->_sHour);
+        $this->_aValidValues['day'] = $this->_calcFieldValues('day', $this->_sDay);
+        $this->_aValidValues['month'] = $this->_calcFieldValues('month', $this->_sMonth);
+        $this->_aValidValues['weekday'] = $this->_calcFieldValues('weekday', $this->_sWDay);
+        $this->_bParsed = true;
+    }
+    
+    private function _calcFieldValues($sField, $sValue) {
+        global $app;
+        
+        $aValidValues = array();
+        
+        // global checks
+        $iFrom = 0;
+        $iTo = 0;
+        switch($sField) {
+            case 'minute':
+                $iTo = 59;
+                break;
+            case 'hour':
+                $iTo = 23;
+                break;
+            case 'day':
+                $iFrom = 1;
+                $iTo = 31;
+                break;
+            case 'month':
+                $sValue = strtr($sValue, array('JAN' => 1,
+                                               'FEB' => 2,
+                                               'MAR' => 3,
+                                               'APR' => 4,
+                                               'MAY' => 5,
+                                               'JUN' => 6,
+                                               'JUL' => 7,
+                                               'AUG' => 8,
+                                               'SEP' => 9,
+                                               'OCT' => 10,
+                                               'NOV' => 11,
+                                               'DEC' => 12)
+                                              );
+                $iFrom = 1;
+                $iTo = 12;
+                break;
+            case 'weekday':
+                $sValue = strtr($sValue, array('SUN' => 0,
+                                               'MON' => 1,
+                                               'TUE' => 2,
+                                               'WED' => 3,
+                                               'THU' => 4,
+                                               'FRI' => 5,
+                                               'SAT' => 6,
+                                               '7' => 0)
+                                              );
+                $iTo = 6;
+                break;
+        }
+        $aParts = explode(',', $sValue);
+        for($a = 0; $a < count($aParts); $a++) {
+            $sValue = $aParts[$a];
+            $iValue = $app->functions->intval($sValue);
+            
+            if($sValue === '*') {
+                // everything is valid
+                for($i = $iFrom; $i <= $iTo; $i++) {
+                    $aValidValues[] = $i;
+                }
+                break; // no need to go any further
+            } elseif((string)$iValue == $sValue) {
+                if($iValue >= $iFrom && $iValue <= $iTo) $aValidValues[] = $iValue;
+            } elseif(preg_match('/^([0-9]+)-([0-9]+)(\/([1-9][0-9]*))?$/', $sValue, $aMatch)) {
+                if($aMatch[1] < $iFrom) $aMatch[1] = $iFrom;
+                if($aMatch[2] > $iTo) $aMatch[2] = $iTo;
+                if(isset($aMatch[3])) {
+                    for($i = $aMatch[1]; $i <= $aMatch[2]; $i++) {
+                        if(($i - $aMatch[1]) % $aMatch[4] == 0) $aValidValues[] = $i;
+                    }
+                } else {
+                    for($i = $aMatch[1]; $i <= $aMatch[2]; $i++) $aValidValues[] = $i;
+                }
+            } elseif(preg_match('/^\*\/([1-9][0-9]*)$/', $sValue, $aMatch)) {
+                for($i = $iFrom; $i <= $iTo; $i++) {
+                    if($i % $aMatch[1] == 0) $aValidValues[] = $i;
+                }
+            }
+        }
+        
+        $aValidValues = array_unique($aValidValues);
+        sort($aValidValues);
+        
+        return $aValidValues;
+    }
+    
+    /**#@-*/
+    
+    /**
+     * Set the cron field values
+     * 
+     * @param string $sMinute the minute field value
+     * @param string $sHour the hour field value
+     * @param string $sDay the day field value
+     * @param string $sWDay the weekday field value
+     * @param string $sMonth the month field value
+     */
+    public function setCronFields($sMinute = '*', $sHour = '*', $sDay = '*', $sMonth = '*', $sWDay = '*') {
+        $this->_sMinute = $sMinute;
+        $this->_sHour = $sHour;
+        $this->_sDay = $sDay;
+        $this->_sMonth = $sMonth;
+        $this->_sWDay = $sWDay;
+        $this->_bParsed = false;
+    }
+    
+    /**
+     * Parse a line of a cron and set the internal field values
+     * 
+     * @param string $sLine cron line
+     */
+    public function parseCronLine($sLine) {
+        $aFields = preg_split('/[ \t]+/', trim($sLine));
+        for($i = 0; $i < 5; $i++) {
+            if(!isset($aFields[$i])) $aFields[$i] = '*';
+        }
+        if($aFields[0] == '@yearly' || $aFields[0] == '@annually') $aFields = array(0, 0, 1, 1, '*');
+        elseif($aFields[0] == '@monthly') $aFields = array(0, 0, 1, '*', '*');
+        elseif($aFields[0] == '@weekly') $aFields = array(0, 0, '*', '*', 0);
+        elseif($aFields[0] == '@daily' || $aFields[0] == '@midnight') $aFields = array(0, 0, '*', '*', '*');
+        elseif($aFields[0] == '@hourly') $aFields = array(0, '*', '*', '*', '*');
+        
+        $this->setCronFields($aFields[0], $aFields[1], $aFields[2], $aFields[3], $aFields[4]);
+    }
+    
+    public function getNextRun($vDate) {
+        global $app;
+        
+        $iTimestamp = ISPConfigDatetime::to_timestamp($vDate);
+        if($iTimestamp === false) return $iTimestamp;
+        
+        if($this->_bParsed == false) $this->_calcValidValues();
+        
+        // get the field values for the given Date.
+        list($iMinute, $iHour, $iDay, $iWDay, $iMonth, $iYear) = explode(':', ISPConfigDateTime::to_string($vDate, 'custom:%M:%H:%d:%w:%m:%Y'));
+        
+        $bValid = false;
+        $iStartYear = $iYear;
+        while($bValid == false) {
+            $iCurMinute = $this->_getNextValue('minute', $iMinute, true);
+            $iCurHour = $this->_getNextValue('hour', $iHour, true);
+            $iCurDay = $this->_getNextValue('day', $iDay, true);
+            $iCurMonth = $this->_getNextValue('month', $iMonth, true);
+            $iCurWDay = $this->_getNextValue('weekday', $iWDay, true);
+            
+            $iNextMinute = $this->_getNextValue('minute', $iMinute);
+            $iNextHour = $this->_getNextValue('hour', $iHour);
+            $iNextDay = $this->_getNextValue('day', $iDay);
+            $iNextMonth = $this->_getNextValue('month', $iMonth);
+            $iNextWDay = $this->_getNextValue('weekday', $iWDay);
+            
+            if($iNextMinute > $iMinute && $iHour == $iCurHour && $iDay == $iCurDay && $iWDay == $iCurWDay && $iMonth == $iCurMonth) {
+                $iMinute = $iNextMinute;
+            } elseif($iNextHour > $iHour && $iDay == $iCurDay && $iWDay == $iCurWDay && $iMonth == $iCurMonth) {
+                $iMinute = reset($this->_aValidValues['minute']);
+                $iHour = $iNextHour;
+            } elseif($iNextDay > $iDay && ISPConfigDateTime::last_day($iMonth) >= $iNextDay && $iMonth == $iCurMonth) {
+                $iMinute = reset($this->_aValidValues['minute']);
+                $iHour = reset($this->_aValidValues['hour']);
+                $iDay = $iNextDay;
+            } elseif($iNextMonth > $iMonth) {
+                $iMinute = reset($this->_aValidValues['minute']);
+                $iHour = reset($this->_aValidValues['hour']);
+                $iDay = reset($this->_aValidValues['day']);
+                $iMonth = $iNextMonth;
+            } else {
+                $iMinute = reset($this->_aValidValues['minute']);
+                $iHour = reset($this->_aValidValues['hour']);
+                $iDay = reset($this->_aValidValues['day']);
+                $iMonth = reset($this->_aValidValues['month']);
+                $iYear++;
+            }
+            
+            $ts = mktime($iHour, $iMinute, 0, $iMonth, $iDay, $iYear);
+            //print strftime('%d.%m.%Y (%A) %H:%M', $ts) . "\n";
+            //var_dump($iCurMinute, $iCurHour, $iCurDay, $iCurMonth, $iCurWDay, '--', $iNextMinute, $iNextHour, $iNextDay, $iNextMonth, $iNextWDay);
+            if(ISPConfigDateTime::last_day($iMonth, $iYear) >= $iDay && in_array($app->functions->intval(strftime('%w', $ts)), $this->_aValidValues['weekday'], true) === true) {
+                $bValid = true;
+            } else {
+                if($iYear - $iStartYear > 5) {
+                    if(LOG_PRIORITY <= PRIO_ERROR) $portal->log('No valid run dates for schedule ' . $this->_sMinute . ' ' . $this->_sHour . ' ' . $this->_sDay . ' ' . $this->_sMonth . ' ' . $this->_sWDay . ' in the next 5 years!', PRIO_ERROR, __FILE__, __LINE__);
+                    return false;
+                }
+            }
+        }
+        
+        //var_dump($vDate, implode('-', array($iYear, $iMonth, $iDay, $iHour, $iNextMinute, 0)), $this->_sMinute, $this->_sHour, $this->_sDay, $this->_sWDay, $this->_sMonth, $this->_aValidValues);
+        return $iYear . '-' . $iMonth . '-' . $iDay . ' ' . $iHour . ':' . $iNextMinute . ':0';
+    }
+    
+    private function _getNextValue($sField, $iValue, $bIncludeCurrent = false) {
+        if(!array_key_exists($sField, $this->_aValidValues)) return false;
+        
+        reset($this->_aValidValues[$sField]);
+        while(($cur = each($this->_aValidValues[$sField])) !== false) {
+            if($bIncludeCurrent == true && $cur['value'] >= $iValue) return $cur['value'];
+            elseif($cur['value'] > $iValue) return $cur['value'];
+        }
+        return reset($this->_aValidValues[$sField]);
+    }
+}
+
+?>
diff --git a/server/lib/classes/cronjob.inc.php b/server/lib/classes/cronjob.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..651365440186c1377401534fa684279f24b0ae12
--- /dev/null
+++ b/server/lib/classes/cronjob.inc.php
@@ -0,0 +1,158 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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 {
+    
+    // default is every 5 minutes
+    protected $_schedule = '*/5 * * * *';
+    
+    // may a run be skipped?
+    protected $_no_skip = false;
+    
+    // if true, this job is run when it is first recognized. If false, the next run is calculated from schedule on first run.
+    protected $_run_at_new = false;
+    
+    protected $_last_run = null;
+    protected $_next_run = null;
+    private $_running = false;
+    
+    /** return schedule */
+    public function getSchedule() {
+        return $this->_schedule;
+    }
+    
+    /** run through cronjob sequence **/
+    public function run() {
+        
+        print "Called run() for class " . get_class($this) . "\n";
+        print "Job has schedule: " . $this->_schedule . "\n";
+        $this->onPrepare();
+        $run_it = $this->onBeforeRun();
+        if($run_it == true) {
+            $this->onRunJob();
+            $this->onAfterRun();
+        }
+        $this->onCompleted();
+        
+        return;
+    }
+    
+    /* this function prepares some data for the job and sets next run time if first executed */
+    protected function onPrepare() {
+        global $app;
+        
+        print "Called onPrepare() for class " . get_class($this) . "\n";
+        // check the run time and values for this job
+
+        // get previous run data
+        $data = $app->db->queryOneRecord("SELECT `last_run`, `next_run`, `running` FROM `sys_cron` WHERE `name` = '" . $app->db->quote(get_class($this)) . "'");
+        if($data) {
+            if($data['last_run']) $this->_last_run = $data['last_run'];
+            if($data['next_run']) $this->_next_run = $data['next_run'];
+            if($data['running'] == 1) $this->_running = true;
+        }
+        if(!$this->_next_run) {
+            if($this->_run_at_new == true) {
+                $this->_next_run = ISPConfigDateTime::dbtime(); // run now.
+            } else {
+                $app->cron->parseCronLine($this->_schedule);
+                $next_run = $app->cron->getNextRun(ISPConfigDateTime::dbtime());
+                $this->_next_run = $next_run;
+                
+                $app->db->query("REPLACE INTO `sys_cron` (`name`, `last_run`, `next_run`, `running`) VALUES ('" . $app->db->quote(get_class($this)) . "', " . ($this->_last_run ? "'" . $app->db->quote($this->_last_run) . "'" : "NULL") . ", " . ($next_run === false ? "NULL" : "'" . $app->db->quote($next_run) . "'") . ", " . ($this->_running == true ? "1" : "0") . ")");
+            }
+        }
+    }
+    
+    /* this function checks if a cron job's next runtime is reached and returns true or false */
+    protected function onBeforeRun() {
+        global $app;
+        
+        print "Called onBeforeRun() for class " . get_class($this) . "\n";
+        
+        if($this->_running == true) return false; // job is still marked as running!
+        
+        print "Jobs next run is " . $this->_next_run . "\n";
+        $reached = ISPConfigDateTime::compare($this->_next_run, ISPConfigDateTime::dbtime());
+        print "Date compare of " . ISPConfigDateTime::to_timestamp($this->_next_run) . " and " . ISPConfigDateTime::dbtime() . " is " . $reached . "\n";
+        if($reached === false) return false; // error!
+        
+        if($reached === -1) {
+            // next_run time not reached
+            return false;
+        }
+        
+        // next_run time reached (reached === 0 or -1)
+        
+        // calculare next run time based on last_run or current time
+        $app->cron->parseCronLine($this->_schedule);
+        if($this->_no_skip == true) {
+            // we need to calculare the next run based on the previous next_run, as we may not skip one.
+            $next_run = $app->cron->getNextRun($this->_next_run);
+            if($next_run === false) {
+                // we could not calculate next run, try it with current time
+                $next_run = $app->cron->getNextRun(ISPConfigDateTime::dbtime());
+            }
+        } else {
+            // calculate next run based on current time
+            $next_run = $app->cron->getNextRun(ISPConfigDateTime::dbtime());
+        }
+        
+        print "Jobs next run is now " . $next_run . "\n";
+        
+        $app->db->query("REPLACE INTO `sys_cron` (`name`, `last_run`, `next_run`, `running`) VALUES ('" . $app->db->quote(get_class($this)) . "', NOW(), " . ($next_run === false ? "NULL" : "'" . $app->db->quote($next_run) . "'") . ", 1)");
+        return true;
+    }
+    
+    // child classes should override this!
+    protected function onRunJob() {
+        global $app;
+        
+        print "Called onRun() for class " . get_class($this) . "\n";
+    }
+    
+    // child classes may override this!
+    protected function onAfterRun() {
+        global $app;
+        
+        print "Called onAfterRun() for class " . get_class($this) . "\n";
+    }
+
+    // child classes may NOT override this!
+    private function onCompleted() {
+        global $app;
+        
+        print "Called onCompleted() for class " . get_class($this) . "\n";
+        $app->db->query("UPDATE `sys_cron` SET `running` = 0 WHERE `name` = '" . $app->db->quote(get_class($this)) . "'");
+    }
+
+}
+
+?>
diff --git a/server/lib/classes/functions.inc.php b/server/lib/classes/functions.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..74f840070682634abf8d4e3c7600d1113fb108db
--- /dev/null
+++ b/server/lib/classes/functions.inc.php
@@ -0,0 +1,398 @@
+<?php
+
+/*
+Copyright (c) 2010, Till Brehm, projektfarm Gmbh
+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.
+*/
+
+//* The purpose of this library is to provide some general functions.
+//* This class is loaded automatically by the ispconfig framework.
+
+class functions {
+	var $idn_converter = null;
+    var $idn_converter_name = '';
+
+	public function mail($to, $subject, $text, $from, $filepath = '', $filetype = 'application/pdf', $filename = '', $cc = '', $bcc = '', $from_name = '') {
+		global $app,$conf;
+		
+		if($conf['demo_mode'] == true) $app->error("Mail sending disabled in demo mode.");
+		
+        $app->uses('getconf,ispcmail');
+		$mail_config = $app->getconf->get_global_config('mail');
+		if($mail_config['smtp_enabled'] == 'y') {
+			$mail_config['use_smtp'] = true;
+			$app->ispcmail->setOptions($mail_config);
+		}
+		$app->ispcmail->setSender($from, $from_name);
+		$app->ispcmail->setSubject($subject);
+		$app->ispcmail->setMailText($text);
+		
+		if($filepath != '') {
+			if(!file_exists($filepath)) $app->error("Mail attachement does not exist ".$filepath);
+			$app->ispcmail->readAttachFile($filepath);
+		}
+		
+		if($cc != '') $app->ispcmail->setHeader('Cc', $cc);
+		if($bcc != '') $app->ispcmail->setHeader('Bcc', $bcc);
+		
+		$app->ispcmail->send($to);
+		$app->ispcmail->finish();
+		
+		/* left in here just for the case...
+		if($filepath != '') {
+			if(!file_exists($filepath)) $app->error("Mail attachement does not exist ".$filepath);
+			
+			$content = file_get_contents($filepath);
+			$content = chunk_split(base64_encode($content));
+			$uid = strtoupper(md5(uniqid(time())));
+			$subject      = "=?utf-8?B?".base64_encode($subject)."?=";
+			
+			if($filename == '') {
+				$path_parts = pathinfo($filepath);
+				$filename = $path_parts["basename"];
+				unset($path_parts);
+			}
+
+			$header = "Return-Path: $from\nFrom: $from\nReply-To: $from\n";
+			if($cc != '') $header .= "Cc: $cc\n";
+			if($bcc != '') $header .= "Bcc: $bcc\n";
+			$header .= "MIME-Version: 1.0\n";
+			$header .= "Content-Type: multipart/mixed; boundary=$uid\n";
+
+			$header .= "--$uid\n";
+			$header .= "Content-Type: text/plain;\n\tcharset=\"UTF-8\"\n";
+			$header .= "Content-Transfer-Encoding: 8bit\n\n";
+			$header .= "$text\n";
+
+			$header .= "--$uid\n";
+			$header .= "Content-Type: $filetype; name=\"$filename\"\n";
+
+			$header .= "Content-Transfer-Encoding: base64\n";
+			$header .= "Content-Disposition: attachment; filename=\"$filename\"\n\n";
+			$header .= "$content\n";
+
+			$header .= "--$uid--";
+
+			mail($to, $subject, "", $header);
+		} else {
+			$header = "From: $from\nReply-To: $from\n";
+			if($cc != '') $header .= "Cc: $cc\n";
+			if($bcc != '') $header .= "Bcc: $bcc\n";
+			$header .= "Content-Type: text/plain;\n\tcharset=\"UTF-8\"\n";
+			$header .= "Content-Transfer-Encoding: 8bit\n\n";
+			$subject      = "=?utf-8?B?".base64_encode($subject)."?=";
+			mail($to, $subject, $text, $header);
+		}
+		*/
+		return true;
+	}
+	
+	public function array_merge($array1,$array2) {
+		$out = $array1;
+		foreach($array2 as $key => $val) {
+			$out[$key] = $val;
+		}
+		return $out;
+	}
+	
+	public function currency_format($number, $view = '') {
+		global $app;
+		if($view != '') $number_format_decimals = (int)$app->lng('number_format_decimals_'.$view);
+        if(!$number_format_decimals) $number_format_decimals = (int)$app->lng('number_format_decimals');
+        
+		$number_format_dec_point = $app->lng('number_format_dec_point');
+		$number_format_thousands_sep = $app->lng('number_format_thousands_sep');
+		if($number_format_thousands_sep == 'number_format_thousands_sep') $number_format_thousands_sep = '';
+		return number_format((double)$number, $number_format_decimals, $number_format_dec_point, $number_format_thousands_sep);
+	}
+	
+	public function get_ispconfig_url() {
+		global $app;
+		
+		$url = (stristr($_SERVER['SERVER_PROTOCOL'],'HTTPS') || stristr($_SERVER['HTTPS'],'on'))?'https':'http';
+		if($_SERVER['SERVER_NAME'] != '_') {
+			$url .= '://'.$_SERVER['SERVER_NAME'];
+			if($_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) {
+				$url .= ':'.$_SERVER['SERVER_PORT'];
+			}
+		} else {
+			$app->uses("getconf");
+			$server_config = $app->getconf->get_server_config(1,'server');
+			$url .= '://'.$server_config['hostname'];
+			if($_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) {
+				$url .= ':'.$_SERVER['SERVER_PORT'];
+			}
+		}
+		return $url;
+	}
+	
+    public function json_encode($data) {
+		if(!function_exists('json_encode')){
+			if(is_array($data) || is_object($data)){
+				$islist = is_array($data) && (empty($data) || array_keys($data) === range(0,count($data)-1));
+
+				if($islist){
+					$json = '[' . implode(',', array_map(array($this, "json_encode"), $data) ) . ']';
+				} else {
+					$items = Array();
+					foreach( $data as $key => $value ) {
+						$items[] = $this->json_encode("$key") . ':' . $this->json_encode($value);
+					}
+					$json = '{' . implode(',', $items) . '}';
+				}
+			} elseif(is_string($data)){
+				# Escape non-printable or Non-ASCII characters.
+				# I also put the \\ character first, as suggested in comments on the 'addclashes' page.
+				$string = '"'.addcslashes($data, "\\\"\n\r\t/".chr(8).chr(12)).'"';
+				$json = '';
+				$len = strlen($string);
+				# Convert UTF-8 to Hexadecimal Codepoints.
+				for($i = 0; $i < $len; $i++){
+					$char = $string[$i];
+					$c1 = ord($char);
+
+					# Single byte;
+					if($c1 <128){
+						$json .= ($c1 > 31) ? $char : sprintf("\\u%04x", $c1);
+						continue;
+					}
+
+					# Double byte
+					$c2 = ord($string[++$i]);
+					if(($c1 & 32) === 0){
+						$json .= sprintf("\\u%04x", ($c1 - 192) * 64 + $c2 - 128);
+						continue;
+					}
+
+					# Triple
+					$c3 = ord($string[++$i]);
+					if(($c1 & 16) === 0){
+						$json .= sprintf("\\u%04x", (($c1 - 224) <<12) + (($c2 - 128) << 6) + ($c3 - 128));
+						continue;
+					}
+
+					# Quadruple
+					$c4 = ord($string[++$i]);
+					if(($c1 & 8) === 0){
+						$u = (($c1 & 15) << 2) + (($c2>>4) & 3) - 1;
+
+						$w1 = (54<<10) + ($u<<6) + (($c2 & 15) << 2) + (($c3>>4) & 3);
+						$w2 = (55<<10) + (($c3 & 15)<<6) + ($c4-128);
+						$json .= sprintf("\\u%04x\\u%04x", $w1, $w2);
+					}
+				}
+			} else {
+				# int, floats, bools, null
+				$json = strtolower(var_export($data, true));
+			}
+			return $json;
+		} else {
+			return json_encode($data);
+		}
+    }
+	
+	public function suggest_ips($type = 'IPv4'){
+		global $app;
+	
+		if($type == 'IPv4'){
+			$regex = "/^[0-9]{1,3}(\.)[0-9]{1,3}(\.)[0-9]{1,3}(\.)[0-9]{1,3}$/";
+		} else {
+			// IPv6
+			$regex = "/^(\:\:([a-f0-9]{1,4}\:){0,6}?[a-f0-9]{0,4}|[a-f0-9]{1,4}(\:[a-f0-9]{1,4}){0,6}?\:\:|[a-f0-9]{1,4}(\:[a-f0-9]{1,4}){1,6}?\:\:([a-f0-9]{1,4}\:){1,6}?[a-f0-9]{1,4})(\/\d{1,3})?$/i";
+		}
+	
+		$ips = array();
+		$results = $app->db->queryAllRecords("SELECT ip_address AS ip FROM server_ip WHERE ip_type = '".$type."'");
+		if(!empty($results) && is_array($results)){
+			foreach($results as $result){
+				if(preg_match($regex, $result['ip'])) $ips[] = $result['ip'];
+			}
+		}
+		$results = $app->db->queryAllRecords("SELECT ip_address AS ip FROM openvz_ip");
+		if(!empty($results) && is_array($results)){
+			foreach($results as $result){
+				if(preg_match($regex, $result['ip'])) $ips[] = $result['ip'];
+			}
+		}
+		$results = $app->db->queryAllRecords("SELECT data AS ip FROM dns_rr WHERE type = 'A' OR type = 'AAAA'");
+		if(!empty($results) && is_array($results)){
+			foreach($results as $result){
+				if(preg_match($regex, $result['ip'])) $ips[] = $result['ip'];
+			}
+		}
+		$results = $app->db->queryAllRecords("SELECT ns AS ip FROM dns_slave");
+		if(!empty($results) && is_array($results)){
+			foreach($results as $result){
+				if(preg_match($regex, $result['ip'])) $ips[] = $result['ip'];
+			}
+		}
+	
+		$results = $app->db->queryAllRecords("SELECT xfer FROM dns_slave WHERE xfer != ''");
+		if(!empty($results) && is_array($results)){
+			foreach($results as $result){
+				$tmp_ips = explode(',', $result['xfer']);
+				foreach($tmp_ips as $tmp_ip){
+					$tmp_ip = trim($tmp_ip);
+					if(preg_match($regex, $tmp_ip)) $ips[] = $tmp_ip;
+				}
+			}
+		}
+		$results = $app->db->queryAllRecords("SELECT xfer FROM dns_soa WHERE xfer != ''");
+		if(!empty($results) && is_array($results)){
+			foreach($results as $result){
+				$tmp_ips = explode(',', $result['xfer']);
+				foreach($tmp_ips as $tmp_ip){
+					$tmp_ip = trim($tmp_ip);
+					if(preg_match($regex, $tmp_ip)) $ips[] = $tmp_ip;
+				}
+			}
+		}
+		$results = $app->db->queryAllRecords("SELECT also_notify FROM dns_soa WHERE also_notify != ''");
+		if(!empty($results) && is_array($results)){
+			foreach($results as $result){
+				$tmp_ips = explode(',', $result['also_notify']);
+				foreach($tmp_ips as $tmp_ip){
+					$tmp_ip = trim($tmp_ip);
+					if(preg_match($regex, $tmp_ip)) $ips[] = $tmp_ip;
+				}
+			}
+		}
+		$results = $app->db->queryAllRecords("SELECT remote_ips FROM web_database WHERE remote_ips != ''");
+		if(!empty($results) && is_array($results)){
+			foreach($results as $result){
+				$tmp_ips = explode(',', $result['remote_ips']);
+				foreach($tmp_ips as $tmp_ip){
+					$tmp_ip = trim($tmp_ip);
+					if(preg_match($regex, $tmp_ip)) $ips[] = $tmp_ip;
+				}
+			}
+		}
+		$ips = array_unique($ips);
+		sort($ips, SORT_NUMERIC);
+
+		$result_array = array('cheader' => array(), 'cdata' => array());
+	
+		if(!empty($ips)){
+			$result_array['cheader'] = array('title' => 'IPs',
+											'total' => count($ips),
+											'limit' => count($ips)
+											);
+	
+			foreach($ips as $ip){
+				$result_array['cdata'][] = array(	'title' => $ip,
+													'description' => $type,
+													'onclick' => '',
+													'fill_text' => $ip
+												);
+			}
+		}
+	
+		return $result_array;
+	}
+
+    public function intval($string, $force_numeric = false) {
+        if(intval($string) == 2147483647 || ($string > 0 && intval($string) < 0)) {
+            if($force_numeric == true) return floatval($string);
+            elseif(preg_match('/^([-]?)[0]*([1-9][0-9]*)([^0-9].*)*$/', $string, $match)) return $match[1].$match[2];
+            else return 0;
+        } else {
+            return intval($string);
+        }
+    }
+    
+    /** IDN converter wrapper.
+     * all converter classes should be placed in ISPC_CLASS_PATH.'/idn/'
+     */
+    private function _idn_encode_decode($domain, $encode = true) {
+        if($domain == '') return '';
+        if(preg_match('/^[0-9\.]+$/', $domain)) return $domain; // may be an ip address - anyway does not need to bee encoded
+        
+        // get domain and user part if it is an email
+        $user_part = false;
+        if(strpos($domain, '@') !== false) {
+            $user_part = substr($domain, 0, strrpos($domain, '@'));
+            $domain = substr($domain, strrpos($domain, '@') + 1);
+        }
+        
+        if($encode == true) {
+            if(function_exists('idn_to_ascii')) {
+                $domain = idn_to_ascii($domain);
+            } elseif(file_exists(ISPC_CLASS_PATH.'/idn/idna_convert.class.php')) {
+                 /* use idna class:
+                 * @author  Matthias Sommerfeld <mso@phlylabs.de>
+                 * @copyright 2004-2011 phlyLabs Berlin, http://phlylabs.de
+                 * @version 0.8.0 2011-03-11
+                 */
+                
+                if(!is_object($this->idn_converter) || $this->idn_converter_name != 'idna_convert.class') {
+                    include_once(ISPC_CLASS_PATH.'/idn/idna_convert.class.php');
+                    $this->idn_converter = new idna_convert(array('idn_version' => 2008));
+                    $this->idn_converter_name = 'idna_convert.class';
+                }
+                $domain = $this->idn_converter->encode($domain);
+            }
+        } else {
+            if(function_exists('idn_to_utf8')) {
+                $domain = idn_to_utf8($domain);
+            } elseif(file_exists(ISPC_CLASS_PATH.'/idn/idna_convert.class.php')) {
+                 /* use idna class:
+                 * @author  Matthias Sommerfeld <mso@phlylabs.de>
+                 * @copyright 2004-2011 phlyLabs Berlin, http://phlylabs.de
+                 * @version 0.8.0 2011-03-11
+                 */
+                
+                if(!is_object($this->idn_converter) || $this->idn_converter_name != 'idna_convert.class') {
+                    include_once(ISPC_CLASS_PATH.'/idn/idna_convert.class.php');
+                    $this->idn_converter = new idna_convert(array('idn_version' => 2008));
+                    $this->idn_converter_name = 'idna_convert.class';
+                }
+                $domain = $this->idn_converter->decode($domain);
+            }
+        }
+        
+        if($user_part !== false) return $user_part . '@' . $domain;
+        else return $domain;
+    }
+     
+    public function idn_encode($domain) {
+        $domains = explode("\n", $domain);
+        for($d = 0; $d < count($domains); $d++) {
+            $domains[$d] = $this->_idn_encode_decode($domains[$d], true);
+        }
+        return implode("\n", $domains);
+    }
+    
+    public function idn_decode($domain) {
+        $domains = explode("\n", $domain);
+        for($d = 0; $d < count($domains); $d++) {
+            $domains[$d] = $this->_idn_encode_decode($domains[$d], false);
+        }
+        return implode("\n", $domains);
+    }
+		
+}
+
+?>
\ No newline at end of file
diff --git a/server/lib/classes/libdatetime.inc.php b/server/lib/classes/libdatetime.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..2735768c828dda85469a7069c7b9e88c31144b67
--- /dev/null
+++ b/server/lib/classes/libdatetime.inc.php
@@ -0,0 +1,479 @@
+<?php
+
+/*
+Copyright (c) 2013, Marius Cramer, pixcept KG
+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.
+*/
+
+/**
+ * Date and Time class
+ * 
+ * provides functions related to date and time operations
+ */
+abstract class ISPConfigDateTime {
+
+    /**
+     * Get days, hours, minutes and seconds
+     *
+     * Returns an array with days, hours, minutes and seconds from a given amount of seconds
+     *
+     * @access public
+     * @param int $seconds amount of seconds
+     * @param bool $get_days if true get the days, too
+     * @return array data (0 => days, 1 => hours, 2 => minutes, 3 => seconds)
+     */
+    public static function get_parts($seconds, $get_days = false) {
+        $days = 0;
+        if($get_days == true) {
+            $days = floor($seconds / (3600 * 24));
+            $seconds = $seconds % (3600 * 24);
+        }
+        $hours = floor($seconds / 3600);
+        $seconds = $seconds % 3600;
+        $minutes = floor($seconds / 60);
+        $seconds = $seconds % 60;
+        
+        return array($days, $hours, $minutes, $seconds);
+    }
+    
+    public static function dbtime() {
+        global $app;
+        
+        $time = $app->db->queryOneRecord('SELECT UNIX_TIMESTAMP() as `time`');
+        return $time['time'];
+    }
+    
+    /**
+     * Get a unix timestamp for a date
+     * 
+     * @access public
+     * @param mixed $date the date to convert. Can be
+     * - int (unix timestamp)
+     * - date string yyyy-mm-dd[ hh:mm:ss]
+     * - date string dd.mm.yyyy[ hh:mm:ss]
+     * @return int the unix timestamp
+     */
+    public static function to_timestamp($date) {
+        if(!is_string($date) && !is_numeric($date)) return false;
+        $date = trim($date);
+        
+        if(is_numeric($date)) return $date;
+        
+        if(strpos($date, '-') !== false) {
+            $regex = "(\d{2,4})-(\d{1,2})-(\d{1,2})(\s+(\d{1,2}):(\d{1,2})(:(\d{1,2}))?)?";
+            $ok = preg_match("'$regex'", $date, $matches);
+            if($ok) {
+                $year = $matches[1];
+                $month = $matches[2];
+                $day = $matches[3];
+                $hour = isset($matches[5]) ? $matches[5] : 0;
+                $minute = isset($matches[6]) ? $matches[6] : 0;
+                $second = isset($matches[8]) ? $matches[8] : 0;
+            }
+        } else {
+            $regex = "(\d{1,2})[/.](\d{1,2})[/.](\d{2,4})(\s+(\d{1,2}):(\d{1,2})(:(\d{1,2}))?)?";
+            $ok = preg_match("'$regex'", $date, $matches);
+            if($ok) {
+                $year = $matches[3];
+                $month = $matches[2];
+                $day = $matches[1];
+                $hour = isset($matches[5]) ? $matches[5] : 0;
+                $minute = isset($matches[6]) ? $matches[6] : 0;
+                $second = isset($matches[8]) ? $matches[8] : 0;
+            }
+        }
+        
+        if(!$ok) return false;
+        
+        if(!$day || !$month || !$year) return false;
+        if(!$hour) $hour = 0;
+        if(!$minute) $minute = 0;
+        if(!$second) $second = 0;
+        if($year < 1900) $year += 1900;
+        
+        if(!checkdate($month, $day, $year)) return false;
+        
+        $date = mktime($hour, $minute, $second, $month, $day, $year);
+        
+        return $date;
+    }
+
+    /**
+     * Get a date string
+     *
+     * Returns a formatted date string
+     *
+     * @access public
+     * @param mixed $date the date to convert. Can be
+     * - int (unix timestamp)
+     * - date string yyyy-mm-dd[ hh:mm:ss]
+     * - date string dd.mm.yyyy[ hh:mm:ss]
+     * @param string $format the format to get the date string in.
+     * - short: dd.mm.yy
+     * - veryshort: dd.mm.
+     * - medium: dd.mm.yyyy
+     * - long: dd. Month yyyy
+     * - extra: Day, dd. Month yyyy
+     * - day: dd
+     * - monthnum: mm
+     * - shortmonth: Short month name like Mar for March
+     * - month: Month name
+     * - shortyear: yy
+     * - year: yyyy
+     * - onlydate: dd.mm
+     * - onlydatelong: dd. Month
+     * - onlytime: HH:MM
+     * - rss: Rss time format for XML
+     * - nice: if you prepend a nice: (like nice:long) you will get results like "today" or "yesterday" if applicable
+     * - custom: you can give a strftime format like %d.%m.%Y %H:%M if you prepend custom: to it
+     * @param bool $time if true apped the time to the date string
+     * @param bool $seconds if true append the seconds to the time
+     * @return string date string
+     */
+    public static function to_string($date, $format = 'short', $time = false, $seconds = false) {
+        global $portal;
+        
+        if(!$date) return '';
+        
+        setlocale(LC_TIME, array('de_DE.UTF-8', 'de_DE', 'de_DE.ISO-8859-1', 'de_DE.ISO-8859-15'));
+        
+        if(!is_numeric($date)) {
+            $date = self::to_timestamp($date);
+            if($date === false) return $date;
+        }
+        
+        if($format == 'timestamp') return $date;
+        
+        $fmt = '';
+        $prepend = '';
+        if(substr($format, 0, 5) == 'nice:') {
+            if(strftime('%d.%m.%Y', $date) == strftime('%d.%m.%Y', $portal->getTime())) {
+                if($time == true) $format = 'onlytime';
+                else $format = '';
+                $prepend = 'Heute';
+            } elseif(strftime('%d.%m.%Y', $date) == strftime('%d.%m.%Y', $portal->getTime() - 86400)) {
+                if($time == true) $format = 'onlytime';
+                else $format = '';
+                $prepend = 'Gestern';
+            } elseif(strftime('%d.%m.%Y', $date) == strftime('%d.%m.%Y', $portal->getTime() + 86400)) {
+                if($time == true) $format = 'onlytime';
+                else $format = '';
+                $prepend = 'Morgen';
+            } else {
+                $format = substr($format, 5);
+            }
+        } elseif(substr($format, 0, 7) == 'custom:') {
+            $fmt = substr($format, 7);
+            $format = '';
+            $time = false;
+        }
+        
+        if($format == 'short') $fmt = '%d.%m.%y';
+        elseif($format == 'veryshort') $fmt = '%d.%m.';
+        elseif($format == 'medium') $fmt = '%d.%m.%Y';
+        elseif($format == 'long') $fmt = '%d. %B %Y';
+        elseif($format == 'extra') $fmt = '%A, %d. %B %Y';
+        elseif($format == 'day') $fmt = '%d';
+        elseif($format == 'monthnum') $fmt = '%m';
+        elseif($format == 'shortmonth') $fmt = '%b';
+        elseif($format == 'month') $fmt = '%B';
+        elseif($format == 'shortyear') $fmt = '%y';
+        elseif($format == 'year') $fmt = '%Y';
+        elseif($format == 'onlydate') $fmt = '%d.%m.';
+        elseif($format == 'onlydatelong') $fmt = '%d. %B';
+        elseif($format == 'onlytime') {
+            $fmt = '%H:%M';
+            $time = false;
+        } elseif($format == 'rss') {
+            $ret = date(DATE_RSS, $date);
+            if($prepend != '') $ret = $prepend . ' ' . $ret;
+            return $ret;
+        } elseif($format == 'sitemap') {
+            $ret = date(DATE_ATOM, $date);
+            if($prepend != '') $ret = $prepend . ' ' . $ret;
+            return $ret;
+        }
+        if($time == true) $fmt .= ' %H:%M' . ($seconds == true ? ':%S' : '');
+        
+        if($fmt != '') $ret = strftime($fmt, $date);
+        else $ret = '';
+        
+        if($prepend != '') $ret = trim($prepend . ' ' . $ret);
+        return $ret;
+    }
+
+    /**
+     * Get the month difference of two dates
+     *
+     * Gets the difference in months of two given dates.
+     * The days are ignored, so the difference between 2010-01-21 and 2010-05-01 is 4!
+     *
+     * @access public
+     * @param mixed $date_from the beginning date, either
+     * - int (unix timestamp)
+     * - date string yyyy-mm-dd[ hh:mm:ss]
+     * - date string dd.mm.yyyy[ hh:mm:ss]
+     * @param mixed $date_to the ending date, either
+     * - int (unix timestamp)
+     * - date string yyyy-mm-dd[ hh:mm:ss]
+     * - date string dd.mm.yyyy[ hh:mm:ss]
+     * @param bool $return_years if set to true, the function returns an array of years and months instead of months
+     * @param bool $include_both if set to true, the starting AND ending month is included, so the month count is +1
+     * @return mixed either int (months) or array of int (0 => years, 1 => months) or FALSE on invalid dates
+     */
+    public static function months_between($date_from, $date_to, $return_years = false, $include_both = false) {
+        $date_from = self::to_string($date_from, 'custom:%Y%m');
+        if($date_from === false) return $date_from;
+        
+        $date_to = self::to_string($date_to, 'custom:%Y%m');
+        if($date_to === false) return $date_to;
+        
+        $date_from = intval($date_from);
+        $date_to = intval($date_to);
+        
+        if($date_to < $date_from) return false;
+        
+        $result = $date_to - $date_from;
+        if($include_both == true) $result++;
+        
+        $years = floor($result / 100);
+        $months = $result % 100;
+        if($months > 12) $months -= 88;
+        elseif($months == 12) {
+            $months = 0;
+            $years++;
+        }
+        if($return_years == true) return array($years, $months);
+        
+        $months += ($years * 12);
+        return $months;
+    }
+
+    /**
+     * Get the day difference of two dates
+     *
+     * Gets the difference in days of two given dates.
+     *
+     * @access public
+     * @param mixed $date_from the beginning date, either
+     * - int (unix timestamp)
+     * - date string yyyy-mm-dd[ hh:mm:ss]
+     * - date string dd.mm.yyyy[ hh:mm:ss]
+     * @param mixed $date_to the ending date, either
+     * - int (unix timestamp)
+     * - date string yyyy-mm-dd[ hh:mm:ss]
+     * - date string dd.mm.yyyy[ hh:mm:ss]
+     * @param bool $include_both if set to true, the starting AND ending day is included, so the day count is +1
+     * @return mixed either int (days) or FALSE on invalid dates
+     */
+    public static function days_between($date_from, $date_to, $include_both = false) {
+        $date_from = self::to_string($date_from, 'custom:%Y-%m-%d');
+        if($date_from === false) return $date_from;
+        list($y, $m, $d) = explode('-', $date_from);
+        $ts_from = mktime(0, 0, 0, $m, $d, $y);
+        
+        $date_to = self::to_string($date_to, 'custom:%Y-%m-%d');
+        if($date_to === false) return $date_to;
+        list($y, $m, $d) = explode('-', $date_to);
+        $ts_to = mktime(0, 0, 0, $m, $d, $y);
+        
+        $result = $ts_to - $ts_from;
+        if($include_both == true) $result++;
+        
+        $days = floor($result / (3600 * 24));
+        
+        return $days;
+    }
+
+    /**
+     * Check if one date is before another
+     *
+     * @access public
+     * @param mixed $date_1 the first date, either
+     * - int (unix timestamp)
+     * - date string yyyy-mm-dd[ hh:mm:ss]
+     * - date string dd.mm.yyyy[ hh:mm:ss]
+     * @param mixed $date_2 the second date, either
+     * - int (unix timestamp)
+     * - date string yyyy-mm-dd[ hh:mm:ss]
+     * - date string dd.mm.yyyy[ hh:mm:ss]
+     * @return mixed either int (1 if the first date is earlier, -1 if the second date is earlier, 0 if both are the same) or FALSE on invalid dates
+     */
+    public static function compare($date_1, $date_2) {
+        $ts_1 = self::to_timestamp($date_1);
+        if($ts_1 === false) return false;
+        $ts_2 = self::to_timestamp($date_2);
+        if($ts_2 === false) return false;
+        
+        if($ts_1 < $ts_2) return 1;
+        elseif($ts_1 > $ts_2) return -1;
+        else return 0;
+    }
+    
+    /**
+     * Convert date to sql format
+     *
+     * Converts a date from different formats to the sql format if possible
+     *
+     * @access public
+     * @param string $date date string in forms
+     * - dd.mm.yy
+     * - yyyy-mm-dd
+     * - yy-mm-dd
+     * - yyyy/mm/dd
+     * - dd.mm.yy
+     * - all formats can have time information HH:MM:SS appended
+     * @param bool $no_time if true, the resulting sql date is without time part even if time was part of the input
+     * @return mixed sql date string on success, error object otherwise
+     */
+    public static function sql_date($date = false, $no_time = false) {
+        global $portal;
+        
+        $result = '';
+        $time = '';
+        
+        if($date === false) $date = $portal->getTime(true);
+        
+        if(is_numeric($date)) {
+            return ($no_time ? strftime('%Y-%m-%d', $date) : strftime('%Y-%m-%d %H:%M:%S', $date));
+        }
+        
+        if(preg_match('/^(.*)(\d{1,2}:\d{1,2}(:\d{1,2})?)(\D|$)/', $date, $matches)) {
+            $date = $matches[1];
+            $time = ' ' . $matches[2];
+        }
+        if(preg_match('/(^|\D)(\d{4,4})-(\d{1,2})-(\d{1,2})(\D|$)/', $date, $result)) {
+            $day = $result[4];
+            $month = $result[3];
+            $year = $result[2];
+        } elseif(preg_match('/(^|\D)(\d{4,4})\/(\d{1,2})\/(\d{1,2})(\D|$)/', $date, $result)) {
+            $day = $result[4];
+            $month = $result[3];
+            $year = $result[2];
+        } elseif(preg_match('/(^|\D)(\d{2,2})-(\d{1,2})-(\d{1,2})(\D|$)/', $date, $result)) {
+            $day = $result[4];
+            $month = $result[3];
+            $year = $result[2];
+        } elseif(preg_match('/(^|\D)(\d{1,2})\.(\d{1,2})\.(\d{4,4})(\D|$)/', $date, $result)) {
+            $day = $result[2];
+            $month = $result[3];
+            $year = $result[4];
+        } elseif(preg_match('/(^|\D)(\d{1,2})\.(\d{1,2})\.(\d{2,2})(\D|$)/', $date, $result)) {
+            $day = $result[2];
+            $month = $result[3];
+            $year = $result[4];
+        } else {
+            return false;
+        }
+        if($no_time == true) $time = '';
+        
+        $day = str_pad(intval($day), 2, '0', STR_PAD_LEFT);
+        $month = str_pad(intval($month), 2, '0', STR_PAD_LEFT);
+        $year = intval($year);
+
+        $valid = checkdate($month, $day, $year);
+        if(!$valid) return false;
+        
+        return $year . '-' . $month . '-' . $day . $time;
+    }
+    
+    /**
+     * Get information if given date is leap year
+     * 
+     * @access public
+     * @param mixed $date Date to check
+     * @return bool true if leap year, false otherwise
+     */
+    public static function is_leap_year($date) {
+        // check if only year was given
+        if(is_numeric($date) && $date < 10000) $date .= '-01-01';
+        
+        $ts = self::to_timestamp($date);
+        if($ts === false) return false;
+        
+        if(date('L', $ts) == 1) return true;
+        else return false;
+    }
+    
+    /**
+     * Get the last day of the month
+     * 
+     * @access public
+     * @param int $month the month to get the last day for
+     * @param int $year the corresponding year (for february in leap years)
+     * @return bool true if leap year, false otherwise
+     */
+    public static function last_day($month, $year = false) {
+        switch($month) {
+            case 1:
+            case 3:
+            case 5:
+            case 7:
+            case 8:
+            case 10:
+            case 12:
+                return 31;
+                break;
+            case 2:
+                return ($year !== false && self::is_leap_year($year) ? 29 : 28);
+                break;
+            default:
+                return 30;
+                break;
+        }
+    }
+
+    /**
+     * Get age for given date
+     *
+     * Returns the age for a given date if possible
+     *
+     * @access public
+     * @param string $date see ISPConfigDateTime::sql_date() for possible values
+     * @return mixed int of age if successful, error object otherwise
+     * @see ISPConfigDateTime::sql_date
+     */
+    public static function calc_age($date) {
+        global $portal;
+        
+        $date = self::sql_date($date);
+        if($date === false) return $date;
+        
+        list($year, $month, $day) = explode('-', $date);
+        list($curyear, $curmonth, $curday) = explode('-', strftime('%Y-%m-%d', $portal->getTime()));
+        
+        $year_diff = $curyear - $year;
+        $month_diff = $curmonth - $month;
+        $day_diff = $curday - $day;
+        
+        if($day_diff < 0) $month_diff--;
+        if($month_diff < 0) $year_diff--;
+        if($year_diff < 0) $year_diff = 0;
+        
+        return $year_diff;
+    }
+}
+
diff --git a/server/lib/classes/monitor_tools.inc.php b/server/lib/classes/monitor_tools.inc.php
index 6b93e1e6aee5abbeeca176780ab9ae25ec6cd097..42ef73ff8ec7ad435f446cc1baffed7002b5c5d1 100644
--- a/server/lib/classes/monitor_tools.inc.php
+++ b/server/lib/classes/monitor_tools.inc.php
@@ -226,1461 +226,119 @@ class monitor_tools {
 		return array('name' => $distname, 'version' => $distver, 'id' => $distid, 'baseid' => $distbaseid);
 	}
 
-		//** Email Quota
-		public function monitorEmailQuota() {
-				global $conf, $app;
-
-		//* Initialize data array
-		$data = array();
-
-		//* the id of the server as int
-		$server_id = intval($conf['server_id']);
-
-		//* The type of the data
-		$type = 'email_quota';
-
-		//* The state of the email_quota.
-		$state = 'ok';
-
-		$mailboxes = $app->db->queryAllRecords("SELECT email,maildir FROM mail_user WHERE server_id = $server_id");
-		if(is_array($mailboxes)) {
-			foreach($mailboxes as $mb) {
-				$email = $mb['email'];
-				$email_parts = explode('@',$mb['email']);
-				$filename = $mb['maildir'].'/.quotausage';
-				if(file_exists($filename) && !is_link($filename)) {
-					$quotafile = file($filename);
-					$data[$email]['used'] = trim($quotafile['1']);
-					unset($quotafile);
-				} else {
-					exec('du -s '.escapeshellcmd($mb['maildir']),$out);
-					$parts = explode(' ',$out[0]);
-					$data[$email]['used'] = intval($parts[0])*1024;
-					unset($out);
-					unset($parts);
-				}
-			}
-		}
-
-		unset($mailboxes);
-
-				//* Dovecot quota check Courier in progress lathama@gmail.com
-		/*
-				if($dir = opendir("/var/vmail")){
-						while (($quotafiles = readdir($dir)) !== false){
-								if(preg_match('/.\_quota$/', $quotafiles)){
-										$quotafile = (file("/var/vmail/" . $quotafiles));
-										$emailaddress = preg_replace('/_quota/',"", $quotafiles);
-										$emailaddress = preg_replace('/_/',"@", $emailaddress);
-										$data[$emailaddress]['used'] = trim($quotafile['1']);
-								}
-						}
-						closedir($dir);
-				}
-		*/
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-				return $res;
-		}
-
-		//** Filesystem Quota
-	public function monitorHDQuota() {
-		global $conf;
-
-		//* Initialize data array
-		$data = array();
-
-		//* the id of the server as int
-		$server_id = intval($conf['server_id']);
-
-		//* The type of the data
-		$type = 'harddisk_quota';
-
-		//* The state of the harddisk_quota.
-		$state = 'ok';
-
-		//* Fetch the data for all users
-		$dfData = shell_exec('repquota -au 2>/dev/null');
-
-		//* Split into array
-		$df = explode("\n", $dfData);
-
-		//* ignore the first 5 lines, process the rest
-		for ($i = 5; $i <= sizeof($df); $i++) {
-			if ($df[$i] != '') {
-				//* Make a array of the data
-				$s = preg_split('/[\s]+/', $df[$i]);
-				$username = $s[0];
-				if (substr($username, 0, 3) == 'web') {
-					if (isset($data['user'][$username])) {
-						$data['user'][$username]['used'] += $s[2];
-						$data['user'][$username]['soft'] += $s[3];
-						$data['user'][$username]['hard'] += $s[4];
-						$data['user'][$username]['files'] += $s[5];
-					} else {
-						$data['user'][$username]['used'] = $s[2];
-						$data['user'][$username]['soft'] = $s[3];
-						$data['user'][$username]['hard'] = $s[4];
-						$data['user'][$username]['files'] = $s[5];
-					}
-				}
-			}
-		}
-
-		//** Fetch the data for all users
-		$dfData = shell_exec('repquota -ag 2>/dev/null');
-
-		//* split into array
-		$df = explode("\n", $dfData);
-
-		//* ignore the first 5 lines, process the rest
-		for ($i = 5; $i <= sizeof($df); $i++) {
-			if ($df[$i] != '') {
-				//* Make a array of the data
-				$s = preg_split('/[\s]+/', $df[$i]);
-				$groupname = $s[0];
-				if (substr($groupname, 0, 6) == 'client') {
-					if (isset($data['group'][$groupname])) {
-						$data['group'][$groupname]['used'] += $s[1];
-						$data['group'][$groupname]['soft'] += $s[2];
-						$data['group'][$groupname]['hard'] += $s[3];
-					} else {
-						$data['group'][$groupname]['used'] = $s[1];
-						$data['group'][$groupname]['soft'] = $s[2];
-						$data['group'][$groupname]['hard'] = $s[3];
-					}
-				}
-			}
-		}
-
-		//* Return the Result
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorServer() {
-		global $conf;
-
-		/* the id of the server as int */
-		$server_id = intval($conf['server_id']);
-
-		/** The type of the data */
-		$type = 'server_load';
-
-		/*
-			Fetch the data into a array
-		 */
-		$procUptime = shell_exec("cat /proc/uptime | cut -f1 -d' '");
-		$data['up_days'] = floor($procUptime / 86400);
-		$data['up_hours'] = floor(($procUptime - $data['up_days'] * 86400) / 3600);
-		$data['up_minutes'] = floor(($procUptime - $data['up_days'] * 86400 - $data['up_hours'] * 3600) / 60);
-
-		$data['uptime'] = shell_exec('uptime');
-
-		$tmp = explode(',', $data['uptime'], 4);
-		$tmpUser = explode(' ', trim($tmp[2]));
-		$data['user_online'] = intval($tmpUser[0]);
-
-		//* New Load Average code to fix "always zero" bug in non-english distros. NEEDS TESTING
-		$loadTmp = shell_exec("cat /proc/loadavg | cut -f1-3 -d' '");
-		$load = explode(' ', $loadTmp);
-		$data['load_1'] = floatval(str_replace(',', '.', $load[0]));
-		$data['load_5'] = floatval(str_replace(',', '.', $load[1]));
-		$data['load_15'] = floatval(str_replace(',', '.', $load[2]));
-
-		/** The state of the server-load. */
-		$state = 'ok';
-		if ($data['load_1'] > 20)
-			$state = 'info';
-		if ($data['load_1'] > 50)
-			$state = 'warning';
-		if ($data['load_1'] > 100)
-			$state = 'critical';
-		if ($data['load_1'] > 150)
-			$state = 'error';
-
-		/*
-		 * Return the Result
-		 */
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorOsVer() {
-		global $conf;
-
-		/* the id of the server as int */
-		$server_id = intval($conf['server_id']);
-
-		/** The type of the data */
-		$type = 'os_info';
-
-		/*
-			Fetch the data into a array
-		 */
-		$dist = $this->get_distname();
-
-		$data['name'] = $dist['name'];
-		$data['version'] = $dist['version'];
-
-		/* the OS has no state. It is, what it is */
-		$state = 'no_state';
-
-		/*
-		 * Return the Result
-		 */
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorIspcVer() {
-		global $conf;
-
-		/* the id of the server as int */
-		$server_id = intval($conf['server_id']);
-
-		/** The type of the data */
-		$type = 'ispc_info';
-
-		/*
-			Fetch the data into a array
-		 */
-		$data['name'] = ISPC_APP_TITLE;
-		$data['version'] = ISPC_APP_VERSION;
-
-		/* the ISPC-Version has no state. It is, what it is */
-		$state = 'no_state';
-
-		/*
-		 * Return the Result
-		 */
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorDiskUsage() {
-		global $app,$conf;
-
-		/* the id of the server as int */
-		$server_id = intval($conf['server_id']);
-
-		/** The type of the data */
-		$type = 'disk_usage';
-
-		/** The state of the disk-usage */
-		$state = 'ok';
-
-		/** Fetch the data of ALL devices into a array (needed for monitoring!) */
-		//$dfData = shell_exec('df -hT 2>/dev/null');
-		$app->uses('getconf');
-        $web_config = $app->getconf->get_server_config($conf['server_id'], 'web');
-        $dfData = shell_exec('df -hT|grep -v "'.$web_config['website_basedir'].'/" 2>/dev/null');
-
-		// split into array
-		$df = explode("\n", $dfData);
-
-		/*
-		 * ignore the first line, process the rest
-		 */
-		for ($i = 1; $i <= sizeof($df); $i++) {
-			if ($df[$i] != '') {
-				/*
-				 * Make an array of the data
-				 */
-				$s = preg_split('/[\s]+/', $df[$i]);
-				$data[$i]['fs'] = $s[0];
-				$data[$i]['type'] = $s[1];
-				$data[$i]['size'] = $s[2];
-				$data[$i]['used'] = $s[3];
-				$data[$i]['available'] = $s[4];
-				$data[$i]['percent'] = $s[5];
-				$data[$i]['mounted'] = $s[6];
-				/*
-				 * calculate the state
-				 */
-				$usePercent = floatval($data[$i]['percent']);
-
-				//* get the free memsize
-				if(substr($data[$i]['available'],-1) == 'G') {
-					$freesize = floatval($data[$i]['available'])*1024;
-				} elseif(substr($data[$i]['available'],-1) == 'T') {
-					$freesize = floatval($data[$i]['available'])*1024*1024;
-				} else {
-					$freesize = floatval($data[$i]['available']);
-				}
-
-				//* We don't want to check some filesystem which have no sensible filling levels
-				switch ($data[$i]['type']) {
-					case 'iso9660':
-					case 'cramfs':
-					case 'udf':
-					case 'tmpfs':
-					case 'devtmpfs':
-					case 'udev':
-						break;
-					default:
-						if ($usePercent > 75 && $freesize < 2000)
-							$state = $this->_setState($state, 'info');
-						if ($usePercent > 80 && $freesize < 1000)
-							$state = $this->_setState($state, 'warning');
-						if ($usePercent > 90 && $freesize < 500)
-							$state = $this->_setState($state, 'critical');
-						if ($usePercent > 95 && $freesize < 100)
-							$state = $this->_setState($state, 'error');
-						break;
-				}
-			}
-		}
-
-		/*
-		 * Return the Result
-		 */
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorMemUsage() {
-		global $conf;
-
-		/* the id of the server as int */
-		$server_id = intval($conf['server_id']);
-
-		/** The type of the data */
-		$type = 'mem_usage';
-
-		/*
-			Fetch the data into a array
-		 */
-		$miData = shell_exec('cat /proc/meminfo');
-
-		$memInfo = explode("\n", $miData);
-
-		foreach ($memInfo as $line) {
-			$part = preg_split('/:/', $line);
-			$key = trim($part[0]);
-			$tmp = explode(' ', trim($part[1]));
-			$value = 0;
-			if ($tmp[1] == 'kB')
-				$value = $tmp[0] * 1024;
-			$data[$key] = $value;
-		}
-
-		/*
-		 * actually this info has no state.
-		 * maybe someone knows better...???...
-		 */
-		$state = 'no_state';
-
-		/*
-		 * Return the Result
-		 */
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorCpu() {
-		global $conf;
-
-		/* the id of the server as int */
-		$server_id = intval($conf['server_id']);
-
-		/** The type of the data */
-		$type = 'cpu_info';
-
-		/*
-			Fetch the data into a array
-		 */
-		if (file_exists('/proc/cpuinfo')) {
-			$cpuData = shell_exec('cat /proc/cpuinfo');
-			$cpuInfo = explode("\n", $cpuData);
-			$processor = 0;
-
-			foreach ($cpuInfo as $line) {
-
-				$part = preg_split('/:/', $line);
-				$key = trim($part[0]);
-				$value = trim($part[1]);
-				if ($key == 'processor')
-					$processor = intval($value);
-				if ($key != '')
-					$data[$key . ' ' . $processor] = $value;
-			}
-
-			/* the cpu has no state. It is, what it is */
-			$state = 'no_state';
-		} else {
-			/*
-			 * It is not Linux, so there is no data and no state
-			 *
-			 * no_state, NOT unknown, because "unknown" is shown as state
-			 * inside the GUI. no_state is hidden.
-			 *
-			 * We have to write NO DATA inside the DB, because the GUI
-			 * could not know, if there is any dat, or not...
-			 */
-			$state = 'no_state';
-			$data['output'] = '';
-		}
-
-		/*
-		 * Return the Result
-		 */
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorServices() {
-		global $app;
-		global $conf;
-
-		/** the id of the server as int */
-		$server_id = intval($conf['server_id']);
-
-		/**  get the "active" Services of the server from the DB */
-		$services = $app->db->queryOneRecord('SELECT * FROM server WHERE server_id = ' . $server_id);
-		/*
-		 * If the DB is down, we have to set the db to "yes".
-		 * If we don't do this, then the monitor will NOT monitor, that the db is down and so the
-		 * rescue-module can not try to rescue the db
-		 */
-		if ($services == null) {
-			$services['db_server'] = 1;
-		}
-
-		/* The type of the Monitor-data */
-		$type = 'services';
-
-		/** the State of the monitoring */
-		/* ok, if ALL active services are running,
-		 * error, if not
-		 * There is no other state!
-		 */
-		$state = 'ok';
-
-		/* Monitor Webserver */
-		$data['webserver'] = -1; // unknown - not needed
-		if ($services['web_server'] == 1) {
-			if ($this->_checkTcp('localhost', 80)) {
-				$data['webserver'] = 1;
-			} else {
-				$data['webserver'] = 0;
-				$state = 'error'; // because service is down
-			}
-		}
-
-		/* Monitor FTP-Server */
-		$data['ftpserver'] = -1; // unknown - not needed
-		if ($services['file_server'] == 1) {
-			if ($this->_checkFtp('localhost', 21)) {
-				$data['ftpserver'] = 1;
-			} else {
-				$data['ftpserver'] = 0;
-				$state = 'error'; // because service is down
-			}
-		}
-
-		/* Monitor SMTP-Server */
-		$data['smtpserver'] = -1; // unknown - not needed
-		if ($services['mail_server'] == 1) {
-			if ($this->_checkTcp('localhost', 25)) {
-				$data['smtpserver'] = 1;
-			} else {
-				$data['smtpserver'] = 0;
-				$state = 'error'; // because service is down
-			}
-		}
-
-		/* Monitor POP3-Server */
-		$data['pop3server'] = -1; // unknown - not needed
-		if ($services['mail_server'] == 1) {
-			if ($this->_checkTcp('localhost', 110)) {
-				$data['pop3server'] = 1;
-			} else {
-				$data['pop3server'] = 0;
-				$state = 'error'; // because service is down
-			}
-		}
-
-		/* Monitor IMAP-Server */
-		$data['imapserver'] = -1; // unknown - not needed
-		if ($services['mail_server'] == 1) {
-			if ($this->_checkTcp('localhost', 143)) {
-				$data['imapserver'] = 1;
-			} else {
-				$data['imapserver'] = 0;
-				$state = 'error'; // because service is down
-			}
-		}
-
-		/* Monitor BIND-Server */
-		$data['bindserver'] = -1; // unknown - not needed
-		if ($services['dns_server'] == 1) {
-			if ($this->_checkUdp('localhost', 53)) {
-				$data['bindserver'] = 1;
-			} else {
-				$data['bindserver'] = 0;
-				$state = 'error'; // because service is down
-			}
-		}
-
-		/* Monitor MySQL Server */
-		$data['mysqlserver'] = -1; // unknown - not needed
-		if ($services['db_server'] == 1) {
-			if ($this->_checkTcp('localhost', 3306)) {
-				$data['mysqlserver'] = 1;
-			} else {
-				$data['mysqlserver'] = 0;
-				$state = 'error'; // because service is down
-			}
-
-			if ($this->_checkTcp('localhost', 27017)) {
-				$data['mongodbserver'] = 1;
-			} else {
-				$data['mongodbserver'] = 0;
-				$state = 'error'; // because service is down
-			}
-		}
-
-		/*
-		 * Return the Result
-		 */
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorOpenVzHost() {
-		global $app;
-		global $conf;
-
-		/* the id of the server as int */
-		$server_id = intval($conf['server_id']);
-
-		/** The type of the data */
-		$type = 'openvz_veinfo';
-
-		/*
-			Fetch the data into a array
-		 */
-		$app->load(openvz_tools);
-		$openVzTools = new openvz_tools();
-		$data = $openVzTools->getOpenVzVeInfo();
-
-		/* the VE-Info has no state. It is, what it is */
-		$state = 'no_state';
-
-		/*
-		 * Return the Result
-		 */
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorOpenVzUserBeancounter() {
-		global $app;
-		global $conf;
-
-		/* the id of the server as int */
-		$server_id = intval($conf['server_id']);
-
-		/** The type of the data */
-		$type = 'openvz_beancounter';
-
-		/*
-			Fetch the data into a array
-		 */
-		$app->load(openvz_tools);
-		$openVzTools = new openvz_tools();
-		$data = $openVzTools->getOpenVzVeBeanCounter();
-
-		/* calculate the state of the beancounter */
-		if ($data == '') {
-			$state = 'no_state';
-		} else {
-			$state = 'ok';
-
-			/* transfer this output-string into a array */
-			$test = explode("\n", $data);
-
-			/* the first list of the output is not needed */
-			array_shift($test);
-
-			/* now process all items of the rest */
-			foreach ($test as $item) {
-				/*
-				 * eliminate all doubled spaces and spaces at the beginning and end
-				 */
-				while (strpos($item, '  ') !== false) {
-					$item = str_replace('  ', ' ', $item);
-				}
-				$item = trim($item);
-
-				/*
-				 * The failcounter is the LAST
-				 */
-				if ($item != '') {
-					$tmp = explode(' ', $item);
-					$failCounter = $tmp[sizeof($tmp) - 1];
-					if ($failCounter > 0)
-						$state = 'info';
-					if ($failCounter > 50)
-						$state = 'warning';
-					if ($failCounter > 200)
-						$state = 'critical';
-					if ($failCounter > 10000)
-						$state = 'error';
-				}
-			}
-		}
-
-		/*
-		 * Return the Result
-		 */
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorSystemUpdate() {
-		global $conf;
-
-		/* the id of the server as int */
-		$server_id = intval($conf['server_id']);
-
-		/** The type of the data */
-		$type = 'system_update';
-
-		/* This monitoring is only available on Debian or Ubuntu */
-		if (file_exists('/etc/debian_version')) {
-
-			/*
-			 * first update the "apt database"
-			 */
-			shell_exec('apt-get update');
-
-			/*
-			 * Then test the upgrade.
-			 * if there is any output, then there is a needed update
-			 */
-			$aptData = shell_exec('apt-get -s -qq dist-upgrade');
-			if ($aptData == '') {
-				/* There is nothing to update! */
-				$state = 'ok';
-			} else {
-				/*
-				 * There is something to update! this is in most cases not critical, so we can
-				 * do a system-update once a month or so...
-				 */
-				$state = 'info';
-			}
-
-			/*
-			 * Fetch the output
-			 */
-			$data['output'] = $aptData;
-		} elseif (file_exists('/etc/gentoo-release')) {
-
-			/*
-			 * first update the portage tree
-			 */
-
-			// In keeping with gentoo's rsync policy, don't update to frequently (every four hours - taken from http://www.gentoo.org/doc/en/source_mirrors.xml)
-			$do_update = true;
-			if (file_exists('/usr/portage/metadata/timestamp.chk')) {
-				$datetime = file_get_contents('/usr/portage/metadata/timestamp.chk');
-				$datetime = trim($datetime);
-
-				$dstamp = strtotime($datetime);
-				if ($dstamp) {
-					$checkat = $dstamp + 14400; // + 4hours
-					if (mktime() < $checkat) {
-						$do_update = false;
-					}
-				}
-			}
-
-			if ($do_update) {
-				shell_exec('emerge --sync --quiet');
-			}
-
-			/*
-			 * Then test the upgrade.
-			 * if there is any output, then there is a needed update
-			 */
-			$emergeData = shell_exec('glsa-check -t affected');
-			if ($emergeData == '') {
-				/* There is nothing to update! */
-				$state = 'ok';
-				$data['output'] = 'No unapplied GLSA\'s found on the system.';
-			} else {
-				/* There is something to update! */
-				$state = 'info';
-				$data['output'] = shell_exec('glsa-check -pv --nocolor affected 2>/dev/null');
-			}
-		} elseif (file_exists('/etc/SuSE-release')) {
-
-			/*
-			 * update and find the upgrade.
-			 * if there is any output, then there is a needed update
-			 */
-			$aptData = shell_exec('zypper -q lu');
-			if ($aptData == '') {
-				/* There is nothing to update! */
-				$state = 'ok';
-			} else {
-				/*
-				 * There is something to update! this is in most cases not critical, so we can
-				 * do a system-update once a month or so...
-				 */
-				$state = 'info';
-			}
-
-			/*
-			 * Fetch the output
-			 */
-			$data['output'] = shell_exec('zypper lu');
-		} else {
-			/*
-			 * It is not Debian/Ubuntu, so there is no data and no state
-			 *
-			 * no_state, NOT unknown, because "unknown" is shown as state
-			 * inside the GUI. no_state is hidden.
-			 *
-			 * We have to write NO DATA inside the DB, because the GUI
-			 * could not know, if there is any dat, or not...
-			 */
-			$state = 'no_state';
-			$data['output'] = '';
-		}
-
-		/*
-		 * Return the Result
-		 */
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorMailQueue() {
-		global $conf;
-
-		/* the id of the server as int */
-		$server_id = intval($conf['server_id']);
-
-		/** The type of the data */
-		$type = 'mailq';
-
-		/* Get the data from the mailq */
-		$data['output'] = shell_exec('mailq');
-
-		/*
-		 *  The last line has more informations
-		 */
-		$tmp = explode("\n", $data['output']);
-		$more = $tmp[sizeof($tmp) - 1];
-		$res = $this->_getIntArray($more);
-		$data['bytes'] = $res[0];
-		$data['requests'] = $res[1];
-
-		/** The state of the mailq. */
-		$state = 'ok';
-		if ($data['requests'] > 2000)
-			$state = 'info';
-		if ($data['requests'] > 5000)
-			$state = 'warning';
-		if ($data['requests'] > 8000)
-			$state = 'critical';
-		if ($data['requests'] > 10000)
-			$state = 'error';
-
-		/*
-		 * Return the Result
-		 */
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorRaid() {
-		global $conf;
-
-		/* the id of the server as int */
-		$server_id = intval($conf['server_id']);
-
-		/** The type of the data */
-		$type = 'raid_state';
-
-		/*
-		 * We support several RAID types, but if we can't find any of them, we have no data
-		 */
-		$state = 'no_state';
-		$data['output'] = '';
-
-		/*
-		 * Check, if Software-RAID is enabled
-		 */
-		if (file_exists('/proc/mdstat')) {
-			/*
-			 * Fetch the output
-			 */
-			$data['output'] = shell_exec('cat /proc/mdstat');
-
-			/*
-			 * Then calc the state.
-			 */
-			$tmp = explode("\n", $data['output']);
-			$state = 'ok';
-			for ($i = 0; $i < sizeof($tmp); $i++) {
-				/* fetch the next line */
-				$line = $tmp[$i];
-
-				if ((strpos($line, '[U_]') !== false) || (strpos($line, '[_U]') !== false)) {
-					/* One Disk is not working.
-					 * if the next line starts with "[>" or "[=" then
-					 * recovery (resync) is in state and the state is
-					 * information instead of critical
-					 */
-					$nextLine = $tmp[$i + 1];
-					if ((strpos($nextLine, '[>') === false) && (strpos($nextLine, '[=') === false)) {
-						$state = $this->_setState($state, 'critical');
-					} else {
-						$state = $this->_setState($state, 'info');
-					}
-				}
-				if (strpos($line, '[__]') !== false) {
-					/* both Disk are not working */
-					$state = $this->_setState($state, 'error');
-				}
-				if (strpos($line, '[UU]') !== false) {
-					/* The disks are OK.
-					 * if the next line starts with "[>" or "[=" then
-					 * recovery (resync) is in state and the state is
-					 * information instead of ok
-					 */
-					$nextLine = $tmp[$i + 1];
-					if ((strpos($nextLine, '[>') === false) && (strpos($nextLine, '[=') === false)) {
-						$state = $this->_setState($state, 'ok');
-					} else {
-						$state = $this->_setState($state, 'info');
-					}
-				}
-			}
-		}
-		/*
-		 * Check, if we have mpt-status installed (LSIsoftware-raid)
-		 */
-		if (file_exists('/proc/mpt/summary')) {
-			system('which mpt-status', $retval);
-			if ($retval === 0) {
-				/*
-				 * Fetch the output
-				 */
-				$data['output'] = shell_exec('mpt-status --autoload');
-
-				/*
-				 * Then calc the state.
-				 */
-				$state = 'ok';
-				if(is_array($data['output'])) {
-					foreach ($data['output'] as $item) {
-						/*
-						* The output contains information for every RAID and every HDD.
-						* We only need the state of the RAID
-						*/
-						if (strpos($item, 'state ') !== false) {
-							/*
-							* We found a raid, process the state of it
-							*/
-							if (strpos($item, ' ONLINE ') !== false) {
-								$this->_setState($state, 'ok');
-							} elseif (strpos($item, ' OPTIMAL ') !== false) {
-								$this->_setState($state, 'ok');
-							} elseif (strpos($item, ' INITIAL ') !== false) {
-								$this->_setState($state, 'info');
-							} elseif (strpos($item, ' INACTIVE ') !== false) {
-								$this->_setState($state, 'critical');
-							} elseif (strpos($item, ' RESYNC ') !== false) {
-								$this->_setState($state, 'info');
-							} elseif (strpos($item, ' DEGRADED ') !== false) {
-								$this->_setState($state, 'critical');
-							} else {
-								/* we don't know the state. so we set the state to critical, that the
-								* admin is warned, that something is wrong
-								*/
-								$this->_setState($state, 'critical');
-							}
-						}
-					}
-				}
-			}
-		}
-
-		/*
-		* 3ware Controller
-		*/
-		system('which tw_cli', $retval);
-		if($retval === 0) {
-
-			$data['output'] = shell_exec('tw_cli info c0');
-
-			$state = 'ok';
-			if(is_array($data['output'])) {
-			foreach ($data['output'] as $item) {
-				if (strpos($item, 'RAID') !== false) {
-					if (strpos($item, ' VERIFYING ') !== false) {
-						$this->_setState($state, 'info');
-					}
-					else if (strpos($item, ' MIGRATE-PAUSED ') !== false) {
-						$this->_setState($state, 'info');
-					}
-					else if (strpos($item, ' MIGRATING ') !== false) {
-						$this->_setState($state, 'ok');
-					}
-					else if (strpos($item, ' INITIALIZING ') !== false) {
-						$this->_setState($state, 'info');
-					}
-					else if (strpos($item, ' INIT-PAUSED ') !== false) {
-						$this->_setState($state, 'info');
-					}
-					else if (strpos($item, ' REBUILDING ') !== false) {
-						$this->_setState($state, 'info');
-					}
-					else if (strpos($item, ' REBUILD-PAUSED ') !== false) {
-						$this->_setState($state, 'warning');
-					}
-					else if (strpos($item, ' RECOVERY ') !== false) {
-						$this->_setState($state, 'warning');
-					}
-					else if (strpos($item, ' DEGRADED ') !== false) {
-						$this->_setState($state, 'critical');
-					}
-					else if (strpos($item, ' UNKNOWN ') !== false) {
-						$this->_setState($state, 'critical');
-					}
-					else if (strpos($item, ' OK ') !== false) {
-						$this->_setState($state, 'ok');
-					}
-					else if (strpos($item, ' OPTIMAL ') !== false) {
-						$this->_setState($state, 'ok');
-					}
-					else {
-						$this->_setState($state, 'critical');
-					}
-				}
-			}
-			}
-		}
-
-
-		/*
-		 * Return the Result
-		 */
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorRkHunter() {
-		global $conf;
-
-		/* the id of the server as int */
-		$server_id = intval($conf['server_id']);
-
-		/** The type of the data */
-		$type = 'rkhunter';
-
-		/* This monitoring is only available if rkhunter is installed */
-		system('which rkhunter', $retval);
-		if ($retval === 0) {
-			/*
-			 * Fetch the output
-			 */
-			$data['output'] = shell_exec('rkhunter --update --checkall --nocolors --skip-keypress');
-
-			/*
-			 * At this moment, there is no state (maybe later)
-			 */
-			$state = 'no_state';
-		} else {
-			/*
-			 * rkhunter is not installed, so there is no data and no state
-			 *
-			 * no_state, NOT unknown, because "unknown" is shown as state
-			 * inside the GUI. no_state is hidden.
-			 *
-			 * We have to write NO DATA inside the DB, because the GUI
-			 * could not know, if there is any dat, or not...
-			 */
-			$state = 'no_state';
-			$data['output'] = '';
-		}
-
-		/*
-		 * Return the Result
-		 */
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorFail2ban() {
-		global $conf;
-
-		/* the id of the server as int */
-		$server_id = intval($conf['server_id']);
-
-		/** The type of the data */
-		$type = 'log_fail2ban';
-
-		/* This monitoring is only available if fail2ban is installed */
-		system('which fail2ban-client', $retval); // Debian, Ubuntu, Fedora
-		if ($retval !== 0)
-			system('which fail2ban', $retval); // CentOS
-		if ($retval === 0) {
-			/*  Get the data of the log */
-			$data = $this->_getLogData($type);
-
-			/*
-			 * At this moment, there is no state (maybe later)
-			 */
-			$state = 'no_state';
-		} else {
-			/*
-			 * fail2ban is not installed, so there is no data and no state
-			 *
-			 * no_state, NOT unknown, because "unknown" is shown as state
-			 * inside the GUI. no_state is hidden.
-			 *
-			 * We have to write NO DATA inside the DB, because the GUI
-			 * could not know, if there is any dat, or not...
-			 */
-			$state = 'no_state';
-			$data = '';
-		}
-
-		/*
-		 * Return the Result
-		 */
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorMongoDB() {
-		global $conf;
-
-		/* the id of the server as int */
-		$server_id = intval($conf['server_id']);
-
-		/** The type of the data */
-		$type = 'log_mongodb';
-
-		/* This monitoring is only available if MongoDB is installed */
-		system('which mongod', $retval); // Debian, Ubuntu, Fedora
-		if ($retval !== 0)
-			system('which mongod', $retval); // CentOS
-		if ($retval === 0) {
-			/*  Get the data of the log */
-			$data = $this->_getLogData($type);
-
-			/*
-			 * At this moment, there is no state (maybe later)
-			 */
-			$state = 'no_state';
-		} else {
-			/*
-			 * MongoDB is not installed, so there is no data and no state
-			 *
-			 * no_state, NOT unknown, because "unknown" is shown as state
-			 * inside the GUI. no_state is hidden.
-			 *
-			 * We have to write NO DATA inside the DB, because the GUI
-			 * could not know, if there is any dat, or not...
-			 */
-			$state = 'no_state';
-			$data = '';
-		}
-
-		/*
-		 * Return the Result
-		 */
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorIPTables() {
-				global $conf;
-
-				/* the id of the server as int */
-				$server_id = intval($conf['server_id']);
-
-				/** The type of the data */
-				$type = 'iptables_rules';
-
-				/* This monitoring is only available if fail2ban is installed */
-				system('which iptables', $retval); // Debian, Ubuntu, Fedora
-				if ($retval === 0) {
-						/*  Get the data of the log */
-						$data['output'] = '<h2>iptables -S (ipv4)</h2>'.shell_exec('iptables -S 2>/dev/null');
-
-						/*
-						 * At this moment, there is no state (maybe later)
-						 */
-						$state = 'no_state';
-				} else {
-						$state = 'no_state';
-						$data = '';
-				}
-
-
-				/* This monitoring is only available if fail2ban is installed */
-				system('which ip6tables', $retval); // Debian, Ubuntu, Fedora
-				if ($retval === 0) {
-						/*  Get the data of the log */
-						$data['output'] .= '<br><h2>ip6tables -S (ipv6)</h2>'.shell_exec('ip6tables -S 2>/dev/null');
-
-						/*
-						 * At this moment, there is no state (maybe later)
-						 */
-						$state = 'no_state';
-				} else {
-						$state = 'no_state';
-						$data = '';
-				}
-
-				/*
-				 * Return the Result
-				 */
-				$res['server_id'] = $server_id;
-				$res['type'] = $type;
-				$res['data'] = $data;
-				$res['state'] = $state;
-				return $res;
-		}
-
-	public function monitorSysLog() {
+    // this function remains in the tools class, because it is used by cron AND rescue
+	public function monitorServices() {
 		global $app;
 		global $conf;
 
-		/* the id of the server as int */
+		/** the id of the server as int */
 		$server_id = intval($conf['server_id']);
 
-		/** The type of the data */
-		$type = 'sys_log';
-
+		/**  get the "active" Services of the server from the DB */
+		$services = $app->db->queryOneRecord('SELECT * FROM server WHERE server_id = ' . $server_id);
 		/*
-		 * is there any warning or error for this server?
+		 * If the DB is down, we have to set the db to "yes".
+		 * If we don't do this, then the monitor will NOT monitor, that the db is down and so the
+		 * rescue-module can not try to rescue the db
 		 */
-		$state = 'ok';
-		$dbData = $app->dbmaster->queryAllRecords('SELECT loglevel FROM sys_log WHERE server_id = ' . $server_id . ' AND loglevel > 0');
-		if (is_array($dbData)) {
-			foreach ($dbData as $item) {
-				if ($item['loglevel'] == 1)
-					$state = $this->_setState($state, 'warning');
-				if ($item['loglevel'] == 2)
-					$state = $this->_setState($state, 'error');
-			}
+		if ($services == null) {
+			$services['db_server'] = 1;
 		}
 
-		/** There is no monitor-data because the data is in the sys_log table */
-		$data['output'] = '';
-
-		/*
-		 * Return the Result
-		 */
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorMailLog() {
-		global $conf;
-
-		/* the id of the server as int */
-		$server_id = intval($conf['server_id']);
-
-		/** The type of the data */
-		$type = 'log_mail';
-
-		/* Get the data of the log */
-		$data = $this->_getLogData($type);
-
-		/*
-		 * actually this info has no state.
-		 * maybe someone knows better...???...
-		 */
-		$state = 'no_state';
-
-		/*
-		 * Return the Result
-		 */
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorMailWarnLog() {
-		global $conf;
-
-		/* the id of the server as int */
-		$server_id = intval($conf['server_id']);
-
-		/** The type of the data */
-		$type = 'log_mail_warn';
-
-		/* Get the data of the log */
-		$data = $this->_getLogData($type);
-
-		/*
-		 * actually this info has no state.
-		 * maybe someone knows better...???...
-		 */
-		$state = 'no_state';
-
-		/*
-		 * Return the Result
-		 */
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorMailErrLog() {
-		global $conf;
-
-		/* the id of the server as int */
-		$server_id = intval($conf['server_id']);
-
-		/** The type of the data */
-		$type = 'log_mail_err';
-
-		/* Get the data of the log */
-		$data = $this->_getLogData($type);
-
-		/*
-		 * actually this info has no state.
-		 * maybe someone knows better...???...
-		 */
-		$state = 'no_state';
-
-		/*
-		 * Return the Result
-		 */
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorMessagesLog() {
-		global $conf;
-
-		/* the id of the server as int */
-		$server_id = intval($conf['server_id']);
-
-		/** The type of the data */
-		$type = 'log_messages';
-
-		/* Get the data of the log */
-		$data = $this->_getLogData($type);
-
-		/*
-		 * actually this info has no state.
-		 * maybe someone knows better...???...
-		 */
-		$state = 'no_state';
-
-		/*
-		 * Return the Result
-		 */
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorISPCCronLog() {
-		global $conf;
-
-		/* the id of the server as int */
-		$server_id = intval($conf['server_id']);
-
-		/** The type of the data */
-		$type = 'log_ispc_cron';
-
-		/* Get the data of the log */
-		$data = $this->_getLogData($type);
-
-		/*
-		 * actually this info has no state.
-		 * maybe someone knows better...???...
-		 */
-		$state = 'no_state';
-
-		/*
-		 * Return the Result
-		 */
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorFreshClamLog() {
-		global $conf;
-
-		/* the id of the server as int */
-		$server_id = intval($conf['server_id']);
-
-		/** The type of the data */
-		$type = 'log_freshclam';
-
-		/* Get the data of the log */
-		$data = $this->_getLogData($type);
+		/* The type of the Monitor-data */
+		$type = 'services';
 
-		/* Get the data from the LAST log-Entry.
-		 * if there can be found:
-		 * WARNING: Your ClamAV installation is OUTDATED!
-		 * then the clamav is outdated. This is a warning!
+		/** the State of the monitoring */
+		/* ok, if ALL active services are running,
+		 * error, if not
+		 * There is no other state!
 		 */
 		$state = 'ok';
 
-		$tmp = explode("\n", $data);
-		$lastLog = array();
-		if ($tmp[sizeof($tmp) - 1] == '') {
-			/* the log ends with an empty line remove this */
-			array_pop($tmp);
-		}
-		if (strpos($tmp[sizeof($tmp) - 1], '-------------') !== false) {
-			/* the log ends with "-----..." remove this */
-			array_pop($tmp);
-		}
-		for ($i = sizeof($tmp) - 1; $i > 0; $i--) {
-			if (strpos($tmp[$i], '---------') === false) {
-				/* no delimiter found, so add this to the last-log */
-				$lastLog[] = $tmp[$i];
+		/* Monitor Webserver */
+		$data['webserver'] = -1; // unknown - not needed
+		if ($services['web_server'] == 1) {
+			if ($this->_checkTcp('localhost', 80)) {
+				$data['webserver'] = 1;
 			} else {
-				/* delimiter found, so there is no more line left! */
-				break;
+				$data['webserver'] = 0;
+				$state = 'error'; // because service is down
 			}
 		}
 
-		/*
-		 * Now we have the last log in the array.
-		 * Check if the outdated-string is found...
-		 */
-		foreach ($lastLog as $line) {
-			if (strpos(strtolower($line), 'outdated') !== false) {
-				/*
-				 * Outdatet is only info, because if we set this to warning, the server is
-				 * as long in state warning, as there is a new version of ClamAv which takes
-				 * sometimes weeks!
-				 */
-				$state = $this->_setState($state, 'info');
+		/* Monitor FTP-Server */
+		$data['ftpserver'] = -1; // unknown - not needed
+		if ($services['file_server'] == 1) {
+			if ($this->_checkFtp('localhost', 21)) {
+				$data['ftpserver'] = 1;
+			} else {
+				$data['ftpserver'] = 0;
+				$state = 'error'; // because service is down
 			}
 		}
 
-		/*
-		 * Return the Result
-		 */
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorClamAvLog() {
-		global $conf;
-
-		/* the id of the server as int */
-		$server_id = intval($conf['server_id']);
-
-		/** The type of the data */
-		$type = 'log_clamav';
-
-		/* Get the data of the log */
-		$data = $this->_getLogData($type);
-
-		// Todo: the state should be calculated.
-		$state = 'ok';
-
-		/*
-		 * Return the Result
-		 */
-		$res['server_id'] = $server_id;
-		$res['type'] = $type;
-		$res['data'] = $data;
-		$res['state'] = $state;
-		return $res;
-	}
-
-	public function monitorIspConfigLog() {
-		global $conf;
+		/* Monitor SMTP-Server */
+		$data['smtpserver'] = -1; // unknown - not needed
+		if ($services['mail_server'] == 1) {
+			if ($this->_checkTcp('localhost', 25)) {
+				$data['smtpserver'] = 1;
+			} else {
+				$data['smtpserver'] = 0;
+				$state = 'error'; // because service is down
+			}
+		}
 
-		/* the id of the server as int */
-		$server_id = intval($conf['server_id']);
+		/* Monitor POP3-Server */
+		$data['pop3server'] = -1; // unknown - not needed
+		if ($services['mail_server'] == 1) {
+			if ($this->_checkTcp('localhost', 110)) {
+				$data['pop3server'] = 1;
+			} else {
+				$data['pop3server'] = 0;
+				$state = 'error'; // because service is down
+			}
+		}
 
-		/** The type of the data */
-		$type = 'log_ispconfig';
+		/* Monitor IMAP-Server */
+		$data['imapserver'] = -1; // unknown - not needed
+		if ($services['mail_server'] == 1) {
+			if ($this->_checkTcp('localhost', 143)) {
+				$data['imapserver'] = 1;
+			} else {
+				$data['imapserver'] = 0;
+				$state = 'error'; // because service is down
+			}
+		}
 
-		/* Get the data of the log */
-		$data = $this->_getLogData($type);
+		/* Monitor BIND-Server */
+		$data['bindserver'] = -1; // unknown - not needed
+		if ($services['dns_server'] == 1) {
+			if ($this->_checkUdp('localhost', 53)) {
+				$data['bindserver'] = 1;
+			} else {
+				$data['bindserver'] = 0;
+				$state = 'error'; // because service is down
+			}
+		}
 
-		// Todo: the state should be calculated.
-		$state = 'ok';
+		/* Monitor MySQL Server */
+		$data['mysqlserver'] = -1; // unknown - not needed
+		if ($services['db_server'] == 1) {
+			if ($this->_checkTcp('localhost', 3306)) {
+				$data['mysqlserver'] = 1;
+			} else {
+				$data['mysqlserver'] = 0;
+				$state = 'error'; // because service is down
+			}
+		}
+        $data['mongodbserver'] = -1;
+        if ($this->_checkTcp('localhost', 27017)) {
+            $data['mongodbserver'] = 1;
+        } else {
+            $data['mongodbserver'] = 0;
+            //$state = 'error'; // because service is down 
+            /* TODO!!! check if this is a mongodbserver at all, otherwise it will always throw an error state!!! */
+        }
 
 		/*
 		 * Return the Result
@@ -1691,7 +349,7 @@ class monitor_tools {
 		$res['state'] = $state;
 		return $res;
 	}
-
+    
 	public function _getLogData($log) {
 		global $conf;
 
@@ -1915,7 +573,7 @@ class monitor_tools {
 	 * * If the actual state is critical and you call the method with error,
 	 *   then the state is error.
 	 */
-	private function _setState($oldState, $newState) {
+	public function _setState($oldState, $newState) {
 		/*
 		 * Calculate the weight of the old state
 		 */
@@ -1965,20 +623,38 @@ class monitor_tools {
 		}
 	}
 
-	private function _getIntArray($line) {
-		/** The array of float found */
-		$res = array();
-		/* First build a array from the line */
-		$data = explode(' ', $line);
-		/* then check if any item is a float */
-		foreach ($data as $item) {
-			if ($item . '' == (int) $item . '') {
-				$res[] = $item;
-			}
-		}
-		return $res;
+	/**
+	 * Deletes Records older than 4 minutes.
+	 * The monitor writes new data every 5 minutes or longer (4 hour, 1 day).
+	 * So if i delete all Date older than 4 minutes i can be sure, that all old data
+	 * are deleted...
+	 */
+	public function delOldRecords($type, $serverId) {
+		global $app;
+
+		// $now = time();
+		// $old = $now - (4 * 60); // 4 minutes
+		$old = 'UNIX_TIMESTAMP() - 240';
+
+		/*
+		 * ATTENTION if i do NOT pay attention of the server id, i delete all data (of the type)
+		 * of ALL servers. This means, if i have a multiserver-environment and a server has a
+		 * time not synced with the others (for example, all server has 11:00 and ONE server has
+		 * 10:45) then the actual data of this server (with the time-stamp 10:45) get lost
+		 * even though it is the NEWEST data of this server. To avoid this i HAVE to include
+		 * the server-id!
+		 */
+		$sql = 'DELETE FROM monitor_data ' .
+				'WHERE ' .
+				'  type =' . "'" . $app->dbmaster->quote($type) . "' " .
+				'AND ' .
+				'  created < ' . $old . ' ' .
+				'AND ' .
+				'  server_id = ' . $serverId;
+		$app->dbmaster->query($sql);
 	}
 
+
 }
 
 ?>
diff --git a/server/mods-available/monitor_core_module.inc.php b/server/mods-available/monitor_core_module.inc.php
deleted file mode 100644
index 88e994dccffc29567d6dba4e58ab7c03e5b58db0..0000000000000000000000000000000000000000
--- a/server/mods-available/monitor_core_module.inc.php
+++ /dev/null
@@ -1,870 +0,0 @@
-<?php
-
-/*
-  Copyright (c) 2007-2011, Till Brehm, projektfarm Gmbh and Oliver Vogel www.muv.com
-  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 monitor_core_module {
-
-	var $interval = 5; // do the monitoring every 5 minutes
-	var $module_name = 'monitor_core_module';
-	var $class_name = 'monitor_core_module';
-	/* No actions at this time. maybe later... */
-	var $actions_available = array();
-	/** The Tools */
-	private $_tools = null;
-    //** time the script was called
-    private $_run_time = null;
-
-	/**
-	 * This function is called during ispconfig installation to determine
-	 * if a symlink shall be created for this plugin.
-	 */
-	public function onInstall() {
-		global $conf;
-		return true;
-	}
-
-	/**
-	 * This function is called when the module is loaded
-	 */
-	public function onLoad() {
-		global $app;
-        
-        //* store the running time
-        $this->_run_time = time();
-        
-		/*
-		 * Do the monitor every n minutes and write the result to the db
-		 */
-		$min = @date('i', $this->_run_time);
-		if (($min % $this->interval) == 0) {
-			$this->_doMonitor();
-		}
-	}
-
-	/**
-	 * This function is called when a change in one of the registered tables is detected.
-	 * The function then raises the events for the plugins.
-	 */
-	public function process($tablename, $action, $data) {
-		// not needed
-	}
-
-	/**
-	 * This method is called every n minutes, when the module ist loaded.
-	 * The method then does a system-monitoring
-	 */
-	// TODO: what monitoring is done should be a config-var
-	private function _doMonitor() {
-		global $app;
-		/*
-		 * We need the tools in almost every method, so initialize them once...
-		 */
-		$app->load('monitor_tools');
-		$this->_tools = new monitor_tools();
-
-		/*
-		 * Calls the single Monitoring steps
-		 */
-		$this->_monitorEmailQuota();
-		$this->_monitorHDQuota();
-		$this->_monitorServer();
-		$this->_monitorOsVer();
-		$this->_monitorIspcVer();
-		$this->_monitorDiskUsage();
-		$this->_monitorMemUsage();
-		$this->_monitorCpu();
-		$this->_monitorServices();
-		if (@file_exists('/proc/user_beancounters')) {
-			$this->_monitorOpenVzHost();
-			$this->_monitorOpenVzUserBeancounter();
-		}
-		$this->_monitorMailLog();
-		$this->_monitorMailWarnLog();
-		$this->_monitorMailErrLog();
-		$this->_monitorMessagesLog();
-		$this->_monitorISPCCronLog();
-		$this->_monitorFreshClamLog();
-		$this->_monitorClamAvLog();
-		$this->_monitorIspConfigLog();
-		$this->_monitorSystemUpdate();
-		$this->_monitorMailQueue();
-		$this->_monitorRaid();
-		$this->_monitorRkHunter();
-		$this->_monitorFail2ban();
-		$this->_monitorMongoDB();
-		$this->_monitorIPTables();
-		$this->_monitorSysLog();
-	}
-
-    private function _monitorEmailQuota() {
-        global $app, $conf;
-
-        /*
-		 *  This monitoring is expensive, so do it only every 15 minutes
-		 */
-		$min = @date('i', $this->_run_time);
-		if ($min % 15 != 0) return;
-
-		$app->uses('getconf');
-		$mail_config = $app->getconf->get_server_config($conf['server_id'], 'mail');
-		if($mail_config['mailbox_quota_stats'] == 'n') return;
-
-
-		/*
-         * First we get the Monitoring-data from the tools
-         */
-        $res = $this->_tools->monitorEmailQuota();
-
-        /*
-         * Insert the data into the database
-         */
-        $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-                'VALUES (' .
-                $res['server_id'] . ', ' .
-                "'" . $app->dbmaster->quote($res['type']) . "', " .
-                'UNIX_TIMESTAMP(), ' .
-                "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-                "'" . $res['state'] . "'" .
-                ')';
-        $app->dbmaster->query($sql);
-
-        /* The new data is written, now we can delete the old one */
-        $this->_delOldRecords($res['type'], $res['server_id']);
-    }
-
-	private function _monitorHDQuota() {
-		global $app;
-
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorHDQuota();
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	private function _monitorServer() {
-		global $app;
-
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorServer();
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	private function _monitorOsVer() {
-		global $app;
-
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorOsVer();
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	private function _monitorIspcVer() {
-		global $app;
-
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorIspcVer();
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	private function _monitorDiskUsage() {
-		global $app;
-
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorDiskUsage();
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	private function _monitorMemUsage() {
-		global $app;
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorMemUsage();
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	private function _monitorCpu() {
-		global $app;
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorCpu();
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	private function _monitorServices() {
-		global $app;
-
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorServices();
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	private function _monitorOpenVzHost() {
-		global $app;
-
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorOpenVzHost();
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	private function _monitorOpenVzUserBeancounter() {
-		global $app;
-
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorOpenVzUserBeancounter();
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	private function _monitorSystemUpdate() {
-		/*
-		 *  This monitoring is expensive, so do it only once an hour
-		 */
-		$min = @date('i', $this->_run_time);
-		if ($min != 0)
-			return;
-
-		/*
-		 * OK - here we go...
-		 */
-		global $app;
-
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorSystemUpdate();
-
-		//* Ensure that output is encoded so that it does not break the serialize
-		//$res['data']['output'] = htmlentities($res['data']['output']);
-		$res['data']['output'] = htmlentities($res['data']['output'],ENT_QUOTES,'UTF-8');
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	private function _monitorMailQueue() {
-		global $app;
-
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorMailQueue();
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	private function _monitorRaid() {
-		global $app;
-
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorRaid();
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	private function _monitorRkHunter() {
-		/*
-		 *  This monitoring is expensive, so do it only once a day
-		 */
-		$min = @date('i', $this->_run_time);
-		$hour = @date('H', $this->_run_time);
-		if (!($min == 0 && $hour == 23))
-			return;
-		/*
-		 * OK . here we go...
-		 */
-		global $app;
-
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorRkHunter();
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	private function _monitorFail2ban() {
-        global $app;
-
-        /*
-         * First we get the Monitoring-data from the tools
-         */
-        $res = $this->_tools->monitorFail2ban();
-
-        /*
-         * Insert the data into the database
-         */
-        $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-                'VALUES (' .
-                $res['server_id'] . ', ' .
-                "'" . $app->dbmaster->quote($res['type']) . "', " .
-                'UNIX_TIMESTAMP(), ' .
-                "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-                "'" . $res['state'] . "'" .
-                ')';
-        $app->dbmaster->query($sql);
-
-        /* The new data is written, now we can delete the old one */
-        $this->_delOldRecords($res['type'], $res['server_id']);
-    }
-
-	private function _monitorMongoDB() {
-	global $app;
-
-        /*
-         * First we get the Monitoring-data from the tools
-         */
-        $res = $this->_tools->monitorMongoDB();
-
-        /*
-         * Insert the data into the database
-         */
-        $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-                'VALUES (' .
-                $res['server_id'] . ', ' .
-                "'" . $app->dbmaster->quote($res['type']) . "', " .
-                'UNIX_TIMESTAMP(), ' .
-                "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-                "'" . $res['state'] . "'" .
-                ')';
-        $app->dbmaster->query($sql);
-
-        /* The new data is written, now we can delete the old one */
-        $this->_delOldRecords($res['type'], $res['server_id']);
-    }
-
-
-	private function _monitorIPTables() {
-		global $app;
-
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorIPTables();
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	private function _monitorSysLog() {
-		global $app;
-
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorSysLog();
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	private function _monitorMailLog() {
-		global $app;
-
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorMailLog();
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	private function _monitorMailWarnLog() {
-		global $app;
-
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorMailWarnLog();
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	private function _monitorMailErrLog() {
-		global $app;
-
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorMailErrLog();
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	private function _monitorMessagesLog() {
-		global $app;
-
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorMessagesLog();
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	private function _monitorISPCCronLog() {
-		global $app;
-
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorISPCCronLog();
-
-		//* Ensure that output is encoded so that it does not break the serialize
-		if(is_array($res) && isset($res['data'])) $res['data'] = htmlentities($res['data']);
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	private function _monitorFreshClamLog() {
-		global $app;
-
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorFreshClamLog();
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	private function _monitorClamAvLog() {
-		global $app;
-
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorClamAvLog();
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	private function _monitorIspConfigLog() {
-		global $app;
-
-		/*
-		 * First we get the Monitoring-data from the tools
-		 */
-		$res = $this->_tools->monitorIspConfigLog();
-
-		/*
-		 * Insert the data into the database
-		 */
-		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
-				'VALUES (' .
-				$res['server_id'] . ', ' .
-				"'" . $app->dbmaster->quote($res['type']) . "', " .
-				'UNIX_TIMESTAMP(), ' .
-				"'" . $app->dbmaster->quote(serialize($res['data'])) . "', " .
-				"'" . $res['state'] . "'" .
-				')';
-		$app->dbmaster->query($sql);
-
-		/* The new data is written, now we can delete the old one */
-		$this->_delOldRecords($res['type'], $res['server_id']);
-	}
-
-	/**
-	 * Deletes Records older than 4 minutes.
-	 * The monitor writes new data every 5 minutes or longer (4 hour, 1 day).
-	 * So if i delete all Date older than 4 minutes i can be sure, that all old data
-	 * are deleted...
-	 */
-	private function _delOldRecords($type, $serverId) {
-		global $app;
-
-		// $now = time();
-		// $old = $now - (4 * 60); // 4 minutes
-		$old = 'UNIX_TIMESTAMP() - 240';
-
-		/*
-		 * ATTENTION if i do NOT pay attention of the server id, i delete all data (of the type)
-		 * of ALL servers. This means, if i have a multiserver-environment and a server has a
-		 * time not synced with the others (for example, all server has 11:00 and ONE server has
-		 * 10:45) then the actual data of this server (with the time-stamp 10:45) get lost
-		 * even though it is the NEWEST data of this server. To avoid this i HAVE to include
-		 * the server-id!
-		 */
-		$sql = 'DELETE FROM monitor_data ' .
-				'WHERE ' .
-				'  type =' . "'" . $app->dbmaster->quote($type) . "' " .
-				'AND ' .
-				'  created < ' . $old . ' ' .
-				'AND ' .
-				'  server_id = ' . $serverId;
-		$app->dbmaster->query($sql);
-	}
-
-}
-
-?>