mcramer
2009-06-23 0b0dc90a467c21513010d62af74a03c952652769
Added: Cron Jobs for clients (url, chrooted, full)
Fixed: Missing server.ini config entries for vlogger and jailkit
Added: Admin interface server_config for vlogger and cron
17 files added
23 files modified
1996 ■■■■■ changed files
install/dist/conf/centos52.conf.php 6 ●●●●● patch | view | raw | blame | history
install/dist/conf/centos53.conf.php 6 ●●●●● patch | view | raw | blame | history
install/dist/conf/debian40.conf.php 6 ●●●●● patch | view | raw | blame | history
install/dist/conf/fedora9.conf.php 6 ●●●●● patch | view | raw | blame | history
install/dist/conf/gentoo.conf.php 6 ●●●●● patch | view | raw | blame | history
install/dist/conf/opensuse110.conf.php 5 ●●●●● patch | view | raw | blame | history
install/lib/installer_base.lib.php 3 ●●●● patch | view | raw | blame | history
install/sql/ispconfig3.sql 33 ●●●●● patch | view | raw | blame | history
install/tpl/server.ini.master 9 ●●●●● patch | view | raw | blame | history
interface/lib/classes/validate_cron.inc.php 191 ●●●●● patch | view | raw | blame | history
interface/web/admin/form/server_config.tform.php 82 ●●●●● patch | view | raw | blame | history
interface/web/admin/lib/lang/de_server_config.lng 5 ●●●●● patch | view | raw | blame | history
interface/web/admin/lib/lang/en_server_config.lng 5 ●●●●● patch | view | raw | blame | history
interface/web/admin/templates/server_config_cron_edit.htm 30 ●●●●● patch | view | raw | blame | history
interface/web/admin/templates/server_config_jailkit_edit.htm 4 ●●●● patch | view | raw | blame | history
interface/web/admin/templates/server_config_vlogger_edit.htm 22 ●●●●● patch | view | raw | blame | history
interface/web/client/form/client.tform.php 34 ●●●●● patch | view | raw | blame | history
interface/web/client/form/client_template.tform.php 34 ●●●●● patch | view | raw | blame | history
interface/web/client/lib/lang/de_client.lng 5 ●●●●● patch | view | raw | blame | history
interface/web/client/lib/lang/de_client_template.lng 5 ●●●●● patch | view | raw | blame | history
interface/web/client/lib/lang/en_client.lng 5 ●●●●● patch | view | raw | blame | history
interface/web/client/lib/lang/en_client_template.lng 5 ●●●●● patch | view | raw | blame | history
interface/web/client/templates/client_edit_limits.htm 14 ●●●●● patch | view | raw | blame | history
interface/web/client/templates/client_template_edit_limits.htm 14 ●●●●● patch | view | raw | blame | history
interface/web/sites/cron_del.php 64 ●●●●● patch | view | raw | blame | history
interface/web/sites/cron_edit.php 226 ●●●●● patch | view | raw | blame | history
interface/web/sites/cron_list.php 23 ●●●●● patch | view | raw | blame | history
interface/web/sites/form/cron.tform.php 189 ●●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/de_cron.lng 21 ●●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/de_cron_list.lng 12 ●●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/en_cron.lng 21 ●●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/en_cron_list.lng 12 ●●●●● patch | view | raw | blame | history
interface/web/sites/lib/module.conf.php 15 ●●●●● patch | view | raw | blame | history
interface/web/sites/list/cron.list.php 152 ●●●●● patch | view | raw | blame | history
interface/web/sites/templates/cron_edit.htm 68 ●●●●● patch | view | raw | blame | history
interface/web/sites/templates/cron_list.htm 71 ●●●●● patch | view | raw | blame | history
interface/web/sites/web_domain_del.php 6 ●●●●● patch | view | raw | blame | history
server/mods-available/cron_module.inc.php 97 ●●●●● patch | view | raw | blame | history
server/plugins-available/cron_jailkit_plugin.inc.php 272 ●●●●● patch | view | raw | blame | history
server/plugins-available/cron_plugin.inc.php 212 ●●●●● patch | view | raw | blame | history
install/dist/conf/centos52.conf.php
@@ -147,8 +147,14 @@
$conf['jailkit']['jk_init'] = 'jk_init.ini';
$conf['jailkit']['jk_chrootsh'] = 'jk_chrootsh.ini';
$conf['jailkit']['jailkit_chroot_app_programs'] = '/usr/bin/groups /usr/bin/id /usr/bin/dircolors /bin/basename /usr/bin/dirname /usr/bin/nano';
$conf['jailkit']['jailkit_chroot_cron_programs'] = '/usr/bin/php /usr/bin/perl /usr/share/perl /usr/share/php';
//* vlogger
$conf['vlogger']['config_dir'] = '/etc';
//* cron
$conf['cron']['init_script'] = 'crond';
$conf['cron']['crontab_dir'] = '/etc/cron.d';
$conf['cron']['wget'] = '/usr/bin/wget';
?>
install/dist/conf/centos53.conf.php
@@ -147,8 +147,14 @@
$conf['jailkit']['jk_init'] = 'jk_init.ini';
$conf['jailkit']['jk_chrootsh'] = 'jk_chrootsh.ini';
$conf['jailkit']['jailkit_chroot_app_programs'] = '/usr/bin/groups /usr/bin/id /usr/bin/dircolors /bin/basename /usr/bin/dirname /usr/bin/nano';
$conf['jailkit']['jailkit_chroot_cron_programs'] = '/usr/bin/php /usr/bin/perl /usr/share/perl /usr/share/php';
//* vlogger
$conf['vlogger']['config_dir'] = '/etc';
//* cron
$conf['cron']['init_script'] = 'crond';
$conf['cron']['crontab_dir'] = '/etc/cron.d';
$conf['cron']['wget'] = '/usr/bin/wget';
?>
install/dist/conf/debian40.conf.php
@@ -147,8 +147,14 @@
$conf['jailkit']['jk_init'] = 'jk_init.ini';
$conf['jailkit']['jk_chrootsh'] = 'jk_chrootsh.ini';
$conf['jailkit']['jailkit_chroot_app_programs'] = '/usr/bin/groups /usr/bin/id /usr/bin/dircolors /usr/bin/lesspipe /usr/bin/basename /usr/bin/dirname /usr/bin/nano /usr/bin/pico';
$conf['jailkit']['jailkit_chroot_cron_programs'] = '/usr/bin/php /usr/bin/perl /usr/share/perl /usr/share/php';
//* vlogger
$conf['vlogger']['config_dir'] = '/etc';
//* cron
$conf['cron']['init_script'] = 'cron';
$conf['cron']['crontab_dir'] = '/etc/cron.d';
$conf['cron']['wget'] = '/usr/bin/wget';
?>
install/dist/conf/fedora9.conf.php
@@ -147,8 +147,14 @@
$conf['jailkit']['jk_init'] = 'jk_init.ini';
$conf['jailkit']['jk_chrootsh'] = 'jk_chrootsh.ini';
$conf['jailkit']['jailkit_chroot_app_programs'] = '/usr/bin/groups /usr/bin/id /usr/bin/dircolors /bin/basename /usr/bin/dirname /usr/bin/nano';
$conf['jailkit']['jailkit_chroot_cron_programs'] = '/usr/bin/php /usr/bin/perl /usr/share/perl /usr/share/php';
//* vlogger
$conf['vlogger']['config_dir'] = '/etc';
//* cron
$conf['cron']['init_script'] = 'crond';
$conf['cron']['crontab_dir'] = '/etc/cron.d';
$conf['cron']['wget'] = '/usr/bin/wget';
?>
install/dist/conf/gentoo.conf.php
@@ -96,8 +96,14 @@
$conf['jailkit']['jk_init'] = 'jk_init.ini';
$conf['jailkit']['jk_chrootsh'] = 'jk_chrootsh.ini';
$conf['jailkit']['jailkit_chroot_app_programs'] = '/usr/bin/groups /usr/bin/id /usr/bin/dircolors /usr/bin/lesspipe /usr/bin/basename /usr/bin/dirname /usr/bin/nano /usr/bin/pico';
$conf['jailkit']['jailkit_chroot_cron_programs'] = '/usr/bin/php /usr/bin/perl /usr/share/perl /usr/share/php';
//* vlogger
$conf['vlogger']['config_dir'] = '/etc';
//* cron
$conf['cron']['init_script'] = 'cron';
$conf['cron']['crontab_dir'] = '/etc/cron.d';
$conf['cron']['wget'] = '/usr/bin/wget';
?>
install/dist/conf/opensuse110.conf.php
@@ -147,9 +147,14 @@
$conf['jailkit']['jk_init'] = 'jk_init.ini';
$conf['jailkit']['jk_chrootsh'] = 'jk_chrootsh.ini';
$conf['jailkit']['jailkit_chroot_app_programs'] = '/usr/bin/groups /usr/bin/id /usr/bin/dircolors /usr/bin/basename /usr/bin/dirname /usr/bin/nano /usr/bin/pico';
$conf['jailkit']['jailkit_chroot_cron_programs'] = '/usr/bin/php /usr/bin/perl /usr/share/perl /usr/share/php';
//* vlogger
$conf['vlogger']['config_dir'] = '/etc';
//* cron
$conf['cron']['init_script'] = 'cron';
$conf['cron']['crontab_dir'] = '/etc/cron.d';
$conf['cron']['wget'] = '/usr/bin/wget';
?>
install/lib/installer_base.lib.php
@@ -210,7 +210,8 @@
        $tpl_ini_array['web']['website_basedir'] = $conf['web']['website_basedir'];
        $tpl_ini_array['web']['website_path'] = $conf['web']['website_path'];
        $tpl_ini_array['web']['website_symlinks'] = $conf['web']['website_symlinks'];
        $tpl_ini_array['cron']['crontab_dir'] = $conf['cron']['crontab_dir'];
        $server_ini_content = array_to_ini($tpl_ini_array);
        $server_ini_content = mysql_real_escape_string($server_ini_content);
        
install/sql/ispconfig3.sql
@@ -92,6 +92,9 @@
  `limit_dns_record` int(11) NOT NULL default '-1',
  `default_dbserver` int(11) NOT NULL default '1',
  `limit_database` int(11) NOT NULL default '-1',
  `limit_cron` int(11) NOT NULL default '0',
  `limit_cron_type` enum('url','chrooted','full') NOT NULL default 'url',
  `limit_cron_frequency` int(11) NOT NULL default '5',
  `limit_client` int(11) NOT NULL default '0',
  `parent_client_id` int(11) unsigned NOT NULL default '0',
  `username` varchar(64) default NULL,
@@ -140,10 +143,40 @@
  `limit_dns_zone` int(11) NOT NULL default '-1',
  `limit_dns_record` int(11) NOT NULL default '-1',
  `limit_database` int(11) NOT NULL default '-1',
  `limit_cron` int(11) NOT NULL default '0',
  `limit_cron_type` enum('url','chrooted','full') NOT NULL default 'url',
  `limit_cron_frequency` int(11) NOT NULL default '5',
  `limit_client` int(11) NOT NULL default '0',
  PRIMARY KEY  (`template_id`)
) ENGINE=MyISAM AUTO_INCREMENT=1;
-- --------------------------------------------------------
--
-- Table structure for table  `dns_rr`
--
CREATE TABLE `cron` (
  `id` int(11) unsigned NOT NULL auto_increment,
  `sys_userid` int(11) unsigned NOT NULL default '0',
  `sys_groupid` int(11) unsigned NOT NULL default '0',
  `sys_perm_user` varchar(5) NULL default NULL,
  `sys_perm_group` varchar(5) NULL default NULL,
  `sys_perm_other` varchar(5) NULL default NULL,
  `server_id` int(11) unsigned NOT NULL default '0',
  `parent_domain_id` int(11) unsigned NOT NULL default '0',
  `type` enum('url','chrooted','full') NOT NULL default 'url',
  `command` varchar(255) NOT NULL,
  `run_min` varchar(100) NULL,
  `run_hour` varchar(100) NULL,
  `run_mday` varchar(100) NULL,
  `run_month` varchar(100) NULL,
  `run_wday` varchar(100) NULL,
  `active` enum('n','y') NOT NULL default 'y',
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  AUTO_INCREMENT=1;
-- --------------------------------------------------------
-- 
install/tpl/server.ini.master
@@ -48,3 +48,12 @@
jailkit_chroot_home=/home/[username]
jailkit_chroot_app_sections=basicshell editors extendedshell netutils ssh sftp scp groups jk_lsh
jailkit_chroot_app_programs=/usr/bin/groups /usr/bin/id /usr/bin/dircolors /usr/bin/lesspipe /usr/bin/basename /usr/bin/dirname /usr/bin/nano /usr/bin/pico
jailkit_chroot_cron_programs=/usr/bin/php /usr/bin/perl /usr/share/perl /usr/share/php
[vlogger]
config_dir=/etc
[cron]
init_script=cron
crontab_dir=/etc/cron.d
wget=/usr/bin/wget
interface/lib/classes/validate_cron.inc.php
New file
@@ -0,0 +1,191 @@
<?php
/*
Copyright (c) 2007, Till Brehm, projektfarm Gmbh
Modified 2009, 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 validate_cron {
    function get_error($errmsg) {
        global $app;
        if(isset($app->tform->wordbook[$errmsg])) {
            return $app->tform->wordbook[$errmsg]."<br>\r\n";
        } else {
            return $errmsg."<br>\r\n";
        }
    }
    /*
        Validator function to check if a given cron command is in correct form (url only).
    */
    function command_format($field_name, $field_value, $validator) {
        if(preg_match("'^(\w+):\/\/'", $field_value, $matches)) {
            $parsed = parse_url($field_value);
            if($parsed === false) return $this->get_error($validator['errmsg']);
            if($parsed["scheme"] != "http" && $parsed["scheme"] != "https") return $this->get_error($validator['errmsg']);
            if(preg_match("'^([a-z0-9][a-z0-9-]{0,62}\.)+([a-z]{2,4})$'i", $parsed["host"]) == false) return $this->get_error($validator['errmsg']);
        }
    }
    /*
        Validator function to check if a given cron time is in correct form.
    */
    function run_time_format($field_name, $field_value, $validator) {
        global $app;
        //* check general form
        $is_ok = true;
        $field_value = str_replace(" ", "", $field_value); // spaces are not needed
        $used_times = array();
        if(preg_match("'^[0-9\-\,\/\*]+$'", $field_value) == false) return $this->get_error($validator['errmsg']); // allowed characters are 0-9, comma, *, -, /
        elseif(preg_match("'[\-\,\/][\-\,\/]'", $field_value) == true) return $this->get_error($validator['errmsg']); // comma, - and / never stand together
        //* now split list and check each entry. store used values in array for later limit-check
        $time_list = split(",", $field_value);
        if(count($time_list) < 1) return $this->get_error($validator['errmsg']);
        $max_entry = 0;
        $min_entry = 0;
        $in_minutes = 1;
        //* get maximum value of entry for each field type (name)
        switch($field_name) {
            case "run_min":
                $max_entry = 59;
                break;
            case "run_hour":
                $max_entry = 23;
                $in_minutes = 60;
                break;
            case "run_mday":
                $max_entry = 31;
                $min_entry = 1;
                $in_minutes = 1440;
                break;
            case "run_month":
                $max_entry = 12;
                $min_entry = 1;
                $in_minutes = 1440 * 28; // not exactly but enough
                break;
            case "run_wday":
                $max_entry = 7;
                $in_minutes = 1440;
                break;
        }
        if($max_entry == 0) return $this->get_error('unknown_fieldtype_error');
        foreach($time_list as $entry) {
            //* possible value combinations:
            //* x               =>      ^(\d+)$
            //* x-y             =>      ^(\d+)\-(\d+)$
            //* x/y             =>      ^(\d+)\/([1-9]\d*)$
            //* x-y/z           =>      ^(\d+)\-(\d+)\/([1-9]\d*)$
            //* */x             =>      ^\*\/([1-9]\d*)$
            //* combined regex  =>      ^(\d+|\*)(\-(\d+))?(\/([1-9]\d*))?$
            if(preg_match("'^(((\d+)(\-(\d+))?)|\*)(\/([1-9]\d*))?$'", $entry, $matches) == false) {
                return $this->get_error($validator['errmsg']);
            }
            //* matches contains:
            //* 1       =>      * or value or x-y range
            //* 2       =>      unused
            //* 3       =>      value if [1] != *
            //* 4       =>      empty if no range was used
            //* 5       =>      2nd value of range if [1] != * and range was used
            //* 6       =>      empty if step was not used
            //* 7       =>      step
            $loop_step = 1;
            $loop_from = $min_entry;
            $loop_to = $max_entry;
            //* calculate used values
            if($matches[1] == "*") {
                //* not to check
            } else {
                if($matches[3] < $min_entry || $matches[3] > $max_entry) {
                    //* check if value is in allowed range
                    return $this->get_error($validator['errmsg']);
                } elseif($matches[4] && ($matches[5] < $min_entry || $matches[5] > $max_entry || $matches[5] <= $matches[3])) {
                    //* check if value is in allowed range and not less or equal to first value
                    return $this->get_error($validator['errmsg']);
                }
                $loop_from = $matches[3];
                $loop_to = $matches[3];
                if($matches[4]) $loop_to = $matches[5];
            }
            if($matches[6] && ($matches[7] < 2 || $matches[7] > $max_entry - 1)) {
                //* check if step value is valid
                return $this->get_error($validator['errmsg']);
            }
            if($matches[7]) $loop_step = $matches[7];
            //* loop through values to set used times
            for($t = $loop_from; $t <= $loop_to; $t = $t + $loop_step) {
                $used_times[] = $t;
            }
        } //* end foreach entry loop
        //* sort used times and erase doubles
        sort($used_times);
        $used_times = array_unique($used_times);
        //* get minimum frequency and store it in $app->tform->cron_min_freq for usage in onUpdateSave and onInsertSave!
        $min_freq = -1;
        $prev_time = -1;
        foreach($used_times as $curtime) {
            if($prev_time != -1) {
                $freq = $curtime - $prev_time;
                if($min_freq == -1 || $freq < $min_freq) $min_freq = $freq;
            }
            $prev_time = $curtime;
        }
        //* check last against first (needed because e.g. wday 1,4,7 has diff 1 not 3
        $prev_time = $used_times[0];
        $freq = ($prev_time - $min_entry) + ($max_entry - $curtime) + 1;
        if($min_freq == -1 || $freq < $min_freq) $min_freq = $freq;
        if($min_freq > 0 && $min_freq <= $max_entry) { //* only store if > 1 && < $max_entry!
            $min_freq = $min_freq * $in_minutes; // we have to overwrite $app->tform->cron_min_freq if this is higher value
            if(!$app->tform->cron_min_freq || $app->tform->cron_min_freq > $min_freq) $app->tform->cron_min_freq = $min_freq;
        }
        //return "DEBUG: " . $app->tform->cron_min_freq . " ($min_freq) --- " . var_export($used_times, true) . "<br />";
    }
}
interface/web/admin/form/server_config.tform.php
@@ -478,6 +478,17 @@
            'width'        => '40',
            'maxlength'    => '1000'
        ),
        'jailkit_chroot_cron_programs' => array (
            'datatype'  => 'VARCHAR',
            'formtype'  => 'TEXT',
            'default'   => '',
            'validators'    => array (  0 => array (    'type'  => 'NOTEMPTY',
                                                        'errmsg'=> 'jailkit_chroot_cron_programs_error_empty'),
                                    ),
            'value'     => '',
            'width'     => '40',
            'maxlength' => '1000'
        ),
    ##################################
    # ENDE Datatable fields
    ##################################
@@ -485,10 +496,79 @@
);
$form["tabs"]['vlogger'] = array (
    'title'     => "vlogger",
    'width'     => 80,
    'template'  => "templates/server_config_vlogger_edit.htm",
    'fields'    => array (
    ##################################
    # Begin Datatable fields
    ##################################
        'config_dir' => array (
            'datatype'  => 'VARCHAR',
            'formtype'  => 'TEXT',
            'default'   => '',
            'validators'    => array (  0 => array (    'type'  => 'NOTEMPTY',
                                                        'errmsg'=> 'vlogger_config_dir_error_empty'),
                                    ),
            'value'     => '',
            'width'     => '40',
            'maxlength' => '255'
        ),
    ##################################
    # ENDE Datatable fields
    ##################################
    )
);
$form["tabs"]['cron'] = array (
    'title'     => "Cron",
    'width'     => 80,
    'template'  => "templates/server_config_cron_edit.htm",
    'fields'    => array (
    ##################################
    # Begin Datatable fields
    ##################################
        'init_script' => array (
            'datatype'  => 'VARCHAR',
            'formtype'  => 'TEXT',
            'default'   => '',
            'validators'    => array (  0 => array (    'type'  => 'NOTEMPTY',
                                                        'errmsg'=> 'cron_init_script_error_empty'),
                                    ),
            'value'     => '',
            'width'     => '40',
            'maxlength' => '255'
        ),
        'crontab_dir' => array (
            'datatype'  => 'VARCHAR',
            'formtype'  => 'TEXT',
            'default'   => '',
            'validators'    => array (  0 => array (    'type'  => 'NOTEMPTY',
                                                        'errmsg'=> 'crontab_dir_error_empty'),
                                    ),
            'value'     => '',
            'width'     => '40',
            'maxlength' => '255'
        ),
        'wget' => array (
            'datatype'  => 'VARCHAR',
            'formtype'  => 'TEXT',
            'default'   => '',
            'validators'    => array (  0 => array (    'type'  => 'NOTEMPTY',
                                                        'errmsg'=> 'cron_wget_error_empty'),
                                    ),
            'value'     => '',
            'width'     => '40',
            'maxlength' => '255'
        ),
    ##################################
    # ENDE Datatable fields
    ##################################
    )
);
interface/web/admin/lib/lang/de_server_config.lng
@@ -2,6 +2,7 @@
$wb['jailkit_chroot_home_txt'] = 'Jailkit chroot home';
$wb['jailkit_chroot_app_sections_txt'] = 'Jailkit chroot app sections';
$wb['jailkit_chroot_app_programs_txt'] = 'Jailkit chrooted applications';
$wb['jailkit_chroot_cron_programs_txt'] = 'Jailkit cron chrooted applications';
$wb['website_path_txt'] = 'Website path';
$wb['website_symlinks_txt'] = 'Website symlinks';
$wb['vhost_conf_dir_txt'] = 'Vhost config dir';
@@ -38,4 +39,8 @@
$wb['gateway_error_wrong'] = 'Invalid Gateway format.';
$wb['hostname_error_empty'] = 'Hostname is empty.';
$wb['nameservers_error_empty'] = 'Nameserver is empty.';
$wb["config_dir_txt"] = 'Config directory';
$wb["init_script_txt"] = 'Cron init script name';
$wb["crontab_dir_txt"] = 'Path for individual crontabs';
$wb["wget_txt"] = 'Path to wget program';
?>
interface/web/admin/lib/lang/en_server_config.lng
@@ -2,6 +2,7 @@
$wb["jailkit_chroot_home_txt"] = 'Jailkit chroot home';
$wb["jailkit_chroot_app_sections_txt"] = 'Jailkit chroot app sections';
$wb["jailkit_chroot_app_programs_txt"] = 'Jailkit chrooted applications';
$wb['jailkit_chroot_cron_programs_txt'] = 'Jailkit cron chrooted applications';
$wb["website_path_txt"] = 'Website path';
$wb["website_symlinks_txt"] = 'Website symlinks';
$wb["website_basedir_txt"] = 'Website basedir';
@@ -38,4 +39,8 @@
$wb["gateway_error_wrong"] = 'Invalid Gateway format.';
$wb["hostname_error_empty"] = 'Hostname is empty.';
$wb["nameservers_error_empty"] = 'Nameserver is empty.';
$wb["config_dir_txt"] = 'Config directory';
$wb["init_script_txt"] = 'Cron init script name';
$wb["crontab_dir_txt"] = 'Path for individual crontabs';
$wb["wget_txt"] = 'Path to wget program';
?>
interface/web/admin/templates/server_config_cron_edit.htm
New file
@@ -0,0 +1,30 @@
<h2><tmpl_var name="list_head_txt"></h2>
<p><tmpl_var name="list_desc_txt"></p>
<div class="panel panel_server_config">
  <div class="pnl_formsarea">
    <fieldset class="inlineLabels">
      <div class="ctrlHolder">
        <label for="init_script">{tmpl_var name='init_script_txt'}</label>
        <input name="init_script" id="init_script" value="{tmpl_var name='init_script'}" size="40" maxlength="255" type="text" class="textInput" />
            </div>
      <div class="ctrlHolder">
        <label for="crontab_dir">{tmpl_var name='crontab_dir_txt'}</label>
        <input name="crontab_dir" id="crontab_dir" value="{tmpl_var name='crontab_dir'}" size="40" maxlength="255" type="text" class="textInput" />
            </div>
      <div class="ctrlHolder">
        <label for="wget">{tmpl_var name='wget_txt'}</label>
        <input name="wget" id="wget" value="{tmpl_var name='wget'}" size="40" maxlength="255" type="text" class="textInput" />
            </div>
    </fieldset>
    <input type="hidden" name="id" value="{tmpl_var name='id'}">
    <div class="buttonHolder buttons">
      <button class="positive iconstxt icoPositive" type="button" value="{tmpl_var name='btn_save_txt'}" onClick="submitForm('pageForm','admin/server_config_edit.php');"><span>{tmpl_var name='btn_save_txt'}</span></button>
      <button class="negative iconstxt icoNegative" type="button" value="{tmpl_var name='btn_cancel_txt'}" onClick="loadContent('admin/server_config_list.php');"><span>{tmpl_var name='btn_cancel_txt'}</span></button>
    </div>
  </div>
</div>
interface/web/admin/templates/server_config_jailkit_edit.htm
@@ -17,6 +17,10 @@
          <label for="jailkit_chroot_app_programs">{tmpl_var name='jailkit_chroot_app_programs_txt'}</label>
        <input name="jailkit_chroot_app_programs" id="jailkit_chroot_app_programs" value="{tmpl_var name='jailkit_chroot_app_programs'}" size="40" maxlength="1000" type="text" class="textInput" />
            </div>
      <div class="ctrlHolder">
        <label for="jailkit_chroot_cron_programs">{tmpl_var name='jailkit_chroot_cron_programs_txt'}</label>
        <input name="jailkit_chroot_cron_programs" id="jailkit_chroot_cron_programs" value="{tmpl_var name='jailkit_chroot_cron_programs'}" size="40" maxlength="1000" type="text" class="textInput" />
            </div>
    </fieldset>
    <input type="hidden" name="id" value="{tmpl_var name='id'}">
interface/web/admin/templates/server_config_vlogger_edit.htm
New file
@@ -0,0 +1,22 @@
<h2><tmpl_var name="list_head_txt"></h2>
<p><tmpl_var name="list_desc_txt"></p>
<div class="panel panel_server_config">
  <div class="pnl_formsarea">
    <fieldset class="inlineLabels">
      <div class="ctrlHolder">
          <label for="config_dir">{tmpl_var name='config_dir_txt'}</label>
        <input name="config_dir" id="config_dir" value="{tmpl_var name='config_dir'}" size="40" maxlength="255" type="text" class="textInput" />
            </div>
    </fieldset>
    <input type="hidden" name="id" value="{tmpl_var name='id'}">
    <div class="buttonHolder buttons">
      <button class="positive iconstxt icoPositive" type="button" value="{tmpl_var name='btn_save_txt'}" onClick="submitForm('pageForm','admin/server_config_edit.php');"><span>{tmpl_var name='btn_save_txt'}</span></button>
      <button class="negative iconstxt icoNegative" type="button" value="{tmpl_var name='btn_cancel_txt'}" onClick="loadContent('admin/server_config_list.php');"><span>{tmpl_var name='btn_cancel_txt'}</span></button>
    </div>
  </div>
</div>
interface/web/client/form/client.tform.php
@@ -663,6 +663,40 @@
            'rows'        => '',
            'cols'        => ''
        ),
        'limit_cron' => array (
            'datatype'  => 'INTEGER',
            'formtype'  => 'TEXT',
            'validators'    => array (  0 => array (    'type'  => 'ISINT',
                                                        'errmsg'=> 'limit_cron_error_notint'),
                                    ),
            'default'   => '0',
            'value'     => '',
            'separator' => '',
            'width'     => '10',
            'maxlength' => '10',
            'rows'      => '',
            'cols'      => ''
        ),
        'limit_cron_type' => array (
            'datatype'  => 'VARCHAR',
            'formtype'  => 'SELECT',
            'default'   => '',
            'value'     => array('full' => 'Full Cron','chrooted' => 'Chrooted Cron','url' => 'URL Cron')
        ),
        'limit_cron_frequency' => array (
            'datatype'  => 'INTEGER',
            'formtype'  => 'TEXT',
            'validators'    => array (  0 => array (    'type'  => 'ISINT',
                                                        'errmsg'=> 'limit_cron_error_frequency'),
                                    ),
            'default'   => '-1',
            'value'     => '',
            'separator' => '',
            'width'     => '10',
            'maxlength' => '10',
            'rows'      => '',
            'cols'      => ''
        ),
    ##################################
    # END Datatable fields
    ##################################
interface/web/client/form/client_template.tform.php
@@ -395,6 +395,40 @@
            'rows'        => '',
            'cols'        => ''
        ),
        'limit_cron' => array (
            'datatype'  => 'INTEGER',
            'formtype'  => 'TEXT',
            'validators'    => array (  0 => array (    'type'  => 'ISINT',
                                                        'errmsg'=> 'limit_cron_error_notint'),
                                    ),
            'default'   => '0',
            'value'     => '',
            'separator' => '',
            'width'     => '10',
            'maxlength' => '10',
            'rows'      => '',
            'cols'      => ''
        ),
        'limit_cron_type' => array (
            'datatype'  => 'VARCHAR',
            'formtype'  => 'SELECT',
            'default'   => '',
            'value'     => array('full' => 'Full Cron','chrooted' => 'Chrooted Cron','url' => 'URL Cron')
        ),
        'limit_cron_frequency' => array (
            'datatype'  => 'INTEGER',
            'formtype'  => 'TEXT',
            'validators'    => array (  0 => array (    'type'  => 'ISINT',
                                                        'errmsg'=> 'limit_cron_error_frequency'),
                                    ),
            'default'   => '-1',
            'value'     => '',
            'separator' => '',
            'width'     => '10',
            'maxlength' => '10',
            'rows'      => '',
            'cols'      => ''
        ),
    ##################################
    # END Datatable fields
    ##################################
interface/web/client/lib/lang/de_client.lng
@@ -39,6 +39,9 @@
$wb['limit_subdomain_txt'] = 'Max. Anzahl an Subdomains';
$wb['limit_webquota_txt'] = 'Max. Webquota';
$wb['limit_database_txt'] = 'Max. Anzahl an Datenbanken';
$wb["limit_cron_txt"] = 'Max. Anzahl Cron Jobs';
$wb["limit_cron_type_txt"] = 'Max. erlaubter Typ von Cron Jobs (chrooted und full erlauben auch url)';
$wb["limit_cron_frequency_txt"] = 'Min. Abstand zwischen Ausf&uuml;hrungen';
$wb['ip_address_txt'] = 'IP Adresse';
$wb['limit_client_error_notint'] = 'The sub client limit must be a number.';
$wb['firstname_error_empty'] = 'Vorname ist leer.';
@@ -74,6 +77,8 @@
$wb['limit_dns_zone_error_notint'] = 'Das DNS Einträge Limit muss eine Nummer sein.';
$wb['default_dbserver_txt'] = 'Standarddatenbankserver';
$wb['limit_database_error_notint'] = 'Das Datenbank Limit muss eine Nummer sein.';
$wb["limit_cron_error_notint"] = 'Das Cron Job Limit muss eine Zahl sein.';
$wb["limit_cron_error_frequency"] = 'Das Cron Job Intervall-Limit muss eine Zahl sein.';
$wb['username_error_regex'] = 'Der Benutzername enthält ungültige Zeichen.';
$wb['password_strength_txt'] = 'Passwortkomplexität';
$wb['template_master_txt'] = 'Master';
interface/web/client/lib/lang/de_client_template.lng
@@ -17,6 +17,9 @@
$wb['limit_subdomain_txt'] = 'Max. Anzahl an Subdomains';
$wb['limit_webquota_txt'] = 'Max. Webquota';
$wb['limit_database_txt'] = 'Max. Anzahl an Datenbanken';
$wb["limit_cron_txt"] = 'Max. Anzahl Cron Jobs';
$wb["limit_cron_type_txt"] = 'Max. erlaubter Typ von Cron Jobs (chrooted und full erlauben auch url)';
$wb["limit_cron_frequency_txt"] = 'Min. Abstand zwischen Ausf&uuml;hrungen';
$wb['limit_web_domain_txt'] = 'Max. Anzahl an Web Domains';
$wb['limit_web_aliasdomain_txt'] = 'Max. Anzahl an Web Aliasdomains';
$wb['limit_web_subdomain_txt'] = 'Max. Anzahl an Web Subdomains';
@@ -43,5 +46,7 @@
$wb['limit_shell_user_error_notint'] = 'Das Shell Benutzer Limit muss eine Nummer sein.';
$wb['limit_dns_zone_error_notint'] = 'Das DNS Einträge Limit muss eine Nummer sein.';
$wb['limit_database_error_notint'] = 'Das Datenbanken Limit muss eine Nummer sein.';
$wb["limit_cron_error_notint"] = 'Das Cron Job Limit muss eine Zahl sein.';
$wb["limit_cron_error_frequency"] = 'Das Cron Job Intervall-Limit muss eine Zahl sein.';
$wb['error_template_name_empty'] = 'Bitte geben sie einen Vorlagenamen ein';
?>
interface/web/client/lib/lang/en_client.lng
@@ -39,6 +39,9 @@
$wb["limit_subdomain_txt"] = 'limit_subdomain';
$wb["limit_webquota_txt"] = 'limit_webquota';
$wb["limit_database_txt"] = 'limit_database';
$wb["limit_cron_txt"] = 'Max. number of cron jobs';
$wb["limit_cron_type_txt"] = 'Max. type of cron jobs (chrooted and full implies url)';
$wb["limit_cron_frequency_txt"] = 'Min. delay between executions';
$wb["ip_address_txt"] = 'ip_address';
$wb["limit_client_error_notint"] = 'Client Limit is not a number.';
$wb["firstname_error_empty"] = 'Firstname is empty.';
@@ -78,6 +81,8 @@
$wb["default_dbserver_txt"] = 'Default Database Server';
$wb["limit_database_txt"] = 'Max. number of Databases';
$wb["limit_database_error_notint"] = 'The database limit must be a number.';
$wb["limit_cron_error_notint"] = 'The cron limit must be a number.';
$wb["limit_cron_error_frequency"] = 'The cron frequency limit must be a number.';
$wb["username_error_regex"] = 'The Username contains invalid chracaters.';
$wb["template_master_txt"] = 'Master template';
$wb["template_additional_txt"] = 'Addon template';
interface/web/client/lib/lang/en_client_template.lng
@@ -17,6 +17,9 @@
$wb["limit_subdomain_txt"] = 'limit_subdomain';
$wb["limit_webquota_txt"] = 'limit_webquota';
$wb["limit_database_txt"] = 'limit_database';
$wb["limit_cron_txt"] = 'Max. number of cron jobs';
$wb["limit_cron_type_txt"] = 'Max. type of cron jobs (chrooted and full implies url)';
$wb["limit_cron_frequency_txt"] = 'Min. delay between executions';
$wb["limit_web_domain_txt"] = 'Max. number of web domains';
$wb["limit_web_aliasdomain_txt"] = 'Max. number of web aliasdomains';
$wb["limit_web_subdomain_txt"] = 'Max. number of web subdomains';
@@ -46,5 +49,7 @@
$wb["limit_dns_zone_error_notint"] = 'The dns record limit must be a number.';
$wb["limit_database_txt"] = 'Max. number of Databases';
$wb["limit_database_error_notint"] = 'The database limit must be a number.';
$wb["limit_cron_error_notint"] = 'The cron limit must be a number.';
$wb["limit_cron_error_frequency"] = 'The cron frequency limit must be a number.';
$wb["error_template_name_empty"] = 'Please enter a Template name';
?>
interface/web/client/templates/client_edit_limits.htm
@@ -155,6 +155,20 @@
          <label for="limit_database">{tmpl_var name='limit_database_txt'}</label>
        <input name="limit_database" id="limit_database" value="{tmpl_var name='limit_database'}" size="10" maxlength="10" type="text" class="textInput formLengthLimit" />
            </div>
      <div class="ctrlHolder">
        <label for="limit_cron">{tmpl_var name='limit_cron_txt'}</label>
        <input name="limit_cron" id="limit_cron" value="{tmpl_var name='limit_cron'}" size="10" maxlength="10" type="text" class="textInput formLengthLimit" />
            </div>
      <div class="ctrlHolder">
        <label for="limit_cron_type">{tmpl_var name='limit_cron_type_txt'}</label>
        <select name="limit_cron_type" id="limit_cron_type" class="selectInput formLengthHalf">
          {tmpl_var name='limit_cron_type'}
        </select>
            </div>
      <div class="ctrlHolder">
        <label for="limit_cron_frequency">{tmpl_var name='limit_cron_frequency_txt'}</label>
        <input name="limit_cron_frequency" id="limit_cron_frequency" value="{tmpl_var name='limit_cron_frequency'}" size="10" maxlength="10" type="text" class="textInput formLengthLimit" />
            </div>
    </fieldset>
    <input type="hidden" name="id" value="{tmpl_var name='id'}">
interface/web/client/templates/client_template_edit_limits.htm
@@ -89,6 +89,20 @@
          <label for="limit_database">{tmpl_var name='limit_database_txt'}</label>
        <input name="limit_database" id="limit_database" value="{tmpl_var name='limit_database'}" size="10" maxlength="10" type="text" class="textInput formLengthLimit" />
            </div>
      <div class="ctrlHolder">
        <label for="limit_cron">{tmpl_var name='limit_cron_txt'}</label>
        <input name="limit_cron" id="limit_cron" value="{tmpl_var name='limit_cron'}" size="10" maxlength="10" type="text" class="textInput formLengthLimit" />
            </div>
      <div class="ctrlHolder">
        <label for="limit_cron_type">{tmpl_var name='limit_cron_type_txt'}</label>
        <select name="limit_cron_type" id="limit_cron_type" class="selectInput formLengthHalf">
          {tmpl_var name='limit_cron_type'}
        </select>
            </div>
      <div class="ctrlHolder">
        <label for="limit_cron_frequency">{tmpl_var name='limit_cron_frequency_txt'}</label>
        <input name="limit_cron_frequency" id="limit_cron_frequency" value="{tmpl_var name='limit_cron_frequency'}" size="10" maxlength="10" type="text" class="textInput formLengthLimit" />
            </div>
    </fieldset>
    <input type="hidden" name="id" value="{tmpl_var name='id'}">
interface/web/sites/cron_del.php
New file
@@ -0,0 +1,64 @@
<?php
/*
Copyright (c) 2008, Till Brehm, projektfarm Gmbh
Modified 2009, 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.
*/
/******************************************
* Begin Form configuration
******************************************/
$list_def_file = "list/cron.list.php";
$tform_def_file = "form/cron.tform.php";
/******************************************
* End Form configuration
******************************************/
require_once('../../lib/config.inc.php');
require_once('../../lib/app.inc.php');
//* Check permissions for module
$app->auth->check_module_permissions('sites');
$app->uses('tpl,tform,tform_actions');
$app->load('tform_actions');
class page_action extends tform_actions {
    function onBeforeDelete() {
        global $app; $conf;
        if($app->tform->checkPerm($this->id,'d') == false) $app->error($app->lng('error_no_delete_permission'));
    }
}
$page = new page_action;
$page->onDelete();
?>
interface/web/sites/cron_edit.php
New file
@@ -0,0 +1,226 @@
<?php
/*
Copyright (c) 2007, Till Brehm, projektfarm Gmbh
Modified 2009, 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.
*/
/******************************************
* Begin Form configuration
******************************************/
$tform_def_file = "form/cron.tform.php";
/******************************************
* End Form configuration
******************************************/
require_once('../../lib/config.inc.php');
require_once('../../lib/app.inc.php');
//* Check permissions for module
$app->auth->check_module_permissions('sites');
// Loading classes
$app->uses('tpl,tform,tform_actions,validate_cron');
$app->load('tform_actions');
class page_action extends tform_actions {
    function onShowNew() {
        global $app, $conf;
        // we will check only users, not admins
        if($_SESSION["s"]["user"]["typ"] == 'user') {
            // Get the limits of the client
            $client_group_id = $_SESSION["s"]["user"]["default_group"];
            $client = $app->db->queryOneRecord("SELECT limit_cron FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
            // Check if the user may add another cron job.
            if($client["limit_cron"] >= 0) {
                $tmp = $app->db->queryOneRecord("SELECT count(id) as number FROM cron WHERE sys_groupid = $client_group_id");
                if($tmp["number"] >= $client["limit_cron"]) {
                    $app->error($app->tform->wordbook["limit_cron_txt"]);
                }
            }
        }
        parent::onShowNew();
    }
    function onShowEnd() {
        global $app, $conf;
        if($this->id > 0) {
            //* we are editing a existing record
            $app->tpl->setVar("edit_disabled", 1);
            $app->tpl->setVar("parent_domain_id_value", $this->dataRecord["parent_domain_id"]);
        } else {
            $app->tpl->setVar("edit_disabled", 0);
        }
        parent::onShowEnd();
    }
    function onSubmit() {
        global $app, $conf;
        if($_SESSION["s"]["user"]["typ"] != 'admin') {
            // Get the limits of the client
            $client_group_id = $_SESSION["s"]["user"]["default_group"];
            $client = $app->db->queryOneRecord("SELECT limit_cron, limit_cron_type FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
            // When the record is updated
            if($this->id > 0) {
            // When the record is inserted
            } else {
                // Check if the user may add another cron job.
                if($client["limit_cron"] >= 0) {
                    $tmp = $app->db->queryOneRecord("SELECT count(id) as number FROM cron WHERE sys_groupid = $client_group_id");
                    if($tmp["number"] >= $client["limit_cron"]) {
                        $app->error($app->tform->wordbook["limit_cron_txt"]);
                    }
                }
            }
        }
        // Get the record of the parent domain
        $parent_domain = $app->db->queryOneRecord("select * FROM web_domain WHERE domain_id = ".intval(@$this->dataRecord["parent_domain_id"]));
        // Set fixed values
        $this->dataRecord["server_id"] = $parent_domain["server_id"];
        //* get type of command
        $command = $this->dataRecord["command"];
        if(preg_match("'^http(s)?:\/\/'i", $command)) {
            $this->dataRecord["type"] = 'url';
        } else {
            $domain_owner = $app->db->queryOneRecord("SELECT limit_cron_type FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = ".intval($parent_domain["sys_groupid"]));
            if($domain_owner["limit_cron_type"] == 'full') $this->dataRecord["type"] = 'full';
            else $this->dataRecord["type"] = 'chrooted';
        }
        parent::onSubmit();
    }
    function onUpdateSave($sql) {
        global $app;
        $has_error = false;
        //* last chance to stop this, so check frequency limit!
        if($_SESSION["s"]["user"]["typ"] != 'admin') {
            // Get the limits of the client
            $client_group_id = $_SESSION["s"]["user"]["default_group"];
            $client = $app->db->queryOneRecord("SELECT limit_cron_frequency FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
            if($client["limit_cron_frequency"] > 1) {
                if($app->tform->cron_min_freq < $client["limit_cron_frequency"]) {
                    $app->error($app->tform->wordbook["limit_cron_frequency_txt"]);
                    $has_error = true;
                }
            }
        }
        if($has_error == true) {
            parent::onError();
            exit;
        }
        else parent::onUpdateSave($sql);
    }
    function onInsertSave($sql) {
        global $app;
        $has_error = false;
        //* last chance to stop this, so check frequency limit!
        if($_SESSION["s"]["user"]["typ"] != 'admin') {
            // Get the limits of the client
            $client_group_id = $_SESSION["s"]["user"]["default_group"];
            $client = $app->db->queryOneRecord("SELECT limit_cron_frequency FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
            if($client["limit_cron_frequency"] > 1) {
                if($app->tform->cron_min_freq < $client["limit_cron_frequency"]) {
                    $app->error($app->tform->wordbook["limit_cron_frequency_txt"]);
                    $has_error = true;
                }
            }
        }
        if($has_error == true) {
            parent::onError();
            exit;
        }
        else parent::onInsertSave($sql);
    }
    function onAfterInsert() {
        global $app, $conf;
        $web = $app->db->queryOneRecord("SELECT * FROM web_domain WHERE domain_id = ".intval($this->dataRecord["parent_domain_id"]));
        $server_id = $web["server_id"];
        // The cron shall be owned by the same group then the website
        $sys_groupid = $web['sys_groupid'];
        $sql = "UPDATE shell_user SET server_id = $server_id, sys_groupid = '$sys_groupid' WHERE id = ".$this->id;
        $app->db->query($sql);
    }
    function onAfterUpdate() {
        global $app, $conf;
    }
    function getClientName() {
        global $app, $conf;
        if($_SESSION["s"]["user"]["typ"] != 'admin') {
            // Get the group-id of the user
            $client_group_id = $_SESSION["s"]["user"]["default_group"];
        } else {
            // Get the group-id from the data itself
            $web = $app->db->queryOneRecord("SELECT sys_groupid FROM web_domain WHERE domain_id = ".intval($this->dataRecord['parent_domain_id']));
            $client_group_id = $web['sys_groupid'];
        }
        /* get the name of the client */
        $tmp = $app->db->queryOneRecord("SELECT name FROM sys_group WHERE groupid = " . $client_group_id);
        $clientName = $tmp['name'];
        if ($clientName == "") $clientName = 'default';
        $clientName = convertClientName($clientName);
        return $clientName;
    }
}
$page = new page_action;
$page->onLoad();
?>
interface/web/sites/cron_list.php
New file
@@ -0,0 +1,23 @@
<?php
require_once('../../lib/config.inc.php');
require_once('../../lib/app.inc.php');
/******************************************
* Begin Form configuration
******************************************/
$list_def_file = "list/cron.list.php";
/******************************************
* End Form configuration
******************************************/
//* Check permissions for module
$app->auth->check_module_permissions('sites');
$app->uses('listform_actions');
$app->listform_actions->onLoad();
?>
interface/web/sites/form/cron.tform.php
New file
@@ -0,0 +1,189 @@
<?php
/*
    Form Definition
    Tabledefinition
    Datatypes:
    - INTEGER (Forces the input to Int)
    - DOUBLE
    - CURRENCY (Formats the values to currency notation)
    - VARCHAR (no format check, maxlength: 255)
    - TEXT (no format check)
    - DATE (Dateformat, automatic conversion to timestamps)
    Formtype:
    - TEXT (Textfield)
    - TEXTAREA (Textarea)
    - PASSWORD (Password textfield, input is not shown when edited)
    - SELECT (Select option field)
    - RADIO
    - CHECKBOX
    - CHECKBOXARRAY
    - FILE
    VALUE:
    - Wert oder Array
    Hint:
    The ID field of the database table is not part of the datafield definition.
    The ID field must be always auto incement (int or bigint).
*/
$form["title"]             = "Cron Job";
$form["description"]     = "";
$form["name"]             = "cron";
$form["action"]            = "cron_edit.php";
$form["db_table"]        = "cron";
$form["db_table_idx"]    = "id";
$form["db_history"]        = "yes";
$form["tab_default"]    = "cron";
$form["list_default"]    = "cron_list.php";
$form["auth"]            = 'yes'; // yes / no
$form["auth_preset"]["userid"]  = 0; // 0 = id of the user, > 0 id must match with id of current user
$form["auth_preset"]["groupid"] = 0; // 0 = default groupid of the user, > 0 id must match with groupid of current user
$form["auth_preset"]["perm_user"] = 'riud'; //r = read, i = insert, u = update, d = delete
$form["auth_preset"]["perm_group"] = 'riud'; //r = read, i = insert, u = update, d = delete
$form["auth_preset"]["perm_other"] = ''; //r = read, i = insert, u = update, d = delete
$form["tabs"]['cron'] = array (
    'title'     => "Cron Job",
    'width'     => 100,
    'template'     => "templates/cron_edit.htm",
    'fields'     => array (
    ##################################
    # Begin Datatable fields
    ##################################
        'server_id' => array (
            'datatype'    => 'INTEGER',
            'formtype'    => 'SELECT',
            'datasource'    => array (     'type'    => 'SQL',
                                        'querystring' => 'SELECT server_id,server_name FROM server WHERE web_server = 1 AND {AUTHSQL} ORDER BY server_name',
                                        'keyfield'=> 'server_id',
                                        'valuefield'=> 'server_name'
                                     ),
            'validators'    => array (     0 => array (    'type'    => 'NOTEMPTY',
                                                        'errmsg'=> 'server_id_error_empty'),
                                    ),
            'default'    => '',
            'value'        => '',
            'width'        => '30',
            'maxlength'    => '255'
        ),
        'parent_domain_id' => array (
            'datatype'  => 'INTEGER',
            'formtype'  => 'SELECT',
            'default'   => '',
            'datasource'    => array (  'type'  => 'SQL',
                                        'querystring' => "SELECT domain_id,domain FROM web_domain WHERE type = 'vhost' AND {AUTHSQL} ORDER BY domain",
                                        'keyfield'=> 'domain_id',
                                        'valuefield'=> 'domain'
                                     ),
            'value'     => ''
        ),
        'run_min' => array (
            'datatype'  => 'VARCHAR',
            'formtype'  => 'TEXT',
            'validators'    => array (  0 => array (    'type'  => 'CUSTOM',
                                                        'class' => 'validate_cron',
                                                        'function' => 'run_time_format',
                                                        'errmsg'=> 'run_min_error_format'),
                                    ),
            'default'   => '',
            'value'     => '',
            'width'     => '30',
            'maxlength' => '255'
        ),
        'run_hour' => array (
            'datatype'  => 'VARCHAR',
            'formtype'  => 'TEXT',
            'validators'    => array (  0 => array (    'type'  => 'CUSTOM',
                                                        'class' => 'validate_cron',
                                                        'function' => 'run_time_format',
                                                        'errmsg'=> 'run_hour_error_format'),
                                    ),
            'default'   => '',
            'value'     => '',
            'width'     => '30',
            'maxlength' => '255'
        ),
        'run_mday' => array (
            'datatype'  => 'VARCHAR',
            'formtype'  => 'TEXT',
            'validators'    => array (  0 => array (    'type'  => 'CUSTOM',
                                                        'class' => 'validate_cron',
                                                        'function' => 'run_time_format',
                                                        'errmsg'=> 'run_mday_error_format'),
                                    ),
            'default'   => '',
            'value'     => '',
            'width'     => '30',
            'maxlength' => '255'
        ),
        'run_month' => array (
            'datatype'  => 'VARCHAR',
            'formtype'  => 'TEXT',
            'validators'    => array (  0 => array (    'type'  => 'CUSTOM',
                                                        'class' => 'validate_cron',
                                                        'function' => 'run_time_format',
                                                        'errmsg'=> 'run_month_error_format'),
                                    ),
            'default'   => '',
            'value'     => '',
            'width'     => '30',
            'maxlength' => '255'
        ),
        'run_wday' => array (
            'datatype'  => 'VARCHAR',
            'formtype'  => 'TEXT',
            'validators'    => array (  0 => array (    'type'  => 'CUSTOM',
                                                        'class' => 'validate_cron',
                                                        'function' => 'run_time_format',
                                                        'errmsg'=> 'run_wday_error_format'),
                                    ),
            'default'   => '',
            'value'     => '',
            'width'     => '30',
            'maxlength' => '255'
        ),
        'command' => array (
            'datatype'    => 'VARCHAR',
            'formtype'    => 'TEXT',
            'validators'    => array (     0 => array (    'type'    => 'NOTEMPTY',
                                                        'errmsg'=> 'command_error_empty'),
                                        1 => array (    'type'  => 'CUSTOM',
                                                        'class' => 'validate_cron',
                                                        'function' => 'command_format',
                                                        'errmsg'=> 'command_error_format'),
                                    ),
            'default'    => '',
            'value'        => '',
            'width'        => '30',
            'maxlength'    => '255'
        ),
        'type' => array (
            'datatype'  => 'VARCHAR',
            'formtype'  => 'SELECT',
            'default'   => 'url',
            'valuelimit' => 'list:url,full,chrooted',
            'value'     => array('url' => 'Url', 'full' => 'Full', 'chrooted' => 'Chrooted')
        ),
        'active' => array (
            'datatype'    => 'VARCHAR',
            'formtype'    => 'CHECKBOX',
            'default'    => 'y',
            'value'        => array(0 => 'n',1 => 'y')
        ),
    ##################################
    # ENDE Datatable fields
    ##################################
    )
);
?>
interface/web/sites/lib/lang/de_cron.lng
New file
@@ -0,0 +1,21 @@
<?php
$wb['server_id_txt'] = 'Server';
$wb['parent_domain_id_txt'] = 'Zugeordnete Website';
$wb['active_txt'] = 'Aktiv';
$wb['client_txt'] = 'Kunde';
$wb['run_min_txt'] = 'Minuten';
$wb['run_hour_txt'] = 'Stunden';
$wb['run_mday_txt'] = 'Tage des Monats';
$wb['run_month_txt'] = 'Monate';
$wb['run_wday_txt'] = 'Tage der Woche';
$wb['command_txt'] = 'Auszuf&uuml;hrender Befehl (Befehle werden mit sh ausgef&uuml;hrt, urls mit wget)';
$wb['limit_cron_txt'] = 'Die maximale Anzahl von erlaubten Cron Jobs ist bereits erreicht.';
$wb['limit_cron_frequency_txt'] = 'Die Ausf&uuml;hrungsh&auml;ufigkeit &uuml;bersteigt Ihr erlaubtes Limit.';
$wb['run_min_error_format'] = 'Das Format f&uuml;r Minuten ist nicht korrekt.';
$wb['run_hour_error_format'] = 'Das Format f&uuml;r Stunden ist nicht korrekt.';
$wb['run_mday_error_format'] = 'Das Format f&uuml;r Tage des Monats ist nicht korrekt.';
$wb['run_month_error_format'] = 'Das Format f&uuml;r Monate ist nicht korrekt.';
$wb['run_wday_error_format'] = 'Das Format f&uuml;r Wochentage ist nicht korrekt.';
$wb['command_error_format'] = 'Das Format f&uuml;r den Befehl ist nicht korrekt. Beachte, dass bei einem URL Aufruf nur http und https erlaubt ist.';
$wb['unknown_fieldtype_error'] = 'Es wurde ein unbekanntes Feld verwendet.';
?>
interface/web/sites/lib/lang/de_cron_list.lng
New file
@@ -0,0 +1,12 @@
<?php
$wb['list_head_txt'] = 'Cron Jobs';
$wb['active_txt'] = 'Activ';
$wb['server_id_txt'] = 'Server';
$wb['run_min_txt'] = 'Minute';
$wb["run_hour_txt"] = 'Stunde';
$wb["run_mday_txt"] = 'Tag des Monats';
$wb["run_month_txt"] = 'Monat';
$wb["run_wday_txt"] = 'Tag der Woche';
$wb['command_txt'] = 'Befehl';
$wb['add_new_cron_txt'] = 'Neuen Cron Job anlegen';
?>
interface/web/sites/lib/lang/en_cron.lng
New file
@@ -0,0 +1,21 @@
<?php
$wb["server_id_txt"] = 'Server';
$wb['parent_domain_id_txt'] = 'Parent website';
$wb['active_txt'] = 'Active';
$wb['client_txt'] = 'Client';
$wb['run_min_txt'] = 'Minutes';
$wb['run_hour_txt'] = 'Hours';
$wb['run_mday_txt'] = 'Days of month';
$wb['run_month_txt'] = 'Months';
$wb['run_wday_txt'] = 'Days of week';
$wb['command_txt'] = 'Command to run (commands are executed via sh, urls via wget)';
$wb['limit_cron_txt'] = 'The maximum number of allowed cron jobs was reached.';
$wb['limit_cron_frequency_txt'] = 'The cron job frequency exceeds the allowed limit.';
$wb['run_min_error_format'] = 'Invalid format for minutes.';
$wb['run_hour_error_format'] = 'Invalid format for hours.';
$wb['run_mday_error_format'] = 'Invalid format for days of month.';
$wb['run_month_error_format'] = 'Invalid format for months.';
$wb['run_wday_error_format'] = 'Invalid format for days of the week.';
$wb['command_error_format'] = 'Invalid command format. Please note that in case of an url call only http/https is allowed.';
$wb['unknown_fieldtype_error'] = 'An unknown field type has been used.';
?>
interface/web/sites/lib/lang/en_cron_list.lng
New file
@@ -0,0 +1,12 @@
<?php
$wb["list_head_txt"] = 'Cron Jobs';
$wb["active_txt"] = 'Active';
$wb["server_id_txt"] = 'Server';
$wb["run_min_txt"] = 'Minute';
$wb["run_hour_txt"] = 'Hour';
$wb["run_mday_txt"] = 'Day of month';
$wb["run_month_txt"] = 'Month';
$wb["run_wday_txt"] = 'Day of week';
$wb["command_txt"] = 'Command';
$wb["add_new_cron_txt"] = 'Add new Cron job';
?>
interface/web/sites/lib/module.conf.php
@@ -77,6 +77,21 @@
                            'items'    => $items);
/*
    Cron menu
*/
$items = array();
$items[] = array( 'title'   => "Cron Jobs",
                  'target'  => 'content',
                  'link'    => 'sites/cron_list.php');
$module["nav"][] = array(   'title' => 'Cron',
                            'open'  => 1,
                            'items' => $items);
//**** Statistics menu
$items = array();
interface/web/sites/list/cron.list.php
New file
@@ -0,0 +1,152 @@
<?php
/*
    Datatypes:
    - INTEGER
    - DOUBLE
    - CURRENCY
    - VARCHAR
    - TEXT
    - DATE
*/
// Name of the list
$liste["name"]                 = "cron";
// Database table
$liste["table"]             = "cron";
// Index index field of the database table
$liste["table_idx"]            = "id";
// Search Field Prefix
$liste["search_prefix"]     = "search_";
// Records per page
$liste["records_per_page"]     = 15;
// Script File of the list
$liste["file"]                = "cron_list.php";
// Script file of the edit form
$liste["edit_file"]            = "cron_edit.php";
// Script File of the delete script
$liste["delete_file"]        = "cron_del.php";
// Paging Template
$liste["paging_tpl"]        = "templates/paging.tpl.htm";
// Enable auth
$liste["auth"]                = "yes";
/*****************************************************
* Suchfelder
*****************************************************/
$liste["item"][] = array(    'field'        => "active",
                            'datatype'    => "VARCHAR",
                            'formtype'    => "SELECT",
                            'op'        => "=",
                            'prefix'    => "",
                            'suffix'    => "",
                            'width'        => "",
                            'value'        => array('y' => "<div id=\"ir-Yes\" class=\"swap\"><span>Yes</span></div>",'n' => "<div class=\"swap\" id=\"ir-No\"><span>No</span></div>"));
$liste["item"][] = array(    'field'        => "server_id",
                            'datatype'    => "VARCHAR",
                            'formtype'    => "SELECT",
                            'op'        => "like",
                            'prefix'    => "%",
                            'suffix'    => "%",
                            'datasource'    => array (     'type'    => 'SQL',
                                                        'querystring' => 'SELECT server_id,server_name FROM server WHERE {AUTHSQL} ORDER BY server_name',
                                                        'keyfield'=> 'server_id',
                                                        'valuefield'=> 'server_name'
                                                       ),
                            'width'        => "",
                            'value'        => "");
$liste["item"][] = array(   'field'     => "parent_domain_id",
                            'datatype'  => "VARCHAR",
                            'formtype'  => "SELECT",
                            'op'        => "like",
                            'prefix'    => "%",
                            'suffix'    => "%",
                            'datasource'    => array (  'type'  => 'SQL',
                                        'querystring' => "SELECT domain_id,domain FROM web_domain WHERE type = 'vhost' AND {AUTHSQL} ORDER BY domain",
                                        'keyfield'=> 'domain_id',
                                        'valuefield'=> 'domain'
                                     ),
                            'width'     => "",
                            'value'     => "");
$liste["item"][] = array(   'field'     => "run_min",
                            'datatype'  => "VARCHAR",
                            'formtype'  => "TEXT",
                            'op'        => "=",
                            'prefix'    => "",
                            'suffix'    => "",
                            'width'     => "",
                            'value'     => "");
$liste["item"][] = array(   'field'     => "run_hour",
                            'datatype'  => "VARCHAR",
                            'formtype'  => "TEXT",
                            'op'        => "=",
                            'prefix'    => "",
                            'suffix'    => "",
                            'width'     => "",
                            'value'     => "");
$liste["item"][] = array(   'field'     => "run_mday",
                            'datatype'  => "VARCHAR",
                            'formtype'  => "TEXT",
                            'op'        => "=",
                            'prefix'    => "",
                            'suffix'    => "",
                            'width'     => "",
                            'value'     => "");
$liste["item"][] = array(   'field'     => "run_month",
                            'datatype'  => "VARCHAR",
                            'formtype'  => "TEXT",
                            'op'        => "=",
                            'prefix'    => "",
                            'suffix'    => "",
                            'width'     => "",
                            'value'     => "");
$liste["item"][] = array(   'field'     => "run_wday",
                            'datatype'  => "VARCHAR",
                            'formtype'  => "TEXT",
                            'op'        => "=",
                            'prefix'    => "",
                            'suffix'    => "",
                            'width'     => "",
                            'value'     => "");
$liste["item"][] = array(    'field'        => "command",
                            'datatype'    => "VARCHAR",
                            'formtype'    => "TEXT",
                            'op'        => "like",
                            'prefix'    => "%",
                            'suffix'    => "%",
                            'width'        => "",
                            'value'        => "");
?>
interface/web/sites/templates/cron_edit.htm
New file
@@ -0,0 +1,68 @@
<h2><tmpl_var name="list_head_txt"></h2>
<p><tmpl_var name="list_desc_txt"></p>
<div class="panel panel_cron">
  <div class="pnl_formsarea">
    <fieldset class="inlineLabels"><legend>Cron Job</legend>
      <div class="ctrlHolder">
        <tmpl_if name="edit_disabled">
        <label for="parent_domain_id">{tmpl_var name='parent_domain_id_txt'}</label>
        <select name="parent_domain_id" id="parent_domain_id" class="selectInput" disabled="disabled">
                    {tmpl_var name='parent_domain_id'}
        </select>
        <input type="hidden" name="parent_domain_id" value="{tmpl_var name='parent_domain_id_value'}" />
        <tmpl_else>
        <label for="parent_domain_id">{tmpl_var name='parent_domain_id_txt'}</label>
        <select name="parent_domain_id" id="parent_domain_id" class="selectInput">
                    {tmpl_var name='parent_domain_id'}
        </select>
        </tmpl_if>
      </div>
      <div class="ctrlHolder">
        <label for="run_min">{tmpl_var name='run_min_txt'}</label>
        <input name="run_min" id="run_min" value="{tmpl_var name='run_min'}" size="10" maxlength="255" type="text" class="textInput" />
                <p class="formHint">e.g. *, */3, 10-20</p>
            </div>
      <div class="ctrlHolder">
        <label for="run_hour">{tmpl_var name='run_hour_txt'}</label>
        <input name="run_hour" id="run_hour" value="{tmpl_var name='run_hour'}" size="10" maxlength="255" type="text" class="textInput" />
                <p class="formHint">e.g. *, */2, 0, 10-12</p>
            </div>
      <div class="ctrlHolder">
        <label for="run_mday">{tmpl_var name='run_mday_txt'}</label>
        <input name="run_mday" id="run_mday" value="{tmpl_var name='run_mday'}" size="10" maxlength="255" type="text" class="textInput" />
                <p class="formHint">e.g. *, */4, 1-5</p>
            </div>
      <div class="ctrlHolder">
        <label for="run_month">{tmpl_var name='run_month_txt'}</label>
        <input name="run_month" id="run_month" value="{tmpl_var name='run_month'}" size="10" maxlength="255" type="text" class="textInput" />
                <p class="formHint">e.g. *, 1-6</p>
            </div>
      <div class="ctrlHolder">
        <label for="run_wday">{tmpl_var name='run_wday_txt'}</label>
        <input name="run_wday" id="run_wday" value="{tmpl_var name='run_wday'}" size="10" maxlength="255" type="text" class="textInput" />
                <p class="formHint">e.g. *, 0, 1-5</p>
            </div>
      <div class="ctrlHolder">
          <label for="command">{tmpl_var name='command_txt'}</label>
        <input name="command" id="command" value="{tmpl_var name='command'}" size="30" maxlength="255" type="text" class="textInput" />
                <p class="formHint">e.g. /var/www/clients/client1/myscript.sh or http://www.mydomain.com/path/script.php</p>
            </div>
      <div class="ctrlHolder">
                <p class="label">{tmpl_var name='active_txt'}</p>
                    <div class="multiField">
                        {tmpl_var name='active'}
                    </div>
            </div>
    </fieldset>
    <input type="hidden" name="id" value="{tmpl_var name='id'}">
    <div class="buttonHolder buttons">
      <button class="positive iconstxt icoPositive" type="button" value="{tmpl_var name='btn_save_txt'}" onClick="submitForm('pageForm','sites/cron_edit.php');"><span>{tmpl_var name='btn_save_txt'}</span></button>
      <button class="negative iconstxt icoNegative" type="button" value="{tmpl_var name='btn_cancel_txt'}" onClick="loadContent('sites/cron_list.php');"><span>{tmpl_var name='btn_cancel_txt'}</span></button>
    </div>
  </div>
</div>
interface/web/sites/templates/cron_list.htm
New file
@@ -0,0 +1,71 @@
<h2><tmpl_var name="list_head_txt"></h2>
<p><tmpl_var name="list_desc_txt"></p>
<div class="panel panel_list_cron">
  <div class="pnl_toolsarea">
    <fieldset><legend>Tools</legend>
      <div class="buttons">
        <button class="iconstxt icoAdd" type="button" onClick="loadContent('sites/cron_edit.php');">
          <span>{tmpl_var name="add_new_cron_txt"}</span>
        </button>
      </div>
    </fieldset>
  </div>
  <div class="pnl_listarea">
    <fieldset><legend><tmpl_var name="list_head_txt"></legend>
      <table class="list">
        <thead>
          <tr>
            <th class="tbl_col_active" scope="col"><tmpl_var name="active_txt"></th>
            <th class="tbl_col_server_id" scope="col"><tmpl_var name="server_id_txt"></th>
            <th class="tbl_col_run_min" scope="col"><tmpl_var name="run_min_txt"></th>
            <th class="tbl_col_run_hour" scope="col"><tmpl_var name="run_hour_txt"></th>
            <th class="tbl_col_run_mday" scope="col"><tmpl_var name="run_mday_txt"></th>
            <th class="tbl_col_run_month" scope="col"><tmpl_var name="run_month_txt"></th>
            <th class="tbl_col_run_wday" scope="col"><tmpl_var name="run_wday_txt"></th>
            <th class="tbl_col_command" scope="col"><tmpl_var name="command_txt"></th>
            <th class="tbl_col_buttons" scope="col">&nbsp;</th>
          </tr>
          <tr>
            <td class="tbl_col_active"><select name="search_active" onChange="submitForm('pageForm','sites/cron_list.php');">{tmpl_var name='search_active'}</select></td>
            <td class="tbl_col_server_id"><select name="search_server_id" onChange="submitForm('pageForm','sites/cron_list.php');">{tmpl_var name='search_server_id'}</select></td>
            <td class="tbl_col_run_min"><input type="text" name="search_run_min" size="3" value="{tmpl_var name='search_run_min'}" /></td>
            <td class="tbl_col_run_hour"><input type="text" name="search_run_hour" size="3" value="{tmpl_var name='search_run_hour'}" /></td>
            <td class="tbl_col_run_mday"><input type="text" name="search_run_mday" size="3" value="{tmpl_var name='search_run_mday'}" /></td>
            <td class="tbl_col_run_month"><input type="text" name="search_run_month" size="3" value="{tmpl_var name='search_run_month'}" /></td>
            <td class="tbl_col_run_wday"><input type="text" name="search_run_wday" size="3" value="{tmpl_var name='search_run_wday'}" /></td>
            <td class="tbl_col_command"><input type="text" name="search_command" value="{tmpl_var name='search_command'}" /></td>
            <td class="tbl_col_buttons"><div class="buttons"><button type="button" class="icons16 icoFilter" name="Filter" id="Filter" value="{tmpl_var name="filter_txt"}" onClick="submitForm('pageForm','sites/cron_list.php');"><span>{tmpl_var name="filter_txt"}</span></button></div></td>
          </tr>
        </thead>
        <tbody>
          <tmpl_loop name="records">
          <tr class="tbl_row_<tmpl_if name='__EVEN__'}even<tmpl_else>uneven</tmpl_if>">
            <td class="tbl_col_active"><a href="#" onClick="loadContent('sites/cron_edit.php?id={tmpl_var name='id'}');"><img src="themes/{tmpl_var name='theme'}/icons/{tmpl_var name='_active_'}" border="0" /></a></td>
            <td class="tbl_col_server_id"><a href="#" onClick="loadContent('sites/cron_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="server_id"}</a></td>
            <td class="tbl_col_run_min"><a href="#" onClick="loadContent('sites/cron_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="run_min"}</a></td>
            <td class="tbl_col_run_hour"><a href="#" onClick="loadContent('sites/cron_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="run_hour"}</a></td>
            <td class="tbl_col_run_mday"><a href="#" onClick="loadContent('sites/cron_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="run_mday"}</a></td>
            <td class="tbl_col_run_month"><a href="#" onClick="loadContent('sites/cron_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="run_month"}</a></td>
            <td class="tbl_col_run_wday"><a href="#" onClick="loadContent('sites/cron_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="run_wday"}</a></td>
            <td class="tbl_col_commnd"><a href="#" onClick="loadContent('sites/cron_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="command"}</a></td>
            <td class="tbl_col_buttons">
              <div class="buttons icons16">
                <a class="icons16 icoDelete" href="javascript: del_record('sites/cron_del.php?id={tmpl_var name='id'}&phpsessid={tmpl_var name='phpsessid'}','{tmpl_var name='delete_confirmation'}');"><span>{tmpl_var name='delete_txt'}</span></a>
              </div>
            </td>
          </tr>
          </tmpl_loop>
        </tbody>
        <tfoot>
          <tr>
            <td class="tbl_footer tbl_paging" colspan="9"><tmpl_var name="paging"></td>
          </tr>
        </tfoot>
      </table>
    </fieldset>
  </div>
</div>
interface/web/sites/web_domain_del.php
@@ -72,6 +72,12 @@
        foreach($records as $rec) {
            $app->db->datalogDelete('shell_user','shell_user_id',$rec['shell_user_id']);
        }
        // Delete all records that belog to this zone.
        $records = $app->db->queryAllRecords("SELECT id FROM cron WHERE parent_domain_id = '".intval($this->id)."'");
        foreach($records as $rec) {
            $app->db->datalogDelete('cron','id',$rec['id']);
        }
    }
}
server/mods-available/cron_module.inc.php
New file
@@ -0,0 +1,97 @@
<?php
/*
Copyright (c) 2007, Till Brehm, projektfarm Gmbh
Modified 2009, 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_module {
    var $module_name = 'cron_module';
    var $class_name = 'cron_module';
    var $actions_available = array(    'cron_insert',
                                    'cron_update',
                                    'cron_delete');
    //* This function is called during ispconfig installation to determine
    //  if a symlink shall be created for this plugin.
    function onInstall() {
        global $conf;
        return true;
    }
    /*
         This function is called when the module is loaded
    */
    function onLoad() {
        global $app;
        /*
        Annonce the actions that where provided by this module, so plugins
        can register on them.
        */
        $app->plugins->announceEvents($this->module_name,$this->actions_available);
        /*
        As we want to get notified of any changes on several database tables,
        we register for them.
        The following function registers the function "functionname"
         to be executed when a record for the table "dbtable" is
         processed in the sys_datalog. "classname" is the name of the
         class that contains the function functionname.
        */
        $app->modules->registerTableHook('cron',$this->module_name,'process');
    }
    /*
     This function is called when a change in one of the registered tables is detected.
     The function then raises the events for the plugins.
    */
    function process($tablename,$action,$data) {
        global $app;
        switch ($tablename) {
            case 'cron':
                if($action == 'i') $app->plugins->raiseEvent('cron_insert',$data);
                if($action == 'u') $app->plugins->raiseEvent('cron_update',$data);
                if($action == 'd') $app->plugins->raiseEvent('cron_delete',$data);
            break;
        } // end switch
    } // end function
} // end class
?>
server/plugins-available/cron_jailkit_plugin.inc.php
New file
@@ -0,0 +1,272 @@
<?php
/*
Copyright (c) 2007, Till Brehm, projektfarm Gmbh
Modified 2009, 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_jailkit_plugin {
    //* $plugin_name and $class_name have to be the same then the name of this class
    var $plugin_name = 'cron_jailkit_plugin';
    var $class_name = 'cron_jailkit_plugin';
    //* This function is called during ispconfig installation to determine
    //  if a symlink shall be created for this plugin.
    function onInstall() {
        global $conf;
        if($conf['services']['web'] == true) {
            return true;
        } else {
            return false;
        }
    }
    /*
         This function is called when the plugin is loaded
    */
    function onLoad() {
        global $app;
        /*
        Register for the events
        */
        $app->plugins->registerEvent('cron_insert', $this->plugin_name, 'insert');
        $app->plugins->registerEvent('cron_update', $this->plugin_name, 'update');
        $app->plugins->registerEvent('cron_delete', $this->plugin_name, 'delete');
    }
    //* This function is called, when a cron job is inserted in the database
    function insert($event_name,$data) {
        global $app, $conf;
        if($data["new"]["parent_domain_id"] == '') {
            $app->log("Parent domain not set",LOGLEVEL_WARN);
            return 0;
        }
        //* get data from web
        $parent_domain = $app->db->queryOneRecord("SELECT `domain_id`, `system_user`, `system_group`, `document_root`, `domain` FROM `web_domain` WHERE `domain_id` = ".intval($data["new"]["parent_domain_id"]));
        if(!$parent_domain["domain_id"]) {
            $app->log("Parent domain not found",LOGLEVEL_WARN);
            return 0;
        } elseif($parent_domain["system_user"] == 'root' or $parent_domain["system_group"] == 'root') {
            $app->log("Websites (and Crons) can not be owned by the root user or group.",LOGLEVEL_WARN);
            return 0;
        }
        $app->uses('system');
        if($app->system->is_user($parent_domain['system_user'])) {
            /**
             * Setup Jailkit Chroot System If Enabled
             */
            if ($data['new']['type'] == "chrooted")
            {
                // load the server configuration options
                $app->uses("getconf");
                $this->data = $data;
                $this->app = $app;
                $this->jailkit_config = $app->getconf->get_server_config($conf["server_id"], 'jailkit');
                $this->parent_domain = $parent_domain;
                $this->_setup_jailkit_chroot();
                //$command .= 'usermod -U '.escapeshellcmd($parent_domain['system_user']);
                //exec($command);
                $this->_add_jailkit_user();
            }
            $app->log("Jailkit Plugin (Cron) -> insert username:".$parent_domain['system_user'],LOGLEVEL_DEBUG);
        } else {
            $app->log("Jailkit Plugin (Cron) -> insert username:".$parent_domain['system_user']." skipped, the user does not exist.",LOGLEVEL_WARN);
        }
    }
    //* This function is called, when a cron job is updated in the database
    function update($event_name,$data) {
        global $app, $conf;
        if($data["new"]["parent_domain_id"] == '') {
            $app->log("Parent domain not set",LOGLEVEL_WARN);
            return 0;
        }
        //* get data from web
        $parent_domain = $app->db->queryOneRecord("SELECT `domain_id`, `system_user`, `system_group`, `document_root`, `domain` FROM `web_domain` WHERE `domain_id` = ".intval($data["new"]["parent_domain_id"]));
        if(!$parent_domain["domain_id"]) {
            $app->log("Parent domain not found",LOGLEVEL_WARN);
            return 0;
        } elseif($parent_domain["system_user"] == 'root' or $parent_domain["system_group"] == 'root') {
            $app->log("Websites (and Crons) can not be owned by the root user or group.",LOGLEVEL_WARN);
            return 0;
        }
        $app->uses('system');
        if($app->system->is_user($parent_domain['system_user'])) {
            /**
             * Setup Jailkit Chroot System If Enabled
             */
            if ($data['new']['type'] == "chrooted")
            {
                $app->log("Jailkit Plugin (Cron) -> setting up jail", LOGLEVEL_DEBUG);
                // load the server configuration options
                $app->uses("getconf");
                $this->data = $data;
                $this->app = $app;
                $this->jailkit_config = $app->getconf->get_server_config($conf["server_id"], 'jailkit');
                $this->parent_domain = $parent_domain;
                $this->_setup_jailkit_chroot();
                $this->_add_jailkit_user();
            }
            $app->log("Jailkit Plugin (Cron) -> update username:".$parent_domain['system_user'],LOGLEVEL_DEBUG);
        } else {
            $app->log("Jailkit Plugin (Cron) -> update username:".$parent_domain['system_user']." skipped, the user does not exist.",LOGLEVEL_WARN);
        }
    }
    //* This function is called, when a cron job is deleted in the database
    function delete($event_name,$data) {
        global $app, $conf;
        //* nothing to do here!
    }
    function _setup_jailkit_chroot()
    {
            //check if the chroot environment is created yet if not create it with a list of program sections from the config
            if (!is_dir($this->parent_domain['document_root'].'/etc/jailkit'))
            {
                $command = '/usr/local/ispconfig/server/scripts/create_jailkit_chroot.sh';
                $command .= ' '.escapeshellcmd($this->parent_domain['document_root']);
                $command .= ' \''.$this->jailkit_config['jailkit_chroot_app_sections'].'\'';
                exec($command);
                $this->app->log("Added jailkit chroot with command: ".$command,LOGLEVEL_DEBUG);
                //$this->_add_jailkit_programs(); // done later on
                $this->app->load('tpl');
                $tpl = new tpl();
                $tpl->newTemplate("bash.bashrc.master");
                $tpl->setVar('jailkit_chroot',true);
                $tpl->setVar('domain',$this->parent_domain['domain']);
                $tpl->setVar('home_dir',$this->_get_home_dir(""));
                $bashrc = escapeshellcmd($this->parent_domain['document_root']).'/etc/bash.bashrc';
                if(@is_file($bashrc)) exec('rm '.$bashrc);
                file_put_contents($bashrc,$tpl->grab());
                unset($tpl);
                $this->app->log("Added bashrc scrpt : ".$bashrc,LOGLEVEL_DEBUG);
                $tpl = new tpl();
                $tpl->newTemplate("motd.master");
                $tpl->setVar('domain',$this->parent_domain['domain']);
                $motd = escapeshellcmd($this->parent_domain['document_root']).'/var/run/motd';
                if(@is_file($motd)) exec('rm '.$motd);
                file_put_contents($motd,$tpl->grab());
            }
            $this->_add_jailkit_programs();
    }
    function _add_jailkit_programs()
    {
        //copy over further programs and its libraries
        $command = '/usr/local/ispconfig/server/scripts/create_jailkit_programs.sh';
        $command .= ' '.escapeshellcmd($this->parent_domain['document_root']);
        $command .= ' \''.$this->jailkit_config['jailkit_chroot_app_programs'].'\'';
        exec($command);
        $this->app->log("Added programs to jailkit chroot with command: ".$command,LOGLEVEL_DEBUG);
        $command = '/usr/local/ispconfig/server/scripts/create_jailkit_programs.sh';
        $command .= ' '.escapeshellcmd($this->parent_domain['document_root']);
        $command .= ' \''.$this->jailkit_config['jailkit_chroot_cron_programs'].'\'';
        exec($command);
        $this->app->log("Added cron programs to jailkit chroot with command: ".$command,LOGLEVEL_DEBUG);
    }
    function _add_jailkit_user()
    {
            //add the user to the chroot
            $jailkit_chroot_userhome = $this->_get_home_dir($this->parent_domain['system_user']);
            if(!is_dir($this->parent_domain['document_root'].'/etc')) mkdir($this->parent_domain['document_root'].'/etc');
            if(!is_file($this->parent_domain['document_root'].'/etc/passwd')) exec('touch '.$this->parent_domain['document_root'].'/etc/passwd');
            // IMPORTANT!
            // ALWAYS create the user. Even if the user was created before
            // if we check if the user exists, then a update (no shell -> jailkit) will not work
            // and the user has FULL ACCESS to the root of the server!
            $command = '/usr/local/ispconfig/server/scripts/create_jailkit_user.sh';
            $command .= ' '.escapeshellcmd($this->parent_domain['system_user']);
            $command .= ' '.escapeshellcmd($this->parent_domain['document_root']);
            $command .= ' '.$jailkit_chroot_userhome;
            $command .= ' '.escapeshellcmd("/bin/bash");
            exec($command);
            $this->app->log("Added jailkit user to chroot with command: ".$command,LOGLEVEL_DEBUG);
            exec("mkdir -p ".escapeshellcmd($this->parent_domain['document_root'].$jailkit_chroot_userhome));
    }
    function _get_home_dir($username)
    {
        return str_replace("[username]",escapeshellcmd($username),$this->jailkit_config["jailkit_chroot_home"]);
    }
} // end class
?>
server/plugins-available/cron_plugin.inc.php
New file
@@ -0,0 +1,212 @@
<?php
/*
Copyright (c) 2007 - 2009, Till Brehm, projektfarm Gmbh
Modified 2009, 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_plugin {
    var $plugin_name = 'cron_plugin';
    var $class_name = 'cron_plugin';
    // private variables
    var $action = '';
    //* This function is called during ispconfig installation to determine
    //  if a symlink shall be created for this plugin.
    function onInstall() {
        global $conf;
        if($conf['services']['web'] == true) {
            return true;
        } else {
            return false;
        }
    }
    /*
         This function is called when the plugin is loaded
    */
    function onLoad() {
        global $app;
        /*
        Register for the events
        */
        $app->plugins->registerEvent('cron_insert',$this->plugin_name,'insert');
        $app->plugins->registerEvent('cron_update',$this->plugin_name,'update');
        $app->plugins->registerEvent('cron_delete',$this->plugin_name,'delete');
    }
    function insert($event_name,$data) {
        global $app, $conf;
        $this->action = 'insert';
        // just run the update function
        $this->update($event_name,$data);
    }
    function update($event_name,$data) {
        global $app, $conf;
        if($this->action != 'insert') $this->action = 'update';
        // load the server configuration options
        $app->uses("getconf");
        if($data["new"]["parent_domain_id"] == '') {
            $app->log("Parent domain not set",LOGLEVEL_WARN);
            return 0;
        }
        //* get data from web
        $parent_domain = $app->db->queryOneRecord("SELECT `domain_id`, `system_user`, `system_group`, `document_root`, `hd_quota` FROM `web_domain` WHERE `domain_id` = ".intval($data["new"]["parent_domain_id"]));
        if(!$parent_domain["domain_id"]) {
            $app->log("Parent domain not found",LOGLEVEL_WARN);
            return 0;
        } elseif($parent_domain["system_user"] == 'root' or $parent_domain["system_group"] == 'root') {
            $app->log("Websites (and Crons) can not be owned by the root user or group.",LOGLEVEL_WARN);
            return 0;
        }
        // Get the client ID
        $client = $app->dbmaster->queryOneRecord("SELECT client_id FROM sys_group WHERE sys_group.groupid = ".intval($data["new"]["sys_groupid"]));
        $client_id = intval($client["client_id"]);
        unset($client);
        // Create group and user, if not exist
        $app->uses("system");
        $groupname = escapeshellcmd($parent_domain["system_group"]);
        if($parent_domain["system_group"] != '' && !$app->system->is_group($parent_domain["system_group"])) {
            exec("groupadd $groupname");
            $app->log("Adding the group: $groupname",LOGLEVEL_DEBUG);
        }
        $username = escapeshellcmd($parent_domain["system_user"]);
        if($parent_domain["system_user"] != '' && !$app->system->is_user($parent_domain["system_user"])) {
            exec("useradd -d ".escapeshellcmd($parent_domain["document_root"])." -g $groupname $username -s /bin/false");
            $app->log("Adding the user: $username",LOGLEVEL_DEBUG);
        }
        // Set the quota for the user
        if($username != '' && $app->system->is_user($username)) {
            if($parent_domain["hd_quota"] > 0){
                $blocks_soft = $parent_domain["hd_quota"] * 1024;
                $blocks_hard = $blocks_soft + 1024;
              } else {
                $blocks_soft = $blocks_hard = 0;
              }
            exec("setquota -u $username $blocks_soft $blocks_hard 0 0 -a &> /dev/null");
            exec("setquota -T -u $username 604800 604800 -a &> /dev/null");
        }
        // make temp direcory writable for the apache user and the website user
        exec("chmod 777 ".escapeshellcmd($parent_domain["document_root"]."/tmp"));
        /** TODO READ CRON MASTER **/
        $this->parent_domain = $parent_domain;
        $this->_write_crontab();
    }
    function delete($event_name,$data) {
        global $app, $conf;
        //* get data from web
        $parent_domain = $app->db->queryOneRecord("SELECT `domain_id`, `system_user`, `system_group`, `document_root`, `hd_quota` FROM `web_domain` WHERE `domain_id` = ".intval($data["old"]["parent_domain_id"]));
        if(!$parent_domain["domain_id"]) {
            $app->log("Parent domain not found",LOGLEVEL_WARN);
            return 0;
        }
        // Get the client ID
        $client = $app->dbmaster->queryOneRecord("SELECT client_id FROM sys_group WHERE sys_group.groupid = ".intval($data["old"]["sys_groupid"]));
        $client_id = intval($client["client_id"]);
        unset($client);
        /** TODO remove deleted record **/
        $this->parent_domain = $parent_domain;
        $this->_write_crontab();
    }
    function _write_crontab() {
        global $app, $conf;
        //* load the server configuration options
        $app->uses("getconf");
        $cron_config = $app->getconf->get_server_config($conf["server_id"], 'cron');
        //* try to find customer's mail address
        $cron_content = "MAILTO=''\n\n";
        //* read all active cron jobs from database and write them to file
        $cron_jobs = $app->db->queryAllRecords("SELECT `run_min`, `run_hour`, `run_mday`, `run_month`, `run_wday`, `command`, `type` FROM `cron` WHERE `parent_domain_id` = ".intval($this->parent_domain["domain_id"]) . " AND `active` = 'y'");
        if($cron_jobs && count($cron_jobs) > 0) {
            foreach($cron_jobs as $job) {
                $command = "{$job['run_min']}\t{$job['run_hour']}\t{$job['run_mday']}\t{$job['run_month']}\t{$job['run_wday']}";
                $command .= "\t{$this->parent_domain['system_user']}"; //* running as user
                if($job['type'] == 'url') {
                    $command .= "\t{$cron_config['wget']} -q -O /dev/null " . escapeshellarg($job['command']) . " >/dev/null 2>&1";
                } else {
                    if($job['type'] == 'chrooted') {
                        if(substr($job['command'], 0, strlen($this->parent_domain['document_root'])) == $this->parent_domain['document_root']) {
                            //* delete the unneeded path part
                            $job['command'] = substr($job['command'], strlen($this->parent_domain['document_root']));
                        }
                    }
                    $command .= "\t";
                    if(substr($job['command'], 0, 1) != "/") $command .= $this->parent_domain['document_root'];
                    $command .= $job['command'];
                }
                $cron_content .= $command . "\n";
            }
        }
        $cron_file = escapeshellcmd($cron_config["crontab_dir"].'/ispc_'.$this->parent_domain["system_user"]);
        file_put_contents($cron_file, $cron_content);
        $app->log("Wrote Cron file $cron_file with content:\n$cron_content",LOGLEVEL_DEBUG);
        return 0;
    }
} // end class
?>