<?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    import
 */

/**
 * Standard code module initialisation function.
 *
 * @ignore
 */
function init__hooks__modules__admin_import__phpbb3()
{
    global $TOPIC_FORUM_CACHE;
    $TOPIC_FORUM_CACHE = array();

    global $STRICT_FILE;
    $STRICT_FILE = false; // Disable this for a quicker import that is quite liable to go wrong if you don't have the files in the right place

    global $OLD_BASE_URL;
    $OLD_BASE_URL = null;

    // Profile Field Types
    if (!defined('FIELD_INT')) {
        define('FIELD_INT', 1);
        define('FIELD_STRING', 2);
        define('FIELD_TEXT', 3);
        define('FIELD_BOOL', 4);
        define('FIELD_DROPDOWN', 5);
        define('FIELD_DATE', 6);
    }
}

/**
 * Forum Driver.
 */
class Hook_phpbb3
{
    /**
     * Standard importer hook info function.
     *
     * @return ?array Importer handling details, including lists of all the import types covered (import types are not necessarily the same as actual tables) (null: importer is disabled).
     */
    public function info()
    {
        $info = array();
        $info['supports_advanced_import'] = false;
        $info['product'] = 'phpBB 3.0.x';
        $info['prefix'] = 'phpbb_';
        $info['import'] = array(
            'custom_comcode',
            'cns_groups',
            'cns_custom_profile_fields',
            'cns_members',
            'cns_member_files',
            'cns_forums',
            'cns_topics',
            'attachments',
            'cns_posts',
            'cns_polls_and_votes',
            //'notifications',  Actually this is read tracking, not for notifications
            'cns_private_topics',
            'cns_warnings',
            'wordfilter',
            'bookmarks',
            'config',
            'ip_bans',
            'friends',
            'reported_posts_forum',
        );
        $info['dependencies'] = array( // This dependency tree is overdefined, but I wanted to make it clear what depends on what, rather than having a simplified version
                                       'attachments' => array('cns_members'),
                                       'cns_warnings' => array('cns_members', 'cns_posts'),
                                       'cns_members' => array('cns_groups', 'cns_custom_profile_fields'),
                                       'cns_member_files' => array('cns_members'),
                                       'cns_forums' => array('cns_members', 'cns_groups'),
                                       'cns_custom_profile_fields' => array('cns_groups'),
                                       'cns_topics' => array('cns_forums', 'cns_members'),
                                       'cns_polls_and_votes' => array('cns_topics', 'cns_members'),
                                       'cns_posts' => array('cns_topics', 'cns_members', 'attachments'),
                                       'notifications' => array('cns_topics', 'cns_members'),
                                       'cns_private_topics' => array('cns_members', 'attachments'),
                                       'friends' => array('cns_members'),
                                       'bookmarks' => array('cns_members', 'cns_topics'),
                                       'reported_posts_forum' => array('cns_members', 'cns_topics', 'cns_posts'),
        );
        $_cleanup_url = build_url(array('page' => 'admin_cleanup'), get_module_zone('admin_cleanup'));
        $cleanup_url = $_cleanup_url->evaluate();
        $info['message'] = (get_param_string('type', 'browse') != 'import' && get_param_string('type', 'browse') != 'hook') ? new Tempcode() : do_lang_tempcode('FORUM_CACHE_CLEAR', escape_html($cleanup_url));

        return $info;
    }

    /**
     * Probe a file path for DB access details.
     *
     * @param  string $file_base The probe path
     * @return array A quartet of the details (db_name, db_user, db_pass, table_prefix)
     */
    public function probe_db_access($file_base)
    {
        $dbname = '';
        $dbuser = '';
        $dbpasswd = '';
        $dbhost = '';
        $table_prefix = '';
        if (!file_exists($file_base . '/config.php')) {
            warn_exit(do_lang_tempcode('BAD_IMPORT_PATH', escape_html('config.php')));
        }
        require($file_base . '/config.php');

        return array($dbname, $dbuser, $dbpasswd, $table_prefix, $dbhost);
    }

    /**
     * Standard import function.
     *
     * @param  object $db The DB connection to import from
     * @param  string $table_prefix The table prefix the target prefix is using
     * @param  PATH $file_base The base directory we are importing from
     */
    public function import_config($db, $table_prefix, $file_base)
    {
        $config_remapping = array(
            'require_activation' => 'require_new_member_validation',
            'board_disable' => 'site_closed',
            'sitename' => 'site_name',
            'site_desc' => 'site_scope',
            'posts_per_page' => 'forum_posts_per_page',
            'topics_per_page' => 'forum_topics_per_page',
            'board_email' => 'staff_address',
            'gzip_compress' => 'gzip_output',
            'smtp_delivery' => 'smtp_sockets_use',
            'smtp_host' => 'smtp_sockets_host',
            'smtp_username' => 'smtp_sockets_username',
            'smtp_password' => 'smtp_sockets_password',
        );
        if (addon_installed('ldap')) {
            $config_remapping += array(
                'ldap_server' => 'ldap_hostname',
                'ldap_user' => 'ldap_bind_rdn',
                'ldap_password' => 'ldap_bind_password',
            );
        }

        $rows = $db->query('SELECT * FROM ' . $table_prefix . 'config');
        $PROBED_FORUM_CONFIG = array();
        foreach ($rows as $row) {
            if ($row['config_name'] == 'require_activation') {
                if ($row['config_value'] == '2') {
                    $row['config_value'] = '1';
                } else {
                    $row['config_value'] = '0';
                }
            }

            if (array_key_exists($row['config_name'], $config_remapping)) {
                $value = $row['config_value'];
                $remapping = $config_remapping[$row['config_name']];
                if ($remapping[0] == '!') {
                    $remapping = substr($remapping, 1);
                    $value = 1 - $value;
                }
                set_option($remapping, $value);
            }
            $PROBED_FORUM_CONFIG[$row['config_name']] = $row['config_value'];
        }

        set_value('timezone', $PROBED_FORUM_CONFIG['board_timezone']);

        set_option('one_per_email_address', strval(1 - intval($PROBED_FORUM_CONFIG['allow_emailreuse'])));

        // Now some usergroup options
        $groups = $GLOBALS['CNS_DRIVER']->get_usergroup_list();
        foreach (array_keys($groups) as $id) {
            if ($GLOBALS['CNS_DRIVER']->is_super_admin($id)) {
                continue;
            }

            $GLOBALS['FORUM_DB']->query_update('f_groups', array('g_max_avatar_width' => $PROBED_FORUM_CONFIG['avatar_max_width'], 'g_max_avatar_height' => $PROBED_FORUM_CONFIG['avatar_max_height'], 'g_max_sig_length_comcode' => $PROBED_FORUM_CONFIG['max_sig_chars']), array('id' => $id), '', 1);

            set_privilege($id, 'own_avatars', $PROBED_FORUM_CONFIG['allow_avatar_upload'] == '1');
            set_privilege($id, 'rename_self', $PROBED_FORUM_CONFIG['allow_namechange'] == '1');
            set_privilege($id, 'bypass_wordfilter', $PROBED_FORUM_CONFIG['allow_namechange'] == '1');
        }
    }

    /**
     * Standard import function.
     *
     * @param  object $db The DB connection to import from
     * @param  string $table_prefix The table prefix the target prefix is using
     * @param  PATH $file_base The base directory we are importing from
     */
    public function import_attachments($db, $table_prefix, $file_base)
    {
        $row_start = 0;
        $rows = array();
        do {
            $rows = $db->query('SELECT * FROM ' . $table_prefix . 'attachments ORDER BY attach_id', 200, $row_start);
            foreach ($rows as $row) {
                if (import_check_if_imported('attachment', strval($row['attach_id']))) {
                    continue;
                }

                $row['poster_id'] = import_id_remap_get('member', strval($row['poster_id']), true);
                if (is_null($row['poster_id'])) {
                    $row['poster_id'] = $GLOBALS['FORUM_DRIVER']->get_guest_id();
                }

                $row_copy = array(
                    'a_member_id' => $row['poster_id'],
                    'a_file_size' => $row['filesize'],
                    'a_url' => 'uploads/attachments/' . urlencode($row['physical_filename']),
                    'a_description' => $row['attach_comment'],
                    'a_thumb_url' => ($row['thumbnail'] == 1) ? ('uploads/attachments_thumbs/' . urlencode($row['physical_filename'] . '.png')) : '',
                    'a_original_filename' => html_entity_decode(urldecode($row['real_filename']), ENT_QUOTES),
                    'a_num_downloads' => $row['download_count'],
                    'a_last_downloaded_time' => null,
                    'a_add_time' => $row['filetime'],
                );
                $id_new = $GLOBALS['FORUM_DB']->query_insert('attachments', $row_copy, true);

                @rename($file_base . '/files/' . $row['physical_filename'], get_custom_file_base() . '/uploads/attachments/' . $row['physical_filename']);
                sync_file(get_custom_file_base() . '/uploads/attachments/' . $row['physical_filename']);

                import_id_remap_put('attachment', strval($row['attach_id']), $id_new);
            }
            $row_start += 200;
        } while (count($rows) > 0);
    }

    /**
     * Standard import function.
     *
     * @param  object $db The DB connection to import from
     * @param  string $table_prefix The table prefix the target prefix is using
     * @param  PATH $file_base The base directory we are importing from
     */
    public function import_cns_groups($db, $table_prefix, $file_base)
    {
        $rows = $db->query('SELECT * FROM ' . $table_prefix . 'config');
        $PROBED_FORUM_CONFIG = array();
        foreach ($rows as $row) {
            $key = $row['config_name'];
            $val = $row['config_value'];
            $PROBED_FORUM_CONFIG[$key] = $val;
        }

        $rows = $db->query('SELECT g.*,u.user_id FROM ' . $table_prefix . 'groups g LEFT JOIN ' . $table_prefix . 'user_group u ON u.group_id=g.group_id AND u.group_leader=1 WHERE u.group_leader=1 OR u.group_leader IS NULL ORDER BY group_id');
        foreach ($rows as $row) {
            if (import_check_if_imported('group', strval($row['group_id']))) {
                continue;
            }
            if ($row['group_name'] == 'BOTS') {
                continue;
            }

            $row_group_leader = null;
            if (!is_null($row['user_id'])) {
                $row_group_leader = -$row['user_id']; // This will be fixed when we import members
            }

            $is_super_admin = 0;
            $is_super_moderator = 0;

            if ($row['group_name'] == 'REGISTERED') {
                $id_new = 9;
            } elseif ($row['group_name'] == 'REGISTERED_COPPA') {
                $id_new = 9;
            } elseif ($row['group_name'] == 'GLOBAL_MODERATORS') {
                $id_new = 3;
            } else {
                $id_new = $GLOBALS['FORUM_DB']->query_select_value_if_there('f_groups', 'id', array($GLOBALS['FORUM_DB']->translate_field_ref('g_name') => $row['group_name']));
            }
            if (is_null($id_new)) {
                $id_new = cns_make_group($row['group_name'], 0, $is_super_admin, $is_super_moderator, '', '', null, null, $row_group_leader, null, null, null, null, $row['group_avatar_width'], $row['group_avatar_height'], null, $row['group_sig_chars']);
            }

            $permissions = $db->query('SELECT * FROM ' . $table_prefix . 'acl_groups WHERE group_id=' . strval($row['group_id']));
            foreach ($permissions as $p) {
                if ($p['auth_role_id'] != 0) { // Do role
                    $rp = $db->query('SELECT * FROM ' . $table_prefix . 'acl_roles_data WHERE role_id=' . strval($p['auth_role_id']));
                    foreach ($rp as $_p) {
                        $this->_import_permg($db, $table_prefix, $_p['auth_option_id'], $id_new, $_p['auth_setting']);
                    }
                } else { // Do privilege
                    $this->_import_permg($db, $table_prefix, $p['auth_option_id'], $id_new, $p['auth_setting']);
                }
            }

            import_id_remap_put('group', strval($row['group_id']), $id_new);
        }
    }

    /**
     * Helper function to import a global permission to a usergroup, from a specific phpBB option row.
     *
     * @param  object $db The DB connection to import from
     * @param  string $table_prefix The table prefix the target prefix is using
     * @param  integer $option_id Option row ID
     * @param  GROUP $group_id Group it applies to
     * @param  BINARY $auth_setting Setting
     */
    protected function _import_permg($db, $table_prefix, $option_id, $group_id, $auth_setting)
    {
        $_pp = $db->query('SELECT * FROM ' . $table_prefix . 'acl_options WHERE is_global=1 AND founder_only=0 AND auth_option_id=' . strval($option_id), 1);
        if (!array_key_exists(0, $_pp)) {
            return;
        }
        $pp = $_pp[0];

        $translated_permission = $this->_translate_permission($pp['auth_option']);
        if (!is_null($translated_permission)) {
            $the_value = $auth_setting;
            if ($translated_permission == 'read') {
                // Nothing can do
            } else {
                $GLOBALS['FORUM_DB']->query_insert('group_privileges', array('privilege' => $translated_permission, 'group_id' => $group_id, 'the_page' => 'topics', 'module_the_name' => '', 'category_name' => '', 'the_value' => $the_value), false, true);
            }
        }
    }

    /**
     * Standard import function.
     *
     * @param  object $db The DB connection to import from
     * @param  string $table_prefix The table prefix the target prefix is using
     * @param  PATH $file_base The base directory we are importing from
     */
    public function import_cns_members($db, $table_prefix, $file_base)
    {
        $row_start = 0;
        $rows = array();
        do {
            $rows = $db->query('SELECT * FROM ' . $table_prefix . 'users u LEFT JOIN ' . $table_prefix . 'banlist b ON u.user_id=b.ban_userid WHERE u.user_type<>2 ORDER BY u.user_id', 200, $row_start);
            foreach ($rows as $row) {
                if (import_check_if_imported('member', strval($row['user_id']))) {
                    continue;
                }

                $test = $GLOBALS['CNS_DRIVER']->get_member_from_username($row['username']);
                if (!is_null($test)) {
                    import_id_remap_put('member', strval($row['user_id']), $test);
                    continue;
                }

                $language = '';
                if ($row['user_lang'] != '') {
                    switch ($language) { // Can be extended as needed
                        case 'english':
                            $language = 'EN';
                            break;
                    }
                }

                $primary_group = import_id_remap_get('group', strval($row['group_id']));
                $rows2 = $db->query('SELECT * FROM ' . $table_prefix . 'user_group WHERE user_id=' . strval($row['user_id']), 200, $row_start);
                $secondary_groups = array();
                foreach ($rows2 as $row2) {
                    if ($row2['group_id'] != $row['group_id']) {
                        $g = import_id_remap_get('group', strval($row2['group_id']), true);
                        if (!is_null($g)) {
                            $secondary_groups[] = array($g, $row2['user_pending']);
                        }
                    }
                }

                $custom_fields = array(
                    cns_make_boiler_custom_field('interests') => array_key_exists('user_interests', $row) ? $row['user_interests'] : '',
                    cns_make_boiler_custom_field('location') => array_key_exists('user_from', $row) ? $row['user_from'] : '',
                    cns_make_boiler_custom_field('occupation') => array_key_exists('user_occ', $row) ? $row['user_occ'] : '',
                );
                if ($row['user_website'] != '') {
                    $custom_fields[cns_make_boiler_custom_field('website')] = (!empty($row['user_website'])) ? ('[url]' . $row['user_website'] . '[/url]') : '';
                }

                $signature = $this->fix_links($row['user_sig'], $row['user_sig_bbcode_uid'], $db, $table_prefix);
                $validated = 1;
                $reveal_age = 0;
                if (strpos($row['user_birthday'], '-') === false) {
                    list($bday_day, $bday_month, $bday_year) = array(null, null, null);
                } else {
                    $bday = explode('-', $row['user_birthday']);
                    list($bday_day, $bday_month, $bday_year) = array(intval(trim($bday[0])), intval(trim($bday[1])), intval(trim($bday[2])));
                }
                $views_signatures = 1;
                $preview_posts = 1;
                $track_posts = $row['user_notify'];
                $title = '';

                // These are done in the members-files stage
                $avatar_url = '';
                $photo_url = '';
                $photo_thumb_url = '';

                $password = $row['user_password'];
                $type = 'phpbb3';
                $salt = '';

                $id_new = cns_make_member($row['username'], $password, $row['user_email'], null, $bday_day, $bday_month, $bday_year, $custom_fields, strval($row['user_timezone']), $primary_group, $validated, $row['user_regdate'], $row['user_lastvisit'], '', $avatar_url, $signature, (!is_null($row['ban_id'])) ? 1 : 0, $preview_posts, $reveal_age, $title, $photo_url, $photo_thumb_url, $views_signatures, $track_posts, $language, 1, $row['user_allow_massemail'], '', '', false, $type, $salt, 1);

                // CPF values
                $cpf_rows = collapse_2d_complexity('field_name', 'field_type', $db->query('SELECT field_name,field_type FROM ' . $table_prefix . 'profile_fields f'));
                $rows2 = $db->query('SELECT * FROM ' . $table_prefix . 'profile_fields_data WHERE user_id=' . strval($row['user_id']), 1);
                $row2 = array();
                if (array_key_exists(0, $rows2)) {
                    foreach ($rows2[0] as $key => $val) {
                        if (substr($key, 0, 3) == 'pf_') {
                            if (is_null($val)) {
                                /* Actually is stored as a string
                                if ($cpf_rows[substr($key, 3)] == FIELD_INT) {
                                    $val = null;
                                } elseif ($cpf_rows[substr($key, 3)] == FIELD_BOOL) {
                                    $val = null;
                                } elseif ($cpf_rows[substr($key, 3)] == FIELD_DATE) {
                                    $val = null;
                                } else
                                */
                                $val = '';
                            }
                            if (!is_string($val)) {
                                $val = strval($val);
                            }
                            $row2['field_' . strval(import_id_remap_get('cpf', substr($key, 3)))] = $val;
                        }
                    }
                    $GLOBALS['FORUM_DB']->query_update('f_member_custom_fields', $row2, array('mf_member_id' => $id_new), '', 1);
                }

                // Fix usergroup leadership
                $GLOBALS['FORUM_DB']->query_update('f_groups', array('g_group_leader' => $id_new), array('g_group_leader' => -$row['user_id']));

                import_id_remap_put('member', strval($row['user_id']), $id_new);

                // Set up usergroup membership
                foreach ($secondary_groups as $s) {
                    list($group, $userpending) = $s;
                    cns_add_member_to_group($id_new, $group, 1 - $userpending);
                }
            }

            $row_start += 200;
        } while (count($rows) > 0);
    }

    /**
     * Standard import function.
     *
     * @param  object $db The DB connection to import from
     * @param  string $table_prefix The table prefix the target prefix is using
     * @param  PATH $file_base The base directory we are importing from
     */
    public function import_cns_member_files($db, $table_prefix, $file_base)
    {
        global $STRICT_FILE;

        $options = $db->query('SELECT * FROM ' . $table_prefix . 'config WHERE ' . db_string_equal_to('config_name', 'avatar_path') . ' OR ' . db_string_equal_to('config_name', 'avatar_gallery_path'));
        $avatar_path = $options[0]['config_value'];
        $avatar_gallery_path = $options[1]['config_value'];

        $row_start = 0;
        $rows = array();
        do {
            $query = 'SELECT user_id,user_avatar,user_avatar_type FROM ' . $table_prefix . 'users WHERE user_type<>2 ORDER BY user_id';
            $rows = $db->query($query, 200, $row_start);
            foreach ($rows as $row) {
                if (import_check_if_imported('member_files', strval($row['user_id']))) {
                    continue;
                }

                $member_id = import_id_remap_get('member', strval($row['user_id']));

                $avatar_url = '';
                switch ($row['user_avatar_type']) {
                    case 0:
                        break;
                    case 1: // Upload
                        $filename = $row['user_avatar'];
                        if ((file_exists(get_custom_file_base() . '/uploads/cns_avatars/' . $filename)) || (@rename($file_base . '/' . $avatar_path . '/' . $filename, get_custom_file_base() . '/uploads/cns_avatars/' . $filename))) {
                            $avatar_url = 'uploads/cns_avatars/' . $filename;
                            sync_file(get_custom_file_base() . '/' . $avatar_url);
                        } else {
                            if ($STRICT_FILE) {
                                warn_exit(do_lang_tempcode('MISSING_AVATAR', escape_html($filename)));
                            }
                            $avatar_url = '';
                        }
                        break;
                    case 2: // Remote
                        $avatar_url = $row['user_avatar'];
                        break;
                    case 3: // Gallery
                        $filename = $row['user_avatar'];
                        if ((file_exists(get_custom_file_base() . '/uploads/cns_avatars/' . $filename)) || (@rename($file_base . '/' . $avatar_gallery_path . '/' . $filename, get_custom_file_base() . '/uploads/cns_avatars/' . $filename))) {
                            $avatar_url = 'uploads/cns_avatars/' . substr($filename, strrpos($filename, '/'));
                            sync_file(get_custom_file_base() . '/' . $avatar_url);
                        } else {
                            // Try as a pack avatar then
                            $striped_filename = str_replace('/', '_', $filename);
                            if (file_exists(get_custom_file_base() . '/uploads/cns_avatars/' . $striped_filename)) {
                                $avatar_url = 'uploads/cns_avatars/' . substr($filename, strrpos($filename, '/'));
                            } else {
                                if ($STRICT_FILE) {
                                    warn_exit(do_lang_tempcode('MISSING_AVATAR', escape_html($filename)));
                                }
                                $avatar_url = '';
                            }
                        }
                        break;
                }

                $GLOBALS['FORUM_DB']->query_update('f_members', array('m_avatar_url' => $avatar_url), array('id' => $member_id), '', 1);

                import_id_remap_put('member_files', strval($row['user_id']), 1);
            }

            $row_start += 200;
        } while (count($rows) > 0);
    }

    /**
     * Standard import function.
     *
     * @param  object $db The DB connection to import from
     * @param  string $table_prefix The table prefix the target prefix is using
     * @param  PATH $file_base The base directory we are importing from
     */
    public function import_ip_bans($db, $table_prefix, $file_base)
    {
        require_code('failure');

        $rows = $db->query('SELECT * FROM ' . $table_prefix . 'banlist WHERE ' . db_string_not_equal_to('ban_ip', ''));
        foreach ($rows as $row) {
            if (import_check_if_imported('ip_ban', strval($row['ban_id']))) {
                continue;
            }

            add_ip_ban($this->_un_phpbb_ip($row['ban_ip']));

            import_id_remap_put('ip_ban', strval($row['ban_id']), 0);
        }
    }

    /**
     * Convert an IP address from phpBB hexadecimal string format.
     *
     * @param  string $ip The phpBB IP address
     * @return IP The normal IP address
     */
    protected function _un_phpbb_ip($ip)
    {
        if (strlen($ip) < 8) {
            return '127.0.0.1';
        }

        $_ip = strval(hexdec($ip[0] . $ip[1])) . '.' . strval(hexdec($ip[2] . $ip[3])) . '.' . strval(hexdec($ip[4] . $ip[5])) . '.' . strval(hexdec($ip[6] . $ip[7]));
        return $_ip;
    }

    /**
     * Standard import function.
     *
     * @param  object $db The DB connection to import from
     * @param  string $table_prefix The table prefix the target prefix is using
     * @param  PATH $old_base_dir The base directory we are importing from
     */
    public function import_cns_forums($db, $table_prefix, $old_base_dir)
    {
        require_code('cns_forums_action2');

        $rows = $db->query('SELECT * FROM ' . $table_prefix . 'forums');
        foreach ($rows as $row) {
            $remapped = import_id_remap_get('forum', strval($row['forum_id']), true);
            if (!is_null($remapped)) {
                continue;
            }

            if ($row['forum_type'] == 0) {
                $id_new = cns_make_forum_grouping($row['forum_name'], '', 1);
                import_id_remap_put('forum', strval($row['forum_id']), $id_new);
                continue;
            }

            $name = $row['forum_name'];
            $description = html_to_comcode($row['forum_desc']);
            $position = 1;
            $post_count_increment = 1;

            $category_id = db_get_first_id();
            $parent_forum = db_get_first_id();

            $rules = $this->fix_links($row['forum_rules'], $row['forum_rules_uid'], $db, $table_prefix);
            if ($row['forum_rules_link'] != '') {
                if ($rules != '') {
                    $rules .= "\n\n";
                }
                $rules .= '[url]' . $row['forum_rules_link'] . '[/url]';
            }

            $answer = $row['forum_password'];
            if (($rules == '') && ($answer != '')) {
                $rules = do_lang('FORUM_PASSWORD_TO_INTRO_QUESTION');
            }

            $id_new = cns_make_forum($name, $description, $category_id, null, $parent_forum, $position, $post_count_increment, 0, $rules, $answer, $row['forum_link']);

            $permissions = $db->query('SELECT * FROM ' . $table_prefix . 'acl_groups WHERE forum_id=' . strval($row['forum_id']));
            foreach ($permissions as $p) {
                $group_id = import_id_remap_get('group', strval($p['group_id']), true);
                if (is_null($group_id)) {
                    continue; // maybe bots group (6)
                }
                if ($p['auth_role_id'] != 0) { // Do role
                    $rp = $db->query('SELECT * FROM ' . $table_prefix . 'acl_roles_data WHERE role_id=' . strval($p['auth_role_id']));
                    foreach ($rp as $_p) {
                        $this->_import_perm($db, $table_prefix, $_p['auth_option_id'], $group_id, $id_new, $_p['auth_setting']);
                    }
                } else { // Do privilege
                    $this->_import_perm($db, $table_prefix, $p['auth_option_id'], $group_id, $id_new, $p['auth_setting']);
                }
            }

            import_id_remap_put('forum', strval($row['forum_id']), $id_new);
        }

        foreach ($rows as $row) {
            if ($row['forum_type'] == 1) {
                $remapped = import_id_remap_get('forum', strval($row['forum_id']));
                list($cat_id, $parent_id) = $this->_find_parent_forum_and_category($rows, $row['parent_id']);
                $parent_forum = is_null($parent_id) ? db_get_first_id() : import_id_remap_get('forum', strval($parent_id));
                $cat = is_null($cat_id) ? db_get_first_id() : import_id_remap_get('forum', strval($cat_id));
                $GLOBALS['FORUM_DB']->query_update('f_forums', array('f_forum_grouping_id' => $cat, 'f_parent_forum' => $parent_forum), array('id' => $remapped), '', 1);
            }
        }
    }

    /**
     * Helper function to locate parent forum and category of a forum. Has to be clever to locate both, by tree traversal.
     *
     * @param  array $rows Rows of forums/categories
     * @param  integer $parent_forum Key for the 'parent' (which may be for cat or may be for real parent)
     * @return array A pair: the category ID, the forum ID
     */
    protected function _find_parent_forum_and_category($rows, $parent_forum)
    {
        $cat_id = null;
        $parent_id = null;
        foreach ($rows as $row2) {
            if ($row2['forum_id'] == $parent_forum) {
                if ($row2['forum_type'] == 0) {
                    $cat_id = $row2['forum_id'];
                    break;
                } else {
                    $parent_id = $row2['forum_id'];
                    break;
                }
            }
        }
        if ($parent_id === 0) {
            $parent_id = null;
        }
        if ($cat_id === 0) {
            $cat_id = null;
        }
        if ((is_null($parent_id)) && (!is_null($cat_id))) {
            foreach ($rows as $row2) {
                if ($row2['forum_id'] == $cat_id) {
                    $cat_parent_id = $row2['parent_id'];
                }
            }
            list(, $parent_id) = $this->_find_parent_forum_and_category($rows, $cat_parent_id);
        }
        return array($cat_id, $parent_id);
    }

    /**
     * Helper function to import a permission to a usergroup, from a specific phpBB option row.
     *
     * @param  object $db The DB connection to import from
     * @param  string $table_prefix The table prefix the target prefix is using
     * @param  integer $option_id Option row ID
     * @param  GROUP $group_id Group it applies to
     * @param  AUTO_LINK $forum_id Forum it applies to
     * @param  BINARY $auth_setting Setting
     */
    protected function _import_perm($db, $table_prefix, $option_id, $group_id, $forum_id, $auth_setting)
    {
        $_pp = $db->query('SELECT * FROM ' . $table_prefix . 'acl_options WHERE is_local=1 AND founder_only=0 AND auth_option_id=' . strval($option_id), 1);
        if (!array_key_exists(0, $_pp)) {
            return;
        }
        $pp = $_pp[0];

        $translated_permission = $this->_translate_permission($pp['auth_option']);
        if (!is_null($translated_permission)) {
            $the_value = $auth_setting;
            if ($translated_permission == 'read') {
                if ($the_value == 1) {
                    $GLOBALS['FORUM_DB']->query_insert('group_category_access', array('group_id' => $group_id, 'module_the_name' => 'forums', 'category_name' => strval($forum_id)), false, true);
                }
            } else {
                $GLOBALS['FORUM_DB']->query_insert('group_privileges', array('privilege' => $translated_permission, 'group_id' => $group_id, 'the_page' => '', 'module_the_name' => 'forums', 'category_name' => strval($forum_id), 'the_value' => $the_value), false, true);
            }
        }
    }

    /**
     * Helper function to translate phpBB permissions to Composr permissions.
     *
     * @param  string $perm Old perm
     * @return ?string New perm (null: could not convert)
     */
    protected function _translate_permission($perm)
    {
        $x = null;

        switch ($perm) {
            case 'f_read':
                $x = 'read';
                break;

            case 'f_post':
                $x = 'submit_midrange_content';
                break;

            case 'f_reply':
                $x = 'submit_lowrange_content';
                break;

            case 'f_edit':
                $x = 'edit_own_lowrange_content';
                break;

            case 'f_delete':
                $x = 'delete_own_lowrange_content';
                break;

            case 'm_edit':
                $x = 'edit_lowrange_content';
                break;

            case 'm_delete':
                $x = 'delete_lowrange_content';
                break;
        }

        return $x;
    }

    /**
     * Standard import function.
     *
     * @param  object $db The DB connection to import from
     * @param  string $table_prefix The table prefix the target prefix is using
     * @param  PATH $file_base The base directory we are importing from
     */
    public function import_cns_topics($db, $table_prefix, $file_base)
    {
        $row_start = 0;
        $rows = array();
        do {
            $rows = $db->query('SELECT * FROM ' . $table_prefix . 'topics WHERE topic_moved_id=0 ORDER BY topic_id', 200, $row_start);
            foreach ($rows as $row) {
                if (import_check_if_imported('topic', strval($row['topic_id']))) {
                    continue;
                }

                if ($row['forum_id'] == 0) {
                    continue; // Weird, 0 forum
                }
                $forum_id = import_id_remap_get('forum', strval($row['forum_id']));

                $id_new = cns_make_topic($forum_id, '', $this->convert_topic_emoticon($row['icon_id']), $row['topic_visibility'], ($row['topic_status'] == 1) ? 0 : 1, ($row['topic_type'] > 0) ? 1 : 0, ($row['topic_type'] > 2) ? 1 : 0, 0, null, null, false, $row['topic_views']);

                import_id_remap_put('topic', strval($row['topic_id']), $id_new);
            }

            $row_start += 200;
        } while (count($rows) > 0);
    }

    /**
     * Standard import function.
     *
     * @param  object $db The DB connection to import from
     * @param  string $table_prefix The table prefix the target prefix is using
     * @param  PATH $file_base The base directory we are importing from
     */
    public function import_cns_posts($db, $table_prefix, $file_base)
    {
        global $STRICT_FILE;

        $row_start = 0;

        // Optimisation to speed through quickly, as can be slow scrolling through so many posts we may have already imported!
        do {
            $rows = $db->query('SELECT post_id FROM ' . $table_prefix . 'posts ORDER BY post_id', 1, $row_start + 200 - 1);
            if ((!array_key_exists(0, $rows)) || (!import_check_if_imported('post', strval($rows[0]['post_id'])))) {
                break;
            }

            $row_start += 200;
        } while (true);

        $rows = array();
        do {
            $rows = $db->query('SELECT * FROM ' . $table_prefix . 'posts ORDER BY post_id', 200, $row_start);
            foreach ($rows as $row) {
                if (import_check_if_imported('post', strval($row['post_id']))) {
                    continue;
                }

                $topic_id = import_id_remap_get('topic', strval($row['topic_id']), true);
                if (is_null($topic_id)) {
                    import_id_remap_put('post', strval($row['post_id']), -1);
                    continue;
                }
                $member_id = import_id_remap_get('member', strval($row['poster_id']), true);
                if (is_null($member_id)) {
                    $member_id = db_get_first_id();
                }

                $forum_id = import_id_remap_get('forum', strval($row['forum_id']), true);

                $title = '';
                $topics = $db->query('SELECT topic_title,topic_time FROM ' . $table_prefix . 'topics WHERE topic_id=' . strval($row['topic_id']));
                $first_post = $topics[0]['topic_time'] == $row['post_time'];
                if ($first_post) {
                    $title = @html_entity_decode($topics[0]['topic_title'], ENT_QUOTES);
                } elseif ((!is_null($row['post_subject'])) && (substr($row['post_subject'], 0, 4) != 'Re: ')) {
                    $title = @html_entity_decode($row['post_subject'], ENT_QUOTES);
                }

                $post = $this->fix_links($row['post_text'], $row['bbcode_uid'], $db, $table_prefix, $row['post_id']);

                $attach_id = collapse_1d_complexity('attach_id', $db->query_select('attachments', array('attach_id'), array('post_msg_id' => $row['post_id'], 'in_message' => 0)));
                foreach ($attach_id as $i => $_attach_id) {
                    $_attach_id = import_id_remap_get('attachment', strval($_attach_id), true);
                    if (!is_null($_attach_id)) {
                        if ((strpos($post, '[attachment') === false) && ($row['post_attachment'] == 1)) {
                            if (!is_null($_attach_id)) {
                                $post .= "\n\n" . '[attachment]' . strval($_attach_id) . '[/attachment]';
                            }
                        }
                    }
                    $attach_id[$i] = $_attach_id;
                }

                $last_edit_by = null;
                $last_edit_time = $row['post_edit_time'];

                if ($row['post_username'] == '') {
                    $row['post_username'] = $GLOBALS['CNS_DRIVER']->get_username($member_id);
                }

                $id_new = cns_make_post($topic_id, $title, $post, 0, $first_post, $row['post_visibility'], 0, $row['post_username'], $this->_un_phpbb_ip($row['poster_ip']), $row['post_time'], $member_id, null, $last_edit_time, $last_edit_by, false, false, $forum_id, false);

                foreach ($attach_id as $i => $_attach_id) {
                    if (!is_null($_attach_id)) {
                        $GLOBALS['FORUM_DB']->query_insert('attachment_refs', array(
                            'r_referer_type' => 'cns_post',
                            'r_referer_id' => $id_new,
                            'a_id' => $_attach_id,
                        ));
                    }
                }

                import_id_remap_put('post', strval($row['post_id']), $id_new);
            }

            $row_start += 200;
        } while (count($rows) > 0);
    }

    /**
     * Substitution callback for 'fix_links'.
     *
     * @param  array $m The match
     * @return  string        The substitution string
     */
    protected function _fix_links_callback_topic($m)
    {
        return 'index.php?page=topicview&id=' . strval(import_id_remap_get('topic', strval($m[2]), true));
    }

    /**
     * Substitution callback for 'fix_links'.
     *
     * @param  array $m The match
     * @return  string        The substitution string
     */
    protected function _fix_links_callback_forum($m)
    {
        return 'index.php?page=forumview&id=' . strval(import_id_remap_get('forum', strval($m[2]), true));
    }

    /**
     * Substitution callback for 'fix_links'.
     *
     * @param  array $m The match
     * @return  string        The substitution string
     */
    protected function _fix_links_callback_member($m)
    {
        return 'index.php?page=members&type=view&id=' . strval(import_id_remap_get('member', strval($m[2]), true));
    }

    /**
     * Convert phpBB URLs pasted in text fields into Composr ones.
     *
     * @param  string $post The text field text (e.g. a post)
     * @param  string $uid Bbcode uid
     * @param  object $db The DB connection to import from
     * @param  string $table_prefix The table prefix the target prefix is using
     * @param  ?AUTO_LINK $post_id The ID of the post/message being imported (null: attachments not supported)
     * @param  boolean $is_pm Whether it is a personal message
     * @return string The new text field text
     */
    public function fix_links($post, $uid, $db, $table_prefix, $post_id = null, $is_pm = false)
    {
        $orig_post = $post;

        $post = preg_replace('#<!-- [mwl] --><a class="[\w\-]+" href="([^"]*)"( onclick="window.open\(this.href\);\s*return false;")?' . '>(.*)</a><!-- [mwl] -->#U', '[url="${3}"]${1}[/url]', $post);
        $post = preg_replace('#<!-- e --><a href="mailto:(.*)">(.*)</a><!-- e -->#U', '[email="${2}"]${1}[/email]', $post);

        global $OLD_BASE_URL;
        if (is_null($OLD_BASE_URL)) {
            $rows = $db->query('SELECT * FROM ' . $table_prefix . 'config WHERE ' . db_string_equal_to('config_name', 'server_name') . ' OR ' . db_string_equal_to('config_name', 'server_port') . ' OR ' . db_string_equal_to('config_name', 'script_path') . ' ORDER BY config_name');
            $server_path = $rows[0]['config_value'];
            $server_name = $rows[1]['config_value'];
            $server_port = $rows[2]['config_value'];
            if ($server_port == '443') {
                $OLD_BASE_URL = 'https://' . $server_name . $server_path;
            } else {
                $OLD_BASE_URL = ($server_port == '80') ? ('http://' . $server_name . $server_path) : ('http://' . $server_name . ':' . $server_port . $server_path);
            }
        }
        $post = preg_replace_callback('#' . preg_quote($OLD_BASE_URL) . '/(viewtopic\.php\?t=)(\d*)#', array($this, '_fix_links_callback_topic'), $post);
        $post = preg_replace_callback('#' . preg_quote($OLD_BASE_URL) . '/(viewforum\.php\?f=)(\d*)#', array($this, '_fix_links_callback_forum'), $post);
        $post = preg_replace_callback('#' . preg_quote($OLD_BASE_URL) . '/(profile\.php\?mode=viewprofile&u=)(\d*)#', array($this, '_fix_links_callback_member'), $post);
        $post = preg_replace('#:[0-9a-f]{10}#', '', $post);

        $matches = array();
        $count = preg_match_all('#\[attachment=(\d+)(:.*)?\].*\[\/attachment(:.*)?\]#Us', $post, $matches);
        $to = mixed();
        for ($i = 0; $i < $count; $i++) {
            if (!is_null($post_id)) {
                $from = $matches[1][$i];
                $attachments = $db->query_select('attachments', array('attach_id'), array('post_msg_id' => $post_id, 'in_message' => $is_pm ? 1 : 0), 'ORDER BY attach_id');
                $to = array_key_exists(intval($from), $attachments) ? $attachments[intval($from)]['attach_id'] : -1;
                $to = import_id_remap_get('attachment', strval($to), true);
            } else {
                $to = null;
            }
            if (is_null($to)) {
                $post = str_replace($matches[0][$i], '(attachment removed)', $post);
            } else {
                $post = str_replace($matches[0][$i], '[attachment]' . strval($to) . '[/attachment]', $post);
            }
        }

        if ($uid != '') {
            $post = str_replace(':' . $uid, '', $post);
        }
        $post = preg_replace('#<!-- s([^\s]*) --><img src="\{SMILIES_PATH\}/[^"]*" alt="([^\s]*)" title="[^"]*" /><!-- s([^\s]*) -->#U', '${1}', $post);

        $post = preg_replace('#\[size="?(\d+)"?\]#i', '[size="${1}%"]', $post);

        $post = str_replace('{', '\{', $post);

        return html_entity_decode($post, ENT_QUOTES);
    }

    /**
     * Standard import function.
     *
     * @param  object $db The DB connection to import from
     * @param  string $table_prefix The table prefix the target prefix is using
     * @param  PATH $file_base The base directory we are importing from
     */
    public function import_cns_polls_and_votes($db, $table_prefix, $file_base)
    {
        $rows = $db->query('SELECT * FROM ' . $table_prefix . 'topics t LEFT JOIN ' . $table_prefix . 'poll_options o ON t.topic_id=o.topic_id WHERE ' . db_string_not_equal_to('poll_title', ''));
        foreach ($rows as $row) {
            if (import_check_if_imported('poll', strval($row['topic_id']))) {
                continue;
            }

            $topic_id = import_id_remap_get('topic', strval($row['topic_id']), true);

            $is_open = ($row['poll_start'] > time()) && (($row['poll_length'] == 0) || (($row['poll_start'] + $row['poll_length']) < time()));

            $rows2 = $db->query('SELECT * FROM ' . $table_prefix . 'poll_options WHERE topic_id=' . strval($row['topic_id']) . ' ORDER BY poll_option_id');
            $answers = array();
            foreach ($rows2 as $answer) {
                $answers[] = $answer['poll_option_text'];
            }
            $maximum = 1;

            $rows2 = $db->query('SELECT * FROM ' . $table_prefix . 'poll_votes WHERE topic_id=' . strval($row['topic_id']));
            foreach ($rows2 as $row2) {
                $row2['vote_user_id'] = import_id_remap_get('member', strval($row2['vote_user_id']), true);
            }

            $id_new = cns_make_poll($topic_id, $row['poll_option_text'], 0, $is_open ? 1 : 0, 1, $maximum, 0, $answers, false);

            $answers = collapse_1d_complexity('id', $GLOBALS['FORUM_DB']->query_select('f_poll_answers', array('id'), array('pa_poll_id' => $id_new))); // Effectively, a remapping from IPB vote number to Composr vote number

            foreach ($rows2 as $row2) {
                $member_id = $row2['vote_user_id'];
                if ((!is_null($member_id)) && ($member_id != 0)) {
                    if (($row2['poll_option_id'] == 0) || (!array_key_exists($row2['poll_option_id'] - 1, $answers))) {
                        $answer = -1;
                    } else {
                        $answer = $answers[$row2['poll_option_id'] - 1];
                    }
                    $GLOBALS['FORUM_DB']->query_insert('f_poll_votes', array('pv_poll_id' => $id_new, 'pv_member_id' => $member_id, 'pv_answer_id' => $answer, 'pv_ip' => ''));
                }
            }

            import_id_remap_put('poll', strval($row['topic_id']), $id_new);
        }
    }

    /**
     * Standard import function.
     *
     * @param  object $db The DB connection to import from
     * @param  string $table_prefix The table prefix the target prefix is using
     * @param  PATH $old_base_dir The base directory we are importing from
     */
    public function import_cns_private_topics($db, $table_prefix, $old_base_dir)
    {
        $rows = $db->query('SELECT * FROM ' . $table_prefix . 'privmsgs ORDER BY message_time');

        // Group them up into what will become topics
        $groups = array();
        foreach ($rows as $i => $row) {
            $rows2 = $db->query('SELECT user_id FROM ' . $table_prefix . 'privmsgs_to WHERE user_id<>' . strval($row['author_id']) . ' AND msg_id=' . strval($row['msg_id']), 1);
            if (!array_key_exists(0, $rows2)) {
                $rows2 = array(array('user_id' => -1));
            }

            $row['privmsgs_from_userid'] = $row['author_id'];
            $row['privmsgs_to_userid'] = $rows2[0]['user_id'];

            // Do some fiddling around for duplication
            if ($row['privmsgs_from_userid'] > $row['privmsgs_to_userid']) {
                $a = $row['privmsgs_to_userid'];
                $b = $row['privmsgs_from_userid'];
            } else {
                $a = $row['privmsgs_from_userid'];
                $b = $row['privmsgs_to_userid'];
            }
            $row['message_subject'] = str_replace('Re: ', '', $row['message_subject']);
            $groups[strval($a) . ':' . strval($b) . ':' . $row['message_subject']][] = $row;
        }

        // Import topics
        foreach ($groups as $group) {
            $row = $group[0];

            if (import_check_if_imported('pt', strval($row['msg_id']))) {
                continue;
            }

            // Create topic
            $from_id = import_id_remap_get('member', strval($row['privmsgs_from_userid']), true);
            if (is_null($from_id)) {
                $from_id = $GLOBALS['CNS_DRIVER']->get_guest_id();
            }
            $to_id = import_id_remap_get('member', strval($row['privmsgs_to_userid']), true);
            if (is_null($to_id)) {
                $to_id = $GLOBALS['CNS_DRIVER']->get_guest_id();
            }
            $topic_id = cns_make_topic(null, '', $this->convert_topic_emoticon($row['icon_id']), 1, 1, 0, 0, 0, $from_id, $to_id, false);

            $first_post = true;
            foreach ($group as $_postdetails) {
                if ($first_post) {
                    $title = @html_entity_decode($row['message_subject'], ENT_QUOTES);
                } else {
                    $title = '';
                }

                $post = $this->fix_links($_postdetails['message_text'], $row['bbcode_uid'], $db, $table_prefix, $_postdetails['msg_id'], true);

                $attach_id = collapse_1d_complexity('attach_id', $db->query_select('attachments', array('attach_id'), array('post_msg_id' => $_postdetails['msg_id'], 'in_message' => 1)));
                foreach ($attach_id as $i => $_attach_id) {
                    $_attach_id = import_id_remap_get('attachment', strval($_attach_id), true);
                    if (!is_null($_attach_id)) {
                        if ((strpos($post, '[attachment') === false) && ($row['message_attachment'] == 1)) {
                            if (!is_null($_attach_id)) {
                                $post .= "\n\n" . '[attachment]' . strval($_attach_id) . '[/attachment]';
                            }
                        }
                    }
                    $attach_id[$i] = $_attach_id;
                }

                $validated = 1;
                $from_id = import_id_remap_get('member', strval($_postdetails['privmsgs_from_userid']), true);
                if (is_null($from_id)) {
                    $from_id = $GLOBALS['CNS_DRIVER']->get_guest_id();
                }
                $poster_name_if_guest = $GLOBALS['CNS_DRIVER']->get_username($from_id);
                $ip_address = $_postdetails['author_ip'];
                $time = $_postdetails['message_time'];
                $poster = $from_id;
                $last_edit_time = $_postdetails['message_edit_time'];
                $last_edit_by = ($_postdetails['message_edit_user'] == 0) ? null : import_id_remap_get('member', strval($_postdetails['message_edit_user']), true);

                $post_id = cns_make_post($topic_id, $title, $post, 0, $first_post, $validated, 0, $poster_name_if_guest, $ip_address, $time, $poster, null, $last_edit_time, $last_edit_by, false, false, null, false);

                foreach ($attach_id as $i => $_attach_id) {
                    if (!is_null($_attach_id)) {
                        $GLOBALS['FORUM_DB']->query_insert('attachment_refs', array(
                            'r_referer_type' => 'cns_post',
                            'r_referer_id' => $post_id,
                            'a_id' => $_attach_id,
                        ));
                    }
                }

                $first_post = false;

                import_id_remap_put('pt_post', strval($_postdetails['msg_id']), $post_id);
            }

            import_id_remap_put('pt', strval($row['msg_id']), $topic_id);
        }
    }

    /**
     * Convert a phpBB topic icon code into a standard Composr theme image code (assumes the default ones).
     *
     * @param  integer $iconid phpBB code
     * @return ID_TEXT Composr code
     */
    public function convert_topic_emoticon($iconid)
    {
        switch ($iconid) {
            case 1:
                return 'cns_emoticons/devil';
            case 2:
                return 'cns_emoticons/angry';
            case 3:
                return 'cns_emoticons/sick';
            case 4:
                return 'cns_emoticons/wub';
            case 5:
                return 'cns_emoticons/king';
            case 6:
                return 'cns_emoticons/cyborg';
            case 7:
                return 'cns_emoticons/confused';
        }
        return '';
    }

    /**
     * Standard import function.
     *
     * @param  object $db The DB connection to import from
     * @param  string $table_prefix The table prefix the target prefix is using
     * @param  PATH $file_base The base directory we are importing from
     */
    public function import_notifications($db, $table_prefix, $file_base)
    {
        require_code('notifications');

        $row_start = 0;
        $rows = array();
        do {
            $rows = $db->query('SELECT * FROM ' . $table_prefix . 'topics_track', 200, $row_start);
            foreach ($rows as $row) {
                if (import_check_if_imported('topic_notification', strval($row['topic_id']) . '-' . strval($row['user_id']))) {
                    continue;
                }

                $member_id = import_id_remap_get('member', strval($row['user_id']), true);
                if (is_null($member_id)) {
                    continue;
                }
                $topic_id = import_id_remap_get('topic', strval($row['topic_id']), true);
                if (is_null($topic_id)) {
                    continue;
                }
                enable_notifications('cns_topic', strval($topic_id), $member_id);

                import_id_remap_put('topic_notification', strval($row['topic_id']) . '-' . strval($row['user_id']), 1);
            }

            $row_start += 200;
        } while (count($rows) > 0);

        $row_start = 0;
        $rows = array();
        do {
            $rows = $db->query('SELECT * FROM ' . $table_prefix . 'forums_track', 200, $row_start);
            foreach ($rows as $row) {
                if (import_check_if_imported('forum_notification', strval($row['forum_id']) . '-' . strval($row['user_id']))) {
                    continue;
                }

                $member_id = import_id_remap_get('member', strval($row['user_id']), true);
                if (is_null($member_id)) {
                    continue;
                }
                $forum_id = import_id_remap_get('forum', strval($row['forum_id']), true);
                if (is_null($forum_id)) {
                    continue;
                }
                enable_notifications('cns_topic', 'forum:' . strval($forum_id), $member_id);

                import_id_remap_put('forum_notification', strval($row['forum_id']) . '-' . strval($row['user_id']), 1);
            }

            $row_start += 200;
        } while (count($rows) > 0);
    }

    /**
     * Standard import function.
     *
     * @param  object $db The DB connection to import from
     * @param  string $table_prefix The table prefix the target prefix is using
     * @param  PATH $file_base The base directory we are importing from
     */
    public function import_custom_comcode($db, $table_prefix, $file_base)
    {
        $rows = $db->query('SELECT * FROM ' . $table_prefix . 'bbcodes');
        foreach ($rows as $row) {
            $test = $GLOBALS['FORUM_DB']->query_select_value_if_there('custom_comcode', 'tag_tag', array('tag_tag' => $row['bbcode_tag']));
            if (!is_null($test)) {
                continue;
            }

            $parameters = '';
            $matches = array();
            $count = preg_match_all('#\{(\w+)\}#', $row['bbcode_match'], $matches);
            for ($i = 0; $i < $count; $i++) {
                if ($matches[1][$i] == 'TEXT') {
                    continue;
                }

                if ($parameters != '') {
                    $parameters .= ',';
                }
                $parameters .= $matches[1][$i];
            }

            $map = array(
                'tag_tag' => $row['bbcode_tag'],
                'tag_replace' => str_replace('{TEXT}', '{content}', $row['bbcode_match']),
                'tag_example' => '',
                'tag_parameters' => $parameters,
                'tag_enabled' => 1,
                'tag_dangerous_tag' => 0,
                'tag_block_tag' => 0,
                'tag_textual_tag' => 0
            );
            $map += insert_lang('tag_title', $row['bbcode_tag'], 3);
            $map += insert_lang('tag_description', $row['bbcode_helpline'], 3);
            $GLOBALS['FORUM_DB']->query_insert('custom_comcode', $map);
        }
    }

    /**
     * Standard import function.
     *
     * @param  object $db The DB connection to import from
     * @param  string $table_prefix The table prefix the target prefix is using
     * @param  PATH $file_base The base directory we are importing from
     */
    public function import_bookmarks($db, $table_prefix, $file_base)
    {
        $rows = $db->query('SELECT * FROM ' . $table_prefix . 'bookmarks', null, null, true);
        if (is_null($rows)) {
            return;
        }
        foreach ($rows as $row) {
            $owner = import_id_remap_get('member', strval($row['user_id']), true);
            $topic_id = import_id_remap_get('topic', strval($row['topic_id']), true);
            if ((is_null($owner)) || (is_null($topic_id))) {
                continue;
            }

            $GLOBALS['FORUM_DB']->query_insert('bookmarks', array('b_owner' => $owner, 'b_folder' => '', 'b_title' => 'Topic #' . strval($topic_id), 'b_page_link' => 'forum:topicview:browse:' . strval($topic_id)));
        }
    }

    /**
     * Standard import function.
     *
     * @param  object $db The DB connection to import from
     * @param  string $table_prefix The table prefix the target prefix is using
     * @param  PATH $file_base The base directory we are importing from
     */
    public function import_wordfilter($db, $table_prefix, $file_base)
    {
        $rows = $db->query('SELECT * FROM ' . $table_prefix . 'words');
        foreach ($rows as $row) {
            add_wordfilter_word($row['word'], $row['replacement']);
        }
    }

    /**
     * Standard import function.
     *
     * @param  object $db The DB connection to import from
     * @param  string $table_prefix The table prefix the target prefix is using
     * @param  PATH $file_base The base directory we are importing from
     */
    public function import_cns_custom_profile_fields($db, $table_prefix, $file_base)
    {
        $rows = $db->query('SELECT f.*,lang_explain FROM ' . $table_prefix . 'profile_fields f LEFT JOIN ' . $table_prefix . 'profile_lang l ON l.field_id=f.field_id');
        foreach ($rows as $row) {
            if (import_check_if_imported('cpf', $row['field_ident'])) {
                continue;
            }

            $name = $row['field_name'];
            $id_new = $GLOBALS['FORUM_DB']->query_select_value_if_there('f_custom_fields', 'id', array($GLOBALS['FORUM_DB']->translate_field_ref('cf_name') => $name));
            if (is_null($id_new)) {
                $default = $row['field_default_value'];

                $type = 'short_text';
                switch ($row['field_type']) {
                    case FIELD_INT:
                        $type = 'integer';
                        break;

                    case FIELD_TEXT:
                        $type = 'long_text';
                        break;

                    case FIELD_BOOL:
                        $type = 'tick';
                        break;

                    case FIELD_DROPDOWN:
                        $type = 'list';

                        $values = collapse_1d_complexity('lang_default_value', $db->query('SELECT lang_default_value FROM ' . $table_prefix . 'profile_lang WHERE field_id=' . strval($row['field_id'])));
                        $_default = $default;
                        foreach ($values as $value) {
                            if ($value != $default) {
                                if ($_default == '') {
                                    $_default .= '|';
                                }
                                $_default .= $value;
                            }
                        }
                        $default = $_default;
                        break;
                    /*case FIELD_DATE: Unsupported
                                        $type = 'integer';
                                        break;*/
                }

                $id_new = cns_make_custom_field($name, 0, is_null($row['lang_explain']) ? '' : $row['lang_explain'], $default, 1 - $row['field_hide'], 1 - $row['field_no_view'], 1 - $row['field_no_view'], 0, $type, $row['field_show_on_reg'], 0, 0, $row['field_order']);
            }

            import_id_remap_put('cpf', $row['field_ident'], $id_new);
        }
    }

    /**
     * Standard import function.
     *
     * @param  object $db The DB connection to import from
     * @param  string $table_prefix The table prefix the target prefix is using
     * @param  PATH $file_base The base directory we are importing from
     */
    public function import_cns_warnings($db, $table_prefix, $file_base)
    {
        $rows = $db->query('SELECT * FROM ' . $table_prefix . 'warnings');
        foreach ($rows as $row) {
            $member_id = import_id_remap_get('member', strval($row['user_id']), true);
            $by = db_get_first_id() + 1;
            if (is_null($member_id)) {
                continue;
            }

            $post_id = import_id_remap_get('post', strval($row['post_id']), true);

            $explanation = is_null($post_id) ? '' : do_lang('IMPORT_WARNING_CONVERT', strval($post_id));

            cns_make_warning($member_id, $explanation, $by, $row['warning_time'], 1);
        }

        $rows = $db->query('SELECT * FROM ' . $table_prefix . 'banlist WHERE ban_end>' . strval(time()));
        foreach ($rows as $row) {
            $member_id = import_id_remap_get('member', strval($row['ban_userid']), true);
            if (is_null($member_id)) {
                continue;
            }

            $GLOBALS['FORUM_DB']->query_update('f_members', array('m_on_probation_until' => $row['ban_end']), array('id' => $member_id));
        }
    }

    /**
     * Standard import function.
     *
     * @param  object $db The DB connection to import from
     * @param  string $table_prefix The table prefix the target prefix is using
     * @param  PATH $file_base The base directory we are importing from
     */
    public function import_friends($db, $table_prefix, $file_base)
    {
        $rows = $db->query('SELECT * FROM ' . $table_prefix . 'zebra');
        foreach ($rows as $row) {
            $likes = import_id_remap_get('member', strval($row['user_id']), true);
            $liked = import_id_remap_get('member', strval($row['zebra_id']), true);
            if (is_null($likes)) {
                continue;
            }
            if (is_null($liked)) {
                continue;
            }

            if ($row['friend'] == 1) {
                $GLOBALS['SITE_DB']->query_insert('chat_friends', array('member_likes' => $likes, 'member_liked' => $liked, 'date_and_time' => time()));
            }

            if ($row['foe'] == 1) {
                $GLOBALS['SITE_DB']->query_insert('chat_blocking', array('member_blocker' => $likes, 'member_blocked' => $liked, 'date_and_time' => time()));
            }
        }
    }

    /**
     * Standard import function.
     *
     * @param  object $db The DB connection to import from
     * @param  string $table_prefix The table prefix the target prefix is using
     * @param  PATH $file_base The base directory we are importing from
     */
    public function import_reported_posts_forum($db, $table_prefix, $file_base)
    {
        $rows = $db->query('SELECT * FROM ' . $table_prefix . 'reports');
        foreach ($rows as $row) {
            $forum_id = $GLOBALS['FORUM_DRIVER']->forum_id_from_name(get_option('reported_posts_forum'));
            if (is_null($forum_id)) {
                warn_exit(do_lang_tempcode('NO_REPORTED_POST_FORUM'));
            }

            $post_id = import_id_remap_get('post', strval($row['post_id']), true);
            if (is_null($post_id)) {
                continue;
            }

            $user_id = import_id_remap_get('post', strval($row['user_id']), true);
            if (is_null($user_id)) {
                continue;
            }

            $post_info = $GLOBALS['SITE_DB']->query_select('f_posts', array('*'), array('id' => $post_id), '', 1);
            $topic_info = $GLOBALS['SITE_DB']->query_select('f_topics', array('*'), array('id' => $post_info[0]['p_topic_id']), '', 1);
            $post_title = @html_entity_decode($post_info[0]['p_title'], ENT_QUOTES);
            if ($post_title == '') {
                $post_title = $post_title[0]['t_cache_first_title'];
            }

            $poster = $post_info[0]['p_poster_name_if_guest'];
            $member = $GLOBALS['FORUM_DRIVER']->get_username($user_id);
            if (is_null($member)) {
                $member = do_lang('UNKNOWN');
            }

            $title = do_lang('REPORTED_POST_TITLE', $post_title);
            $topic_id = cns_make_topic($forum_id, $title, '', $row['topic_approved'], ($row['report_closed'] == 1) ? 0 : 1, 0, 0, 0, null, null, false);
            $post = do_template('CNS_REPORTED_POST_FCOMCODE', array('_GUID' => '0dd1532216390f75385323ce11baedba', 'POST_ID' => strval($post_id), 'MEMBER' => $member, 'TOPIC_NAME' => $topic_info[0]['t_cache_first_title'], 'POST' => $row['report_text'], 'POSTER' => $poster), null, false, null, '.txt', 'text');
            cns_make_post($topic_id, $title, $post->evaluate(), 0, true, 1, 0, $member, null, $row['report_time'], $user_id, null, null, null, false, true, null, true, $title, 0, null, false);
        }
    }
}
