tbrehm
2012-11-20 68ec43740a49be874d629f4d2e9be9787c3ae2ea
Merged revisions 3670-3683 from 3.0.5 stable branch.
1 files added
20 files modified
417 ■■■■ changed files
install/sql/incremental/upd_0045.sql 1 ●●●● patch | view | raw | blame | history
install/tpl/debian6_dovecot-sql.conf.master 2 ●●● patch | view | raw | blame | history
install/tpl/debian_dovecot-sql.conf.master 2 ●●● patch | view | raw | blame | history
install/tpl/fedora_dovecot-sql.conf.master 2 ●●● patch | view | raw | blame | history
install/tpl/opensuse_dovecot-sql.conf.master 2 ●●● patch | view | raw | blame | history
install/tpl/server.ini.master 26 ●●●● patch | view | raw | blame | history
interface/lib/classes/listform.inc.php 58 ●●●● patch | view | raw | blame | history
interface/lib/classes/tform.inc.php 43 ●●●● patch | view | raw | blame | history
interface/web/admin/form/server_config.tform.php 42 ●●●● patch | view | raw | blame | history
interface/web/admin/lib/lang/de_system_config.lng 4 ●●●● patch | view | raw | blame | history
interface/web/admin/lib/lang/en_server_config.lng 11 ●●●●● patch | view | raw | blame | history
interface/web/admin/lib/lang/en_system_config.lng 4 ●●●● patch | view | raw | blame | history
interface/web/admin/templates/server_config_server_edit.htm 24 ●●●●● patch | view | raw | blame | history
interface/web/admin/templates/server_config_web_edit.htm 26 ●●●●● patch | view | raw | blame | history
interface/web/sites/web_vhost_subdomain_edit.php 4 ●●●● patch | view | raw | blame | history
interface/web/themes/default/css/styles.css 29 ●●●●● patch | view | raw | blame | history
server/conf/vhost.conf.master 2 ●●● patch | view | raw | blame | history
server/cron_daily.sh 7 ●●●● patch | view | raw | blame | history
server/plugins-available/apache2_plugin.inc.php 51 ●●●●● patch | view | raw | blame | history
server/plugins-available/nginx_plugin.inc.php 75 ●●●●● patch | view | raw | blame | history
server/server.sh 2 ●●●●● patch | view | raw | blame | history
install/sql/incremental/upd_0045.sql
New file
@@ -0,0 +1 @@
UPDATE `web_domain` SET `redirect_path` = CONCAT(`redirect_path`, '/') WHERE `redirect_path` != '' AND RIGHT(`redirect_path`, 1) != '/' AND (LEFT(`redirect_path`, 7) = 'http://' OR  LEFT(`redirect_path`, 8) = 'https://' OR LEFT(`redirect_path`, 11) = '[scheme]://');
install/tpl/debian6_dovecot-sql.conf.master
@@ -13,7 +13,7 @@
connect = host={mysql_server_host} dbname={mysql_server_database} user={mysql_server_ispconfig_user} password={mysql_server_ispconfig_password}
default_pass_scheme = CRYPT
password_query = SELECT password FROM mail_user WHERE login = '%u' AND disable%Ls = 'n'
password_query = SELECT password FROM mail_user WHERE (login = '%u' OR email = '%u') AND disable%Ls = 'n'
user_query = SELECT email as user, maildir as home, CONCAT('maildir:', maildir, '/Maildir') as mail, uid, gid, CONCAT('*:storage=', quota, 'B') AS quota_rule, CONCAT(maildir, '/.sieve') as sieve FROM mail_user WHERE (login = '%u' OR email = '%u') AND disable%Ls = 'n'
# The iterate_query is required for the doveadm command only and works only on dovecot 2 servers.
install/tpl/debian_dovecot-sql.conf.master
@@ -120,7 +120,7 @@
connect = host={mysql_server_host} dbname={mysql_server_database} user={mysql_server_ispconfig_user} password={mysql_server_ispconfig_password}
default_pass_scheme = CRYPT
password_query = SELECT password FROM mail_user WHERE login = '%u' AND disable%Ls = 'n'
password_query = SELECT password FROM mail_user WHERE (login = '%u' OR email = '%u') AND disable%Ls = 'n'
user_query = SELECT email as user, maildir as home, CONCAT('maildir:', maildir, '/Maildir') as mail, uid, gid, CONCAT('*:storage=', quota, 'B') AS quota_rule, CONCAT(maildir, '/.sieve') as sieve FROM mail_user WHERE (login = '%u' OR email = '%u') AND disable%Ls = 'n'
# The iterate_query is required for the doveadm command only and works only on dovecot 2 servers.
install/tpl/fedora_dovecot-sql.conf.master
@@ -133,7 +133,7 @@
connect = host={mysql_server_host} dbname={mysql_server_database} user={mysql_server_ispconfig_user} password={mysql_server_ispconfig_password}
default_pass_scheme = CRYPT
password_query = SELECT password FROM mail_user WHERE login = '%u' AND disable%Ls = 'n'
password_query = SELECT password FROM mail_user WHERE (login = '%u' OR email = '%u') AND disable%Ls = 'n'
user_query = SELECT email as user, maildir as home, CONCAT('maildir:', maildir, '/Maildir') as mail, uid, gid, CONCAT('*:storage=', quota, 'B') AS quota_rule, CONCAT(maildir, '/.sieve') as sieve FROM mail_user WHERE (login = '%u' OR email = '%u') AND disable%Ls = 'n'
# The iterate_query is required for the doveadm command only and works only on dovecot 2 servers.
install/tpl/opensuse_dovecot-sql.conf.master
@@ -133,7 +133,7 @@
connect = host={mysql_server_host} dbname={mysql_server_database} user={mysql_server_ispconfig_user} password={mysql_server_ispconfig_password}
default_pass_scheme = CRYPT
password_query = SELECT password FROM mail_user WHERE login = '%u' AND disable%Ls = 'n'
password_query = SELECT password FROM mail_user WHERE (login = '%u' OR email = '%u') AND disable%Ls = 'n'
user_query = SELECT email as user, maildir as home, CONCAT('maildir:', maildir, '/Maildir') as mail, uid, gid, CONCAT('*:storage=', quota, 'B') AS quota_rule, CONCAT(maildir, '/.sieve') as sieve FROM mail_user WHERE (login = '%u' OR email = '%u') AND disable%Ls = 'n'
# The iterate_query is required for the doveadm command only and works only on dovecot 2 servers.
install/tpl/server.ini.master
@@ -5,12 +5,13 @@
[server]
auto_network_configuration=n
ip_address=0.0.0.0
netmask=255.255.255.0
gateway=0.0.0.0
hostname=server1.domain.tld
nameservers=8.8.8.8,8.8.4.4
auto_network_configuration=n
ip_address=0.0.0.0
netmask=255.255.255.0
v6_prefix=
gateway=0.0.0.0
hostname=server1.domain.tld
nameservers=8.8.8.8,8.8.4.4
firewall=bastille
loglevel=2
backup_dir=/var/backup
@@ -40,12 +41,13 @@
[web]
server_type=apache
website_basedir=/var/www
website_path=/var/www/clients/client[client_id]/web[website_id]
website_symlinks=/var/www/[website_domain]/:/var/www/clients/client[client_id]/[website_domain]/
website_symlinks_rel=n
vhost_conf_dir=/etc/apache2/sites-available
vhost_conf_enabled_dir=/etc/apache2/sites-enabled
nginx_vhost_conf_dir=/etc/nginx/sites-available
website_path=/var/www/clients/client[client_id]/web[website_id]
website_symlinks=/var/www/[website_domain]/:/var/www/clients/client[client_id]/[website_domain]/
website_symlinks_rel=n
vhost_rewrite_v6=n
vhost_conf_dir=/etc/apache2/sites-available
vhost_conf_enabled_dir=/etc/apache2/sites-enabled
nginx_vhost_conf_dir=/etc/nginx/sites-available
nginx_vhost_conf_enabled_dir=/etc/nginx/sites-enabled
security_level=20
user=www-data
interface/lib/classes/listform.inc.php
@@ -243,21 +243,65 @@
    public function getPagingHTML($vars)
    {
        global $app;
        $content = '<a href="'."javascript:loadContent('".$vars['list_file'].'?page=0'.$vars['page_params']."');".'">'
                    .'<img src="themes/'.$_SESSION['s']['theme'].'/icons/x16/arrow_stop_180.png"></a> &nbsp; ';
        // we want to show at max 17 page numbers (8 left, current, 8 right)
        $show_pages_count = 17;
        $show_pages = array(0); // first page
        if($vars['pages'] > 0) $show_pages[] = $vars['pages']; // last page
        for($p = $vars['page'] - 2; $p <= $vars['page'] + 2; $p++) { // surrounding pages
            if($p > 0 && $p < $vars['pages']) $show_pages[] = $p;
        }
        $l_start = $vars['page'] - 13;
        $l_start -= ($l_start % 10) + 1;
        $h_end = $vars['page'] + 23;
        $h_end -= ($h_end % 10) + 1;
        for($p = $l_start; $p <= $h_end; $p += 10) { // surrounding pages
            if($p > 0 && $p < $vars['pages'] && !in_array($p, $show_pages, true) && count($show_pages) < $show_pages_count) $show_pages[] = $p;
        }
        $l_start = $vars['page'] - 503;
        $l_start -= ($l_start % 100) + 1;
        $h_end = $vars['page'] + 603;
        $h_end -= ($h_end % 100) + 1;
        for($p = $l_start; $p <= $h_end; $p += 100) { // surrounding pages
            if($p > 0 && $p < $vars['pages'] && !in_array($p, $show_pages, true) && count($show_pages) < $show_pages_count) $show_pages[] = $p;
        }
        $l_start = $vars['page'] - 203;
        $l_start -= ($l_start % 25) + 1;
        $h_end = $vars['page'] + 228;
        $h_end -= ($h_end % 25) + 1;
        for($p = $l_start; $p <= $h_end; $p += 25) { // surrounding pages
            if($p > 0 && $p < $vars['pages'] && abs($p - $vars['page']) > 30 && !in_array($p, $show_pages, true) && count($show_pages) < $show_pages_count) $show_pages[] = $p;
        }
        sort($show_pages);
        $show_pages = array_unique($show_pages);
        //* Show Back 
        if(isset($vars['show_page_back']) && $vars['show_page_back'] == 1){
            $content .= '<a href="'."javascript:loadContent('".$vars['list_file'].'?page='.$vars['last_page'].$vars['page_params']."');".'">'
        $content = '<a class="btn-page first-page" href="'."javascript:loadContent('".$vars['list_file'].'?page=0'.$vars['page_params']."');".'">'
                    .'<img src="themes/'.$_SESSION['s']['theme'].'/icons/x16/arrow_stop_180.png"></a> &nbsp; ';
            $content .= '<a class="btn-page previous-page" href="'."javascript:loadContent('".$vars['list_file'].'?page='.$vars['last_page'].$vars['page_params']."');".'">'
                        .'<img src="themes/'.$_SESSION['s']['theme'].'/icons/x16/arrow_180.png"></a> &nbsp; ';
        }
        $content .= ' '.$this->lng('page_txt').' '.$vars['next_page'].' '.$this->lng('page_of_txt').' '.$vars['max_pages'].' &nbsp; ';
        $content .= ' '.$this->lng('page_txt').' ';
        $prev = -1;
        foreach($show_pages as $p) {
            if($prev != -1 && $p > $prev + 1) $content .= '<span class="page-spacer">...</span>';
            $content .= '<a class="link-page' . ($p == $vars['page'] ? ' current-page' : '') . '" href="'."javascript:loadContent('".$vars['list_file'].'?page='.$p.$vars['page_params']."');".'">'. ($p+1) .'</a>';
            $prev = $p;
        }
        //.$vars['next_page'].' '.$this->lng('page_of_txt').' '.$vars['max_pages'].' &nbsp; ';
        //* Show Next
        if(isset($vars['show_page_next']) && $vars['show_page_next'] == 1){
            $content .= '<a href="'."javascript:loadContent('".$vars['list_file'].'?page='.$vars['next_page'].$vars['page_params']."');".'">'
            $content .= '<a class="btn-page next-page" href="'."javascript:loadContent('".$vars['list_file'].'?page='.$vars['next_page'].$vars['page_params']."');".'">'
                        .'<img src="themes/'.$_SESSION['s']['theme'].'/icons/x16/arrow.png"></a> &nbsp; ';
        }
        $content .= '<a href="'."javascript:loadContent('".$vars['list_file'].'?page='.$vars['pages'].$vars['page_params']."');".'">'
        $content .= '<a class="btn-page last-page" href="'."javascript:loadContent('".$vars['list_file'].'?page='.$vars['pages'].$vars['page_params']."');".'">'
                    .'<img src="themes/'.$_SESSION['s']['theme'].'/icons/x16/arrow_stop.png"></a>';
        }
        return $content;
    }
        
interface/lib/classes/tform.inc.php
@@ -884,12 +884,43 @@
                                             $this->errorMessage .= $this->wordbook[$errmsg]."<br />\r\n";
                                          } else {
                                             $this->errorMessage .= $errmsg."<br />\r\n";
                                          }
                                        }
                                break;
                                case 'ISIPV4':
                                $vip=1;
                                if(preg_match("/^[0-9]{1,3}(\.)[0-9]{1,3}(\.)[0-9]{1,3}(\.)[0-9]{1,3}$/", $field_value)){
                                          }
                                        }
                                break;
                case 'ISV6PREFIX':
                    $v6_prefix_ok = 0;
                    $explode_field_value = explode(':',$field_value);
                    if ($explode_field_value[count($explode_field_value)-1]=='' && $explode_field_value[count($explode_field_value)-2]=='' ){
                            if ( count($explode_field_value) <= 9 ) {
                                    if(filter_var(substr($field_value,0,strlen($field_value)-2),FILTER_VALIDATE_IP,FILTER_FLAG_IPV6) or filter_var(substr($field_value,0,strlen($field_value)-2).'::0',FILTER_VALIDATE_IP,FILTER_FLAG_IPV6) or filter_var(substr($field_value,0,strlen($field_value)-2).':0',FILTER_VALIDATE_IP,FILTER_FLAG_IPV6) ) {
                                            $v6_prefix_ok = 1;
                                    }
                            }
                    } else {
                        $v6_prefix_ok = 2;
                    }
                    // check subnet against defined server-ipv6
                    $sql_v6 = $app->db->queryOneRecord("SELECT ip_address FROM server_ip WHERE ip_type = 'IPv6' AND virtualhost = 'y' LIMIT 0,1");
                    $sql_v6_explode=explode(':',$sql_v6['ip_address']);
                    if ( count($sql_v6_explode) < count($explode_field_value) && isset($sql_v6['ip_address']) )  {
                        $v6_prefix_ok = 3;
                    }
                    if($v6_prefix_ok == 0) {
                        $errmsg = $validator['errmsg'];
                    }
                    if($v6_prefix_ok == 2) {
                        $errmsg = 'IPv6 Prefix must end with ::';
                    }
                    if($v6_prefix_ok == 3) {
                        $errmsg = 'IPv6 Prefix too long (according to Server IP Addresses)';
                    }
                    if($v6_prefix_ok <> 1){
                        $this->errorMessage .= $errmsg."<br />\r\n";
                    }
                break;
                                case 'ISIPV4':
                                $vip=1;
                                if(preg_match("/^[0-9]{1,3}(\.)[0-9]{1,3}(\.)[0-9]{1,3}(\.)[0-9]{1,3}$/", $field_value)){
                                $groups=explode(".",$field_value);
                                foreach($groups as $group){
                                    if($group<0 OR $group>255)
interface/web/admin/form/server_config.tform.php
@@ -83,12 +83,20 @@
                    'errmsg' => 'netmask_error_wrong'),
            ),
            'value' => '',
            'width' => '15',
            'maxlength' => '255'
        ),
        'gateway' => array(
            'datatype' => 'VARCHAR',
            'formtype' => 'TEXT',
            'width' => '15',
            'maxlength' => '255'
        ),
        'v6_prefix' => array(
            'datatype' => 'VARCHAR',
            'formtype' => 'TEXT',
                        'validators' => array(0 => array('type' => 'ISV6PREFIX',
                                        'errmsg' => 'v6_prefix_wrong'),
                        ),
        'default' => ''
        ),
        'gateway' => array(
            'datatype' => 'VARCHAR',
            'formtype' => 'TEXT',
            'default' => '192.168.0.1',
            'validators' => array(0 => array('type' => 'ISIPV4',
                    'errmsg' => 'gateway_error_wrong'),
@@ -402,12 +410,22 @@
            'formtype' => 'TEXT',
            'default' => '',
            'value' => '',
            'width' => '40',
            'maxlength' => '255'
        ),
        'vhost_conf_dir' => array(
            'datatype' => 'VARCHAR',
            'formtype' => 'TEXT',
            'width' => '40',
            'maxlength' => '255'
        ),
'vhost_rewrite_v6' => array (
'datatype' => 'VARCHAR',
'formtype' => 'CHECKBOX',
'default' => 'n',
'value' => array(0 => 'n',1 => 'y')
),
        'vhost_conf_dir' => array(
            'datatype' => 'VARCHAR',
            'formtype' => 'TEXT',
            'default' => '',
            'validators' => array(0 => array('type' => 'NOTEMPTY',
                    'errmsg' => 'vhost_conf_dir_error_empty'),
interface/web/admin/lib/lang/de_system_config.lng
@@ -24,8 +24,8 @@
$wb['dashboard_atom_url_client_txt'] = 'Dashboard atom feed URL (für Kunden)';
$wb['webdavuser_prefix_txt'] = 'WebDAV Benutzer Präfix';
$wb['webdavuser_prefix_error_regex'] = 'Zeichen nicht zulässig im WebDAV Benutzer Präfix.';
$wb['use_domain_module_txt'] = 'Das Domain Modul benutzen, um neue Domains hinzuzufügen';
$wb['use_domain_module_hint'] = 'Falls Sie dieses Modul benutzen, können Ihre Kunden nur eine der Domains auswählen, die der Admin für sie angelegt hat. Die Kunden können das Domain-Feld nicht frei editieren. Sie müssen sich neu einloggen, wenn Sie diesen Wert Ã¤ndern.';
$wb['use_domain_module_txt'] = 'Domain Limits im Kundenmodul benutzen, um neue Domains hinzuzufügen';
$wb['use_domain_module_hint'] = 'Falls Sie die Domain Limits benutzen, können Ihre Kunden nur eine der Domains auswählen, die der Admin für sie angelegt hat. Die Kunden können das Domain-Feld nicht frei editieren. Sie müssen sich neu einloggen, wenn Sie diesen Wert Ã¤ndern.';
$wb['new_domain_txt'] = 'HTML Text zum Anlegen einer neuen Domain';
$wb['webftp_url_txt'] = 'WebFTP URL';
$wb['enable_custom_login_txt'] = 'Abweichenden Login Namen erlauben';
interface/web/admin/lib/lang/en_server_config.lng
@@ -167,7 +167,10 @@
$wb["firewall_txt"] = 'Firewall';
$wb["mailbox_quota_stats_txt"] = 'Mailbox quota statistics';
$wb["enable_ip_wildcard_txt"] = 'Enable IP wildcard (*)';
$wb["web_folder_protection_txt"] = 'Make web folders immutable (extended attributes)';
$wb["overtraffic_notify_admin_txt"] = 'Send overtraffic notification to admin';
$wb["overtraffic_notify_client_txt"] = 'Send overtraffic notification to client';
?>
$wb["web_folder_protection_txt"] = 'Make web folders immutable (extended attributes)';
$wb["overtraffic_notify_admin_txt"] = 'Send overtraffic notification to admin';
$wb["overtraffic_notify_client_txt"] = 'Send overtraffic notification to client';
$wb["v6_prefix_txt"] = 'IPv6 Prefix';
$wb["vhost_rewrite_v6_txt"] = 'Rewrite IPv6 on Mirror';
$wb["v6_prefix_wrong"] = 'Invalid v6 Netmask format.';
?>
interface/web/admin/lib/lang/en_system_config.lng
@@ -27,8 +27,8 @@
$wb["mailmailinglist_link_txt"] = 'Link to mailing list in Mailing list list';
$wb["mailmailinglist_url_txt"] = 'Mailing list URL';
$wb["phpmyadmin_url_txt"] = 'PHPMyAdmin URL';
$wb["use_domain_module_txt"] = 'Use the domain-module to add new domains';
$wb["use_domain_module_hint"] = 'If you use this module, your customers can only select one of the domains the admin creates for them. They cannot freely edit the domain-field. You have to re-login after changing this value, to make the changes visible.';
$wb["use_domain_module_txt"] = 'Use the domain limits in client module to add new domains';
$wb["use_domain_module_hint"] = 'If you use the domain limits, your customers can only select one of the domains the admin creates for them. They cannot freely edit the domain-field. You have to re-login after changing this value, to make the changes visible.';
$wb["new_domain_txt"] = 'HTML to create a new domain';
$wb["webftp_url_txt"] = 'WebFTP URL';
$wb['admin_mail_txt'] = 'Administrator\'s e-mail';
interface/web/admin/templates/server_config_server_edit.htm
@@ -16,12 +16,16 @@
                <input name="ip_address" id="ip_address" value="{tmpl_var name='ip_address'}" size="15" maxlength="255" type="text" class="textInput formLengthIPv4" />
            </div>
            <div class="ctrlHolder">
                <label for="netmask">{tmpl_var name='netmask_txt'}</label>
                <input name="netmask" id="netmask" value="{tmpl_var name='netmask'}" size="15" maxlength="255" type="text" class="textInput formLengthIPv4" />
            </div>
            <div class="ctrlHolder">
                <label for="gateway">{tmpl_var name='gateway_txt'}</label>
                <input name="gateway" id="gateway" value="{tmpl_var name='gateway'}" size="15" maxlength="255" type="text" class="textInput formLengthIPv4" />
                <label for="netmask">{tmpl_var name='netmask_txt'}</label>
                <input name="netmask" id="netmask" value="{tmpl_var name='netmask'}" size="15" maxlength="255" type="text" class="textInput formLengthIPv4" />
            </div>
       <div class="ctrlHolder">
        <label for="v6_prefix">{tmpl_var name='v6_prefix_txt'}</label>
        <input name="v6_prefix" id="v6_prefix" value="{tmpl_var name='v6_prefix'}" size="15" maxlength="255" type="text" class="textInput formLengthIPv4" />
           </div>
            <div class="ctrlHolder">
                <label for="gateway">{tmpl_var name='gateway_txt'}</label>
                <input name="gateway" id="gateway" value="{tmpl_var name='gateway'}" size="15" maxlength="255" type="text" class="textInput formLengthIPv4" />
            </div>
            <div class="ctrlHolder">
                <label for="hostname">{tmpl_var name='hostname_txt'}</label>
@@ -61,7 +65,7 @@
        <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>
        </div>
    </div>
</div>
interface/web/admin/templates/server_config_web_edit.htm
@@ -32,12 +32,18 @@
                </div>
            </div>
            <div class="ctrlHolder">
                <label for="website_autoalias">{tmpl_var name='website_autoalias_txt'}</label>
                <input name="website_autoalias" id="website_autoalias" value="{tmpl_var name='website_autoalias'}" size="40" maxlength="255" type="text" class="textInput" />&nbsp;{tmpl_var name='website_autoalias_note_txt'} <a href="javascript:void(0);" class="addPlaceholder">[client_id]</a>, <a href="javascript:void(0);" class="addPlaceholder">[client_username]</a>, <a href="javascript:void(0);" class="addPlaceholder">[website_id]</a>, <a href="javascript:void(0);" class="addPlaceholder">[website_domain]</a>
            </div>
            <div class="ctrlHolder apache">
                <label for="vhost_conf_dir">{tmpl_var name='vhost_conf_dir_txt'}</label>
                <input name="vhost_conf_dir" id="vhost_conf_dir" value="{tmpl_var name='vhost_conf_dir'}" size="40" maxlength="255" type="text" class="textInput" />
                <label for="website_autoalias">{tmpl_var name='website_autoalias_txt'}</label>
                <input name="website_autoalias" id="website_autoalias" value="{tmpl_var name='website_autoalias'}" size="40" maxlength="255" type="text" class="textInput" />&nbsp;{tmpl_var name='website_autoalias_note_txt'} <a href="javascript:void(0);" class="addPlaceholder">[client_id]</a>, <a href="javascript:void(0);" class="addPlaceholder">[client_username]</a>, <a href="javascript:void(0);" class="addPlaceholder">[website_id]</a>, <a href="javascript:void(0);" class="addPlaceholder">[website_domain]</a>
            </div>
        <div class="ctrlHolder apache">
            <label for="vhost_rewrite_v6">{tmpl_var name='vhost_rewrite_v6_txt'}</label>
            <div class="multiField">
                {tmpl_var name='vhost_rewrite_v6'}
            </div>
        </div>
            <div class="ctrlHolder apache">
                <label for="vhost_conf_dir">{tmpl_var name='vhost_conf_dir_txt'}</label>
                <input name="vhost_conf_dir" id="vhost_conf_dir" value="{tmpl_var name='vhost_conf_dir'}" size="40" maxlength="255" type="text" class="textInput" />
            </div>
            <div class="ctrlHolder apache">
                <label for="vhost_conf_enabled_dir">{tmpl_var name='vhost_conf_enabled_dir_txt'}</label>
@@ -250,7 +256,7 @@
            jQuery('.apache').hide();
        } else {
            jQuery('.nginx').hide();
            jQuery('.apache').show();
        }
    }
</script>
            jQuery('.apache').show();
        }
    }
</script>
interface/web/sites/web_vhost_subdomain_edit.php
@@ -369,6 +369,8 @@
            
            
            $this->dataRecord['web_folder'] = strtolower($this->dataRecord['web_folder']);
            if(substr($this->dataRecord['web_folder'], 0, 1) === '/') $this->dataRecord['web_folder'] = substr($this->dataRecord['web_folder'], 1);
            if(substr($this->dataRecord['web_folder'], -1) === '/') $this->dataRecord['web_folder'] = substr($this->dataRecord['web_folder'], 0, -1);
            $forbidden_folders = array('', 'cgi-bin', 'log', 'private', 'ssl', 'tmp', 'webdav');
            $check_folder = strtolower($this->dataRecord['web_folder']);
            if(substr($check_folder, 0, 1) === '/') $check_folder = substr($check_folder, 1); // strip / at beginning to check against forbidden entries
@@ -377,10 +379,12 @@
                $app->tform->errorMessage .= $app->tform->lng("web_folder_invalid_txt")."<br>";
            }
            // check for duplicate folder usage
            /*
            $check = $app->db->queryOneRecord("SELECT COUNT(*) as `cnt` FROM `web_domain` WHERE `type` = 'vhostsubdomain' AND `parent_domain_id` = '" . $app->functions->intval($this->dataRecord['parent_domain_id']) . "' AND `web_folder` = '" . $app->db->quote($this->dataRecord['web_folder']) . "' AND `domain_id` != '" . $app->functions->intval($this->id) . "'");
            if($check && $check['cnt'] > 0) {
                $app->tform->errorMessage .= $app->tform->lng("web_folder_unique_txt")."<br>";
            }
            */
        } else {
            $this->dataRecord["domain"] = $this->dataRecord["domain"].'.'.$parent_domain["domain"];
        }
interface/web/themes/default/css/styles.css
@@ -1787,4 +1787,31 @@
.ui-combobox-toggle { position: absolute !important; top: 0; bottom: 0; margin-left: -1px; padding: 1px !important; background: none repeat scroll 0 0 #FFFFFF !important; border: 1px solid #DFDFDF !important;}
.ui-combobox-input { background: none repeat scroll 0 0 #FFFFFF !important; border: 1px solid #DFDFDF !important; padding: 1px; font-weight: normal !important; }
.panel_install_package .ui-combobox { float: left; }
.clear-float { clear: both; }
.clear-float { clear: both; }
a.link-page, span.page-spacer {
    display: inline-block;
    text-align: center;
    padding: 2px;
    line-height: 16px;
    text-decoration: none !important;
    color: inherit !important;
    min-width: 16px;
}
a.link-page {
    border: 1px solid #FFFFFF;
    margin: 0 5px;
}
a.link-page:hover {
    background-color: #DFDFDF;
}
span.page-spacer {
    margin: 0 -5px;
}
a.link-page.current-page {
    background-color: #DFDFDF;
    font-weight: bold;
}
server/conf/vhost.conf.master
@@ -266,7 +266,7 @@
        RewriteCond %{REQUEST_URI} !^/webdav/
        RewriteCond %{REQUEST_URI} !^<tmpl_var name='rewrite_target'>
</tmpl_if>
        RewriteRule   ^/(.*)$ <tmpl_var name='rewrite_target'>$1  <tmpl_var name='rewrite_type'>
        RewriteRule   ^/(.*)$ <tmpl_var name='rewrite_target'><tmpl_if name="rewrite_add_path" op="==" value="y">$1</tmpl_if>  <tmpl_var name='rewrite_type'>
</tmpl_loop>
</tmpl_if>
server/cron_daily.sh
@@ -11,9 +11,6 @@
/usr/bin/php -q /usr/local/ispconfig/server/cron_daily.php
if [ -f /usr/local/ispconfig/interface/web/billing/cron/create_recurring_invoices_cron.php ]; then
        /usr/bin/php -q /usr/local/ispconfig/interface/web/billing/cron/create_recurring_invoices_cron.php
fi
if [ -f /usr/local/ispconfig/interface/web/billing/cron/recurring_items_reminders.php ]; then
        /usr/bin/php -q /usr/local/ispconfig/interface/web/billing/cron/recurring_items_reminders.php
if [ -f /usr/local/ispconfig/server/cron_daily_billing.sh ]; then
        /usr/local/ispconfig/server/cron_daily_billing.sh
fi
server/plugins-available/apache2_plugin.inc.php
@@ -888,26 +888,30 @@
                        'rewrite_type'         => ($data['new']['redirect_type'] == 'no')?'':'['.$data['new']['redirect_type'].']',
                        'rewrite_target'     => $rewrite_target,
                        'rewrite_target_ssl' => $rewrite_target_ssl,
                        'rewrite_is_url'    => ($this->_is_url($rewrite_target) ? 'y' : 'n'));
                        'rewrite_is_url'    => ($this->_is_url($rewrite_target) ? 'y' : 'n'),
                        'rewrite_add_path' => (substr($rewrite_target, -1) == '/' ? 'y' : 'n'));
                    $rewrite_rules[] = array(    'rewrite_domain'     => '^' . $this->_rewrite_quote('www.'.$data['new']['domain']),
                            'rewrite_type'         => ($data['new']['redirect_type'] == 'no')?'':'['.$data['new']['redirect_type'].']',
                            'rewrite_target'     => $rewrite_target,
                            'rewrite_target_ssl' => $rewrite_target_ssl,
                            'rewrite_is_url'    => ($this->_is_url($rewrite_target) ? 'y' : 'n'));
                            'rewrite_is_url'    => ($this->_is_url($rewrite_target) ? 'y' : 'n'),
                            'rewrite_add_path' => (substr($rewrite_target, -1) == '/' ? 'y' : 'n'));
                    break;
                case '*':
                    $rewrite_rules[] = array(    'rewrite_domain'     => '(^|\.)'.$this->_rewrite_quote($data['new']['domain']),
                        'rewrite_type'         => ($data['new']['redirect_type'] == 'no')?'':'['.$data['new']['redirect_type'].']',
                        'rewrite_target'     => $rewrite_target,
                        'rewrite_target_ssl' => $rewrite_target_ssl,
                        'rewrite_is_url'    => ($this->_is_url($rewrite_target) ? 'y' : 'n'));
                        'rewrite_is_url'    => ($this->_is_url($rewrite_target) ? 'y' : 'n'),
                        'rewrite_add_path' => (substr($rewrite_target, -1) == '/' ? 'y' : 'n'));
                    break;
                default:
                    $rewrite_rules[] = array(    'rewrite_domain'     => '^'.$this->_rewrite_quote($data['new']['domain']),
                        'rewrite_type'         => ($data['new']['redirect_type'] == 'no')?'':'['.$data['new']['redirect_type'].']',
                        'rewrite_target'     => $rewrite_target,
                        'rewrite_target_ssl' => $rewrite_target_ssl,
                        'rewrite_is_url'    => ($this->_is_url($rewrite_target) ? 'y' : 'n'));
                        'rewrite_is_url'    => ($this->_is_url($rewrite_target) ? 'y' : 'n'),
                        'rewrite_add_path' => (substr($rewrite_target, -1) == '/' ? 'y' : 'n'));
            }
        }
        
@@ -983,19 +987,22 @@
                                'rewrite_type'         => ($alias['redirect_type'] == 'no')?'':'['.$alias['redirect_type'].']',
                                'rewrite_target'     => $rewrite_target,
                                'rewrite_target_ssl' => $rewrite_target_ssl,
                                'rewrite_is_url'    => ($this->_is_url($rewrite_target) ? 'y' : 'n'));
                                'rewrite_is_url'    => ($this->_is_url($rewrite_target) ? 'y' : 'n'),
                                'rewrite_add_path' => (substr($rewrite_target, -1) == '/' ? 'y' : 'n'));
                            $rewrite_rules[] = array(    'rewrite_domain'     => '^' . $this->_rewrite_quote('www.'.$alias['domain']),
                                    'rewrite_type'         => ($alias['redirect_type'] == 'no')?'':'['.$alias['redirect_type'].']',
                                    'rewrite_target'     => $rewrite_target,
                                    'rewrite_target_ssl' => $rewrite_target_ssl,
                                    'rewrite_is_url'    => ($this->_is_url($rewrite_target) ? 'y' : 'n'));
                                    'rewrite_is_url'    => ($this->_is_url($rewrite_target) ? 'y' : 'n'),
                                    'rewrite_add_path' => (substr($rewrite_target, -1) == '/' ? 'y' : 'n'));
                            break;
                        case '*':
                            $rewrite_rules[] = array(    'rewrite_domain'     => '(^|\.)'.$this->_rewrite_quote($alias['domain']),
                                'rewrite_type'         => ($alias['redirect_type'] == 'no')?'':'['.$alias['redirect_type'].']',
                                'rewrite_target'     => $rewrite_target,
                                'rewrite_target_ssl' => $rewrite_target_ssl,
                                'rewrite_is_url'    => ($this->_is_url($rewrite_target) ? 'y' : 'n'));
                                'rewrite_is_url'    => ($this->_is_url($rewrite_target) ? 'y' : 'n'),
                                'rewrite_add_path' => (substr($rewrite_target, -1) == '/' ? 'y' : 'n'));
                            break;
                        default:
                            if(substr($alias['domain'], 0, 2) === '*.') $domain_rule = '(^|\.)'.$this->_rewrite_quote(substr($alias['domain'], 2));
@@ -1004,7 +1011,8 @@
                                'rewrite_type'         => ($alias['redirect_type'] == 'no')?'':'['.$alias['redirect_type'].']',
                                'rewrite_target'     => $rewrite_target,
                                'rewrite_target_ssl' => $rewrite_target_ssl,
                                'rewrite_is_url'    => ($this->_is_url($rewrite_target) ? 'y' : 'n'));
                                'rewrite_is_url'    => ($this->_is_url($rewrite_target) ? 'y' : 'n'),
                                'rewrite_add_path' => (substr($rewrite_target, -1) == '/' ? 'y' : 'n'));
                    }
                }
            }
@@ -1266,14 +1274,25 @@
            } else {
                $vhosts[] = array('ip_address' => $data['new']['ip_address'], 'ssl_enabled' => 1, 'port' => '443');
            }
            $app->log('Enable SSL for: '.$domain,LOGLEVEL_DEBUG);
        }
        //* Add vhost for IPv6 IP
        if($data['new']['ipv6_address'] != '') {
            if(count($rewrite_rules) > 0){
                $vhosts[] = array('ip_address' => '['.$data['new']['ipv6_address'].']', 'ssl_enabled' => 0, 'port' => 80, 'redirects' => $rewrite_rules);
            } else {
            $app->log('Enable SSL for: '.$domain,LOGLEVEL_DEBUG);
        }
    //* Add vhost for IPv6 IP
    if($data['new']['ipv6_address'] != '') {
        if ($conf['serverconfig']['web']['vhost_rewrite_v6'] == 'y') {
            if (isset($conf['serverconfig']['server']['v6_prefix']) && $conf['serverconfig']['server']['v6_prefix'] <> '') {
                $explode_v6prefix=explode(':',$conf['serverconfig']['server']['v6_prefix']);
                $explode_v6=explode(':',$data['new']['ipv6_address']);
                for ( $i = 0; $i <= count($explode_v6prefix)-3; $i++ ) {
                        $explode_v6[$i] = $explode_v6prefix[$i];
                }
                $data['new']['ipv6_address'] = implode(':',$explode_v6);
            }
        }
            if(count($rewrite_rules) > 0){
                $vhosts[] = array('ip_address' => '['.$data['new']['ipv6_address'].']', 'ssl_enabled' => 0, 'port' => 80, 'redirects' => $rewrite_rules);
            } else {
                $vhosts[] = array('ip_address' => '['.$data['new']['ipv6_address'].']', 'ssl_enabled' => 0, 'port' => 80);
            }
        
server/plugins-available/nginx_plugin.inc.php
@@ -833,7 +833,21 @@
        $vhost_data['web_basedir'] = $web_config['website_basedir'];
        
        // IPv6
        if($data['new']['ipv6_address'] != '') $tpl->setVar('ipv6_enabled', 1);
        if($data['new']['ipv6_address'] != ''){
            $tpl->setVar('ipv6_enabled', 1);
            if ($conf['serverconfig']['web']['vhost_rewrite_v6'] == 'y') {
                if (isset($conf['serverconfig']['server']['v6_prefix']) && $conf['serverconfig']['server']['v6_prefix'] <> '') {
                    $explode_v6prefix=explode(':',$conf['serverconfig']['server']['v6_prefix']);
                    $explode_v6=explode(':',$data['new']['ipv6_address']);
                    for ( $i = 0; $i <= count($explode_v6prefix)-3; $i++ ) {
                        $explode_v6[$i] = $explode_v6prefix[$i];
                    }
                    $data['new']['ipv6_address'] = implode(':',$explode_v6);
                    $vhost_data['ipv6_address'] = $data['new']['ipv6_address'];
                }
            }
        }
        
        // PHP-FPM
        // Support for multiple PHP versions
@@ -1619,8 +1633,63 @@
            if($data['old']['type'] == 'vhost' || $data['old']['type'] == 'vhostsubdomain') {
                $docroot = escapeshellcmd($data['old']['document_root']);
                if($docroot != '' && !stristr($docroot,'..')) {
                    if($data['old']['type'] == 'vhost') exec('rm -rf '.$docroot);
                    elseif(!stristr($data['old']['web_folder'], '..')) exec('rm -rf '.$docroot.'/'.$web_folder);
                    if($data['old']['type'] == 'vhost') {
                        // this is a vhost - we delete everything in here.
                        exec('rm -rf '.$docroot);
                    } elseif(!stristr($data['old']['web_folder'], '..')) {
                        // this is a vhost subdomain
                        // IMPORTANT: do some folder checks before we delete this!
                        $do_delete = true;
                        $delete_folder = preg_replace('/[\/]{2,}/', '/', $web_folder); // replace / occuring multiple times
                        if(substr($delete_folder, 0, 1) === '/') $delete_folder = substr($delete_folder, 1);
                        if(substr($delete_folder, -1) === '/') $delete_folder = substr($delete_folder, 0, -1);
                        $path_elements = explode('/', $delete_folder);
                        if($path_elements[0] == 'web' || $path_elements[0] === '') {
                            // paths beginning with /web should NEVER EVER be deleted, empty paths should NEVER occur - but for safety reasons we check it here!
                            // we use strict check as otherwise directories named '0' may not be deleted
                            $do_delete = false;
                        } else {
                            // read all vhost subdomains with same parent domain
                            $used_paths = array();
                            $tmp = $app->db->queryAllRecords("SELECT `web_folder` FROM web_domain WHERE type = 'vhostsubdomain' AND parent_domain_id = ".intval($data['old']['parent_domain_id'])." AND domain_id != ".intval($data['old']['domain_id']));
                            foreach($tmp as $tmprec) {
                                // we normalize the folder entries because we need to compare them
                                $tmp_folder = preg_replace('/[\/]{2,}/', '/', $tmprec['web_folder']); // replace / occuring multiple times
                                if(substr($tmp_folder, 0, 1) === '/') $tmp_folder = substr($tmp_folder, 1);
                                if(substr($tmp_folder, -1) === '/') $tmp_folder = substr($tmp_folder, 0, -1);
                                // add this path and it's parent paths to used_paths array
                                while(strpos($tmp_folder, '/') !== false) {
                                    if(in_array($tmp_folder, $used_paths) == false) $used_paths[] = $tmp_folder;
                                    $tmp_folder = substr($tmp_folder, 0, strrpos($tmp_folder, '/'));
                                }
                                if(in_array($tmp_folder, $used_paths) == false) $used_paths[] = $tmp_folder;
                            }
                            unset($tmp);
                            // loop and check if the path is still used and stop at first used one
                            // set do_delete to false so nothing gets deleted if the web_folder itself is still used
                            $do_delete = false;
                            while(count($path_elements) > 0) {
                                $tmp_folder = implode('/', $path_elements);
                                if(in_array($tmp_folder, $used_paths) == true) break;
                                // this path is not used - set it as path to delete, strip the last element from the array and set do_delete to true
                                $delete_folder = $tmp_folder;
                                $do_delete = true;
                                array_pop($path_elements);
                            }
                            unset($tmp_folder);
                            unset($used_paths);
                        }
                        if($do_delete === true && $delete_folder !== '') exec('rm -rf '.$docroot.'/'.$delete_folder);
                        unset($delete_folder);
                        unset($path_elements);
                    }
                }
            
                //remove the php fastgi starter script if available
server/server.sh
@@ -4,6 +4,8 @@
. /etc/profile
umask 022
if [ -f /usr/local/ispconfig/server/lib/php.ini ]; then
        PHPINIOWNER=`stat -c %U /usr/local/ispconfig/server/lib/php.ini`
        if [ $PHPINIOWNER == 'root' ] || [ $PHPINIOWNER == 'ispconfig'  ]; then