<?php /*

 Composr
 Copyright (c) ocProducts, 2004-2016

 See text/EN/licence.txt for full licencing information.


 NOTE TO PROGRAMMERS:
   Do not edit this file. If you need to make changes, save your changed file to the appropriate *_custom folder
   **** If you ignore this advice, then your website upgrades (e.g. for bug fixes) will likely kill your changes ****

*/

/**
 * @license    http://opensource.org/licenses/cpal_1.0 Common Public Attribution License
 * @copyright  ocProducts Ltd
 * @package    core_cns
 */

/*

Conversr is designed to run under a number of different situations, via the object orientated driver situation, and some driver variable switcher functions in import.php.
 - Standalone Conversr (FORUM_DB==SITE_DB, but not explicitly)
 - Installation (force standalone Conversr, regardless of whether it is on an MSN in normal use: FORUM_DB:=SITE_DB, for installation/upgrading of Conversr only)
 - Multi site network linking / Importing a non-forum (FORUM_DB!=SITE_DB)
 - Importing a forum (import.php functions used to to and from Conversr and normal-forum-driver [which might not be Conversr])

Exception: Welcome Mails are per-site, so run through SITE_DB. They have their own install code in the admin module though.

SITE_DB - The site database, always
FORUM_DB - The forum database. If not using Conversr, will not be the Conversr db. Switched around by installer/forum-importers according for need for locality/Conversrality.
FORUM_DRIVER - The forum driver. May not be Conversr, depending on which forum driver is used.
CNS_DRIVER - A forum driver to Conversr. This is always used in Conversr rather than FORUM_DRIVER, in case Conversr functions are being called when Conversr is not the primary forum driver running (when importing to Conversr but using a different forum driver, often when in the process of switching forums)

The Conversr functions should always call up the attachment and language systems using explicitly the forum database, so multi site networks function properly.

*/

/**
 * Standard code module initialisation function.
 *
 * @ignore
 */
function init__cns_install()
{
    global $CNS_TRUE_PERMISSIONS, $CNS_FALSE_PERMISSIONS;
    $CNS_TRUE_PERMISSIONS = array(
        'run_multi_moderations',
        'use_pt',
        'edit_private_topic_posts',
        'may_unblind_own_poll',
        'may_report_post',
        'view_member_photos',
        'use_quick_reply',
        'view_profiles',
        'own_avatars',
        'double_post',
        'delete_account',
    );
    $CNS_FALSE_PERMISSIONS = array(
        'rename_self',
        'use_special_emoticons',
        'view_any_profile_field',
        'disable_lost_passwords',
        'close_own_topics',
        'edit_own_polls',
        'see_warnings',
        'see_ip',
        'may_choose_custom_title',
        'view_other_pt',
        'view_poll_results_before_voting',
        'moderate_private_topic',
        'member_maintenance',
        'probate_members',
        'warn_members',
        'control_usergroups',
        'multi_delete_topics',
        'show_user_browsing',
        'see_hidden_groups',
        'pt_anyone',
        'delete_private_topic_posts',
    );
}

/**
 * Uninstall Conversr
 */
function uninstall_cns()
{
    global $CNS_TRUE_PERMISSIONS, $CNS_FALSE_PERMISSIONS;

    foreach ($CNS_TRUE_PERMISSIONS as $permission) {
        delete_privilege($permission);
    }
    foreach ($CNS_FALSE_PERMISSIONS as $permission) {
        delete_privilege($permission);
    }

    $GLOBALS['FORUM_DB']->query_delete('group_category_access', array('module_the_name' => 'forums'));

    delete_value('cns_newest_member_id');
    delete_value('cns_newest_member_username');
    delete_value('cns_member_count');
    delete_value('cns_topic_count');
    delete_value('cns_post_count');

    require_code('files');
    if (!$GLOBALS['DEV_MODE']) {
        deldir_contents(get_custom_file_base() . '/uploads/cns_avatars', true);
        deldir_contents(get_custom_file_base() . '/uploads/cns_photos', true);
        deldir_contents(get_custom_file_base() . '/uploads/cns_photos_thumbs', true);
        deldir_contents(get_custom_file_base() . '/uploads/avatars', true);
        deldir_contents(get_custom_file_base() . '/uploads/photos', true);
        deldir_contents(get_custom_file_base() . '/uploads/photos_thumbs', true);
    }

    delete_attachments('cns_post');
    delete_attachments('cns_signature');

    require_code('database_action');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_emoticons');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_forum_group_access');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_custom_fields');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_member_custom_fields');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_groups');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_forum_groupings');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_forums');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_forum_intro_ip');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_forum_intro_member');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_topics');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_posts');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_polls');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_poll_answers');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_poll_votes');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_post_templates');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_warnings');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_moderator_logs');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_member_known_login_ips');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_members');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_group_members');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_read_logs');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_forum_tracking');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_topic_tracking');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_multi_moderations');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_invites');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_forum_group_access');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_special_pt_access');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_saved_warnings');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_member_cpf_perms');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_group_join_log');
    $GLOBALS['FORUM_DB']->drop_table_if_exists('f_password_history');

    $GLOBALS['FORUM_DB']->query_delete('group_privileges', array('module_the_name' => 'forums'));

    delete_privilege('exceed_post_edit_time_limit');
    delete_privilege('exceed_post_delete_time_limit');

    delete_privilege('bypass_required_cpfs');
    delete_privilege('bypass_required_cpfs_if_already_empty');
    delete_privilege('bypass_email_address');
    delete_privilege('bypass_email_address_if_already_empty');
    delete_privilege('bypass_dob');
    delete_privilege('bypass_dob_if_already_empty');
}

/**
 * Install/upgrade Conversr.
 *
 * @param  ?float $upgrade_from The version to upgrade from (null: fresh install).
 */
function install_cns($upgrade_from = null)
{
    if (cms_srv('REQUEST_METHOD') != 'POST') {
        exit(); // Needed as YSlow can load as GET's in background and cause horrible results
    }

    require_code('cns_members');
    require_code('cns_topics');
    require_code('cns_groups');
    require_code('cns_forums');
    require_lang('cns');
    require_lang('cns_config');
    require_lang('cns_special_cpf');
    require_code('cns_moderation_action');
    require_code('cns_posts_action');
    require_code('cns_members_action');
    require_code('cns_groups_action');
    require_code('cns_general_action');
    require_code('cns_forums_action');
    require_code('cns_topics_action');
    require_code('database_action');

    if (is_null($upgrade_from)) {
        uninstall_cns(); // Remove if already installed
    }

    // Upgrade code for making changes (<8 not supported) lots of LEGACY code below
    if ((is_null($upgrade_from)) || ($upgrade_from < 10.0)) {
        $GLOBALS['FORUM_DB']->create_table('f_group_join_log', array(
            'id' => '*AUTO',
            'member_id' => 'MEMBER',
            'usergroup_id' => '?AUTO_LINK',
            'join_time' => 'TIME'
        ));
        $GLOBALS['FORUM_DB']->create_index('f_group_join_log', 'member_id', array('member_id'));
        $GLOBALS['FORUM_DB']->create_index('f_group_join_log', 'usergroup_id', array('usergroup_id'));
        $GLOBALS['FORUM_DB']->create_index('f_group_join_log', 'join_time', array('join_time'));

        $GLOBALS['FORUM_DB']->create_table('f_password_history', array(
            'id' => '*AUTO',
            'p_member_id' => 'MEMBER',
            'p_hash_salted' => 'SHORT_TEXT',
            'p_salt' => 'SHORT_TEXT',
            'p_time' => 'TIME',
        ));
        $GLOBALS['FORUM_DB']->create_index('f_password_history', 'p_member_id', array('p_member_id'));
    }
    if ((!is_null($upgrade_from)) && ($upgrade_from < 10.0)) {
        delete_config_option('no_dob_ask');

        $GLOBALS['FORUM_DB']->delete_index_if_exists('f_posts', 'posts_by');

        $GLOBALS['FORUM_DB']->add_table_field('f_members', 'm_profile_views', 'UINTEGER');
        $GLOBALS['FORUM_DB']->add_table_field('f_members', 'm_total_sessions', 'UINTEGER');

        $GLOBALS['FORUM_DB']->add_auto_key('f_poll_votes');
        $GLOBALS['FORUM_DB']->add_table_field('f_poll_votes', 'pv_ip', 'IP');

        $GLOBALS['FORUM_DB']->rename_table('f_categories', 'f_forum_groupings');
        $GLOBALS['FORUM_DB']->alter_table_field('f_forums', 'f_category_id', '?AUTO_LINK', 'f_forum_grouping_id');
        $privileges = array('moderate_personal_topic' => 'moderate_private_topic', 'edit_personal_topic_posts' => 'edit_private_topic_posts');
        foreach ($privileges as $old => $new) {
            rename_privilege($old, $new);
        }
        $GLOBALS['FORUM_DB']->delete_table_field('f_members', 'm_notes');
        $GLOBALS['FORUM_DB']->delete_table_field('f_members', 'm_zone_wide');
        delete_config_option('skip_email_confirm_join');
        delete_config_option('prevent_shouting');

        // Initialise f_password_history with current data (we'll assume m_last_submit_time represents last password change, which is not true - but ok enough for early initialisation, and will scatter things quite nicely to break in the new rules gradually)
        if (php_function_allowed('set_time_limit')) {
            @set_time_limit(0);
        }
        $max = 500;
        $start = 0;
        do {
            $members = $GLOBALS['FORUM_DB']->query_select('f_members', array('id', 'm_pass_hash_salted', 'm_pass_salt', 'm_last_submit_time', 'm_join_time'), null, '', $max, $start);
            foreach ($members as $member) {
                if ($member['id'] != $GLOBALS['FORUM_DRIVER']->get_guest_id()) {
                    $GLOBALS['FORUM_DB']->query_insert('f_password_history', array(
                        'p_member_id' => $member['id'],
                        'p_hash_salted' => $member['m_pass_hash_salted'],
                        'p_salt' => $member['m_pass_salt'],
                        'p_time' => is_null($member['m_last_submit_time']) ? $member['m_join_time'] : $member['m_last_submit_time'],
                    ));
                }
            }
            $start += $max;
        } while (count($members) > 0);

        $GLOBALS['FORUM_DB']->add_table_field('f_custom_fields', 'cf_options', 'SHORT_TEXT');

        $GLOBALS['SITE_DB']->query_update('f_custom_fields', array('cf_type' => 'member'), array('cf_type' => 'user'));
        $GLOBALS['SITE_DB']->query_update('f_custom_fields', array('cf_type' => 'member_multi'), array('cf_type' => 'user_multi'));
        $GLOBALS['SITE_DB']->query_update('f_custom_fields', array('cf_type' => 'codename', 'cf_default' => 'RANDOM'), array('cf_type' => 'random'));
        $GLOBALS['SITE_DB']->query_update('f_custom_fields', array('cf_type' => 'list_multi', 'cf_options' => 'widget=vertical_checkboxes,custom_values=yes'), array('cf_type' => 'combo_multi'));
        $GLOBALS['SITE_DB']->query_update('f_custom_fields', array('cf_type' => 'list_multi'), array('cf_type' => 'multilist'));
        $GLOBALS['SITE_DB']->query_update('f_custom_fields', array('cf_type' => 'list_multi', 'cf_options' => 'widget=horizontal_checkboxes'), array('cf_type' => 'tick_multi'));
        $GLOBALS['SITE_DB']->query_update('f_custom_fields', array('cf_type' => 'list', 'cf_options' => 'widget=radio,custom_values=yes'), array('cf_type' => 'combo'));
        $GLOBALS['SITE_DB']->query_update('f_custom_fields', array('cf_type' => 'list', 'cf_options' => 'widget=radio'), array('cf_type' => 'radiolist'));
        $GLOBALS['SITE_DB']->query_update('f_custom_fields', array('cf_type' => 'integer', 'cf_default' => 'AUTO_INCREMENT'), array('cf_type' => 'auto_increment'));

        $GLOBALS['FORUM_DB']->add_table_field('f_forums', 'f_allows_anonymous_posts', 'BINARY', intval(get_option('is_on_anonymous_posts')));

        $GLOBALS['FORUM_DB']->add_table_field('f_members', 'm_auto_mark_read', 'BINARY', 1);

        $GLOBALS['SITE_DB']->query('DELETE FROM ' . get_table_prefix() . 'db_meta_indices WHERE i_name LIKE \'#mcf%\'');

        $GLOBALS['FORUM_DB']->drop_table_if_exists('f_post_history');

        rename_config_option('post_history_days', 'post_read_history_days');

        // Directory moving
        require_code('upgrade');
        $fields = array(
            'm_photo_url' => 'uploads/ocf_photos',
            'm_photo_thumb_url' => 'uploads/ocf_photos_thumbs',
            'm_avatar_url' => 'uploads/ocf_avatars',
        );
        foreach ($fields as $field => $dir) {
            $GLOBALS['FORUM_DB']->query('UPDATE ' . $GLOBALS['FORUM_DB']->get_table_prefix() . 'f_members SET ' . $field . '=REPLACE(' . $field . ',\'ocf_\',\'cns_\') WHERE ' . $field . ' LIKE \'%ocf\_%\'');
            move_folder_contents($dir, str_replace('ocf_', 'cns_', $dir));
        }
        move_folder_contents('uploads/ocf_cpf_upload', 'uploads/cns_cpf_upload');

        $GLOBALS['FORUM_DB']->query('UPDATE ' . $GLOBALS['FORUM_DB']->get_table_prefix() . 'f_emoticons SET e_theme_img_code=REPLACE(e_theme_img_code,\'ocf_\',\'cns_\') WHERE e_theme_img_code LIKE \'%ocf\_%\'');

        $GLOBALS['FORUM_DB']->query('UPDATE ' . $GLOBALS['FORUM_DB']->get_table_prefix() . 'f_groups SET g_rank_image=REPLACE(g_rank_image,\'ocf_\',\'cns_\') WHERE g_rank_image LIKE \'%ocf\_%\'');

        $GLOBALS['FORUM_DB']->query('UPDATE ' . $GLOBALS['FORUM_DB']->get_table_prefix() . 'f_topics SET t_emoticon=REPLACE(t_emoticon,\'ocf_\',\'cns_\') WHERE t_emoticon LIKE \'%ocf\_%\'');

        $GLOBALS['FORUM_DB']->change_primary_key('f_multi_moderations', array('id'));

        $GLOBALS['SITE_DB']->query_update('privilege_list', array('the_default' => 1), array('the_name' => 'double_post'));
        $GLOBALS['SITE_DB']->query_update('privilege_list', array('the_default' => 1), array('the_name' => 'delete_account'));

        add_privilege('FORUMS_AND_MEMBERS', 'delete_private_topic_posts', false, false);

        $GLOBALS['FORUM_DB']->delete_index_if_exists('f_topics', 'unread_forums');
        $GLOBALS['FORUM_DB']->create_index('f_topics', 'unread_forums', array('t_forum_id', 't_cache_last_time'));

        $GLOBALS['FORUM_DB']->delete_index_if_exists('f_posts', 'posts_since');
        $GLOBALS['FORUM_DB']->create_index('f_posts', 'posts_since', array('p_time', 'p_cache_forum_id')); // p_cache_forum_id is used to not count PT posts

        // Fix up legacy issues with CPFs that we can no longer tolerate
        $fields = $GLOBALS['FORUM_DB']->query_select('f_custom_fields', array('id', 'cf_type'));
        foreach ($fields as $field) {
            $type = $field['cf_type'];
            list($_type, $index) = get_cpf_storage_for($type);

            $id = $field['id'];

            $GLOBALS['FORUM_DB']->delete_index_if_exists('f_member_custom_fields', 'mcf' . strval($id));
            $GLOBALS['FORUM_DB']->delete_index_if_exists('f_member_custom_fields', '#mcf_ft_' . strval($id));

            if (substr(get_db_type(), 0, 5) == 'mysql') {
                $GLOBALS['SITE_DB']->query('SET sql_mode=\'\'', null, null, true); // Turn off strict mode
            }
            $GLOBALS['FORUM_DB']->alter_table_field('f_member_custom_fields', 'field_' . strval($id), $_type);

            build_cpf_indices($id, $index, $type, $_type);
        }
    }

    // If we have the forum installed to this db already, leave
    if (is_null($upgrade_from)) {
        $GLOBALS['FORUM_DB']->create_table('f_member_cpf_perms', array(
            'member_id' => '*MEMBER',
            'field_id' => '*AUTO_LINK',
            'guest_view' => 'BINARY',
            'member_view' => 'BINARY',
            'friend_view' => 'BINARY',
            'group_view' => 'SHORT_TEXT'
        ));

        $GLOBALS['FORUM_DB']->create_table('f_emoticons', array(
            'e_code' => '*ID_TEXT',
            'e_theme_img_code' => 'SHORT_TEXT',
            'e_relevance_level' => 'INTEGER', // 0=core,1=supported,2=unsupported,3=poor,4=unused
            'e_use_topics' => 'BINARY', // Whether to use it to show a topics emotion
            'e_is_special' => 'BINARY'
        ));
        $GLOBALS['FORUM_DB']->create_index('f_emoticons', 'relevantemoticons', array('e_relevance_level'));
        $GLOBALS['FORUM_DB']->create_index('f_emoticons', 'topicemos', array('e_use_topics'));

        $GLOBALS['FORUM_DB']->create_table('f_custom_fields', array(
            'id' => '*AUTO',
            'cf_locked' => 'BINARY',  // Can't be deleted
            'cf_name' => 'SHORT_TRANS',
            'cf_description' => 'LONG_TRANS',
            'cf_default' => 'LONG_TEXT',
            'cf_public_view' => 'BINARY',
            'cf_owner_view' => 'BINARY',
            'cf_owner_set' => 'BINARY',
            'cf_type' => 'ID_TEXT', // can be short_text,long_text,long_trans,integer,url,upload,picture,list,tick
            'cf_required' => 'BINARY',
            'cf_show_in_posts' => 'BINARY',
            'cf_show_in_post_previews' => 'BINARY',
            'cf_order' => 'INTEGER',
            'cf_only_group' => 'LONG_TEXT',
            'cf_encrypted' => 'BINARY',
            'cf_show_on_join_form' => 'BINARY',
            'cf_options' => 'SHORT_TEXT',
        ));

        // These don't need to be filled in. We just use default from custom field if they aren't
        $GLOBALS['FORUM_DB']->create_table('f_member_custom_fields', array(
            'mf_member_id' => '*MEMBER'
        ));

        cns_make_boiler_custom_field('about');
        cns_make_boiler_custom_field('interests');
        cns_make_boiler_custom_field('occupation');
        cns_make_boiler_custom_field('staff_notes');
        if (!addon_installed('user_mappr')) {
            cns_make_boiler_custom_field('location');
        }
        //cns_make_boiler_custom_field('im_jabber'); Old-school, although XMPP is still popular for some, so we won't remove entirely
        cns_make_boiler_custom_field('im_skype');
        cns_make_boiler_custom_field('sn_facebook');
        cns_make_boiler_custom_field('sn_google');
        cns_make_boiler_custom_field('sn_twitter');

        $GLOBALS['FORUM_DB']->create_table('f_invites', array(
            'id' => '*AUTO',
            'i_inviter' => 'MEMBER',
            'i_email_address' => 'SHORT_TEXT',
            'i_time' => 'TIME',
            'i_taken' => 'BINARY'
        ));

        $GLOBALS['FORUM_DB']->create_table('f_group_members', array(
            'gm_group_id' => '*GROUP',
            'gm_member_id' => '*MEMBER',
            'gm_validated' => 'BINARY'
        ));
        $GLOBALS['FORUM_DB']->create_index('f_group_members', 'gm_validated', array('gm_validated'));
        $GLOBALS['FORUM_DB']->create_index('f_group_members', 'gm_member_id', array('gm_member_id'));
        $GLOBALS['FORUM_DB']->create_index('f_group_members', 'gm_group_id', array('gm_group_id'));

        $GLOBALS['FORUM_DB']->create_table('f_members', array(
            'id' => '*AUTO',
            'm_username' => 'ID_TEXT',
            'm_pass_hash_salted' => 'SHORT_TEXT', // Not MD5 type because it could store different things according to password_compatibility_scheme
            'm_pass_salt' => 'SHORT_TEXT',
            'm_theme' => 'ID_TEXT', // Blank means default
            'm_avatar_url' => 'URLPATH', // Blank means no avatar
            'm_validated' => 'BINARY',
            'm_validated_email_confirm_code' => 'SHORT_TEXT',
            'm_cache_num_posts' => 'INTEGER',
            'm_cache_warnings' => 'INTEGER',
            'm_join_time' => 'TIME',
            'm_timezone_offset' => 'SHORT_TEXT',
            'm_primary_group' => 'GROUP',
            'm_last_visit_time' => 'TIME', // This field is generally kept up-to-date, while the cookie 'last_visit' refers to the previous browsing session's time
            'm_last_submit_time' => 'TIME',
            'm_signature' => 'LONG_TRANS__COMCODE',
            'm_is_perm_banned' => 'BINARY',
            'm_preview_posts' => 'BINARY',
            'm_dob_day' => '?SHORT_INTEGER',
            'm_dob_month' => '?SHORT_INTEGER',
            'm_dob_year' => '?INTEGER',
            'm_reveal_age' => 'BINARY',
            'm_email_address' => 'SHORT_TEXT',
            'm_title' => 'SHORT_TEXT', // Blank means use title
            'm_photo_url' => 'URLPATH', // Blank means no photo
            'm_photo_thumb_url' => 'URLPATH', // Blank means no photo
            'm_views_signatures' => 'BINARY',
            'm_auto_monitor_contrib_content' => 'BINARY',
            'm_language' => 'ID_TEXT',
            'm_ip_address' => 'IP',
            'm_allow_emails' => 'BINARY',
            'm_allow_emails_from_staff' => 'BINARY',
            'm_highlighted_name' => 'BINARY',
            'm_pt_allow' => 'SHORT_TEXT',
            'm_pt_rules_text' => 'LONG_TRANS__COMCODE',
            'm_max_email_attach_size_mb' => 'INTEGER',
            'm_password_change_code' => 'SHORT_TEXT',
            'm_password_compat_scheme' => 'ID_TEXT',
            'm_on_probation_until' => '?TIME',
            'm_profile_views' => 'UINTEGER',
            'm_total_sessions' => 'UINTEGER',
            'm_auto_mark_read' => 'BINARY',
        ));
        $GLOBALS['FORUM_DB']->create_index('f_members', '#search_user', array('m_username'));
        $GLOBALS['FORUM_DB']->create_index('f_members', 'user_list', array('m_username'));
        $GLOBALS['FORUM_DB']->create_index('f_members', 'menail', array('m_email_address'));
        $GLOBALS['FORUM_DB']->create_index('f_members', 'external_auth_lookup', array('m_pass_hash_salted'));
        $GLOBALS['FORUM_DB']->create_index('f_members', 'sort_post_count', array('m_cache_num_posts'));
        $GLOBALS['FORUM_DB']->create_index('f_members', 'm_join_time', array('m_join_time'));
        $GLOBALS['FORUM_DB']->create_index('f_members', 'whos_validated', array('m_validated'));
        $GLOBALS['FORUM_DB']->create_index('f_members', 'birthdays', array('m_dob_day', 'm_dob_month'));
        $GLOBALS['FORUM_DB']->create_index('f_members', 'ftjoin_msig', array('m_signature'));
        $GLOBALS['FORUM_DB']->create_index('f_members', 'primary_group', array('m_primary_group'));
        $GLOBALS['FORUM_DB']->create_index('f_members', 'avatar_url', array('m_avatar_url')); // Used for uniform avatar randomisation

        $no_use_topics = array(
            'party' => true,
            'christmas' => true,
            'offtopic' => true,
            'rockon' => true,
            'guitar' => true,
            'sinner' => true,
            'wink' => true,
            'kiss' => true,
            'nod' => true,
            'smile' => true,
            'mellow' => true,
            'whistle' => true,
            'shutup' => true,
            'cyborg' => true,
            'idea' => true,
            'boat' => true,
            'fishing' => true,
            'reallybadday' => true,
        );
        $core_emoticons = array(
            ':P' => 'cheeky',
            ":'(" => 'cry',
            ':dry:' => 'dry',
            ':$' => 'blush',
            ';)' => 'wink',
            'O_o' => 'blink',
            ':wub:' => 'wub',
            ':cool:' => 'cool',
            ':lol:' => 'lol',
            ':(' => 'sad',
            ':)' => 'smile',
            ':thumbs:' => 'thumbs',
            ':|' => 'mellow',
            ':ninja:' => 'ph34r',
            ':o' => 'shocked'
        );
        $supported_emoticons = array(
            ':offtopic:' => 'offtopic', // Larger than normal, so don't put in core set
            ':rolleyes:' => 'rolleyes',
            ':D' => 'grin',
            '^_^' => 'glee',
            '(K)' => 'kiss',
            ':S' => 'confused',
            ':@' => 'angry',
            ':shake:' => 'shake',
            ':hand:' => 'hand',
            ':drool:' => 'drool',
            ':devil:' => 'devil',
            ':party:' => 'party',
            ':constipated:' => 'constipated',
            ':depressed:' => 'depressed',
            ':zzz:' => 'zzz',
            ':whistle:' => 'whistle',
            ':upsidedown:' => 'upsidedown',
            ':sick:' => 'sick',
            ':shutup:' => 'shutup',
            ':sarcy:' => 'sarcy',
            ':puppyeyes:' => 'puppyeyes',
            ':nod:' => 'nod',
            ':nerd:' => 'nerd',
            ':king:' => 'king',
            ':birthday:' => 'birthday',
            ':cyborg:' => 'cyborg',
            ':hippie:' => 'hippie',
            ':ninja2:' => 'ninja2',
            ':rockon:' => 'rockon',
            ':sinner:' => 'sinner',
            ':guitar:' => 'guitar',
            ':angel:' => 'angel',
            ':cowboy:' => 'cowboy',
            ':fight:' => 'fight',
            ':goodbye:' => 'goodbye',
            ':idea:' => 'idea',
            ':boat:' => 'boat',
            ':fishing:' => 'fishing',
            ':reallybadday:' => 'reallybadday',
        );
        $unused_emoticons = array(
            ':christmas:' => 'christmas'
        );
        foreach ($core_emoticons as $a => $b) {
            cns_make_emoticon($a, 'cns_emoticons/' . $b, 0, array_key_exists($b, $no_use_topics) ? 0 : 1);
        }
        foreach ($supported_emoticons as $a => $b) {
            cns_make_emoticon($a, 'cns_emoticons/' . $b, 1, array_key_exists($b, $no_use_topics) ? 0 : 1);
        }
        foreach ($unused_emoticons as $a => $b) {
            cns_make_emoticon($a, 'cns_emoticons/' . $b, 1, array_key_exists($b, $no_use_topics) ? 0 : 1);
        }

        $GLOBALS['FORUM_DB']->create_table('f_groups', array(
            'id' => '*AUTO',
            'g_name' => 'SHORT_TRANS',
            'g_is_default' => 'BINARY',
            'g_is_presented_at_install' => 'BINARY',
            'g_is_super_admin' => 'BINARY',
            'g_is_super_moderator' => 'BINARY',
            'g_group_leader' => '?MEMBER',
            'g_title' => 'SHORT_TRANS',
            'g_promotion_target' => '?GROUP',
            'g_promotion_threshold' => '?INTEGER',
            'g_flood_control_submit_secs' => 'INTEGER',
            'g_flood_control_access_secs' => 'INTEGER',
            'g_gift_points_base' => 'INTEGER',
            'g_gift_points_per_day' => 'INTEGER',
            'g_max_daily_upload_mb' => 'INTEGER',
            'g_max_attachments_per_post' => 'INTEGER',
            'g_max_avatar_width' => 'INTEGER',
            'g_max_avatar_height' => 'INTEGER',
            'g_max_post_length_comcode' => 'INTEGER',
            'g_max_sig_length_comcode' => 'INTEGER',
            'g_enquire_on_new_ips' => 'BINARY',
            'g_rank_image' => 'ID_TEXT',
            'g_hidden' => 'BINARY',
            'g_order' => 'INTEGER',
            'g_rank_image_pri_only' => 'BINARY',
            'g_open_membership' => 'BINARY',
            'g_is_private_club' => 'BINARY',
        ));
        $GLOBALS['FORUM_DB']->create_index('f_groups', 'ftjoin_gname', array('g_name'));
        $GLOBALS['FORUM_DB']->create_index('f_groups', 'ftjoin_gtitle', array('g_title'));
        $GLOBALS['FORUM_DB']->create_index('f_groups', 'is_private_club', array('g_is_private_club'));
        $GLOBALS['FORUM_DB']->create_index('f_groups', 'is_super_admin', array('g_is_super_admin'));
        $GLOBALS['FORUM_DB']->create_index('f_groups', 'is_super_moderator', array('g_is_super_moderator'));
        $GLOBALS['FORUM_DB']->create_index('f_groups', 'is_default', array('g_is_default'));
        $GLOBALS['FORUM_DB']->create_index('f_groups', 'hidden', array('g_hidden'));
        $GLOBALS['FORUM_DB']->create_index('f_groups', 'is_presented_at_install', array('g_is_presented_at_install'));
        $GLOBALS['FORUM_DB']->create_index('f_groups', 'gorder', array('g_order', 'id'));

        // For the_zone_access table
        require_code('zones2');
        reinstall_module('adminzone', 'admin_permissions');

        // Make guest
        $guest_group = cns_make_group(do_lang('GUESTS'), 0, 0, 0, do_lang('DESCRIPTION_GUESTS'));
        // Make admin
        $administrator_group = cns_make_group(do_lang('ADMINISTRATORS'), 0, 1, 0, do_lang('DESCRIPTION_ADMINISTRATORS'), 'cns_rank_images/admin', null, null, null, 0);
        // Make mod
        $super_moderator_group = cns_make_group(do_lang('SUPER_MODERATORS'), 0, 0, 1, do_lang('DESCRIPTION_SUPER_MODERATORS'), 'cns_rank_images/mod', null, null, null, 0);
        // Make supermember
        $super_member_group = cns_make_group(do_lang('SUPER_MEMBERS'), 0, 0, 0, do_lang('DESCRIPTION_SUPER_MEMBERS'), '', null, null, null, 0);
        // Make member
        $member_group_4 = cns_make_group(do_lang('DEFAULT_RANK_4'), 0, 0, 0, do_lang('DESCRIPTION_MEMBERS'), 'cns_rank_images/4');
        $member_group_3 = cns_make_group(do_lang('DEFAULT_RANK_3'), 0, 0, 0, do_lang('DESCRIPTION_MEMBERS'), 'cns_rank_images/3', $member_group_4, 10000);
        $member_group_2 = cns_make_group(do_lang('DEFAULT_RANK_2'), 0, 0, 0, do_lang('DESCRIPTION_MEMBERS'), 'cns_rank_images/2', $member_group_3, 2500);
        $member_group_1 = cns_make_group(do_lang('DEFAULT_RANK_1'), 0, 0, 0, do_lang('DESCRIPTION_MEMBERS'), 'cns_rank_images/1', $member_group_2, 400);
        $member_group_0 = cns_make_group(do_lang('DEFAULT_RANK_0'), 0, 0, 0, do_lang('DESCRIPTION_MEMBERS'), 'cns_rank_images/0', $member_group_1, 100); // Not default because primary is always defaulted to this one
        // Make probation
        $probation_group = cns_make_group(do_lang('PROBATION'), 0, 0, 0, do_lang('DESCRIPTION_PROBATION'), '', null, null, null, 0);

        $GLOBALS['FORUM_DB']->create_table('f_forum_groupings', array(
            'id' => '*AUTO',
            'c_title' => 'SHORT_TEXT',
            'c_description' => 'LONG_TEXT',
            'c_expanded_by_default' => 'BINARY'
        ));
        $forum_grouping_id = cns_make_forum_grouping(do_lang('DEFAULT_GROUPING_TITLE'), '');
        $forum_grouping_id_staff = cns_make_forum_grouping(do_lang('STAFF'), '');

        $GLOBALS['FORUM_DB']->create_table('f_forums', array(
            'id' => '*AUTO',
            'f_name' => 'SHORT_TEXT',
            'f_description' => 'LONG_TRANS__COMCODE',
            'f_forum_grouping_id' => '?AUTO_LINK', // Categories can exist on multiple forum levels and positions - wherever a forum exists, the forum grouping it uses exists too (but not forums in the forum grouping which aren't at level and position)
            'f_parent_forum' => '?AUTO_LINK',
            'f_position' => 'INTEGER', // might have been called 'f_order' => 'INTEGER' (consistent with other table's ordering fields) if we had not used f_order as a text field to determine the automatic ordering type
            'f_order_sub_alpha' => 'BINARY',
            'f_post_count_increment' => 'BINARY',
            'f_intro_question' => 'LONG_TRANS__COMCODE',
            'f_intro_answer' => 'SHORT_TEXT',    // Comcode
            'f_cache_num_topics' => 'INTEGER',
            'f_cache_num_posts' => 'INTEGER',
            'f_cache_last_topic_id' => '?AUTO_LINK',
            'f_cache_last_title' => 'SHORT_TEXT',
            'f_cache_last_time' => '?TIME',
            'f_cache_last_username' => 'SHORT_TEXT',
            'f_cache_last_member_id' => '?MEMBER',
            'f_cache_last_forum_id' => '?AUTO_LINK',
            'f_redirection' => 'SHORT_TEXT',
            'f_order' => 'ID_TEXT',
            'f_is_threaded' => 'BINARY',
            'f_allows_anonymous_posts' => 'BINARY',
        ));
        $GLOBALS['FORUM_DB']->create_index('f_forums', 'cache_num_posts', array('f_cache_num_posts')); // Used to find active forums
        $GLOBALS['FORUM_DB']->create_index('f_forums', 'subforum_parenting', array('f_parent_forum'));
        $GLOBALS['FORUM_DB']->create_index('f_forums', 'findnamedforum', array('f_name'));
        $GLOBALS['FORUM_DB']->create_index('f_forums', 'f_position', array('f_position'));
        $typical_access = array($guest_group => 4, $administrator_group => 5, $super_moderator_group => 5, $probation_group => 2, $super_member_group => 4, $member_group_0 => 4, $member_group_1 => 4, $member_group_2 => 4, $member_group_3 => 4, $member_group_4 => 4);
        $staff_post_access = array($guest_group => 1, $administrator_group => 5, $super_moderator_group => 5, $probation_group => 1, $super_member_group => 2, $member_group_0 => 1, $member_group_1 => 1, $member_group_2 => 1, $member_group_3 => 1, $member_group_4 => 1);
        $staff_access = array($administrator_group => 5, $super_moderator_group => 5);
        $root_forum = cns_make_forum(do_lang('ROOT_FORUM'), '', null, $staff_post_access, null);
        cns_make_forum(do_lang('DEFAULT_FORUM_TITLE'), '', $forum_grouping_id, $typical_access, $root_forum);
        cns_make_forum(do_lang('REPORTED_POSTS_FORUM'), '', $forum_grouping_id_staff, $staff_access, $root_forum);
        $trash_forum_id = cns_make_forum(do_lang('TRASH'), '', $forum_grouping_id_staff, $staff_access, $root_forum);
        cns_make_forum(do_lang('COMMENT_FORUM_NAME'), '', $forum_grouping_id, $typical_access, $root_forum, 1, 1, 0, '', '', '', 'last_post', 1);
        $staff_forum_id = cns_make_forum(do_lang('STAFF'), '', $forum_grouping_id_staff, $staff_access, $root_forum);

        $GLOBALS['FORUM_DB']->create_table('f_topics', array(
            'id' => '*AUTO',
            't_pinned' => 'BINARY',
            't_sunk' => 'BINARY',
            't_cascading' => 'BINARY', // Cascades to deeper forums, as an announcement
            't_forum_id' => '?AUTO_LINK', // Null if it's a Private Topic
            't_pt_from' => '?MEMBER',
            't_pt_to' => '?MEMBER',
            't_pt_from_category' => 'SHORT_TEXT',
            't_pt_to_category' => 'SHORT_TEXT',
            't_description' => 'SHORT_TEXT',
            't_description_link' => 'SHORT_TEXT',
            't_emoticon' => 'SHORT_TEXT',
            't_num_views' => 'INTEGER',
            't_validated' => 'BINARY',
            't_is_open' => 'BINARY',
            't_poll_id' => '?AUTO_LINK',
            't_cache_first_post_id' => '?AUTO_LINK',
            't_cache_first_time' => '?TIME',
            't_cache_first_title' => 'SHORT_TEXT',
            't_cache_first_post' => '?LONG_TRANS__COMCODE', // Careful, can't use this if !multi_lang_content()
            't_cache_first_username' => 'ID_TEXT',
            't_cache_first_member_id' => '?MEMBER',
            't_cache_last_post_id' => '?AUTO_LINK',
            't_cache_last_time' => '?TIME',
            't_cache_last_title' => 'SHORT_TEXT',
            't_cache_last_username' => 'ID_TEXT',
            't_cache_last_member_id' => '?MEMBER',
            't_cache_num_posts' => 'INTEGER',
        ));
        $GLOBALS['FORUM_DB']->create_index('f_topics', 't_num_views', array('t_num_views'));
        $GLOBALS['FORUM_DB']->create_index('f_topics', 't_pt_to', array('t_pt_to'));
        $GLOBALS['FORUM_DB']->create_index('f_topics', 't_pt_from', array('t_pt_from'));
        $GLOBALS['FORUM_DB']->create_index('f_topics', 't_validated', array('t_validated'));
        $GLOBALS['FORUM_DB']->create_index('f_topics', 'in_forum', array('t_forum_id'));
        $GLOBALS['FORUM_DB']->create_index('f_topics', 'topic_order_time', array('t_cache_last_time'));
        $GLOBALS['FORUM_DB']->create_index('f_topics', 'topic_order_time_2', array('t_cache_first_time'));
        $GLOBALS['FORUM_DB']->create_index('f_topics', '#t_description', array('t_description'));
        $GLOBALS['FORUM_DB']->create_index('f_topics', 'descriptionsearch', array('t_description'));
        $GLOBALS['FORUM_DB']->create_index('f_topics', 'forumlayer', array('t_cache_first_title'));
        $GLOBALS['FORUM_DB']->create_index('f_topics', 't_cascading', array('t_cascading'));
        $GLOBALS['FORUM_DB']->create_index('f_topics', 't_cascading_or_forum', array('t_cascading', 't_forum_id'));
        $GLOBALS['FORUM_DB']->create_index('f_topics', 'topic_order', array('t_cascading', 't_pinned', 't_cache_last_time')); // Ordering for forumview, is picked up over topic_order_3 for just the ordering bit (it seems)
        $GLOBALS['FORUM_DB']->create_index('f_topics', 'topic_order_2', array('t_forum_id', 't_cascading', 't_pinned', 't_sunk', 't_cache_last_time')); // Total index for forumview, including ordering. Doesn't work on current MySQL.
        $GLOBALS['FORUM_DB']->create_index('f_topics', 'topic_order_3', array('t_forum_id', 't_cascading', 't_pinned', 't_cache_last_time')); // Total index for forumview, including ordering. Works if disable_sunk is turned on.
        $GLOBALS['FORUM_DB']->create_index('f_topics', 'ownedtopics', array('t_cache_first_member_id'));
        $GLOBALS['FORUM_DB']->create_index('f_topics', 'unread_forums', array('t_forum_id', 't_cache_last_time'));

        // Welcome topic
        $topic_id = cns_make_topic($staff_forum_id, '', '', 1, 1, 0, 0, 0, null, null, false);

        $GLOBALS['FORUM_DB']->create_table('f_posts', array(
            'id' => '*AUTO',
            'p_title' => 'SHORT_TEXT',
            'p_post' => 'LONG_TRANS__COMCODE',
            'p_ip_address' => 'IP',
            'p_time' => 'TIME',
            'p_poster' => 'MEMBER',
            'p_intended_solely_for' => '?MEMBER',
            'p_poster_name_if_guest' => 'ID_TEXT',
            'p_validated' => 'BINARY',
            'p_topic_id' => 'AUTO_LINK',
            'p_cache_forum_id' => '?AUTO_LINK', // Null if for a PT
            'p_last_edit_time' => '?TIME',
            'p_last_edit_by' => '?MEMBER',
            'p_is_emphasised' => 'BINARY',
            'p_skip_sig' => 'BINARY',
            'p_parent_id' => '?AUTO_LINK'
        ));
        $GLOBALS['FORUM_DB']->create_index('f_posts', 'p_validated', array('p_validated'));
        $GLOBALS['FORUM_DB']->create_index('f_posts', 'in_topic', array('p_topic_id', 'p_time', 'id'));
        $GLOBALS['FORUM_DB']->create_index('f_posts', 'post_order_time', array('p_time', 'id'));
        $GLOBALS['FORUM_DB']->create_index('f_posts', 'posts_since', array('p_time', 'p_cache_forum_id')); // p_cache_forum_id is used to not count PT posts
        $GLOBALS['FORUM_DB']->create_index('f_posts', 'p_last_edit_time', array('p_last_edit_time'));
        $GLOBALS['FORUM_DB']->create_index('f_posts', 'find_pp', array('p_intended_solely_for'));
        $GLOBALS['FORUM_DB']->create_index('f_posts', 'search_join', array('p_post'));
        $GLOBALS['FORUM_DB']->create_index('f_posts', 'postsinforum', array('p_cache_forum_id'));
        $GLOBALS['FORUM_DB']->create_index('f_posts', 'deletebyip', array('p_ip_address'));

        $GLOBALS['FORUM_DB']->create_table('f_special_pt_access', array(
            's_member_id' => '*MEMBER',
            's_topic_id' => '*AUTO_LINK',
        ));

        $GLOBALS['FORUM_DB']->create_table('f_saved_warnings', array(
            's_title' => '*SHORT_TEXT',
            's_explanation' => 'LONG_TEXT',
            's_message' => 'LONG_TEXT',
        ), false, false, true);

        $GLOBALS['FORUM_DB']->create_table('f_forum_intro_ip', array(
            'i_forum_id' => '*AUTO_LINK',
            'i_ip' => '*IP'
        ));

        $GLOBALS['FORUM_DB']->create_table('f_forum_intro_member', array(
            'i_forum_id' => '*AUTO_LINK',
            'i_member_id' => '*MEMBER'
        ));

        $GLOBALS['FORUM_DB']->create_table('f_post_templates', array(
            'id' => '*AUTO',
            't_title' => 'SHORT_TEXT',
            't_text' => 'LONG_TEXT',
            't_forum_multi_code' => 'SHORT_TEXT',
            't_use_default_forums' => 'BINARY'
        ));
        if (addon_installed('cns_post_templates')) {
            require_lang('cns_post_templates');
            cns_make_post_template(do_lang('DEFAULT_POST_TEMPLATE_bug_title'), do_lang('DEFAULT_POST_TEMPLATE_bug_text'), '', 0);
            cns_make_post_template(do_lang('DEFAULT_POST_TEMPLATE_task_title'), do_lang('DEFAULT_POST_TEMPLATE_task_text'), '', 0);
            cns_make_post_template(do_lang('DEFAULT_POST_TEMPLATE_fault_title'), do_lang('DEFAULT_POST_TEMPLATE_fault_text'), '', 0);
        }

        $GLOBALS['FORUM_DB']->create_index('f_posts', '#p_title', array('p_title'));

        $GLOBALS['FORUM_DB']->create_table('f_polls', array(
            'id' => '*AUTO',
            'po_question' => 'SHORT_TEXT',
            'po_cache_total_votes' => 'INTEGER',
            'po_is_private' => 'BINARY',
            'po_is_open' => 'BINARY',
            'po_minimum_selections' => 'INTEGER',
            'po_maximum_selections' => 'INTEGER',
            'po_requires_reply' => 'BINARY'
        ));

        $GLOBALS['FORUM_DB']->create_table('f_poll_answers', array(
            'id' => '*AUTO',
            'pa_poll_id' => 'AUTO_LINK',
            'pa_answer' => 'SHORT_TEXT',
            'pa_cache_num_votes' => 'INTEGER'
        ));

        $GLOBALS['FORUM_DB']->create_table('f_poll_votes', array(
            'id' => '*AUTO',
            'pv_poll_id' => 'AUTO_LINK',
            'pv_member_id' => 'MEMBER',
            'pv_answer_id' => 'AUTO_LINK', // -1 means "forfeited". We'd use null, but we aren't allowed null fragments in keys
            'pv_ip' => 'IP'
        ));

        $GLOBALS['FORUM_DB']->create_table('f_multi_moderations', array(
            'id' => '*AUTO',
            'mm_name' => 'SHORT_TRANS',
            'mm_post_text' => 'LONG_TEXT',    // Comcode
            'mm_move_to' => '?AUTO_LINK',
            'mm_pin_state' => '?BINARY',
            'mm_sink_state' => '?BINARY',
            'mm_open_state' => '?BINARY',
            'mm_forum_multi_code' => 'SHORT_TEXT',
            'mm_title_suffix' => 'SHORT_TEXT'
        ));
        cns_make_multi_moderation(do_lang('TRASH_VERB'), '', $trash_forum_id, 0, 0, 0);

        $GLOBALS['FORUM_DB']->create_table('f_warnings', array(
            'id' => '*AUTO',
            'w_member_id' => 'MEMBER',
            'w_time' => 'TIME',
            'w_explanation' => 'LONG_TEXT',
            'w_by' => 'MEMBER',
            'w_is_warning' => 'BINARY',
            'p_silence_from_topic' => '?AUTO_LINK',
            'p_silence_from_forum' => '?AUTO_LINK',
            'p_probation' => 'INTEGER',
            'p_banned_ip' => 'IP',
            'p_charged_points' => 'INTEGER',
            'p_banned_member' => 'BINARY',
            'p_changed_usergroup_from' => '?GROUP',
        ));
        $GLOBALS['FORUM_DB']->create_index('f_warnings', 'warningsmemberid', array('w_member_id'));

        $GLOBALS['FORUM_DB']->create_table('f_moderator_logs', array(
            'id' => '*AUTO',
            'l_the_type' => 'ID_TEXT', // Language string ID
            'l_param_a' => 'SHORT_TEXT',
            'l_param_b' => 'SHORT_TEXT',
            'l_date_and_time' => 'TIME',
            'l_reason' => 'LONG_TEXT',
            'l_by' => 'MEMBER'
        ));

        $GLOBALS['FORUM_DB']->create_table('f_member_known_login_ips', array(
            'i_member_id' => '*MEMBER',
            'i_ip' => '*IP',
            'i_val_code' => 'SHORT_TEXT'
        ));

        // NB: post_param_string's will return default's if Conversr is being installed but not used yet (e.g. IPB forum driver chosen at installation)
        // Make guest
        cns_make_member(do_lang('GUEST'), '', '', null, null, null, null, array(), null, $guest_group, 1, time(), time(), '', null, '', 0, 1, 1, '', '', '', 1, 0, '', 1, 1, null, '', false);
        // Make admin user
        cns_make_member(post_param_string('admin_username', 'admin'), post_param_string('cns_admin_password', 'admin'), '', null, null, null, null, array(), null, $administrator_group, 1, time(), time(), '', 'themes/default/images/cns_default_avatars/default_set/cool_flare.png', '', 0, 0, 1, '', '', '', 1, 1, '', 1, 1, null, '', false);
        // Make test user
        cns_make_member('test', post_param_string('cns_admin_password', 'admin'), '', null, null, null, null, array(), null, $member_group_0, 1, time(), time(), '', null, '', 0, 0, 1, '', '', '', 1, 0, '', 1, 1, null, '', false);

        $GLOBALS['FORUM_DB']->create_table('f_read_logs', array(
            'l_member_id' => '*MEMBER',
            'l_topic_id' => '*AUTO_LINK',
            'l_time' => 'TIME'
        ));
        $GLOBALS['FORUM_DB']->create_index('f_read_logs', 'erase_old_read_logs', array('l_time'));

        cns_make_post($topic_id, do_lang('DEFAULT_POST_TITLE'), do_lang('DEFAULT_POST_CONTENT'), 0, true, 1, 0, do_lang('SYSTEM'), '127.0.0.1', time(), $GLOBALS['CNS_DRIVER']->get_guest_id(), null, null, null, false, true);

        // Add privileges
        global $CNS_TRUE_PERMISSIONS, $CNS_FALSE_PERMISSIONS;
        foreach ($CNS_TRUE_PERMISSIONS as $permission) {
            add_privilege('FORUMS_AND_MEMBERS', $permission, true);
        }
        foreach ($CNS_FALSE_PERMISSIONS as $permission) {
            add_privilege('FORUMS_AND_MEMBERS', $permission, false, ($permission == 'view_other_pt'));
        }
    }

    if ((is_null($upgrade_from)) || ($upgrade_from < 10.0)) {
        $GLOBALS['FORUM_DB']->create_index('f_members', 'last_visit_time', array('m_dob_month', 'm_dob_day', 'm_last_visit_time'));
        $GLOBALS['FORUM_DB']->create_index('f_posts', 'posts_by_in_forum', array('p_poster', 'p_cache_forum_id')); // Used for searching by member, filtered by forum access
        $GLOBALS['FORUM_DB']->create_index('f_posts', 'posts_by_in_topic', array('p_poster', 'p_topic_id')); // Used to help on some joins / complex queries
        $GLOBALS['FORUM_DB']->create_index('f_posts', 'posts_by', array('p_poster', 'p_time'));
        $GLOBALS['FORUM_DB']->create_index('f_topics', 't_cache_num_posts', array('t_cache_num_posts'));
        $GLOBALS['FORUM_DB']->create_index('f_posts', 'in_topic_change_order', array('p_topic_id', 'p_last_edit_time', 'p_time', 'id'));
        $GLOBALS['FORUM_DB']->create_index('f_topics', 't_cache_last_member_id', array('t_cache_last_member_id'));
        $GLOBALS['FORUM_DB']->create_index('f_topics', 't_cache_first_post_id', array('t_cache_first_post_id'));
        $GLOBALS['FORUM_DB']->create_index('f_topics', 't_cache_last_post_id', array('t_cache_last_post_id'));

        $GLOBALS['FORUM_DB']->create_index('f_groups', '#groups_search__combined', array('g_name', 'g_title'));
        $GLOBALS['FORUM_DB']->create_index('f_posts', '#posts_search__combined', array('p_post', 'p_title'));

        // Has to be done after f_groups is added
        add_privilege('FORUMS_AND_MEMBERS', 'exceed_post_edit_time_limit', true);
        add_privilege('FORUMS_AND_MEMBERS', 'exceed_post_delete_time_limit', true);
        add_privilege('FORUMS_AND_MEMBERS', 'bypass_required_cpfs');
        add_privilege('FORUMS_AND_MEMBERS', 'bypass_required_cpfs_if_already_empty');
        add_privilege('FORUMS_AND_MEMBERS', 'bypass_email_address');
        add_privilege('FORUMS_AND_MEMBERS', 'bypass_email_address_if_already_empty');
        add_privilege('FORUMS_AND_MEMBERS', 'bypass_dob');
        add_privilege('FORUMS_AND_MEMBERS', 'bypass_dob_if_already_empty');
    }
}
