<?php
// $Id: pnadmin.php,v 1.42.2.1 2006/01/12 13:03:22 markwest Exp $
// ----------------------------------------------------------------------
// PostNuke Content Management System
// Copyright (C) 2002 by the PostNuke Development Team.
// http://www.postnuke.com/
// ----------------------------------------------------------------------
// Based on:
// PHP-NUKE Web Portal System - http://phpnuke.org/
// Thatware - http://thatware.org/
// ----------------------------------------------------------------------
// LICENSE
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License (GPL)
// 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.
//
// To read the license please visit http://www.gnu.org/copyleft/gpl.html
// ----------------------------------------------------------------------
// Original Author of file: Mark West
// Purpose of file:  Groups administration display functions
// ----------------------------------------------------------------------

/**
 * @package PostNuke_System_Modules
 * @subpackage Groups
 * @license http://www.gnu.org/copyleft/gpl.html
*/
/**
 * Groups Module main administration function
 * This function is the default function, and is called whenever the
 * module is initiated without defining arguments.  As such it can
 * be used for a number of things, but most commonly it either just
 * shows the module menu and returns or calls whatever the module
 * designer feels should be the default function (often this is the
 * view() function)
 * @author Mark West
 * @version $Revision: 1.42.2.1 $
 * @return string HTML output string
 * @todo template output
 */
function Groups_admin_main()
{
    // Security check - important to do this as early as possible to avoid
    // potential security holes or just too much wasted processing.  For the
    // main function we want to check that the user has at least edit privilege
    // for some item within this component, or else they won't be able to do
    // anything and so we refuse access altogether.  The lowest level of access
    // for administration depends on the particular module, but it is generally
    // either 'edit' or 'delete'

    $any_access = false;
    // get all groups from the API
    $groups = pnModAPIFunc('Groups', 'user', 'getall');
    if (is_array($groups)) {
        foreach($groups as $group) {
            if (pnSecAuthAction(0, 'Groups::', $group['name'] . '::' . $group['gid'], ACCESS_EDIT)) {
                $any_access = true;
                break;
            }
        }
    }
    if ($any_access == false) {
        // we found no groups that we are allowed to administer
        // return now
        return pnVarPrepHTMLDisplay(_MODULENOAUTH);
    }

    // Create output object - this object will store all of our output so that
    // we can return it easily when required
    $pnRender =& new pnRender('Groups');

    // As Admin output changes often, we do not want caching.
    $pnRender->caching = false;

    // Return the output that has been generated by this function
    return $pnRender->fetch('groups_admin_main.htm');
}

/**
 * Add a new group
 * This is a standard function that is called whenever an administrator
 * wishes to create a new group
 * @author Mark West
 * @version $Revision: 1.42.2.1 $
 * @return string HTML output string
 * @todo template output
 */
function Groups_admin_new()
{
    // Security check - important to do this as early as possible to avoid
    // potential security holes or just too much wasted processing
    if (!pnSecAuthAction(0, 'Groups::', '::', ACCESS_ADD)) {
        pnVarPrepHTMLDisplay(_MODULENOAUTH);
    }

    // Create output object - this object will store all of our output so that
    // we can return it easily when required
    $pnRender =& new pnRender('Groups');

    // As Admin output changes often, we do not want caching.
    $pnRender->caching = false;

    // Return the output that has been generated by this function
    return $pnRender->fetch('groups_admin_new.htm');
}

/**
 * This is a standard function that is called with the results of the
 * form supplied by groups admin_new() to create a new group
 * @author Mark West
 * @version $Revision: 1.42.2.1 $
 * @param string 'name' the name of the group to be created
 * @return bool true if group created succesfully, false otherwise
 */
function Groups_admin_create($args)
{
    // Get parameters from whatever input we need.  All arguments to this
    // function should be obtained from pnVarCleanFromInput(), getting them
    // from other places such as the environment is not allowed, as that makes
    // assumptions that will not hold in future versions of PostNuke
    $name = pnVarCleanFromInput('name');

    // Admin functions of this type can be called by other modules.  If this
    // happens then the calling module will be able to pass in arguments to
    // this function through the $args parameter.  Hence we extract these
    // arguments *after* we have obtained any form-based input through
    // pnVarCleanFromInput().
    extract($args);

    // Confirm authorisation code.  This checks that the form had a valid
    // authorisation code attached to it.  If it did not then the function will
    // proceed no further as it is possible that this is an attempt at sending
    // in false data to the system
    if (!pnSecConfirmAuthKey()) {
        pnSessionSetVar('errormsg', _BADAUTHKEY);
        pnRedirect(pnModURL('Groups', 'admin', 'view'));
        return true;
    }

    // Notable by its absence there is no security check here.  This is because
    // the security check is carried out within the API function and as such we
    // do not duplicate the work here

    // The API function is called.  Note that the name of the API function and
    // the name of this function are identical, this helps a lot when
    // programming more complex modules.  The arguments to the function are
    // passed in as their own arguments array
    $check = pnModAPIFunc('Groups',
                          'admin',
                          'getgidbyname',
                          array('name' => $name));

    if ($check != false) {
        // Group already exists
        pnSessionSetVar('errormsg', _GROUPSALREADYEXISTS);
    } else {
        $gid = pnModAPIFunc('Groups',
                            'admin',
                            'create',
                            array('name' => $name));

        // The return value of the function is checked here, and if the function
        // suceeded then an appropriate message is posted.  Note that if the
        // function did not succeed then the API function should have already
        // posted a failure message so no action is required
        if ($gid != false) {
            // Success
            pnSessionSetVar('statusmsg', _GROUPSCREATED);
        }
    }

    // This function generated no output, and so now it is complete we redirect
    // the user to an appropriate page for them to carry on their work
    pnRedirect(pnModURL('Groups', 'admin', 'view'));

    // Return
    return true;
}

/**
 * modify a group
 * This is a standard function that is called whenever an administrator
 * wishes to modify a current group item
 * @author Mark West
 * @version $Revision: 1.42.2.1 $
 * @param int 'gid' the id of the group to be modified
 * @param int 'objectid' generic object id mapped onto gid if present
 * @return string HTML output string
 * @todo template output
 */
function Groups_admin_modify($args)
{
    // Get parameters from whatever input we need.  All arguments to this
    // function should be obtained from pnVarCleanFromInput(), getting them
    // from other places such as the environment is not allowed, as that makes
    // assumptions that will not hold in future versions of PostNuke
    list($gid,
         $objectid)= pnVarCleanFromInput('gid',
                                         'objectid');


    // Admin functions of this type can be called by other modules.  If this
    // happens then the calling module will be able to pass in arguments to
    // this function through the $args parameter.  Hence we extract these
    // arguments *after* we have obtained any form-based input through
    // pnVarCleanFromInput().
    extract($args);

    // At this stage we check to see if we have been passed $objectid, the
    // generic item identifier.  This could have been passed in by a hook or
    // through some other function calling this as part of a larger module, but
    // if it exists it overrides $tid
    //
    // Note that this module couuld just use $objectid everywhere to avoid all
    // of this munging of variables, but then the resultant code is less
    // descriptive, especially where multiple objects are being used.  The
    // decision of which of these ways to go is up to the module developer
    if (!empty($objectid)) {
        $gid = $objectid;
    }

    // The user API function is called.  This takes the item ID which we
    // obtained from the input and gets us the information on the appropriate
    // item.  If the item does not exist we post an appropriate message and
    // return
    $item = pnModAPIFunc('Groups',
                         'user',
                         'get',
                         array('gid' => $gid));

    if ($item == false) {
        return pnVarPrepHTMLDisplay(_GROUPSNOSUCHITEM);
    }

    // Security check - important to do this as early as possible to avoid
    // potential security holes or just too much wasted processing.  However,
    // in this case we had to wait until we could obtain the item name to
    // complete the instance information so this is the first chance we get to
    // do the check
    if (!pnSecAuthAction(0, 'Groups::', "$item[name]::$gid", ACCESS_EDIT)) {
        return pnVarPrepHTMLDisplay(_MODULENOAUTH);
    }

    // Create output object - this object will store all of our output so that
    // we can return it easily when required
    $pnRender =& new pnRender('Groups');

    // As Admin output changes often, we do not want caching.
    $pnRender->caching = false;

    // Add a hidden variable for the item id.  This needs to be passed on to
    // the update function so that it knows which item for which item to carry
    // out the update
    $pnRender->assign('gid', $gid);

	// assign the item
    $pnRender->assign($item);

    // Return the output that has been generated by this function
    return $pnRender->fetch('groups_admin_modify.htm');
}


/**
 * This is a standard function that is called with the results of the
 * form supplied by groups_admin_modify() to update a current group item
 * @author Mark West
 * @version $Revision: 1.42.2.1 $
 * @param int 'gid' the id of the group to be modified
 * @param int 'objectid' generic object id mapped onto gid if present
 * @param string 'name' the name of the group to be updated
 * @return bool true if group updated successfully, false otherwise
 */
function Groups_admin_update($args)
{
    // Get parameters from whatever input we need.  All arguments to this
    // function should be obtained from pnVarCleanFromInput(), getting them
    // from other places such as the environment is not allowed, as that makes
    // assumptions that will not hold in future versions of PostNuke
    list($gid,
         $objectid,
         $name) = pnVarCleanFromInput('gid',
                                      'objectid',
                                      'name');

    // User functions of this type can be called by other modules.  If this
    // happens then the calling module will be able to pass in arguments to
    // this function through the $args parameter.  Hence we extract these
    // arguments *after* we have obtained any form-based input through
    // pnVarCleanFromInput().
    extract($args);

    // At this stage we check to see if we have been passed $objectid, the
    // generic item identifier.  This could have been passed in by a hook or
    // through some other function calling this as part of a larger module, but
    // if it exists it overrides $tid
    //
    // Note that this module couuld just use $objectid everywhere to avoid all
    // of this munging of variables, but then the resultant code is less
    // descriptive, especially where multiple objects are being used.  The
    // decision of which of these ways to go is up to the module developer
    if (!empty($objectid)) {
        $gid = $objectid;
    }

    // Confirm authorisation code.  This checks that the form had a valid
    // authorisation code attached to it.  If it did not then the function will
    // proceed no further as it is possible that this is an attempt at sending
    // in false data to the system
    if (!pnSecConfirmAuthKey()) {
        pnSessionSetVar('errormsg', _BADAUTHKEY);
        pnRedirect(pnModURL('Groups', 'admin', 'view'));
        return true;
    }

    // Notable by its absence there is no security check here.  This is because
    // the security check is carried out within the API function and as such we
    // do not duplicate the work here

    // The API function is called.  Note that the name of the API function and
    // the name of this function are identical, this helps a lot when
    // programming more complex modules.  The arguments to the function are
    // passed in as their own arguments array.
    //
    // The return value of the function is checked here, and if the function
    // suceeded then an appropriate message is posted.  Note that if the
    // function did not succeed then the API function should have already
    // posted a failure message so no action is required
    if(pnModAPIFunc('Groups',
                    'admin',
                    'update',
                    array('gid'  => $gid,
                          'name' => $name))) {
        // Success
        pnSessionSetVar('statusmsg', _GROUPSUPDATED);
    }

    // This function generated no output, and so now it is complete we redirect
    // the user to an appropriate page for them to carry on their work
    pnRedirect(pnModURL('Groups', 'admin', 'view'));

    // Return
    return true;
}

/**
 * delete group
 * This is a standard function that is called whenever an administrator
 * wishes to delete a current group item.  Note that this function is
 * the equivalent of both of the modify() and update() functions above as
 * it both creates a form and processes its output.  This is fine for
 * simpler functions, but for more complex operations such as creation and
 * modification it is generally easier to separate them into separate
 * functions.  There is no requirement in the PostNuke MDG to do one or the
 * other, so either or both can be used as seen appropriate by the module
 * developer
 * @author Mark West
 * @version $Revision: 1.42.2.1 $
 * @param int 'gid' the id of the item to be deleted
 * @param bool 'confirmation' confirmation that this item can be deleted
 * @param int 'objectid' generic object id mapped onto gid if present
 * @return mixed HTML output string if no confirmation, true if group deleted succesfully, false otherwise
 * @todo template output
 */
function Groups_admin_delete($args)
{
    // Get parameters from whatever input we need.  All arguments to this
    // function should be obtained from pnVarCleanFromInput(), getting them
    // from other places such as the environment is not allowed, as that makes
    // assumptions that will not hold in future versions of PostNuke
    list($gid,
         $objectid,
         $confirmation) = pnVarCleanFromInput('gid',
                                              'objectid',
                                              'confirmation');


    // User functions of this type can be called by other modules.  If this
    // happens then the calling module will be able to pass in arguments to
    // this function through the $args parameter.  Hence we extract these
    // arguments *after* we have obtained any form-based input through
    // pnVarCleanFromInput().
    extract($args);

     // At this stage we check to see if we have been passed $objectid, the
     // generic item identifier.  This could have been passed in by a hook or
     // through some other function calling this as part of a larger module, but
     // if it exists it overrides $tid
     //
     // Note that this module couuld just use $objectid everywhere to avoid all
     // of this munging of variables, but then the resultant code is less
     // descriptive, especially where multiple objects are being used.  The
     // decision of which of these ways to go is up to the module developer
     if (!empty($objectid)) {
         $gid = $objectid;
     }

    // The user API function is called.  This takes the item ID which we
    // obtained from the input and gets us the information on the appropriate
    // item.  If the item does not exist we post an appropriate message and
    // return
    $item = pnModAPIFunc('Groups',
                         'user',
                         'get',
                         array('gid' => $gid));

    if ($item == false) {
        pnSessionSetVar('errormsg', _GROUPSNOSUCHITEM);
        pnRedirect(pnModURL('Groups', 'admin', 'main'));
        return true;
    }

    // Security check - important to do this as early as possible to avoid
    // potential security holes or just too much wasted processing.  However,
    // in this case we had to wait until we could obtain the item name to
    // complete the instance information so this is the first chance we get to
    // do the check
    if (!pnSecAuthAction(0, 'Groups::', "$item[name]::$gid", ACCESS_DELETE)) {
        return pnVarPrepHTMLDisplay(_MODULENOAUTH);
    }

    // get the user default group - we do not allow its deletion
    $defaultgroup = pnModGetVar('Groups', 'defaultgroup');
    if ($item['name'] == $defaultgroup) {
        pnSessionSetVar('errormsg', _GROUPSDEFAULTGROUPCANNOTBEDELETED);
        pnRedirect(pnModURL('Groups', 'admin', 'main'));
        return true;
    }

    // Check for confirmation.
    if (empty($confirmation)) {

        // No confirmation yet - display a suitable form to obtain confirmation
        // of this action from the user

        // Create output object - this object will store all of our output so that
        // we can return it easily when required
        $pnRender =& new pnRender('Groups');

        // As Admin output changes often, we do not want caching.
        $pnRender->caching = false;

        // Add a hidden variable for the item id.  This needs to be passed on to
        // the update function so that it knows which item for which item to carry
        // out the update
        $pnRender->assign('gid', $gid);

        // Return the output that has been generated by this function
        return $pnRender->fetch('groups_admin_delete.htm');
    }

    // If we get here it means that the user has confirmed the action

    // Confirm authorisation code.  This checks that the form had a valid
    // authorisation code attached to it.  If it did not then the function will
    // proceed no further as it is possible that this is an attempt at sending
    // in false data to the system
    if (!pnSecConfirmAuthKey()) {
        pnSessionSetVar('errormsg', _BADAUTHKEY);
        pnRedirect(pnModURL('Groups', 'admin', 'view'));
        return true;
    }

    // The API function is called.  Note that the name of the API function and
    // the name of this function are identical, this helps a lot when
    // programming more complex modules.  The arguments to the function are
    // passed in as their own arguments array.
    //
    // The return value of the function is checked here, and if the function
    // suceeded then an appropriate message is posted.  Note that if the
    // function did not succeed then the API function should have already
    // posted a failure message so no action is required
    if (pnModAPIFunc('Groups',
                     'admin',
                     'delete',
                     array('gid' => $gid))) {
        // Success
        pnSessionSetVar('statusmsg', _GROUPSDELETED);
    }

    // This function generated no output, and so now it is complete we redirect
    // the user to an appropriate page for them to carry on their work
    pnRedirect(pnModURL('Groups', 'admin', 'view'));

    // Return
    return true;
}

/**
 * View all groups
 * this function creates a tabular output of all group items in the module
 * @author Mark West
 * @version $Revision: 1.42.2.1 $
 * @return string HTML output string
 * @todo template output
 * @todo add pager for function
 */
function Groups_admin_view()
{
    // Get parameters from whatever input we need.  All arguments to this
    // function should be obtained from pnVarCleanFromInput(), getting them
    // from other places such as the environment is not allowed, as that makes
    // assumptions that will not hold in future versions of PostNuke
    $startnum = pnVarCleanFromInput('startnum');

    // we need this value multiple times, so we keep it
    $itemsperpage = pnModGetVar('Groups', 'itemsperpage');

    // get th defaul user group
    $defaultgroup = pnModGetVar('Groups', 'defaultgroup');

    // The user API function is called.  This takes the number of items
    // required and the first number in the list of all items, which we
    // obtained from the input and gets us the information on the appropriate
    // items.
    $items = pnModAPIFunc('Groups',
                          'user',
                          'getall',
                          array('startnum' => $startnum,
                                'numitems' => $itemsperpage));

    $groups = array();
    foreach ($items as $item) {

        if (pnSecAuthAction(0, 'Groups::', "$item[name]::$item[gid]", ACCESS_READ)) {

            // Options for the item.  Note that each item has the appropriate
            // levels of authentication checked to ensure that it is suitable
            // for display
            $options = array();
            if (pnSecAuthAction(0, 'Groups::', "$item[name]::$item[gid]", ACCESS_EDIT)) {
                $options[] = array('url' => pnModURL('Groups', 'admin', 'modify', array('gid'   => $item['gid'])),
                                                                                        'title' => _EDIT);
                if ((pnSecAuthAction(0, 'Groups::', "$item[name]::$item[gid]", ACCESS_DELETE))
                    && ($item['name'] <> $defaultgroup) ) {
                    $options[] = array('url' => pnModURL('Groups', 'admin', 'delete', array('gid'   => $item['gid'])),
                                                                                            'title' => _DELETE);
                }
                $options[] = array('url' => pnModURL('Groups', 'admin', 'groupmembership', array('gid'   => $item['gid'])),
                                                                                                 'title' => _GROUPSMEMBERSHIP);
                if ($item['name'] == $defaultgroup) {
                    $item['name'] .= " (*)";
                }
                $groups[] = array('name'    => $item['name'],
                                  'gid'     => $item['gid'],
                                  'options' => $options);
            }
        }
    }

    if(count($groups)==0) {
        // groups array is empty which means there are no groups that we are allowed
        // to administer - return now
        return pnVarPrepHTMLDisplay(_MODULENOAUTH);
    }

    // Create output object - this object will store all of our output so that
    // we can return it easily when required
    $pnRender =& new pnRender('Groups');

    // As Admin output changes often, we do not want caching.
    $pnRender->caching = false;

    $pnRender->assign('groups', $groups);

    // assign the values for the smarty plugin to produce a pager in case of there
    // being many items to display.
    //
    // Note that this function includes another user API function.  The
    // function returns a simple count of the total number of items in the item
    // table so that the pager function can do its job properly
    $pnRender->assign('pager', array('numitems'     => pnModAPIFunc('Groups',
                                                                    'user',
                                                                    'countitems'),
                                     'itemsperpage' => $itemsperpage));

    // Return the output that has been generated by this function
    return $pnRender->fetch('groups_admin_view.htm');
}

/**
 * This is a standard function to display members of a group
 * @author Mark West
 * @link http://www.markwest.me.uk/
 * @version $Revision: 1.42.2.1 $
 * @param int 'gid' the id of the group to list membership for
 * @param int 'objectid' generic object id mapped onto gid if present
 * @return string HTML output string
 * @todo template output
 */
function Groups_admin_groupmembership($args)
{
    // Get parameters from whatever input we need.  All arguments to this
    // function should be obtained from pnVarCleanFromInput(), getting them
    // from other places such as the environment is not allowed, as that makes
    // assumptions that will not hold in future versions of PostNuke
    list($gid,
         $objectid,
         $startnum,
         $letter)= pnVarCleanFromInput('gid',
                                       'objectid',
                                       'startnum',
                                       'letter');

    // Admin functions of this type can be called by other modules.  If this
    // happens then the calling module will be able to pass in arguments to
    // this function through the $args parameter.  Hence we extract these
    // arguments *after* we have obtained any form-based input through
    // pnVarCleanFromInput().
    extract($args);

    // At this stage we check to see if we have been passed $objectid, the
    // generic item identifier.  This could have been passed in by a hook or
    // through some other function calling this as part of a larger module, but
    // if it exists it overrides $tid
    //
    // Note that this module couuld just use $objectid everywhere to avoid all
    // of this munging of variables, but then the resultant code is less
    // descriptive, especially where multiple objects are being used.  The
    // decision of which of these ways to go is up to the module developer
    if (!empty($objectid)) {
        $gid = $objectid;
    }

    // The user API function is called.  This takes the item ID which
    // we obtained from the input and gets us the information on the
    // appropriate item.  If the item does not exist we post an appropriate
    // message and return
    $item = pnModAPIFunc('Groups',
                         'user',
                         'get',
                         array('gid' => $gid));

    // check for a letter parameter
    if (empty($letter) && strlen($letter) != 1) {
        $letter = 'A';
    }

    // Security check - important to do this as early as possible to avoid
    // potential security holes or just too much wasted processing
    if (!pnSecAuthAction(0, 'Groups::', "$item[name]::$item[gid]", ACCESS_ADMIN)) {
        return pnVarPrepHTMLDisplay(_MODULENOAUTH);
    }

    // Create output object - this object will store all of our output so that
    // we can return it easily when required
    $pnRender =& new pnRender('Groups');

    // As Admin output changes often, we do not want caching.
    $pnRender->caching = false;

    // add group id to form as hidden component
    $pnRender->assign('gid', $gid);

    // The user API function is called.  This takes the number of items
    // required and the first number in the list of all items, which we
    // obtained from the input and gets us the information on the appropriate
    // items.
    $item = pnModAPIFunc('Groups',
                         'user',
                         'get',
                         array('gid'      => $gid,
                               'startnum' => $startnum,
                               'numitems' => pnModGetVar('Groups', 'itemsperpage')));

    $users = $item['members'];

    $groupmembers = array();

    if (is_array($users)) {
        foreach ($users as $user) {
            $options = array();
            if (pnSecAuthAction(0, 'Groups::', "$item[name]::$item[gid]", ACCESS_EDIT)) {
                // Fix for patch #206 - Brian Bain 'uid' => $user['uid'],
                $options[] = array('url'   => pnModURL('Groups', 'admin', 'removeuser', array('gid'    => $item['gid'],
                                                                                              'uid'    => $user,
                                                                                              'authid' => pnSecGenAuthKey())),
                                   'title' => _GROUPSREMOVEUSER);
            }
            // Fix for patch #206 - Brian Bain
            // $row[] = pnUserGetVar('uname', $user['uid']);
            // $row[] = $user['uid'];
            $uname = pnUserGetVar('uname', $user);
            $groupmembers[] = array('uname'   => $uname,
                                    'name'    => pnUserGetVar('name', $user),
                                    'uid'     => $user,
                                    'options' => $options);
        }
    }

    // sort alphabetically.
    foreach($groupmembers as $res) {
        $sortAarr[] = strtolower($res['uname']);
    }
    array_multisort($sortAarr, SORT_ASC, $groupmembers);

    $pnRender->assign('groupmembers', $groupmembers);

    // The user API function is called.  This takes the number of items
    // required and the first number in the list of all items, which we
    // obtained from the input and gets us the information on the appropriate
    // items.
    // We need to call this api without the paging parameters so we can work
    // out what users aren't in the group
    $item = pnModAPIFunc('Groups',
                         'user',
                         'get',
                         array('gid' => $gid));

    // Number of items to display per page
    $row = array();
    $users = pnUserGetAll();

    $allusers = array();
    foreach ($users as $user) {
        if ($user['uname'] == 'Anonymous')  continue;
        if (strtoupper($user['uname'][0]) == strtoupper($letter) || $letter == '*') {
            $alias = '';
            if (!empty($user['name'])) {
                $alias = ' (' . $user['name'] . ')';
            }
            $allusers[$user['uid']] = $user['uname'] . $alias;
        }
        $chrid = ord(strtoupper($user['uname'][0]));
        if ($letter == '?' && !($chrid >=65 && $chrid <=90)) {
            if (!empty($user['name'])) {
              $alias = ' (' . $user['name'] . ')';
            }
            $allusers[$user['uid']] = $user['uname'] . $alias;
        }
    }

    // Now lets remove the uers that are currently part of the group
    // flip the array so we have the user id's as the key
    // this makes the array the same is the group members array
    // from the get function
    $flippedusers = array_flip($allusers);
    // now lets diff the array
    $diffedusers = array_diff($flippedusers, $item['members']);
    // now flip the array back
    $allusers = array_flip($diffedusers);
    // sort the users by user name
    natcasesort($allusers);

    // assign the users not in the group to the template
    $pnRender->assign('uids', $allusers);

    // Assign the values for the smarty plugin to produce a pager in case of there
    // being many items to display.
    //
    // Note that this function includes another user API function.  The
    // function returns a simple count of the total number of items in the item
    // table so that the pager function can do its job properly
    $pnRender->assign('pager', array('numitems'     => pnModAPIFunc('Groups', 'user', 'countgroupmembers', array('gid' => $gid)),
                                     'itemsperpage' => pnModGetVar('Groups',  'itemsperpage')));

    // Return the output that has been generated by this function
    return $pnRender->fetch('groups_admin_groupmembership.htm');

}

/**
 * This is a standard function to add a user to a group
 * @author Mark West
 * @version $Revision: 1.42.2.1 $
 * @param int 'gid' the id of the group
 * @param mixed 'uid' the id of the user (int) or an array of userids
 * @return string true is user added succesfully, false otherwise
 */
function Groups_admin_adduser($args)
{
    // Get parameters from whatever input we need.  All arguments to this
    // function should be obtained from pnVarCleanFromInput(), getting them
    // from other places such as the environment is not allowed, as that makes
    // assumptions that will not hold in future versions of PostNuke
    list($gid,
         $uid)= pnVarCleanFromInput('gid',
                                    'uid');

    // Admin functions of this type can be called by other modules.  If this
    // happens then the calling module will be able to pass in arguments to
    // this function through the $args parameter.  Hence we extract these
    // arguments *after* we have obtained any form-based input through
    // pnVarCleanFromInput().
    extract($args);

    // Confirm authorisation code.  This checks that the form had a valid
    // authorisation code attached to it.  If it did not then the function will
    // proceed no further as it is possible that this is an attempt at sending
    // in false data to the system
    if (!pnSecConfirmAuthKey()) {
        pnSessionSetVar('errormsg', _BADAUTHKEY);
        pnRedirect(pnModURL('Groups', 'admin', 'view'));
        return true;
    }

    // The API function is called.  Note that the name of the API function and
    // the name of this function are identical, this helps a lot when
    // programming more complex modules.  The arguments to the function are
    // passed in as their own arguments array.
    //
    // The return value of the function is checked here, and if the function
    // suceeded then an appropriate message is posted.  Note that if the
    // function did not succeed then the API function should have already
    // posted a failure message so no action is required
    if (is_array($uid)) {
        foreach($uid as $id) {
            if (!pnModAPIFunc('Groups',
                              'admin',
                              'adduser',
                              array('gid' => $gid,
                                    'uid' => $id))) {
                // Failiure
                pnSessionSetVar('errormsg', _GROUPSUSERNOTADDED);
            }
        }
    } else {
        if(pnModAPIFunc('Groups',
                        'admin',
                        'adduser',
                        array('gid' => $gid,
                              'uid' => $uid))) {
            // Success
            pnSessionSetVar('statusmsg', _GROUPSUSERADDED);
        }
    }

    // This function generated no output, and so now it is complete we redirect
    // the user to an appropriate page for them to carry on their work
    pnRedirect(pnModURL('Groups', 'admin', 'groupmembership', array('gid' => $gid)));

    // Return
    return true;

}

/**
 * This is a standard function to add a user to a group
 * @author Mark West
 * @version $Revision: 1.42.2.1 $
 * @param int 'gid' the id of the group
 * @param int 'uid' the id of the user
 * @return string true is user added succesfully, false otherwise
*/
function Groups_admin_removeuser($args)
{
    // Get parameters from whatever input we need.  All arguments to this
    // function should be obtained from pnVarCleanFromInput(), getting them
    // from other places such as the environment is not allowed, as that makes
    // assumptions that will not hold in future versions of PostNuke
    list($gid,
         $uid)= pnVarCleanFromInput('gid',
                                    'uid');

    // Admin functions of this type can be called by other modules.  If this
    // happens then the calling module will be able to pass in arguments to
    // this function through the $args parameter.  Hence we extract these
    // arguments *after* we have obtained any form-based input through
    // pnVarCleanFromInput().
    extract($args);

    // Confirm authorisation code.  This checks that the form had a valid
    // authorisation code attached to it.  If it did not then the function will
    // proceed no further as it is possible that this is an attempt at sending
    // in false data to the system
    if (!pnSecConfirmAuthKey()) {
        pnSessionSetVar('errormsg', _BADAUTHKEY);
        pnRedirect(pnModURL('Groups', 'admin', 'view'));
        return true;
    }

    // The API function is called.  Note that the name of the API function and
    // the name of this function are identical, this helps a lot when
    // programming more complex modules.  The arguments to the function are
    // passed in as their own arguments array.
    //
    // The return value of the function is checked here, and if the function
    // suceeded then an appropriate message is posted.  Note that if the
    // function did not succeed then the API function should have already
    // posted a failure message so no action is required
    if(pnModAPIFunc('Groups',
                    'admin',
                    'removeuser',
                    array('gid' => $gid,
                          'uid' => $uid))) {
        // Success
        pnSessionSetVar('statusmsg', _GROUPSUSERREMOVED);
    }

    // This function generated no output, and so now it is complete we redirect
    // the user to an appropriate page for them to carry on their work
    pnRedirect(pnModURL('Groups', 'admin', 'groupmembership', array('gid' => $gid)));

    // Return
    return true;

}

/**
 * This is a standard function to modify the configuration parameters of the
 * module
 * @author Mark West
 * @version $Revision: 1.42.2.1 $
 * @since 1.14
 * @return string HTML string
 */
function Groups_admin_modifyconfig()
{
    // Security check - important to do this as early as possible to avoid
    // potential security holes or just too much wasted processing
    if (!pnSecAuthAction(0, 'Groups::', '::', ACCESS_ADMIN)) {
        return pnVarPrepHTMLDisplay(_MODULENOAUTH);
    }

    // Create output object - this object will store all of our output so that
    // we can return it easily when required
    $pnRender =& new pnRender('Groups');

    // As Admin output changes often, we do not want caching.
    $pnRender->caching = false;

    // assign the module vars
    $pnRender->assign(pnModGetVar('Groups'));

    // get all groups from the API
    $groups = pnModAPIFunc('Groups', 'user', 'getall');

    // build an array suitable for html_options
    $groupslist = array();
    foreach ($groups as $group) {
        $groupslist[$group['name']] = $group['name'];
    }

    // assign the list of existing groups
    $pnRender->assign('groups', $groupslist);

    // Return the output that has been generated by this function
    return $pnRender->fetch('groups_admin_modifyconfig.htm');
}

/**
 * This is a standard function to update the configuration parameters of the
 * module given the information passed back by the modification form
 * @author Mark West
 * @version $Revision: 1.42.2.1 $
 * @since 1.14
 * @return bool true
 */
function Groups_admin_updateconfig()
{
    // Security check - important to do this as early as possible to avoid
    // potential security holes or just too much wasted processing
    if (!pnSecAuthAction(0, 'Groups::', '::', ACCESS_ADMIN)) {
        return pnVarPrepHTMLDisplay(_MODULENOAUTH);
    }

    // Get parameters from whatever input we need.  All arguments to this
    // function should be obtained from pnVarCleanFromInput(), getting them
    // from other places such as the environment is not allowed, as that makes
    // assumptions that will not hold in future versions of PostNuke
    list($itemsperpage, $defaultgroup) = pnVarCleanFromInput('itemsperpage', 'defaultgroup');

    // Confirm authorisation code.  This checks that the form had a valid
    // authorisation code attached to it.  If it did not then the function will
    // proceed no further as it is possible that this is an attempt at sending
    // in false data to the system
    if (!pnSecConfirmAuthKey()) {
        pnSessionSetVar('errormsg', pnVarPrepForDisplay(_BADAUTHKEY));
        pnRedirect(pnModURL('Groups', 'admin', 'view'));
        return true;
    }

    // Update module variables.  Note that depending on the HTML structure used
    // to obtain the information from the user it is possible that the values
    // might be unset, so it is important to check them all and assign them
    // default values if required
    if (empty($itemsperpage)) {
        $itemsperpage = 25;
    }
    pnModSetVar('Groups', 'itemsperpage', $itemsperpage);

    if (empty($defaultgroup)) {
        $defaultgroup = 'Users';
    }
    pnModSetVar('Groups', 'defaultgroup', $defaultgroup);

    // report configuration updated
    pnSessionSetVar('statusmsg', pnVarPrepForDisplay(_GROUPSCONFIGUPDATED));

    // Let any other modules know that the modules configuration has been updated
    pnModCallHooks('module','updateconfig','Groups', array('module' => 'Groups'));

    // the module configuration has been updated successfuly
    pnSessionSetVar('statusmsg', _CONFIGUPDATED);

    // This function generated no output, and so now it is complete we redirect
    // the user to an appropriate page for them to carry on their work
    pnRedirect(pnModURL('Groups', 'admin', 'view'));

    // Return
    return true;
}

?>