tbrehm
2008-01-06 b5a23a1be34827ba18ca537740edb121e616cd7a
Added reseller capabilities to all modules.
Added a server module for clients and a mail plugin.
3 files added
20 files modified
602 ■■■■ changed files
TODO.txt 3 ●●●●● patch | view | raw | blame | history
install/sql/ispconfig3.sql 20 ●●●●● patch | view | raw | blame | history
install/tpl/config.inc.php.master 3 ●●●●● patch | view | raw | blame | history
interface/lib/app.inc.php 5 ●●●●● patch | view | raw | blame | history
interface/lib/classes/auth.inc.php 87 ●●●●● patch | view | raw | blame | history
interface/lib/classes/tform.inc.php 6 ●●●● patch | view | raw | blame | history
interface/lib/config.inc.php 1 ●●●● patch | view | raw | blame | history
interface/web/client/client_del.php 32 ●●●●● patch | view | raw | blame | history
interface/web/client/client_edit.php 26 ●●●● patch | view | raw | blame | history
interface/web/client/form/client.tform.php 15 ●●●●● patch | view | raw | blame | history
interface/web/client/lib/lang/en_client.lng 1 ●●●● patch | view | raw | blame | history
interface/web/client/lib/module.conf.php 79 ●●●●● patch | view | raw | blame | history
interface/web/client/templates/client_edit_limits.htm 7 ●●●●● patch | view | raw | blame | history
interface/web/dns/dns_soa_edit.php 21 ●●●● patch | view | raw | blame | history
interface/web/dns/form/dns_soa.tform.php 2 ●●● patch | view | raw | blame | history
interface/web/dns/templates/dns_soa_edit.htm 10 ●●●●● patch | view | raw | blame | history
interface/web/mail/mail_domain_edit.php 19 ●●●● patch | view | raw | blame | history
interface/web/mail/mail_user_edit.php 2 ●●● patch | view | raw | blame | history
interface/web/mail/templates/mail_domain_edit.htm 10 ●●●●● patch | view | raw | blame | history
interface/web/sites/templates/web_domain_edit.htm 10 ●●●●● patch | view | raw | blame | history
interface/web/sites/web_domain_edit.php 47 ●●●● patch | view | raw | blame | history
server/mods-enabled/client_module.inc.php 87 ●●●●● patch | view | raw | blame | history
server/plugins-enabled/mail_plugin.inc.php 109 ●●●●● patch | view | raw | blame | history
TODO.txt
@@ -46,9 +46,6 @@
Clients module
--------------------------------------
- Add the ability that Clients can add clients (Reseller functionality)
  Task assigned to: Till
Sites (web) module
--------------------------------------
install/sql/ispconfig3.sql
@@ -60,6 +60,8 @@
  `default_dnsserver` int(10) unsigned NOT NULL default '1',
  `limit_dns_zone` int(11) NOT NULL default '-1',
  `limit_dns_record` int(11) NOT NULL default '-1',
  `limit_client` int(11) NOT NULL default '0',
  `parent_client_id` int(10) unsigned NOT NULL default '0',
  `username` varchar(255) default NULL,
  `password` varchar(255) default NULL,
  `language` varchar(255) NOT NULL default 'en',
@@ -847,15 +849,15 @@
  `redirect_type` varchar(255) default NULL,
  `redirect_path` varchar(255) default NULL,
  `ssl` enum('n','y') NOT NULL default 'n',
  `ssl_state` varchar(255) NOT NULL,
  `ssl_locality` varchar(255) NOT NULL,
  `ssl_organisation` varchar(255) NOT NULL,
  `ssl_organisation_unit` varchar(255) NOT NULL,
  `ssl_country` varchar(255) NOT NULL,
  `ssl_request` mediumtext NOT NULL,
  `ssl_cert` mediumtext NOT NULL,
  `ssl_bundle` mediumtext NOT NULL,
  `ssl_action` varchar(10) NOT NULL,
  `ssl_state` varchar(255) NULL,
  `ssl_locality` varchar(255) NULL,
  `ssl_organisation` varchar(255) NULL,
  `ssl_organisation_unit` varchar(255) NULL,
  `ssl_country` varchar(255) NULL,
  `ssl_request` mediumtext NULL,
  `ssl_cert` mediumtext NULL,
  `ssl_bundle` mediumtext NULL,
  `ssl_action` varchar(10) NULL,
  `active` varchar(255) NOT NULL default 'y',
  PRIMARY KEY  (`domain_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
install/tpl/config.inc.php.master
@@ -58,6 +58,9 @@
define('ISPC_TEMP_PATH',   ISPC_ROOT_PATH.'/temp');
define('ISPC_CACHE_PATH',  ISPC_ROOT_PATH.'/cache');
//** Interface settings
define('ISPC_INTERFACE_MODULES_ENABLED', 'mail,sites,dns');
/*
    Server variables
interface/lib/app.inc.php
@@ -63,6 +63,8 @@
            if(empty($_SESSION['s']['theme'])) $_SESSION['s']['theme'] = $conf['theme'];
            if(empty($_SESSION['s']['language'])) $_SESSION['s']['language'] = $conf['language'];
        }
        $this->uses('auth');
    }
    public function uses($classes)
@@ -176,6 +178,9 @@
        if(isset($_SESSION['s']['user']) && $_SESSION['s']['user']['typ'] == 'admin') {
            $this->tpl->setVar('is_admin', 1);
        }
        if(isset($_SESSION['s']['user']) && $this->auth->has_clients($_SESSION['s']['user']['userid'])) {
            $this->tpl->setVar('is_reseller', 1);
        }
    }
    
} // end class
interface/lib/classes/auth.inc.php
New file
@@ -0,0 +1,87 @@
<?php
/*
Copyright (c) 2008, Till Brehm, projektfarm Gmbh
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
class auth {
    public function has_clients($userid) {
        global $app, $conf;
        $userid = intval($userid);
        $client = $app->db->queryOneRecord("SELECT client.limit_client FROM sys_user, client WHERE sys_user.userid = $userid AND sys_user.client_id = client.client_id");
        if($client['limit_client'] > 0) {
            return true;
        } else {
            return false;
        }
    }
    //** This function adds a given group id to a given user.
    public function add_group_to_user($userid,$groupid) {
        global $app;
        $userid = intval($userid);
        $groupid = intval($groupid);
        if($userid > 0 && $groupid > 0) {
            $user = $app->db->queryOneRecord("SELECT * FROM sys_user WHERE userid = $userid");
            $groups = explode(',',$user['groups']);
            if(!in_array($groupid,$groups)) $groups[] = $groupid;
            $groups_string = implode(',',$groups);
            $sql = "UPDATE sys_user SET groups = '$groups_string' WHERE userid = $userid";
            $app->db->query($sql);
            return true;
        } else {
            return false;
        }
    }
    //** This function removes a given group id from a given user.
    public function remove_group_from_user($userid,$groupid) {
        global $app;
        $userid = intval($userid);
        $groupid = intval($groupid);
        if($userid > 0 && $groupid > 0) {
            $user = $app->db->queryOneRecord("SELECT * FROM sys_user WHERE userid = $userid");
            $groups = explode(',',$user['groups']);
            $key = array_search($groupid,$groups);
            unset($groups[$key]);
            $groups_string = implode(',',$groups);
            $sql = "UPDATE sys_user SET groups = '$groups_string' WHERE userid = $userid";
            $app->db->query($sql);
            return true;
        } else {
            return false;
        }
    }
}
?>
interface/lib/classes/tform.inc.php
@@ -718,7 +718,7 @@
                                                }
                                        } else {
                                                if($field['formtype'] == 'PASSWORD') {
                                                        if($field['encryption'] == 'CRYPT') {
                                                        if(isset($field['encryption']) && $field['encryption'] == 'CRYPT') {
                                                                $salt="$1$";
                                                                for ($n=0;$n<8;$n++) {
                                                                    $salt.=chr(mt_rand(64,126));
@@ -999,8 +999,8 @@
                        }
                } else {
                        $result = false;
                        if($this->formDef["auth_preset"]["userid"] == $_SESSION["s"]["user"]["userid"] && stristr($perm,$this->formDef["auth_preset"]["perm_user"])) $result = true;
                        if($this->formDef["auth_preset"]["groupid"] == $_SESSION["s"]["user"]["groupid"] && stristr($perm,$this->formDef["auth_preset"]["perm_group"])) $result = true;
                        if(@$this->formDef["auth_preset"]["userid"] == $_SESSION["s"]["user"]["userid"] && stristr($perm,$this->formDef["auth_preset"]["perm_user"])) $result = true;
                        if(@$this->formDef["auth_preset"]["groupid"] == $_SESSION["s"]["user"]["groupid"] && stristr($perm,$this->formDef["auth_preset"]["perm_group"])) $result = true;
                        if(@stristr($this->formDef["auth_preset"]["perm_other"],$perm)) $result = true;
                        // if preset == 0, everyone can insert a record of this type
interface/lib/config.inc.php
@@ -51,6 +51,7 @@
define('ISPC_TEMP_PATH',   ISPC_ROOT_PATH.'/temp');
define('ISPC_CACHE_PATH',  ISPC_ROOT_PATH.'/cache');
define('ISPC_INTERFACE_MODULES_ENABLED', 'mail,sites,dns');
//********************************************************************************
//** Future Code idea  - pedro - rfc
interface/web/client/client_del.php
@@ -48,7 +48,35 @@
    exit;
}
$app->uses("tform_actions");
$app->tform_actions->onDelete();
$app->uses('tpl,tform');
$app->load('tform_actions');
class page_action extends tform_actions {
    function onAfterDelete() {
        global $app, $conf;
        $client_id = intval($this->dataRecord['client_id']);
        if($client_id > 0) {
            // TODO: Delete all records (sub-clients, mail, web, etc....)  of this client.
            // remove the group of the client from the resellers group
            $parent_client_id = intval($this->dataRecord['parent_client_id']);
            $parent_user = $app->db->queryOneRecord("SELECT userid FROM sys_user WHERE client_id = $parent_client_id");
            $client_group = $app->db->queryOneRecord("SELECT groupid FROM sys_group WHERE client_id = $client_id");
            $app->auth->remove_group_from_user($parent_user['userid'],$client_group['groupid']);
            // delete the group of the client
            $app->db->query("DELETE FROM sys_group WHERE client_id = $client_id");
            // delete the sys user(s) of the client
            $app->db->query("DELETE FROM sys_user WHERE client_id = $client_id");
        }
    }
}
$page = new page_action;
$page->onDelete()
?>
interface/web/client/client_edit.php
@@ -63,10 +63,12 @@
        $sql = "INSERT INTO sys_group (name,description,client_id) VALUES ('".addslashes($this->dataRecord["username"])."','',".$this->id.")";
        $app->db->query($sql);
        $groupid = $app->db->insertID();
        $groups = $groupid;
        
        $username = addslashes($this->dataRecord["username"]);
        $password = addslashes($this->dataRecord["password"]);
        $modules = 'mail,sites,dns';
        $modules = ISPC_INTERFACE_MODULES_ENABLED;
        if($this->dataRecord["limit_client"] > 0) $modules .= ',client';
        $startmodule = 'mail';
        $usertheme = addslashes($this->dataRecord["usertheme"]);
        $type = 'user';
@@ -75,8 +77,17 @@
        
        // Create the controlpaneluser for the client
        $sql = "INSERT INTO sys_user (username,passwort,modules,startmodule,app_theme,typ,active,language,groups,default_group,client_id)
        VALUES ('$username',md5('$password'),'$modules','$startmodule','$usertheme','$type','$active','$language',$groupid,$groupid,".$this->id.")";
        VALUES ('$username',md5('$password'),'$modules','$startmodule','$usertheme','$type','$active','$language',$groups,$groupid,".$this->id.")";
        $app->db->query($sql);
        //* If the user who inserted the client is a reseller (not admin), we will have to add this new client group
        //* to his groups, so he can administrate the records of this client.
        if($_SESSION['s']['user']['typ'] == 'user') {
            $app->auth->add_group_to_user($_SESSION['s']['user']['userid'],$groupid);
            $app->db->query("UPDATE client SET parent_client_id = ".intval($_SESSION['s']['user']['client_id'])." WHERE client_id = ".$this->id);
        }
    }
    
    
@@ -105,8 +116,15 @@
            $app->db->query($sql);
        }
        
        // reseller status changed
        if(isset($this->dataRecord["limit_client"])) {
            $modules = ISPC_INTERFACE_MODULES_ENABLED;
            if($this->dataRecord["limit_client"] > 0) $modules .= ',client';
            $modules = addslashes($modules);
            $client_id = $this->id;
            $sql = "UPDATE sys_user SET modules = '$modules' WHERE client_id = $client_id";
            $app->db->query($sql);
        }
    }
    
    
interface/web/client/form/client.tform.php
@@ -104,6 +104,7 @@
        'password' => array (
            'datatype'    => 'VARCHAR',
            'formtype'    => 'PASSWORD',
            'encryption'=> 'MD5',
            'default'    => '',
            'value'        => '',
            'separator'    => '',
@@ -579,6 +580,20 @@
            'rows'        => '',
            'cols'        => ''
        ),
        'limit_client' => array (
            'datatype'    => 'INTEGER',
            'formtype'    => 'TEXT',
            'validators'    => array (     0 => array (    'type'    => 'ISINT',
                                                        'errmsg'=> 'limit_client_error_notint'),
                                    ),
            'default'    => '0',
            'value'        => '',
            'separator'    => '',
            'width'        => '10',
            'maxlength'    => '10',
            'rows'        => '',
            'cols'        => ''
        ),
    ##################################
    # END Datatable fields
    ##################################
interface/web/client/lib/lang/en_client.lng
@@ -54,5 +54,6 @@
$wb["limit_dns_zone_txt"] = 'Max. number of DNS zones';
$wb["limit_dns_record_txt"] = 'Max. number DNS records';
$wb["limit_shell_user_txt"] = 'Max. number of Shell users';
$wb["limit_client_txt"] = 'Max. number of Clients';
?>
interface/web/client/lib/module.conf.php
@@ -1,57 +1,26 @@
<?php
$module = array (
  'name' => 'client',
  'title' => 'Client',
  'template' => 'module.tpl.htm',
  'navframe_page' => '',
  'startpage' => 'client/client_list.php',
  'tab_width' => '',
  'nav' =>
  array (
    0 =>
    array (
      'title' => 'Clients',
      'open' => 1,
      'items' =>
      array (
        0 =>
        array (
          'title' => 'Add Client',
          'target' => 'content',
          'link' => 'client/client_edit.php',
        ),
        1 =>
        array (
          'title' => 'Edit Client',
          'target' => 'content',
          'link' => 'client/client_list.php',
        ),
      ),
    ),
    1 =>
    array (
      'title' => 'Statistics',
      'open' => 1,
      'items' =>
      array (
      ),
    ),
    2 =>
    array (
      'title' => 'Invoices',
      'open' => 1,
      'items' =>
      array (
      ),
    ),
    3 =>
    array (
      'title' => 'Mailings',
      'open' => 1,
      'items' =>
      array (
      ),
    ),
  ),
)
$module["name"]         = "client";
$module["title"]         = "Client";
$module["template"]     = "module.tpl.htm";
$module["startpage"]     = "client/client_list.php";
$module["tab_width"]    = '';
/*
    Email accounts menu
*/
$items[] = array( 'title'     => "Add Client",
                  'target'     => 'content',
                  'link'    => 'client/client_edit.php');
$items[] = array( 'title'     => "Edit Client",
                  'target'     => 'content',
                  'link'    => 'client/client_list.php');
$module["nav"][] = array(    'title'    => 'Clients',
                            'open'     => 1,
                            'items'    => $items);
?>
interface/web/client/templates/client_edit_limits.htm
@@ -114,6 +114,13 @@
    <td class="frmText11" width="220"><input name="limit_dns_record" type="text" class="text" value="{tmpl_var name='limit_dns_record'}" size="10" maxlength="10"></td>
  </tr>
  <tr>
    <td><h2>Clients</h2></td>
  </tr>
  <tr>
    <td class="frmText11" width="280">{tmpl_var name='limit_client_txt'}:</td>
    <td class="frmText11" width="220"><input name="limit_client" type="text" class="text" value="{tmpl_var name='limit_client'}" size="10" maxlength="10"></td>
  </tr>
  <tr>
    <td class="frmText11">&nbsp;</td>
    <td class="frmText11">&nbsp;</td>
  </tr>
interface/web/dns/dns_soa_edit.php
@@ -79,11 +79,12 @@
        global $app, $conf;
        
        // If user is admin, we will allow him to select to whom this record belongs
        if($_SESSION["s"]["user"]["typ"] == 'admin') {
        if($_SESSION["s"]["user"]["typ"] == 'admin' || $app->auth->has_clients($_SESSION['s']['user']['userid'])) {
            // Getting Domains of the user
            $sql = "SELECT groupid, name FROM sys_group WHERE client_id > 0";
            $clients = $app->db->queryAllRecords($sql);
            $client_select = "<option value='0'></option>";
            $client_select = '';
            if($_SESSION["s"]["user"]["typ"] == 'admin') $client_select .= "<option value='0'></option>";
            if(is_array($clients)) {
                foreach( $clients as $client) {
                    $selected = ($client["groupid"] == $this->dataRecord["sys_groupid"])?'SELECTED':'';
@@ -134,8 +135,14 @@
    function onAfterInsert() {
        global $app, $conf;
        
        // make sure that the record belongs to the clinet group and not the admin group when a dmin inserts it
        // make sure that the record belongs to the client group and not the admin group when a dmin inserts it
        if($_SESSION["s"]["user"]["typ"] == 'admin' && isset($this->dataRecord["client_group_id"])) {
            $client_group_id = intval($this->dataRecord["client_group_id"]);
            $app->db->query("UPDATE dns_soa SET sys_groupid = $client_group_id WHERE id = ".$this->id);
            // And we want to update all rr records too, that belong to this record
            $app->db->query("UPDATE dns_rr SET sys_groupid = $client_group_id WHERE zone = ".$this->id);
        }
        if($app->auth->has_clients($_SESSION['s']['user']['userid']) && isset($this->dataRecord["client_group_id"])) {
            $client_group_id = intval($this->dataRecord["client_group_id"]);
            $app->db->query("UPDATE dns_soa SET sys_groupid = $client_group_id WHERE id = ".$this->id);
            // And we want to update all rr records too, that belong to this record
@@ -146,13 +153,19 @@
    function onAfterUpdate() {
        global $app, $conf;
        
        // make sure that the record belongs to the clinet group and not the admin group when a dmin inserts it
        // make sure that the record belongs to the client group and not the admin group when a dmin inserts it
        if($_SESSION["s"]["user"]["typ"] == 'admin' && isset($this->dataRecord["client_group_id"])) {
            $client_group_id = intval($this->dataRecord["client_group_id"]);
            $app->db->query("UPDATE dns_soa SET sys_groupid = $client_group_id WHERE id = ".$this->id);
            // And we want to update all rr records too, that belong to this record
            $app->db->query("UPDATE dns_rr SET sys_groupid = $client_group_id WHERE zone = ".$this->id);
        }
        if($app->auth->has_clients($_SESSION['s']['user']['userid']) && isset($this->dataRecord["client_group_id"])) {
            $client_group_id = intval($this->dataRecord["client_group_id"]);
            $app->db->query("UPDATE dns_soa SET sys_groupid = $client_group_id WHERE id = ".$this->id);
            // And we want to update all rr records too, that belong to this record
            $app->db->query("UPDATE dns_rr SET sys_groupid = $client_group_id WHERE zone = ".$this->id);
        }
    }
    
}
interface/web/dns/form/dns_soa.tform.php
@@ -202,7 +202,7 @@
             'class'   => 'plugin_listview',
             'options' => array(
                'listdef' => 'list/dns_a.list.php',
                'sqlextwhere' => "zone = ".intval($_REQUEST['id']),
                'sqlextwhere' => "zone = ".intval(@$_REQUEST['id']),
                'sql_order_by' => "ORDER BY type, name"
            )
        )
interface/web/dns/templates/dns_soa_edit.htm
@@ -17,6 +17,16 @@
    </td>
  </tr>
  </tmpl_if>
  <tmpl_if name="is_reseller">
  <tr>
    <td class="frmText11">{tmpl_var name='client_txt'}:</td>
    <td class="frmText11">
        <select name="client_group_id" class="text">
            {tmpl_var name='client_group_id'}
        </select>
    </td>
  </tr>
  </tmpl_if>
  <tr>
    <td class="frmText11">{tmpl_var name='origin_txt'}:</td>
    <td class="frmText11"><input name="origin" type="text" class="text" value="{tmpl_var name='origin'}" size="30" maxlength="255"> e.g. mydomain.com.</td>
interface/web/mail/mail_domain_edit.php
@@ -78,11 +78,12 @@
    function onShowEnd() {
        global $app, $conf;
        
        if($_SESSION["s"]["user"]["typ"] == 'admin') {
        if($_SESSION["s"]["user"]["typ"] == 'admin' || $app->auth->has_clients($_SESSION['s']['user']['userid'])) {
            // Getting Domains of the user
            $sql = "SELECT groupid, name FROM sys_group WHERE client_id > 0";
            $clients = $app->db->queryAllRecords($sql);
            $client_select = "<option value='0'></option>";
            $client_select = '';
            if($_SESSION["s"]["user"]["typ"] == 'admin') $client_select .= "<option value='0'></option>";
            if(is_array($clients)) {
                foreach( $clients as $client) {
                    $selected = ($client["groupid"] == $this->dataRecord["sys_groupid"])?'SELECTED':'';
@@ -140,7 +141,7 @@
            }
            
            // Clients may not set the client_group_id, so we unset them if user is not a admin
            unset($this->dataRecord["client_group_id"]);
            if(!$app->auth->has_clients($_SESSION['s']['user']['userid'])) unset($this->dataRecord["client_group_id"]);
        }
        parent::onSubmit();
    }
@@ -148,11 +149,15 @@
    function onAfterInsert() {
        global $app, $conf;
        
        // make sure that the record belongs to the clinet group and not the admin group when a dmin inserts it
        // make sure that the record belongs to the client group and not the admin group when a dmin inserts it
        // also make sure that the user can not delete domain created by a admin
        if($_SESSION["s"]["user"]["typ"] == 'admin' && isset($this->dataRecord["client_group_id"])) {
            $client_group_id = intval($this->dataRecord["client_group_id"]);
            $app->db->query("UPDATE mail_domain SET sys_groupid = $client_group_id, sys_perm_group = 'ru' WHERE domain_id = ".$this->id);
        }
        if($app->auth->has_clients($_SESSION['s']['user']['userid']) && isset($this->dataRecord["client_group_id"])) {
            $client_group_id = intval($this->dataRecord["client_group_id"]);
            $app->db->query("UPDATE mail_domain SET sys_groupid = $client_group_id, sys_perm_group = 'riud' WHERE domain_id = ".$this->id);
        }
        
        // Spamfilter policy
@@ -177,12 +182,16 @@
    function onAfterUpdate() {
        global $app, $conf;
        
        // make sure that the record belongs to the clinet group and not the admin group when a dmin inserts it
        // make sure that the record belongs to the clinet group and not the admin group when admin inserts it
        // also make sure that the user can not delete domain created by a admin
        if($_SESSION["s"]["user"]["typ"] == 'admin' && isset($this->dataRecord["client_group_id"])) {
            $client_group_id = intval($this->dataRecord["client_group_id"]);
            $app->db->query("UPDATE mail_domain SET sys_groupid = $client_group_id, sys_perm_group = 'ru' WHERE domain_id = ".$this->id);
        }
        if($app->auth->has_clients($_SESSION['s']['user']['userid']) && isset($this->dataRecord["client_group_id"])) {
            $client_group_id = intval($this->dataRecord["client_group_id"]);
            $app->db->query("UPDATE mail_domain SET sys_groupid = $client_group_id, sys_perm_group = 'riud' WHERE domain_id = ".$this->id);
        }
        
        // Spamfilter policy
        $policy_id = intval($this->dataRecord["policy"]);
interface/web/mail/mail_user_edit.php
@@ -89,7 +89,7 @@
        $domain_select = '';
        if(is_array($domains)) {
            foreach( $domains as $domain) {
                $selected = ($domain["domain"] == $email_parts[1])?'SELECTED':'';
                $selected = ($domain["domain"] == @$email_parts[1])?'SELECTED':'';
                $domain_select .= "<option value='$domain[domain]' $selected>$domain[domain]</option>\r\n";
            }
        }
interface/web/mail/templates/mail_domain_edit.htm
@@ -17,6 +17,16 @@
    </td>
  </tr>
  </tmpl_if>
  <tmpl_if name="is_reseller">
  <tr>
    <td class="frmText11">{tmpl_var name='client_txt'}:</td>
    <td class="frmText11">
        <select name="client_group_id" class="text">
            {tmpl_var name='client_group_id'}
        </select>
    </td>
  </tr>
  </tmpl_if>
  <tr>
    <td class="frmText11">{tmpl_var name='domain_txt'}:</td>
    <td class="frmText11"><input name="domain" type="text" class="text" value="{tmpl_var name='domain'}" size="30" maxlength="255"></td>
interface/web/sites/templates/web_domain_edit.htm
@@ -17,6 +17,16 @@
    </td>
  </tr>
  </tmpl_if>
  <tmpl_if name="is_reseller">
  <tr>
    <td class="frmText11">{tmpl_var name='client_txt'}:</td>
    <td class="frmText11">
        <select name="client_group_id" class="text">
            {tmpl_var name='client_group_id'}
        </select>
    </td>
  </tr>
  </tmpl_if>
  <tr>
    <td class="frmText11">{tmpl_var name='ip_address_txt'}:</td>
    <td class="frmText11">
interface/web/sites/web_domain_edit.php
@@ -78,11 +78,11 @@
    function onShowEnd() {
        global $app, $conf;
        
        if($_SESSION["s"]["user"]["typ"] != 'admin') {
        if($_SESSION["s"]["user"]["typ"] != 'admin' && !$app->auth->has_clients($_SESSION['s']['user']['userid'])) {
        
            // Get the limits of the client
            $client_group_id = $_SESSION["s"]["user"]["default_group"];
            $client = $app->db->queryOneRecord("SELECT limit_maildomain, default_mailserver FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
            $client = $app->db->queryOneRecord("SELECT limit_web_domain, default_webserver FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
            
            // Set the webserver to the default server of the client
            $tmp = $app->db->queryOneRecord("SELECT server_name FROM server WHERE server_id = $client[default_webserver]");
@@ -90,6 +90,35 @@
            unset($tmp);
            
            // Fill the IP select field with the IP addresses that are allowed for this client
            $ip_select = "<option value='*'>*</option>";
            $app->tpl->setVar("ip_address",$ip_select);
        } elseif ($_SESSION["s"]["user"]["typ"] != 'admin' && $app->auth->has_clients($_SESSION['s']['user']['userid'])) {
            // Get the limits of the client
            $client_group_id = $_SESSION["s"]["user"]["default_group"];
            $client = $app->db->queryOneRecord("SELECT limit_web_domain, default_webserver FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
            // Set the webserver to the default server of the client
            $tmp = $app->db->queryOneRecord("SELECT server_name FROM server WHERE server_id = $client[default_webserver]");
            $app->tpl->setVar("server_id","<option value='$client[default_webserver]'>$tmp[server_name]</option>");
            unset($tmp);
            // Fill the client select field
            $sql = "SELECT groupid, name FROM sys_group WHERE client_id > 0";
            $clients = $app->db->queryAllRecords($sql);
            $client_select = '';
            if(is_array($clients)) {
                foreach( $clients as $client) {
                    $selected = @($client["groupid"] == $this->dataRecord["sys_groupid"])?'SELECTED':'';
                    $client_select .= "<option value='$client[groupid]' $selected>$client[name]</option>\r\n";
                }
            }
            $app->tpl->setVar("client_group_id",$client_select);
            // Fill the IP select field with the IP addresses that are allowed for this client
            $ip_select = "<option value='*'>*</option>";
            $app->tpl->setVar("ip_address",$ip_select);
            
        } else {
            
@@ -169,8 +198,8 @@
                
            }
            
            // Clients may not set the client_group_id, so we unset them if user is not a admin
            unset($this->dataRecord["client_group_id"]);
            // Clients may not set the client_group_id, so we unset them if user is not a admin and the client is not a reseller
            if(!$app->auth->has_clients($_SESSION['s']['user']['userid'])) unset($this->dataRecord["client_group_id"]);
        }
        
        
@@ -185,6 +214,10 @@
        if($_SESSION["s"]["user"]["typ"] == 'admin' && isset($this->dataRecord["client_group_id"])) {
            $client_group_id = intval($this->dataRecord["client_group_id"]);
            $app->db->query("UPDATE web_domain SET sys_groupid = $client_group_id, sys_perm_group = 'ru' WHERE domain_id = ".$this->id);
        }
        if($app->auth->has_clients($_SESSION['s']['user']['userid']) && isset($this->dataRecord["client_group_id"])) {
            $client_group_id = intval($this->dataRecord["client_group_id"]);
            $app->db->query("UPDATE web_domain SET sys_groupid = $client_group_id, sys_perm_group = 'riud' WHERE domain_id = ".$this->id);
        }
        
        // Get configuration for the web system
@@ -222,6 +255,10 @@
            $client_group_id = intval($this->dataRecord["client_group_id"]);
            $app->db->query("UPDATE web_domain SET sys_groupid = $client_group_id, sys_perm_group = 'ru' WHERE domain_id = ".$this->id);
        }
        if($app->auth->has_clients($_SESSION['s']['user']['userid']) && isset($this->dataRecord["client_group_id"])) {
            $client_group_id = intval($this->dataRecord["client_group_id"]);
            $app->db->query("UPDATE web_domain SET sys_groupid = $client_group_id, sys_perm_group = 'riud' WHERE domain_id = ".$this->id);
        }
        
        // Get configuration for the web system
        $app->uses("getconf");
@@ -230,7 +267,7 @@
        $document_root = str_replace("[website_id]",$this->id,$web_config["website_path"]);
        
        // get the ID of the client
        if($_SESSION["s"]["user"]["typ"] != 'admin') {
        if($_SESSION["s"]["user"]["typ"] != 'admin' && !$app->auth->has_clients($_SESSION['s']['user']['userid'])) {
            $client_group_id = $_SESSION["s"]["user"]["default_group"];
            $client = $app->db->queryOneRecord("SELECT client_id FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
            $client_id = intval($client["client_id"]);
server/mods-enabled/client_module.inc.php
New file
@@ -0,0 +1,87 @@
<?php
/*
Copyright (c) 2007, Till Brehm, projektfarm Gmbh
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
class web_module {
    var $module_name = 'client_module';
    var $class_name = 'client_module';
    var $actions_available = array(    'client_insert',
                                    'client_update',
                                    'client_delete');
    /*
         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('client',$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 'client':
                if($action == 'i') $app->plugins->raiseEvent('client_insert',$data);
                if($action == 'u') $app->plugins->raiseEvent('client_update',$data);
                if($action == 'd') $app->plugins->raiseEvent('client_delete',$data);
            break;
        } // end switch
    } // end function
} // end class
?>
server/plugins-enabled/mail_plugin.inc.php
New file
@@ -0,0 +1,109 @@
<?php
/*
Copyright (c) 2007, Till Brehm, projektfarm Gmbh
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
class mail_plugin {
    var $plugin_name = 'mail_plugin';
    var $class_name  = 'mail_plugin';
    /*
         This function is called when the plugin is loaded
    */
    function onLoad() {
        global $app;
        /*
        Register for the events
        */
        $app->plugins->registerEvent('mail_user_insert',$this->plugin_name,'user_insert');
        $app->plugins->registerEvent('mail_user_update',$this->plugin_name,'user_update');
        $app->plugins->registerEvent('mail_user_delete',$this->plugin_name,'user_delete');
    }
    function user_insert($event_name,$data) {
        global $app, $conf;
        // Create the maildir, if it does not exist
        if(!is_dir($data['new']['maildir']) {
            mkdir($data['new']['maildir']);
            exec('chown '.$mail_config['mailuser_name'].':'.$mail_config['mailuser_group'].' '.escapeshellcmd($data['new']['maildir']));
            $app->log('Created Maildir: '.$data['new']['maildir'],LOGLEVEL_DEBUG);
        }
    }
    function user_update($event_name,$data) {
        global $app, $conf;
        // get the config
        $app->uses("getconf");
        $mail_config = $app->getconf->get_server_config($conf["server_id"], 'mail');
        // Create the maildir, if it does not exist
        if(!is_dir($data['new']['maildir']) {
            mkdir($data['new']['maildir']);
            exec('chown '.$mail_config['mailuser_name'].':'.$mail_config['mailuser_group'].' '.escapeshellcmd($data['new']['maildir']));
            $app->log('Created Maildir: '.$data['new']['maildir'],LOGLEVEL_DEBUG);
        }
        // Move mailbox, if domain has changed and delete old mailbox
        if($data['new']['maildir'] != $data['old']['maildir'] && is_dir($data['old']['maildir'])) {
            exec('mv -f'.escapeshellcmd($data['old']['maildir']).'* '.escapeshellcmd($data['new']['maildir']));
            unlink($data['old']['maildir']);
            $app->log('Moved Maildir from: '.$data['old']['maildir'].' to '.$data['new']['maildir'],LOGLEVEL_DEBUG);
        }
    }
    function user_delete($event_name,$data) {
        global $app, $conf;
        $old_maildir_path = escapeshellcmd($data['old']['maildir']);
        if(!stristr($old_maildir_path,'..') && !stristr($old_maildir_path,'*') && strlen($old_maildir_path) >= 10) {
            exec('rm -rf '.$old_maildir_path);
            $app->log('Deleted the Maildir: '.$data['old']['maildir'],LOGLEVEL_DEBUG);
        } else {
            $app->log('Possible security violation when deleting the maildir: '.$data['old']['maildir'],LOGLEVEL_ERROR);
        }
    }
} // end class
?>