<?php
// $Id: pnadmin.php,v 1.70 2005/08/19 16:52:18 landseer 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:  Admin administration display functions
// ----------------------------------------------------------------------

/**
 * @package PostNuke_System_Modules
 * @subpackage Admin
 * @license http://www.gnu.org/copyleft/gpl.html
*/

/**
 * the 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
 * @return string HTML string
 */

function Admin_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'
    if (!pnSecAuthAction(0, 'Admin::', '::', 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('Admin');

    // 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('admin_admin_main.htm');
}

/**
 * Add a new admin category
 * This is a standard function that is called whenever an administrator
 * wishes to create a new module item
 * @author Mark West
 * @return string HTML string
 */

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

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

    // Security check - important to do this as early as possible to avoid
    // potential security holes or just too much wasted processing
    if (!pnSecAuthAction(0, 'Admin::Item', '::', ACCESS_ADD)) {
        return pnVarPrepHTMLDisplay(_MODULENOAUTH);
    }

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

/**
 * This is a standard function that is called with the results of the
 * form supplied by admin_admin_new() to create a new category
 * @author Mark West
 * @see Admin_admin_new()
 * @param string $args['catname'] the name of the category to be created
 * @param string $args['description'] the description of the category to be created
 * @return mixed category id if create successful, false otherwise
 */

function Admin_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
    list($catname,
         $description) = pnVarCleanFromInput('catname',
                                             'description');
    // 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('Admin', '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
    $cid = pnModAPIFunc('Admin',
                        'admin',
                        'create',
                        array('catname' => $catname,
                              'description' => $description));

    // 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 ($cid != false) {
        // Success
        pnSessionSetVar('statusmsg', _ADMINCATEGORYCREATED);
    }

    // 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('Admin', 'admin', 'view'));

    // Return
    return true;
}

/**
 * Modify a category
 * This is a standard function that is called whenever an administrator
 * wishes to modify an admin category
 * @author Mark West
 * @param int $args['cid'] category id
 * @param int $args['objectid'] generic object id maps to cid if present
 * @return string HTML string
 */

function Admin_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($cid,
         $objectid)= pnVarCleanFromInput('cid',
                                         '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)) {
        $cid = $objectid;

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

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

    // 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('Admin',
                         'admin',
                         'get',
                         array('cid' => $cid));

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

    // 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, 'Admin::Category', "$item[catname]::$cid", ACCESS_EDIT)) {
        return pnVarPrepHTMLDisplay(_MODULENOAUTH);
    }

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

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

/**
 * This is a standard function that is called with the results of the
 * form supplied by template_admin_modify() to update a current item
 * @author Mark West
 * @see Admin_admin_modify()
 * @param int $args['cid'] the id of the item to be updated
 * @param int $args['objectid'] generic object id maps to cid if present
 * @param string $args['catname'] the name of the category to be updated
 * @param string $args['description'] the description of the item to be updated
 * @return bool true if update successful, false otherwise
 */

function Admin_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($cid,
         $objectid,
         $catname,
         $description) = pnVarCleanFromInput('cid',
                                             'objectid',
                                             'catname',
                                             'description');
    // 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)) {
        $cid = $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('Admin', '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('Admin',
                    'admin',
                    'update',
                    array('cid' => $cid,
                          'catname' => $catname,
                          'description' => $description))) {
        // Success
        pnSessionSetVar('statusmsg', _ADMINCATEGORYUPDATED);
    }

    // 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('Admin', 'admin', 'view'));

    // Return
    return true;
}

/**
 * delete item
 * This is a standard function that is called whenever an administrator
 * wishes to delete a current module 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
 * @param int $args['cid'] the id of the category to be deleted
 * @param int $args['objectid'] generic object id maps to cid if present
 * @param bool $args['confirmation'] confirmation that this item can be deleted
 * @return mixed HTML string if confirmation is null, true if delete successful, false otherwise
 */

function Admin_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($cid,
         $objectid,
         $confirmation) = pnVarCleanFromInput('cid',
                                              '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)) {
         $cid = $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('Admin',
                         'admin',
                         'get',
                         array('cid' => $cid));

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

    // 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, 'Admin::Category', "$item[catname]::$cid", ACCESS_DELETE)) {
        return pnVarPrepHTMLDisplay(_MODULENOAUTH);
    }

    // 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('Admin');
        // 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('cid', $cid);
        // Return the output that has been generated by this function
        return $pnRender->fetch('admin_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('Admin', '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('Admin',
                     'admin',
                     'delete',
                     array('cid' => $cid))) {
        // Success
        pnSessionSetVar('statusmsg', _ADMINDELETED);
    }
    // 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('Admin', 'admin', 'view'));
    // Return
    return true;
}

/**
 * View all admin categories
 * @author Mark West
 * @param int $startnum the starting id to view from - optional
 * @return string HTML string
 */

function Admin_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');
    // Create output object - this object will store all of our output so that
    // we can return it easily when required
    $pnRender =& new pnRender('Admin');
    // As Admin output changes often, we do not want caching.
    $pnRender->caching = false;
    // 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, 'Admin::', '::', ACCESS_EDIT)) {
        return pnVarPrepHTMLDisplay(_MODULENOAUTH);
    }

    // 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('Admin',
                          'admin',
                          'getall',
                          array('startnum' => $startnum,
                                'numitems' => pnModGetVar('Admin',
                                                          'itemsperpage')));
    $rows = array();
    foreach ($items as $item) {
        if (pnSecAuthAction(0, 'Admin::', "$item[catname]::$item[cid]", 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, 'Admin::', "$item[catname]::$item[cid]", ACCESS_EDIT)) {
                $options[] = array( 'url' => pnModURL('Admin', 'admin', 'modify', array('cid' => $item['cid'])),
                                    'text' => _EDIT);
                if (pnSecAuthAction(0, 'Admin::', "$item[catname]::$item[cid]", ACCESS_DELETE)) {
                    $options[] = array( 'url' => pnModURL('Admin', 'admin', 'delete', array('cid' => $item['cid'])),
                                        'text' => _DELETE);
                }
                    $options[] = array( 'url' => pnModURL('Admin', 'admin', 'adminpanel', array('cid' => $item['cid'])),
                                        'text' => _ADMINPANELCATEGORY);
            }
            $rows[] = array('catname' => $item['catname'],
                            'options' =>$options);
        }
    }
    $pnRender->assign('items', $rows);
    // 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('Admin', 'admin', 'countitems'),
                                     'itemsperpage' => pnModGetVar('Admin', 'itemsperpage')));
    // Return the output that has been generated by this function
    return $pnRender->fetch('admin_admin_view.htm');
}

/**
 * Display main admin panel for a category
 * @author Mark West
 * @param int $args['cid'] the id of the category to be displayed
 * @return string HTML string
 */
function Admin_admin_adminpanel($args)
{
    if (!pnSecAuthAction(0, '::', '::', ACCESS_EDIT)) {
        // suppress admin display - return to index.
        pnRedirect('index.php');
    }

    // Create output object - this object will store all of our output so that
    // we can return it easily when required
    $pnRender =& new pnRender('Admin');
    // As Admin output changes often, we do not want caching.

    // We can use caching if we delete the cache whenever a  module is added or deleted. -- jn
    $pnRender->caching = false;

    if (!pnModGetVar('Admin', 'ignoreinstallercheck')) {
        // check if install.php or install folder exist
        $installexists = file_exists('install.php') || file_exists('install');
        // check if the PostNuke Swiss Army Knife exists
        $psakexists = file_exists('psak.php');
        // if either one them is true we show a warning and do not let the admin go to
        // the admin panel
        if($installexists==true || $psakexists==true) {
            $pnRender->assign('installexists', $installexists);
            $pnRender->assign('psakexists', $psakexists);
            $pnRender->assign('adminpanellink', pnModURL('Admin','admin', 'adminpanel'));
            return $pnRender->fetch('admin_admin_warning.htm');
        }
    }

    // Now prepare the display of the admin panel by getting the relevant info.

    // Get parameters from whatever input we need.
    $cid = pnVarCleanFromInput('cid');
    // Get arguments from argument array. The only parameter interesing here is cid.
    extract($args);
    // cid isn't set, so we check the last session var lastcid to see where the admin has been before.
    if (empty($cid)) {
        $cid = pnSessionGetVar('lastcid');
        if(empty($cid)) {
            // cid is still not set, go to the default category
            $cid = pnModGetVar('Admin', 'startcategory');
        }
    }
    // now we know where we are or where the admin wants us to go to, lets store it in a
    // session var for later use
    pnSessionSetVar('lastcid', $cid);

    // Add category menu to output - it helps if all of the module pages have a standard
    // menu at their head to aid in navigation
    $pnRender->assign('menu', Admin_admin_categorymenu(array('cid' => $cid)));

    // Admin_admin_categorymenu may have changed the cid. In this case it has been
    // stored to lastcid so we need to read it again now
    $cid = pnSessionGetVar('lastcid');

    // Get Datails on the selected category
    $category = pnModAPIFunc('Admin',
                             'admin',
                             'get',
                             array('cid' => $cid));

    if (!$category) {
        // The API function returned false; which means that the category
        // passed does not exist. We therefore use the default category
        // (Another option would be to return nothing but an error message)
        $cid = pnModGetVar('Admin', 'startcategory');
        $category = pnModAPIFunc('Admin',
                                 'admin',
                                 'get',
                                 array('cid' => $cid));
    }

    // Title - putting a title ad the head of each page reminds the user what
    // they are doing
    $pnRender->assign('category', $category);

    // modules per row
    $pnRender->assign('modulesperrow', pnModGetVar('Admin', 'modulesperrow'));

    // show icons in admin
    $pnRender->assign('admingraphic', pnModGetVar('Admin', 'admingraphic'));

    // set locations for default admin graphic
    if (file_exists($systemdirdefaultfile = 'system/Admin/pnimages/default.gif')) {
        $pnRender->assign('defaultimage', $systemdirdefaultfile);
    } else if (file_exists($modulesdirdefaultfile = 'modules/Admin/pnimages/default.gif')) {
        $pnRender->assign('defaultimage', $modulesdirdefaultfile);
    }

    // get admin capable modules
    $adminmodules = pnModGetAdminMods();
    $adminlinks = array();
    foreach ($adminmodules as $adminmodule) {
        if (pnSecAuthAction(0, "$adminmodule[name]::", '::', ACCESS_EDIT)) {
            $catid = pnModAPIFunc('Admin',
                                  'admin',
                                  'getmodcategory',
                                  array('mid' => pnModGetIDFromName($adminmodule['name'])));
            if (($catid == $cid) || (($catid == false) && ($cid == pnModGetVar('Admin', 'defaultcategory')))) {
                $modinfo = pnModGetInfo(pnModGetIDFromName($adminmodule['name']));
                if ($modinfo['type'] == 2 || $modinfo['type'] == 3) {
                    $menutexturl = pnModURL($modinfo['name'], 'admin');
                    $menutext = $modinfo['displayname'];
                    $menutexttitle = $modinfo['description'];
                } else {
                    $menutexturl = 'admin.php?module=' . $modinfo['name'];
                    $menutext = $modinfo['displayname'];
                    $menutexttitle =  $modinfo['description'];
                }
                $adminlinks[] = array('menutexturl' => $menutexturl,
                                      'menutext' => $menutext,
                                      'menutexttitle' => $menutexttitle,
                                      'modname' => $modinfo['name']);
            }
        }
    }
    $pnRender->assign('adminlinks', $adminlinks);

    // work out what stylesheet is being used to render to the admin panel
    $css = pnModGetVar('Admin', 'modulestylesheet');
    $cssfile = explode('.', $css);

    // Return the output that has been generated by this function
    if ($pnRender->template_exists('admin_admin_adminpanel_'.$cssfile[0].'.htm')) {
        return $pnRender->fetch('admin_admin_adminpanel_'.$cssfile[0].'.htm');
    } else {
        return $pnRender->fetch('admin_admin_adminpanel.htm');
    }
}

/**
 * This is a standard function to modify the configuration parameters of the
 * module
 * @author Mark West
 * @return string HTML string
 */

function Admin_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, 'Admin::', '::', 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('Admin');

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

    // get admin capable mods
    $adminmodules = pnModGetAdminMods();

    // 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.
    $categories = pnModAPIFunc('Admin',
                          'admin',
                          'getall');
    $pnRender->assign('categories', $categories);
    // assign all the module vars
    $pnRender->assign(pnModGetVar('Admin'));

    $modulecatories = array();
    foreach ($adminmodules as $adminmodule) {
        // 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.
        $category = pnModAPIFunc('Admin',
                                 'admin',
                                 'getmodcategory',
                                 array('mid' => pnModGetIDFromName($adminmodule['name'])));
        // output module category selection
        $modulecategories[] = array('name' => $adminmodule['name'],
                                    'category' => $category);
    }
    $pnRender->assign('modulecategories', $modulecategories);
    // Return the output that has been generated by this function
    return $pnRender->fetch('admin_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
 * @see Admin_admin_modifyconfig()
 * @param int $modulesperrow the number of modules to display per row in the admin panel
 * @param int $admingraphic switch for display of admin icons
 * @param int $modulename,... the id of the category to set for each module
 * @return string HTML string
 */
function Admin_admin_updateconfig()
{
    // 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('Admin', 'admin', 'view'));
        return true;
    }

    // set modules per row module var
    $modulesperrow = pnVarCleanFromInput('modulesperrow');
    if (empty($modulesperrow)) {
        $modulesperrow = 5;
    }

    if (!is_numeric($modulesperrow))
    {
        pnSessionSetVar('errormsg', _ADMINMODSPERROWNUMERIC);
    } else {
        pnModSetVar('Admin', 'modulesperrow', $modulesperrow);
    }

    // set the ignore installer check module var
    $ignoreinstallercheck = pnVarCleanFromInput('ignoreinstallercheck');
    if (empty($ignoreinstallercheck)) {
        $ignoreinstallercheck = false;
    }
    pnModSetVar('Admin', 'ignoreinstallercheck', $ignoreinstallercheck);

    // set modules per row module var
    $itemsperpage = pnVarCleanFromInput('itemsperpage');
    if (empty($itemsperpage)) {
        $itemsperpage = 20;
    }

    if (!is_numeric($itemsperpage))
    {
        pnSessionSetVar('errormsg', _ADMINCATPERPAGENUMERIC);
    } else {
        pnModSetVar('Admin', 'itemsperpage', $itemsperpage);
    }

    // set admin icons config var (should be moved to module var at some point)
    $adminskin = pnVarCleanFromInput('modulestylesheet');
    if (empty($adminskin)) {
        $adminskin = 'navtabs.css';
    }
    pnModSetVar('Admin', 'modulestylesheet', $adminskin);

    // set admin icons config var (should be moved to module var at some point)
    $admingraphic = pnVarCleanFromInput('admingraphic');
    if (empty($admingraphic)) {
        $admingraphic = 0;
    }
    pnModSetVar('Admin', 'admingraphic', $admingraphic);

    // set start category module var
    $startcategory = pnVarCleanFromInput('startcategory');
    if (empty($startcategory)) {
        $startcategory = 1;
    }
    pnModSetVar('Admin', 'startcategory', $startcategory);

    // set default category module var
    $defaultcategory = pnVarCleanFromInput('defaultcategory');
    if (empty($defaultcategory)) {
        $defaultcategory = 1;
    }
    pnModSetVar('Admin', 'defaultcategory', $defaultcategory);

    // get admin modules
    $adminmodules = pnModGetAdminMods();

    foreach ($adminmodules as $adminmodule) {
        // 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

        $category = pnVarCleanFromInput($adminmodule['name']);

        // 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.
        $result = pnModAPIFunc('Admin',
                               'admin',
                               'addmodtocategory',
                               array('module' => $adminmodule['name'],
                                     'category' => $category));
        if ($result == false) {
            pnSessionSetVar('errormsg', _ADMINFAILEDADDMODTOCAT);
            pnRedirect(pnModURL('Admin', 'admin', 'view'));
            return true;
        }
    }

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

    // 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('Admin', 'admin', 'main'));

    // Return
    return true;
}

/**
 * Main category menu
 * @author Mark West
 * @return string HTML string
 */
function Admin_admin_categorymenu($args)
{
    // Create output object - this object will store all of our output so that
    // we can return it easily when required
    $pnRender =& new pnRender('Admin');

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

    // get the current category
    $cid = pnVarCleanFromInput('cid');
    extract($args);
    if (empty($cid)) {
        $cid = pnSessionGetVar('lastcid');
        if(empty($cid)) {
            // cid is still not set, go to the default category
            $cid = pnModGetVar('Admin', 'startcategory');
        }
    }

    // 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('Admin',
                          'admin',
                          'getall');

    // get admin capable modules
    $adminmodules = pnModGetAdminMods();
    $adminlinks = array();

    foreach ($adminmodules as $adminmodule) {
        if (pnSecAuthAction(0, "$adminmodule[name]::", '::', ACCESS_EDIT)) {
            $catid = pnModAPIFunc('Admin',
                                  'admin',
                                  'getmodcategory',
                                  array('mid' => pnModGetIDFromName($adminmodule['name'])));
            $modinfo = pnModGetInfo(pnModGetIDFromName($adminmodule['name']));
            if ($modinfo['type'] == 2 || $modinfo['type'] == 3) {
                $menutexturl = pnModURL($modinfo['name'], 'admin');
                $menutext = $modinfo['displayname'];
                $menutexttitle = $modinfo['description'];
            } else {
                $menutexturl = 'admin.php?module=' . $modinfo['name'];
                $menutext = $modinfo['displayname'];
                $menutexttitle =  $modinfo['description'];
            }
            $adminlinks[$catid][] = array('menutexturl' => $menutexturl,
                                          'menutext' => $menutext,
                                          'menutexttitle' => $menutexttitle,
                                          'modname' => $modinfo['name']);
        }
    }

    // Menu options.  These options are all added in a single row, to add
    // multiple rows of options the code below would just be repeated
    $menuoptions = array();
    $possible_cids = array();
    $permission = false;

    if(isset($items) && is_array($items)) {
        foreach($items as $item) {
            // only categories containing modules where the current user has permissions will
            // be shown, all others will be hidden
            // admin will see all categories
            if( (isset($adminlinks[$item['cid']]) && count($adminlinks[$item['cid']])<>0 )
                || pnSecAuthAction(0, '.*', '.*', ACCESS_ADMIN) ) {
                $menuoption = array('url'         => pnModURL('Admin','admin','adminpanel', array('cid' => $item['cid'])),
                                    'title'       => $item['catname'],
                                    'description' => $item['description'],
                                    'cid'         => $item['cid']);
                if(array_key_exists($item['cid'], $adminlinks) ) {
                    $menuoption['items'] = $adminlinks[$item['cid']];
                } else {
                    $menuoption['items'] = array();
                }
                array_push($menuoptions, $menuoption);
                $possible_cids[] = $item['cid'];
                if($cid==$item['cid']) {
                    $permission =true;
                }
            }
        }
    }

    // if permission is false we are not allowed to see this category because its
    // empty and we are not admin
    if($permission==false) {
        // show the first category
        $cid = (int)$possible_cids[0];
    }
    // store it
    pnSessionSetVar('lastcid', $cid);

    $pnRender->assign('currentcat', $cid);
    $pnRender->assign('menuoptions', $menuoptions);

    // postnuke baseline security analyzer
    // check for magic_quotes
    $magic_quotes = (bool) get_magic_quotes_gpc();
    $pnRender->assign('magic_quotes', $magic_quotes);

    // check for register_globals
    $register_globals = (bool) ini_get('register_globals');
    $pnRender->assign('register_globals', $register_globals);

    // check for config.php beeing writable
    $config_php = (bool) is_writable('config.php');
    $pnRender->assign('config_php', $config_php);

    // check for config-old.php beeing writable
    $config_old_php = (bool) is_writable('config-old.php');
    $pnRender->assign('config_old_php', $config_old_php);

    // check for .htaccess in /pnTemp
    global $pnconfig;
    if ($pnconfig['temp'] == 'pnTemp') {
          // default installation, check for .htaccess
        $pntemp_htaccess = (bool) file_exists('pnTemp/.htaccess');
    } else {
          // already customized, admin should know about what he's doing...
          $pntemp_htaccess = true;
    }
    $pnRender->assign('pntemp_htaccess', $pntemp_htaccess);

    // work out what stylesheet is being used to render to the admin panel
    $css = pnModGetVar('Admin', 'modulestylesheet');
    $cssfile = explode('.', $css);

    // Return the output that has been generated by this function
    if ($pnRender->template_exists('admin_admin_categorymenu_'.$cssfile[0].'.htm')) {
        return $pnRender->fetch('admin_admin_categorymenu_'.$cssfile[0].'.htm');
    } else {
        return $pnRender->fetch('admin_admin_categorymenu.htm');
    }
}

?>