/**
 *	This function is the start point for configuration of permissions within SimpleDesk.
 *
 *	@since 2.0
*/
function shd_admin_permissions()
{
    global $context, $scripturl, $sourcedir, $settings, $txt, $modSettings;
    shd_load_all_permission_sets();
    loadTemplate('sd_template/SimpleDesk-AdminPermissions');
    shd_load_language('sd_language/SimpleDeskPermissions');
    $subactions = array('main' => 'shd_admin_role_list', 'createrole' => 'shd_admin_create_role', 'editrole' => 'shd_admin_edit_role', 'saverole' => 'shd_admin_save_role', 'copyrole' => 'shd_admin_copy_role');
    $_REQUEST['sa'] = isset($_REQUEST['sa']) && isset($subactions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : 'main';
    $subactions[$_REQUEST['sa']]();
}
/**
 *	Sets up the profile menu additions.
 *
 *	@param array $profile_areas Current profile_areas.
 *
 *	@since 2.0
*/
function shd_profile_areas(&$profile_areas)
{
    global $sourcedir, $modSettings, $context, $txt;
    static $called = false;
    if ($called) {
        return;
    }
    if (empty($called)) {
        $called = true;
    }
    // SimpleDesk sections. Added here after the initial cleaning is done, so that we can do our own permission checks without arguing with SMF's system (so much)
    if (empty($modSettings['helpdesk_active'])) {
        return;
    }
    shd_load_language('sd_language/SimpleDeskProfile');
    // Put it here so we can reuse it for the left menu a bit
    $context['helpdesk_menu'] = array('title' => $txt['shd_profile_area'], 'areas' => array('hd_profile' => array('label' => $txt['shd_profile_main'], 'file' => 'sd_source/SimpleDesk-Profile.php', 'function' => 'shd_profile_main', 'enabled' => shd_allowed_to('shd_view_profile_any') || $context['user']['is_owner'] && shd_allowed_to('shd_view_profile_own'), 'permission' => array('own' => array('is_not_guest'), 'any' => array('is_not_guest'))), 'hd_prefs' => array('label' => $txt['shd_profile_preferences'], 'file' => 'sd_source/SimpleDesk-Profile.php', 'function' => 'shd_profile_main', 'enabled' => shd_allowed_to('shd_view_preferences_any') || $context['user']['is_owner'] && shd_allowed_to('shd_view_preferences_own'), 'permission' => array('own' => array('shd_view_preferences_own'), 'any' => array('shd_view_preferences_any'))), 'hd_showtickets' => array('label' => $txt['shd_profile_show_tickets'], 'file' => 'sd_source/SimpleDesk-Profile.php', 'function' => 'shd_profile_main', 'enabled' => $context['user']['is_owner'] && shd_allowed_to('shd_view_ticket_own') || shd_allowed_to('shd_view_ticket_any'), 'permission' => array('own' => array('shd_view_ticket_own'), 'any' => array('shd_view_ticket_any'))), 'hd_permissions' => array('label' => $txt['shd_profile_permissions'], 'file' => 'sd_source/SimpleDesk-Profile.php', 'function' => 'shd_profile_main', 'enabled' => shd_allowed_to('admin_helpdesk'), 'permission' => array('own' => array('admin_helpdesk'), 'any' => array('admin_helpdesk'))), 'hd_actionlog' => array('label' => $txt['shd_profile_actionlog'], 'file' => 'sd_source/SimpleDesk-Profile.php', 'function' => 'shd_profile_main', 'enabled' => empty($modSettings['shd_disable_action_log']) && (shd_allowed_to('shd_view_profile_log_any') || $context['user']['is_owner'] && shd_allowed_to('shd_view_profile_log_own')), 'permission' => array('own' => array('shd_view_profile_log_own'), 'any' => array('shd_view_profile_log_any')))));
    // Kill the existing profile menu but save it in a temporary place first.
    $old_profile_areas = $profile_areas;
    $profile_areas = array();
    // Now, where we add this depends very much on what mode we're in. In HD only mode, we want our menu first before anything else.
    if (!empty($modSettings['shd_helpdesk_only'])) {
        require_once $sourcedir . '/Profile-Modify.php';
        // Move some stuff around.
        $context['helpdesk_menu']['areas']['permissions'] = array('label' => $txt['shd_show_forum_permissions'], 'file' => 'Profile-View.php', 'function' => 'showPermissions', 'enabled' => allowedTo('manage_permissions'));
        $context['helpdesk_menu']['areas']['tracking'] = array('label' => $txt['trackUser'], 'file' => 'Profile-View.php', 'function' => 'tracking', 'subsections' => array('activity' => array($txt['trackActivity'], 'moderate_forum'), 'ip' => array($txt['trackIP'], 'moderate_forum'), 'edits' => array($txt['trackEdits'], 'moderate_forum')), 'enabled' => allowedTo('moderate_forum'));
        $profile_areas['helpdesk'] = $context['helpdesk_menu'];
        $profile_areas += $old_profile_areas;
        unset($profile_areas['info']['areas']['permissions'], $profile_areas['info']['areas']['tracking']);
        $remove = array('info' => array('summary', 'statistics', 'showposts', 'viewwarning'), 'edit_profile' => array('forumprofile', 'ignoreboards', 'lists', 'notification'), 'profile_action' => array('issuewarning'));
        if (!empty($modSettings['shd_disable_pm'])) {
            $remove['profile_action'][] = 'sendpm';
            $remove['edit_profile'][] = 'pmprefs';
        }
        foreach ($remove as $area => $items) {
            foreach ($items as $item) {
                if (!empty($profile_areas[$area]['areas'][$item])) {
                    $profile_areas[$area]['areas'][$item]['enabled'] = false;
                }
            }
        }
        $profile_areas['edit_profile']['areas']['theme']['file'] = 'sd_source/SimpleDesk-Profile.php';
        $profile_areas['edit_profile']['areas']['theme']['function'] = 'shd_profile_theme_wrapper';
    } else {
        foreach ($old_profile_areas as $area => $details) {
            if ($area == 'edit_profile') {
                $profile_areas['helpdesk'] = $context['helpdesk_menu'];
            }
            $profile_areas[$area] = $details;
        }
    }
    // Now engage any hooks.
    call_integration_hook('shd_hook_profilemenu', array(&$profile_areas));
}
/**
 *	The start point for all interaction with the SimpleDesk plugins.
 *
 *	Directed here from the main administration centre, after permission checks and a few dependencies loaded, this deals solely with managing custom fields.
 *
 *	@since 2.0
*/
function shd_admin_plugins()
{
    global $context, $scripturl, $sourcedir, $settings, $txt, $modSettings;
    loadTemplate('sd_template/SimpleDesk-AdminPlugins');
    shd_load_language('ManageSettings');
    loadTemplate(false, array('admin', 'helpdesk_admin'));
    $context['shd_enabled_plugins'] = !empty($modSettings['shd_enabled_plugins']) ? explode(',', $modSettings['shd_enabled_plugins']) : array();
    // 1. Look at the plugin directory and figure out whether or not there are some plugins.
    $plugins = array();
    $plugindir = $sourcedir . '/sd_plugins_source';
    $handle = @opendir($plugindir);
    while ($dir_entry = readdir($handle)) {
        if (is_dir($plugindir . '/' . $dir_entry) && $dir_entry != '.' && $dir_entry != '..' && file_exists($plugindir . '/' . $dir_entry . '/index.php')) {
            include_once $plugindir . '/' . $dir_entry . '/index.php';
            $function = 'shdplugin_' . $dir_entry;
            if (function_exists($function)) {
                $plugins[$dir_entry] = $function();
            }
        }
    }
    @closedir($handle);
    // 2. Figure out what language stuff is going on
    $master_langlist = array('albanian', 'arabic', 'bangla', 'bulgarian', 'catalan', 'chinese_simplified', 'chinese_traditional', 'croatian', 'czech', 'danish', 'dutch', 'english', 'english_british', 'finnish', 'french', 'galician', 'german', 'hebrew', 'hindi', 'hungarian', 'indonesian', 'italian', 'japanese', 'kurdish_kurmanji', 'kurdish_sorani', 'macedonian', 'malay', 'norwegian', 'persian', 'polish', 'portuguese_brazilian', 'portuguese_pt', 'romanian', 'russian', 'serbian_cyrillic', 'serbian_latin', 'slovak', 'spanish_es', 'spanish_latin', 'swedish', 'thai', 'turkish', 'ukrainian', 'urdu', 'uzbek_latin', 'vietnamese');
    $langtemplates = array();
    $langfilelist = @opendir($settings['default_theme_dir'] . '/languages/sd_plugins_lang/');
    while ($langfile_entry = readdir($langfilelist)) {
        if (preg_match('~([a-z0-9]+)\\.([a-z\\-\\_]+)(-utf8)?\\.php$~i', $langfile_entry, $matches)) {
            $langtemplates[$matches[1]][$matches[2]] = true;
        }
    }
    @closedir($langfilelist);
    // 3. Figure out what shape the plugins are in
    foreach ($plugins as $id => $plugin) {
        // 3.1 Is installable?
        if (empty($plugins[$id]['details']['compatibility'])) {
            $plugins[$id]['details']['compatibility'] = array($txt['unknown']);
        }
        $plugins[$id]['installable'] = in_array(SHD_VERSION, $plugin['details']['compatibility']);
        // 3.2 Admin language files? (That also means, let's get a list of known languages for this mod)
        $plugins[$id]['languages'] = array();
        if (!empty($plugin['includes']['language']['hdadmin'])) {
            $include = is_array($plugin['includes']['language']['hdadmin']) ? $plugin['includes']['language']['hdadmin'] : array($plugin['includes']['language']['hdadmin']);
            if (!empty($include[0])) {
                $plugins[$id]['languages'] = array_keys($langtemplates[$include[0]]);
            }
            foreach ($include as $langfile) {
                shd_load_language('sd_plugins_lang/' . $langfile);
            }
        }
        // 3.3 Sort out some strings - now we've loaded the lang file
        if (!empty($txt[$plugin['details']['title']])) {
            $plugins[$id]['details']['title'] = $txt[$plugin['details']['title']];
        }
        if (!empty($plugin['details']['description']) && !empty($txt[$plugin['details']['description']])) {
            $plugins[$id]['details']['description'] = $txt[$plugin['details']['description']];
        }
        if (empty($plugin['details']['author'])) {
            $plugins[$id]['details']['author'] = $txt['unknown'];
        }
        // 3.4 Is it enabled?
        $plugins[$id]['enabled'] = in_array($id, $context['shd_enabled_plugins']);
        $plugins[$id]['details']['acp_url'] = !empty($plugin['details']['acp_url']) && $plugins[$id]['enabled'] ? strpos($plugin['details']['acp_url'], 'http') === false ? $scripturl . '?' . $plugin['details']['acp_url'] . ';' . $context['session_var'] . '=' . $context['session_id'] : $plugin['details']['acp_url'] : false;
    }
    // 3. Throw it at the template.
    $context['sub_template'] = 'shd_plugin_listing';
    $context['plugins'] = $plugins;
    $context['page_title'] = $txt['shd_admin_plugins'];
    // 4. Are we saving any changes?
    if (isset($_POST['save'])) {
        checkSession();
        $list_of_settings = shd_list_hooks();
        $setting_changes = array();
        foreach ($list_of_settings as $item) {
            $setting_changes[$item] = array();
        }
        $post_var_prefix = empty($_POST['js_worked']) ? 'feature_plain_' : 'feature_';
        foreach ($plugins as $id => $plugin) {
            if (empty($plugin['installable'])) {
                continue;
            }
            // GET OUT YE WRONGLY VERSIONED SHI--STUFF
            // Is it enabled, if so, go do the voodoo that you do so well!!!!
            if (!empty($_POST[$post_var_prefix . $id])) {
                $setting_changes['shd_enabled_plugins'][] = $id;
                foreach ($plugin['includes']['source'] as $include_point => $include_file) {
                    if (isset($setting_changes['shd_include_' . $include_point]) && file_exists($sourcedir . '/sd_plugins_source/' . $id . '/' . $include_file)) {
                        $setting_changes['shd_include_' . $include_point][] = $id . '/' . $include_file;
                    }
                }
                foreach ($plugin['includes']['language'] as $include_point => $include_file) {
                    if (isset($setting_changes['shd_includelang_' . $include_point])) {
                        $setting_changes['shd_includelang_' . $include_point][] = $include_file;
                    }
                }
                foreach ($plugin['hooks'] as $include_point => $function) {
                    if (isset($setting_changes['shd_hook_' . $include_point])) {
                        $setting_changes['shd_hook_' . $include_point][] = $function;
                    }
                }
            }
            // Is there a call back for settings?
            if (isset($plugin['setting_callback'])) {
                $returned_settings = $plugin['setting_callback'](!empty($_POST[$post_var_prefix . $id]));
                if (!empty($returned_settings)) {
                    $setting_changes = array_merge($setting_changes, $returned_settings);
                }
            }
            // Standard save callback?
            if (isset($plugin['on_save'])) {
                $plugin['on_save']();
            }
        }
        // OK, so whatever we have at this point, we know we're going to be implode'ing and saving.
        foreach ($setting_changes as $setting => $array) {
            $setting_changes[$setting] = implode(',', $array);
        }
        updateSettings($setting_changes);
        // Any post save things?
        foreach ($plugins as $id => $plugin) {
            // Standard save callback?
            if (isset($plugin['save_callback'])) {
                $plugin['save_callback'](!empty($_POST[$post_var_prefix . $id]));
            }
        }
        redirectexit('action=admin;area=helpdesk_plugins;' . $context['session_var'] . '=' . $context['session_id']);
    }
}
/**
 *	Adds the SimpleDesk action to the action list, and also handles most of the shutting down of forum items in helpdesk-only mode.
 *
 *	@param string &$actionArray The master list of actions from index.php
 *
 *	@since 2.0
*/
function shd_init_actions(&$actionArray)
{
    global $modSettings, $context;
    if (empty($modSettings['helpdesk_active'])) {
        return;
    }
    // Deal with SimpleDesk. If we're enabling HD only mode, rebuild everything, otherwise just add it to the array.
    $actionArray['helpdesk'] = array('sd_source/SimpleDesk.php', 'shd_main');
    // Rewrite the array for unread purposes.
    $context['shd_unread_actions'] = array('unread' => $actionArray['unread'], 'unreadreplies' => $actionArray['unreadreplies']);
    $actionArray['unread'] = array('sd_source/SimpleDesk-Unread.php', 'shd_unread_posts');
    $actionArray['unreadreplies'] = array('sd_source/SimpleDesk-Unread.php', 'shd_unread_posts');
    // If we're going to a help page (for admin), make sure to load the relevant text.
    if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'helpadmin') {
        shd_load_language('sd_language/SimpleDeskAdmin');
    }
    if (!empty($modSettings['shd_helpdesk_only'])) {
        // Firstly, remove all the standard actions we neither want nor need.
        // Note we did this to prevent breakage of other mods that may be installed, e.g. gallery or portal or something.
        $unwanted_actions = array('announce', 'attachapprove', 'buddy', 'calendar', 'clock', 'collapse', 'deletemsg', 'display', 'editpoll', 'editpoll2', 'emailuser', 'lock', 'lockvoting', 'markasread', 'mergetopics', 'moderate', 'modifycat', 'modifykarma', 'movetopic', 'movetopic2', 'notify', 'notifyboard', 'post', 'post2', 'printpage', 'quotefast', 'quickmod', 'quickmod2', 'recent', 'removepoll', 'removetopic2', 'reporttm', 'restoretopic', 'search', 'search2', 'sendtopic', 'smstats', 'splittopics', 'stats', 'sticky', 'about:mozilla', 'about:unknown', 'unread', 'unreadreplies', 'vote', 'viewquery', 'who', '.xml', 'xmlhttp');
        // that's the generic stuff, now for specific options
        if (!empty($modSettings['shd_disable_pm'])) {
            $unwanted_actions[] = 'pm';
        }
        if (!empty($modSettings['shd_disable_mlist'])) {
            $unwanted_actions[] = 'mlist';
        }
        foreach ($unwanted_actions as $unwanted) {
            if (isset($actionArray[$unwanted])) {
                unset($actionArray[$unwanted]);
            }
        }
        // Secondly, rewrite the defaults to point to helpdesk, for unknown actions. I'm doing this rather than munging the main code - easier to unbreak stuff
        if (empty($actionArray[$_GET['action']])) {
            $_GET['action'] = 'helpdesk';
        }
    }
    // Now engage any SD specific hooks.
    call_integration_hook('shd_hook_actions', array(&$actionArray));
    // Lastly, any other-action-specific hooks?
    if (!empty($_GET['action']) && !empty($actionArray[$_GET['action']])) {
        shd_load_plugin_files('action_' . $_GET['action']);
        shd_load_plugin_langfiles('action_' . $_GET['action']);
        call_integration_hook('shd_hook_action' . $_GET['action'], array(&$actionArray));
    }
    $context['master_action_list'] = array_keys($actionArray);
}
function shd_profile_actionlog($memID)
{
    global $context, $txt, $scripturl, $sourcedir, $user_info, $settings;
    loadTemplate('sd_template/SimpleDesk-Profile');
    shd_load_language('sd_language/SimpleDeskProfile');
    require_once $sourcedir . '/sd_source/Subs-SimpleDeskAdmin.php';
    $context['action_log'] = shd_load_action_log_entries(-1, 10, '', '', 'la.id_member = ' . $memID);
    $context['action_log_count'] = shd_count_action_log_entries('la.id_member = ' . $memID);
    $context['action_full_log'] = allowedTo('admin_forum') || shd_allowed_to('admin_helpdesk', 0);
    $context['page_title'] = $txt['shd_profile_area'] . ' - ' . $txt['shd_profile_actionlog'];
    $context['sub_template'] = 'shd_profile_actionlog';
}
/**
 *	Load the form up for asking users what board they want to go to.
 *
 *	Validates the user permission and session, then displays a list of boards the user can create new topics in.
 *
 *	Accessed through action=helpdesk;sa=tickettotopic;ticket=x;sessvar=sessid
 *
 *	@see shd_tickettotopic2()
 *	@since 1.0
*/
function shd_tickettotopic()
{
    global $smcFunc, $context, $user_info, $sourcedir, $txt, $modSettings, $scripturl;
    checkSession('get');
    if (empty($context['ticket_id'])) {
        fatal_lang_error('shd_no_ticket');
    }
    // Get ticket details - and kick it out if they shouldn't be able to see it.
    $query = shd_db_query('', '
		SELECT id_member_started, id_member_assigned, private, subject, deleted_replies, hdt.id_dept, hdd.dept_name
		FROM {db_prefix}helpdesk_tickets AS hdt
			INNER JOIN {db_prefix}helpdesk_depts AS hdd ON (hdt.id_dept = hdd.id_dept)
		WHERE {query_see_ticket} AND id_ticket = {int:ticket}', array('ticket' => $context['ticket_id']));
    if ($row = $smcFunc['db_fetch_row']($query)) {
        list($ticket_starter, $ticket_owner, $private, $subject, $deleted_replies, $dept, $dept_name) = $row;
        $smcFunc['db_free_result']($query);
    } else {
        $smcFunc['db_free_result']($query);
        fatal_lang_error('shd_no_ticket');
    }
    if (!shd_allowed_to('shd_ticket_to_topic', $dept) || !empty($modSettings['shd_helpdesk_only']) || !empty($modSettings['shd_disable_tickettotopic'])) {
        fatal_lang_error('shd_cannot_move_ticket', false);
    }
    // Hang on... are there any deleted replies?
    if ($deleted_replies > 0) {
        if (shd_allowed_to('shd_access_recyclebin', $dept)) {
            $context['deleted_prompt'] = true;
        } else {
            fatal_lang_error('shd_cannot_move_ticket_with_deleted');
        }
    }
    // In a department, for the linktree?
    if ($context['shd_multi_dept']) {
        $context['linktree'][] = array('url' => $scripturl . '?' . $context['shd_home'] . ';dept=' . $dept, 'name' => $dept_name);
    }
    // Build the linktree
    $context['linktree'][] = array('url' => $scripturl . '?' . $context['shd_home'] . ($context['shd_multi_dept'] ? ';dept=' . $dept : ''), 'name' => $txt['shd_linktree_move_ticket']);
    $context['linktree'][] = array('url' => $scripturl . '?action=helpdesk;sa=ticket;ticket=' . $context['ticket_id'], 'name' => $subject);
    // They should only be able to move it to boards they are allowed to post in.
    $allowedboards = boardsAllowedTo('post_new');
    if ($allowedboards[0] == 0) {
        $allowedboards = '';
    }
    // They can access everything.
    // All good, now figure out what board(s) they can move it to. (MoveTopic.php style 0-:D)
    $request = shd_db_query('order_by_board_order', '
		SELECT b.id_board, b.name, b.child_level, c.name AS cat_name, c.id_cat
		FROM {db_prefix}boards AS b
			LEFT JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat)
		WHERE {query_see_board}
			AND b.redirect = {string:blank_redirect}
			' . (!empty($allowedboards) ? 'AND id_board IN({array_int:allowed_boards})' : ''), array('blank_redirect' => '', 'allowed_boards' => $allowedboards));
    $context['boards'] = array();
    while ($row = $smcFunc['db_fetch_assoc']($request)) {
        if (!isset($context['categories'][$row['id_cat']])) {
            $context['categories'][$row['id_cat']] = array('name' => strip_tags($row['cat_name']), 'boards' => array());
        }
        $context['categories'][$row['id_cat']]['boards'][] = array('id' => $row['id_board'], 'name' => strip_tags($row['name']), 'category' => strip_tags($row['cat_name']), 'child_level' => $row['child_level']);
    }
    $smcFunc['db_free_result']($request);
    if (empty($context['categories'])) {
        fatal_lang_error('shd_moveticket_noboards', false);
    }
    // OK, now we got to check for custom fields. In any case, we need to fetch the list of fields that might be applicable to this ticket.
    shd_load_language('sd_language/SimpleDeskAdmin');
    $context['field_types'] = array(CFIELD_TYPE_TEXT => array($txt['shd_admin_custom_fields_ui_text'], 'text'), CFIELD_TYPE_LARGETEXT => array($txt['shd_admin_custom_fields_ui_largetext'], 'largetext'), CFIELD_TYPE_INT => array($txt['shd_admin_custom_fields_ui_int'], 'int'), CFIELD_TYPE_FLOAT => array($txt['shd_admin_custom_fields_ui_float'], 'float'), CFIELD_TYPE_SELECT => array($txt['shd_admin_custom_fields_ui_select'], 'select'), CFIELD_TYPE_CHECKBOX => array($txt['shd_admin_custom_fields_ui_checkbox'], 'checkbox'), CFIELD_TYPE_RADIO => array($txt['shd_admin_custom_fields_ui_radio'], 'radio'), CFIELD_TYPE_MULTI => array($txt['shd_admin_custom_fields_ui_multi'], 'multi'));
    $query = $smcFunc['db_query']('', '
		SELECT hdcf.id_field, hdcf.field_name, hdcf.field_order, hdcf.field_type, hdcf.can_see
		FROM {db_prefix}helpdesk_custom_fields_depts AS hdd
			INNER JOIN {db_prefix}helpdesk_custom_fields AS hdcf ON (hdd.id_field = hdcf.id_field)
		WHERE hdd.id_dept = {int:dept}
			AND hdcf.active = {int:active}
		ORDER BY hdcf.field_order', array('dept' => $dept, 'active' => 1));
    $context['custom_fields'] = array();
    $is_staff = shd_allowed_to('shd_staff', $dept);
    $is_admin = shd_allowed_to('admin_helpdesk', $dept);
    while ($row = $smcFunc['db_fetch_assoc']($query)) {
        list($user_see, $staff_see) = explode(',', $row['can_see']);
        $context['custom_fields'][$row['id_field']] = array('id_field' => $row['id_field'], 'name' => $row['field_name'], 'type' => $row['field_type'], 'visible' => array('user' => $user_see, 'staff' => $staff_see, 'admin' => true), 'values' => array());
    }
    $smcFunc['db_free_result']($query);
    // Having got all the possible fields for this ticket, let's fetch the values for it. That way if we don't have any values for a field, we don't have to care about showing the user.
    // But first, we need all the message ids.
    $context['ticket_messages'] = array();
    $query = $smcFunc['db_query']('', '
		SELECT id_msg
		FROM {db_prefix}helpdesk_ticket_replies AS hdtr
		WHERE id_ticket = {int:ticket}', array('ticket' => $context['ticket_id']));
    while ($row = $smcFunc['db_fetch_row']($query)) {
        $context['ticket_messages'][] = $row[0];
    }
    $smcFunc['db_free_result']($query);
    // Now get a reference for the field values.
    $query = shd_db_query('', '
		SELECT cfv.id_post, cfv.id_field, cfv.post_type
		FROM {db_prefix}helpdesk_custom_fields_values AS cfv
		WHERE (cfv.id_post = {int:ticket} AND cfv.post_type = 1)' . (!empty($context['ticket_messages']) ? '
			OR (cfv.id_post IN ({array_int:msgs}) AND cfv.post_type = 2)' : ''), array('ticket' => $context['ticket_id'], 'msgs' => $context['ticket_messages']));
    while ($row = $smcFunc['db_fetch_assoc']($query)) {
        if (isset($context['custom_fields'][$row['id_field']])) {
            $context['custom_fields'][$row['id_field']]['values'][$row['post_type']][$row['id_post']] = true;
        }
    }
    $smcFunc['db_free_result']($query);
    // Having now established what fields we do actually have values for, let's proceed to deal with them.
    foreach ($context['custom_fields'] as $field_id => $field) {
        // Didn't we have any values? If not, prune it, not interested.
        if (empty($field['values'])) {
            unset($context['custom_fields'][$field_id]);
        }
        // If the user is an administrator, they can always see the fields.
        if ($is_admin) {
            // But users might not be able to, in which case warn the user.
            if (!$field['visible']['user'] || !$field['visible']['staff']) {
                $context['custom_fields'][$field_id]['visible_warn'] = true;
                $context['custom_fields_warning'] = true;
            }
        } elseif ($is_staff) {
            // So they're staff. But the field might not be visible to them; they can't deal with it.
            if (!$field['visible']['staff']) {
                fatal_lang_error('cannot_shd_move_ticket_topic_hidden_cfs', false);
            } elseif (!$field['visible']['user']) {
                // Normal mortals can't see it even if this person can, so warn them.
                $context['custom_fields'][$field_id]['visible_warn'] = true;
                $context['custom_fields_warning'] = true;
            }
        } else {
            // Non staff aren't special. They should not be able to make this decision. If someone can't see it, they don't get to make the choice.
            if (!$field['visible']['user'] || !$field['visible']['staff']) {
                fatal_lang_error('cannot_shd_move_ticket_topic_hidden_cfs', false);
            }
        }
    }
    // Store the ticket subject for the template
    $context['ticket_subject'] = $subject;
    loadTemplate('sd_template/SimpleDesk-TicketTopicMove');
    $context['sub_template'] = 'shd_tickettotopic';
    $context['page_title'] = $txt['shd_move_ticket_to_topic'];
    checkSubmitOnce('register');
}
/**
 *	Provide the list of possible notification recipients.
 *
 *	@since 2.0
*/
function shd_ajax_notify()
{
    global $txt, $context, $smcFunc, $user_profile, $modSettings, $sourcedir;
    $session_check = checkSession('get', '', false);
    // check the session but don't die fatally.
    if (!empty($session_check)) {
        return $context['ajax_return'] = array('error' => $txt[$session_check]);
    }
    shd_load_language('sd_language/SimpleDeskNotifications');
    require_once $sourcedir . '/sd_source/SimpleDesk-Notifications.php';
    if (!empty($context['ticket_id'])) {
        $query = shd_db_query('', '
			SELECT hdt.private, hdt.id_member_started, id_member_assigned, id_dept, status
			FROM {db_prefix}helpdesk_tickets AS hdt
			WHERE {query_see_ticket}
				AND hdt.id_ticket = {int:ticket}', array('ticket' => $context['ticket_id']));
        if ($smcFunc['db_num_rows']($query) != 0) {
            $ticket = $smcFunc['db_fetch_assoc']($query);
        }
        $smcFunc['db_free_result']($query);
    }
    if (empty($ticket) || !shd_allowed_to('shd_singleton_email', $ticket['id_dept']) || $ticket['status'] == TICKET_STATUS_CLOSED || $ticket['status'] == TICKET_STATUS_DELETED) {
        return $context['ajax_return'] = array('error' => $txt['shd_no_ticket']);
    }
    // So, we need to start figuring out who's going to be notified, who won't be and who we might be interested in notifying.
    $notify_list = array('being_notified' => array(), 'optional' => array(), 'optional_butoff' => array());
    // Let's get all the possible actual people. The possible people who can be notified... well, they're staff.
    $staff = shd_get_visible_list($ticket['id_dept'], $ticket['private'], $ticket['id_member_started'], empty($modSettings['shd_admins_not_assignable']), false);
    // Let's start figuring it out then! First, get the big ol' lists.
    $query = $smcFunc['db_query']('', '
		SELECT id_member, notify_state
		FROM {db_prefix}helpdesk_notify_override
		WHERE id_ticket = {int:ticket}', array('ticket' => $context['ticket_id']));
    while ($row = $smcFunc['db_fetch_assoc']($query)) {
        $notify_list[$row['notify_state'] == NOTIFY_NEVER ? 'optional_butoff' : 'being_notified'][$row['id_member']] = true;
    }
    // Did we exclude admins? If we did, we would have scooped the list of admins. If they're in the 'not being notified but you can...' list, remove them.
    if (!empty($context['list_admin_exclude'])) {
        foreach ($context['list_admin_exclude'] as $user_id) {
            if (isset($notify_list['optional_butoff'][$user_id])) {
                unset($notify_list['optional_butoff'][$user_id]);
            }
        }
    }
    // Now we get the list by preferences. This is where it starts to get complicated.
    $possible_members = array();
    // People who want replies to their own ticket, without including the ticket starter because they'd know about it...
    if (!empty($modSettings['shd_notify_new_reply_own']) && $context['user']['id'] != $ticket['id_member_started']) {
        $possible_members[$ticket['id_member_started']]['new_reply_own'] = true;
    }
    // The ticket is assigned to someone and they want to be notified if it changes.
    if (!empty($modSettings['shd_notify_new_reply_assigned']) && !empty($ticket['id_member_assigned']) && $context['user']['id'] != $ticket['id_member_assigned']) {
        $possible_members[$ticket['id_member_assigned']]['new_reply_assigned'] = true;
    }
    // So, if you're staff, and you've replied to this ticket before, do you want to be notified this time?
    if (!empty($modSettings['shd_notify_new_reply_previous'])) {
        $query = $smcFunc['db_query']('', '
			SELECT id_member
			FROM {db_prefix}helpdesk_ticket_replies
			WHERE id_ticket = {int:ticket}
			GROUP BY id_member', array('ticket' => $context['ticket_id']));
        $responders = array();
        while ($row = $smcFunc['db_fetch_row']($query)) {
            $responders[] = $row[0];
        }
        // this shouldn't be nil, ever, because we're replying, so the topic already exists so there's at least one name in there...
        $smcFunc['db_free_result']($query);
        $responders = array_intersect($responders, $staff);
        foreach ($responders as $id) {
            $possible_members[$id]['new_reply_previous'] = true;
        }
    }
    // If you're staff, did you have 'spam my inbox every single time' selected?
    if (!empty($modSettings['shd_notify_new_reply_any'])) {
        foreach ($staff as $id) {
            $possible_members[$id]['new_reply_any'] = true;
        }
    }
    // Now we have the list of possibles, exclude everyone who is either set to on, or off, since we don't need to query those for preferences.
    foreach ($possible_members as $id => $type_list) {
        if (isset($notify_list['being_notified'][$id]) || isset($notify_list['optional_butoff'][$id])) {
            unset($possible_members[$id]);
        }
    }
    if (!empty($possible_members)) {
        // Get the default preferences
        $prefs = shd_load_user_prefs(false);
        $pref_groups = $prefs['groups'];
        $base_prefs = $prefs['prefs'];
        // Build a list of users -> default prefs. We know this is for the list of possible contenders only.
        $member_prefs = array();
        $pref_list = array();
        foreach ($possible_members as $id => $type_list) {
            foreach ($type_list as $type => $value) {
                $member_prefs[$id][$type] = $base_prefs['notify_' . $type]['default'];
                $pref_list['notify_' . $type] = true;
            }
        }
        // Grab pref list from DB for these users and update
        $query = $smcFunc['db_query']('', '
			SELECT id_member, variable, value
			FROM {db_prefix}helpdesk_preferences
			WHERE id_member IN ({array_int:members})
				AND variable IN ({array_string:variables})', array('members' => array_keys($possible_members), 'variables' => array_keys($pref_list)));
        while ($row = $smcFunc['db_fetch_assoc']($query)) {
            $row['id_member'] = (int) $row['id_member'];
            $variable = substr($row['variable'], 7);
            if (isset($member_prefs[$row['id_member']][$variable])) {
                $member_prefs[$row['id_member']][$variable] = $row['value'];
            }
        }
        $smcFunc['db_free_result']($query);
        // unset $members where member pref doesn't indicate they want it on.
        foreach ($member_prefs as $id => $value) {
            foreach ($value as $pref_id => $pref_item) {
                if (empty($pref_item)) {
                    unset($possible_members[$id][$pref_id]);
                }
            }
        }
        // Now, it's possible that we have a ticket that the starter can't see, but that their preferences would indicate they'd like a reply.
        // What should be done here is to remove them from the automatic list, and make them part of the ping list instead.
        if (!empty($ticket['id_member_started']) && !in_array($ticket['id_member_started'], $staff)) {
            $possible_members[$ticket['id_member_started']] = array();
        }
        // Now the clever bit, we've taken everyone who wasn't on the normal notify list, and figured out what their preferences are.
        // We now traverse $possible_members by id, if the array is empty, we know none of their preferences accounted for emails - so they're possible.
        // Otherwise we add them to the list of being notified.
        foreach ($possible_members as $id => $list) {
            if (empty($list)) {
                $notify_list['optional'][$id] = true;
            } else {
                $notify_list['being_notified'][$id] = true;
            }
        }
    }
    // By now we have three lists that include people who will be notified, people who could be notified, and people who don't really want to be.
    // Let's translate that into a list of people that we can make use of.
    $members = array_merge(array_keys($notify_list['being_notified']), array_keys($notify_list['optional']), array_keys($notify_list['optional_butoff']));
    if (!empty($members)) {
        // Get everyone's name.
        $loaded = loadMemberData($members);
        foreach ($loaded as $user) {
            if (!empty($user_profile[$user]) && $user_profile[$user]['is_activated'] > 0 && $user_profile[$user]['is_activated'] < 10) {
                // active & not banned
                $people[$user] = array('id' => $user, 'name' => $user_profile[$user]['real_name']);
            }
        }
        // Right, now let's step through and tidy up the three lists
        foreach ($notify_list as $list_type => $list_members) {
            foreach ($list_members as $id_member => $data) {
                if (isset($people[$id_member]) && $id_member != $context['user']['id']) {
                    // We really shouldn't be in this list.
                    $list_members[$id_member] = $people[$id_member]['name'];
                } else {
                    unset($list_members[$id_member]);
                }
            }
            if (!empty($list_members)) {
                asort($list_members);
                array_walk($list_members, 'shd_format_notify_name', $ticket['id_member_started']);
                $notify_list[$list_type] = $list_members;
            } else {
                unset($notify_list[$list_type]);
            }
        }
    }
    if (empty($notify_list) || empty($members)) {
        return $context['ajax_raw'] = '<notify><![C' . 'DATA[' . cleanXml($txt['shd_ping_none']) . ']' . ']></notify>';
    } else {
        ob_start();
        echo '<notify><![C', 'DATA[';
        $selected = array();
        if (!empty($_GET['list'])) {
            $_GET['list'] = explode(',', $_GET['list']);
            foreach ($_GET['list'] as $id) {
                if ((int) $id > 0) {
                    $selected[] = (int) $id;
                }
            }
        }
        if (!empty($notify_list['being_notified'])) {
            echo '<span class="shd_ajax_head">', $txt['shd_ping_already_' . (count($notify_list['being_notified']) == 1 ? '1' : 'n')], '</span><br />', implode(', ', $notify_list['being_notified']);
        }
        if (!empty($notify_list['optional'])) {
            if (!empty($notify_list['being_notified'])) {
                echo '<br /><br />';
            }
            echo '<span class="shd_ajax_head">', $txt['shd_ping_' . (count($notify_list['optional']) == 1 ? '1' : 'n')], '</span><br />';
            foreach ($notify_list['optional'] as $id => $member) {
                echo '<div class="shd_ajaxnotify"><input type="checkbox" name="notify[', $id, ']" value="', $id, '"', in_array($id, $selected) ? ' checked="checked"' : '', ' class="input_check" /> ', $member, '</div>';
            }
        }
        if (!empty($notify_list['optional_butoff'])) {
            if (!empty($notify_list['being_notified']) || !empty($notify_list['optional_butoff'])) {
                echo '<br /><br />';
            }
            echo '<span class="shd_ajax_head">', $txt['shd_ping_none_' . (count($notify_list['optional_butoff']) == 1 ? '1' : 'n')], '</span><br />';
            foreach ($notify_list['optional_butoff'] as $id => $member) {
                echo '<div class="shd_ajaxnotify"><input type="checkbox" name="notify[', $id, ']" value="', $id, '"', in_array($id, $selected) ? ' checked="checked"' : '', ' class="input_check" /> ', $member, '</div>';
            }
        }
        echo ']', ']></notify>';
        $content = ob_get_clean();
        return $context['ajax_raw'] = cleanXml($content);
    }
}
/**
 *	Add the SimpleDesk option into the Core Features page inside the admin panel.
 *
 *	@param array &$core_features The array of Core Features as provided by ManageSettings.php
*/
function shd_admin_core_features(&$core_features)
{
    $temp = $core_features;
    $core_features = array();
    shd_load_language('sd_language/SimpleDeskAdmin');
    foreach ($temp as $k => $v) {
        // Insert it before the moderation log
        if ($k == 'ml') {
            $core_features['shd'] = array('url' => 'action=admin;area=helpdesk_info');
        }
        $core_features[$k] = $v;
    }
}
/**
 *	Intergrates into SMF's admin search.
 *
 *	@since 2.0
 *	@param array &$language_files language files to include.
 *	@param array &$include_files Files to load.
 *	@param array &$settings_search Settings to search.
*/
function shd_admin_search(&$language_files, &$include_files, &$settings_search)
{
    // Add in language files.
    shd_load_language('sd_language/SimpleDeskAdmin');
    $include_files = array_merge($include_files, array('sd_source/SimpleDesk-Admin'));
    // Add SimpleDesk functions
    $settings_search = array_merge($settings_search, array(array('shd_modify_display_options', 'area=helpdesk_options;sa=display'), array('shd_modify_posting_options', 'area=helpdesk_options;sa=posting'), array('shd_modify_admin_options', 'area=helpdesk_options;sa=admin'), array('shd_modify_standalone_options', 'area=helpdesk_options;sa=standalone'), array('shd_modify_actionlog_options', 'area=helpdesk_options;sa=actionlog'), array('shd_modify_notifications_options', 'area=helpdesk_options;sa=notifications')));
    // Our plugins may still use the old SHD hook.
    call_integration_hook('shd_hook_hdadminoptssrch', array(&$settings_search));
}
/**
 *	Display the notice of email.
 *
 *	@todo Finish documenting
 *	@since 2.0
*/
function shd_notify_popup()
{
    global $txt, $context, $settings, $modSettings, $smcFunc, $user_profile, $user_info, $scripturl;
    // First, verify we got a log entry, that the log entry is right, and it points to a ticket we can actually see.
    $_GET['log'] = isset($_GET['log']) ? (int) $_GET['log'] : 0;
    $email_type = isset($_GET['template']) ? preg_replace('~[^a-z_]~', '', $_GET['template']) : '';
    if (empty($modSettings['shd_display_ticket_logs']) || empty($_GET['log']) || empty($email_type)) {
        fatal_lang_error('no_access', false);
    }
    $query = $smcFunc['db_query']('', '
		SELECT hdla.id_member, hdla.id_ticket, hdla.id_msg, hdla.extra, IFNULL(hdtr.body, {string:empty}) AS body, IFNULL(mem.real_name, hdtr.poster_name) AS poster_name
		FROM {db_prefix}helpdesk_log_action AS hdla
			LEFT JOIN {db_prefix}helpdesk_ticket_replies AS hdtr ON (hdla.id_msg = hdtr.id_msg)
			LEFT JOIN {db_prefix}members AS mem ON (hdtr.id_member = mem.id_member)
		WHERE id_action = {int:log}
			AND action = {string:notify}', array('log' => $_GET['log'], 'notify' => 'notify', 'empty' => ''));
    if ($smcFunc['db_num_rows']($query) == 0) {
        $smcFunc['db_free_result']($query);
        fatal_lang_error('no_access');
    }
    $row = $smcFunc['db_fetch_assoc']($query);
    $smcFunc['db_free_result']($query);
    $row['extra'] = unserialize($row['extra']);
    // Just check we did actually log an email of that type.
    if (empty($row['extra']['emails'][$_GET['template']])) {
        fatal_lang_error('no_access', false);
    }
    $ticketinfo = shd_load_ticket($row['id_ticket']);
    // OK, if we're here, we can see the ticket. Can we actually see the email log at this point?
    if (!shd_allowed_to('shd_view_ticket_logs_any', $ticketinfo['dept']) && (!shd_allowed_to('shd_view_ticket_logs_own', $ticketinfo['dept']) || !$ticketinfo['is_own'])) {
        fatal_lang_error('no_access', false);
    }
    // We're reusing the Help template, need its language file.
    loadLanguage('Help');
    shd_load_language('sd_language/SimpleDeskAdmin');
    shd_load_language('sd_language/SimpleDeskLogAction');
    shd_load_language('sd_language/SimpleDeskNotifications');
    // Set the page up
    loadTemplate('Help');
    $context['page_title'] = $context['forum_name'] . ' - ' . $txt['shd_log_notifications'];
    $context['template_layers'] = array();
    $context['sub_template'] = 'popup';
    $users = array();
    // First, get the list of users, and load their username etc if we haven't already attempted it before.
    if (isset($row['extra']['emails'][$email_type]['u'])) {
        $users = array_merge($users, explode(',', $row['extra']['emails'][$email_type]['u']));
    }
    if (!empty($users)) {
        $users = array_unique($users);
        if (!empty($users)) {
            loadMemberData($users, false, 'minimal');
        }
    }
    // Now we have all the usernames for this instance, let's go and build this entry.
    $context['help_text'] = $txt['shd_log_notify_to'] . '<br />';
    $new_content = '';
    if (!empty($users)) {
        $first = true;
        foreach ($users as $user) {
            if (empty($user_profile[$user])) {
                continue;
            }
            $new_content .= ($first ? '<img src="' . shd_image_url('user.png') . '" alt="" /> ' : ', ') . shd_profile_link($user_profile[$user]['real_name'], $user);
            $first = false;
        }
    }
    if (!empty($row['extra']['emails'][$email_type]['e'])) {
        $emails = explode(',', $row['extra']['emails'][$email_type]['e']);
        // Admins can see the actual emails.
        if (shd_allowed_to('admin_helpdesk', 0) || $user_info['is_admin']) {
            foreach ($emails as $key => $value) {
                $emails[$key] = '<a href="mailto:' . $value . '">' . $value . '</a>';
            }
            $new_content .= '<img src="' . shd_image_url('log_notify.png') . '" alt="" /> ' . implode(', ', $emails);
        } else {
            $new_content .= '<img src="' . shd_image_url('log_notify.png') . '" alt="" /> ' . (count($emails) == 1 ? $txt['shd_log_notify_hiddenemail_1'] : sprintf($txt['shd_log_notify_hiddenemail'], count($emails)));
        }
    }
    if (!empty($new_content)) {
        $context['help_text'] .= $new_content;
    }
    $context['help_text'] .= '<hr />';
    // So the general prep is done. Now let's rebuild the email contents.
    if (empty($row['extra']['withbody']) || empty($row['body'])) {
        $body = '';
    } else {
        $body = trim(un_htmlspecialchars(strip_tags(strtr(shd_format_text($row['body'], false), array('<br />' => "\n", '</div>' => "\n", '</li>' => "\n", '&#91;' => '[', '&#93;' => ']')))));
    }
    $replacements = array("\n" => '<br />', '{ticket_id}' => str_pad($row['id_ticket'], $modSettings['shd_zerofill'], '0', STR_PAD_LEFT), '{subject}' => empty($row['extra']['subject']) ? $txt['no_subject'] : $row['extra']['subject'], '{ticketlink}' => $scripturl . '?action=helpdesk;sa=ticket;ticket=' . $row['id_ticket'] . (empty($row['id_msg']) ? '.0' : '.msg' . $row['id_msg'] . '#msg' . $row['id_msg']), '{body}' => $body, '{poster_name}' => $row['poster_name']);
    $email_subject = str_replace(array_keys($replacements), array_values($replacements), $txt['template_subject_notify_' . $email_type]);
    $email_body = str_replace(array_keys($replacements), array_values($replacements), $txt['template_' . (empty($row['extra']['withbody']) || empty($row['body']) ? 'body' : 'bodyfull') . '_notify_' . $email_type]);
    $context['help_text'] .= '<strong>' . $txt['subject'] . ':</strong> ' . $email_subject . '<br /><br />' . $email_body;
}
function shd_admin_edit_dept()
{
    global $context, $txt, $smcFunc, $scripturl;
    shd_load_language('sd_language/SimpleDeskPermissions');
    $_REQUEST['dept'] = isset($_REQUEST['dept']) ? (int) $_REQUEST['dept'] : 0;
    // Get the current department
    $query = $smcFunc['db_query']('', '
		SELECT id_dept, dept_name, description, board_cat, before_after, dept_theme, autoclose_days
		FROM {db_prefix}helpdesk_depts
		WHERE id_dept = {int:dept}', array('dept' => $_REQUEST['dept']));
    if ($smcFunc['db_num_rows']($query) == 0) {
        $smcFunc['db_free_result']($query);
        fatal_lang_error('shd_unknown_dept', false);
    }
    $context['shd_dept'] = $smcFunc['db_fetch_assoc']($query);
    $context['shd_dept']['description'] = htmlspecialchars($context['shd_dept']['description']);
    $smcFunc['db_free_result']($query);
    // Get the category list
    $context['shd_cat_list'] = array(0 => $txt['shd_boardindex_cat_none']);
    $request = $smcFunc['db_query']('', '
		SELECT id_cat, name
		FROM {db_prefix}categories
		ORDER BY cat_order');
    while ($row = $smcFunc['db_fetch_assoc']($request)) {
        $context['shd_cat_list'][$row['id_cat']] = $row['name'];
    }
    $smcFunc['db_free_result']($request);
    // Now the role list
    $query = $smcFunc['db_query']('', '
		SELECT id_role, template, role_name
		FROM {db_prefix}helpdesk_roles
		ORDER BY id_role');
    while ($row = $smcFunc['db_fetch_assoc']($query)) {
        $context['shd_roles'][$row['id_role']] = $row;
    }
    $smcFunc['db_free_result']($query);
    $query = $smcFunc['db_query']('', '
		SELECT id_role
		FROM {db_prefix}helpdesk_dept_roles
		WHERE id_dept = {int:dept}', array('dept' => $_REQUEST['dept']));
    while ($row = $smcFunc['db_fetch_assoc']($query)) {
        $context['shd_roles'][$row['id_role']]['in_dept'] = true;
    }
    $smcFunc['db_free_result']($query);
    // And the theme list
    shd_get_dept_theme_list();
    $context['page_title'] = $txt['shd_edit_dept'];
    $context['sub_template'] = 'shd_edit_dept';
}
Beispiel #12
0
/**
 *	Initialises the helpdesk action log.
 *
 *	This function loads the language strings, and hands off to {@link shd_load_action_log_entries()} to perform the actual log
 *	generation.
 *
 *	Before doing so, however, this function will also prepare for deletion of old entries, as well as sorting out the columns and
 *	ordering rules before handing control to the other function.
 *
 *	@since 1.0
*/
function shd_admin_action_log()
{
    global $context, $settings, $scripturl, $txt, $sourcedir, $smcFunc, $sort_types;
    shd_load_language('sd_language/SimpleDeskLogAction');
    $context['can_delete'] = allowedTo('admin_forum');
    $context['displaypage'] = 30;
    $context['hoursdisable'] = 24;
    $context['waittime'] = time() - $context['hoursdisable'] * 3600;
    // Handle deletion...
    if (isset($_REQUEST['removeall']) && $context['can_delete']) {
        shd_db_query('', '
			DELETE FROM {db_prefix}helpdesk_log_action
			WHERE log_time < {int:twenty_four_hours_wait}', array('twenty_four_hours_wait' => $context['waittime']));
    } elseif (!empty($_REQUEST['remove']) && $context['can_delete']) {
        shd_db_query('', '
			DELETE FROM {db_prefix}helpdesk_log_action
			WHERE id_action = {int:gtfo}
			AND log_time < {int:twenty_four_hours_wait}', array('twenty_four_hours_wait' => $context['waittime'], 'gtfo' => (int) $_REQUEST['remove']));
    }
    // Do the column stuff!
    $sort_types = array('action' => 'la.action', 'time' => 'la.log_time', 'member' => 'mem.real_name', 'position' => 'mg.group_name', 'ip' => 'la.ip');
    // Setup the direction stuff...
    $context['sort'] = isset($_REQUEST['sort']) && isset($sort_types[$_REQUEST['sort']]) ? $sort_types[$_REQUEST['sort']] : $sort_types['time'];
    $context['start'] = isset($_REQUEST['start']) ? $_REQUEST['start'] : 0;
    $context['order'] = isset($_REQUEST['asc']) ? 'ASC' : 'DESC';
    $context['url_sort'] = isset($_REQUEST['sort']) ? ';sort=' . $_REQUEST['sort'] : '';
    $context['url_order'] = isset($_REQUEST['asc']) ? ';asc' : '';
    // Get all action log entries
    $context['actions'] = shd_load_action_log_entries($context['start'], $context['displaypage'], $context['sort'], $context['order']);
    $context['page_index'] = shd_no_expand_pageindex($scripturl . '?action=admin;area=helpdesk_info;sa=actionlog' . $context['url_sort'] . $context['url_order'], $context['start'], shd_count_action_log_entries(), $context['displaypage']);
    $context['sub_template'] = 'shd_action_log';
}