Welcome to Centmin Mod Community
Become a Member

Nginx 502 Bad Gateway

Discussion in 'Nginx, PHP-FPM & MariaDB MySQL' started by elargento, Feb 19, 2018.

  1. elargento

    elargento Member

    352
    17
    18
    Jan 4, 2016
    Ratings:
    +44
    Local Time:
    11:32 AM
    10
    I've changed some values and during the import, CPU load average is 0.9. Do you know how can I assign more resources and increase some limits? The node has 6 cores.


    The script itself doesn't have anything to play with except 'limit' =>:
    Code:
    <?php
    
    
    /*
     * New classes:
     *
     * XenForo_Authentication_IPBoard
     *
     */
    
    class XenForo_Importer_IPBoard extends XenForo_Importer_Abstract
    {
        /**
        * Source database connection.
        *
        * @var Zend_Db_Adapter_Abstract
        */
        protected $_sourceDb;
    
        protected $_prefix;
    
        protected $_charset = 'windows-1252';
    
        protected $_config;
    
        protected $_groupMap = null;
    
        protected $_userFieldMap = null;
    
        protected $_adminPermissions = null;
    
        protected $_profileFieldMap = null;
    
        protected $_nodePermissionsGrouped = null;
    
        public static function getName()
        {
            return 'IP.Board 3.1';
        }
    
        public function configure(XenForo_ControllerAdmin_Abstract $controller, array &$config)
        {
            if ($config)
            {
                $errors = $this->validateConfiguration($config);
                if ($errors)
                {
                    return $controller->responseError($errors);
                }
    
                $this->_bootstrap($config);
    
                return true;
            }
            else
            {
                $viewParams = array('input' => array
                (
                    'sql_host' => 'localhost',
                    'sql_port' => 3306,
                    'sql_user' => '',
                    'sql_pass' => '',
                    'sql_database' => '',
                    'sql_tbl_prefix' => '',
    
                    //'ipboard_path' => getcwd(),
                    'ipboard_path' => $_SERVER['DOCUMENT_ROOT'],
                ));
    
                $configPath = getcwd() . '/conf_global.php';
                if (file_exists($configPath))
                {
                    include($configPath);
    
                    $viewParams['input'] = array_merge($viewParams['input'], $INFO);
                }
    
                return $controller->responseView('XenForo_ViewAdmin_Import_IPBoard_Config', 'import_ipboard_config', $viewParams);
            }
        }
    
        public function validateConfiguration(array &$config)
        {
            $errors = array();
    
            $config['db']['prefix'] = preg_replace('/[^a-z0-9_]/i', '', $config['db']['prefix']);
    
            try
            {
                $db = Zend_Db::factory('mysqli',
                    array(
                        'host' => $config['db']['host'],
                        'port' => $config['db']['port'],
                        'username' => $config['db']['username'],
                        'password' => $config['db']['password'],
                        'dbname' => $config['db']['dbname'],
                        'charset' => $config['db']['charset']
                    )
                );
                $db->getConnection();
            }
            catch (Zend_Db_Exception $e)
            {
                $errors[] = new XenForo_Phrase('source_database_connection_details_not_correct_x', array('error' => $e->getMessage()));
            }
    
            if ($errors)
            {
                return $errors;
            }
    
            try
            {
                $db->query('
                    SELECT member_id
                    FROM ' . $config['db']['prefix'] . 'members
                    LIMIT 1
                ');
            }
            catch (Zend_Db_Exception $e)
            {
                if ($config['db']['dbname'] === '')
                {
                    $errors[] = new XenForo_Phrase('please_enter_database_name');
                }
                else
                {
                    $errors[] = new XenForo_Phrase('table_prefix_or_database_name_is_not_correct');
                }
            }
    
            if (!empty($config['ipboard_path']))
            {
                if (!file_exists($config['ipboard_path']) || !is_dir($config['ipboard_path'] . '/uploads'))
                {
                    $errors[] = new XenForo_Phrase('error_could_not_find_uploads_directory_at_specified_path');
                }
            }
    
            if (!$errors)
            {
                $defaultCharset = $db->fetchOne("
                    SELECT IF(conf_value = '' OR conf_value IS NULL, conf_default, conf_value)
                    FROM {$config['db']['prefix']}core_sys_conf_settings
                    WHERE conf_key = 'gb_char_set'
                ");
                if (!$defaultCharset || str_replace('-', '', strtolower($defaultCharset)) == 'iso88591')
                {
                    $config['charset'] = 'windows-1252';
                }
                else
                {
                    $config['charset'] = strtolower($defaultCharset);
                }
            }
    
            return $errors;
        }
    
        public function getSteps()
        {
            return array(
                'userGroups' => array(
                    'title' => new XenForo_Phrase('import_user_groups')
                ),
                'userFields' => array(
                    'title' => new XenForo_Phrase('import_custom_user_fields')
                ),
                'users' => array(
                    'title' => new XenForo_Phrase('import_users'),
                    'depends' => array('userGroups', 'userFields')
                ),
                'avatars' => array(
                    'title' => new XenForo_Phrase('import_custom_avatars'),
                    'depends' => array('users')
                ),
                'privateMessages' => array(
                    'title' => new XenForo_Phrase('import_private_messages'),
                    'depends' => array('users')
                ),
                'profileComments' => array(
                    'title' => new XenForo_Phrase('import_profile_comments'),
                    'depends' => array('users')
                ),
                'statusUpdates' => array(
                    'title' => new XenForo_Phrase('import_user_status_updates'),
                    'depends' => array('users')
                ),
                'forums' => array(
                    'title' => new XenForo_Phrase('import_forums'),
                    'depends' => array('userGroups')
                ),
                'forumPermissions' => array(
                    'title' => new XenForo_Phrase('import_forum_permissions'),
                    'depends' => array('forums')
                ),
                'moderators' => array(
                    'title' => new XenForo_Phrase('import_moderators'),
                    'depends' => array('forums', 'users')
                ),
                'threads' => array(
                    'title' => new XenForo_Phrase('import_threads_and_posts'),
                    'depends' => array('forums', 'users')
                ),
                'polls' => array(
                    'title' => new XenForo_Phrase('import_polls'),
                    'depends' => array('threads')
                ),
                'attachments' => array(
                    'title' => new XenForo_Phrase('import_attached_files'),
                    'depends' => array('threads')
                ),
                'reputation' => array(
                    'title' => new XenForo_Phrase('import_positive_reputation'),
                    'depends' => array('threads')
                ),
            );
    
            // TODO: user upgrades?
            // deferred: announcements, custom bb code, calendars/events, social groups, infractions
        }
    
        protected function _bootstrap(array $config)
        {
            if ($this->_sourceDb)
            {
                // already run
                return;
            }
    
            @set_time_limit(0);
    
            $this->_config = $config;
    
            $this->_sourceDb = Zend_Db::factory('mysqli',
                array(
                    'host' => $config['db']['host'],
                    'port' => $config['db']['port'],
                    'username' => $config['db']['username'],
                    'password' => $config['db']['password'],
                    'dbname' => $config['db']['dbname'],
                    'charset' => $config['db']['charset']
                )
            );
            if (empty($config['db']['charset']))
            {
                $this->_sourceDb->query('SET character_set_results = NULL');
            }
    
            $this->_prefix = preg_replace('/[^a-z0-9_]/i', '', $config['db']['prefix']);
    
            if (!empty($config['charset']))
            {
                $this->_charset = $config['charset'];
            }
        }
    
        public function configStepUserGroups(array $options)
        {
            if ($options)
            {
                return false;
            }
    
            $viewParams = array('input' => array
            (
                'auth_group' => 1,
                'guest_group' => 2,
                'member_group' => 3,
                'admin_group' => 4,
                'banned_group' => 5,
            ));
    
            $config = $this->_session->getConfig();
    
            $configPath = $config['ipboard_path'] . '/conf_global.php';
            if (file_exists($configPath))
            {
                /** @var array $INFO */
                include($configPath);
    
                $viewParams['input'] = array_merge($viewParams['input'], $INFO);
            }
    
            return $this->_controller->responseView('XenForo_ViewAdmin_Import_IPBoard_ConfigUserGroups', 'import_ipboard_config_usergroups', $viewParams);
        }
    
        public function stepUserGroups($start, array $options)
        {
            $options = array_merge(array
            (
                'auth_group' => 1,
                'guest_group' => 2,
                'member_group' => 3,
                'admin_group' => 4,
                'banned_group' => 5,
            ), $options);
    
            $this->_session->setExtraData('groups', $options);
    
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            /* @var $model XenForo_Model_Import */
            $model = $this->_importModel;
            $model->retainableKeys[] = 'user_group_id';
    
            $userGroups = $sDb->fetchAll('
                SELECT *
                FROM ' . $prefix . 'groups
                ORDER BY g_id
            ');
    
            $total = 0;
    
            XenForo_Db::beginTransaction();
    
            foreach ($userGroups AS $userGroup)
            {
                $titlePriority = 5;
                switch ($userGroup['g_id'])
                {
                    case $options['guest_group']: // guests (default 2)
                        $model->logImportData('userGroup', $userGroup['g_id'], XenForo_Model_User::$defaultGuestGroupId);
                        break;
    
                    case $options['auth_group']: // email confirm / validating (default 1)
                    case $options['member_group']: // registered users (default 3)
                        $model->logImportData('userGroup', $userGroup['g_id'], XenForo_Model_User::$defaultRegisteredGroupId);
                        break;
    
                    case $options['admin_group']: // admins (default 4)
                        $model->logImportData('userGroup', $userGroup['g_id'], XenForo_Model_User::$defaultAdminGroupId);
                        continue;
    
                    // TODO: make banned users?
                    #case 5: // banned
                    #    $model->logImportData('userGroup', $userGroup['g_id'], XenForo_Model_User::)
                    #    continue;
    
                    case 6: // mods
                        $model->logImportData('userGroup', $userGroup['g_id'], XenForo_Model_User::$defaultModeratorGroupId);
                        continue;
    
                    default:
                        $import = array(
                            'title' => $this->_convertToUtf8($userGroup['g_title']),
                            'user_title' => $this->_convertToUtf8($userGroup['g_title']),
                            'display_style_priority' => $titlePriority,
                            'permissions' => $this->_calculateUserGroupPermissions($userGroup)
                        );
    
                        if ($model->importUserGroup($userGroup['g_id'], $import))
                        {
                            $total++;
                        }
                }
            }
    
            XenForo_Model::create('XenForo_Model_UserGroup')->rebuildDisplayStyleCache();
    
            XenForo_Db::commit();
    
            $this->_session->incrementStepImportTotal($total);
    
            return true;
        }
    
        protected function _calculateUserGroupPermissions(array $userGroup)
        {
            $perms = array();
    
            if ($userGroup['g_view_board'])
            {
                $perms['general']['view'] = 'allow';
                $perms['general']['viewNode'] = 'allow';
                $perms['forum']['viewAttachment'] = 'allow'; // TODO: this appears to be fixed to board viewing perms
                $perms['forum']['viewContent'] = 'allow';
                $perms['forum']['viewOthers'] = 'allow';
            }
    
            if ($userGroup['g_mem_info'])
            {
                $perms['general']['viewProfile'] = 'allow';
                $perms['general']['viewMemberList'] = 'allow';
                $perms['profilePost']['view'] = 'allow';
                $perms['profilePost']['post'] = 'allow';
                $perms['profilePost']['comment'] = 'allow';
            }
    
            if ($userGroup['g_avoid_flood'])
            {
                $perms['general']['bypassFloodCheck'] = 'allow';
            }
    
            if ($userGroup['g_use_search'])
            {
                $perms['general']['search'] = 'allow';
            }
    
            // forum permissions
    
            if ($userGroup['g_post_new_topics'])
            {
                $perms['forum']['postThread'] = 'allow';
            }
            if ($userGroup['g_reply_own_topics'] || $userGroup['g_reply_other_topics'])
            {
                $perms['forum']['postReply'] = 'allow';
            }
            if ($userGroup['g_delete_own_posts'] || $userGroup['g_bitoptions'] & 128) // gbw_soft_delete_own
            {
                $perms['forum']['deleteOwnPost'] = 'allow';
            }
            if ($userGroup['g_delete_own_topics'] || $userGroup['g_bitoptions'] & 256) // gbw_soft_delete_own_topic
            {
                $perms['forum']['deleteOwnThread'] = 'allow';
            }
            if ($userGroup['g_edit_posts'])
            {
                $perms['forum']['editOwnPost'] = 'allow';
            }
            if ($userGroup['g_edit_cutoff'])
            {
                $perms['forum']['editOwnPostTimeLimit'] = $userGroup['g_edit_cutoff'];
            }
            if (($userGroup['g_attach_max'] + 0) >= 0)
            {
                $perms['forum']['uploadAttachment'] = 'allow';
            }
            if ($userGroup['g_vote_polls'])
            {
                $perms['forum']['votePoll'] = 'allow';
            }
    
            // forum moderator permissions
    
            if ($userGroup['g_open_close_posts'])
            {
                $perms['forum']['lockUnlockThread'] = 'allow';
            }
    
            if ($userGroup['g_bitoptions'] & 1024 || $userGroup['g_bitoptions'] & 8192) // gbw_soft_delete_see OR gbw_soft_delete_topic_see
            {
                $perms['forum']['viewDeleted'] = 'allow';
            }
    
            if ($userGroup['g_is_supmod'])
            {
                $perms['forum']['stickUnstickThread'] = 'allow';
                $perms['forum']['manageAnyThread'] = 'allow';
                // TODO: others permissions?
            }
    
            // this is mapped from max number of +ve reputation points awardable in 24h
            if ($userGroup['g_rep_max_positive'])
            {
                $perms['forum']['like'] = 'allow';
                $perms['profilePost']['like'] = 'allow';
            }
    
            if ($userGroup['g_use_pm'])
            {
                $perms['conversation']['start'] = 'allow';
                $perms['conversation']['receive'] = 'allow';
                $perms['conversation']['maxRecipients'] = $userGroup['g_max_mass_pm']; // should be max 500
            }
    
            $perms['avatar'] = $this->_getUserGroupAvatarPerms($userGroup);
    
            return $perms;
        }
    
        protected function _getUserGroupAvatarPerms(array $userGroup)
        {
            $avatarPerms = array();
    
            if ($userGroup['g_avatar_upload'])
            {
                $avatarPerms['allowed'] = 'allow';
                $avatarPerms['maxFileSize'] = intval($userGroup['g_photo_max_vars']); // take the first value from '500:170:240'
                if ($avatarPerms['maxFileSize'] > 2147483647)
                {
                    $avatarPerms['maxFileSize'] = -1;
                }
            }
    
            return $avatarPerms;
        }
    
        public function stepUserFields($start, array $options)
        {
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            /* @var $model XenForo_Model_Import */
            $model = $this->_importModel;
    
            $ignoreFields = array(
                'gender',
                'website',
                'location',
                'interests',
            );
    
            $profileFields = $sDb->fetchAll('
                SELECT pfields_data.*,
                    pfields_groups.pf_group_key
                FROM ' . $prefix . 'pfields_data AS pfields_data
                INNER JOIN ' . $prefix . 'pfields_groups AS pfields_groups ON
                    (pfields_groups.pf_group_id = pfields_data.pf_group_id)
                #WHERE pfields_data.pf_key NOT IN(' . $sDb->quote($ignoreFields) . ')
            ');
    
            $existingFields = $model->getUserFieldDefinitions();
    
            $total = 0;
    
            XenForo_Db::beginTransaction($this->_db);
    
            foreach ($profileFields AS $profileField)
            {
                switch ($profileField['pf_key'])
                {
                    case 'icq':
                    case 'aim':
                    case 'facebook':
                    case 'msn':
                    case 'yahoo':
                    case 'skype':
                    case 'twitter':
                    case 'gender':
                    case 'website':
                    case 'location':
                    case 'interests':
                    {
                        // just store the mapping, no need to import these
                        $model->logImportData('userField', $profileField['pf_id'], $this->_convertToUtf8($profileField['pf_key']));
                        break;
                    }
    
                    default:
                    {
                        $fieldId = $this->_convertToUtf8($model->getUniqueFieldId($profileField['pf_key'], $existingFields, 25));
    
                        $convertChoices = false;
    
                        switch ($profileField['pf_type'])
                        {
                            case 'textarea':
                                $fieldType = 'textarea';
                                break;
    
                            case 'drop':
                                $fieldType = 'select';
                                $convertChoices = true;
                                break;
    
                            case 'cbox':
                                $fieldType = 'checkbox';
                                $convertChoices = true;
                                break;
    
                            case 'radio':
                                $fieldType = 'radio';
                                $convertChoices = true;
                                break;
    
                            case 'input':
                            default:
                                $fieldType ='textbox';
                                break;
                        }
    
                        if ($profileField['pf_admin_only'])
                        {
                            $profileField['pf_member_hide'] = true;
                            $profileField['pf_member_edit'] = false;
                        }
    
                        $import = array(
                            'field_id' => $fieldId,
                            'title' => $this->_convertToUtf8($profileField['pf_title']),
                            'description' => $this->_convertToUtf8($profileField['pf_desc']),
                            'field_type' => $fieldType,
                            'display_order' => $profileField['pf_position'],
                            'display_group' => ($profileField['pf_group_key'] == 'contact' ? 'contact' : 'personal'),
                            'max_length' => $profileField['pf_max_input'],
                            'required' => $profileField['pf_not_null'],
                            'show_registration' => $profileField['pf_show_on_reg'],
                            'user_editable' => ($profileField['pf_member_edit'] ? 'yes' : 'never'),
                            'viewable_profile' => !$profileField['pf_member_hide']
                        );
    
                        if ($profileField['pf_input_format'])
                        {
                            $import['match_type'] = 'regex';
                            $import['match_regex'] = $this->_convertUserFieldMatchTypeToRegex($profileField['pf_input_format']);
                        }
    
                        if ($convertChoices)
                        {
                            $import['field_choices'] = $this->_convertUserFieldChoices($profileField);
                        }
    
                        if ($newFieldId = $model->importUserField($profileField['pf_id'], $import))
                        {
                            $total++;
                        }
                        break;
                    }
                }
            }
    
            XenForo_Db::commit($this->_db);
    
            $this->_session->incrementStepImportTotal($total);
    
            return true;
        }
    
        /**
        * Converts IPB's aann-naa style of input matching into a regular expression
        *
        * @param string $inputFormat
        *
        * @return string
        */
        protected function _convertUserFieldMatchTypeToRegex($inputFormat)
        {
            $inputFormat = preg_quote($inputFormat);
    
            $strlen = utf8_strlen($inputFormat);
    
            $regex = '^';
            $i = 0;
    
            while ($i < $strlen)
            {
                $count = 0;
    
                switch ($inputFormat{$i})
                {
                    case 'n':
                    case 'a':
                        $repeatChar = $inputFormat{$i};
                        while ($i < $strlen && $inputFormat{$i} === $repeatChar)
                        {
                            $i++;
                            $count++;
                        }
    
                        $regex .= ($repeatChar == 'n' ? '\d' : '[a-zA-Z]') . ($count > 1 ? "{{$count}}" : '');
                        break;
    
                    default:
                        $regex .= $inputFormat{$i};
                        $i++;
                        break;
                }
            }
    
            return $regex . '$';
        }
    
        /**
        * Convert's IPB's a=A|b=B|c=C user field choice format into XF's array format
        *
        * @param array $profileField
        *
        * @return array
        */
        protected function _convertUserFieldChoices(array $profileField)
        {
            if (!strlen($profileField['pf_content']))
            {
                return array();
            }
    
            $choices = array();
    
            foreach (explode('|', $this->_convertToUtf8($profileField['pf_content'])) AS $choiceString)
            {
                if (strpos($choiceString, '=') === false)
                {
                    continue;
                }
    
                list($key, $value) = explode('=', $choiceString, 2);
    
                $choices[$key] = $value;
            }
    
            return $choices;
        }
    
        public function configStepUsers(array $options)
        {
            if ($options)
            {
                return false;
            }
    
            return $this->_controller->responseView('XenForo_ViewAdmin_Import_IPBoard_ConfigUsers', 'import_config_users');
        }
    
        public function stepUsers($start, array $options)
        {
            $options = array_merge(array(
                'limit' => 100,
                'max' => false,
                // all checkbox options must default to false as they may not be submitted
                'mergeEmail' => false,
                'mergeName' => false,
                'gravatar' => false
            ), $options);
    
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            if ($options['max'] === false)
            {
                $options['max'] = $sDb->fetchOne('
                    SELECT MAX(member_id)
                    FROM ' . $prefix . 'members
                ');
            }
    
            $users = $sDb->fetchAll(
                $sDb->limit($this->_getSelectUserSql('members.member_id > ' . $sDb->quote($start)), $options['limit'])
            );
            if (!$users)
            {
                return $this->_getNextUserStep();
            }
    
            XenForo_Db::beginTransaction();
    
            $next = 0;
            $total = 0;
            foreach ($users AS $user)
            {
                $next = $user['member_id'];
    
                $imported = $this->_importOrMergeUser($user, $options);
                if ($imported)
                {
                    $total++;
                }
            }
    
            XenForo_Db::commit();
    
            $this->_session->incrementStepImportTotal($total);
    
            return array($next, $options, $this->_getProgressOutput($next, $options['max']));
        }
    
        public function stepUsersMerge($start, array $options)
        {
            $sDb = $this->_sourceDb;
    
            $manual = $this->_session->getExtraData('userMerge');
    
            if ($manual)
            {
                $merge = $sDb->fetchAll($this->_getSelectUserSql('members.member_id IN (' . $sDb->quote(array_keys($manual)) . ')'));
    
                $resolve = $this->_controller->getInput()->filterSingle('resolve', XenForo_Input::ARRAY_SIMPLE);
                if ($resolve && !empty($options['shownForm']))
                {
                    $this->_session->unsetExtraData('userMerge');
                    $this->_resolveUserConflicts($merge, $resolve);
                }
                else
                {
                    // prevents infinite loop if redirected back to step
                    $options['shownForm'] = true;
                    $this->_session->setStepInfo(0, $options);
    
                    $users = array();
                    foreach ($merge AS $user)
                    {
                        $users[$user['member_id']] = array(
                            'username' => $this->_convertToUtf8($user['name'], true),
                            'email' => $this->_convertToUtf8($user['email']),
                            'message_count' => $user['posts'],
                            'register_date' => $user['joined'],
                            'conflict' => $manual[$user['member_id']]
                        );
                    }
    
                    return $this->_controller->responseView(
                        'XenForo_ViewAdmin_Import_MergeUsers', 'import_merge_users', array('users' => $users)
                    );
                }
            }
    
            return $this->_getNextUserStep();
        }
    
        public function stepUsersFailed($start, array $options)
        {
            $sDb = $this->_sourceDb;
    
            $manual = $this->_session->getExtraData('userFailed');
    
            if ($manual)
            {
                $users = $this->_sourceDb->fetchAll($this->_getSelectUserSql('members.member_id IN (' . $sDb->quote(array_keys($manual)) . ')'));
    
                $resolve = $this->_controller->getInput()->filterSingle('resolve', XenForo_Input::ARRAY_SIMPLE);
                if ($resolve && !empty($options['shownForm']))
                {
                    $this->_session->unsetExtraData('userFailed');
                    $this->_resolveUserConflicts($users, $resolve);
                }
                else
                {
                    // prevents infinite loop if redirected back to step
                    $options['shownForm'] = true;
                    $this->_session->setStepInfo(0, $options);
    
                    $failedUsers = array();
                    foreach ($users AS $user)
                    {
                        $failedUsers[$user['member_id']] = array(
                            'username' => $this->_convertToUtf8($user['name'], true),
                            'email' => $this->_convertToUtf8($user['email']),
                            'message_count' => $user['posts'],
                            'register_date' => $user['joined'],
                            'failure' => $manual[$user['member_id']]
                        );
                    }
    
                    return $this->_controller->responseView(
                        'XenForo_ViewAdmin_Import_FailedUsers', 'import_failed_users', array('users' => $failedUsers)
                    );
                }
            }
    
            return $this->_getNextUserStep();
        }
    
        protected function _resolveUserConflicts(array $users, array $resolve)
        {
            /* @var $model XenForo_Model_Import */
            $model = $this->_importModel;
    
            $total = 0;
    
            XenForo_Db::beginTransaction();
    
            foreach ($users AS $user)
            {
                if (empty($resolve[$user['member_id']]))
                {
                    continue;
                }
    
                $info = $resolve[$user['member_id']];
    
                if (empty($info['action']) || $info['action'] == 'change')
                {
                    if (isset($info['email']))
                    {
                        $user['email'] = $info['email'];
                    }
                    if (isset($info['username']))
                    {
                        $user['name'] = $info['username'];
                    }
    
                    $imported = $this->_importOrMergeUser($user);
                    if ($imported)
                    {
                        $total++;
                    }
                }
                else if ($info['action'] == 'merge')
                {
                    $im = $this->_importModel;
    
                    if ($match = $im->getUserIdByEmail($this->_convertToUtf8($user['email'])))
                    {
                        $this->_mergeUser($user, $match);
                    }
                    else if ($match = $im->getUserIdByUserName($this->_convertToUtf8($user['name'], true)))
                    {
                        $this->_mergeUser($user, $match);
                    }
    
                    $total++;
                }
            }
    
            XenForo_Db::commit();
    
            $this->_session->incrementStepImportTotal($total, 'users');
        }
    
        protected function _getNextUserStep()
        {
            if ($this->_session->getExtraData('userMerge'))
            {
                return 'usersMerge';
            }
    
            if ($this->_session->getExtraData('userFailed'))
            {
                return 'usersFailed';
            }
    
            return true;
        }
    
        protected function _importOrMergeUser(array $user, array $options = array())
        {
            $im = $this->_importModel;
    
            if ($user['email'] && $emailMatch = $im->getUserIdByEmail($this->_convertToUtf8($user['email'])))
            {
                if (!empty($options['mergeEmail']))
                {
                    return $this->_mergeUser($user, $emailMatch);
                }
                else
                {
                    if ($im->getUserIdByUserName($this->_convertToUtf8($user['name'], true)))
                    {
                        $this->_session->setExtraData('userMerge', $user['member_id'], 'both');
                    }
                    else
                    {
                        $this->_session->setExtraData('userMerge', $user['member_id'], 'email');
                    }
                    return false;
                }
            }
    
            $name = utf8_substr($this->_convertToUtf8(trim($user['name']), true), 0, 50);
    
            if ($nameMatch = $im->getUserIdByUserName($name))
            {
                if (!empty($options['mergeName']))
                {
                    return $this->_mergeUser($user, $nameMatch);
                }
                else
                {
                    $this->_session->setExtraData('userMerge', $user['member_id'], 'name');
                    return false;
                }
            }
    
            return $this->_importUser($user, $options);
        }
    
        protected function _importUser(array $user, array $options)
        {
            if ($this->_groupMap === null)
            {
                $this->_groupMap = $this->_importModel->getImportContentMap('userGroup');
            }
    
            if ($this->_userFieldMap === null)
            {
                $this->_userFieldMap = $this->_importModel->getImportContentMap('userField');
            }
    
            // handle degenerate user group info
            if (empty($user['member_group_id']) || !isset($this->_groupMap[$user['member_group_id']]))
            {
                $groupConfig = $this->_session->getExtraData('groups');
    
                $user['member_group_id'] = $groupConfig['member_group'];
            }
    
            // unserialize the 'cache' blob
            $user['members_cache'] = unserialize($user['members_cache']);
    
            $import = array(
                'username' => $this->_convertToUtf8($user['name'], true),
                'email' => $this->_convertToUtf8($user['email']),
                'user_group_id' => $this->_mapLookUp($this->_groupMap, $user['member_group_id'], XenForo_Model_User::$defaultRegisteredGroupId),
                'secondary_group_ids' => $this->_mapLookUpList($this->_groupMap, $this->_ipbExplode($user['mgroup_others'])),
                'authentication' => array(
                    'scheme_class' => 'XenForo_Authentication_IPBoard',
                    'data' => array(
                        'hash' => $user['members_pass_hash'],
                        'salt' => $user['members_pass_salt']
                    )
                ),
                'about' => $this->_convertToUtf8($user['pp_about_me']),
    
                'last_activity' => $user['last_activity'],
                'register_date' => $user['joined'],
                'ip' => $user['ip_address'],
                'message_count' => $user['posts'],
    
                'timezone' => $this->_importModel->resolveTimeZoneOffset($user['time_offset'], $user['dst_in_use']), // TODO: check members.dst_in_use
    
                'signature' => $this->_parseIPBoardBbCode($user['signature']),
                'content_show_signature' => $user['view_sigs'],
    
                'receive_admin_email' => $user['allow_admin_mails'],
                'allow_send_personal_conversation' => ($user['members_disable_pm'] ? 'none' : 'everyone'),
                'allow_post_profile' => ($user['pp_setting_count_comments'] ? 'everyone' : 'none'),
    
                'dob_day'   => $user['bday_day'],
                'dob_month' => $user['bday_month'],
                'dob_year'  => $user['bday_year'],
    
                'show_dob_year' => 1,
                'show_dob_date' => 1,
    
                'is_banned' => ($user['member_banned'] || $user['temp_ban']),
            );
    
            // try to give users without an avatar that have actually posted a gravatar
            if ($user['avatar_type'] == 'gravatar')
            {
                $import['gravatar'] = $this->_convertToUtf8($user['avatar_location']);
            }
    
            // custom title
            if ($user['title'])
            {
                $import['custom_title'] = strip_tags(
                    preg_replace('#<br\s*/?>#i', ', ',
                        htmlspecialchars_decode(
                            $this->_convertToUtf8($user['title'])
                        )
                    )
                );
            }
    
            // custom user fields
            $userFieldDefinitions = $this->_importModel->getUserFieldDefinitions();
    
            foreach ($this->_userFieldMap AS $oldFieldId => $newFieldId)
            {
                if (isset($user["field_$oldFieldId"]) && $user["field_$oldFieldId"] !== '')
                {
                    $userFieldValue = $this->_convertToUtf8($user["field_$oldFieldId"]);
    
                    switch ($newFieldId)
                    {
                        // map these custom fields to our hard-coded fields
                        case 'gender':
                            $import['gender'] = $this->_handleProfileFieldGender($userFieldValue);
                            break;
    
                        case 'website':
                            $import['homepage'] = $userFieldValue;
                            break;
    
                        case 'location':
                            $import['location'] = $userFieldValue;
                            break;
    
                        case 'interests':
                            $import['about'] .= "\n\n" . $userFieldValue;
                            break;
    
                        // handle IPB custom fields that we also treat as custom
                        default:
                        {
                            if (!isset($userFieldDefinitions[$newFieldId]))
                            {
                                continue;
                            }
    
                            if ($userFieldDefinitions[$newFieldId]['field_type'] == 'checkbox')
                            {
                                $keys = preg_split('/\|/', $userFieldValue, -1, PREG_SPLIT_NO_EMPTY);
    
                                $userFieldValue = array_combine($keys, $keys);
                            }
    
                            $import[XenForo_Model_Import::USER_FIELD_KEY][$newFieldId] = $userFieldValue;
                        }
                    }
                }
            }
    
            $groups = $this->_session->getExtraData('groups');
    
            // user state
            switch ($user['member_group_id'])
            {
                case $groups['auth_group']:
                    $import['user_state'] = 'email_confirm';
                    break;
                default:
                    $import['user_state'] = 'valid';
            }
    
            // default watch state
            switch ($user['auto_track'])
            {
                case '':
                case 0:
                    $import['default_watch_state'] = '';
                    break;
                case 'none':
                    $import['default_watch_state'] = 'watch_no_email';
                    break;
                default:
                    $import['default_watch_state'] = 'watch_email';
            }
    
            // is admin
            if ($import['is_admin'] = $this->_isAdmin($user, $adminRestrictions))
            {
                if (empty($adminRestrictions))
                {
                    $import['admin_permissions'] = $this->_importModel->getAdminPermissionIds();
                }
                else
                {
                    $importAdminPerms = array();
    
                    if ($this->_hasAdminPermission($adminRestrictions, 'core', 'tools'))
                    {
                        $importAdminPerms[] = 'option';
                        $importAdminPerms[] = 'import';
                        $importAdminPerms[] = 'upgradeXenForo';
                    }
    
                    if ($this->_hasAdminPermission($adminRestrictions, 'core', 'applications'))
                    {
                        $importAdminPerms[] = 'addOn';
                    }
    
                    if ($this->_hasAdminPermission($adminRestrictions, 'core', 'posts', 'bbcode_manage')
                    #||    $this->_hasAdminPermission($adminRestrictions, 'core', 'posts', 'media_manage')
                    #||    $this->_hasAdminPermission($adminRestrictions, 'core', 'posts', 'emoticons_manage')
                    )
                    {
                        $importAdminPerms[] = 'bbCodeSmilie';
                    }
    
                    if ($this->_hasAdminPermission($adminRestrictions, 'core', 'system', 'task_manage'))
                    {
                        $importAdminPerms[] = 'cron';
                    }
    
                    if ($this->_hasAdminPermission($adminRestrictions, 'core', 'templates'))
                    {
                        $importAdminPerms[] = 'style';
                    }
    
                    if ($this->_hasAdminPermission($adminRestrictions, 'core', 'languages'))
                    {
                        $importAdminPerms[] = 'language';
                    }
    
                    if ($this->_hasAdminPermission($adminRestrictions, 'forums', 'forums'))
                    {
                        $importAdminPerms[] = 'node';
                    }
    
                    if ($this->_hasAdminPermission($adminRestrictions, 'members', 'members'))
                    {
                        $importAdminPerms[] = 'user';
                        $importAdminPerms[] = 'trophy';
                        $importAdminPerms[] = 'userUpgrade';
                    }
    
                    if ($this->_hasAdminPermission($adminRestrictions, 'members', 'members', 'member_ban'))
                    {
                        $importAdminPerms[] = 'ban';
                    }
    
                    if ($this->_hasAdminPermission($adminRestrictions, 'members', 'members', 'profilefields_global'))
                    {
                        $importAdminPerms[] = 'identityService';
                    }
    
                    if ($this->_hasAdminPermission($adminRestrictions, 'members', 'groups'))
                    {
                        $importAdminPerms[] = 'userGroup';
                    }
    
                    $import['admin_permissions'] = $importAdminPerms;
                }
            }
    
            $importedUserId = $this->_importModel->importUser($user['member_id'], $import, $failedKey);
    
            if ($importedUserId)
            {
                // import bans
                if ($import['is_banned'])
                {
                    if (strpos($user['temp_ban'], ':') !== false)
                    {
                        // temporary ban / suspended user
                        $banBits = explode(':', $user['temp_ban']);
                        $endDate = intval($banBits[1]);
                    }
                    else
                    {
                        // permanent ban
                        $endDate = 0;
                    }
    
                    $this->_importModel->importBan(array(
                        'user_id' => $importedUserId,
                        'ban_user_id' => 0,
                        'ban_date' => 0,
                        'end_date' => $endDate,
                    ));
                }
    
                // import super moderators
                if ($this->_isSuperModerator($user))
                {
                    $this->_session->setExtraData('superMods', $user['member_id'], $importedUserId);
                }
    
                if (!empty($user['members_cache']['friends']) && is_array($user['members_cache']['friends']))
                {
                    $friendIds = array_keys($user['members_cache']['friends']);
                    $friendIds = $this->_importModel->getImportContentMap('user', $friendIds);
                    $this->_importModel->importFollowing($importedUserId, $friendIds);
                }
            }
            else if ($failedKey)
            {
                $this->_session->setExtraData('userFailed', $user['member_id'], $failedKey);
            }
    
            return $importedUserId;
        }
    
        /**
        * Returns the value of a member custom profile field for the specified member
        *
        * @param array $user
        * @param string $title Name of the custom profile field
        * @param integer If specified, fetch the field by its numeric id instead
        *
        * @return string UTF-8 converted
        */
        protected function _getProfileField(array $user, $title, $id = null)
        {
            if ($id === null && empty($this->_profileFieldMap))
            {
                $map = $this->_sourceDb->fetchPairs('
                    SELECT pf_title, pf_id
                    FROM ' . $this->_prefix . 'pfields_data
                ');
    
                $this->_profileFieldMap = array();
    
                foreach ($map AS $title => $id)
                {
                    $this->_profileFieldMap[strtolower($title)] = $id;
                }
            }
    
            if ($id)
            {
                $title = $id;
            }
    
            $title = strtolower($title);
    
            if (array_key_exists($title, $this->_profileFieldMap))
            {
                $field = sprintf('field_%d', $this->_profileFieldMap[$title]);
    
                if (method_exists($this, "_handleProfileField{$title}"))
                {
                    return call_user_func(array($this, "_handleProfileField{$title}"), $user[$field]);
                }
    
                return $this->_convertToUtf8($user[$field]);
            }
    
            return null;
        }
    
        /**
        * Interpret the data stored in IPB's gender field
        *
        * @param string $gender
        *
        * @return string
        */
        protected function _handleProfileFieldGender($gender)
        {
            switch ($gender)
            {
                case 'm': return 'male';
                case 'f': return 'female';
                default: return '';
            }
        }
    
        /**
        * Fetches an array of all user groups to which the user belongs
        *
        * @param array $user
        *
        * @return array
        */
        protected function _getGroupsForUser(array $user)
        {
            $groupCache = $this->_getGroupCache();
    
            $groups = array(
                $user['member_group_id'] => $groupCache[$user['member_group_id']]
            );
    
            if ($user['mgroup_others'])
            {
                foreach ($this->_ipbExplode($user['mgroup_others']) AS $groupId)
                {
                    if (isset($groupCache[$groupId]))
                    {
                        $groups[$groupId] = $groupCache[$groupId];
                    }
                }
            }
    
            return $groups;
        }
    
        /**
        * Check if the specified user is a super moderator but checking all
        * their user group memberships for g_is_supmod
        *
        * @param array $user
        *
        * @return boolean
        */
        protected function _isSuperModerator(array $user)
        {
            foreach ($this->_getGroupsForUser($user) AS $group)
            {
                if ($group['g_is_supmod'])
                {
                    return true;
                }
            }
    
            return false;
        }
    
        /**
        * Check if the specified user is an administrator, by looking at all of their
        * user group memberships and checking if any of them have cp access privs.
        *
        * @param array $user
        * @param array $adminRestrictions
        *
        * @return boolean
        */
        protected function _isAdmin(array $user, array &$adminRestrictions = null)
        {
            $groups = $this->_session->getExtraData('groups');
    
            if ($user['member_group_id'] == $groups['admin_group'])
            {
                if (!empty($user['admin_restrictions']))
                {
                    $adminRestrictions = unserialize($user['admin_restrictions']);
                }
    
                return 1;
            }
            else
            {
                foreach ($this->_getGroupsForUser($user) AS $group)
                {
                    if ($group['g_access_cp'])
                    {
                        if (!empty($group['admin_restrictions']))
                        {
                            $adminRestrictions = unserialize($group['admin_restrictions']);
                        }
    
                        return 1;
                    }
                }
            }
    
            return 0;
        }
    
        /**
        * Checks that the $permissions array given has the admin permission specified
        *
        * @param array $adminRestrictions
        * @param string $appName
        * @param string $moduleName
        * @param string $permName
        *
        * @return boolean
        */
        protected function _hasAdminPermission(array $adminRestrictions, $appName, $moduleName = null, $permName = null)
        {
            $appCache = $this->_getAppCache();
    
            if (!array_key_exists($appName, $appCache) || !in_array($appCache[$appName]['app_id'], $adminRestrictions['applications']))
            {
                return false;
            }
    
            if (isset($moduleName))
            {
                $moduleCache = $this->_getModuleCache();
    
                foreach ($moduleCache[$appName] AS $module)
                {
                    if ($module['sys_module_key'] == $moduleName)
                    {
                        $moduleId = $module['sys_module_id'];
    
                        if (!in_array($moduleId, $adminRestrictions['modules']))
                        {
                            return false;
                        }
    
                        if (isset($permName) && !in_array($permName, $adminRestrictions['items'][$moduleId]))
                        {
                            return false;
                        }
    
                        return true;
                    }
                }
            }
    
            return true;
        }
    
        protected function _getSelectUserSql($where)
        {
            return '
                SELECT pfields_content.*, profile_portal.*,
                    apr.row_perm_cache AS admin_restrictions,
                    members.*
                FROM ' . $this->_prefix . 'members AS members
                LEFT JOIN  ' . $this->_prefix . 'pfields_content AS pfields_content ON
                    (pfields_content.member_id = members.member_id)
                LEFT JOIN ' . $this->_prefix . 'profile_portal AS profile_portal ON
                    (profile_portal.pp_member_id = members.member_id)
                LEFT JOIN ' . $this->_prefix .  'admin_permission_rows AS apr ON
                    (apr.row_id = members.member_id AND apr.row_id_type = \'member\')
                WHERE '  . $where . '
                ORDER BY members.member_id
            ';
        }
    
        protected function _mergeUser(array $user, $targetUserId)
        {
            $user['joined'] = max(0, $user['joined']);
    
            $this->_db->query('
                UPDATE xf_user SET
                    message_count = message_count + ?,
                    register_date = IF(register_date > ?, ?, register_date)
                WHERE user_id = ?
            ', array($user['posts'], $user['joined'], $user['joined'], $targetUserId));
    
            $this->_importModel->logImportData('user', $user['member_id'], $targetUserId);
    
            return $targetUserId;
        }
    
        public function configStepAvatars(array $options)
        {
            if ($options)
            {
                return false;
            }
    
            return $this->_controller->responseView('XenForo_ViewAdmin_Import_IPBoard_ConfigAvatars', 'import_ipboard_config_avatars');
        }
    
        public function stepAvatars($start, array $options)
        {
            $options = array_merge(array(
                'path' => $this->_config['ipboard_path'] . '/uploads',
                'limit' => 50,
                'max' => false,
                // all checkbox options must default to false as they may not be submitted
                'fetchRemote' => false,
                'importPhotos' => false
            ), $options);
    
            $where = array("pp.avatar_type = 'upload'");
    
            if ($options['fetchRemote'])
            {
                $where[] = "pp.avatar_type = 'url'";
            }
    
            if ($options['importPhotos'])
            {
                $where[] = "pp.pp_main_photo <> ''";
            }
    
            $where = '(' . implode(' OR ', $where) . ')';
    
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            /* @var $model XenForo_Model_Import */
            $model = $this->_importModel;
    
            if ($options['max'] === false)
            {
                $options['max'] = $sDb->fetchOne('
                    SELECT MAX(pp_member_id)
                    FROM ' . $prefix . 'profile_portal AS pp
                    WHERE ' . $where . '
                ');
            }
    
            $avatars = $sDb->fetchAll($sDb->limit(
                '
                    SELECT members.member_id,
                        pp.pp_main_photo, pp.pp_main_width, pp.pp_main_height,
                        pp.avatar_location, pp.avatar_size, pp.avatar_type
                    FROM ' . $prefix . 'profile_portal AS pp
                    INNER JOIN ' . $prefix . 'members AS members ON
                        (members.member_id = pp.pp_member_id)
                    WHERE ' . $where . '
                        AND pp.pp_member_id > ' . $sDb->quote($start) . '
                    ORDER BY pp.pp_member_id
                ', $options['limit']
            ));
            if (!$avatars)
            {
                return true;
            }
    
            $userIdMap = $model->getUserIdsMapFromArray($avatars, 'member_id');
    
            $next = 0;
            $total = 0;
    
            foreach ($avatars AS $avatar)
            {
                $next = $avatar['member_id'];
    
                $newUserId = $this->_mapLookUp($userIdMap, $avatar['member_id']);
                if (!$newUserId)
                {
                    continue;
                }
    
                $avatarFile = null;
    
                // use profile photo instead of avatar
                if (!empty($options['importPhotos'])
                    && $avatar['pp_main_photo']
                    && file_exists("$options[path]/$avatar[pp_main_photo]"))
                {
                    $avatarFile = tempnam(XenForo_Helper_File::getTempDir(), 'xf');
                    copy("$options[path]/$avatar[pp_main_photo]", $avatarFile);
                }
    
                // fetch remote URL avatar if specified
                else if (!empty($options['fetchRemote'])
                    && $avatar['avatar_type'] == 'url'
                    && $avatar['avatar_location']
                    && $avatar['avatar_location'] != 'noavatar'
                    && Zend_Uri::check($avatar['avatar_location']))
                {
                    try
                    {
                        $httpClient = XenForo_Helper_Http::getClient(preg_replace('/\s+/', '%20', $avatar['avatar_location']));
    
                        $response = $httpClient->request('GET');
    
                        if ($response->isSuccessful())
                        {
                            $avatarFile = tempnam(XenForo_Helper_File::getTempDir(), 'xf');
                            file_put_contents($avatarFile, $response->getBody());
                        }
                    }
                    catch (Zend_Http_Client_Exception $e) {}
                }
    
                // regular avatar import
                if (empty($avatarFile)
                    && $avatar['avatar_type'] == 'upload'
                    && $avatar['avatar_location']
                    && file_exists("$options[path]/$avatar[avatar_location]"))
                {
                    $avatarFile = tempnam(XenForo_Helper_File::getTempDir(), 'xf');
                    copy("$options[path]/$avatar[avatar_location]", $avatarFile);
                }
    
                $isTemp = true;
    
                if ($this->_importModel->importAvatar($avatar['member_id'], $newUserId, $avatarFile))
                {
                    $total++;
                }
    
                if ($isTemp)
                {
                    @unlink($avatarFile);
                }
            }
    
            $this->_session->incrementStepImportTotal($total);
    
            return array($next, $options, $this->_getProgressOutput($next, $options['max']));
        }
    
        public function stepPrivateMessages($start, array $options)
        {
            $options = array_merge(array(
                'limit' => 300,
                'max' => false
            ), $options);
    
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            /* @var $model XenForo_Model_Import */
            $model = $this->_importModel;
    
            if ($options['max'] === false)
            {
                $options['max'] = $sDb->fetchOne('
                    SELECT MAX(mt_id)
                    FROM ' . $prefix . 'message_topics
                    WHERE mt_is_draft = 0
                        AND mt_is_deleted = 0
                        AND mt_is_system = 0
    
                ');
            }
    
            $topics = $this->_getPrivateMessages($start, $options);
            if (!$topics)
            {
                return true;
            }
    
            $next = 0;
            $total = 0;
    
            XenForo_Db::beginTransaction();
    
            foreach ($topics AS $topic)
            {
                $next = $topic['mt_id'];
    
                $topicUserMap = $this->_getTopicUserMap($topic);
    
                $mapUserIds = $model->getUserIdsMapFromArray($topicUserMap, 'map_user_id');
    
                $recipients = array();
                foreach ($topicUserMap AS $user)
                {
                    $newUserId = $this->_mapLookUp($mapUserIds, $user['map_user_id']);
                    if (!$newUserId)
                    {
                        continue;
                    }
    
                    if ($user['map_user_active'] == 0)
                    {
                        $recipientState = 'deleted_ignored';
                    }
                    /*else if ($user['map_ignore_notification'])
                    {
                        $recipientState = 'deleted'; // not actually sure that is an appropriate mapping
                    }*/
                    else
                    {
                        $recipientState = 'active';
                    }
    
                    $recipients[$newUserId] = array(
                        'username' => $this->_convertToUtf8($user['map_user_name'], true),
                        'last_read_date' => $user['map_read_time'],
                        'recipient_state' => $recipientState,
                        'is_unread' => $user['map_has_unread'],
                    );
                }
    
                $conversation = array(
                    'title' => $this->_convertToUtf8($topic['mt_title'], true),
                    'user_id' => $this->_mapLookUp($mapUserIds, $topic['mt_starter_id']),
                    'username' => $this->_convertToUtf8($topic['mt_starter_name'], true),
                    'start_date' => $topic['mt_date'],
                    'open_invite' => 0,
                    'conversation_open' => 1
                );
    
                $posts = $this->_getMessagePosts($topic);
    
                $messages = array();
    
                foreach ($posts AS $post)
                {
                    $message = $this->_parseIPBoardBbCode($post['msg_post']);
    
                    if (stripos($message, '[quote ') !== false)
                    {
                        $message = preg_replace(
                            '/\[quote\s+name=(\'|")(.+)\1[^\]]+\]/siU',
                            "[quote='\\2']",
                            $message
                        );
                    }
    
                    $messages[$post['msg_id']] = array(
                        'message_date' => $post['msg_date'],
                        'user_id' => $this->_mapLookUp($mapUserIds, $post['msg_author_id'], 0),
                        'username' => $this->_convertToUtf8($post['msg_author_name'], true),
                        'message' => $message
                    );
                }
    
                if ($model->importConversation($topic['mt_id'], $conversation, $recipients, $messages))
                {
                    $total++;
                }
            }
    
            XenForo_Db::commit();
    
            $this->_session->incrementStepImportTotal($total);
    
            return array($next, $options, $this->_getProgressOutput($next, $options['max']));
        }
    
        protected function _getPrivateMessages($start, array $options)
        {
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            return $sDb->fetchAll($sDb->limit(
                '
                    SELECT mtopics.*,
                        members.name AS mt_starter_name
                    FROM ' . $prefix . 'message_topics AS mtopics
                    INNER JOIN  ' . $prefix . 'members AS members ON
                        (mtopics.mt_starter_id = members.member_id)
                    WHERE mtopics.mt_id > ' . $sDb->quote($start) . '
                        AND mt_is_draft = 0
                        AND mt_is_deleted = 0
                        AND mt_is_system = 0
                    ORDER BY mtopics.mt_id
                ', $options['limit']
            ));
        }
    
        protected function _getTopicUserMap(array $topic)
        {
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            return $sDb->fetchAll('
                SELECT topicUserMap.*,
                    members.name AS map_user_name
                FROM ' . $prefix . 'message_topic_user_map AS topicUserMap
                INNER JOIN ' . $prefix . 'members AS members ON
                    (topicUserMap.map_user_id = members.member_id)
                WHERE topicUserMap.map_topic_id = ' . $sDb->quote($topic['mt_id'])
            );
        }
    
        protected function _getMessagePosts(array $topic)
        {
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            return $sDb->fetchAll('
                SELECT messagePosts.*,
                    members.name AS msg_author_name
                FROM ' . $prefix . 'message_posts AS messagePosts
                INNER JOIN ' . $prefix . 'members AS members ON
                    (messagePosts.msg_author_id = members.member_id)
                WHERE messagePosts.msg_topic_id = ' . $sDb->quote($topic['mt_id']) . '
                ORDER BY messagePosts.msg_date
            ');
        }
    
        public function stepProfileComments($start, array $options)
        {
            $options = array_merge(array(
                'limit' => 200,
                'max' => false
            ), $options);
    
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            /* @var $model XenForo_Model_Import */
            $model = $this->_importModel;
    
            if ($options['max'] === false)
            {
                $options['max'] = $sDb->fetchOne('
                    SELECT MAX(comment_id)
                    FROM ' . $prefix . 'profile_comments
                ');
            }
    
            $pcs = $sDb->fetchAll($sDb->limit(
                '
                    SELECT pc.*,
                        members.name AS comment_by_member_name
                    FROM ' . $prefix . 'profile_comments AS pc
                    INNER JOIN ' . $prefix . 'members AS members ON
                        (pc.comment_by_member_id = members.member_id)
                    WHERE pc.comment_id > ' . $sDb->quote($start) . '
                    ORDER BY pc.comment_id
                ', $options['limit']
            ));
            if (!$pcs)
            {
                return true;
            }
    
            $next = 0;
            $total = 0;
    
            $userIds = array();
            foreach ($pcs AS $pc)
            {
                $userIds[] = $pc['comment_for_member_id'];
                $userIds[] = $pc['comment_by_member_id'];
            }
            $userIdMap = $model->getImportContentMap('user', $userIds);
    
            XenForo_Db::beginTransaction();
    
            foreach ($pcs AS $pc)
            {
                if (trim($pc['comment_by_member_name']) === '')
                {
                    continue;
                }
    
                $next = $pc['comment_id'];
    
                $profileUserId = $this->_mapLookUp($userIdMap, $pc['comment_for_member_id']);
                if (!$profileUserId)
                {
                    continue;
                }
    
                $postUserId = $this->_mapLookUp($userIdMap, $pc['comment_by_member_id'], 0);
    
                $import = array(
                    'profile_user_id' => $profileUserId,
                    'user_id' => $postUserId,
                    'username' => $this->_convertToUtf8($pc['comment_by_member_name'], true),
                    'post_date' => $pc['comment_date'],
                    'message' => $this->_parseIPBoardText($pc['comment_content']),
                    'ip' => $pc['comment_ip_address'],
                    'message_state' => ($pc['comment_approved'] ? 'visible' : 'moderated'),
                );
    
                if ($model->importProfilePost($pc['comment_id'], $import))
                {
                    $total++;
                }
            }
    
            XenForo_Db::commit();
    
            $this->_session->incrementStepImportTotal($total);
    
            return array($next, $options, $this->_getProgressOutput($next, $options['max']));
        }
    
        public function stepStatusUpdates($start, array $options)
        {
            $options = array_merge(array(
                'limit' => 200,
                'max' => false
            ), $options);
    
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            /* @var $model XenForo_Model_Import */
            $model = $this->_importModel;
    
            if ($options['max'] === false)
            {
                $options['max'] = $sDb->fetchOne('
                    SELECT MAX(status_id)
                    FROM ' . $prefix . 'member_status_updates
                ');
            }
    
            $statusUpdates = $this->_getStatusUpdates($start, $options['limit']);
            if (!$statusUpdates)
            {
                return true;
            }
    
            $next = 0;
            $total = 0;
    
            $userIdMap = $this->_getStatusUpdateUserIdMap($model, $statusUpdates);
    
            XenForo_Db::beginTransaction();
    
            foreach ($statusUpdates AS $statusUpdate)
            {
                $next = $statusUpdate['status_id'];
    
                list($profileUserId, $userId, $username, $ip) = $this->_getStatusUpdateUserInfo($statusUpdate, $userIdMap);
    
                $import = array(
                    'profile_user_id' => $profileUserId,
                    'user_id' => $userId,
                    'username' => $this->_convertToUtf8($username, true),
                    'post_date' => $statusUpdate['status_date'],
                    'message' => $this->_prepareStatusMessageText($statusUpdate['status_content']),
                    'message_state' => 'visible',
                    'comment_count' => $statusUpdate['status_replies'],
                    'ip' => $ip,
                );
    
                if ($profilePostId = $model->importProfilePost($statusUpdate['status_id'], $import))
                {
                    $db = XenForo_Application::getDb();
    
                    if ($statusUpdate['status_is_latest'])
                    {
                        $db->update('xf_user_profile', array
                        (
                            'status' => $import['message'],
                            'status_date' => $import['post_date'],
                            'status_profile_post_id' => $profilePostId
                        ), 'user_id = ' . $db->quote($userId));
                    }
    
                    $total++;
    
                    $importUpdate = array();
    
                    if (!empty($statusUpdate['status_replies']))
                    {
                        $replies = $this->_getStatusReplies($statusUpdate);
                        if ($replies)
                        {
                            $replyUserIdMap = $model->getUserIdsMapFromArray($replies, 'reply_member_id');
    
                            $lastIds = array();
    
                            foreach ($replies AS $reply)
                            {
                                $commentImport = array(
                                    'profile_post_id' => $profilePostId,
                                    'user_id' => $this->_mapLookUp($replyUserIdMap, $reply['reply_member_id']),
                                    'username' => $this->_convertToUtf8($reply['name']),
                                    'comment_date' => $reply['reply_date'],
                                    'message' => $this->_prepareStatusMessageText($reply['reply_content']),
                                );
    
                                $commentId = $model->importProfilePostComment($reply['reply_id'], $commentImport);
                                $lastIds[] = $commentId;
                                $this->_importStatusReplyExtra($reply, $commentId, $commentImport);
                            }
    
                            $firstReply = reset($replies);
                            $lastReply = end($replies);
    
                            $importUpdate = array(
                                'comment_count' => count($replies),
                                'first_comment_date' => $firstReply['reply_date'],
                                'last_comment_date' => $lastReply['reply_date'],
                                'latest_comment_ids' => implode(',', array_slice($lastIds, -3))
                            );
                        }
                    }
    
                    if ($importUpdateExtra = $this->_importStatusUpdateExtra($statusUpdate, $profilePostId, $import))
                    {
                        $importUpdate = array_merge($importUpdate, $importUpdateExtra);
                    }
    
                    if ($importUpdate)
                    {
                        $db->update('xf_profile_post', $importUpdate, 'profile_post_id = ' . $sDb->quote($profilePostId));
                    }
                }
            }
    
            XenForo_Db::commit();
    
            $this->_session->incrementStepImportTotal($total);
    
            return array($next, $options, $this->_getProgressOutput($next, $options['max']));
        }
    
        protected function _getStatusUpdates($start, $limit)
        {
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            return $sDb->fetchAll($sDb->limit(
                '
                    SELECT msus.*,
                        members.name AS status_member_name
                    FROM ' . $prefix . 'member_status_updates AS msus
                    INNER JOIN ' . $prefix . 'members AS members ON
                        (msus.status_member_id = members.member_id)
                    WHERE msus.status_id > ' . $sDb->quote($start) . '
                    ORDER BY msus.status_id
                ', $limit
            ));
        }
    
        protected function _getStatusReplies(array $statusUpdate)
        {
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            return $sDb->fetchAll('
                SELECT replies.*, members.name
                FROM ' . $prefix . 'member_status_replies AS replies
                INNER JOIN  ' . $prefix . 'members AS members ON
                    (replies.reply_member_id = members.member_id)
                WHERE replies.reply_status_id = ' . $sDb->quote($statusUpdate['status_id']) . '
                ORDER BY replies.reply_date
            ');
        }
    
        protected function _getStatusUpdateUserIdMap(XenForo_Model_Import $model, array $statusUpdates)
        {
            return $model->getUserIdsMapFromArray($statusUpdates, 'status_member_id');
        }
    
        protected function _getStatusUpdateUserInfo(array $statusUpdate, array $userIdMap)
        {
            $profileUserId = $this->_mapLookUp($userIdMap, $statusUpdate['status_member_id']);
            $userId = $profileUserId;
            $username = $statusUpdate['status_member_name'];
            $ip = false;
    
            return array($profileUserId, $userId, $username, false);
        }
    
        /**
        * Perform any additional importing behaviour for the specified status update
        *
        * @param array $statusUpdate Source data
        * @param integer $profilePostId Inserted profile post id
        * @param array $profilePost Imported data
        *
        * @return array Data with which to update the profile post
        */
        protected function _importStatusUpdateExtra(array $statusUpdate, $profilePostId, array $profilePost)
        {
            return array();
        }
    
        /**
        * Perform any additional importing behaviour for the specified status replies
        *
        * @param array $statusReply Source data
        * @param integer $commentId Inserted profile post comment id
        * @param array $comment Imported data
        *
        */
        protected function _importStatusReplyExtra(array $statusReply, $commentId, array $comment)
        {
        }
    
        protected function _prepareStatusMessageText($text)
        {
            return $this->_parseIPBoardText($text);
        }
    
        public function stepForums($start, array $options)
        {
            /* @var $model XenForo_Model_Import */
            $model = $this->_importModel;
    
            if ($start > 0)
            {
                // after importing everything, rebuild nested set info.
                XenForo_Model::create('XenForo_Model_Node')->updateNestedSetInfo();
    
                // rebuild the full permission cache so forums appear
                XenForo_Model::create('XenForo_Model_Permission')->rebuildPermissionCache();
    
                return true;
            }
    
            $forums = $this->_getForums();
            if (!$forums)
            {
                return true;
            }
    
            $forumTree = array();
            foreach ($forums AS $forum)
            {
                $forumTree[$forum['parent_id']][$forum['id']] = $forum;
            }
    
            XenForo_Db::beginTransaction();
    
            $total = $this->_importForumTree(-1, $forumTree);
    
            XenForo_Db::commit();
    
            $this->_session->incrementStepImportTotal($total);
    
            return array(1, array(), '');
        }
    
        protected function _importForumTree($parentId, array $forumTree, array $forumIdMap = array())
        {
            if (!isset($forumTree[$parentId]))
            {
                return 0;
            }
    
            XenForo_Db::beginTransaction();
    
            $total = 0;
    
            foreach ($forumTree[$parentId] AS $forum)
            {
                $import = array(
                    'title' => $this->_convertToUtf8($forum['name'], true),
                    'description' => $this->_convertToUtf8($forum['description'], true),
                    'display_order' => $forum['position'],
                    'parent_node_id' => $this->_mapLookUp($forumIdMap, $forum['parent_id'], 0),
                    'display_in_list' => 1 // no equivalent
                );
    
                if ($forum['redirect_on'] && $forum['redirect_url'])
                {
                    $import['node_type_id'] = 'LinkForum';
                    $import['link_url'] = $this->_convertToUtf8($forum['redirect_url']);
    
                    $nodeId = $this->_importModel->importLinkForum($forum['id'], $import);
                }
                else if ($forum['sub_can_post']) // forum
                {
                    $import['node_type_id'] = 'Forum';
                    $import['discussion_count'] = $forum['topics'];
                    $import['message_count'] = $forum['posts'] + $forum['topics'];
                    $import['last_post_date'] = $forum['last_post'];
                    $import['last_post_username'] = $this->_convertToUtf8($forum['last_poster_name'], true);
    
                    $nodeId = $this->_importModel->importForum($forum['id'], $import);
                }
                else
                {
                    $import['node_type_id'] = 'Category';
    
                    $nodeId = $this->_importModel->importCategory($forum['id'], $import);
                }
    
                if ($nodeId)
                {
                    $forumIdMap[$forum['id']] = $nodeId;
    
                    $total++;
                    $total += $this->_importForumTree($forum['id'], $forumTree, $forumIdMap);
                }
            }
    
            XenForo_Db::commit();
    
            return $total;
        }
    
        protected function _getForums()
        {
            return $this->_sourceDb->fetchAll('
                SELECT *
                FROM ' . $this->_prefix . 'forums
            ');
        }
    
        public function configStepForumPermissions(array $options)
        {
            if ($options)
            {
                return false;
            }
    
            $this->_bootstrap($this->_session->getConfig());
    
            $nodeMap = $this->_importModel->getImportContentMap('node');
    
            $forumStates = $this->_guessForumPermissions();
    
            /* @var $nodeModel XenForo_Model_Node */
            $nodeModel = $this->_importModel->getModelFromCache('XenForo_Model_Node');
    
            $nodes = $nodeModel->getAllNodes();
    
            $displayNodes = array();
    
            foreach ($nodes AS $nodeId => $node)
            {
                if (in_array($nodeId, $nodeMap))
                {
                    $node['permissionState'] = $forumStates[$nodeId];
    
                    $displayNodes[$nodeId] = $node;
                }
            }
    
            $viewParams = array('nodes' => $displayNodes);
    
            return $this->_controller->responseView(
                'XenForo_ViewAdmin_Import_IPBoard_ConfigForumPermissions',
                'import_ipboard_config_forumpermissions',
                $viewParams
            );
        }
    
        public function stepForumPermissions($start, array $options)
        {
            /* @var $model XenForo_Model_Import */
            $model = $this->_importModel;
    
            if ($start > 0)
            {
                //rebuild the full permission cache so forums appear
                XenForo_Model::create('XenForo_Model_Permission')->rebuildPermissionCache();
    
                return true;
            }
    
            $reset = array('general' => array('viewNode' => 'reset'));
            $allow = array('general' => array('viewNode' => 'content_allow'));
    
            $total = 0;
    
            XenForo_Db::beginTransaction();
    
            foreach ($options AS $nodeId => $permission)
            {
                switch ($permission)
                {
                    case 'memberOnly':
                    {
                        // revoke view permissions for guests (1)
                        $model->insertNodePermissionEntries($nodeId, 1, 0, $reset);
    
                        $total++;
    
                        break;
                    }
    
                    case 'staffOnly':
                    {
                        // revoke view permissions for all but staff
                        $model->insertNodePermissionEntries($nodeId, 0, 0, $reset);
    
                        // allow 'Administrating' group (3)
                        $model->insertNodePermissionEntries($nodeId, 3, 0, $allow);
    
                        // allow 'Moderating' group (4)
                        $model->insertNodePermissionEntries($nodeId, 4, 0, $allow);
    
                        $total++;
    
                        break;
                    }
    
                    case 'public':
                    default:
                        // no change required
                }
            }
    
            XenForo_Db::commit();
    
            $this->_session->incrementStepImportTotal($total);
    
            return array(1, array(), '');
        }
    
        /**
        * Forums must have been imported already for this to function.
        */
        protected function _guessForumPermissions()
        {
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            $groupIds = $this->_session->getExtraData('groups');
    
            $groupPermSets = $sDb->fetchPairs('
                SELECT g_id, g_perm_id
                FROM ' . $prefix . 'groups
            ');
            foreach ($groupPermSets AS &$permSets)
            {
                $permSets = $this->_ipbExplode($permSets);
            }
    
            $forumPermissions = array();
    
            $ipbForumPerms = $sDb->fetchPairs('
                SELECT forums.id, perms.perm_view
                FROM ' . $prefix . 'forums AS forums
                LEFT JOIN ' . $prefix . 'permission_index AS perms ON
                    (perms.perm_type_id = forums.id AND perms.perm_type = \'forum\')
            ');
            foreach ($ipbForumPerms AS $forumId => $viewPermSets)
            {
                if ($viewPermSets == '*')
                {
                    $state = 'public';
                }
                else
                {
                    $viewPermSets = $this->_ipbExplode($viewPermSets);
    
                    $guestViews = array_intersect($groupPermSets[$groupIds['guest_group']], $viewPermSets);
                    if (empty($guestViews))
                    {
                        // forum is not viewable by guests
                        $state = 'memberOnly';
    
                        $memberViews = array_intersect($groupPermSets[$groupIds['member_group']], $viewPermSets);
                        if (empty($memberViews))
                        {
                            // forum is not viewable by registered members
                            $state = 'staffOnly';
                        }
                    }
                    else
                    {
                        $state = 'public';
                    }
                }
    
                $forumPermissions[$this->_importModel->mapNodeId($forumId)] = $state;
            }
    
            return $forumPermissions;
        }
    
        public function stepModerators($start, array $options)
        {
            /* @var $model XenForo_Model_Import */
            $model = $this->_importModel;
    
            $moderators = array();
    
            $forumMods = $this->_getModerators();
            foreach ($forumMods AS $forumMod)
            {
                $moderators[$forumMod['member_id']] = $forumMod;
            }
    
            if ($superMods = $this->_session->getExtraData('superMods'))
            {
                // get the full list of super moderator permissions
                $superModPerms = XenForo_Model::create('XenForo_Model_Moderator')->getFullPermissionSet();
    
                foreach ($superMods AS $oldUserId => $newUserId)
                {
                    $moderators[$oldUserId]['superMod'] = $newUserId;
                }
            }
    
            if (!$moderators)
            {
                return true;
            }
    
            $nodeMap = $model->getImportContentMap('node');
            $userIdMap = $model->getImportContentMap('user', array_keys($moderators));
    
            $total = 0;
    
            XenForo_Db::beginTransaction();
    
            foreach ($moderators AS $userId => $moderator)
            {
                $newUserId = $this->_mapLookUp($userIdMap, $userId);
                if (!$newUserId)
                {
                    continue;
                }
    
                if (!empty($moderator['superMod']))
                {
                    $globalModPermissions = $superModPerms;
                    $superMod = true;
                }
                else
                {
                    $globalModPermissions = array();
                    $superMod = false;
                }
    
                if (!empty($moderator['forum_id']))
                {
                    $forumPerms = $this->_calculateModeratorPermissions($moderator);
    
                    foreach ($this->_ipbExplode($moderator['forum_id']) AS $forumId)
                    {
                        $newNodeId = $this->_mapLookUp($nodeMap, $forumId);
                        if (!$newNodeId)
                        {
                            continue;
                        }
    
                        $mod = array(
                            'content_id' => $newNodeId,
                            'user_id' => $newUserId,
                            'moderator_permissions' => array('forum' => $forumPerms['forum'])
                        );
    
                        $model->importNodeModerator($forumId, $newUserId, $mod);
    
                        $total++;
                    }
                }
    
                $mod = array(
                    'user_id' => $newUserId,
                    'is_super_moderator' => $superMod,
                    'moderator_permissions' => $globalModPermissions
                );
                $model->importGlobalModerator($userId, $mod);
            }
    
            $this->_session->incrementStepImportTotal($total);
    
            XenForo_Db::commit();
    
            return true;
        }
    
        protected function _getModerators()
        {
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            return $sDb->fetchAll('
                SELECT moderators.*
                FROM ' . $prefix . 'moderators AS moderators
                INNER JOIN ' . $prefix . 'members AS members ON
                    (moderators.member_id = members.member_id)
            ');
        }
    
        protected function _calculateModeratorPermissions(array $mod)
        {
            $modBits = intval($mod['mod_bitoptions']);
    
            $general = array();
    
            if (!empty($mod['view_ip']))
            {
                $general['viewIps'] = true;
            }
    
            if ($modBits & 1) // bw_flag_spammers
            {
                $general['cleanSpam'] = true;
            }
    
            $forum = array
            (
                'viewModerated' => true,
                'approveUnapprove' => true
            );
    
            if (!empty($mod['edit_post']))
            {
                $forum['editAnyPost'] = true;
            }
    
            if (!empty($mod['edit_topic']))
            {
                $forum['manageAnyThread'] = true;
            }
    
            if (!empty($mod['pin_topic'])
            || !empty($mod['unpin_topic']))
            {
                $forum['stickUnstickThread'] = true;
            }
    
            if (!empty($mod['close_topic'])
            || !empty($mod['open_topic']))
            {
                $forum['lockUnlockThread'] = true;
            }
    
            if ($modBits & 2) // bw_mod_soft_delete
            {
                $forum['deleteAnyPost'] = true;
            }
    
            if ($mod['delete_post'])
            {
                $forum['hardDeleteAnyPost'] = true;
            }
    
            if ($modBits & 16) // bw_mod_soft_delete_topic
            {
                $forum['deleteAnyThread'] = true;
            }
    
            if (!empty($mod['delete_topic']))
            {
                $forum['hardDeleteAnyThread'] = true;
            }
    
            if ($modBits & 4   // bw_mod_un_soft_delete
            || $modBits & 32) // bw_mod_un_soft_delete_topic
            {
                $forum['undelete'] = true;
            }
    
            if ($modBits & 8    // bw_mod_soft_delete_see
            || $modBits & 64   // bw_mod_soft_delete_topic_see
            || $modBits & 256) // bw_mod_soft_delete_see_post
            {
                $forum['viewDeleted'] = true;
            }
    
            return array(
                'general' => $general,
                'forum' => $forum
            );
        }
    
        public function stepThreads($start, array $options)
        {
            $options = array_merge(array(
                'limit' => 100,
                'postDateStart' => 0,
                'postLimit' => 800,
                'max' => false
            ), $options);
    
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            /* @var $model XenForo_Model_Import */
            $model = $this->_importModel;
    
            if ($options['max'] === false)
            {
                $options['max'] = $sDb->fetchOne('
                    SELECT MAX(tid)
                    FROM ' . $prefix . 'topics
                ');
            }
    
            // pull threads from things we actually imported as forums
            $threads = $this->_getThreads($start, $options);
            if (!$threads)
            {
                return true;
            }
    
            $next = 0;
            $total = 0;
            $totalPosts = 0;
    
            $nodeMap = $model->getImportContentMap('node');
    
            XenForo_Db::beginTransaction();
    
            foreach ($threads AS $thread)
            {
                if (trim($thread['title']) === '')
                {
                    continue;
                }
    
                $postDateStart = $options['postDateStart'];
    
                $next = $thread['tid'] + 1; // uses >=, will be moved back down if need to continue
                $options['postDateStart'] = 0;
    
                $maxPosts = $options['postLimit'] - $totalPosts;
                $posts = $this->_getPosts($thread, $postDateStart, $maxPosts);
                if (!$posts)
                {
                    if ($postDateStart)
                    {
                        // continuing thread but it has no more posts
                        $total++;
                    }
                    continue;
                }
    
                if ($postDateStart)
                {
                    // continuing thread we already imported
                    $threadId = $model->mapThreadId($thread['tid']);
    
                    $position = $this->_db->fetchOne('
                        SELECT MAX(position)
                        FROM xf_post
                        WHERE thread_id = ?
                    ', $threadId);
                }
                else
                {
                    $forumId = $this->_mapLookUp($nodeMap, $thread['forum_id']);
                    if (!$forumId)
                    {
                        continue;
                    }
    
                    if (trim($thread['starter_name']) === '')
                    {
                        $thread['starter_name'] = 'Guest';
                    }
    
                    $import = array(
                        'title' => $this->_convertToUtf8($thread['title'], true),
                        'node_id' => $forumId,
                        'user_id' => $model->mapUserId($thread['starter_id'], 0),
                        'username' => $this->_convertToUtf8($thread['starter_name'], true),
                        'discussion_open' => ($thread['state'] == 'open' ? 1 : 0),
                        'post_date' => $thread['start_date'],
                        'reply_count' => $thread['posts'],
                        'view_count' => $thread['views'],
                        'sticky' => $thread['pinned'],
                        'last_post_date' => $thread['last_post'],
                        'last_post_user_id' => $model->mapUserId($thread['last_poster_id'], 0),
                        'last_post_username' => $this->_convertToUtf8($thread['last_poster_name'], true)
                    );
                    switch ($thread['approved'])
                    {
                        case 0: $import['discussion_state'] = 'moderated'; break;
                        case -1: $import['discussion_state'] = 'deleted'; break;
                        case 2: $import['discussion_state'] = 'deleted'; break;
                        default: $import['discussion_state'] = 'visible'; break;
                    }
    
                    $threadId = $model->importThread($thread['tid'], $import);
                    if (!$threadId)
                    {
                        continue;
                    }
    
                    $position = -1;
    
                    $this->_importThreadWatch($threadId, $thread);
                }
    
                if ($threadId)
                {
                    $quotedPostIds = array();
    
                    $threadTitleRegex = '#^(re:\s*)?' . preg_quote($thread['title'], '#') . '$#i';
    
                    $userIdMap = $model->getUserIdsMapFromArray($posts, 'author_id');
    
                    foreach ($posts AS $i => $post)
                    {
                        if (isset($post['post_title']) && $post['post_title'] !== '' && !preg_match($threadTitleRegex, $post['post_title']))
                        {
                            $post['post'] = '[b]' . htmlspecialchars_decode($post['post_title']) . "[/b]\n\n" . ltrim($post['post']);
                        }
    
                        $post['post'] = $this->_parseIPBoardBbCode($post['post']);
    
                        if (trim($post['author_name']) === '')
                        {
                            $post['username'] = 'Guest';
                        }
    
                        //echo "<div>Import message $post[pid]<br /><textarea rows=4 cols=60>" . $this->_strToHex($post['post']) . "</textarea></div>";
    
                        $import = array(
                            'thread_id' => $threadId,
                            'user_id' => $this->_mapLookUp($userIdMap, $post['author_id'], 0),
                            'username' => $this->_convertToUtf8($post['author_name'], true),
                            'post_date' => $post['post_date'],
                            'message' => $post['post'],
                            'ip' => $post['ip_address'],
                            'last_edit_date' => !empty($post['edit_date']) ? $post['edit_date'] : 0,
                            'edit_count' => !empty($post['edit_date']) ? 1 : 0
                        );
                        $import = $this->_getMessageStateAndPosition($post, $import, $position);
    
                        $post['xf_post_id'] = $model->importPost($post['pid'], $import);
    
                        $options['postDateStart'] = $post['post_date'];
                        $totalPosts++;
    
                        $quotedPostIds = $this->_getQuotedPostIds($post, $quotedPostIds);
    
                        $posts[$i] = $post;
                    }
    
                    $postIdMap = (empty($quotedPostIds) ? array() : $model->getImportContentMap('post', $quotedPostIds));
    
                    $db = XenForo_Application::getDb();
    
                    foreach ($posts AS $post)
                    {
                        if (!empty($post['quotes']))
                        {
                            $postQuotesRewrite = $this->_rewriteQuotes($post['post'], $post['quotes'], $postIdMap);
    
                            if ($post['post'] != $postQuotesRewrite)
                            {
                                $db->update('xf_post', array('message' => $postQuotesRewrite), 'post_id = ' . $db->quote($post['xf_post_id']));
                            }
                        }
                    }
                }
    
                if (count($posts) < $maxPosts)
                {
                    // done this thread
                    $total++;
                    $options['postDateStart'] = 0;
                }
                else
                {
                    // not necessarily done the thread; need to pick it up next page
                    break;
                }
            }
    
            if ($options['postDateStart'])
            {
                // not done this thread, need to continue with it
                $next--;
            }
    
            XenForo_Db::commit();
    
            $this->_session->incrementStepImportTotal($total);
    
            return array($next, $options, $this->_getProgressOutput($next - 1, $options['max']));
        }
    
        protected function _getThreads($start, array $options)
        {
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            return $sDb->fetchAll($sDb->limit(
                '
                    SELECT
                        topics.*, IF (members.name IS NULL, topics.starter_name, members.name) AS starter_name,
                        IF (lastposters.name IS NULL, topics.last_poster_name, lastposters.name) AS last_poster_name
                    FROM ' . $prefix . 'topics AS topics FORCE INDEX (PRIMARY)
                    LEFT JOIN ' . $prefix . 'members AS members ON
                        (topics.starter_id = members.member_id)
                    LEFT JOIN ' . $prefix . 'members AS lastposters ON
                        (topics.last_poster_id = lastposters.member_id)
                    INNER JOIN ' . $prefix . 'forums AS forums ON
                        (topics.forum_id = forums.id AND forums.redirect_on = 0 AND forums.sub_can_post = 1)
                    WHERE topics.tid >= ' . $sDb->quote($start) . '
                        AND topics.state <> \'link\'
                    ORDER BY topics.tid
                ', $options['limit']
            ));
        }
    
        protected function _getPosts(array $thread, $postDateStart, $maxPosts)
        {
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            return $sDb->fetchAll($sDb->limit(
                '
                    SELECT posts.*,
                        IF (members.name IS NULL, posts.author_name, members.name) AS author_name
                    FROM ' . $prefix . 'posts AS posts
                    LEFT JOIN ' . $prefix . 'members AS members ON
                        (posts.author_id = members.member_id)
                    WHERE posts.topic_id = ' . $sDb->quote($thread['tid']) . '
                        AND posts.post_date > ' . $sDb->quote($postDateStart) . '
                    ORDER BY posts.post_date
                ', $maxPosts
            ));
        }
    
        protected function _getMessageStateAndPosition(array $post, array $import, &$position)
        {
            switch ($post['queued'])
            {
                case 1: $import['message_state'] = 'moderated'; $import['position'] = $position; break;
                case 2: $import['message_state'] = 'deleted'; $import['position'] = $position; break;
                case 3: $import['message_state'] = 'deleted'; $import['position'] = $position; break;
                default: $import['message_state'] = 'visible'; $import['position'] = ++$position; break;
            }
    
            return $import;
        }
    
        protected function _getQuotedPostIds(array &$post, array $quotedPostIds)
        {
            // look for attributed quotes
            if (stripos($post['post'], '[quote ') !== false) // yes, with the space!
            {
                if (preg_match_all('/\[quote\s+([^"\'\]]+|"[^"]*"|\'[^\']*\')+\]/siU', $post['post'], $quotes))
                {
                    $post['quotes'] = array_fill_keys($quotes[0], true);
    
                    foreach ($post['quotes'] AS $quote => $quotedPostId)
                    {
                        // extract the post id
                        if (preg_match('/\spost=(\'|"|)(\d+)\1/si', $quote, $match))
                        {
                            $quotedPostId = intval($match[2]);
    
                            $quotedPostIds[] = $quotedPostId;
                        }
                    }
                }
            }
    
            return $quotedPostIds;
        }
    
        protected function _rewriteQuotes($message, array $quotes, array $postIdMap)
        {
            foreach ($quotes AS $quote => &$replace)
            {
                if (preg_match('/ name=(\'|")(.+)\1/siU', $quote, $nameMatch))
                {
                    $name = $nameMatch[2];
    
                    if (preg_match('/ post=(\'|"|)(\d+)\1/siU', $quote, $postMatch))
                    {
                        $post = $this->_mapLookUp($postIdMap, $postMatch[2]);
    
                        $replace = sprintf('[quote="%s, post: %d"]', $name, $post);
                    }
                    else
                    {
                        $replace = sprintf('[quote="%s"]', $name);
                    }
                }
                else
                {
                    unset($quotes[$quote]);
                }
            }
    
            if (!empty($quotes))
            {
                return str_replace(array_keys($quotes), $quotes, $message);
            }
    
            return $message;
        }
    
        /**
        * Imports thread watch records for the given thread
        *
        * @param integer $threadId Imported XenForo thread ID
        * @param array $sourceThread IPB source thread data
        */
        protected function _importThreadWatch($threadId, array $sourceThread)
        {
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
            $model = $this->_importModel;
    
            $subs = $sDb->fetchPairs('
                SELECT member_id, topic_track_type
                FROM ' . $prefix . 'tracker
                WHERE topic_id = ' . $sDb->quote($sourceThread['tid'])
            );
            if ($subs)
            {
                $userIdMap = $model->getImportContentMap('user', array_keys($subs));
                foreach ($subs AS $userId => $emailUpdate)
                {
                    $newUserId = $this->_mapLookUp($userIdMap, $userId);
                    if (!$newUserId)
                    {
                        continue;
                    }
    
                    $model->importThreadWatch($newUserId, $threadId, ($emailUpdate == 'none' ? 0 : 1));
                }
            }
        }
    
        public function configStepPolls(array $options)
        {
            if ($options)
            {
                return false;
            }
    
            return $this->_controller->responseView('XenForo_ViewAdmin_Import_IPBoard_ConfigPolls', 'import_ipboard_config_polls');
        }
    
        public function stepPolls($start, array $options)
        {
            $options = array_merge(array(
                'whichQuestion' => 'first',
                'limit' => 100,
                'max' => false
            ), $options);
    
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            /* @var $model XenForo_Model_Import */
            $model = $this->_importModel;
    
            if ($options['max'] === false)
            {
                $options['max'] = $sDb->fetchOne('
                    SELECT MAX(pid)
                    FROM ' . $prefix . 'polls
                ');
            }
    
            $polls = $this->_getPolls($start, $options);
            if (!$polls)
            {
                return true;
            }
    
            $next = 0;
            $total = 0;
    
            $threadIdMap = $model->getThreadIdsMapFromArray($polls, 'tid');
            $donePolls = array();
    
            XenForo_Db::beginTransaction();
    
            foreach ($polls AS $poll)
            {
                $next = $poll['pid'];
    
                $newThreadId = $this->_mapLookUp($threadIdMap, $poll['tid']);
                if (!$newThreadId)
                {
                    continue;
                }
    
                if (isset($donePolls[$poll['pid']]))
                {
                    // some times the pid in the thread table isn't unique so it can try to import dupes
                    continue;
                }
    
                $existingPoll = $this->_db->fetchOne("
                    SELECT poll_id
                    FROM xf_poll
                    WHERE content_type = 'thread'
                        AND content_id = ?
                ", $newThreadId);
                if ($existingPoll)
                {
                    continue;
                }
    
                /* Usually, the choice field looks like this (choice, votes and question):
                * array(3) {
                *      ["choice"] => array(2) {
                *        [1] => string(8) "Homemade"
                *        [2] => string(11) "Storebought"
                *      }
                *      ["votes"] => array(2) {
                *        [1] => string(1) "1"
                *        [2] => string(1) "3"
                *      }
                *      ["question"] => string(9) "Incubator"
                *    }
                */
                $questions = $this->_prepareQuestions($poll['choices']);
    
                if (!is_array($questions))
                {
                    continue;
                }
    
                $pollInfo = ($options['whichQuestion'] == 'last' ? end($questions) : reset($questions));
    
                if (empty($pollInfo['choice']))
                {
                    /* sometimes, the choice field looks like this (just choices, not keyed under 'choice':
                    *
                    * array(3) {
                    *      [0] => string(1) "1"
                    *      [1] => string(2) "No"
                    *      [2] => string(1) "3"
                    *    }
                    */
                    $pollInfo['choice'] = $pollInfo;
                }
                if (!is_array($pollInfo['choice']) || !$pollInfo['choice'])
                {
                    continue;
                }
    
                if (empty($pollInfo['question']))
                {
                    /* Sometimes, the choice field looks like this (choices and votes, no question key):
                    *
                    * array(2) {
                    *      ["choice"] => array(2) {
                    *        [1] => string(3) "4x3"
                    *        [2] => string(3) "4x5"
                    *      }
                    *      ["votes"] => array(2) {
                    *        [1] => string(1) "0"
                    *        [2] => string(1) "7"
                    *      }
                    *    }
                    */
                    $pollInfo['question'] = $poll['poll_question'];
                }
    
                $import = array(
                    'question' => $this->_convertToUtf8($pollInfo['question']),
                    'public_votes' => $poll['poll_view_voters'],
                    'max_votes' => empty($pollInfo['multi']) ? 1 : 0,
                    'close_date' => 0,
                );
    
                $newPollId = $model->importThreadPoll($poll['pid'], $newThreadId, $import, array_map(array($this, '_convertToUtf8'), $pollInfo['choice']), $responseIds);
                if ($newPollId)
                {
                    $donePolls[$poll['pid']] = $newPollId;
    
                    $voters = $this->_getVoters($poll);
    
                    if ($voters)
                    {
                        $checkVote = reset($voters);
    
                        // if member_choices is null, we have only vote counts, not dates and users
                        if (!isset($checkVote['member_choices']))
                        {
                            if (!empty($pollInfo['votes']))
                            {
                                foreach ($pollInfo['votes'] AS $voteOption => $count)
                                {
                                    if (isset($responseIds[$voteOption]))
                                    {
                                        for ($i = 0; $i < $count; $i++)
                                        {
                                            $model->importPollVote($newPollId, 0, $responseIds[$voteOption], 0);
                                        }
                                    }
                                }
                            }
                            else
                            {
                                // weird polls end up here - log if you like
                            }
                        }
                        // we have vote dates and user ids
                        else
                        {
                            $userIdMap = $model->getUserIdsMapFromArray($voters, 'member_id');
                            foreach ($voters AS $voter)
                            {
                                $userId = $this->_mapLookUp($userIdMap, $voter['member_id']);
                                if (!$userId)
                                {
                                    continue;
                                }
    
                                $answers = $this->_prepareAnswers($voter['member_choices']);
    
                                if (!$answers)
                                {
                                    continue;
                                }
    
                                $votes = ($options['whichQuestion'] == 'last' ? end($answers) : reset($answers));
                                if (!is_array($votes))
                                {
                                    // likely a poll with a single question
                                    $votes = $answers;
                                }
    
                                foreach ($votes AS $voteOption)
                                {
                                    if (!is_array($voteOption))
                                    {
                                        $voteOption = array($voteOption);
                                    }
    
                                    foreach ($voteOption AS $option)
                                    {
                                        if (!isset($responseIds[$option]))
                                        {
                                            continue;
                                        }
    
                                        $model->importPollVote($newPollId, $userId, $responseIds[$option], $voter['vote_date']);
                                    }
                                }
                            }
                        }
                    }
                }
    
                $total++;
            }
    
            XenForo_Db::commit();
    
            $this->_session->incrementStepImportTotal($total);
    
            return array($next, $options, $this->_getProgressOutput($next, $options['max']));
        }
    
        protected function _getPolls($start, array $options)
        {
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            return $sDb->fetchAll($sDb->limit(
                '
                    SELECT polls.*
                    FROM ' . $prefix . 'polls AS polls
                    INNER JOIN ' . $prefix . 'topics AS topics ON
                        (topics.tid = polls.tid AND topics.state <> \'link\')
                    WHERE polls.pid > ' . $sDb->quote($start) . '
                    ORDER BY polls.pid
                ', $options['limit']
            ));
        }
    
        protected function _getVoters(array $poll)
        {
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            return $sDb->fetchAll('
                SELECT member_id, vote_date, member_choices
                FROM ' . $prefix . 'voters
                WHERE tid = ' . $sDb->quote($poll['tid']) . '
                AND member_choices IS NOT NULL
            ');
        }
    
        protected function _prepareQuestions($choices)
        {
            try
            {
                return @unserialize(stripslashes($choices));
            }
            catch (Exception $e)
            {
                // unserialize failed, skip importing this poll
                return false;
            }
        }
    
        protected function _prepareAnswers($choices)
        {
            return @unserialize(stripslashes($choices));
        }
    
        public function stepAttachments($start, array $options)
        {
            $options = array_merge(array(
                'limit' => 50,
                'max' => false
            ), $options);
    
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            /* @var $model XenForo_Model_Import */
            $model = $this->_importModel;
    
            if ($options['max'] === false)
            {
                $options['max'] = $sDb->fetchOne('
                    SELECT MAX(attach_id)
                    FROM ' . $prefix . 'attachments
                ');
            }
    
            $attachments = $this->_getAttachments($start, $options);
            if (!$attachments)
            {
                return true;
            }
    
            $next = 0;
            $total = 0;
    
            $userIdMap = $model->getUserIdsMapFromArray($attachments, 'member_id');
    
            $postIdMap = $model->getPostIdsMapFromArray($attachments, 'post_id');
            $posts = $model->getModelFromCache('XenForo_Model_Post')->getPostsByIds($postIdMap);
    
            foreach ($attachments AS $attachment)
            {
                $next = $attachment['attach_id'];
    
                $newPostId = $this->_mapLookUp($postIdMap, $attachment['post_id']);
                if (!$newPostId)
                {
                    continue;
                }
    
                $attachFileOrig = $this->_config['ipboard_path'] . '/uploads/' . $attachment['attach_location'];
                if (!file_exists($attachFileOrig))
                {
                    continue;
                }
    
                $attachFile = tempnam(XenForo_Helper_File::getTempDir(), 'xf');
                copy($attachFileOrig, $attachFile);
    
                $isTemp = true;
    
                $success = $model->importPostAttachment(
                    $attachment['attach_id'],
                    $this->_convertToUtf8($attachment['attach_file']),
                    $attachFile,
                    $this->_mapLookUp($userIdMap, $attachment['member_id'], 0),
                    $newPostId,
                    $attachment['attach_date'],
                    array('view_count' => $attachment['attach_hits']),
                    array($this, 'processAttachmentTags'),
                    $posts[$newPostId]['message']
                );
                if ($success)
                {
                    $total++;
                }
    
                if ($isTemp)
                {
                    @unlink($attachFile);
                }
            }
    
            $this->_session->incrementStepImportTotal($total);
    
            return array($next, $options, $this->_getProgressOutput($next, $options['max']));
        }
    
        protected function _getAttachments($start, array $options)
        {
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            return $sDb->fetchAll($sDb->limit(
                '
                    SELECT
                        attach_id, attach_date, attach_hits,
                        attach_file, attach_location,
                        attach_member_id AS member_id,
                        attach_rel_id AS post_id
                    FROM ' . $prefix . 'attachments
                    WHERE attach_id > ' . $sDb->quote($start) . '
                        AND attach_rel_module = \'post\'
                    ORDER BY attach_id
                ', $options['limit']
            ));
        }
    
        public static function processAttachmentTags($oldAttachmentId, $newAttachmentId, $messageText)
        {
            if (stripos($messageText, '[attach') !== false)
            {
                $messageText = preg_replace("/\[attach]{$oldAttachmentId}\.IPB[\/attach]/siU", "[ATTACH]{$newAttachmentId}[/ATTACH]", $messageText);
            }
    
            return $messageText;
        }
    
        public function configStepReputation(array $options)
        {
            if ($options)
            {
                return false;
            }
    
            return $this->_controller->responseView('XenForo_ViewAdmin_Import_IPBoard_ConfigReputation', 'import_config_likes');
        }
    
        public function stepReputation($start, array $options)
        {
            $options = array_merge(array(
                'fetchLikeUsers' => false,
                'limit' => 100,
                'max' => false
            ), $options);
    
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            /* @var $model XenForo_Model_Import */
            $model = $this->_importModel;
    
            if ($options['max'] === false)
            {
                $options['max'] = $sDb->fetchOne('
                    SELECT MAX(id)
                    FROM ' . $prefix . 'reputation_index
                    WHERE rep_rating > 0
                        AND app = \'forums\'
                        AND type = \'pid\'
                ');
            }
    
            $reputations = $this->_getReputations($start, $options);
            if (!$reputations)
            {
                return true;
            }
    
            $next = 0;
            $total = 0;
    
            $userIds = array();
            foreach ($reputations AS $rep)
            {
                $userIds[] = $rep['member_id'];
                $userIds[] = $rep['author_id'];
            }
    
            $postIdMap = $model->getPostIdsMapFromArray($reputations, 'type_id');
            $userIdMap = $model->getImportContentMap('user', $userIds);
    
            XenForo_Db::beginTransaction();
    
            foreach ($reputations AS $rep)
            {
                $next = $rep['id'];
    
                $newPostId = $this->_mapLookUp($postIdMap, $rep['type_id']);
                if (!$newPostId)
                {
                    continue;
                }
    
                $model->importLike(
                    'post',
                    $newPostId,
                    $this->_mapLookUp($userIdMap, $rep['author_id']),
                    $this->_mapLookUp($userIdMap, $rep['member_id']),
                    $rep['rep_date'],
                    $options['fetchLikeUsers']
                );
    
                $total++;
            }
    
            XenForo_Db::commit();
    
            $this->_session->incrementStepImportTotal($total);
    
            return array($next, $options, $this->_getProgressOutput($next, $options['max']));
        }
    
        protected function _getReputations($start, array $options)
        {
            $sDb = $this->_sourceDb;
            $prefix = $this->_prefix;
    
            return $sDb->fetchAll($sDb->limit(
                '
                    SELECT rep.*,
                        posts.author_id
                    FROM ' . $prefix . 'reputation_index AS rep
                    INNER JOIN ' . $prefix . 'posts AS posts ON
                        (posts.pid = rep.type_id AND rep.app = \'forums\' AND rep.type = \'pid\')
                    WHERE id > ' . $sDb->quote($start) . '
                        AND rep.rep_rating > 0
                    ORDER BY rep.id
                ', $options['limit']
            ));
        }
    
        // Cache fetchers
    
        protected $_groupCache = null;
    
        /**
        * Fetches an array representing all the source user groups
        *
        * @return array [userGroupId => userGroup, userGroupId => userGroup...]
        */
        protected function _getGroupCache()
        {
            if ($this->_groupCache === null)
            {
                $this->_groupCache = array();
    
                $groups = $this->_sourceDb->fetchAll('
                    SELECT groups.*,
                        apr.row_perm_cache AS admin_restrictions
                    FROM ' . $this->_prefix . 'groups AS groups
                    LEFT JOIN ' . $this->_prefix . 'admin_permission_rows AS apr ON
                        (apr.row_id = groups.g_id AND apr.row_id_type = \'group\')
                ');
    
                foreach ($groups AS $group)
                {
                    $this->_groupCache[$group['g_id']] = $group;
                }
            }
    
            return $this->_groupCache;
        }
    
        protected $_appCache = null;
    
        protected $_moduleCache = null;
    
        /**
        * Caches the app_cache and module_cache from IPB
        */
        protected function _cacheAppsAndModules()
        {
            $caches = $this->_sourceDb->fetchPairs('
                SELECT cs_key, cs_value
                FROM ' . $this->_prefix . 'cache_store
                WHERE cs_key IN(\'app_cache\', \'module_cache\')
            ');
    
            $this->_appCache = unserialize($caches['app_cache']);
            $this->_moduleCache = unserialize($caches['module_cache']);
        }
    
        /**
        * Gets the application cache
        *
        * @return array
        */
        protected function _getAppCache()
        {
            if ($this->_appCache === null)
            {
                $this->_cacheAppsAndModules();
            }
    
            return $this->_appCache;
        }
    
        /**
        * Gets the module cache
        *
        * @return array
        */
        protected function _getModuleCache()
        {
            if ($this->_moduleCache === null)
            {
                $this->_cacheAppsAndModules();
            }
    
            return $this->_moduleCache;
        }
    
        // IPB data handling functions
    
        /**
        * Remove HTML line breaks and UTF-8 conversion
        *
        * @param string $message
        *
        * @return string
        */
        protected function _parseIPBoardText($message)
        {
            // Handle HTML line breaks
            $message = preg_replace('/<br( \/)?>(\r?\n)?/si', "\n", $message);
    
            return $this->_convertToUtf8($message, true);
        }
    
        /**
        * Parse out HTML smilies and other stuff we can't use from IP.Board BB code
        *
        * @param string $message
        * @param boolean Auto-link URLs in IP.Board messages
        *
        * @return string
        */
        protected function _parseIPBoardBbCode($message, $autoLink = true)
        {
            $message = $this->_parseIPBoardText($message);
    
            // handle the IPB media format
            if (stripos($message, '[media') !== false)
            {
                $message = $this->_parseIPBoardMediaCode($message);
            }
    
            $search = $this->_getIPBoardBBCodeReplacements();
    
            return preg_replace(array_keys($search), $search, $message);
        }
    
        protected function _getIPBoardBBCodeReplacements()
        {
            return array(
                // HTML image <img /> smilies
                "/<img\s+src='([^']+)'\s+class='bbc_emoticon'\s+alt='([^']+)'\s+\/>/siU"
                    => '\2',
                "/<img[^>]+src=(\"|')[^\"']+(\"|')[^>]*emoid=(\"|')([^\"']+)(\"|')[^>]*>/siU"
                    => '\4',
    
                // translate attachments to something resembling our format in all cases (for quoted content in particular)
                "/\[attachment=(\d+):[^\]]+\]/siU"
                    => '[ATTACH]\1.IPB[/ATTACH]',
    
                // strip anything after a comma in [FONT]
                '/\[(font)=(\'|"|)([^,\]]+)(,[^\]]*)(\2)\]/siU'
                    => '[\1=\2\3\2]'
            );
        }
    
        protected function _parseIPBoardMediaCode($message)
        {
            return preg_replace_callback('#\[media[^\]]*\](http://.*)\[/media\]#siU', array($this, '_convertIPBoardMediaTag'), $message);
        }
    
        protected function _convertIPBoardMediaTag(array $regexMatches)
        {
            if ($embedHtml = XenForo_Helper_Media::convertMediaLinkToEmbedHtml($regexMatches[1]))
            {
                return $embedHtml;
            }
            else
            {
                return '[url]' . $regexMatches[1] . '[/url]';
            }
        }
    
        /**
        * Explodes IPB's ,x,y,z, format into array(x, y, z)
        *
        * @param string $commaList
        *
        * @return array
        */
        protected function _ipbExplode($commaList)
        {
            return preg_split('/,/', $commaList, -1, PREG_SPLIT_NO_EMPTY);
        }
    }
    
    and Slavik said
    Code:
    pool:                 www
    process manager:      ondemand
    start time:           18/Feb/2018:19:09:07 +0000
    start since:          1782
    accepted conn:        779
    listen queue:         0
    max listen queue:     0
    listen queue len:     511
    idle processes:       0
    active processes:     2
    total processes:      2
    max active processes: 2
    max children reached: 0
    slow requests:        0
     
    Last edited: Feb 19, 2018
  2. elargento

    elargento Member

    352
    17
    18
    Jan 4, 2016
    Ratings:
    +44
    Local Time:
    11:32 AM
    10
    Brogan advises on another post:
    but on centminmod I can't find any specific documentation talking about MySQL read/writes. Any clue?

    During import:
    upload_2018-2-18_16-49-44.png
     
  3. eva2000

    eva2000 Administrator Staff Member

    53,142
    12,108
    113
    May 24, 2014
    Brisbane, Australia
    Ratings:
    +18,643
    Local Time:
    12:32 AM
    Nginx 1.27.x
    MariaDB 10.x/11.4+
    You using Xenforo native default importer ? I have actually never used that or done IPB imports. Only do vBulletin imports and I always use for vB to XF importers the BigBoard Imported Xenforo Addon as it's much faster than Xenforo native importer vBulletin Big Board Importer [vBulletin 3 + vBulletin 4]
     
  4. elargento

    elargento Member

    352
    17
    18
    Jan 4, 2016
    Ratings:
    +44
    Local Time:
    11:32 AM
    10
    yup, it's IPB 3.x importer.
     
  5. eva2000

    eva2000 Administrator Staff Member

    53,142
    12,108
    113
    May 24, 2014
    Brisbane, Australia
    Ratings:
    +18,643
    Local Time:
    12:32 AM
    Nginx 1.27.x
    MariaDB 10.x/11.4+
  6. eva2000

    eva2000 Administrator Staff Member

    53,142
    12,108
    113
    May 24, 2014
    Brisbane, Australia
    Ratings:
    +18,643
    Local Time:
    12:32 AM
    Nginx 1.27.x
    MariaDB 10.x/11.4+
    Nginx Amplify is a free service :)