<?php

/* Reminder: always indent with 4 spaces (no tabs). */
// +---------------------------------------------------------------------------+
// | Geeklog 1.5                                                               |
// +---------------------------------------------------------------------------+
// | group.php                                                                 |
// |                                                                           |
// | Geeklog group administration page.                                        |
// +---------------------------------------------------------------------------+
// | Copyright (C) 2000-2008 by the following authors:                         |
// |                                                                           |
// | Authors: Tony Bibbs        - tony AT tonybibbs DOT com                    |
// |          Mark Limburg      - mlimburg AT users DOT sourceforge DOT net    |
// |          Jason Whittenburg - jwhitten AT securitygeeks DOT com            |
// |          Dirk Haun         - dirk AT haun-online DOT de                   |
// +---------------------------------------------------------------------------+
// |                                                                           |
// | This program is free software; you can redistribute it and/or             |
// | modify it under the terms of the GNU General Public License               |
// | as published by the Free Software Foundation; either version 2            |
// | of the License, or (at your option) any later version.                    |
// |                                                                           |
// | This program is distributed in the hope that it will be useful,           |
// | but WITHOUT ANY WARRANTY; without even the implied warranty of            |
// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             |
// | GNU General Public License for more details.                              |
// |                                                                           |
// | You should have received a copy of the GNU General Public License         |
// | along with this program; if not, write to the Free Software Foundation,   |
// | Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.           |
// |                                                                           |
// +---------------------------------------------------------------------------+
//
// $Id: group.php,v 1.103 2008/06/07 12:41:44 dhaun Exp $

/**
* This file is the Geeklog Group administration page
*
* @author   Tony Bibbs  <tony@tonybibbs.com>
*
*/

/**
* Geeklog common function library
*/
require_once '../lib-common.php';

/**
* Verifies that current user even has access to the page to this point
*/
require_once 'auth.inc.php';

// Uncomment the line below if you need to debug the HTTP variables being passed
// to the script.  This will sometimes cause errors but it will allow you to see
// the data being passed in a POST operation
// echo COM_debug($_POST);

$display = '';

// Make sure user has rights to access this page
if (!SEC_hasRights ('group.edit')) {
    $display .= COM_siteHeader ('menu', $MESSAGE[30]);
    $display .= COM_startBlock ($MESSAGE[30], '',
                                COM_getBlockTemplate ('_msg_block', 'header'));
    $display .= $MESSAGE[37];
    $display .= COM_endBlock (COM_getBlockTemplate ('_msg_block', 'footer'));
    $display .= COM_siteFooter ();
    COM_accessLog ("User {$_USER['username']} tried to illegally access the group administration screen.");
    echo $display;
    exit;
}

/**
* Shows the group editor form
*
* @param    string      $grp_id     ID of group to edit
* @return   string      HTML for group editor
*
*/
function editgroup($grp_id = '')
{
    global $_TABLES, $_CONF, $_USER, $LANG_ACCESS, $LANG_ADMIN, $MESSAGE,
           $LANG28, $VERBOSE;

    $retval = '';

    $thisUsersGroups = SEC_getUserGroups ();
    if (!empty ($grp_id) &&
        ($grp_id > 0) &&
        !in_array ($grp_id, $thisUsersGroups) &&
        !SEC_groupIsRemoteUserAndHaveAccess($grp_id, $thisUsersGroups)) {
        $retval .= COM_startBlock ($LANG_ACCESS['groupeditor'], '',
                           COM_getBlockTemplate ('_msg_block', 'header'));
        if (!SEC_inGroup ('Root') && (DB_getItem ($_TABLES['groups'],
                'grp_name', "grp_id = $grp_id") == 'Root')) {
            $retval .= $LANG_ACCESS['canteditroot'];
            COM_accessLog ("User {$_USER['username']} tried to edit the Root group with insufficient privileges.");
        } else {
            $retval .= $LANG_ACCESS['canteditgroup'];
        }
        $retval .= COM_endBlock (COM_getBlockTemplate ('_msg_block', 'footer'));

        return $retval;
    }

    $group_templates = new Template($_CONF['path_layout'] . 'admin/group');
    $group_templates->set_file('editor','groupeditor.thtml');
    $group_templates->set_var('site_url', $_CONF['site_url']);
    $group_templates->set_var('site_admin_url', $_CONF['site_admin_url']);
    $group_templates->set_var('layout_url', $_CONF['layout_url']);
    $group_templates->set_var('lang_save', $LANG_ADMIN['save']);
    $group_templates->set_var('lang_cancel', $LANG_ADMIN['cancel']);
    $group_templates->set_var('lang_admingroup',$LANG28[49]);
    $group_templates->set_var('lang_admingrp_msg', $LANG28[50]);
    $group_templates->set_var( 'xhtml', XHTML );
    $showall = 0;
    if (isset ($_GET['chk_showall'])) {
        $showall =  COM_applyFilter ($_GET['chk_showall'], true);
    }
    $group_templates->set_var('show_all', $showall);

    if (!empty ($grp_id)) {
        $result = DB_query ("SELECT grp_id,grp_name,grp_descr,grp_gl_core FROM {$_TABLES['groups']} WHERE grp_id ='$grp_id'");
        $A = DB_fetchArray ($result);
        if ($A['grp_gl_core'] > 0) {
            $group_templates->set_var ('chk_adminuse', 'checked="checked"');
        }
    } else {
        // new group, so it's obviously not a core group
        $A['grp_gl_core'] = 0;
    }

    $retval .= COM_startBlock ($LANG_ACCESS['groupeditor'], '',
                               COM_getBlockTemplate ('_admin_block', 'header'));

    if (!empty($grp_id)) {
        // Groups tied to Geeklog's functionality shouldn't be deleted
        if ($A['grp_gl_core'] != 1) {
            $delbutton = '<input type="submit" value="' . $LANG_ADMIN['delete']
                       . '" name="mode"%s' . XHTML . '>';
            $jsconfirm = ' onclick="return confirm(\'' . $MESSAGE[76] . '\');"';
            $group_templates->set_var ('delete_option',
                                       sprintf ($delbutton, $jsconfirm));
            $group_templates->set_var ('delete_option_no_confirmation',
                                       sprintf ($delbutton, ''));
            $group_templates->set_var ('group_core', 0);
        } else {
            $group_templates->set_var ('group_core', 1);
        }
        $group_templates->set_var ('group_id', $A['grp_id']);
    } else {
        $group_templates->set_var ('group_core', 0);
    }

    $group_templates->set_var('lang_groupname', $LANG_ACCESS['groupname']);

    if ($A['grp_gl_core'] != 1) {
        $group_templates->set_var('groupname_inputtype', 'text');
        $group_templates->set_var('groupname_static', '');
    } else {
        $group_templates->set_var('groupname_inputtype', 'hidden');
        $group_templates->set_var('groupname_static', $A['grp_name']);
    }
    if (isset ($A['grp_name'])) {
        $group_templates->set_var('group_name', $A['grp_name']);
    } else {
        $group_templates->set_var('group_name', '');
    }

    $group_templates->set_var('lang_description', $LANG_ACCESS['description']);
    if (isset ($A['grp_descr'])) {
        $group_templates->set_var('group_description', $A['grp_descr']);
    } else {
        $group_templates->set_var('group_description', '');
    }
    $group_templates->set_var('lang_securitygroups', $LANG_ACCESS['securitygroups']);

    //$groups = SEC_getUserGroups('','',$grp_id);
    $selected = '';
    if (!empty($grp_id)) {
        $tmp = DB_query("SELECT ug_main_grp_id FROM {$_TABLES['group_assignments']} WHERE ug_grp_id = $grp_id");
        $num_groups = DB_numRows($tmp);
        for ($x = 1; $x <= $num_groups; $x++) {
            $G = DB_fetchArray($tmp);
            if ($x > 1) {
                $selected .= ' ' . $G['ug_main_grp_id'];
            } else {
                $selected .= $G['ug_main_grp_id'];
            }
        }
    }
    if ($A['grp_gl_core'] == 1) {
        $group_templates->set_var('lang_securitygroupmsg', $LANG_ACCESS['coregroupmsg']);
        $group_templates->set_var('hide_adminoption',' style="display:none;"');

        if (!empty($selected)) {
            $inclause = str_replace(' ',',',$selected);
            $result= DB_query("SELECT grp_id,grp_name FROM {$_TABLES['groups']} WHERE grp_id <> $grp_id AND grp_id in ($inclause) ORDER BY grp_name");
            $nrows = DB_numRows($result);
        } else {
            $nrows = 0;
        }

        if ($nrows == 0) {
            // this group doesn't belong to anything...give a friendly message
            $group_templates->set_var('group_options', $LANG_ACCESS['nogroupsforcoregroup']);
        } else {
            $groupoptions = '';
            for ($i = 1; $i <= $nrows; $i++) {
                $GRPS = DB_fetchArray($result);
                $groupoptions .= $GRPS['grp_name'] . '<input type="hidden" name="groups[]" value="' . $GRPS['grp_id'] . '"' . XHTML . '><br' . XHTML . '>' .LB;
            }
            $group_templates->set_var('group_options', $groupoptions);
        }
    } else {
        $group_templates->set_var('lang_securitygroupmsg', $LANG_ACCESS['groupmsg']);
        $group_templates->set_var('hide_adminoption','');
        if ($VERBOSE) {
            COM_errorLog("SELECTED: $selected");
        }

        // make sure to list only those groups of which the Group Admin
        // is a member
        $whereGroups = '(grp_id IN (' . implode (',', $thisUsersGroups) . '))';

        // You can no longer give access to the Root group....
        // it's pointless and doesn't make any sense
        if (!empty($grp_id)) {
            $group_templates->set_var ('group_options', COM_checkList ($_TABLES['groups'], 'grp_id,grp_name', "(grp_id <> $grp_id) AND (grp_name <> 'Root') AND " . $whereGroups, $selected));
        } else {
            $group_templates->set_var ('group_options', COM_checkList ($_TABLES['groups'], 'grp_id,grp_name', "(grp_name <> 'Root') AND " . $whereGroups, ''));
        }
    }
    $group_templates->set_var('lang_rights', $LANG_ACCESS['rights']);

    if ($A['grp_gl_core'] == 1) {
        $group_templates->set_var('lang_rightsmsg', $LANG_ACCESS['corerightsdescr']);
    } else {
        $group_templates->set_var('lang_rightsmsg', $LANG_ACCESS['rightsdescr']);
    }

    $group_templates->set_var('rights_options', printrights($grp_id, $A['grp_gl_core']));
    $group_templates->set_var('gltoken_name', CSRF_TOKEN);
    $group_templates->set_var('gltoken', SEC_createToken());
    $group_templates->parse('output','editor');
    $retval .= $group_templates->finish($group_templates->get_var('output'));
    $retval .= COM_endBlock (COM_getBlockTemplate ('_admin_block', 'footer'));

    return $retval;
}


/**
* Get the indirect features for a group, i.e. a list of all the features
* that this group inherited from other groups.
*
* @param    int      $grp_id   ID of group
* @return   string   comma-separated list of feature names
*
*/
function getIndirectFeatures ($grp_id)
{
    global $_TABLES;

    $checked = array ();
    $tocheck = array ($grp_id);

    do {
        $grp = array_pop ($tocheck);

        $result = DB_query ("SELECT ug_main_grp_id FROM {$_TABLES['group_assignments']} WHERE ug_grp_id = $grp AND ug_uid IS NULL");
        $numrows = DB_numRows ($result);

        $checked[] = $grp;

        for ($j = 0; $j < $numrows; $j++) {
            $A = DB_fetchArray ($result);
            if (!in_array ($A['ug_main_grp_id'], $checked) &&
                !in_array ($A['ug_main_grp_id'], $tocheck)) {
                $tocheck[] = $A['ug_main_grp_id'];
            }
        }
    }
    while (sizeof ($tocheck) > 0);

    // get features for all groups in $checked
    $glist = join (',', $checked);
    $result = DB_query("SELECT DISTINCT ft_name FROM {$_TABLES['access']},{$_TABLES['features']} WHERE ft_id = acc_ft_id AND acc_grp_id IN ($glist)");
    $nrows = DB_numRows ($result);

    $retval = '';
    for ($j = 1; $j <= $nrows; $j++) {
        $A = DB_fetchArray ($result);
        $retval .= $A['ft_name'];
        if ($j < $nrows) {
            $retval .= ',';
        }
    }

    return $retval;
}

/**
* Prints the features a group has access.  Please follow the comments in the
* code closely if you need to modify this function. Also right is synonymous
* with feature.
*
* @param    mixed       $grp_id     ID to print rights for
* @param    boolean     $core       indicates if group is a core Geeklog group
* @return   string      HTML for rights
*
*/
function printrights ($grp_id = '', $core = 0)
{
    global $_TABLES, $_USER, $LANG_ACCESS, $VERBOSE;

    // $VERBOSE = true;
    // this gets a bit complicated so bear with the comments

    // get a list of all the features that the current user (i.e. Group Admin)
    // has access to, so we only include these features in the list below
    if (!SEC_inGroup('Root')) {
        $GroupAdminFeatures = SEC_getUserPermissions ();
        $availableFeatures = explode (',', $GroupAdminFeatures);
        $GroupAdminFeatures = "'" . implode ("','", $availableFeatures) . "'";
        $ftWhere = ' WHERE ft_name IN (' . $GroupAdminFeatures . ')';
    } else {
        $ftWhere = '';
    }

    // now query for all available features
    $features = DB_query ("SELECT ft_id,ft_name,ft_descr FROM {$_TABLES['features']}{$ftWhere} ORDER BY ft_name");
    $nfeatures = DB_numRows($features);

    $grpftarray = array ();
    if (!empty($grp_id)) {
        // now get all the feature this group gets directly
         $directfeatures = DB_query("SELECT acc_ft_id,ft_name FROM {$_TABLES['access']},{$_TABLES['features']} WHERE ft_id = acc_ft_id AND acc_grp_id = $grp_id",1);

        // now in many cases the features will be given to this user indirectly
        // via membership to another group.  These are not editable and must,
        // instead, be removed from that group directly
        $indirectfeatures = getIndirectFeatures ($grp_id);
        $indirectfeatures = explode (',', $indirectfeatures);

        // Build an array of indirect features
        for ($i = 0; $i < sizeof($indirectfeatures); $i++) {
            $grpftarray[current($indirectfeatures)] = 'indirect';
            next($indirectfeatures);
        }

        // Build an arrray of direct features
        $grpftarray1 = array ();
        $ndirect = DB_numRows($directfeatures);
        for ($i = 0; $i < $ndirect; $i++) {
            $A = DB_fetchArray($directfeatures);
            $grpftarray1[$A['ft_name']] = 'direct';
        }

        // Now merge the two arrays
        $grpftarray = array_merge ($grpftarray, $grpftarray1);
        if ($VERBOSE) {
            // this is for debugging purposes
            for ($i = 1; $i < sizeof($grpftarray); $i++) {
                COM_errorLog("element $i is feature " . key($grpftarray) . " and is " . current($grpftarray),1);
                next($grpftarray);
            }
        }
    }

    // OK, now loop through and print all the features giving edit rights
    // to only the ones that are direct features
    $ftcount = 0;
    $retval = '<tr>' . LB;
    for ($i = 1; $i <= $nfeatures; $i++) {
        if ($i > 0 AND ($i % 3 == 1)) {
            $retval .= "</tr>\n<tr>";
        }
        $A = DB_fetchArray($features);

        if ((empty($grpftarray[$A['ft_name']]) OR ($grpftarray[$A['ft_name']] == 'direct')) AND ($core != 1)) {
            $ftcount++;
            $retval .= '<td><input type="checkbox" name="features[]" value="'. $A['ft_id'] . '"';
            if (!empty ($grpftarray[$A['ft_name']])) {
                if ($grpftarray[$A['ft_name']] == 'direct') {
                    $retval .= ' checked="checked"';
                }
            }
            $retval .= XHTML . '><span title="' . $A['ft_descr'] . '">' . $A['ft_name']
                    . '</span></td>';
        } else {
            // either this is an indirect right OR this is a core feature
            if ((($core == 1) AND (isset ($grpftarray[$A['ft_name']]) AND (($grpftarray[$A['ft_name']] == 'indirect') OR ($grpftarray[$A['ft_name']] == 'direct')))) OR ($core != 1)) {
                $ftcount++;
                $retval .= '<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(<i title="'
                        . $A['ft_descr'] . '">' .  $A['ft_name'] . '</i>)</td>';
            }
        }
    }
    if ($ftcount == 0) {
        // This group doesn't have rights to any features
        $retval .= '<td colspan="3">' . $LANG_ACCESS['grouphasnorights'] . '</td>';
    }

    $retval .= '</tr>' . LB;

    return $retval;
}

/**
* Save a group to the database
*
* @param    string  $grp_id         ID of group to save
* @param    string  $grp_name       Group Name
* @param    string  $grp_descr      Description of group
* @param    boolean $grp_admin      Flag that indicates this is an admin use group
* @param    boolean $grp_gl_core    Flag that indicates if this is a core Geeklog group
* @param    array   $features       Features the group has access to
* @param    array   $groups         Groups this group will belong to
* @return   string                  HTML refresh or error message
*
*/
function savegroup ($grp_id, $grp_name, $grp_descr, $grp_admin, $grp_gl_core, $features, $groups)
{
    global $_CONF, $_TABLES, $_USER, $LANG_ACCESS, $VERBOSE;

    $retval = '';
    if (!empty ($grp_name) && !empty ($grp_descr)) {
        $GroupAdminGroups = SEC_getUserGroups ();
        if (!empty ($grp_id) &&
            ($grp_id > 0) &&
            !in_array ($grp_id, $GroupAdminGroups) &&
            !SEC_groupIsRemoteUserAndHaveAccess($grp_id, $GroupAdminGroups)) {
            COM_accessLog ("User {$_USER['username']} tried to edit group '$grp_name' ($grp_id) with insufficient privileges.");

            return COM_refresh ($_CONF['site_admin_url'] . '/group.php');
        }

        if ($grp_gl_core == 1 AND !is_array ($features)) {
            COM_errorLog ("Sorry, no valid features were passed to this core group ($grp_id) and saving could cause problem...bailing.");

            return COM_refresh ($_CONF['site_admin_url'] . '/group.php');
        }

        // group names have to be unique, so check if this one exists already
        $g_id = DB_getItem ($_TABLES['groups'], 'grp_id',
                            "grp_name = '$grp_name'");
        if ($g_id > 0) {
            if (empty ($grp_id) || ($grp_id != $g_id)) {
                // there already is a group with that name - complain
                $retval .= COM_siteHeader ('menu', $LANG_ACCESS['groupeditor']);
                $retval .= COM_startBlock ($LANG_ACCESS['groupexists'], '',
                           COM_getBlockTemplate ('_msg_block', 'header'));
                $retval .= $LANG_ACCESS['groupexistsmsg'];
                $retval .= COM_endBlock (COM_getBlockTemplate ('_msg_block', 'footer'));
                $retval .= editgroup ($grp_id);
                $retval .= COM_siteFooter ();

                return $retval;
            }
        }

        $grp_descr = COM_stripslashes ($grp_descr);
        $grp_descr = addslashes ($grp_descr);

        if (empty ($grp_id)) {
            DB_save ($_TABLES['groups'], 'grp_name,grp_descr,grp_gl_core',
                     "'$grp_name','$grp_descr',$grp_gl_core");
            $grp_id = DB_getItem ($_TABLES['groups'], 'grp_id',
                                  "grp_name = '$grp_name'");
            $new_group = true;
        } else {
            DB_save ($_TABLES['groups'],
                     'grp_id,grp_name,grp_descr,grp_gl_core',
                     "$grp_id,'$grp_name','$grp_descr',$grp_gl_core");
            $new_group = false;
        }

        if (empty($grp_id) || ($grp_id < 1)) {
            // "this shouldn't happen"
            COM_errorLog("Internal error: invalid group id");
            $retval .= COM_siteHeader('menu', $LANG_ACCESS['groupeditor']);
            $retval .= COM_showMessage(95);
            $retval .= COM_siteFooter();

            return $retval;
        }

        // Use the field grp_gl_core to indicate if this is non-core GL Group is an Admin related group
        if (($grp_gl_core != 1) AND ($grp_id > 1)) {
            if ($grp_admin == 'on') {
                DB_query("UPDATE {$_TABLES['groups']} SET grp_gl_core=2 WHERE grp_id=$grp_id");
            } else {
                DB_query("UPDATE {$_TABLES['groups']} SET grp_gl_core=0 WHERE grp_id=$grp_id");
            }
        }

        // now save the features
        DB_delete ($_TABLES['access'], 'acc_grp_id', $grp_id);
        if (SEC_inGroup ('Root')) {
            for ($i = 1; $i <= sizeof ($features); $i++) {
                DB_query ("INSERT INTO {$_TABLES['access']} (acc_ft_id,acc_grp_id) VALUES (" . current ($features) . ",$grp_id)");
                next ($features);
            }
        } else {
            $GroupAdminFeatures = SEC_getUserPermissions ();
            $availableFeatures = explode (',', $GroupAdminFeatures);
            for ($i = 1; $i <= sizeof($features); $i++) {
                if (in_array (current ($features), $availableFeatures)) {
                    DB_query("INSERT INTO {$_TABLES['access']} (acc_ft_id,acc_grp_id) VALUES (" . current($features) . ",$grp_id)");
                    next($features);
                }
            }
        }
        if ($VERBOSE) {
            COM_errorLog('groups = ' . $groups);
            COM_errorLog("deleting all group_assignments for group $grp_id/$grp_name",1);
        }

        DB_delete ($_TABLES['group_assignments'], 'ug_grp_id', $grp_id);
        if (!empty ($groups)) {
            for ($i = 1; $i <= sizeof ($groups); $i++) {
                if (in_array ($grp_id, $GroupAdminGroups)) {
                    if ($VERBOSE) COM_errorLog("adding group_assignment " . current($groups) . " for $grp_name",1);
                    $sql = "INSERT INTO {$_TABLES['group_assignments']} (ug_main_grp_id, ug_grp_id) VALUES (" . current($groups) . ",$grp_id)";
                    DB_query($sql);
                }
                next($groups);
            }
        }

        // Make sure Root group belongs to any new group
        if (DB_getItem ($_TABLES['group_assignments'], 'COUNT(*)',
                "ug_main_grp_id = $grp_id AND ug_grp_id = 1") == 0) {
            DB_query("INSERT INTO {$_TABLES['group_assignments']} (ug_main_grp_id, ug_grp_id) VALUES ($grp_id, 1)");
        }

        // make sure this Group Admin belongs to the new group
        if (!SEC_inGroup ('Root')) {
            if (DB_count ($_TABLES['group_assignments'], 'ug_uid',
            "(ug_uid = {$_USER['uid']}) AND (ug_main_grp_id = $grp_id)") == 0) {
                DB_query ("INSERT INTO {$_TABLES['group_assignments']} (ug_main_grp_id, ug_uid) VALUES ($grp_id,{$_USER['uid']})");
            }
        }

        if ($new_group) {
            PLG_groupChanged ($grp_id, 'new');
        } else {
            PLG_groupChanged ($grp_id, 'edit');
        }
        if ($_POST['chk_showall'] == 1) {
            echo COM_refresh($_CONF['site_admin_url'] . '/group.php?msg=49&showall=1');
        } else {
            echo COM_refresh($_CONF['site_admin_url'] . '/group.php?msg=49');
        }
    } else {
        $retval .= COM_siteHeader ('menu', $LANG_ACCESS['groupeditor']);
        $retval .= COM_startBlock ($LANG_ACCESS['missingfields'], '',
                           COM_getBlockTemplate ('_msg_block', 'header'));
        $retval .= $LANG_ACCESS['missingfieldsmsg'];
        $retval .= COM_endBlock (COM_getBlockTemplate ('_msg_block', 'footer'));
        $retval .= editgroup ($grp_id);
        $retval .= COM_siteFooter ();

        return $retval;
    }
}

/**
* Get a list (actually an array) of all groups this group belongs to.
*
* @param   basegroup   int     id of group
* @return              array   array of all groups 'basegroup' belongs to
*
*/
function getGroupList ($basegroup)
{
    global $_TABLES;

    $to_check = array ();
    array_push ($to_check, $basegroup);

    $checked = array ();

    while (sizeof ($to_check) > 0) {
        $thisgroup = array_pop ($to_check);
        if ($thisgroup > 0) {
            $result = DB_query ("SELECT ug_grp_id FROM {$_TABLES['group_assignments']} WHERE ug_main_grp_id = $thisgroup");
            $numGroups = DB_numRows ($result);
            for ($i = 0; $i < $numGroups; $i++) {
                $A = DB_fetchArray ($result);
                if (!in_array ($A['ug_grp_id'], $checked)) {
                    if (!in_array ($A['ug_grp_id'], $to_check)) {
                        array_push ($to_check, $A['ug_grp_id']);
                    }
                }
            }
            $checked[] = $thisgroup;
        }
    }

    return $checked;
}

/**
* Display a list of all users in a given group.
*
* @param   grp_id   int      group id
* @return           string   HTML for user listing
*
*/
function listusers ($grp_id)
{
    global $_CONF, $_TABLES, $LANG28, $LANG_ACCESS, $LANG_ADMIN, $_IMAGE_TYPE;

    require_once $_CONF['path_system'] . 'lib-admin.php';

    $retval = '';

    $thisUsersGroups = SEC_getUserGroups ();
    if (!empty ($grp_id) &&
        ($grp_id > 0) &&
        !in_array ($grp_id, $thisUsersGroups) &&
        !SEC_groupIsRemoteUserAndHaveAccess( $grp_id, $thisUsersGroups)) {
        $retval .= COM_startBlock ($LANG_ACCESS['usergroupadmin'], '',
                           COM_getBlockTemplate ('_msg_block', 'header'));
        $retval .= $LANG_ACCESS['cantlistgroup'];
        $retval .= COM_endBlock (COM_getBlockTemplate ('_msg_block', 'footer'));

        return $retval;
    }

    if ($_CONF['lastlogin']) {
        $login_text = $LANG28[41];
        $login_field = 'lastlogin';
    } else {
        $login_text = $LANG28[40];
        $login_field = 'regdate';
    }

    $header_arr = array (
        array('text' => $LANG_ADMIN['edit'], 'field' => 'edit', 'sort' => false),
        array('text' => $LANG28[37], 'field' => 'uid', 'sort' => true),
        array('text' => $LANG28[3], 'field' => 'username', 'sort' => true),
        array('text' => $LANG28[4], 'field' => 'fullname', 'sort' => true),
        array('text' => $login_text, 'field' => $login_field, 'sort' => true),
        array('text' => $LANG28[7], 'field' => 'email', 'sort' => true)
    );

    $defsort_arr = array ('field'     => 'username',
                          'direction' => 'asc'
    );

    $form_url = $_CONF['site_admin_url'] . '/group.php?mode=listusers&amp;grp_id='.$grp_id;
    if (isset ($_REQUEST['chk_showall']) && ($_REQUEST['chk_showall'] == 1)) {
        $form_url .= '&amp;chk_showall=1';
    }

    $groupname = DB_getItem ($_TABLES['groups'], 'grp_name',
                             "grp_id = '$grp_id'");
    $headline = sprintf ($LANG_ACCESS['usersingroup'], $groupname);

    $url = $_CONF['site_admin_url'] . '/group.php';
    if (isset ($_REQUEST['chk_showall']) && ($_REQUEST['chk_showall'] == 1)) {
        $url .= '?chk_showall=1';
    }
    $menu_arr = array (
                    array('url'  => $url,
                          'text' => $LANG28[38]),
                    array('url'  => $_CONF['site_admin_url'],
                          'text' => $LANG_ADMIN['admin_home']));

    $retval .= COM_startBlock($headline, '',
                              COM_getBlockTemplate('_admin_block', 'header'));

    $retval .= ADMIN_createMenu(
        $menu_arr,
        '&nbsp;',
        $_CONF['layout_url'] . '/images/icons/group.' . $_IMAGE_TYPE
    );

    $text_arr = array (
        'has_extras' => true,
        'form_url'   => $form_url,
        'help_url'   => ''
    );

    $join_userinfo = '';
    $select_userinfo = '';
    if ($_CONF['lastlogin']) {
        $join_userinfo = "LEFT JOIN {$_TABLES['userinfo']} ON {$_TABLES['users']}.uid={$_TABLES['userinfo']}.uid ";
        $select_userinfo = ",lastlogin ";
    }

    $groups = getGroupList ($grp_id);
    $groupList = implode (',', $groups);

    $sql = "SELECT DISTINCT {$_TABLES['users']}.uid,username,fullname,email,photo,regdate$select_userinfo "
          ."FROM {$_TABLES['group_assignments']},{$_TABLES['users']} $join_userinfo "
          ."WHERE {$_TABLES['users']}.uid > 1 "
          ."AND {$_TABLES['users']}.uid = {$_TABLES['group_assignments']}.ug_uid "
          ."AND ({$_TABLES['group_assignments']}.ug_main_grp_id IN ({$groupList}))";

    $query_arr = array ('table' => 'users',
                        'sql' => $sql,
                        'query_fields' => array('username', 'email', 'fullname'),
                        'default_filter' => "AND {$_TABLES['users']}.uid > 1"
    );

    $retval .= ADMIN_list('user', 'ADMIN_getListField_users', $header_arr,
                          $text_arr, $query_arr, $defsort_arr);
    $retval .= COM_endBlock(COM_getBlockTemplate('_admin_block', 'footer'));

    return $retval;
}

function listgroups()
{
    global $_CONF, $_TABLES, $LANG_ADMIN, $LANG_ACCESS, $LANG28, $_IMAGE_TYPE;

    require_once $_CONF['path_system'] . 'lib-admin.php';

    $retval = '';

    $header_arr = array(      // display 'text' and use table field 'field'
        array('text' => $LANG_ADMIN['edit'], 'field' => 'edit', 'sort' => false),
        array('text' => $LANG_ACCESS['groupname'], 'field' => 'grp_name', 'sort' => true),
        array('text' => $LANG_ACCESS['description'], 'field' => 'grp_descr', 'sort' => true),
        array('text' => $LANG_ACCESS['coregroup'], 'field' => 'grp_gl_core', 'sort' => true),
        array('text' => $LANG_ACCESS['listusers'], 'field' => 'list', 'sort' => false)
    );

    $defsort_arr = array('field' => 'grp_name', 'direction' => 'asc');

    $form_url = $_CONF['site_admin_url'] . '/group.php';
    if (isset ($_REQUEST['chk_showall']) && ($_REQUEST['chk_showall'] == 1)) {
        $form_url .= '?chk_showall=1';
    }

    $menu_arr = array (
        array('url' => $_CONF['site_admin_url'] . '/group.php?mode=edit',
              'text' => $LANG_ADMIN['create_new']),
        array('url' => $_CONF['site_admin_url'],
              'text' => $LANG_ADMIN['admin_home'])
    );

    $retval .= COM_startBlock($LANG_ACCESS['groupmanager'], '',
                              COM_getBlockTemplate('_admin_block', 'header'));

    $retval .= ADMIN_createMenu(
        $menu_arr,
        $LANG_ACCESS['newgroupmsg'],
        $_CONF['layout_url'] . '/images/icons/group.' . $_IMAGE_TYPE
    );

    $text_arr = array(
        'has_extras' => true,
        'form_url'   => $form_url
    );

    $filter = '<span style="padding-right:20px;">';

    // Extra test required to handle that different ways this option is passed and need to be able to
    // over-ride the option using the posted form when the URL contains the variable as well
    $show_all_groups = false;
    $checked ='';
    if (isset($_POST['q'])) {   // Form has been posted - test actual option in this form
        if ($_POST['chk_showall'] == 1) {
            $show_all_groups = true;
            $checked = ' checked';
        }
    } else if (isset ($_GET['chk_showall']) && ($_GET['chk_showall'] == 1)) {
        $show_all_groups = true;
        $checked = ' checked';
    }

    if (SEC_inGroup('Root')) {
        $grpFilter = '';
    } else {
        $thisUsersGroups = SEC_getUserGroups ();
        $grpFilter = 'AND (grp_id IN (' . implode (',', $thisUsersGroups) . '))';
    }

    if ($show_all_groups) {
        $filter .= '<label for="chk_showall"><input id="chk_showall" type="checkbox" name="chk_showall" value="1" checked="checked"' . XHTML . '>';
        $query_arr = array(
            'table' => 'groups',
            'sql' => "SELECT * FROM {$_TABLES['groups']} WHERE 1=1",
            'query_fields' => array('grp_name', 'grp_descr'),
            'default_filter' => $grpFilter);
    } else {
        $filter .= "<label for=\"chk_showall\"><input id=\"chk_showall\" type=\"checkbox\" name=\"chk_showall\" value=\"1\"$checked" . XHTML . ">";
        $query_arr = array(
            'table' => 'groups',
            'sql' => "SELECT * FROM {$_TABLES['groups']} WHERE (grp_gl_core = 0 OR grp_id in (2,13))",
            'query_fields' => array('grp_name', 'grp_descr'),
            'default_filter' => $grpFilter);
    }
    $filter .= $LANG28[48] . '</label></span>';

    $retval .= ADMIN_list('groups', 'ADMIN_getListField_groups', $header_arr,
                          $text_arr, $query_arr, $defsort_arr, $filter);
    $retval .= COM_endBlock(COM_getBlockTemplate('_admin_block', 'footer'));

    return $retval;
}

function grp_selectUsers ($group_id, $allusers = false)
{
    global $_TABLES, $_USER;

    $retval = '';

    // Get a list of users in the Root Group and the selected group
    $sql  = "SELECT DISTINCT uid FROM {$_TABLES['users']} LEFT JOIN {$_TABLES['group_assignments']} ";
    $sql .= "ON {$_TABLES['group_assignments']}.ug_uid = uid WHERE uid > 1 AND ";
    $sql .= "({$_TABLES['group_assignments']}.ug_main_grp_id = 1 OR {$_TABLES['group_assignments']}.ug_main_grp_id = $group_id)";
    $result = DB_query ($sql);
    $filteredusers = array();
    while ($A = DB_fetchArray($result)) {
        $filteredusers[] = $A['uid'];
    }

    $groups = getGroupList ($group_id);
    $grouplist = '(' . implode (',', $groups) . ')';
    $sql = "SELECT DISTINCT uid,username FROM {$_TABLES['users']} LEFT JOIN {$_TABLES['group_assignments']} ";
    $sql .= "ON {$_TABLES['group_assignments']}.ug_uid = uid WHERE uid > 1 AND ";
    $sql .= "{$_TABLES['group_assignments']}.ug_main_grp_id ";
    if ($allusers) {
        $sql .= 'NOT ';
    }
    $sql .= "IN {$grouplist} ";
    // Filter out the users that will be in the selected group
    if ($allusers) {
        $filteredusers = implode(',',$filteredusers);
        $sql .= " AND uid NOT IN ($filteredusers) ";
    }
    $sql .= "ORDER BY username";
    $result = DB_query ($sql);
    $numUsers = DB_numRows ($result);
    for ($i = 0; $i < $numUsers; $i++) {
        list($uid, $username) = DB_fetchArray ($result);
        $retval .= '<option value="' . $uid . '">' . $username . '</option>';
    }

    return $retval;
}

/**
* Allow easy addition/removal of users to/from a group
*
* @param    int     $group  Group ID
* @return   string          HTML form
*
*/
function editusers($group)
{
    global $_CONF, $_TABLES, $_USER, $LANG_ACCESS, $LANG_ADMIN, $LANG28;

    $retval = '';

    $thisUsersGroups = SEC_getUserGroups ();
    $groupName = DB_getItem($_TABLES['groups'],'grp_name',"grp_id='$group'");
    if (!empty ($group) &&
       ($group > 0) &&
       !in_array ($group, $thisUsersGroups) &&
       !SEC_groupIsRemoteUserAndHaveAccess($group, $thisUsersGroups)
       ) {
        $retval .= COM_startBlock ($LANG_ACCESS['usergroupadmin'], '',
                           COM_getBlockTemplate ('_msg_block', 'header'));
        if (!SEC_inGroup ('Root') && (DB_getItem ($_TABLES['groups'],
                'grp_name', "grp_id = $group") == 'Root')) {
            $retval .= $LANG_ACCESS['canteditroot'];
            COM_accessLog ("User {$_USER['username']} tried to edit the Root group with insufficient privileges.");
        } else {
            $retval .= $LANG_ACCESS['canteditgroup'];
        }
        $retval .= COM_endBlock (COM_getBlockTemplate ('_msg_block', 'footer'));

        return $retval;
    }

    $group_listing_url = $_CONF['site_admin_url'] . '/group.php';
    $showall = 0;
    if (isset($_REQUEST['chk_showall']) && ($_REQUEST['chk_showall'] == 1)) {
        $group_listing_url .= '?chk_showall=1';
        $showall = 1;
    }

    $retval .= COM_startBlock($LANG_ACCESS['usergroupadmin'] . " - $groupName" , '',
                       COM_getBlockTemplate('_admin_block', 'header'));
    $groupmembers = new Template($_CONF['path_layout'] . 'admin/group');
    $groupmembers->set_file(array('groupmembers'=>'groupmembers.thtml'));
    $groupmembers->set_var('site_url', $_CONF['site_url']);
    $groupmembers->set_var('site_admin_url', $_CONF['site_admin_url']);
    $groupmembers->set_var('group_listing_url', $group_listing_url);
    $groupmembers->set_var('layout_url', $_CONF['layout_url']);
    $groupmembers->set_var('phpself', $_CONF['site_admin_url'] . '/group.php');
    $groupmembers->set_var('lang_adminhome', $LANG_ACCESS['adminhome']);
    $groupmembers->set_var('lang_instructions', $LANG_ACCESS['editgroupmsg']);
    $groupmembers->set_var('LANG_sitemembers',$LANG_ACCESS['availmembers']);
    $groupmembers->set_var('LANG_grpmembers',$LANG_ACCESS['groupmembers']);
    $groupmembers->set_var('sitemembers', grp_selectUsers($group,true) );
    $groupmembers->set_var('group_list', grp_selectUsers($group) );
    $groupmembers->set_var('LANG_add',$LANG_ACCESS['add']);
    $groupmembers->set_var('LANG_remove',$LANG_ACCESS['remove']);
    $groupmembers->set_var('lang_save', $LANG_ADMIN['save']);
    $groupmembers->set_var('lang_cancel', $LANG_ADMIN['cancel']);
    $groupmembers->set_var('lang_grouplist', $LANG28[38]);
    $groupmembers->set_var('show_all', $showall);
    $groupmembers->set_var('group_id',$group);
    $groupmembers->set_var('xhtml', XHTML);
    $groupmembers->set_var('gltoken_name', CSRF_TOKEN);
    $groupmembers->set_var('gltoken', SEC_createToken());
    $groupmembers->parse('output', 'groupmembers');
    $retval .= $groupmembers->finish($groupmembers->get_var('output'));
    $retval .= COM_endBlock(COM_getBlockTemplate('_admin_block', 'footer'));

    return $retval;
}

function savegroupusers ($groupid, $groupmembers)
{
    global $_CONF, $_TABLES;

    // Delete all the current buddy records for this user and add all the selected ones
    $sql = "DELETE FROM {$_TABLES['group_assignments']} WHERE ug_main_grp_id={$groupid} AND ug_uid IS NOT NULL";
    DB_query($sql);
    $adduser = explode("|",$groupmembers);
    for( $i = 0; $i < count($adduser); $i++ )    {
        $adduser[$i] = COM_applyFilter($adduser[$i], true);
        DB_query("INSERT INTO {$_TABLES['group_assignments']} (ug_main_grp_id, ug_uid) VALUES ('$groupid', '$adduser[$i]')");
    }
    if ($_POST['chk_showall'] == 1) {
        echo COM_refresh($_CONF['site_admin_url'] . '/group.php?msg=49&showall=1');
    } else {
        echo COM_refresh($_CONF['site_admin_url'] . '/group.php?msg=49');
    }
}

/**
* Delete a group
*
* @param    int     $grp_id     id of group to delete
* @return   string              HTML redirect
*
*/
function deleteGroup ($grp_id)
{
    global $_CONF, $_TABLES, $_USER;

    if (!SEC_inGroup ('Root') && (DB_getItem ($_TABLES['groups'], 'grp_name',
            "grp_id = $grp_id") == 'Root')) {
        COM_accessLog ("User {$_USER['username']} tried to delete the Root group with insufficient privileges.");

        return COM_refresh ($_CONF['site_admin_url'] . '/group.php');
    }

    $GroupAdminGroups = SEC_getUserGroups ();
    if (!in_array ($grp_id, $GroupAdminGroups) && !SEC_groupIsRemoteUserAndHaveAccess($grp_id, $GroupAdminGroups)) {
        COM_accessLog ("User {$_USER['username']} tried to delete group $grp_id with insufficient privileges.");

        return COM_refresh ($_CONF['site_admin_url'] . '/group.php');
    }

    DB_delete ($_TABLES['access'], 'acc_grp_id', $grp_id);
    DB_delete ($_TABLES['group_assignments'], 'ug_grp_id', $grp_id);
    DB_delete ($_TABLES['group_assignments'], 'ug_main_grp_id', $grp_id);
    DB_delete ($_TABLES['groups'], 'grp_id', $grp_id);

    PLG_groupChanged ($grp_id, 'delete');
    if ($_POST['chk_showall'] == 1) {
        return COM_refresh($_CONF['site_admin_url'] . '/group.php?msg=50&showall=1');
    } else {
        return COM_refresh($_CONF['site_admin_url'] . '/group.php?msg=50');
    }
}

// MAIN
$mode = '';
if (isset($_REQUEST['mode'])) {
    $mode = $_REQUEST['mode'];
}

if (($mode == $LANG_ADMIN['delete']) && !empty ($LANG_ADMIN['delete'])) {
    $grp_id = COM_applyFilter ($_REQUEST['grp_id'], true);
    if (!isset ($grp_id) || empty ($grp_id) || ($grp_id == 0)) {
        COM_errorLog ('Attempted to delete group grp_id=' . $grp_id);
        $display .= COM_refresh ($_CONF['site_admin_url'] . '/group.php');
    } elseif (SEC_checkToken()) {
        $display .= deleteGroup ($grp_id);
    } else {
        COM_accessLog("User {$_USER['username']} tried to illegally delete group $grp_id and failed CSRF checks.");
        echo COM_refresh($_CONF['site_admin_url'] . '/index.php');
    }
} elseif (($mode == $LANG_ADMIN['save']) && !empty($LANG_ADMIN['save']) && SEC_checkToken()) {
    $chk_grpadmin = '';
    if (isset($_POST['chk_grpadmin'])) {
        $chk_grpadmin = COM_applyFilter($_POST['chk_grpadmin']);
    }
    $features = array();
    if (isset($_POST['features'])) {
        $features = $_POST['features'];
    }
    $groups = array();
    if (isset($_POST[$_TABLES['groups']])) {
        $groups = $_POST[$_TABLES['groups']];
    }
    $display .= savegroup(COM_applyFilter($_POST['grp_id'], true),
                          COM_applyFilter($_POST['grp_name']),
                          $_POST['grp_descr'], $chk_grpadmin,
                          COM_applyFilter($_POST['grp_gl_core']),
                          $features, $groups);
} else if (($mode == 'savegroupusers') && SEC_checkToken()) {
    $grp_id = COM_applyFilter ($_REQUEST['grp_id'], true);
    $display .= savegroupusers ($grp_id, $_POST['groupmembers']);
} else if ($mode == 'edit') {
    $grp_id = 0;
    if (isset ($_REQUEST['grp_id'])) {
        $grp_id = COM_applyFilter ($_REQUEST['grp_id'], true);
    }
    $display .= COM_siteHeader ('menu', $LANG_ACCESS['groupeditor']);
    $display .= editgroup ($grp_id);
    $display .= COM_siteFooter ();
} else if ($mode == 'listusers') {
    $grp_id = COM_applyFilter ($_REQUEST['grp_id'], true);
    $display .= COM_siteHeader ('menu', $LANG_ACCESS['groupmembers']);
    $display .= listusers ($grp_id);
    $display .= COM_siteFooter ();
} else if ($mode == 'editusers') {
    $grp_id = COM_applyFilter ($_REQUEST['grp_id'], true);
    $display .= COM_siteHeader ('menu', $LANG_ACCESS['usergroupadmin']);
    $display .= editusers ($grp_id);
    $display .= COM_siteFooter ();
} else { // 'cancel' or no mode at all
    $display .= COM_siteHeader ('menu', $LANG28[38]);
    if (isset ($_REQUEST['msg'])) {
        $display .= COM_showMessage (COM_applyFilter ($_REQUEST['msg'], true));
    }
    $display .= listgroups();
    $display .= COM_siteFooter();
}

echo $display;

?>
