<?php

/**
 * Project: 
 * Contenido Content Management System
 * 
 * Description: 
 * Session Management for PHP3
 * 
 * Requirements: 
 * @con_php_req 5
 *
 * @package    ContenidoBackendArea
 * @version    0.1
 * @author     Boris Erdmann, Kristian Koehntopp
 * @copyright  four for business AG <www.4fb.de>
 * @license    http://www.contenido.org/license/LIZENZ.txt
 * @link       http://www.4fb.de
 * @link       http://www.contenido.org
 * @since      file available since contenido release <Contenido Version>
 * @deprecated file deprecated in contenido release <Contenido Version>
 * 
 * {@internal 
 *   created  2002-08-16
 *   modified 2008-07-04, bilal arslan, added security fix
 *   modified 2009-10-29, Murat Purc, replaced deprecated functions (PHP 5.3 ready) and some formatting
 *
 *   $Id$:
 * }}
 * 
 */
if (!defined('CON_FRAMEWORK')) {
    die('Illegal call');
}

class Contenido_Perm {

    var $classname = "Contenido_Perm";
    var $areacache = array();
    var $actioncache = array();
    var $db;
    var $db_perm;

    function getGroupsForUser($user) {
        global $cfg;

        if (!is_object($this->db)) {
            $this->db = new DB_Contenido;
        }

        $sql = "SELECT group_id FROM
                            " . $cfg["tab"]["groupmembers"] . "
                        WHERE user_id = '" . Contenido_Security::escapeDB($user, $this->db) . "'";
        $this->db->query($sql);

        $groups = array();

        while ($this->db->next_record()) {
            $groups[] = $this->db->f("group_id");
        }

        return $groups;
    }

    function getIDForArea($area) {
        global $cfg;

        if (!is_object($this->db_perm)) {
            $this->db_perm = new DB_Contenido;
        }

        if (!is_numeric($area)) {
            if (!@ array_key_exists($area, $this->areacache)) {
                $sql = "SELECT idarea
                                            FROM
                               " . $cfg["tab"]["area"] . "
                                 WHERE
                                    name = \"" . Contenido_Security::escapeDB($area, $this->db_perm) . "\"";
                $this->db_perm->query($sql);

                $this->db_perm->next_record();
                $this->areacache[$area] = $this->db_perm->f("idarea");
                $area = $this->db_perm->f(0);
            } else {
                $area = $this->areacache[$area];
            }

            return ($area);
        }

        return $area;
    }

    function getIDForAction($action) {

        global $cfg;

        if (!is_object($this->db_perm)) {
            $this->db_perm = new DB_Contenido;
        }

        if (!is_numeric($action)) {
            if (!@ array_key_exists($action, $this->actioncache)) {
                $sql = "SELECT idaction
                                            FROM
                                  " . $cfg["tab"]["actions"] . "
                                     WHERE
                                   name = \"" . Contenido_Security::escapeDB($action, $this->db_perm) . "\"";

                $this->db_perm->query($sql);
                $this->db_perm->next_record();

                $this->actioncache[$action] = $this->db_perm->f("idaction");
                $action = $this->db_perm->f(0);
            } else {
                $action = $this->actioncache[$action];
            }
            return ($action);
        }

        return $action;
    }

    function load_permissions($force = false) {

        global $sess, $area_rights, $item_rights, $db, $client, $lang, $auth, $cfg, $changelang, $changeclient;

        $return = "1";
        //if not admin or sysadmin
        if (!$this->have_perm()) {
            $return = isset($area_rights);

            if (!isset($area_rights) || !isset($item_rights) || isset($changeclient) || isset($changelang) || $force) {
                $return = "3";
                //register variables
                $sess->register("area_rights");
                $sess->register("item_rights");
                $item_rights = array();

                $groups = $this->getGroupsForUser($auth->auth["uid"]);

                if (is_array($groups)) {
                    foreach ($groups as $group) {
                        $this->load_permissions_for_user($group);
                    }
                }

                $this->load_permissions_for_user($auth->auth["uid"]);
            }
        }

        return $return;
    }

    function load_permissions_for_user($user) {
        global $db, $client, $lang, $cfg;
        global $area_rights, $item_rights;
        $sql = "SELECT *
                                  FROM " . $cfg["tab"]["rights"] . "
                                  WHERE user_id='" . Contenido_Security::escapeDB($user, $db) . "' AND idcat='0' AND idclient='" . Contenido_Security::toInteger($client) . "' AND idlang='" . Contenido_Security::toInteger($lang) . "'";
        $db->query($sql);

        if (!is_array($area_rights)) {
            $area_rights = array();
        }
        while ($db->next_record()) {
            $area_rights[$db->f("idarea")][$db->f("idaction")] = true;
        }

        // Select Rights for Article and Sructure    Atention    Hard code Areas
        $sql = "SELECT
                             idarea
                         FROM
                           " . $cfg["tab"]["area"];
        $db->query($sql);

        $tmp_area = array();
        while ($db->next_record()) {
            array_push($tmp_area, $db->f("idarea"));
        }

        $tmp_area_string = implode("','", array_keys($tmp_area));
        $sql = "SELECT
                     idarea, idaction, idcat
                                  FROM " . $cfg["tab"]["rights"] . "
                                  WHERE user_id='" . Contenido_Security::escapeDB($user, $db) . "' AND idclient='" . Contenido_Security::toInteger($client) . "' AND idlang='" . Contenido_Security::toInteger($lang) . "' AND idarea IN ('$tmp_area_string') AND idcat != '0'";
        $db->query($sql);

        while ($db->next_record()) {
            $item_rights[$db->f(0)][$db->f(1)][$db->f(2)] = $db->f(2);
        }
    }

    function have_perm_area_action_anyitem($area, $action = 0) {

        if ($this->have_perm_area_action($area, $action)) {
            return true;
        }

        $area = $this->getIDForArea($area);
        $action = $this->getIDForAction($action);

        global $item_rights;

        if (isset($item_rights[$area][$action])) {
            return true;
        } else {
            return false;
        }
    }

    function have_perm_area_action_item($area, $action, $itemid) {
        global $item_rights, $auth, $client, $lang, $cfg;

        if (!is_object($this->db)) {
            $this->db = new DB_Contenido;
        }

        $area = $this->getIDForArea($area);
        $action = $this->getIDForAction($action);

        if ($this->have_perm()) {
            return true;
        } else {
            //if the user has a right on this action in this area   check for the items
            if ($this->have_perm_area_action($area, $action)) {
                return true;
            }
            //check rights for the action in this area at this item
            if (isset($item_rights[$area][$action][$itemid])) {
                //if have action for area + action +item  check right for client and lang
                return true;
            } elseif ($item_rights[$area] != "noright") {

                $groupsForUser = $this->getGroupsForUser($auth->auth['uid']);
                $groupsForUser[] = $auth->auth['uid'];

                $tmp_userstring = implode("','", $groupsForUser);

                $sql = "SELECT *
                                          FROM " . $cfg["tab"]["rights"] . "
                                          WHERE user_id IN ('" . $tmp_userstring . "') AND idclient = '" . Contenido_Security::toInteger($client) . "' AND idlang = '" . Contenido_Security::toInteger($lang) . "' AND idarea = '$area'  AND idcat != '0'";
                $this->db->query($sql);

                //if there are no rights for this area set the flag norights
                if ($this->db->nf() == 0) {
                    $item_rights[$area] = "noright";
                    return false;
                }

                while ($this->db->next_record()) {
                    $item_rights[$this->db->f("idarea")][$this->db->f("idaction")][$this->db->f("idcat")] = $this->db->f("idcat");
                }

                //check
                if (isset($item_rights[$area][$action][$itemid])) {
                    //if have action for area + action +item  check right for client and lang
                    return true;
                }
            }
            return false;
        }
    }

    function getParentAreaId($area) {

        global $client, $lang, $cfg, $sess;

        if (!is_object($this->db)) {
            $this->db = new DB_Contenido;
        }

        if (is_numeric($area)) {
            $sql = "SELECT
                                b.name
                            FROM
                                " . $cfg["tab"]["area"] . " AS a,
                                " . $cfg["tab"]["area"] . " AS b
                            WHERE
                                a.idarea = '" . Contenido_Security::toInteger($area) . "' AND
                                b.name = a.parent_id";
        } else {
            $sql = "SELECT
                                b.name
                            FROM
                                " . $cfg["tab"]["area"] . " AS a,
                                " . $cfg["tab"]["area"] . " AS b
                            WHERE
                                a.name = '" . Contenido_Security::escapeDB($area, $this->db) . "' AND
                                b.name = a.parent_id";
        }
        $this->db->query($sql);

        if ($this->db->next_record()) {
            return $this->db->f(0);
        } else {
            return $area;
        }
    }

    function have_perm_area_action($area, $action = 0) {
        global $area_rights, $client, $lang, $cfg;
        //if not admin or sysadmin
        if (!is_object($this->db_perm)) {
            $this->db_perm = new DB_Contenido;
        }

        $area = $this->getIDForArea($area);
        $action = $this->getIDForAction($action);

        if ($action == 0) {
            $area = $this->getParentAreaId($area);
        }

        $area = $this->getIDForArea($area);

        if (!$this->have_perm()) {

            if ($action == 0 && $area_rights[$area]) {
                //if have action for area + action   check right for client and lang
                return ($this->have_perm_client_lang($client, $lang));
            }

            //check rights for the action in this area
            if ($area_rights[$area][$action]) {
                //if have action for area + action   check right for client and lang
                return $this->have_perm_client_lang($client, $lang);
            }

            return false;
        }
        return true;
    }

    function have_perm_client_lang($client, $lang) {
        // Changed back to a full featured function, as have_perm
        // needs $client as global variable - not provided by this
        // function
        //return ($this->have_perm("client[$client],lang[$lang]"));

        global $auth;

        if (!isset($auth->auth['perm'])) {
            $auth->auth['perm'] = '';
        }

        // Split the permissions of the user
        $userperm = explode(',', $auth->auth['perm']);

        if (in_array('sysadmin', $userperm)) {
            return true; // User is sysadmin
        } elseif (in_array("admin[$client]", $userperm)) {
            return true; // User is admin
        } else {
            // Check rights for the client and the language
            $pageperm = explode(',', "client[$client],lang[$lang]");
            foreach ($pageperm as $value) {
                if (!in_array($value, $userperm)) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * hasClientPermission
     * Checks if a user has access rights for a specific client.
     * 
     * @param integer $iClient    idclient to check, or false for the current client
     * @param object  $oUser    User object to check against, or false for the current user    
     */
    function hasClientPermission($iClient = false, $oUser = false) {
        global $auth;

        if ($iClient === false) {
            global $client;
            $iClient = $client;
        }

        $oUser = $this->_checkUserObject($oUser);

        if ($this->isSysadmin($oUser) || $this->isClientAdmin($iClient, $oUser) || $this->isClientUser($iClient, $oUser)) {
            return true;
        } else {
            return false;
        }
        /* Commented out Timo Trautmann, because here only client access is checked, possibility for admin or sysadmin access was ignored 
          functions isSysadmin isClientAdmin isClientUser also handles permission for groups
          #Check clients' rights of users' group(s)
          $aGroups = $this->getGroupsForUser($auth->auth["uid"]);
          if (is_array($aGroups))
          {
          foreach ($aGroups as $group)
          {
          $oGroup = new Group;
          $oGroup->loadGroupByGroupID ($group);

          if ($this->isClientGroup($iClient, $oGroup))
          {
          return true;
          }
          }
          }

          return false;
          } */
    }

    /**
     * isClientUser
     * Checks if the given user has access permission for a client
     * 
     * @param integer    $iClient    idclient to check
     * @param object     $oUser        User object to check against
     */
    function isClientUser($iClient, $oUser) {
        $oUser = $this->_checkUserObject($oUser);

        $aPermissions = explode(",", $oUser->getEffectiveUserPerms());

        if (in_array("client[$iClient]", $aPermissions)) {
            return true;
        }

        return false;
    }

    /**
     * isClientGroup
     * Checks if the given group has access permission for a client
     * 
     * @param integer    $iClient    idclient to check
     * @param object     $oGroup        Group object to check against
     */
    function isClientGroup($iClient, $oGroup) {
        $aPermissions = explode(",", $oGroup->getField("perms"));

        if (in_array("client[$iClient]", $aPermissions)) {
            return true;
        }

        return false;
    }

    /**
     * isClientAdmin
     * Checks if the given user has an admin permission
     * 
     * @param integer    $iClient    idclient to check
     * @param object     $oUser        User object to check against
     */
    function isClientAdmin($iClient, $oUser) {
        $oUser = $this->_checkUserObject($oUser);

        $aPermissions = explode(",", $oUser->getEffectiveUserPerms());
        if (in_array("admin[$iClient]", $aPermissions)) {
            return true;
        }

        return false;
    }

    /**
     * Checks if the given user has sysadmin permission
     * 
     * @param User $oUser userobject or false (default)
     * @return boolean true if user is sysadmin
     */
    public function isSysadmin($oUser = FALSE) {
        $oUser2Check = $this->_checkUserObject($oUser);
        if(!is_object($oUser2Check)) {
            return false;
        }
        $aPermissions = explode(",", $oUser2Check->getEffectiveUserPerms());
        if (in_array("sysadmin", $aPermissions)) {
            return true;
        }
        return false;
    }

    /**
     * _checkUserObject
     * 
     * Checks if the given object is a user object. 
     * 
     * If oUser is false, initialize the object from the currently logged in user. If oUser is not
     * a object of the class User, issue a warning.
     * 
     * @parameter object oUser User object
     * @access private
     */
    private function _checkUserObject($oUser) {
        if ($oUser === false) {
            global $currentuser;
            $oUser = $currentuser;
        }

        if (!is_object($oUser)) {
            global $auth;
            $oUser = new User;
            $oUser->loadUserByUserID($auth->auth["uid"]);
        }

        if (strtolower(get_class($oUser)) != "user") {
            cWarning(__FILE__, __LINE__, "oUser parameter is not of type User");
        }

        return $oUser;
    }

    /**
     * @deprecated
     */
    function have_perm_client($p = 'x') {
        global $auth, $client;

        if (!isset($auth->auth['perm'])) {
            $auth->auth['perm'] = '';
        }

        //split the permissions of the user
        $userperm = explode(',', $auth->auth['perm']);

        //if User is sysadmin or admin at this client return true
        if (in_array('sysadmin', $userperm)) {
            return true;
        }

        //if there are more permissions to ask split them
        $pageperm = explode(',', $p);
        foreach ($pageperm as $value) {
            if (!in_array($value, $userperm)) {
                return false;
            }
        }
        return true;
    }

    function have_perm($p = 'x') {
        global $auth, $client;

        if (!isset($auth->auth['perm'])) {
            $auth->auth['perm'] = '';
        }

        //split the permissions of the user
        $userperm = explode(',', $auth->auth['perm']);

        //if User is sysadmin or admin at this client return true
        if (in_array('sysadmin', $userperm)) {
            return true;
        } elseif (in_array("admin[$client]", $userperm)) {
            return true;
            //else check rights for the client and the language
        } else {
            //if there are more permissions to ask split them
            $pageperm = explode(',', $p);
            foreach ($pageperm as $value) {
                if (!in_array($value, $userperm)) {
                    return false;
                }
            }
        }
        return true;
    }

    //checks if an item have any perms
    function have_perm_item($mainarea, $itemid) {

        global $cfg, $item_rights, $cfg, $client, $lang, $auth, $area_tree, $sess;

        $mainarea = $this->getIDForArea($mainarea);

        //if is not admin or sysadmin
        if (!$this->have_perm()) {

            if (!is_object($this->db)) {
                $this->db = new DB_Contenido;
            }

            $this->showareas($mainarea);

            $flg = false;
            //check if there are any rights for this areas
            foreach ($area_tree[$mainarea] as $value) {
                // if the flag noright is set there are no rights in this area
                if ($item_rights[$value] == "noright") {
                    continue;
                } elseif (is_array($item_rights[$value])) {
                    //if there are any rights
                    foreach ($item_rights[$value] as $value2) {
                        if (in_array($itemid, $value2)) {
                            return true;
                        }
                    }
                } elseif ($item_rights[$value] != "noright") {

                    $groupsForUser = $this->getGroupsForUser($auth->auth['uid']);
                    $groupsForUser[] = $auth->auth['uid'];

                    //else search for rights for this user in this area
                    $sql = "SELECT
                                            *
                                         FROM
                                            " . $cfg["tab"]["rights"] . "
                                         WHERE
                                            user_id IN ('" . implode("','", $groupsForUser) . "') AND
                                            idclient = '" . Contenido_Security::toInteger($client) . "' AND
                                            idlang = '" . Contenido_Security::toInteger($lang) . "' AND
                                            idarea = '$value' AND
                                            idcat != '0'";
                    $this->db->query($sql);

                    //if there are no rights for this area set the flag norights
                    if ($this->db->affected_rows() == 0) {
                        $item_rights[$value] = "noright";
                    }

                    //set the rights
                    while ($this->db->next_record()) {
                        if ($this->db->f("idcat") == $itemid) {
                            $flg = true;
                        }
                        $item_rights[$this->db->f("idarea")][$this->db->f("idaction")][$this->db->f("idcat")] = $this->db->f("idcat");
                    }
                } //end if
            } //end for
            return $flg;
        } //end if
        return true;
    }

    function showareas($mainarea) {

        global $area_tree, $sess, $perm, $cfg;

        if (!is_object($this->db)) {
            $this->db = new DB_Contenido;
        }

        $mainarea = $this->getIDForArea($mainarea);

        //if $area_tree for this area is not register
        if (!isset($area_tree[$mainarea])) {
            $sess->register("area_tree");

            // parent_id uses the name not the idarea
            $sql = "SELECT
                              name
                           FROM
                              " . $cfg["tab"]["area"] . "
                           WHERE
                              idarea='$mainarea'";

            $this->db->query($sql);
            $this->db->next_record();
            $name = $this->db->f("name");

            //check which subareas are there and write them in the array
            $sql = "SELECT
                              idarea
                           FROM
                              " . $cfg["tab"]["area"] . "
                           WHERE
                              parent_id='$name' OR
                              idarea='$mainarea'";

            $this->db->query($sql);
            $area_tree[$mainarea] = array();
            while ($this->db->next_record()) {
                $area_tree[$mainarea][] = $this->db->f("idarea");
            }
        }
        return $mainarea;
    }

}
