<?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__smf()
{
    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
}

/**
 * Forum Driver.
 */
class Hook_smf
{
    /**
     * 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'] = 'SMF 1.1.x';
        $info['prefix'] = 'smf_';
        $info['import'] = array(
            'config',
            'cns_groups',
            'cns_members',
            'cns_member_files',
            'ip_bans',
            'cns_forum_groupings',
            'cns_forums',
            'cns_topics',
            'cns_private_topics',
            'cns_posts',
            'cns_post_files',
            'cns_polls_and_votes',
            'notifications',
            'wordfilter',
            'calendar'
        );

        $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
                                       'cns_members' => array('cns_groups'),
                                       'cns_member_files' => array('cns_members'),
                                       'cns_forums' => array('cns_forum_groupings', 'cns_members', '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'),
                                       'cns_post_files' => array('cns_posts', 'cns_private_topics'),
                                       'notifications' => array('cns_topics', 'cns_members', 'cns_polls_and_votes'),
                                       'cns_private_topics' => array('cns_members')
        );
        $_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)
    {
        $db_name = '';
        $db_user = '';
        $db_passwd = '';
        $db_prefix = '';
        $db_server = '';
        if (!file_exists($file_base . '/Settings.php')) {
            warn_exit(do_lang_tempcode('BAD_IMPORT_PATH', escape_html('Settings.php')));
        }
        require($file_base . '/Settings.php');

        return array($db_name, $db_user, $db_passwd, $db_prefix, $db_server);
    }

    /**
     * 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)
    {
        $webmaster_email = '';
        $mbname = '';
        $boardurl = '';
        $cookiename = '';

        require($file_base . '/Settings.php');

        $rows = $db->query_select('settings');

        $config_remapping = array();
        $config_remapping['staff_address'] = $webmaster_email;
        $config_remapping['site_name'] = $mbname;
        $board_url = $boardurl;
        $config_remapping['site_name'] = $mbname;
        $config_remapping['staff_address'] = $webmaster_email;
        $additional_data = array();

        foreach ($rows as $row) {
            if (isset($row['variable']) && $row['variable'] == 'topicSummaryPosts') {
                $config_remapping['forum_posts_per_page'] = $row['value'];
                continue;
            }

            if (isset($row['variable']) && $row['variable'] == 'newsletter_title') {
                $config_remapping['news'] = $row['value'];
                continue;
            }

            if (isset($row['variable']) && $row['variable'] == 'smtp_port') {
                $config_remapping['smtp_sockets_port'] = $row['value'];
                continue;
            }

            if (isset($row['variable']) && $row['variable'] == 'smtp_username') {
                $config_remapping['smtp_sockets_username'] = $row['value'];
                continue;
            }

            if (isset($row['variable']) && $row['variable'] == 'smtp_password') {
                $config_remapping['smtp_sockets_password'] = $row['value'];
                continue;
            }

            if (isset($row['variable']) && $row['variable'] == 'smtp_host') {
                $config_remapping['smtp_sockets_host'] = $row['value'];
                continue;
            }

            if (isset($row['variable']) && $row['variable'] == 'mail_type') {
                $config_remapping['smtp_sockets_use'] = ($row['value'] == '1') ? 1 : 0;
                continue;
            }

            if (isset($row['variable']) && $row['variable'] == 'databaseSession_lifetime') {
                $config_remapping['session_expiry_time'] = $row['value'];
                continue;
            }

            if (isset($row['variable']) && $row['variable'] == 'hotTopicPosts') {
                $config_remapping['hot_topic_definition'] = $row['value'];
                continue;
            }

            if (isset($row['variable']) && $row['variable'] == 'reserveNames') {
                $config_remapping['restricted_usernames'] = $row['value'];
                continue;
            }

            if (isset($row['variable']) && $row['variable'] == 'defaultMaxTopics') {
                $config_remapping['forum_topics_per_page'] = $row['value'];
                continue;
            }

            if (isset($row['variable']) && $row['variable'] == 'enableCompressedOutput') {
                $config_remapping['gzip_output'] = $row['value'];
                continue;
            }

            if (isset($row['variable']) && $row['variable'] == 'default_timezone') {
                $config_remapping['timezone'] = $row['value'];
                continue;
            }

            if (isset($row['variable']) && $row['variable'] == 'attachmentNumPerPostLimit') {
                $additional_data['maxattachments'] = $row['value'];
                continue;
            }

            if (isset($row['variable']) && $row['variable'] == 'avatar_max_width_upload') {
                $additional_data['avatar_max_width'] = $row['value'];
                continue;
            }

            if (isset($row['variable']) && $row['variable'] == 'avatar_max_height_upload') {
                $additional_data['avatar_max_height'] = $row['value'];
                continue;
            }
        }

        $PROBED_FORUM_CONFIG = array();

        foreach ($config_remapping as $key => $value) {
            if ($key != 'timezone') {
                set_option($key, $value);
            } else {
                set_value('timezone', str_replace('Etc/GMT+', '', $value));
            }

            $PROBED_FORUM_CONFIG[$key] = $row;
        }

        $groups = $GLOBALS['CNS_DRIVER']->get_usergroup_list();
        foreach ($groups as $id => $groupname) {
            if (preg_match('/Administrator/i', $groupname) != 0) {
                continue;
            }

            $GLOBALS['FORUM_DB']->query_update('f_groups', array('g_max_attachments_per_post' => $additional_data['maxattachments'], 'g_max_avatar_width' => $additional_data['avatar_max_width'], 'g_max_avatar_height' => $additional_data['avatar_max_height']), array('id' => $id), '', 1);
        }

        $PROBED_FORUM_CONFIG['board_prefix'] = $boardurl;
        $PROBED_FORUM_CONFIG['user_cookie'] = $cookiename;
    }

    /**
     * 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)
    {
        require($file_base . '/Settings.php');

        $rows = $db->query('SELECT * FROM ' . $table_prefix . 'settings WHERE ' . db_string_equal_to('variable', 'avatar_max_width_upload') . ' OR ' . db_string_equal_to('variable', 'avatar_max_height_upload'));
        $PROBED_FORUM_CONFIG = array();
        foreach ($rows as $row) {
            $key = $row['variable'];
            $val = $row['value'];
            $PROBED_FORUM_CONFIG[$key] = $val;
        }

        $avatar_max_width = $PROBED_FORUM_CONFIG['avatar_max_width_upload'];
        $avatar_max_height = $PROBED_FORUM_CONFIG['avatar_max_height_upload'];

        $rows = $db->query('SELECT * FROM ' . $table_prefix . 'membergroups ORDER BY ID_GROUP');
        foreach ($rows as $row) {
            if (import_check_if_imported('group', strval($row['ID_GROUP']))) {
                continue;
            }

            $is_super_admin = ($row['groupName'] == 'Administrator') ? 1 : 0;
            $is_super_moderator = ($row['groupName'] == 'Global Moderator') ? 1 : 0;

            $id_new = $GLOBALS['FORUM_DB']->query_select_value_if_there('f_groups', 'id', array($GLOBALS['FORUM_DB']->translate_field_ref('g_name') => $row['groupName']));
            if (is_null($id_new)) {
                $id_new = cns_make_group($row['groupName'], 0, $is_super_admin, $is_super_moderator, '', '', null, null, null, null, null, null, null, $avatar_max_width, $avatar_max_height, null);
            }

            // privileges
            set_privilege($id_new, 'allow_html', true);

            if (!import_check_if_imported('group', strval($row['ID_GROUP']))) {
                import_id_remap_put('group', strval($row['ID_GROUP']), $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_members($db, $table_prefix, $file_base)
    {
        $row_start = 0;
        $rows = array();

        $default_group = get_first_default_group();

        do {
            $rows = $db->query('SELECT u.ID_MEMBER AS \'muid\',u.*,b.* FROM ' . $table_prefix . 'members u LEFT JOIN ' . $table_prefix . 'ban_items b ON u.ID_MEMBER=b.ID_MEMBER WHERE u.ID_MEMBER<>-1 ORDER BY u.ID_MEMBER', 200, $row_start);

            foreach ($rows as $row) {
                if (import_check_if_imported('member', strval($row['muid']))) {
                    continue;
                }

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

                $language = 'EN';

                $secondary = explode(',', $row['additionalGroups']);
                $secondary_groups = array();
                foreach ($secondary as $g) {
                    if (trim($g) != '') {
                        $g = import_id_remap_get('group', $g, true);
                        if (!is_null($g)) {
                            $secondary_groups[] = intval($g);
                        }
                    }
                }

                $primary_group = $row['ID_GROUP'];
                if ($primary_group == 0) {
                    $primary_group = $row['ID_POST_GROUP'];
                }
                if ($primary_group == 0) {
                    $primary_group = $default_group;
                } else {
                    $primary_group = import_id_remap_get('group', strval($primary_group));
                }

                $custom_fields = array();
                if ($row['websiteUrl'] != '') {
                    $custom_fields[cns_make_boiler_custom_field('website')] = $row['websiteUrl'];
                }

                $signature = $this->fix_links($row['signature'], $db, $table_prefix, $file_base);
                $validated = 1;
                $reveal_age = 0;

                if ($row['birthdate'] != '') {
                    $birthdate = $row['birthdate'];
                    $birthdata = explode('-', $birthdate);
                    $bday_day = (isset($birthdata[0]) && ($birthdata[0] != '')) ? $birthdata[0] : null;
                    $bday_month = (isset($birthdata[1]) && ($birthdata[1] != '')) ? $birthdata[1] : null;
                    $bday_year = (isset($birthdata[2]) && ($birthdata[2] != '')) ? $birthdata[2] : null;
                } else {
                    list($bday_day, $bday_month, $bday_year) = array(null, null, null);
                }

                $views_signatures = 1;
                $preview_posts = 1;
                $track_posts = $row['notifyAnnouncements'];
                $title = '';

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

                $password = $row['passwd'];
                $type = 'smf';
                $salt = $row['passwordSalt'];

                if ($row['dateRegistered'] == 0) {
                    $row['dateRegistered'] = time();
                }
                $id_new = cns_make_member($row['memberName'], $password, $row['emailAddress'], null, $bday_day, $bday_month, $bday_year, $custom_fields, strval($row['timeOffset']), $primary_group, $validated, $row['dateRegistered'], $row['lastLogin'], '', $avatar_url, $signature, 0, $preview_posts, $reveal_age, $title, $photo_url, $photo_thumb_url, $views_signatures, $track_posts, $language, $row['instantMessages'], 1, '', '', false, $type, $salt, 1);

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

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

                // Set up usergroup membership
                foreach ($secondary_groups as $s) {
                    cns_add_member_to_group($id_new, $s, 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_cns_member_files($db, $table_prefix, $file_base)
    {
        $boardurl = '';
        $boarddir = '';

        global $STRICT_FILE;
        require($file_base . '/Settings.php');

        $options = $db->query('SELECT * FROM ' . $table_prefix . 'settings WHERE variable LIKE \'' . db_encode_like('%avatar%') . '\'');
        $options_array = array();

        $homeurl = $boardurl;

        $avatar_path = '';
        $avatar_gallery_path = '';
        $avatar_path = 'attachments';

        foreach ($options as $option) {
            $options_array[$option['variable']] = $option['value'];

            if ($option['variable'] == 'avatar_url') {
                $avatar_gallery_path = $option['value'];
            }
        }

        $avatar_gallery_path = str_replace($boardurl, '', $avatar_gallery_path);

        $forum_dir = preg_replace('#\\\\#', '/', $boarddir);

        $avatar_gallery_path = $forum_dir . $avatar_gallery_path;
        $avatar_path = $forum_dir . '/' . $avatar_path;

        $row_start = 0;
        $rows = array();
        do {
            $query = 'SELECT ID_MEMBER,avatar FROM ' . $table_prefix . 'members WHERE ID_MEMBER<>-1 ORDER BY ID_MEMBER';

            $rows = $db->query($query, 200, $row_start);
            foreach ($rows as $row) {
                if (import_check_if_imported('member_files', strval($row['ID_MEMBER']))) {
                    continue;
                }

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

                $avatar_url = '';
                if (!isset($row['avatar']) || (strlen($row['avatar']) == 0)) {
                    $query_attachments = 'SELECT ID_MEMBER,filename,width,height,size,attachmentType FROM ' . $table_prefix . 'attachments WHERE ' . db_string_equal_to('attachmentType', '0') . ' AND ' . db_string_equal_to('ID_MEMBER', strval($row['ID_MEMBER']));

                    $attachment_data = $db->query($query_attachments, 1, 0);
                    if (isset($attachment_data[0]['filename']) && (strlen($attachment_data[0]['filename']) > 0)) {
                        // Uploaded avatar
                        $filename = $attachment_data[0]['filename'];
                        if ((file_exists(get_custom_file_base() . '/uploads/cns_avatars/' . $filename)) || (@rename($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 = '';
                        }
                    }
                } else {
                    if (preg_match('#http\:#', $row['avatar']) != 0) {
                        //Remote file is set as avatar
                        $avatar_url = $row['avatar'];
                    } elseif (strlen($row['avatar']) > 0) {
                        // Gallery
                        $filename_with_subdir = $row['avatar'];
                        $filename = preg_replace('#.*\/#', '', $filename_with_subdir); //we need just a filename

                        if ((file_exists(get_custom_file_base() . '/uploads/cns_avatars/' . $filename)) || (@rename($avatar_gallery_path . '/' . $filename_with_subdir, 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 = '';
                            }
                        }
                    }
                }

                $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['ID_MEMBER']), 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)
    {
        global $SITE_INFO;

        require_code('failure');

        $rows = $db->query('SELECT * FROM ' . $table_prefix . 'ban_groups u LEFT JOIN ' . $table_prefix . 'ban_items b ON u.ID_BAN_GROUP=b.ID_BAN_GROUP');

        foreach ($rows as $row) {
            $ban_time = $row['ban_time']; //when is banned user
            $ban_till = $row['expire_time']; //member is banned until

            if (($ban_till > time()) || empty($ban_till)) {
                $user = $db->query_select('members', array('ID_MEMBER'), array('memberName' => $row['name']));

                if (isset($user[0]['ID_MEMBER']) && ($user[0]['ID_MEMBER'] != 0)) {
                    $uid = $user[0]['ID_MEMBER'];

                    if (empty($ban_till)) {
                        $GLOBALS['SITE_DB']->query_update('f_members', array('m_is_perm_banned' => 1), array('id' => $uid));
                    } else {
                        $GLOBALS['SITE_DB']->query_update('f_members', array('m_on_probation_until' => $ban_till), array('id' => $uid));
                    }

                    if ($row['ip_low1'] >= 127 && empty($ban_till)) {
                        if (import_check_if_imported('ip_ban', strval($uid))) {
                            continue;
                        }

                        for ($i = $row['ip_low1']; $i <= $row['ip_high1']; $i++) {
                            for ($j = $row['ip_low2']; $j <= $row['ip_high2']; $j++) {
                                for ($h = $row['ip_low3']; $h <= $row['ip_high3']; $h++) {
                                    for ($f = $row['ip_low4']; $f <= $row['ip_high4']; $f++) {
                                        $ip_to_ban = strval($i . '.' . $j . '.' . $h . '.' . $f);

                                        add_ip_ban($ip_to_ban);
                                        import_id_remap_put('ip_ban', $ip_to_ban, 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_forum_groupings($db, $table_prefix, $old_base_dir)
    {
        $rows = $db->query_select('categories');
        foreach ($rows as $row) {
            if (import_check_if_imported('category', strval($row['ID_CAT']))) {
                continue;
            }

            $title = $row['name'];
            $title = @html_entity_decode($title, ENT_QUOTES, get_charset());

            $test = $GLOBALS['FORUM_DB']->query_select_value_if_there('f_forum_groupings', 'id', array('c_title' => $title));
            if (!is_null($test)) {
                import_id_remap_put('category', strval($row['ID_CAT']), $test);
                continue;
            }

            $id_new = cns_make_forum_grouping($title, '', 1);

            import_id_remap_put('category', strval($row['ID_CAT']), $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_forums($db, $table_prefix, $old_base_dir)
    {
        require_code('cns_forums_action2');

        $remap_id = array();

        $rows = $db->query_select('boards');
        foreach ($rows as $row) {
            $remapped = import_id_remap_get('forum', strval($row['ID_BOARD']), true);
            if (!is_null($remapped)) {
                continue;
            }

            $name = $row['name'];
            cns_over_msn();
            $description = html_to_comcode($row['description']);
            cns_over_local();
            $position = $row['boardOrder'];
            $post_count_increment = 1;

            $parent_forum = ($row['ID_PARENT'] > 0) ? $row['ID_PARENT'] : db_get_first_id();
            $cat_id = $row['ID_CAT'];

            $permission_mode = $row['permission_mode'];

            $category_id = import_id_remap_get('category', strval($cat_id), true);

            $access_mapping = array();

            $permissions_on_groups = $db->query('SELECT DISTINCT ID_GROUP FROM ' . $table_prefix . 'board_permissions');
            foreach ($permissions_on_groups as $gid) {
                $permissions = $db->query('SELECT * FROM ' . $table_prefix . 'board_permissions WHERE ID_GROUP=' . strval($gid) . ' AND ID_BOARD=' . strval($row['ID_BOARD']));

                $v = 0;
                foreach ($permissions as $p) {
                    if ($p['permission'] == 'send_topic' && $p['addDeny'] != 1 && $v < 2) {
                        $v = 2;
                    }
                    if ($p['permission'] == 'post_reply_any' && $p['addDeny'] != 1 && $v < 3) {
                        $v = 3;
                    }
                    if ($p['permission'] == 'poll_post' && $p['addDeny'] != 1 && $v < 4) {
                        $v = 4;
                    }

                    $group_id = import_id_remap_get('group', strval($p['ID_GROUP']));
                    $access_mapping[$group_id] = $v;
                }
            }

            $id_new = cns_make_forum($name, $description, $category_id, $access_mapping, $parent_forum, $position, $post_count_increment, 0, '');

            $remap_id[$row['ID_BOARD']] = $id_new;
            import_id_remap_put('forum', strval($row['ID_BOARD']), $id_new);
        }

        // Now we must fix parenting
        foreach ($rows as $row) {
            if ((!is_null($row['ID_PARENT'])) && (isset($remap_id[$row['ID_BOARD']]))) {
                $parent_id = array_key_exists($row['ID_PARENT'], $remap_id) ? $remap_id[$row['ID_PARENT']] : db_get_first_id();
                $GLOBALS['FORUM_DB']->query_update('f_forums', array('f_parent_forum' => $parent_id), array('id' => $remap_id[$row['ID_BOARD']]), '', 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_cns_topics($db, $table_prefix, $file_base)
    {
        $row_start = 0;
        $rows = array();
        do {
            $rows = $db->query('SELECT * FROM ' . $table_prefix . 'topics t LEFT JOIN ' . $table_prefix . 'messages m ON t.ID_FIRST_MSG=m.ID_MSG' . (can_arbitrary_groupby() ? ' GROUP BY t.ID_TOPIC' : ''), 200, $row_start);
            $rows = remove_duplicate_rows($rows, 'ID_TOPIC');
            foreach ($rows as $row) {
                if (import_check_if_imported('topic', strval($row['ID_TOPIC']))) {
                    continue;
                }

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

                $id_new = cns_make_topic($forum_id, $row['subject'], '', 1, ($row['locked'] == 0) ? 1 : 0, 0, 0, 0, null, null, false, $row['numViews']);

                import_id_remap_put('topic', strval($row['ID_TOPIC']), $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 ID_MSG FROM ' . $table_prefix . 'messages p ORDER BY p.ID_MSG', 1, $row_start + 200 - 1);
            if ((!array_key_exists(0, $rows)) || (!import_check_if_imported('post', strval($rows[0]['ID_MSG'])))) {
                break;
            }

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

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

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

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

                $title = $row['subject'];
                $title = @html_entity_decode($title, ENT_QUOTES, get_charset());

                cns_over_msn();
                $post_description = html_to_comcode($row['body']);
                cns_over_local();

                $post = $this->fix_links($post_description, $db, $table_prefix, $file_base);

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

                $post_username = $row['posterName'];

                $id_new = cns_make_post($topic_id, $title, $post, 0, true, 1, 0, $post_username, $row['posterIP'], $row['posterTime'], $member_id, null, $last_edit_time, $last_edit_by, false, false, $forum_id, false);

                import_id_remap_put('post', strval($row['ID_MSG']), $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?topic=' . 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?board=' . 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?action=profile;u=' . strval(import_id_remap_get('member', strval($m[2]), true));
    }

    /**
     * Convert SMF URLs pasted in text fields into Composr ones.
     *
     * @param  string $post The text field text (e.g. a post)
     * @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
     * @return string The new text field text
     */
    public function fix_links($post, $db, $table_prefix, $file_base = '')
    {
        $boardurl = '';

        require($file_base . '/Settings.php');
        $old_base_url = $boardurl;

        $post = preg_replace_callback('#' . preg_quote($old_base_url) . '/(index\.php\?topic=)(\d*)#', array($this, '_fix_links_callback_topic'), $post);
        $post = preg_replace_callback('#' . preg_quote($old_base_url) . '/(index\.php\?board=)(\d*)#', array($this, '_fix_links_callback_forum'), $post);
        $post = preg_replace_callback('#' . preg_quote($old_base_url) . '/(index\.php\?action=profile;u=)(\d*)#', array($this, '_fix_links_callback_member'), $post);
        $post = preg_replace('#:[0-9a-f]{10}#', '', $post);
        return $post;
    }

    /**
     * Convert an SMF database file to a Composr uploaded file (stored on disk).
     *
     * @param  string $data The file data
     * @param  string $filename The optimal filename
     * @param  ID_TEXT $sections The upload type (e.g. cns_photos)
     * @param  object $db The DB connection to import from
     * @param  string $table_prefix The table prefix the target prefix is using
     * @param  string $output_filename The filename to output to
     * @param  PATH $file_base The base directory we are importing from
     * @param  string $attachment_id Attachment ID
     * @return URLPATH The URL
     */
    public function data_to_disk($data, $filename, $sections, $db, $table_prefix = '', $output_filename = '', $file_base = '', $attachment_id = '')
    {
        $boardurl = '';
        $boarddir = '';

        require($file_base . '/Settings.php');
        $homeurl = $boardurl;

        $forum_dir = preg_replace('#\\\\#', '/', $boarddir); // Full path to the forum folder

        $attachments_dir = $forum_dir . '/attachments/'; // Forum attachments directory

        // Start preparing the attachment file path by adding it's md5-ied filename and attachment id
        $file_stripped = preg_replace(array('/\s/', '/[^\w\.\-]/'), array('_', ''), $filename);
        $filename_fixed = ((strlen($attachment_id) > 0) ? ($attachment_id . '_' . str_replace('.', '_', $file_stripped) . md5($file_stripped)) : (str_replace('.', '_', $file_stripped) . md5($file_stripped)));
        $file_path = $attachments_dir . $filename_fixed;

        $data = ($data == '') ? @file_get_contents($file_path) : $data;
        $filename = ($output_filename == '') ? $filename_fixed : $output_filename;

        $filename = find_derivative_filename('uploads/' . $sections, $filename);
        $path = get_custom_file_base() . '/uploads/' . $sections . '/' . $filename;

        require_code('files');
        cms_file_put_contents_safe($path, $data, FILE_WRITE_FIX_PERMISSIONS | FILE_WRITE_SYNC_FILE);

        $url = 'uploads/' . $sections . '/' . $filename;

        return $url;
    }

    /**
     * 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_post_files($db, $table_prefix, $file_base)
    {
        global $STRICT_FILE;
        require_code('attachments2');
        require_code('attachments3');

        $row_start = 0;
        $rows = array();
        do {
            $rows = $db->query('SELECT * FROM ' . $table_prefix . 'attachments a JOIN ' . $table_prefix . 'messages m ON a.ID_MSG=m.ID_MSG WHERE a.ID_MSG<>0' . (can_arbitrary_groupby() ? ' GROUP BY ID_ATTACH' : ''), 200, $row_start);
            $rows = remove_duplicate_rows($rows, 'ID_ATTACH');
            foreach ($rows as $row) {
                if (import_check_if_imported('post_files', strval($row['ID_ATTACH']))) {
                    continue;
                }

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

                $post_row = $GLOBALS['FORUM_DB']->query_select('f_posts', array('p_time', 'p_poster', 'p_post'), array('id' => $post_id), '', 1);
                if (!array_key_exists(0, $post_row)) {
                    import_id_remap_put('post_files', strval($row['ID_ATTACH']), 1);
                    continue; // Orphaned post
                }
                $post = get_translated_text($post_row[0]['p_post'], $GLOBALS['SITE_DB']);
                $member_id = $post_row[0]['p_poster'];

                $url = $this->data_to_disk('', $row['filename'], 'attachments', $db, $table_prefix, '', $file_base, $row['ID_ATTACH']);
                $a_id = $GLOBALS['SITE_DB']->query_insert('attachments', array('a_member_id' => $member_id, 'a_file_size' => $row['size'], 'a_url' => $url, 'a_thumb_url' => $url, 'a_original_filename' => $row['filename'], 'a_num_downloads' => $row['downloads'], 'a_last_downloaded_time' => null, 'a_add_time' => $row['posterTime'], 'a_description' => ''), true);

                $GLOBALS['SITE_DB']->query_insert('attachment_refs', array('r_referer_type' => 'cns_post', 'r_referer_id' => strval($post_id), 'a_id' => $a_id));
                $post .= "\n\n" . '[attachment]' . strval($a_id) . '[/attachment]';

                cns_over_msn();
                $GLOBALS['FORUM_DB']->query_update('f_posts', update_lang_comcode_attachments('p_post', $post_row[0]['p_post'], $post, 'cns_post', strval($post_id)), array('id' => $post_id), '', 1);
                cns_over_local();

                import_id_remap_put('post_files', strval($row['ID_ATTACH']), 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_cns_polls_and_votes($db, $table_prefix, $file_base)
    {
        $rows = $db->query('SELECT * FROM ' . $table_prefix . 'polls');
        foreach ($rows as $row) {
            if (import_check_if_imported('poll', strval($row['ID_POLL']))) {
                continue;
            }

            $poll_topic_id = $db->query('SELECT ID_TOPIC FROM ' . $table_prefix . 'topics WHERE ID_POLL=' . strval($row['ID_POLL']));
            if (!isset($poll_topic_id[0]['ID_TOPIC'])) {
                continue;
            }
            $poll_topic_id = $poll_topic_id[0]['ID_TOPIC'];

            $topic_id = import_id_remap_get('topic', strval($poll_topic_id), true);
            if (is_null($topic_id)) {
                import_id_remap_put('poll', strval($row['ID_POLL']), -1);
                continue;
            }

            $is_open = ($row['expireTime'] == 0 || $row['expireTime'] > time()) ? 1 : 0;

            $answers = array();
            $poll_choices = $db->query('SELECT * FROM ' . $table_prefix . 'poll_choices WHERE ID_POLL=' . strval($row['ID_POLL']));

            $answers_array = array();
            foreach ($poll_choices as $key => $value) {
                $answers_array[] = $value['label'];
            }

            $answer_map = array();
            $maximum = 0;
            foreach ($answers_array as $key => $answer) {
                $answer_map[$key] = $poll_choices[$key]['votes'];
                $answers[$key] = $answer;
                $maximum += $poll_choices[$key]['votes'];
            }

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

            $id_new = cns_make_poll($topic_id, $row['question'], 0, $is_open, 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)));

            foreach ($rows2 as $row2) {
                $member_id = $row2['ID_MEMBER'];
                if ((!is_null($member_id)) && ($member_id != 0)) {
                    $answer = $answers[strval($row2['ID_CHOICE'])];

                    $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['ID_POLL']), $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 . 'personal_messages p LEFT JOIN ' . $table_prefix . 'pm_recipients r ON p.ID_PM=r.ID_PM ORDER BY msgtime');

        // Group them up into what will become topics
        $groups = array();
        foreach ($rows as $row) {
            // Do some fiddling around for duplication
            if ($row['ID_MEMBER_FROM'] > $row['ID_MEMBER']) {
                $a = $row['ID_MEMBER'];
                $b = $row['ID_MEMBER_FROM'];
            } else {
                $a = $row['ID_MEMBER_FROM'];
                $b = $row['ID_MEMBER'];
            }
            $row['subject'] = str_replace('Re: ', '', $row['subject']);
            $groups[strval($a) . ':' . strval($b) . ':' . $row['subject']][] = $row;
        }

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

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

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

            $first_post = true;
            foreach ($group as $_post) {
                if ($first_post) {
                    $title = $row['subject'];
                } else {
                    $title = '';
                }

                $title = @html_entity_decode($title, ENT_QUOTES, get_charset());

                cns_over_msn();
                $post_description = html_to_comcode($_post['body']);
                cns_over_local();

                $post = $this->fix_links($post_description, $db, $table_prefix, $old_base_dir);
                $validated = 1;
                $from_id = import_id_remap_get('member', strval($_post['ID_MEMBER_FROM']), 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 = '';
                $time = $_post['msgtime'];
                $poster = $from_id;
                $last_edit_time = null;
                $last_edit_by = null;

                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);
                $first_post = false;
            }

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

    /**
     * Convert a SMF topic icon code into a standard Composr theme image code.
     *
     * @param  integer $iconid VB code
     * @return ID_TEXT Composr code
     */
    public function convert_topic_emoticon($iconid)
    {
        switch ($iconid) {
            case 1:
                return 'cns_emoticons/smile';
            case 2:
                return 'cns_emoticons/wink';
            case 3:
                return 'cns_emoticons/cheeky';
            case 4:
                return 'cns_emoticons/grin';
            case 5:
                return 'cns_emoticons/angry';
            case 6:
                return 'cns_emoticons/sad';
            case 7:
                return 'cns_emoticons/shocked';
            case 8:
                return 'cns_emoticons/cool';
            case 10:
                return 'cns_emoticons/rolleyes';
            case 13:
                return 'cns_emoticons/shutup';
            case 14:
                return 'cns_emoticons/confused';
            case 15:
                return 'cns_emoticons/kiss';
            case 16:
                return 'cns_emoticons/cry';
            case 17:
                return 'cns_emoticons/devil';
        }
        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 . 'log_notify WHERE ID_TOPIC<>0', 200, $row_start);
            foreach ($rows as $row) {
                if (import_check_if_imported('topic_notification', strval($row['ID_TOPIC']) . '-' . strval($row['ID_MEMBER']))) {
                    continue;
                }

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

                import_id_remap_put('topic_notification', strval($row['ID_TOPIC']) . '-' . strval($row['ID_MEMBER']), 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_wordfilter($db, $table_prefix, $file_base)
    {
        $rows = $db->query('SELECT * FROM ' . $table_prefix . 'settings WHERE ' . db_string_equal_to('variable', 'censor_vulgar') . ' OR ' . db_string_equal_to('variable', 'censor_proper'));

        $censor_vulgar = array();
        $censor_proper = array();
        foreach ($rows as $row) {
            if ($row['variable'] == 'censor_vulgar') {
                $censor_vulgar = preg_split('/[\n\r]+/', $row['value']);
            } else {
                $censor_proper = preg_split('/[\n\r]+/', $row['value']);
            }
        }

        foreach ($censor_vulgar as $key => $row) {
            add_wordfilter_word($censor_vulgar[$key], array_key_exists($key, $censor_proper) ? $censor_proper[$key] : '');
        }
    }

    /**
     * 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_calendar($db, $table_prefix, $file_base)
    {
        require_code('calendar2');

        $rows = $db->query_select('calendar');
        foreach ($rows as $row) {
            if (import_check_if_imported('event', strval($row['ID_EVENT']))) {
                continue;
            }

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

            $recurrence = 'none';
            $recurrences = null;

            $days = intval(floor((strtotime($row['endDate']) - strtotime($row['startDate'])) / (60 * 60 * 24))); //Max 7 days in SMF
            if ($days == 0) {
                $recurrence = 'daily 1';
            } else {
                $recurrence = 'daily ';
                for ($i = 1; $i <= $days; $i++) {
                    $recurrence .= '1';
                }
            }

            $start_hour = 0;
            $start_minute = 0;
            list($start_year, $start_month, $start_day) = array_map('intval', explode('-', $row['eventDate']));
            list($end_year, $end_month, $end_day, $end_hour, $end_minute) = array($start_year, $start_month, $start_day, $start_hour, $start_minute);

            $description = '';
            if ($row['ID_TOPIC'] != 0) {
                $messages = $db->query('SELECT * FROM ' . $table_prefix . 'messages WHERE ID_TOPIC=' . strval($row['ID_TOPIC']) . ' ORDER BY ID_TOPIC ASC');
                cns_over_msn();
                $description = (isset($messages[0]['body']) && ($messages[0]['body'] != '')) ? html_to_comcode($messages[0]['body']) : '';
                cns_over_local();
            }

            cns_over_msn();
            $id_new = add_calendar_event(db_get_first_id() + 1, $recurrence, $recurrences, 0, $row['title'], $description, 3, $start_year, $start_month, $start_day, 'day_of_month', $start_hour, $start_minute, $end_year, $end_month, $end_day, 'day_of_month', $end_hour, $end_minute, null, 1, null, 1, 1, 1, 1, '', $submitter);
            cns_over_local();

            import_id_remap_put('event', strval($row['ID_EVENT']), $id_new);
        }

        $rows = array();
        $rows = $db->query_select('calendar_holidays');
        foreach ($rows as $row) {
            if (import_check_if_imported('event', strval($row['ID_HOLIDAY']))) {
                continue;
            }

            $submitter = $GLOBALS['CNS_DRIVER']->get_guest_id();

            $recurrence = 'none';
            $recurrences = null;

            list($start_year, $start_month, $start_day, $start_hour, $start_minute) = array_map('intval', explode('-', date('Y-m-d-h-i', strtotime($row['eventDate']))));
            list($end_year, $end_month, $end_day, $end_hour, $end_minute) = array_map('intval', explode('-', date('Y-m-d-h-i', strtotime($row['eventDate']))));

            cns_over_msn();
            $id_new = add_calendar_event(db_get_first_id() + 1, $recurrence, $recurrences, 0, $row['title'], $row['title'], 3, $start_year, $start_month, $start_day, 'day_of_month', $start_hour, $start_minute, $end_year, $end_month, $end_day, 'day_of_month', $end_hour, $end_minute, null, 1, null, 1, 1, 1, 1, '', $submitter);
            cns_over_local();

            import_id_remap_put('event', strval($row['ID_HOLIDAY']), $id_new);
        }
    }
}
