/**
  * Edit or add a user subscription.
  *
  * - Accessed from ?action=admin;area=paidsubscribe;sa=modifyuser
  */
 public function action_modifyuser()
 {
     global $context, $txt, $modSettings;
     require_once SUBSDIR . '/PaidSubscriptions.subs.php';
     loadSubscriptions();
     $context['log_id'] = isset($_REQUEST['lid']) ? (int) $_REQUEST['lid'] : 0;
     $context['sub_id'] = isset($_REQUEST['sid']) ? (int) $_REQUEST['sid'] : 0;
     $context['action_type'] = $context['log_id'] ? 'edit' : 'add';
     // Setup the template.
     $context['sub_template'] = 'modify_user_subscription';
     $context['page_title'] = $txt[$context['action_type'] . '_subscriber'];
     loadJavascriptFile('suggest.js', array('defer' => true));
     // If we haven't been passed the subscription ID get it.
     if ($context['log_id'] && !$context['sub_id']) {
         $context['sub_id'] = validateSubscriptionID($context['log_id']);
     }
     if (!isset($context['subscriptions'][$context['sub_id']])) {
         fatal_lang_error('no_access', false);
     }
     $context['current_subscription'] = $context['subscriptions'][$context['sub_id']];
     // Searching?
     if (isset($_POST['ssearch'])) {
         return $this->action_viewsub();
     } elseif (isset($_REQUEST['save_sub'])) {
         checkSession();
         // Work out the dates...
         $starttime = mktime($_POST['hour'], $_POST['minute'], 0, $_POST['month'], $_POST['day'], $_POST['year']);
         $endtime = mktime($_POST['hourend'], $_POST['minuteend'], 0, $_POST['monthend'], $_POST['dayend'], $_POST['yearend']);
         // Status.
         $status = $_POST['status'];
         // New one?
         if (empty($context['log_id'])) {
             // Find the user...
             require_once SUBSDIR . '/Members.subs.php';
             $member = getMemberByName($_POST['name']);
             if (empty($member)) {
                 fatal_lang_error('error_member_not_found');
             }
             if (alreadySubscribed($context['sub_id'], $member['id_member'])) {
                 fatal_lang_error('member_already_subscribed');
             }
             // Actually put the subscription in place.
             if ($status == 1) {
                 addSubscription($context['sub_id'], $member['id_member'], 0, $starttime, $endtime);
             } else {
                 $details = array('id_subscribe' => $context['sub_id'], 'id_member' => $member['id_member'], 'id_group' => $member['id_group'], 'start_time' => $starttime, 'end_time' => $endtime, 'status' => $status);
                 logSubscription($details);
             }
         } else {
             $subscription_status = getSubscriptionStatus($context['log_id']);
             // Pick the right permission stuff depending on what the status is changing from/to.
             if ($subscription_status['old_status'] == 1 && $status != 1) {
                 removeSubscription($context['sub_id'], $subscription_status['id_member']);
             } elseif ($status == 1 && $subscription_status['old_status'] != 1) {
                 addSubscription($context['sub_id'], $subscription_status['id_member'], 0, $starttime, $endtime);
             } else {
                 $item = array('start_time' => $starttime, 'end_time' => $endtime, 'status' => $status, 'current_log_item' => $context['log_id']);
                 updateSubscriptionItem($item);
             }
         }
         // Done - redirect...
         redirectexit('action=admin;area=paidsubscribe;sa=viewsub;sid=' . $context['sub_id']);
     } elseif (isset($_REQUEST['delete']) || isset($_REQUEST['finished'])) {
         checkSession();
         // Do the actual deletes!
         if (!empty($_REQUEST['delsub'])) {
             $toDelete = array();
             foreach ($_REQUEST['delsub'] as $id => $dummy) {
                 $toDelete[] = (int) $id;
             }
             $deletes = prepareDeleteSubscriptions($toDelete);
             foreach ($deletes as $id_subscribe => $id_member) {
                 removeSubscription($id_subscribe, $id_member, isset($_REQUEST['delete']));
             }
         }
         redirectexit('action=admin;area=paidsubscribe;sa=viewsub;sid=' . $context['sub_id']);
     }
     // Default attributes.
     if ($context['action_type'] == 'add') {
         $context['sub'] = array('id' => 0, 'start' => array('year' => (int) strftime('%Y', time()), 'month' => (int) strftime('%m', time()), 'day' => (int) strftime('%d', time()), 'hour' => (int) strftime('%H', time()), 'min' => (int) strftime('%M', time()) < 10 ? '0' . (int) strftime('%M', time()) : (int) strftime('%M', time()), 'last_day' => 0), 'end' => array('year' => (int) strftime('%Y', time()), 'month' => (int) strftime('%m', time()), 'day' => (int) strftime('%d', time()), 'hour' => (int) strftime('%H', time()), 'min' => (int) strftime('%M', time()) < 10 ? '0' . (int) strftime('%M', time()) : (int) strftime('%M', time()), 'last_day' => 0), 'status' => 1);
         $context['sub']['start']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['sub']['start']['month'] == 12 ? 1 : $context['sub']['start']['month'] + 1, 0, $context['sub']['start']['month'] == 12 ? $context['sub']['start']['year'] + 1 : $context['sub']['start']['year']));
         $context['sub']['end']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['sub']['end']['month'] == 12 ? 1 : $context['sub']['end']['month'] + 1, 0, $context['sub']['end']['month'] == 12 ? $context['sub']['end']['year'] + 1 : $context['sub']['end']['year']));
         if (isset($_GET['uid'])) {
             require_once SUBSDIR . '/Members.subs.php';
             // Get the latest activated member's display name.
             $result = getBasicMemberData((int) $_GET['uid']);
             $context['sub']['username'] = $result['real_name'];
         } else {
             $context['sub']['username'] = '';
         }
     } else {
         $row = getPendingSubscriptions($context['log_id']);
         if (empty($row)) {
             fatal_lang_error('no_access', false);
         }
         // Any pending payments?
         $context['pending_payments'] = array();
         if (!empty($row['pending_details'])) {
             $pending_details = @unserialize($row['pending_details']);
             foreach ($pending_details as $id => $pending) {
                 // Only this type need be displayed.
                 if ($pending[3] == 'payback') {
                     // Work out what the options were.
                     $costs = @unserialize($context['current_subscription']['real_cost']);
                     if ($context['current_subscription']['real_length'] == 'F') {
                         foreach ($costs as $duration => $cost) {
                             if ($cost != 0 && $cost == $pending[1] && $duration == $pending[2]) {
                                 $context['pending_payments'][$id] = array('desc' => sprintf($modSettings['paid_currency_symbol'], $cost . '/' . $txt[$duration]));
                             }
                         }
                     } elseif ($costs['fixed'] == $pending[1]) {
                         $context['pending_payments'][$id] = array('desc' => sprintf($modSettings['paid_currency_symbol'], $costs['fixed']));
                     }
                 }
             }
             // Check if we are adding/removing any.
             if (isset($_GET['pending'])) {
                 foreach ($pending_details as $id => $pending) {
                     // Found the one to action?
                     if ($_GET['pending'] == $id && $pending[3] == 'payback' && isset($context['pending_payments'][$id])) {
                         // Flexible?
                         if (isset($_GET['accept'])) {
                             addSubscription($context['current_subscription']['id'], $row['id_member'], $context['current_subscription']['real_length'] == 'F' ? strtoupper(substr($pending[2], 0, 1)) : 0);
                         }
                         unset($pending_details[$id]);
                         $new_details = serialize($pending_details);
                         // Update the entry.
                         updatePendingSubscription($context['log_id'], $new_details);
                         // Reload
                         redirectexit('action=admin;area=paidsubscribe;sa=modifyuser;lid=' . $context['log_id']);
                     }
                 }
             }
         }
         $context['sub_id'] = $row['id_subscribe'];
         $context['sub'] = array('id' => 0, 'start' => array('year' => (int) strftime('%Y', $row['start_time']), 'month' => (int) strftime('%m', $row['start_time']), 'day' => (int) strftime('%d', $row['start_time']), 'hour' => (int) strftime('%H', $row['start_time']), 'min' => (int) strftime('%M', $row['start_time']) < 10 ? '0' . (int) strftime('%M', $row['start_time']) : (int) strftime('%M', $row['start_time']), 'last_day' => 0), 'end' => array('year' => (int) strftime('%Y', $row['end_time']), 'month' => (int) strftime('%m', $row['end_time']), 'day' => (int) strftime('%d', $row['end_time']), 'hour' => (int) strftime('%H', $row['end_time']), 'min' => (int) strftime('%M', $row['end_time']) < 10 ? '0' . (int) strftime('%M', $row['end_time']) : (int) strftime('%M', $row['end_time']), 'last_day' => 0), 'status' => $row['status'], 'username' => $row['username']);
         $context['sub']['start']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['sub']['start']['month'] == 12 ? 1 : $context['sub']['start']['month'] + 1, 0, $context['sub']['start']['month'] == 12 ? $context['sub']['start']['year'] + 1 : $context['sub']['start']['year']));
         $context['sub']['end']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['sub']['end']['month'] == 12 ? 1 : $context['sub']['end']['month'] + 1, 0, $context['sub']['end']['month'] == 12 ? $context['sub']['end']['year'] + 1 : $context['sub']['end']['year']));
     }
 }
/**
 * Removes a subscription from a user, as in removes the groups.
 *
 * @param int $id_subscribe
 * @param int $id_member
 * @param boolean $delete
 */
function removeSubscription($id_subscribe, $id_member, $delete = false)
{
    global $context;
    $db = database();
    loadSubscriptions();
    // Load the user core bits.
    require_once SUBSDIR . '/Members.subs.php';
    $member_info = getBasicMemberData($id_member, array('moderation' => true));
    // Just in case of errors.
    if (empty($member_info)) {
        $db->query('', '
			DELETE FROM {db_prefix}log_subscribed
			WHERE id_member = {int:current_member}', array('current_member' => $id_member));
        return;
    }
    // Get all of the subscriptions for this user that are active - it will be necessary!
    $request = $db->query('', '
		SELECT
			id_subscribe, old_id_group
		FROM {db_prefix}log_subscribed
		WHERE id_member = {int:current_member}
			AND status = {int:is_active}', array('current_member' => $id_member, 'is_active' => 1));
    // These variables will be handy, honest ;)
    $removals = array();
    $allowed = array();
    $member = array();
    $member['id_group'] = 0;
    $new_id_group = -1;
    while ($row = $db->fetch_assoc($request)) {
        if (!isset($context['subscriptions'][$row['id_subscribe']])) {
            continue;
        }
        // The one we're removing?
        if ($row['id_subscribe'] == $id_subscribe) {
            $removals = explode(',', $context['subscriptions'][$row['id_subscribe']]['add_groups']);
            if ($context['subscriptions'][$row['id_subscribe']]['prim_group'] != 0) {
                $removals[] = $context['subscriptions'][$row['id_subscribe']]['prim_group'];
            }
            $member['id_group'] = $row['old_id_group'];
        } else {
            $allowed = array_merge($allowed, explode(',', $context['subscriptions'][$row['id_subscribe']]['add_groups']));
            if ($context['subscriptions'][$row['id_subscribe']]['prim_group'] != 0) {
                $allowed[] = $context['subscriptions'][$row['id_subscribe']]['prim_group'];
                $new_id_group = $context['subscriptions'][$row['id_subscribe']]['prim_group'];
            }
        }
    }
    $db->free_result($request);
    // Now, for everything we are removing check they defintely are not allowed it.
    $existingGroups = explode(',', $member_info['additional_groups']);
    foreach ($existingGroups as $key => $group) {
        if (empty($group) || in_array($group, $removals) && !in_array($group, $allowed)) {
            unset($existingGroups[$key]);
        }
    }
    // Finally, do something with the current primary group.
    if (in_array($member_info['id_group'], $removals)) {
        // If this primary group is actually allowed keep it.
        if (in_array($member_info['id_group'], $allowed)) {
            $existingGroups[] = $member_info['id_group'];
        }
        // Either way, change the id_group back.
        if ($new_id_group < 1) {
            // If we revert to the old id-group we need to ensure it wasn't from a subscription.
            foreach ($context['subscriptions'] as $id => $group) {
                // It was? Make them a regular member then!
                if ($group['prim_group'] == $member['id_group']) {
                    $member['id_group'] = 0;
                }
            }
            $member_info['id_group'] = $member['id_group'];
        } else {
            $member_info['id_group'] = $new_id_group;
        }
    }
    // Crazy stuff, we seem to have our groups fixed, just make them unique
    $existingGroups = array_unique($existingGroups);
    // Update the member
    assignGroupsToMember($id_member, $member_info['id_group'], $existingGroups);
    // Disable the subscription.
    if (!$delete) {
        $db->query('', '
			UPDATE {db_prefix}log_subscribed
			SET status = {int:not_active}
			WHERE id_member = {int:current_member}
				AND id_subscribe = {int:current_subscription}', array('not_active' => 0, 'current_member' => $id_member, 'current_subscription' => $id_subscribe));
    } else {
        $db->query('', '
			DELETE FROM {db_prefix}log_subscribed
			WHERE id_member = {int:current_member}
				AND id_subscribe = {int:current_subscription}', array('current_member' => $id_member, 'current_subscription' => $id_subscribe));
    }
}
Beispiel #3
0
/**
 * Return the details of the members using a certain range of IPs
 * except the current one
 *
 * @param string[] $ips a list of IP addresses
 * @param int $memID the id of the "current" member (maybe it could be retrieved with currentMemberID)
 */
function getMembersInRange($ips, $memID)
{
    $db = database();
    $message_members = array();
    $members_in_range = array();
    // Get member ID's which are in messages...
    $request = $db->query('', '
		SELECT mem.id_member
		FROM {db_prefix}messages AS m
			INNER JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)
		WHERE m.poster_ip IN ({array_string:ip_list})
		GROUP BY mem.id_member
		HAVING mem.id_member != {int:current_member}', array('current_member' => $memID, 'ip_list' => $ips));
    while ($row = $db->fetch_assoc($request)) {
        $message_members[] = $row['id_member'];
    }
    $db->free_result($request);
    // And then get the member ID's belong to other users
    $request = $db->query('', '
		SELECT id_member
		FROM {db_prefix}members
		WHERE id_member != {int:current_member}
			AND member_ip IN ({array_string:ip_list})', array('current_member' => $memID, 'ip_list' => $ips));
    while ($row = $db->fetch_assoc($request)) {
        $message_members[] = $row['id_member'];
    }
    $db->free_result($request);
    // Once the IDs are all combined, let's clean them up
    $message_members = array_unique($message_members);
    // And finally, fetch their names, cause of the GROUP BY doesn't like giving us that normally.
    if (!empty($message_members)) {
        require_once SUBSDIR . '/Members.subs.php';
        // Get the latest activated member's display name.
        $members_in_range = getBasicMemberData($message_members);
    }
    return $members_in_range;
}
Beispiel #4
0
/**
 * Create a post, either as new topic (id_topic = 0) or in an existing one.
 *
 * The input parameters of this function assume:
 * - Strings have been escaped.
 * - Integers have been cast to integer.
 * - Mandatory parameters are set.
 *
 * @package Posts
 * @param mixed[] $msgOptions
 * @param mixed[] $topicOptions
 * @param mixed[] $posterOptions
 */
function createPost(&$msgOptions, &$topicOptions, &$posterOptions)
{
    global $user_info, $txt, $modSettings;
    $db = database();
    // Set optional parameters to the default value.
    $msgOptions['icon'] = empty($msgOptions['icon']) ? 'xx' : $msgOptions['icon'];
    $msgOptions['smileys_enabled'] = !empty($msgOptions['smileys_enabled']);
    $msgOptions['attachments'] = empty($msgOptions['attachments']) ? array() : $msgOptions['attachments'];
    $msgOptions['approved'] = isset($msgOptions['approved']) ? (int) $msgOptions['approved'] : 1;
    $topicOptions['id'] = empty($topicOptions['id']) ? 0 : (int) $topicOptions['id'];
    $topicOptions['poll'] = isset($topicOptions['poll']) ? (int) $topicOptions['poll'] : null;
    $topicOptions['lock_mode'] = isset($topicOptions['lock_mode']) ? $topicOptions['lock_mode'] : null;
    $topicOptions['sticky_mode'] = isset($topicOptions['sticky_mode']) ? $topicOptions['sticky_mode'] : null;
    $topicOptions['redirect_expires'] = isset($topicOptions['redirect_expires']) ? $topicOptions['redirect_expires'] : null;
    $topicOptions['redirect_topic'] = isset($topicOptions['redirect_topic']) ? $topicOptions['redirect_topic'] : null;
    $posterOptions['id'] = empty($posterOptions['id']) ? 0 : (int) $posterOptions['id'];
    $posterOptions['ip'] = empty($posterOptions['ip']) ? $user_info['ip'] : $posterOptions['ip'];
    // We need to know if the topic is approved. If we're told that's great - if not find out.
    if (!$modSettings['postmod_active']) {
        $topicOptions['is_approved'] = true;
    } elseif (!empty($topicOptions['id']) && !isset($topicOptions['is_approved'])) {
        $request = $db->query('', '
			SELECT approved
			FROM {db_prefix}topics
			WHERE id_topic = {int:id_topic}
			LIMIT 1', array('id_topic' => $topicOptions['id']));
        list($topicOptions['is_approved']) = $db->fetch_row($request);
        $db->free_result($request);
    }
    // If nothing was filled in as name/email address, try the member table.
    if (!isset($posterOptions['name']) || $posterOptions['name'] == '' || empty($posterOptions['email']) && !empty($posterOptions['id'])) {
        if (empty($posterOptions['id'])) {
            $posterOptions['id'] = 0;
            $posterOptions['name'] = $txt['guest_title'];
            $posterOptions['email'] = '';
        } elseif ($posterOptions['id'] != $user_info['id']) {
            require_once SUBSDIR . '/Members.subs.php';
            $result = getBasicMemberData($posterOptions['id']);
            // Couldn't find the current poster?
            if (empty($result)) {
                trigger_error('createPost(): Invalid member id ' . $posterOptions['id'], E_USER_NOTICE);
                $posterOptions['id'] = 0;
                $posterOptions['name'] = $txt['guest_title'];
                $posterOptions['email'] = '';
            } else {
                $posterOptions['name'] = $result['member_name'];
                $posterOptions['email'] = $result['email_address'];
            }
        } else {
            $posterOptions['name'] = $user_info['name'];
            $posterOptions['email'] = $user_info['email'];
        }
    }
    // It's do or die time: forget any user aborts!
    $previous_ignore_user_abort = ignore_user_abort(true);
    $new_topic = empty($topicOptions['id']);
    $message_columns = array('id_board' => 'int', 'id_topic' => 'int', 'id_member' => 'int', 'subject' => 'string-255', 'body' => !empty($modSettings['max_messageLength']) && $modSettings['max_messageLength'] > 65534 ? 'string-' . $modSettings['max_messageLength'] : (empty($modSettings['max_messageLength']) ? 'string' : 'string-65534'), 'poster_name' => 'string-255', 'poster_email' => 'string-255', 'poster_time' => 'int', 'poster_ip' => 'string-255', 'smileys_enabled' => 'int', 'modified_name' => 'string', 'icon' => 'string-16', 'approved' => 'int');
    $message_parameters = array('id_board' => $topicOptions['board'], 'id_topic' => $topicOptions['id'], 'id_member' => $posterOptions['id'], 'subject' => $msgOptions['subject'], 'body' => $msgOptions['body'], 'poster_name' => $posterOptions['name'], 'poster_email' => $posterOptions['email'], 'poster_time' => empty($posterOptions['time']) ? time() : $posterOptions['time'], 'poster_ip' => $posterOptions['ip'], 'smileys_enabled' => $msgOptions['smileys_enabled'] ? 1 : 0, 'modified_name' => '', 'icon' => $msgOptions['icon'], 'approved' => $msgOptions['approved']);
    // What if we want to do anything with posts?
    call_integration_hook('integrate_before_create_post', array(&$msgOptions, &$topicOptions, &$posterOptions, &$message_columns, &$message_parameters));
    // Insert the post.
    $db->insert('', '{db_prefix}messages', $message_columns, $message_parameters, array('id_msg'));
    $msgOptions['id'] = $db->insert_id('{db_prefix}messages', 'id_msg');
    // Something went wrong creating the message...
    if (empty($msgOptions['id'])) {
        return false;
    }
    // Fix the attachments.
    if (!empty($msgOptions['attachments'])) {
        $db->query('', '
			UPDATE {db_prefix}attachments
			SET id_msg = {int:id_msg}
			WHERE id_attach IN ({array_int:attachment_list})', array('attachment_list' => $msgOptions['attachments'], 'id_msg' => $msgOptions['id']));
    }
    // What if we want to export new posts out to a CMS?
    call_integration_hook('integrate_create_post', array($msgOptions, $topicOptions, $posterOptions, $message_columns, $message_parameters));
    // Insert a new topic (if the topicID was left empty.)
    if ($new_topic) {
        $topic_columns = array('id_board' => 'int', 'id_member_started' => 'int', 'id_member_updated' => 'int', 'id_first_msg' => 'int', 'id_last_msg' => 'int', 'locked' => 'int', 'is_sticky' => 'int', 'num_views' => 'int', 'id_poll' => 'int', 'unapproved_posts' => 'int', 'approved' => 'int', 'redirect_expires' => 'int', 'id_redirect_topic' => 'int');
        $topic_parameters = array('id_board' => $topicOptions['board'], 'id_member_started' => $posterOptions['id'], 'id_member_updated' => $posterOptions['id'], 'id_first_msg' => $msgOptions['id'], 'id_last_msg' => $msgOptions['id'], 'locked' => $topicOptions['lock_mode'] === null ? 0 : $topicOptions['lock_mode'], 'is_sticky' => $topicOptions['sticky_mode'] === null ? 0 : $topicOptions['sticky_mode'], 'num_views' => 0, 'id_poll' => $topicOptions['poll'] === null ? 0 : $topicOptions['poll'], 'unapproved_posts' => $msgOptions['approved'] ? 0 : 1, 'approved' => $msgOptions['approved'], 'redirect_expires' => $topicOptions['redirect_expires'] === null ? 0 : $topicOptions['redirect_expires'], 'id_redirect_topic' => $topicOptions['redirect_topic'] === null ? 0 : $topicOptions['redirect_topic']);
        call_integration_hook('integrate_before_create_topic', array(&$msgOptions, &$topicOptions, &$posterOptions, &$topic_columns, &$topic_parameters));
        $db->insert('', '{db_prefix}topics', $topic_columns, $topic_parameters, array('id_topic'));
        $topicOptions['id'] = $db->insert_id('{db_prefix}topics', 'id_topic');
        // The topic couldn't be created for some reason.
        if (empty($topicOptions['id'])) {
            // We should delete the post that did work, though...
            $db->query('', '
				DELETE FROM {db_prefix}messages
				WHERE id_msg = {int:id_msg}', array('id_msg' => $msgOptions['id']));
            return false;
        }
        // Fix the message with the topic.
        $db->query('', '
			UPDATE {db_prefix}messages
			SET id_topic = {int:id_topic}
			WHERE id_msg = {int:id_msg}', array('id_topic' => $topicOptions['id'], 'id_msg' => $msgOptions['id']));
        // There's been a new topic AND a new post today.
        trackStats(array('topics' => '+', 'posts' => '+'));
        updateStats('topic', true);
        updateStats('subject', $topicOptions['id'], $msgOptions['subject']);
        // What if we want to export new topics out to a CMS?
        call_integration_hook('integrate_create_topic', array($msgOptions, $topicOptions, $posterOptions));
    } else {
        $update_parameters = array('poster_id' => $posterOptions['id'], 'id_msg' => $msgOptions['id'], 'locked' => $topicOptions['lock_mode'], 'is_sticky' => $topicOptions['sticky_mode'], 'id_topic' => $topicOptions['id'], 'counter_increment' => 1);
        if ($msgOptions['approved']) {
            $topics_columns = array('id_member_updated = {int:poster_id}', 'id_last_msg = {int:id_msg}', 'num_replies = num_replies + {int:counter_increment}');
        } else {
            $topics_columns = array('unapproved_posts = unapproved_posts + {int:counter_increment}');
        }
        if ($topicOptions['lock_mode'] !== null) {
            $topics_columns[] = 'locked = {int:locked}';
        }
        if ($topicOptions['sticky_mode'] !== null) {
            $topics_columns[] = 'is_sticky = {int:is_sticky}';
        }
        call_integration_hook('integrate_before_modify_topic', array(&$topics_columns, &$update_parameters, &$msgOptions, &$topicOptions, &$posterOptions));
        // Update the number of replies and the lock/sticky status.
        $db->query('', '
			UPDATE {db_prefix}topics
			SET
				' . implode(', ', $topics_columns) . '
			WHERE id_topic = {int:id_topic}', $update_parameters);
        // One new post has been added today.
        trackStats(array('posts' => '+'));
    }
    // Creating is modifying...in a way.
    // @todo id_msg_modified needs to be set when you create a post, now this query is
    // the only place it does get set for post creation.  Why not set it on the insert?
    $db->query('', '
		UPDATE {db_prefix}messages
		SET id_msg_modified = {int:id_msg}
		WHERE id_msg = {int:id_msg}', array('id_msg' => $msgOptions['id']));
    // Increase the number of posts and topics on the board.
    if ($msgOptions['approved']) {
        $db->query('', '
			UPDATE {db_prefix}boards
			SET num_posts = num_posts + 1' . ($new_topic ? ', num_topics = num_topics + 1' : '') . '
			WHERE id_board = {int:id_board}', array('id_board' => $topicOptions['board']));
    } else {
        $db->query('', '
			UPDATE {db_prefix}boards
			SET unapproved_posts = unapproved_posts + 1' . ($new_topic ? ', unapproved_topics = unapproved_topics + 1' : '') . '
			WHERE id_board = {int:id_board}', array('id_board' => $topicOptions['board']));
        // Add to the approval queue too.
        $db->insert('', '{db_prefix}approval_queue', array('id_msg' => 'int'), array($msgOptions['id']), array());
    }
    // Mark inserted topic as read (only for the user calling this function).
    if (!empty($topicOptions['mark_as_read']) && !$user_info['is_guest']) {
        // Since it's likely they *read* it before replying, let's try an UPDATE first.
        if (!$new_topic) {
            $db->query('', '
				UPDATE {db_prefix}log_topics
				SET id_msg = {int:id_msg}
				WHERE id_member = {int:current_member}
					AND id_topic = {int:id_topic}', array('current_member' => $posterOptions['id'], 'id_msg' => $msgOptions['id'], 'id_topic' => $topicOptions['id']));
            $flag = $db->affected_rows() != 0;
        }
        if (empty($flag)) {
            require_once SUBSDIR . '/Topic.subs.php';
            markTopicsRead(array($posterOptions['id'], $topicOptions['id'], $msgOptions['id'], 0), false);
        }
    }
    // If there's a custom search index, it may need updating...
    require_once SUBSDIR . '/Search.subs.php';
    $searchAPI = findSearchAPI();
    if (is_callable(array($searchAPI, 'postCreated'))) {
        $searchAPI->postCreated($msgOptions, $topicOptions, $posterOptions);
    }
    // Increase the post counter for the user that created the post.
    if (!empty($posterOptions['update_post_count']) && !empty($posterOptions['id']) && $msgOptions['approved']) {
        // Are you the one that happened to create this post?
        if ($user_info['id'] == $posterOptions['id']) {
            $user_info['posts']++;
        }
        updateMemberData($posterOptions['id'], array('posts' => '+'));
    }
    // They've posted, so they can make the view count go up one if they really want. (this is to keep views >= replies...)
    $_SESSION['last_read_topic'] = 0;
    // Better safe than sorry.
    if (isset($_SESSION['topicseen_cache'][$topicOptions['board']])) {
        $_SESSION['topicseen_cache'][$topicOptions['board']]--;
    }
    // Update all the stats so everyone knows about this new topic and message.
    updateStats('message', true, $msgOptions['id']);
    // Update the last message on the board assuming it's approved AND the topic is.
    if ($msgOptions['approved']) {
        updateLastMessages($topicOptions['board'], $new_topic || !empty($topicOptions['is_approved']) ? $msgOptions['id'] : 0);
    }
    // Alright, done now... we can abort now, I guess... at least this much is done.
    ignore_user_abort($previous_ignore_user_abort);
    // Success.
    return true;
}
    /**
     * This function actually makes all the group changes
     *
     * @return string
     */
    public function action_groupMembership2()
    {
        global $context, $user_profile, $modSettings, $scripturl, $language;
        $db = database();
        $memID = currentMemberID();
        // Let's be extra cautious...
        if (!$context['user']['is_owner'] || empty($modSettings['show_group_membership'])) {
            isAllowedTo('manage_membergroups');
        }
        if (!isset($_REQUEST['gid']) && !isset($_POST['primary'])) {
            fatal_lang_error('no_access', false);
        }
        checkSession(isset($_GET['gid']) ? 'get' : 'post');
        require_once SUBSDIR . '/Membergroups.subs.php';
        $old_profile =& $user_profile[$memID];
        $context['can_manage_membergroups'] = allowedTo('manage_membergroups');
        $context['can_manage_protected'] = allowedTo('admin_forum');
        // By default the new primary is the old one.
        $newPrimary = $old_profile['id_group'];
        $addGroups = array_flip(explode(',', $old_profile['additional_groups']));
        $canChangePrimary = $old_profile['id_group'] == 0 ? 1 : 0;
        $changeType = isset($_POST['primary']) ? 'primary' : (isset($_POST['req']) ? 'request' : 'free');
        // One way or another, we have a target group in mind...
        $group_id = isset($_REQUEST['gid']) ? (int) $_REQUEST['gid'] : (int) $_POST['primary'];
        $foundTarget = $changeType == 'primary' && $group_id == 0 ? true : false;
        // Sanity check!!
        if ($group_id == 1) {
            isAllowedTo('admin_forum');
        }
        // What ever we are doing, we need to determine if changing primary is possible!
        $groups_details = membergroupsById(array($group_id, $old_profile['id_group']), 0, true);
        // Protected groups require proper permissions!
        if ($group_id != 1 && $groups_details[$group_id]['group_type'] == 1) {
            isAllowedTo('admin_forum');
        }
        foreach ($groups_details as $key => $row) {
            // Is this the new group?
            if ($row['id_group'] == $group_id) {
                $foundTarget = true;
                $group_name = $row['group_name'];
                // Does the group type match what we're doing - are we trying to request a non-requestable group?
                if ($changeType == 'request' && $row['group_type'] != 2) {
                    fatal_lang_error('no_access', false);
                } elseif ($changeType == 'free' && $row['group_type'] == 2 && $old_profile['id_group'] != $row['id_group'] && !isset($addGroups[$row['id_group']])) {
                    fatal_lang_error('no_access', false);
                } elseif ($changeType == 'free' && $row['group_type'] != 3 && $row['group_type'] != 2) {
                    fatal_lang_error('no_access', false);
                }
                // We can't change the primary group if this is hidden!
                if ($row['hidden'] == 2) {
                    $canChangePrimary = false;
                }
            }
            // If this is their old primary, can we change it?
            if ($row['id_group'] == $old_profile['id_group'] && ($row['group_type'] > 1 || $context['can_manage_membergroups']) && $canChangePrimary !== false) {
                $canChangePrimary = 1;
            }
            // If we are not doing a force primary move, don't do it automatically if current primary is not 0.
            if ($changeType != 'primary' && $old_profile['id_group'] != 0) {
                $canChangePrimary = false;
            }
            // If this is the one we are acting on, can we even act?
            if (!$context['can_manage_protected'] && $row['group_type'] == 1 || !$context['can_manage_membergroups'] && $row['group_type'] == 0) {
                $canChangePrimary = false;
            }
        }
        // Didn't find the target?
        if (!$foundTarget) {
            fatal_lang_error('no_access', false);
        }
        // Final security check, don't allow users to promote themselves to admin.
        if ($context['can_manage_membergroups'] && !allowedTo('admin_forum')) {
            $request = $db->query('', '
				SELECT COUNT(permission)
				FROM {db_prefix}permissions
				WHERE id_group = {int:selected_group}
					AND permission = {string:admin_forum}
					AND add_deny = {int:not_denied}', array('selected_group' => $group_id, 'not_denied' => 1, 'admin_forum' => 'admin_forum'));
            list($disallow) = $db->fetch_row($request);
            $db->free_result($request);
            if ($disallow) {
                isAllowedTo('admin_forum');
            }
        }
        // If we're requesting, add the note then return.
        if ($changeType == 'request') {
            $request = $db->query('', '
				SELECT id_member
				FROM {db_prefix}log_group_requests
				WHERE id_member = {int:selected_member}
					AND id_group = {int:selected_group}', array('selected_member' => $memID, 'selected_group' => $group_id));
            if ($db->num_rows($request) != 0) {
                fatal_lang_error('profile_error_already_requested_group');
            }
            $db->free_result($request);
            // Log the request.
            $db->insert('', '{db_prefix}log_group_requests', array('id_member' => 'int', 'id_group' => 'int', 'time_applied' => 'int', 'reason' => 'string-65534'), array($memID, $group_id, time(), $_POST['reason']), array('id_request'));
            // Send an email to all group moderators etc.
            require_once SUBSDIR . '/Mail.subs.php';
            // Do we have any group moderators?
            $request = $db->query('', '
				SELECT id_member
				FROM {db_prefix}group_moderators
				WHERE id_group = {int:selected_group}', array('selected_group' => $group_id));
            $moderators = array();
            while ($row = $db->fetch_assoc($request)) {
                $moderators[] = $row['id_member'];
            }
            $db->free_result($request);
            // Otherwise this is the backup!
            if (empty($moderators)) {
                require_once SUBSDIR . '/Members.subs.php';
                $moderators = membersAllowedTo('manage_membergroups');
            }
            if (!empty($moderators)) {
                require_once SUBSDIR . '/Members.subs.php';
                $members = getBasicMemberData($moderators, array('preferences' => true, 'sort' => 'lngfile'));
                foreach ($members as $member) {
                    if ($member['notify_types'] != 4) {
                        continue;
                    }
                    // Check whether they are interested.
                    if (!empty($member['mod_prefs'])) {
                        list(, , $pref_binary) = explode('|', $member['mod_prefs']);
                        if (!($pref_binary & 4)) {
                            continue;
                        }
                    }
                    $replacements = array('RECPNAME' => $member['member_name'], 'APPYNAME' => $old_profile['member_name'], 'GROUPNAME' => $group_name, 'REASON' => $_POST['reason'], 'MODLINK' => $scripturl . '?action=moderate;area=groups;sa=requests');
                    $emaildata = loadEmailTemplate('request_membership', $replacements, empty($member['lngfile']) || empty($modSettings['userLanguage']) ? $language : $member['lngfile']);
                    sendmail($member['email_address'], $emaildata['subject'], $emaildata['body'], null, null, false, 2);
                }
            }
            return $changeType;
        } elseif ($changeType == 'free') {
            // Are we leaving?
            if ($old_profile['id_group'] == $group_id || isset($addGroups[$group_id])) {
                if ($old_profile['id_group'] == $group_id) {
                    $newPrimary = 0;
                } else {
                    unset($addGroups[$group_id]);
                }
            } else {
                // Can we change the primary, and do we want to?
                if ($canChangePrimary) {
                    if ($old_profile['id_group'] != 0) {
                        $addGroups[$old_profile['id_group']] = -1;
                    }
                    $newPrimary = $group_id;
                } else {
                    $addGroups[$group_id] = -1;
                }
            }
        } elseif ($canChangePrimary) {
            if ($old_profile['id_group'] != 0) {
                $addGroups[$old_profile['id_group']] = -1;
            }
            if (isset($addGroups[$group_id])) {
                unset($addGroups[$group_id]);
            }
            $newPrimary = $group_id;
        }
        // Finally, we can make the changes!
        foreach ($addGroups as $id => $dummy) {
            if (empty($id)) {
                unset($addGroups[$id]);
            }
        }
        $addGroups = implode(',', array_flip($addGroups));
        // Ensure that we don't cache permissions if the group is changing.
        if ($context['user']['is_owner']) {
            $_SESSION['mc']['time'] = 0;
        } else {
            updateSettings(array('settings_updated' => time()));
        }
        updateMemberData($memID, array('id_group' => $newPrimary, 'additional_groups' => $addGroups));
        return $changeType;
    }
Beispiel #6
0
    }
}
if (empty($txnType)) {
    generateSubscriptionError($txt['paid_unknown_transaction_type']);
}
// Get the subscription and member ID amoungst others...
@(list($subscription_id, $member_id) = $gatewayClass->precheck());
// Integer these just in case.
$subscription_id = (int) $subscription_id;
$member_id = (int) $member_id;
// This would be bad...
if (empty($member_id)) {
    generateSubscriptionError($txt['paid_empty_member']);
}
// Verify the member.
$member_info = getBasicMemberData($member_id);
// Didn't find them?
if (empty($member_info)) {
    generateSubscriptionError(sprintf($txt['paid_could_not_find_member'], $member_id));
}
// Get the subscription details.
$request = $db->query('', '
	SELECT cost, length, name
	FROM {db_prefix}subscriptions
	WHERE id_subscribe = {int:current_subscription}', array('current_subscription' => $subscription_id));
// Didn't find it?
if ($db->num_rows($request) === 0) {
    generateSubscriptionError(sprintf($txt['paid_count_not_find_subscription'], $member_id, $subscription_id));
}
$subscription_info = $db->fetch_assoc($request);
$db->free_result($request);
 /**
  * This function will display the contact information for the forum, as well a form to fill in.
  * Accessed by action=coppa
  */
 public function action_coppa()
 {
     global $context, $modSettings, $txt;
     loadLanguage('Login');
     loadTemplate('Register');
     // No User ID??
     if (!isset($_GET['member'])) {
         fatal_lang_error('no_access', false);
     }
     // Get the user details...
     require_once SUBSDIR . '/Members.subs.php';
     $member = getBasicMemberData((int) $_GET['member'], array('authentication' => true));
     // If doesn't exist or not pending coppa
     if (empty($member) || $member['is_activated'] != 5) {
         fatal_lang_error('no_access', false);
     }
     if (isset($_GET['form'])) {
         // Some simple contact stuff for the forum.
         $context['forum_contacts'] = (!empty($modSettings['coppaPost']) ? $modSettings['coppaPost'] . '<br /><br />' : '') . (!empty($modSettings['coppaFax']) ? $modSettings['coppaFax'] . '<br />' : '');
         $context['forum_contacts'] = !empty($context['forum_contacts']) ? $context['forum_name_html_safe'] . '<br />' . $context['forum_contacts'] : '';
         // Showing template?
         if (!isset($_GET['dl'])) {
             // Shortcut for producing underlines.
             $context['ul'] = '<u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</u>';
             Template_Layers::getInstance()->removeAll();
             $context['sub_template'] = 'coppa_form';
             $context['page_title'] = replaceBasicActionUrl($txt['coppa_form_title']);
             $context['coppa_body'] = str_replace(array('{PARENT_NAME}', '{CHILD_NAME}', '{USER_NAME}'), array($context['ul'], $context['ul'], $member['member_name']), replaceBasicActionUrl($txt['coppa_form_body']));
         } else {
             // The data.
             $ul = '                ';
             $crlf = "\r\n";
             $data = $context['forum_contacts'] . $crlf . $txt['coppa_form_address'] . ':' . $crlf . $txt['coppa_form_date'] . ':' . $crlf . $crlf . $crlf . replaceBasicActionUrl($txt['coppa_form_body']);
             $data = str_replace(array('{PARENT_NAME}', '{CHILD_NAME}', '{USER_NAME}', '<br>', '<br />'), array($ul, $ul, $member['member_name'], $crlf, $crlf), $data);
             // Send the headers.
             header('Connection: close');
             header('Content-Disposition: attachment; filename="approval.txt"');
             header('Content-Type: ' . (isBrowser('ie') || isBrowser('opera') ? 'application/octetstream' : 'application/octet-stream'));
             header('Content-Length: ' . count($data));
             echo $data;
             obExit(false);
         }
     } else {
         $context += array('page_title' => $txt['coppa_title'], 'sub_template' => 'coppa');
         $context['coppa'] = array('body' => str_replace('{MINIMUM_AGE}', $modSettings['coppaAge'], replaceBasicActionUrl($txt['coppa_after_registration'])), 'many_options' => !empty($modSettings['coppaPost']) && !empty($modSettings['coppaFax']), 'post' => empty($modSettings['coppaPost']) ? '' : $modSettings['coppaPost'], 'fax' => empty($modSettings['coppaFax']) ? '' : $modSettings['coppaFax'], 'phone' => empty($modSettings['coppaPhone']) ? '' : str_replace('{PHONE_NUMBER}', $modSettings['coppaPhone'], $txt['coppa_send_by_phone']), 'id' => $_GET['member']);
     }
 }
 /**
  * View the forum's error log.
  *
  * What it does:
  * - This method sets all the context up to show the error log for maintenance.
  * - It requires the admin_forum permission.
  * - It is accessed from ?action=admin;area=logs;sa=errorlog.
  *
  * @uses the Errors template and error_log sub template.
  */
 protected function action_log()
 {
     global $scripturl, $txt, $context, $modSettings, $user_profile, $filter;
     // We'll escape some strings...
     $db = database();
     require_once SUBSDIR . '/Error.subs.php';
     // Templates, etc...
     loadLanguage('Maintenance');
     loadTemplate('Errors');
     // You can filter by any of the following columns:
     $filters = array('id_member' => $txt['username'], 'ip' => $txt['ip_address'], 'session' => $txt['session'], 'url' => $txt['error_url'], 'message' => $txt['error_message'], 'error_type' => $txt['error_type'], 'file' => $txt['file'], 'line' => $txt['line']);
     // Set up the filtering...
     if (isset($_GET['value'], $_GET['filter']) && isset($filters[$_GET['filter']])) {
         $filter = array('variable' => $_GET['filter'], 'value' => array('sql' => in_array($_GET['filter'], array('message', 'url', 'file')) ? base64_decode(strtr($_GET['value'], array(' ' => '+'))) : $db->escape_wildcard_string($_GET['value'])), 'href' => ';filter=' . $_GET['filter'] . ';value=' . $_GET['value'], 'entity' => $filters[$_GET['filter']]);
     } elseif (isset($_GET['filter']) || isset($_GET['value'])) {
         unset($_GET['filter'], $_GET['value']);
     }
     // Deleting, are we?
     $type = isset($_POST['delall']) ? 'delall' : (isset($_POST['delete']) ? 'delete' : false);
     $error_list = isset($_POST['delete']) ? $_POST['delete'] : null;
     if ($type != false) {
         // Make sure the session exists and is correct; otherwise, might be a hacker.
         checkSession();
         validateToken('admin-el');
         deleteErrors($type, $filter, $error_list);
         // Go back to where we were.
         if ($type == 'delete') {
             redirectexit('action=admin;area=logs;sa=errorlog' . (isset($_REQUEST['desc']) ? ';desc' : '') . ';start=' . $_GET['start'] . (isset($filter) ? ';filter=' . $_GET['filter'] . ';value=' . $_GET['value'] : ''));
         }
         // Go back to where we were.
         redirectexit('action=admin;area=logs;sa=errorlog' . (isset($_REQUEST['desc']) ? ';desc' : ''));
     }
     $num_errors = numErrors($filter);
     // If this filter is empty...
     if ($num_errors == 0 && isset($filter)) {
         redirectexit('action=admin;area=logs;sa=errorlog' . (isset($_REQUEST['desc']) ? ';desc' : ''));
     }
     // Clean up start.
     if (!isset($_GET['start']) || $_GET['start'] < 0) {
         $_GET['start'] = 0;
     }
     // Do we want to reverse error listing?
     $context['sort_direction'] = isset($_REQUEST['desc']) ? 'down' : 'up';
     // Set the page listing up.
     $context['page_index'] = constructPageIndex($scripturl . '?action=admin;area=logs;sa=errorlog' . ($context['sort_direction'] == 'down' ? ';desc' : '') . (isset($filter) ? $filter['href'] : ''), $_GET['start'], $num_errors, $modSettings['defaultMaxMessages']);
     $context['start'] = $_GET['start'];
     $context['errors'] = array();
     $logdata = getErrorLogData($_GET['start'], $context['sort_direction'], $filter);
     if (!empty($logdata)) {
         $context['errors'] = $logdata['errors'];
         $members = $logdata['members'];
     }
     // Load the member data.
     if (!empty($members)) {
         require_once SUBSDIR . '/Members.subs.php';
         $members = getBasicMemberData($members, array('add_guest' => true));
         // Go through each error and tack the data on.
         foreach ($context['errors'] as $id => $dummy) {
             $memID = $context['errors'][$id]['member']['id'];
             $context['errors'][$id]['member']['username'] = $members[$memID]['member_name'];
             $context['errors'][$id]['member']['name'] = $members[$memID]['real_name'];
             $context['errors'][$id]['member']['href'] = empty($memID) ? '' : $scripturl . '?action=profile;u=' . $memID;
             $context['errors'][$id]['member']['link'] = empty($memID) ? $txt['guest_title'] : '<a href="' . $scripturl . '?action=profile;u=' . $memID . '">' . $context['errors'][$id]['member']['name'] . '</a>';
         }
     }
     // Filtering anything?
     if (isset($filter)) {
         $context['filter'] =& $filter;
         // Set the filtering context.
         if ($filter['variable'] == 'id_member') {
             $id = $filter['value']['sql'];
             loadMemberData($id, false, 'minimal');
             $context['filter']['value']['html'] = '<a href="' . $scripturl . '?action=profile;u=' . $id . '">' . $user_profile[$id]['real_name'] . '</a>';
         } elseif ($filter['variable'] == 'url') {
             $context['filter']['value']['html'] = '\'' . strtr(htmlspecialchars((substr($filter['value']['sql'], 0, 1) == '?' ? $scripturl : '') . $filter['value']['sql'], ENT_COMPAT, 'UTF-8'), array('\\_' => '_')) . '\'';
         } elseif ($filter['variable'] == 'message') {
             $context['filter']['value']['html'] = '\'' . strtr(htmlspecialchars($filter['value']['sql'], ENT_COMPAT, 'UTF-8'), array("\n" => '<br />', '&lt;br /&gt;' => '<br />', "\t" => '&nbsp;&nbsp;&nbsp;', '\\_' => '_', '\\%' => '%', '\\\\' => '\\')) . '\'';
             $context['filter']['value']['html'] = preg_replace('~&amp;lt;span class=&amp;quot;remove&amp;quot;&amp;gt;(.+?)&amp;lt;/span&amp;gt;~', '$1', $context['filter']['value']['html']);
         } elseif ($filter['variable'] == 'error_type') {
             $context['filter']['value']['html'] = '\'' . strtr(htmlspecialchars($filter['value']['sql'], ENT_COMPAT, 'UTF-8'), array("\n" => '<br />', '&lt;br /&gt;' => '<br />', "\t" => '&nbsp;&nbsp;&nbsp;', '\\_' => '_', '\\%' => '%', '\\\\' => '\\')) . '\'';
         } else {
             $context['filter']['value']['html'] =& $filter['value']['sql'];
         }
     }
     $sort = $context['sort_direction'] == 'down' ? ';desc' : '';
     // What type of errors do we have and how many do we have?
     $context['error_types'] = array();
     $context['error_types'] = fetchErrorsByType($filter, $sort);
     $tmp = array_keys($context['error_types']);
     $sum = (int) end($tmp);
     $context['error_types']['all'] = array('label' => $txt['errortype_all'], 'description' => isset($txt['errortype_all_desc']) ? $txt['errortype_all_desc'] : '', 'url' => $scripturl . '?action=admin;area=logs;sa=errorlog' . ($context['sort_direction'] == 'down' ? ';desc' : ''), 'is_selected' => empty($filter));
     // Update the all errors tab with the total number of errors
     $context['error_types']['all']['label'] .= ' (' . $sum . ')';
     // Finally, work out what is the last tab!
     if (isset($context['error_types'][$sum])) {
         $context['error_types'][$sum]['is_last'] = true;
     } else {
         $context['error_types']['all']['is_last'] = true;
     }
     // And this is pretty basic ;).
     $context['page_title'] = $txt['errlog'];
     $context['has_filter'] = isset($filter);
     $context['sub_template'] = 'error_log';
     createToken('admin-el');
 }
Beispiel #9
0
/**
 * This functions determines whether this is the first login of the given user.
 *
 * @package Authorization
 * @param int $id_member the id of the member to check for
 */
function isFirstLogin($id_member)
{
    // First login?
    require_once SUBSDIR . '/Members.subs.php';
    $member = getBasicMemberData($id_member, array('moderation' => true));
    return !empty($member) && $member['last_login'] == 0;
}
Beispiel #10
0
 /**
  * Report for showing all the forum staff members - quite a feat!
  * functions ending with "Report" are responsible for generating data
  * for reporting.
  * they are all called from action_index.
  * never access the context directly, but use the data handling
  * functions to do so.
  */
 public function action_staff()
 {
     global $txt;
     require_once SUBSDIR . '/Members.subs.php';
     require_once SUBSDIR . '/Boards.subs.php';
     require_once SUBSDIR . '/Membergroups.subs.php';
     // Fetch all the board names.
     $boards = fetchBoardsInfo('all');
     $moderators = allBoardModerators(true);
     $boards_moderated = array();
     foreach ($moderators as $id_member => $rows) {
         foreach ($rows as $row) {
             $boards_moderated[$id_member][] = $row['id_board'];
         }
     }
     // Get a list of global moderators (i.e. members with moderation powers).
     $global_mods = array_intersect(membersAllowedTo('moderate_board', 0), membersAllowedTo('approve_posts', 0), membersAllowedTo('remove_any', 0), membersAllowedTo('modify_any', 0));
     // How about anyone else who is special?
     $allStaff = array_merge(membersAllowedTo('admin_forum'), membersAllowedTo('manage_membergroups'), membersAllowedTo('manage_permissions'), array_keys($moderators), $global_mods);
     // Make sure everyone is there once - no admin less important than any other!
     $allStaff = array_unique($allStaff);
     // This is a bit of a cop out - but we're protecting their forum, really!
     if (count($allStaff) > 300) {
         fatal_lang_error('report_error_too_many_staff');
     }
     // Get all the possible membergroups!
     $all_groups = getBasicMembergroupData(array('all'), array(), null, false);
     $groups = array(0 => $txt['full_member']);
     foreach ($all_groups as $row) {
         $groups[$row['id']] = empty($row['online_color']) ? $row['name'] : '<span style="color: ' . $row['online_color'] . '">' . $row['name'] . '</span>';
     }
     // All the fields we'll show.
     $staffSettings = array('position' => $txt['report_staff_position'], 'moderates' => $txt['report_staff_moderates'], 'posts' => $txt['report_staff_posts'], 'last_login' => $txt['report_staff_last_login']);
     // Do it in columns, it's just easier.
     setKeys('cols');
     // Get the latest activated member's display name.
     $result = getBasicMemberData($allStaff, array('moderation' => true, 'sort' => 'real_name'));
     foreach ($result as $row) {
         // Each member gets their own table!.
         newTable($row['real_name'], '', 'left', 'auto', 'left', 200, 'center');
         // First off, add in the side key.
         addData($staffSettings);
         // Create the main data array.
         $staffData = array('position' => isset($groups[$row['id_group']]) ? $groups[$row['id_group']] : $groups[0], 'posts' => $row['posts'], 'last_login' => standardTime($row['last_login']), 'moderates' => array());
         // What do they moderate?
         if (in_array($row['id_member'], $global_mods)) {
             $staffData['moderates'] = '<em>' . $txt['report_staff_all_boards'] . '</em>';
         } elseif (isset($boards_moderated[$row['id_member']])) {
             // Get the names
             foreach ($boards_moderated[$row['id_member']] as $board) {
                 if (isset($boards[$board])) {
                     $staffData['moderates'][] = $boards[$board]['name'];
                 }
             }
             $staffData['moderates'] = implode(', ', $staffData['moderates']);
         } else {
             $staffData['moderates'] = '<em>' . $txt['report_staff_no_boards'] . '</em>';
         }
         // Next add the main data.
         addData($staffData);
     }
 }
Beispiel #11
0
/**
 * Builds the 'query_see_board' element for a certain member
 *
 * @package Members
 * @param integer $id_member a valid member id
 */
function memberQuerySeeBoard($id_member)
{
    global $modSettings;
    $member = getBasicMemberData($id_member, array('moderation' => true));
    if (empty($member['additional_groups'])) {
        $groups = array($member['id_group'], $member['id_post_group']);
    } else {
        $groups = array_merge(array($member['id_group'], $member['id_post_group']), explode(',', $member['additional_groups']));
    }
    foreach ($groups as $k => $v) {
        $groups[$k] = (int) $v;
    }
    $groups = array_unique($groups);
    if (in_array(1, $groups)) {
        return '1=1';
    } else {
        require_once SUBSDIR . '/Boards.subs.php';
        $boards_mod = boardsModerated($id_member);
        $mod_query = empty($boards_mod) ? '' : ' OR b.id_board IN (' . implode(',', $boards_mod) . ')';
        return '((FIND_IN_SET(' . implode(', b.member_groups) != 0 OR FIND_IN_SET(', $groups) . ', b.member_groups) != 0)' . (!empty($modSettings['deny_boards_access']) ? ' AND (FIND_IN_SET(' . implode(', b.deny_member_groups) = 0 AND FIND_IN_SET(', $groups) . ', b.deny_member_groups) = 0)' : '') . $mod_query . ')';
    }
}
 /**
  * List and allow adding/entering all man rules, such as
  *
  * What it does:
  * - If it itches, it will be scratched.
  * - Yes or No are perfectly acceptable answers to almost every question.
  * - Men see in only 16 colors, Peach, for example, is a fruit, not a color.
  *
  * @uses sub template rules
  */
 public function action_manrules()
 {
     global $txt, $context, $user_info, $scripturl;
     require_once SUBSDIR . '/PersonalMessage.subs.php';
     // The link tree - gotta have this :o
     $context['linktree'][] = array('url' => $scripturl . '?action=pm;sa=manrules', 'name' => $txt['pm_manage_rules']);
     $context['page_title'] = $txt['pm_manage_rules'];
     $context['sub_template'] = 'rules';
     // Load them... load them!!
     loadRules();
     // Likely to need all the groups!
     require_once SUBSDIR . '/Membergroups.subs.php';
     $context['groups'] = accessibleGroups();
     // Applying all rules?
     if (isset($_GET['apply'])) {
         checkSession('get');
         applyRules(true);
         redirectexit('action=pm;sa=manrules');
     }
     // Editing a specific rule?
     if (isset($_GET['add'])) {
         $context['rid'] = isset($_GET['rid']) && isset($context['rules'][$_GET['rid']]) ? (int) $_GET['rid'] : 0;
         $context['sub_template'] = 'add_rule';
         // Any known rule
         $js_rules = '';
         foreach ($context['known_rules'] as $rule) {
             $js_rules .= JavaScriptEscape($rule) . ': ' . JavaScriptEscape($txt['pm_rule_' . $rule]) . ',';
         }
         $js_rules = '{' . substr($js_rules, 0, -1) . '}';
         // Any known label
         $js_labels = '';
         foreach ($context['labels'] as $label) {
             if ($label['id'] != -1) {
                 $js_labels .= JavaScriptEscape($label['id'] + 1) . ': ' . JavaScriptEscape($label['name']) . ',';
             }
         }
         $js_labels = '{' . substr($js_labels, 0, -1) . '}';
         // And all of the groups as well
         $js_groups = '';
         foreach ($context['groups'] as $id => $title) {
             $js_groups .= JavaScriptEscape($id) . ': ' . JavaScriptEscape($title) . ',';
         }
         $js_groups = '{' . substr($js_groups, 0, -1) . '}';
         // Oh my, we have a lot of text strings for this
         addJavascriptVar(array('criteriaNum' => 0, 'actionNum' => 0, 'groups' => $js_groups, 'labels' => $js_labels, 'rules' => $js_rules, 'txt_pm_readable_and' => $txt['pm_readable_and'], 'txt_pm_readable_or' => $txt['pm_readable_or'], 'txt_pm_readable_member' => $txt['pm_readable_member'], 'txt_pm_readable_group' => $txt['pm_readable_group'], 'txt_pm_readable_subject ' => $txt['pm_readable_subject'], 'txt_pm_readable_body' => $txt['pm_readable_body'], 'txt_pm_readable_buddy' => $txt['pm_readable_buddy'], 'txt_pm_readable_label' => $txt['pm_readable_label'], 'txt_pm_readable_delete' => $txt['pm_readable_delete'], 'txt_pm_readable_start' => $txt['pm_readable_start'], 'txt_pm_readable_end' => $txt['pm_readable_end'], 'txt_pm_readable_then' => $txt['pm_readable_then'], 'txt_pm_rule_not_defined' => $txt['pm_rule_not_defined'], 'txt_pm_rule_criteria_pick' => $txt['pm_rule_criteria_pick'], 'txt_pm_rule_sel_group' => $txt['pm_rule_sel_group'], 'txt_pm_rule_sel_action' => $txt['pm_rule_sel_action'], 'txt_pm_rule_label' => $txt['pm_rule_label'], 'txt_pm_rule_delete' => $txt['pm_rule_delete'], 'txt_pm_rule_sel_label' => $txt['pm_rule_sel_label']), true);
         // Current rule information...
         if ($context['rid']) {
             $context['rule'] = $context['rules'][$context['rid']];
             $members = array();
             // Need to get member names!
             foreach ($context['rule']['criteria'] as $k => $criteria) {
                 if ($criteria['t'] == 'mid' && !empty($criteria['v'])) {
                     $members[(int) $criteria['v']] = $k;
                 }
             }
             if (!empty($members)) {
                 require_once SUBSDIR . '/Members.subs.php';
                 $result = getBasicMemberData(array_keys($members));
                 foreach ($result as $row) {
                     $context['rule']['criteria'][$members[$row['id_member']]]['v'] = $row['member_name'];
                 }
             }
         } else {
             $context['rule'] = array('id' => '', 'name' => '', 'criteria' => array(), 'actions' => array(), 'logic' => 'and');
         }
         // Add a dummy criteria to allow expansion for none js users.
         $context['rule']['criteria'][] = array('t' => '', 'v' => '');
     } elseif (isset($_GET['save'])) {
         checkSession('post');
         $context['rid'] = isset($_GET['rid']) && isset($context['rules'][$_GET['rid']]) ? (int) $_GET['rid'] : 0;
         // Name is easy!
         $ruleName = Util::htmlspecialchars(trim($_POST['rule_name']));
         if (empty($ruleName)) {
             fatal_lang_error('pm_rule_no_name', false);
         }
         // Sanity check...
         if (empty($_POST['ruletype']) || empty($_POST['acttype'])) {
             fatal_lang_error('pm_rule_no_criteria', false);
         }
         // Let's do the criteria first - it's also hardest!
         $criteria = array();
         foreach ($_POST['ruletype'] as $ind => $type) {
             // Check everything is here...
             if ($type == 'gid' && (!isset($_POST['ruledefgroup'][$ind]) || !isset($context['groups'][$_POST['ruledefgroup'][$ind]]))) {
                 continue;
             } elseif ($type != 'bud' && !isset($_POST['ruledef'][$ind])) {
                 continue;
             }
             // Members need to be found.
             if ($type == 'mid') {
                 require_once SUBSDIR . '/Members.subs.php';
                 $name = trim($_POST['ruledef'][$ind]);
                 $member = getMemberByName($name, true);
                 if (empty($member)) {
                     continue;
                 }
                 $criteria[] = array('t' => 'mid', 'v' => $member['id_member']);
             } elseif ($type == 'bud') {
                 $criteria[] = array('t' => 'bud', 'v' => 1);
             } elseif ($type == 'gid') {
                 $criteria[] = array('t' => 'gid', 'v' => (int) $_POST['ruledefgroup'][$ind]);
             } elseif (in_array($type, array('sub', 'msg')) && trim($_POST['ruledef'][$ind]) != '') {
                 $criteria[] = array('t' => $type, 'v' => Util::htmlspecialchars(trim($_POST['ruledef'][$ind])));
             }
         }
         // Also do the actions!
         $actions = array();
         $doDelete = 0;
         $isOr = $_POST['rule_logic'] == 'or' ? 1 : 0;
         foreach ($_POST['acttype'] as $ind => $type) {
             // Picking a valid label?
             if ($type == 'lab' && (!isset($_POST['labdef'][$ind]) || !isset($context['labels'][$_POST['labdef'][$ind] - 1]))) {
                 continue;
             }
             // Record what we're doing.
             if ($type == 'del') {
                 $doDelete = 1;
             } elseif ($type == 'lab') {
                 $actions[] = array('t' => 'lab', 'v' => (int) $_POST['labdef'][$ind] - 1);
             }
         }
         if (empty($criteria) || empty($actions) && !$doDelete) {
             fatal_lang_error('pm_rule_no_criteria', false);
         }
         // What are we storing?
         $criteria = serialize($criteria);
         $actions = serialize($actions);
         // Create the rule?
         if (empty($context['rid'])) {
             addPMRule($user_info['id'], $ruleName, $criteria, $actions, $doDelete, $isOr);
         } else {
             updatePMRule($user_info['id'], $context['rid'], $ruleName, $criteria, $actions, $doDelete, $isOr);
         }
         redirectexit('action=pm;sa=manrules');
     } elseif (isset($_POST['delselected']) && !empty($_POST['delrule'])) {
         checkSession('post');
         $toDelete = array();
         foreach ($_POST['delrule'] as $k => $v) {
             $toDelete[] = (int) $k;
         }
         if (!empty($toDelete)) {
             deletePMRules($user_info['id'], $toDelete);
         }
         redirectexit('action=pm;sa=manrules');
     }
 }
 /**
  * Editing a membergroup.
  *
  * What it does:
  * - Screen to edit a specific membergroup.
  * - Called by ?action=admin;area=membergroups;sa=edit;group=x.
  * - It requires the manage_membergroups permission.
  * - Also handles the delete button of the edit form.
  * - Redirects to ?action=admin;area=membergroups.
  *
  * @uses the edit_group sub template of ManageMembergroups.
  */
 public function action_edit()
 {
     global $context, $txt, $modSettings;
     $current_group_id = isset($_REQUEST['group']) ? (int) $_REQUEST['group'] : 0;
     if (!empty($modSettings['deny_boards_access'])) {
         loadLanguage('ManagePermissions');
     }
     require_once SUBSDIR . '/Membergroups.subs.php';
     // Make sure this group is editable.
     if (!empty($current_group_id)) {
         $current_group = membergroupById($current_group_id);
     }
     // Now, do we have a valid id?
     if (!allowedTo('admin_forum') && !empty($current_group_id) && $current_group['group_type'] == 1) {
         fatal_lang_error('membergroup_does_not_exist', false);
     }
     // The delete this membergroup button was pressed.
     if (isset($_POST['delete'])) {
         checkSession();
         validateToken('admin-mmg');
         if (empty($current_group_id)) {
             fatal_lang_error('membergroup_does_not_exist', false);
         }
         // Let's delete the group
         deleteMembergroups($current_group['id_group']);
         redirectexit('action=admin;area=membergroups;');
     } elseif (isset($_POST['save'])) {
         // Validate the session.
         checkSession();
         validateToken('admin-mmg');
         if (empty($current_group_id)) {
             fatal_lang_error('membergroup_does_not_exist', false);
         }
         require_once SUBSDIR . '/DataValidator.class.php';
         $validator = new Data_Validator();
         // Cleanup the inputs! :D
         $validator->sanitation_rules(array('max_messages' => 'intval', 'min_posts' => 'intval|abs', 'group_type' => 'intval', 'group_desc' => 'trim|Util::htmlspecialchars', 'group_name' => 'trim|Util::htmlspecialchars', 'group_hidden' => 'intval', 'group_inherit' => 'intval', 'icon_count' => 'intval', 'icon_image' => 'trim|Util::htmlspecialchars', 'online_color' => 'trim|valid_color'));
         $validator->input_processing(array('boardaccess' => 'array'));
         $validator->validation_rules(array('boardaccess' => 'contains[allow,ignore,deny]'));
         $validator->validate($_POST);
         // Can they really inherit from this group?
         if ($validator->group_inherit != -2 && !allowedTo('admin_forum')) {
             $inherit_type = membergroupById($validator->group_inherit);
         }
         $min_posts = $validator->group_type == -1 && $validator->min_posts >= 0 && $current_group['id_group'] > 3 ? $validator->min_posts : ($current_group['id_group'] == 4 ? 0 : -1);
         $group_inherit = $current_group['id_group'] > 1 && $current_group['id_group'] != 3 && (empty($inherit_type['group_type']) || $inherit_type['group_type'] != 1) ? $validator->group_inherit : -2;
         //@todo Don't set online_color for the Moderators group?
         // Do the update of the membergroup settings.
         $properties = array('max_messages' => $validator->max_messages, 'min_posts' => $min_posts, 'group_type' => $validator->group_type < 0 || $validator->group_type > 3 || $validator->group_type == 1 && !allowedTo('admin_forum') ? 0 : $validator->group_type, 'hidden' => !$validator->group_hidden || $min_posts != -1 || $current_group['id_group'] == 3 ? 0 : $validator->group_hidden, 'id_parent' => $group_inherit, 'current_group' => $current_group['id_group'], 'group_name' => $validator->group_name, 'online_color' => $validator->online_color, 'icons' => $validator->icon_count <= 0 ? '' : min($validator->icon_count, 10) . '#' . $validator->icon_image, 'description' => $current_group['id_group'] == 1 || $validator->group_type != -1 ? $validator->group_desc : '');
         updateMembergroupProperties($properties);
         call_integration_hook('integrate_save_membergroup', array($current_group['id_group']));
         // Time to update the boards this membergroup has access to.
         if ($current_group['id_group'] == 2 || $current_group['id_group'] > 3) {
             $changed_boards = array();
             $changed_boards['allow'] = array();
             $changed_boards['deny'] = array();
             $changed_boards['ignore'] = array();
             if ($validator->boardaccess) {
                 foreach ($validator->boardaccess as $group_id => $action) {
                     $changed_boards[$action][] = (int) $group_id;
                 }
             }
             foreach (array('allow', 'deny') as $board_action) {
                 // Find all board this group is in, but shouldn't be in.
                 detachGroupFromBoards($current_group['id_group'], $changed_boards, $board_action);
                 // Add the membergroup to all boards that hadn't been set yet.
                 if (!empty($changed_boards[$board_action])) {
                     assignGroupToBoards($current_group['id_group'], $changed_boards, $board_action);
                 }
             }
         }
         // Remove everyone from this group!
         if ($min_posts != -1) {
             detachDeletedGroupFromMembers($current_group['id_group']);
         } elseif ($current_group['id_group'] != 3) {
             // Making it a hidden group? If so remove everyone with it as primary group (Actually, just make them additional).
             if ($validator->group_hidden == 2) {
                 setGroupToHidden($current_group['id_group']);
             }
             // Either way, let's check our "show group membership" setting is correct.
             validateShowGroupMembership();
         }
         // Do we need to set inherited permissions?
         if ($group_inherit != -2 && $group_inherit != $_POST['old_inherit']) {
             require_once SUBSDIR . '/Permission.subs.php';
             updateChildPermissions($group_inherit);
         }
         // Finally, moderators!
         $moderator_string = isset($_POST['group_moderators']) ? trim($_POST['group_moderators']) : '';
         detachGroupModerators($current_group['id_group']);
         if ((!empty($moderator_string) || !empty($_POST['moderator_list'])) && $min_posts == -1 && $current_group['id_group'] != 3) {
             // Get all the usernames from the string
             if (!empty($moderator_string)) {
                 $moderator_string = strtr(preg_replace('~&amp;#(\\d{4,5}|[2-9]\\d{2,4}|1[2-9]\\d);~', '&#$1;', htmlspecialchars($moderator_string, ENT_QUOTES, 'UTF-8')), array('&quot;' => '"'));
                 preg_match_all('~"([^"]+)"~', $moderator_string, $matches);
                 $moderators = array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $moderator_string)));
                 for ($k = 0, $n = count($moderators); $k < $n; $k++) {
                     $moderators[$k] = trim($moderators[$k]);
                     if (strlen($moderators[$k]) == 0) {
                         unset($moderators[$k]);
                     }
                 }
                 // Find all the id_member's for the member_name's in the list.
                 if (!empty($moderators)) {
                     $group_moderators = getIDMemberFromGroupModerators($moderators);
                 }
             } else {
                 $moderators = array();
                 foreach ($_POST['moderator_list'] as $moderator) {
                     $moderators[] = (int) $moderator;
                 }
                 $group_moderators = array();
                 if (!empty($moderators)) {
                     require_once SUBSDIR . '/Members.subs.php';
                     $members = getBasicMemberData($moderators);
                     foreach ($members as $member) {
                         $group_moderators[] = $member['id_member'];
                     }
                 }
             }
             // Found some?
             if (!empty($group_moderators)) {
                 assignGroupModerators($current_group['id_group'], $group_moderators);
             }
         }
         // There might have been some post group changes.
         updateStats('postgroups');
         // We've definitely changed some group stuff.
         updateSettings(array('settings_updated' => time()));
         // Log the edit.
         logAction('edited_group', array('group' => $validator->group_name), 'admin');
         redirectexit('action=admin;area=membergroups');
     }
     // Fetch the current group information.
     $row = membergroupById($current_group['id_group'], true);
     if (empty($row) || !allowedTo('admin_forum') && $row['group_type'] == 1) {
         fatal_lang_error('membergroup_does_not_exist', false);
     }
     $row['icons'] = explode('#', $row['icons']);
     $context['group'] = array('id' => $row['id_group'], 'name' => $row['group_name'], 'description' => htmlspecialchars($row['description'], ENT_COMPAT, 'UTF-8'), 'editable_name' => $row['group_name'], 'color' => $row['online_color'], 'min_posts' => $row['min_posts'], 'max_messages' => $row['max_messages'], 'icon_count' => (int) $row['icons'][0], 'icon_image' => isset($row['icons'][1]) ? $row['icons'][1] : '', 'is_post_group' => $row['min_posts'] != -1, 'type' => $row['min_posts'] != -1 ? 0 : $row['group_type'], 'hidden' => $row['min_posts'] == -1 ? $row['hidden'] : 0, 'inherited_from' => $row['id_parent'], 'allow_post_group' => $row['id_group'] == 2 || $row['id_group'] > 4, 'allow_delete' => $row['id_group'] == 2 || $row['id_group'] > 4, 'allow_protected' => allowedTo('admin_forum'));
     // Get any moderators for this group
     $context['group']['moderators'] = getGroupModerators($row['id_group']);
     $context['group']['moderator_list'] = empty($context['group']['moderators']) ? '' : '&quot;' . implode('&quot;, &quot;', $context['group']['moderators']) . '&quot;';
     if (!empty($context['group']['moderators'])) {
         list($context['group']['last_moderator_id']) = array_slice(array_keys($context['group']['moderators']), -1);
     }
     // Get a list of boards this membergroup is allowed to see.
     $context['boards'] = array();
     if ($row['id_group'] == 2 || $row['id_group'] > 3) {
         require_once SUBSDIR . '/Boards.subs.php';
         $context += getBoardList(array('override_permissions' => true, 'access' => $row['id_group'], 'not_redirection' => true));
         // Include a list of boards per category for easy toggling.
         foreach ($context['categories'] as $category) {
             $context['categories'][$category['id']]['child_ids'] = array_keys($category['boards']);
         }
     }
     // Finally, get all the groups this could be inherited off.
     $context['inheritable_groups'] = getInheritableGroups($row['id_group']);
     call_integration_hook('integrate_view_membergroup');
     $context['sub_template'] = 'edit_group';
     $context['page_title'] = $txt['membergroups_edit_group'];
     // Use the autosuggest script when needed
     if ($context['group']['id'] != 3 && $context['group']['id'] != 4) {
         loadJavascriptFile('suggest.js', array('defer' => true));
     }
     createToken('admin-mmg');
 }
Beispiel #14
0
/**
 * Given a list of userid's for a PM, finds the member name associated with the ID
 * so it can be presented to the user.
 *
 * - keeps track of bcc and to names for the PM
 *
 * @package Drafts
 * @todo this is the same as whats in PersonalMessage.controller, when that gets refractored
 * this should go away and use the refractored PM subs
 * @param int[] $allRecipients
 * @param mixed[] $recipient_ids
 */
function draftsRecipients($allRecipients, $recipient_ids)
{
    // Holds our results
    $recipients = array('to' => array(), 'bcc' => array());
    require_once SUBSDIR . '/Members.subs.php';
    // Get all the member names that this PM is going to
    $results = getBasicMemberData($allRecipients);
    foreach ($results as $result) {
        // Load the to/bcc name array
        $recipientType = in_array($result['id_member'], $recipient_ids['bcc']) ? 'bcc' : 'to';
        $recipients[$recipientType][] = $result['real_name'];
    }
    return $recipients;
}
 /**
  * Let them see what their signature looks like before they use it like spam
  */
 public function action_sig_preview()
 {
     global $context, $txt, $user_info;
     require_once SUBSDIR . '/Profile.subs.php';
     loadLanguage('Profile');
     loadLanguage('Errors');
     $user = isset($_POST['user']) ? (int) $_POST['user'] : 0;
     $is_owner = $user == $user_info['id'];
     // @todo Temporary
     // Borrowed from loadAttachmentContext in Display.controller.php
     $can_change = $is_owner ? allowedTo(array('profile_extra_any', 'profile_extra_own')) : allowedTo('profile_extra_any');
     $errors = array();
     if (!empty($user) && $can_change) {
         require_once SUBSDIR . '/Members.subs.php';
         // Get the current signature
         $member = getBasicMemberData($user, array('preferences' => true));
         censorText($member['signature']);
         $member['signature'] = parse_bbc($member['signature'], true, 'sig' . $user);
         // And now what they want it to be
         $preview_signature = !empty($_POST['signature']) ? Util::htmlspecialchars($_POST['signature']) : '';
         $validation = profileValidateSignature($preview_signature);
         // An odd check for errors to be sure
         if ($validation !== true && $validation !== false) {
             $errors[] = array('value' => $txt['profile_error_' . $validation], 'attributes' => array('type' => 'error'));
         }
         preparsecode($preview_signature);
         censorText($preview_signature);
         $preview_signature = parse_bbc($preview_signature, true, 'sig' . $user);
     } elseif (!$can_change) {
         if ($is_owner) {
             $errors[] = array('value' => $txt['cannot_profile_extra_own'], 'attributes' => array('type' => 'error'));
         } else {
             $errors[] = array('value' => $txt['cannot_profile_extra_any'], 'attributes' => array('type' => 'error'));
         }
     } else {
         $errors[] = array('value' => $txt['no_user_selected'], 'attributes' => array('type' => 'error'));
     }
     // Return the response for the template
     $context['xml_data']['signatures'] = array('identifier' => 'signature', 'children' => array());
     if (isset($member['signature'])) {
         $context['xml_data']['signatures']['children'][] = array('value' => $member['signature'], 'attributes' => array('type' => 'current'));
     }
     if (isset($preview_signature)) {
         $context['xml_data']['signatures']['children'][] = array('value' => $preview_signature, 'attributes' => array('type' => 'preview'));
     }
     if (!empty($errors)) {
         $context['xml_data']['errors'] = array('identifier' => 'error', 'children' => array_merge(array(array('value' => $txt['profile_errors_occurred'], 'attributes' => array('type' => 'errors_occurred'))), $errors));
     }
 }
 /**
  * Choose a theme from a list.
  * Allows a user or administrator to pick a new theme with an interface.
  *
  * What it does:
  * - Can edit everyone's (u = 0), guests' (u = -1), or a specific user's.
  * - Uses the Themes template. (pick sub template.)
  * - Accessed with ?action=admin;area=theme;sa=pick.
  *
  * @uses Profile language text
  * @uses ManageThemes template
  * @todo thought so... Might be better to split this file in ManageThemes and Themes,
  * with centralized admin permissions on ManageThemes.
  */
 public function action_pick()
 {
     global $txt, $context, $modSettings, $user_info, $scripturl, $settings;
     require_once SUBSDIR . '/Themes.subs.php';
     if (!$modSettings['theme_allow'] && $settings['disable_user_variant'] && !allowedTo('admin_forum')) {
         fatal_lang_error('no_access', false);
     }
     loadLanguage('Profile');
     loadTemplate('ManageThemes');
     // Build the link tree.
     $context['linktree'][] = array('url' => $scripturl . '?action=theme;sa=pick;u=' . (!empty($_REQUEST['u']) ? (int) $_REQUEST['u'] : 0), 'name' => $txt['theme_pick']);
     $context['default_theme_id'] = $modSettings['theme_default'];
     $_SESSION['id_theme'] = 0;
     if (isset($_GET['id'])) {
         $_GET['th'] = $_GET['id'];
     }
     // Saving a variant cause JS doesn't work - pretend it did ;)
     if (isset($_POST['save'])) {
         // Which theme?
         foreach ($_POST['save'] as $k => $v) {
             $_GET['th'] = (int) $k;
         }
         if (isset($_POST['vrt'][$k])) {
             $_GET['vrt'] = $_POST['vrt'][$k];
         }
     }
     // Have we made a decision, or are we just browsing?
     if (isset($_GET['th'])) {
         checkSession('get');
         $_GET['th'] = (int) $_GET['th'];
         // Save for this user.
         if (!isset($_REQUEST['u']) || !allowedTo('admin_forum')) {
             updateMemberData($user_info['id'], array('id_theme' => (int) $_GET['th']));
             // A variants to save for the user?
             if (!empty($_GET['vrt'])) {
                 updateThemeOptions(array($_GET['th'], $user_info['id'], 'theme_variant', $_GET['vrt']));
                 cache_put_data('theme_settings-' . $_GET['th'] . ':' . $user_info['id'], null, 90);
                 $_SESSION['id_variant'] = 0;
             }
             redirectexit('action=profile;area=theme');
         }
         // If changing members or guests - and there's a variant - assume changing default variant.
         if (!empty($_GET['vrt']) && ($_REQUEST['u'] == '0' || $_REQUEST['u'] == '-1')) {
             updateThemeOptions(array($_GET['th'], 0, 'default_variant', $_GET['vrt']));
             // Make it obvious that it's changed
             cache_put_data('theme_settings-' . $_GET['th'], null, 90);
         }
         // For everyone.
         if ($_REQUEST['u'] == '0') {
             updateMemberData(null, array('id_theme' => (int) $_GET['th']));
             // Remove any custom variants.
             if (!empty($_GET['vrt'])) {
                 deleteVariants((int) $_GET['th']);
             }
             redirectexit('action=admin;area=theme;sa=admin;' . $context['session_var'] . '=' . $context['session_id']);
         } elseif ($_REQUEST['u'] == '-1') {
             updateSettings(array('theme_guests' => (int) $_GET['th']));
             redirectexit('action=admin;area=theme;sa=admin;' . $context['session_var'] . '=' . $context['session_id']);
         } else {
             // The forum's default theme is always 0 and we
             if (isset($_GET['th']) && $_GET['th'] == 0) {
                 $_GET['th'] = $modSettings['theme_guests'];
             }
             updateMemberData((int) $_REQUEST['u'], array('id_theme' => (int) $_GET['th']));
             if (!empty($_GET['vrt'])) {
                 updateThemeOptions(array($_GET['th'], (int) $_REQUEST['u'], 'theme_variant', $_GET['vrt']));
                 cache_put_data('theme_settings-' . $_GET['th'] . ':' . (int) $_REQUEST['u'], null, 90);
                 if ($user_info['id'] == $_REQUEST['u']) {
                     $_SESSION['id_variant'] = 0;
                 }
             }
             redirectexit('action=profile;u=' . (int) $_REQUEST['u'] . ';area=theme');
         }
     }
     // Figure out who the member of the minute is, and what theme they've chosen.
     if (!isset($_REQUEST['u']) || !allowedTo('admin_forum')) {
         $context['current_member'] = $user_info['id'];
         $current_theme = $user_info['theme'];
     } elseif ($_REQUEST['u'] == '0') {
         $context['current_member'] = 0;
         $current_theme = 0;
     } elseif ($_REQUEST['u'] == '-1') {
         $context['current_member'] = -1;
         $current_theme = $modSettings['theme_guests'];
     } else {
         $context['current_member'] = (int) $_REQUEST['u'];
         require_once SUBSDIR . '/Members.subs.php';
         $member = getBasicMemberData($context['current_member']);
         $current_theme = $member['id_theme'];
     }
     // Get the theme name and descriptions.
     list($context['available_themes'], $guest_theme) = availableThemes($current_theme, $context['current_member']);
     // As long as we're not doing the default theme...
     if (!isset($_REQUEST['u']) || $_REQUEST['u'] >= 0) {
         if ($guest_theme != 0) {
             $context['available_themes'][0] = $context['available_themes'][$guest_theme];
         }
         $context['available_themes'][0]['id'] = 0;
         $context['available_themes'][0]['name'] = $txt['theme_forum_default'];
         $context['available_themes'][0]['selected'] = $current_theme == 0;
         $context['available_themes'][0]['description'] = $txt['theme_global_description'];
     }
     ksort($context['available_themes']);
     $context['page_title'] = $txt['theme_pick'];
     $context['sub_template'] = 'pick';
 }
/**
 * Sends a personal message from the specified person to the specified people
 * ($from defaults to the user)
 *
 * @package PersonalMessage
 * @param mixed[] $recipients - an array containing the arrays 'to' and 'bcc', both containing id_member's.
 * @param string $subject - should have no slashes and no html entities
 * @param string $message - should have no slashes and no html entities
 * @param bool $store_outbox
 * @param mixed[]|null $from - an array with the id, name, and username of the member.
 * @param int $pm_head - the ID of the chain being replied to - if any.
 * @return mixed[] an array with log entries telling how many recipients were successful and which recipients it failed to send to.
 */
function sendpm($recipients, $subject, $message, $store_outbox = true, $from = null, $pm_head = 0)
{
    global $scripturl, $txt, $user_info, $language, $modSettings, $webmaster_email;
    $db = database();
    // Make sure the PM language file is loaded, we might need something out of it.
    loadLanguage('PersonalMessage');
    // Needed for our email and post functions
    require_once SUBSDIR . '/Mail.subs.php';
    require_once SUBSDIR . '/Post.subs.php';
    // Initialize log array.
    $log = array('failed' => array(), 'sent' => array());
    if ($from === null) {
        $from = array('id' => $user_info['id'], 'name' => $user_info['name'], 'username' => $user_info['username']);
    } else {
        $user_info['name'] = $from['name'];
    }
    // This is the one that will go in their inbox.
    $htmlmessage = Util::htmlspecialchars($message, ENT_QUOTES, 'UTF-8', true);
    preparsecode($htmlmessage);
    $htmlsubject = strtr(Util::htmlspecialchars($subject), array("\r" => '', "\n" => '', "\t" => ''));
    if (Util::strlen($htmlsubject) > 100) {
        $htmlsubject = Util::substr($htmlsubject, 0, 100);
    }
    // Make sure is an array
    if (!is_array($recipients)) {
        $recipients = array($recipients);
    }
    // Integrated PMs
    call_integration_hook('integrate_personal_message', array(&$recipients, &$from, &$subject, &$message));
    // Get a list of usernames and convert them to IDs.
    $usernames = array();
    foreach ($recipients as $rec_type => $rec) {
        foreach ($rec as $id => $member) {
            if (!is_numeric($recipients[$rec_type][$id])) {
                $recipients[$rec_type][$id] = Util::strtolower(trim(preg_replace('/[<>&"\'=\\\\]/', '', $recipients[$rec_type][$id])));
                $usernames[$recipients[$rec_type][$id]] = 0;
            }
        }
    }
    if (!empty($usernames)) {
        $request = $db->query('pm_find_username', '
			SELECT
				id_member, member_name
			FROM {db_prefix}members
			WHERE ' . (defined('DB_CASE_SENSITIVE') ? 'LOWER(member_name)' : 'member_name') . ' IN ({array_string:usernames})', array('usernames' => array_keys($usernames)));
        while ($row = $db->fetch_assoc($request)) {
            if (isset($usernames[Util::strtolower($row['member_name'])])) {
                $usernames[Util::strtolower($row['member_name'])] = $row['id_member'];
            }
        }
        $db->free_result($request);
        // Replace the usernames with IDs. Drop usernames that couldn't be found.
        foreach ($recipients as $rec_type => $rec) {
            foreach ($rec as $id => $member) {
                if (is_numeric($recipients[$rec_type][$id])) {
                    continue;
                }
                if (!empty($usernames[$member])) {
                    $recipients[$rec_type][$id] = $usernames[$member];
                } else {
                    $log['failed'][$id] = sprintf($txt['pm_error_user_not_found'], $recipients[$rec_type][$id]);
                    unset($recipients[$rec_type][$id]);
                }
            }
        }
    }
    // Make sure there are no duplicate 'to' members.
    $recipients['to'] = array_unique($recipients['to']);
    // Only 'bcc' members that aren't already in 'to'.
    $recipients['bcc'] = array_diff(array_unique($recipients['bcc']), $recipients['to']);
    // Combine 'to' and 'bcc' recipients.
    $all_to = array_merge($recipients['to'], $recipients['bcc']);
    // Check no-one will want it deleted right away!
    $request = $db->query('', '
		SELECT
			id_member, criteria, is_or
		FROM {db_prefix}pm_rules
		WHERE id_member IN ({array_int:to_members})
			AND delete_pm = {int:delete_pm}', array('to_members' => $all_to, 'delete_pm' => 1));
    $deletes = array();
    // Check whether we have to apply anything...
    while ($row = $db->fetch_assoc($request)) {
        $criteria = unserialize($row['criteria']);
        // Note we don't check the buddy status, cause deletion from buddy = madness!
        $delete = false;
        foreach ($criteria as $criterium) {
            if ($criterium['t'] == 'mid' && $criterium['v'] == $from['id'] || $criterium['t'] == 'gid' && in_array($criterium['v'], $user_info['groups']) || $criterium['t'] == 'sub' && strpos($subject, $criterium['v']) !== false || $criterium['t'] == 'msg' && strpos($message, $criterium['v']) !== false) {
                $delete = true;
            } elseif (!$row['is_or']) {
                $delete = false;
                break;
            }
        }
        if ($delete) {
            $deletes[$row['id_member']] = 1;
        }
    }
    $db->free_result($request);
    // Load the membergrounp message limits.
    static $message_limit_cache = array();
    if (!allowedTo('moderate_forum') && empty($message_limit_cache)) {
        $request = $db->query('', '
			SELECT
				id_group, max_messages
			FROM {db_prefix}membergroups', array());
        while ($row = $db->fetch_assoc($request)) {
            $message_limit_cache[$row['id_group']] = $row['max_messages'];
        }
        $db->free_result($request);
    }
    // Load the groups that are allowed to read PMs.
    // @todo move into a separate function on $permission.
    $allowed_groups = array();
    $disallowed_groups = array();
    $request = $db->query('', '
		SELECT
			id_group, add_deny
		FROM {db_prefix}permissions
		WHERE permission = {string:read_permission}', array('read_permission' => 'pm_read'));
    while ($row = $db->fetch_assoc($request)) {
        if (empty($row['add_deny'])) {
            $disallowed_groups[] = $row['id_group'];
        } else {
            $allowed_groups[] = $row['id_group'];
        }
    }
    $db->free_result($request);
    if (empty($modSettings['permission_enable_deny'])) {
        $disallowed_groups = array();
    }
    $request = $db->query('', '
		SELECT
			member_name, real_name, id_member, email_address, lngfile,
			pm_email_notify, personal_messages,' . (allowedTo('moderate_forum') ? ' 0' : '
			(receive_from = {int:admins_only}' . (empty($modSettings['enable_buddylist']) ? '' : ' OR
			(receive_from = {int:buddies_only} AND FIND_IN_SET({string:from_id}, buddy_list) = 0) OR
			(receive_from = {int:not_on_ignore_list} AND FIND_IN_SET({string:from_id}, pm_ignore_list) != 0)') . ')') . ' AS ignored,
			FIND_IN_SET({string:from_id}, buddy_list) != 0 AS is_buddy, is_activated,
			additional_groups, id_group, id_post_group
		FROM {db_prefix}members
		WHERE id_member IN ({array_int:recipients})
		ORDER BY lngfile
		LIMIT {int:count_recipients}', array('not_on_ignore_list' => 1, 'buddies_only' => 2, 'admins_only' => 3, 'recipients' => $all_to, 'count_recipients' => count($all_to), 'from_id' => $from['id']));
    $notifications = array();
    while ($row = $db->fetch_assoc($request)) {
        // Don't do anything for members to be deleted!
        if (isset($deletes[$row['id_member']])) {
            continue;
        }
        // We need to know this members groups.
        $groups = explode(',', $row['additional_groups']);
        $groups[] = $row['id_group'];
        $groups[] = $row['id_post_group'];
        $message_limit = -1;
        // For each group see whether they've gone over their limit - assuming they're not an admin.
        if (!in_array(1, $groups)) {
            foreach ($groups as $id) {
                if (isset($message_limit_cache[$id]) && $message_limit != 0 && $message_limit < $message_limit_cache[$id]) {
                    $message_limit = $message_limit_cache[$id];
                }
            }
            if ($message_limit > 0 && $message_limit <= $row['personal_messages']) {
                $log['failed'][$row['id_member']] = sprintf($txt['pm_error_data_limit_reached'], $row['real_name']);
                unset($all_to[array_search($row['id_member'], $all_to)]);
                continue;
            }
            // Do they have any of the allowed groups?
            if (count(array_intersect($allowed_groups, $groups)) == 0 || count(array_intersect($disallowed_groups, $groups)) != 0) {
                $log['failed'][$row['id_member']] = sprintf($txt['pm_error_user_cannot_read'], $row['real_name']);
                unset($all_to[array_search($row['id_member'], $all_to)]);
                continue;
            }
        }
        // Note that PostgreSQL can return a lowercase t/f for FIND_IN_SET
        if (!empty($row['ignored']) && $row['ignored'] != 'f' && $row['id_member'] != $from['id']) {
            $log['failed'][$row['id_member']] = sprintf($txt['pm_error_ignored_by_user'], $row['real_name']);
            unset($all_to[array_search($row['id_member'], $all_to)]);
            continue;
        }
        // If the receiving account is banned (>=10) or pending deletion (4), refuse to send the PM.
        if ($row['is_activated'] >= 10 || $row['is_activated'] == 4 && !$user_info['is_admin']) {
            $log['failed'][$row['id_member']] = sprintf($txt['pm_error_user_cannot_read'], $row['real_name']);
            unset($all_to[array_search($row['id_member'], $all_to)]);
            continue;
        }
        // Send a notification, if enabled - taking the buddy list into account.
        if (!empty($row['email_address']) && ($row['pm_email_notify'] == 1 || $row['pm_email_notify'] > 1 && (!empty($modSettings['enable_buddylist']) && $row['is_buddy'])) && $row['is_activated'] == 1) {
            $notifications[empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']][] = $row['email_address'];
        }
        $log['sent'][$row['id_member']] = sprintf(isset($txt['pm_successfully_sent']) ? $txt['pm_successfully_sent'] : '', $row['real_name']);
    }
    $db->free_result($request);
    // Only 'send' the message if there are any recipients left.
    if (empty($all_to)) {
        return $log;
    }
    // Track the pm count for our stats
    if (!empty($modSettings['trackStats'])) {
        trackStats(array('pm' => '+'));
    }
    // Insert the message itself and then grab the last insert id.
    $db->insert('', '{db_prefix}personal_messages', array('id_pm_head' => 'int', 'id_member_from' => 'int', 'deleted_by_sender' => 'int', 'from_name' => 'string-255', 'msgtime' => 'int', 'subject' => 'string-255', 'body' => 'string-65534'), array($pm_head, $from['id'], $store_outbox ? 0 : 1, $from['username'], time(), $htmlsubject, $htmlmessage), array('id_pm'));
    $id_pm = $db->insert_id('{db_prefix}personal_messages', 'id_pm');
    // Add the recipients.
    if (!empty($id_pm)) {
        // If this is new we need to set it part of it's own conversation.
        if (empty($pm_head)) {
            $db->query('', '
				UPDATE {db_prefix}personal_messages
				SET id_pm_head = {int:id_pm_head}
				WHERE id_pm = {int:id_pm_head}', array('id_pm_head' => $id_pm));
        }
        // Some people think manually deleting personal_messages is fun... it's not. We protect against it though :)
        $db->query('', '
			DELETE FROM {db_prefix}pm_recipients
			WHERE id_pm = {int:id_pm}', array('id_pm' => $id_pm));
        $insertRows = array();
        $to_list = array();
        foreach ($all_to as $to) {
            $insertRows[] = array($id_pm, $to, in_array($to, $recipients['bcc']) ? 1 : 0, isset($deletes[$to]) ? 1 : 0, 1);
            if (!in_array($to, $recipients['bcc'])) {
                $to_list[] = $to;
            }
        }
        $db->insert('insert', '{db_prefix}pm_recipients', array('id_pm' => 'int', 'id_member' => 'int', 'bcc' => 'int', 'deleted' => 'int', 'is_new' => 'int'), $insertRows, array('id_pm', 'id_member'));
    }
    $maillist = !empty($modSettings['maillist_enabled']) && !empty($modSettings['pbe_pm_enabled']);
    // If they have post by email enabled, override disallow_sendBody
    if (!$maillist && !empty($modSettings['disallow_sendBody'])) {
        $message = '';
        censorText($subject);
    } else {
        require_once SUBSDIR . '/Emailpost.subs.php';
        pbe_prepare_text($message, $subject);
    }
    $to_names = array();
    if (count($to_list) > 1) {
        require_once SUBSDIR . '/Members.subs.php';
        $result = getBasicMemberData($to_list);
        foreach ($result as $row) {
            $to_names[] = un_htmlspecialchars($row['real_name']);
        }
    }
    $replacements = array('SUBJECT' => $subject, 'MESSAGE' => $message, 'SENDER' => un_htmlspecialchars($from['name']), 'READLINK' => $scripturl . '?action=pm;pmsg=' . $id_pm . '#msg' . $id_pm, 'REPLYLINK' => $scripturl . '?action=pm;sa=send;f=inbox;pmsg=' . $id_pm . ';quote;u=' . $from['id'], 'TOLIST' => implode(', ', $to_names));
    // Select the right template
    $email_template = ($maillist && empty($modSettings['disallow_sendBody']) ? 'pbe_' : '') . 'new_pm' . (empty($modSettings['disallow_sendBody']) ? '_body' : '') . (!empty($to_names) ? '_tolist' : '');
    foreach ($notifications as $lang => $notification_list) {
        // Using maillist functionality
        if ($maillist) {
            $sender_details = query_sender_wrapper($from['id']);
            $from_wrapper = !empty($modSettings['maillist_mail_from']) ? $modSettings['maillist_mail_from'] : (empty($modSettings['maillist_sitename_address']) ? $webmaster_email : $modSettings['maillist_sitename_address']);
            // Add in the signature
            $replacements['SIGNATURE'] = $sender_details['signature'];
            // And off it goes, looking a bit more personal
            $mail = loadEmailTemplate($email_template, $replacements, $lang);
            $reference = !empty($pm_head) ? $pm_head : null;
            sendmail($notification_list, $mail['subject'], $mail['body'], $from['name'], 'p' . $id_pm, false, 2, null, true, $from_wrapper, $reference);
        } else {
            // Off the notification email goes!
            $mail = loadEmailTemplate($email_template, $replacements, $lang);
            sendmail($notification_list, $mail['subject'], $mail['body'], null, 'p' . $id_pm, false, 2, null, true);
        }
    }
    // Integrated After PMs
    call_integration_hook('integrate_personal_message_after', array(&$id_pm, &$log, &$recipients, &$from, &$subject, &$message));
    // Back to what we were on before!
    loadLanguage('index+PersonalMessage');
    // Add one to their unread and read message counts.
    foreach ($all_to as $k => $id) {
        if (isset($deletes[$id])) {
            unset($all_to[$k]);
        }
    }
    if (!empty($all_to)) {
        updateMemberData($all_to, array('personal_messages' => '+', 'unread_messages' => '+', 'new_pm' => 1));
    }
    return $log;
}
 /**
  * View the forum's badbehavior log.
  *
  * What it does:
  * - This function sets all the context up to show the badbehavior log for review.
  * - It requires the maintain_forum permission.
  * - It is accessed from ?action=admin;area=logs;sa=badbehaviorlog.
  *
  * @uses the BadBehavior template and badbehavior_log sub template.
  */
 public function action_log()
 {
     global $scripturl, $txt, $context, $modSettings, $user_profile, $filter;
     $db = database();
     // Check for the administrative permission to do this.
     isAllowedTo('admin_forum');
     // Templates, etc...
     loadLanguage('BadBehaviorlog');
     loadTemplate('BadBehavior');
     // Functions we will need
     require_once SUBSDIR . '/BadBehavior.subs.php';
     // You can filter by any of the following columns:
     $filters = array('id_member' => $txt['badbehaviorlog_username'], 'ip' => $txt['badbehaviorlog_ip'], 'session' => $txt['badbehaviorlog_session'], 'valid' => $txt['badbehaviorlog_key'], 'request_uri' => $txt['badbehaviorlog_request'], 'user_agent' => $txt['badbehaviorlog_agent']);
     // Set up the filtering...
     $filter = array();
     if (isset($_GET['value'], $_GET['filter']) && isset($filters[$_GET['filter']])) {
         $filter = array('variable' => $_GET['filter'] == 'useragent' ? 'user_agent' : $_GET['filter'], 'value' => array('sql' => in_array($_GET['filter'], array('request_uri', 'user_agent')) ? base64_decode(strtr($_GET['value'], array(' ' => '+'))) : $db->escape_wildcard_string($_GET['value'])), 'href' => ';filter=' . $_GET['filter'] . ';value=' . $_GET['value'], 'entity' => $filters[$_GET['filter']]);
     } elseif (isset($_GET['filter']) || isset($_GET['value'])) {
         // Bad filter or something else going on, back to the start you go
         unset($_GET['filter'], $_GET['value']);
         redirectexit('action=admin;area=logs;sa=badbehaviorlog' . (isset($_REQUEST['desc']) ? ';desc' : ''));
     }
     // Deleting or just doing a little weeding?
     if (isset($_POST['delall']) || isset($_POST['delete'])) {
         $type = isset($_POST['delall']) ? 'delall' : 'delete';
         // Make sure the session exists and the token is correct
         checkSession();
         validateToken('admin-bbl');
         $redirect = deleteBadBehavior($type, $filter);
         if ($redirect === 'delete') {
             $start = isset($_REQUEST['start']) ? (int) $_REQUEST['start'] : 0;
             // Go back to where we were.
             redirectexit('action=admin;area=logs;sa=badbehaviorlog' . (isset($_REQUEST['desc']) ? ';desc' : '') . ';start=' . $start . (!empty($filter) ? ';filter=' . $_GET['filter'] . ';value=' . $_GET['value'] : ''));
         }
         redirectexit('action=admin;area=logs;sa=badbehaviorlog' . (isset($_REQUEST['desc']) ? ';desc' : ''));
     }
     // Just how many entries are there?
     $num_errors = getBadBehaviorLogEntryCount($filter);
     // If this filter turns up empty, just return
     if (empty($num_errors) && !empty($filter)) {
         redirectexit('action=admin;area=logs;sa=badbehaviorlog' . (isset($_REQUEST['desc']) ? ';desc' : ''));
     }
     // Clean up start.
     $start = !isset($_GET['start']) || $_GET['start'] < 0 ? 0 : (int) $_GET['start'];
     // Do we want to reverse the listing?
     $sort = isset($_REQUEST['desc']) ? 'down' : 'up';
     // Set the page listing up.
     $context['page_index'] = constructPageIndex($scripturl . '?action=admin;area=logs;sa=badbehaviorlog' . ($sort == 'down' ? ';desc' : '') . (!empty($filter) ? $filter['href'] : ''), $start, $num_errors, $modSettings['defaultMaxMessages']);
     // Find and sort out the log entries.
     $context['bb_entries'] = getBadBehaviorLogEntries($start, $modSettings['defaultMaxMessages'], $sort, $filter);
     $members = array();
     foreach ($context['bb_entries'] as $member) {
         $members[] = $member['member']['id'];
     }
     // Load the member data so we have more information available
     if (!empty($members)) {
         require_once SUBSDIR . '/Members.subs.php';
         $members = getBasicMemberData($members, array('add_guest' => true));
         // Go through each entry and add the member data.
         foreach ($context['bb_entries'] as $id => $dummy) {
             $memID = $context['bb_entries'][$id]['member']['id'];
             $context['bb_entries'][$id]['member']['username'] = $members[$memID]['member_name'];
             $context['bb_entries'][$id]['member']['name'] = $members[$memID]['real_name'];
             $context['bb_entries'][$id]['member']['href'] = empty($memID) ? '' : $scripturl . '?action=profile;u=' . $memID;
             $context['bb_entries'][$id]['member']['link'] = empty($memID) ? $txt['guest_title'] : '<a href="' . $scripturl . '?action=profile;u=' . $memID . '">' . $context['bb_entries'][$id]['member']['name'] . '</a>';
         }
     }
     // Filtering?
     if (!empty($filter)) {
         $context['filter'] = $filter;
         // Set the filtering context.
         if ($filter['variable'] === 'id_member') {
             $id = $filter['value']['sql'];
             loadMemberData($id, false, 'minimal');
             $context['filter']['value']['html'] = '<a href="' . $scripturl . '?action=profile;u=' . $id . '">' . $user_profile[$id]['real_name'] . '</a>';
         } elseif ($filter['variable'] === 'url') {
             $context['filter']['value']['html'] = '\'' . strtr(htmlspecialchars((substr($filter['value']['sql'], 0, 1) === '?' ? $scripturl : '') . $filter['value']['sql'], ENT_COMPAT, 'UTF-8'), array('\\_' => '_')) . '\'';
         } elseif ($filter['variable'] === 'headers') {
             $context['filter']['value']['html'] = '\'' . strtr(htmlspecialchars($filter['value']['sql'], ENT_COMPAT, 'UTF-8'), array("\n" => '<br />', '&lt;br /&gt;' => '<br />', "\t" => '&nbsp;&nbsp;&nbsp;', '\\_' => '_', '\\%' => '%', '\\\\' => '\\')) . '\'';
             $context['filter']['value']['html'] = preg_replace('~&amp;lt;span class=&amp;quot;remove&amp;quot;&amp;gt;(.+?)&amp;lt;/span&amp;gt;~', '$1', $context['filter']['value']['html']);
         } else {
             $context['filter']['value']['html'] = $filter['value']['sql'];
         }
     }
     // And the standard template goodies
     $context['page_title'] = $txt['badbehaviorlog_log'];
     $context['has_filter'] = !empty($filter);
     $context['sub_template'] = 'badbehavior_log';
     $context['sort_direction'] = $sort;
     $context['start'] = $start;
     createToken('admin-bbl');
 }
Beispiel #19
0
/**
 * Returns member data for a given member id in a suggestion format used by bans
 *
 * @package Bans
 * @uses getBasicMemberData
 * @param int $id
 */
function getMemberData($id)
{
    $suggestions = array();
    require_once SUBSDIR . '/Members.subs.php';
    $result = getBasicMemberData($id, array('moderation' => true));
    if (!empty($result)) {
        $suggestions = array('member' => array('id' => $result['id_member'], 'name' => $result['real_name']), 'main_ip' => $result['member_ip'], 'email' => $result['email_address']);
    }
    return $suggestions;
}
Beispiel #20
0
 /**
  * Verify the answer to the secret question.
  * Accessed with sa=secret2
  */
 public function action_secret2()
 {
     global $txt, $context;
     checkSession();
     validateToken('remind-sai');
     // Hacker?  How did you get this far without an email or username?
     if (empty($_REQUEST['uid'])) {
         fatal_lang_error('username_no_exist', false);
     }
     loadLanguage('Login');
     // Get the information from the database.
     require_once SUBSDIR . '/Members.subs.php';
     $member = getBasicMemberData((int) $_REQUEST['uid'], array('authentication' => true));
     if (empty($member)) {
         fatal_lang_error('username_no_exist', false);
     }
     // Check if the secret answer is correct.
     if ($member['secret_question'] == '' || $member['secret_answer'] == '' || md5($_POST['secret_answer']) !== $member['secret_answer']) {
         log_error(sprintf($txt['reminder_error'], $member['member_name']), 'user');
         fatal_lang_error('incorrect_answer', false);
     }
     // If it's OpenID this is where the music ends.
     if (!empty($member['openid_uri'])) {
         $context['sub_template'] = 'sent';
         $context['description'] = sprintf($txt['reminder_openid_is'], $member['openid_uri']);
         return;
     }
     // You can't use a blank one!
     if (strlen(trim($_POST['passwrd1'])) === 0) {
         fatal_lang_error('no_password', false);
     }
     // They have to be the same too.
     if ($_POST['passwrd1'] != $_POST['passwrd2']) {
         fatal_lang_error('passwords_dont_match', false);
     }
     // Make sure they have a strong enough password.
     require_once SUBSDIR . '/Auth.subs.php';
     $passwordError = validatePassword($_POST['passwrd1'], $member['member_name'], array($member['email_address']));
     // Invalid?
     if ($passwordError != null) {
         fatal_lang_error('profile_error_password_' . $passwordError, false);
     }
     // Alright, so long as 'yer sure.
     require_once SUBSDIR . '/Auth.subs.php';
     $sha_passwd = $_POST['passwrd1'];
     updateMemberData($member['id_member'], array('passwd' => validateLoginPassword($sha_passwd, '', $member['member_name'], true)));
     call_integration_hook('integrate_reset_pass', array($member['member_name'], $member['member_name'], $_POST['passwrd1']));
     // Tell them it went fine.
     loadTemplate('Login');
     loadJavascriptFile('sha256.js', array('defer' => true));
     $context += array('page_title' => $txt['reminder_password_set'], 'sub_template' => 'login', 'default_username' => $member['member_name'], 'default_password' => $_POST['passwrd1'], 'never_expire' => false, 'description' => $txt['reminder_password_set']);
     createToken('login');
 }
Beispiel #21
0
/**
 * This simple function gets a list of all administrators and sends them an email
 * to let them know a new member has joined.
 * Called by registerMember() function in subs/Members.subs.php.
 * Email is sent to all groups that have the moderate_forum permission.
 * The language set by each member is being used (if available).
 *
 * @param string $type types supported are 'approval', 'activation', and 'standard'.
 * @param int $memberID
 * @param string|null $member_name = null
 * @uses the Login language file.
 */
function sendAdminNotifications($type, $memberID, $member_name = null)
{
    global $modSettings, $language, $scripturl, $user_info;
    $db = database();
    // If the setting isn't enabled then just exit.
    if (empty($modSettings['notify_new_registration'])) {
        return;
    }
    // Needed to notify admins, or anyone
    require_once SUBSDIR . '/Mail.subs.php';
    if ($member_name == null) {
        require_once SUBSDIR . '/Members.subs.php';
        // Get the new user's name....
        $member_info = getBasicMemberData($memberID);
        $member_name = $member_info['real_name'];
    }
    $groups = array();
    // All membergroups who can approve members.
    $request = $db->query('', '
		SELECT id_group
		FROM {db_prefix}permissions
		WHERE permission = {string:moderate_forum}
			AND add_deny = {int:add_deny}
			AND id_group != {int:id_group}', array('add_deny' => 1, 'id_group' => 0, 'moderate_forum' => 'moderate_forum'));
    while ($row = $db->fetch_assoc($request)) {
        $groups[] = $row['id_group'];
    }
    $db->free_result($request);
    // Add administrators too...
    $groups[] = 1;
    $groups = array_unique($groups);
    // Get a list of all members who have ability to approve accounts - these are the people who we inform.
    $request = $db->query('', '
		SELECT id_member, lngfile, email_address
		FROM {db_prefix}members
		WHERE (id_group IN ({array_int:group_list}) OR FIND_IN_SET({raw:group_array_implode}, additional_groups) != 0)
			AND notify_types != {int:notify_types}
		ORDER BY lngfile', array('group_list' => $groups, 'notify_types' => 4, 'group_array_implode' => implode(', additional_groups) != 0 OR FIND_IN_SET(', $groups)));
    $current_language = $user_info['language'];
    while ($row = $db->fetch_assoc($request)) {
        $replacements = array('USERNAME' => $member_name, 'PROFILELINK' => $scripturl . '?action=profile;u=' . $memberID);
        $emailtype = 'admin_notify';
        // If they need to be approved add more info...
        if ($type == 'approval') {
            $replacements['APPROVALLINK'] = $scripturl . '?action=admin;area=viewmembers;sa=browse;type=approve';
            $emailtype .= '_approval';
        }
        $emaildata = loadEmailTemplate($emailtype, $replacements, empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']);
        // And do the actual sending...
        sendmail($row['email_address'], $emaildata['subject'], $emaildata['body'], null, null, false, 0);
    }
    $db->free_result($request);
    if (isset($current_language) && $current_language != $user_info['language']) {
        loadLanguage('Login');
    }
}
Beispiel #22
0
 /**
  * Send the emails.
  *
  * - Sends off emails to all the moderators.
  * - Sends to administrators and global moderators. (1 and 2)
  * - Called by action_reporttm(), and thus has the same permission and setting requirements as it does.
  * - Accessed through ?action=reporttm when posting.
  */
 public function action_reporttm2()
 {
     global $txt, $scripturl, $topic, $board, $user_info, $modSettings, $language, $context;
     // You must have the proper permissions!
     isAllowedTo('report_any');
     // Make sure they aren't spamming.
     spamProtection('reporttm');
     require_once SUBSDIR . '/Mail.subs.php';
     // No errors, yet.
     $report_errors = Error_Context::context('report', 1);
     // Check their session.
     if (checkSession('post', '', false) != '') {
         $report_errors->addError('session_timeout');
     }
     // Make sure we have a comment and it's clean.
     if (!isset($_POST['comment']) || Util::htmltrim($_POST['comment']) === '') {
         $report_errors->addError('no_comment');
     }
     $poster_comment = strtr(Util::htmlspecialchars($_POST['comment']), array("\r" => '', "\t" => ''));
     if (Util::strlen($poster_comment) > 254) {
         $report_errors->addError('post_too_long');
     }
     // Guests need to provide their address!
     if ($user_info['is_guest']) {
         require_once SUBSDIR . '/DataValidator.class.php';
         if (!Data_Validator::is_valid($_POST, array('email' => 'valid_email'), array('email' => 'trim'))) {
             empty($_POST['email']) ? $report_errors->addError('no_email') : $report_errors->addError('bad_email');
         }
         isBannedEmail($_POST['email'], 'cannot_post', sprintf($txt['you_are_post_banned'], $txt['guest_title']));
         $user_info['email'] = htmlspecialchars($_POST['email'], ENT_COMPAT, 'UTF-8');
     }
     // Could they get the right verification code?
     if ($user_info['is_guest'] && !empty($modSettings['guests_report_require_captcha'])) {
         require_once SUBSDIR . '/VerificationControls.class.php';
         $verificationOptions = array('id' => 'report');
         $context['require_verification'] = create_control_verification($verificationOptions, true);
         if (is_array($context['require_verification'])) {
             foreach ($context['require_verification'] as $error) {
                 $report_errors->addError($error, 0);
             }
         }
     }
     // Any errors?
     if ($report_errors->hasErrors()) {
         return $this->action_reporttm();
     }
     // Get the basic topic information, and make sure they can see it.
     $msg_id = (int) $_POST['msg'];
     $message = posterDetails($msg_id, $topic);
     if (empty($message)) {
         fatal_lang_error('no_board', false);
     }
     $poster_name = un_htmlspecialchars($message['real_name']) . ($message['real_name'] != $message['poster_name'] ? ' (' . $message['poster_name'] . ')' : '');
     $reporterName = un_htmlspecialchars($user_info['name']) . ($user_info['name'] != $user_info['username'] && $user_info['username'] != '' ? ' (' . $user_info['username'] . ')' : '');
     $subject = un_htmlspecialchars($message['subject']);
     // Get a list of members with the moderate_board permission.
     require_once SUBSDIR . '/Members.subs.php';
     $moderators = membersAllowedTo('moderate_board', $board);
     $result = getBasicMemberData($moderators, array('preferences' => true, 'sort' => 'lngfile'));
     $mod_to_notify = array();
     foreach ($result as $row) {
         if ($row['notify_types'] != 4) {
             $mod_to_notify[] = $row;
         }
     }
     // Check that moderators do exist!
     if (empty($mod_to_notify)) {
         fatal_lang_error('no_mods', false);
     }
     // If we get here, I believe we should make a record of this, for historical significance, yabber.
     if (empty($modSettings['disable_log_report'])) {
         require_once SUBSDIR . '/Messages.subs.php';
         $id_report = recordReport($message, $poster_comment);
         // If we're just going to ignore these, then who gives a monkeys...
         if ($id_report === false) {
             redirectexit('topic=' . $topic . '.msg' . $msg_id . '#msg' . $msg_id);
         }
     }
     // Find out who the real moderators are - for mod preferences.
     require_once SUBSDIR . '/Boards.subs.php';
     $real_mods = getBoardModerators($board, true);
     // Send every moderator an email.
     foreach ($mod_to_notify as $row) {
         // Maybe they don't want to know?!
         if (!empty($row['mod_prefs'])) {
             list(, , $pref_binary) = explode('|', $row['mod_prefs']);
             if (!($pref_binary & 1) && (!($pref_binary & 2) || !in_array($row['id_member'], $real_mods))) {
                 continue;
             }
         }
         $replacements = array('TOPICSUBJECT' => $subject, 'POSTERNAME' => $poster_name, 'REPORTERNAME' => $reporterName, 'TOPICLINK' => $scripturl . '?topic=' . $topic . '.msg' . $msg_id . '#msg' . $msg_id, 'REPORTLINK' => !empty($id_report) ? $scripturl . '?action=moderate;area=reports;report=' . $id_report : '', 'COMMENT' => $_POST['comment']);
         $emaildata = loadEmailTemplate('report_to_moderator', $replacements, empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']);
         // Send it to the moderator.
         sendmail($row['email_address'], $emaildata['subject'], $emaildata['body'], $user_info['email'], null, false, 2);
     }
     // Keep track of when the mod reports get updated, that way we know when we need to look again.
     updateSettings(array('last_mod_report_action' => time()));
     // Back to the post we reported!
     redirectexit('reportsent;topic=' . $topic . '.msg' . $msg_id . '#msg' . $msg_id);
 }
Beispiel #23
0
/**
 * This function determines the actions of the members passed in urls.
 *
 * Adding actions to the Who's Online list:
 * Adding actions to this list is actually relatively easy...
 * - for actions anyone should be able to see, just add a string named whoall_ACTION.
 *   (where ACTION is the action used in index.php.)
 * - for actions that have a subaction which should be represented differently, use whoall_ACTION_SUBACTION.
 * - for actions that include a topic, and should be restricted, use whotopic_ACTION.
 * - for actions that use a message, by msg or quote, use whopost_ACTION.
 * - for administrator-only actions, use whoadmin_ACTION.
 * - for actions that should be viewable only with certain permissions, use whoallow_ACTION and
 * add a list of possible permissions to the $allowedActions array, using ACTION as the key.
 *
 * @param mixed[]|string $urls a single url (string) or an array of arrays, each inner array being (serialized request data, id_member)
 * @param string|false $preferred_prefix = false
 * @return mixed[]|string an array of descriptions if you passed an array, otherwise the string describing their current location.
 */
function determineActions($urls, $preferred_prefix = false)
{
    global $txt, $user_info, $modSettings, $scripturl;
    $db = database();
    if (!allowedTo('who_view')) {
        return array();
    }
    loadLanguage('Who');
    // Actions that require a specific permission level.
    $allowedActions = array('admin' => array('moderate_forum', 'manage_membergroups', 'manage_bans', 'admin_forum', 'manage_permissions', 'send_mail', 'manage_attachments', 'manage_smileys', 'manage_boards', 'edit_news'), 'ban' => array('manage_bans'), 'boardrecount' => array('admin_forum'), 'calendar' => array('calendar_view'), 'editnews' => array('edit_news'), 'mailing' => array('send_mail'), 'maintain' => array('admin_forum'), 'manageattachments' => array('manage_attachments'), 'manageboards' => array('manage_boards'), 'memberlist' => array('view_mlist'), 'moderate' => array('access_mod_center', 'moderate_forum', 'manage_membergroups'), 'optimizetables' => array('admin_forum'), 'repairboards' => array('admin_forum'), 'search' => array('search_posts'), 'setcensor' => array('moderate_forum'), 'setreserve' => array('moderate_forum'), 'stats' => array('view_stats'), 'viewErrorLog' => array('admin_forum'), 'viewmembers' => array('moderate_forum'));
    // Provide integration a way to add to the allowed action array
    call_integration_hook('integrate_whos_online_allowed', array(&$allowedActions));
    if (!is_array($urls)) {
        $url_list = array(array($urls, $user_info['id']));
    } else {
        $url_list = $urls;
    }
    // These are done to query these in large chunks. (instead of one by one.)
    $topic_ids = array();
    $profile_ids = array();
    $board_ids = array();
    $data = array();
    foreach ($url_list as $k => $url) {
        // Get the request parameters..
        $actions = @unserialize($url[0]);
        if ($actions === false) {
            continue;
        }
        // If it's the admin or moderation center, and there is an area set, use that instead.
        if (isset($actions['action']) && ($actions['action'] == 'admin' || $actions['action'] == 'moderate') && isset($actions['area'])) {
            $actions['action'] = $actions['area'];
        }
        // Check if there was no action or the action is display.
        if (!isset($actions['action']) || $actions['action'] == 'display') {
            // It's a topic!  Must be!
            if (isset($actions['topic'])) {
                // Assume they can't view it, and queue it up for later.
                $data[$k] = $txt['who_hidden'];
                $topic_ids[(int) $actions['topic']][$k] = $txt['who_topic'];
            } elseif (isset($actions['board'])) {
                // Hide first, show later.
                $data[$k] = $txt['who_hidden'];
                $board_ids[$actions['board']][$k] = $txt['who_board'];
            } else {
                $data[$k] = replaceBasicActionUrl($txt['who_index']);
            }
        } elseif ($actions['action'] == '') {
            $data[$k] = replaceBasicActionUrl($txt['who_index']);
        } else {
            // Viewing/editing a profile.
            if ($actions['action'] == 'profile') {
                // Whose?  Their own?
                if (empty($actions['u'])) {
                    require_once SUBSDIR . '/Profile.subs.php';
                    $memID = currentMemberID();
                    if ($memID == $user_info['id']) {
                        $actions['u'] = $url[1];
                    } else {
                        $actions['u'] = $memID;
                    }
                }
                $data[$k] = $txt['who_hidden'];
                $profile_ids[(int) $actions['u']][$k] = $actions['action'] == 'profile' ? $txt['who_viewprofile'] : $txt['who_profile'];
            } elseif (($actions['action'] == 'post' || $actions['action'] == 'post2' || $actions['action'] == 'topicbyemail') && empty($actions['topic']) && isset($actions['board'])) {
                $data[$k] = $txt['who_hidden'];
                if ($actions['action'] == 'topicbyemail') {
                    $board_ids[(int) $actions['board']][$k] = $txt['who_topicbyemail'];
                } else {
                    $board_ids[(int) $actions['board']][$k] = isset($actions['poll']) ? $txt['who_poll'] : $txt['who_post'];
                }
            } elseif (isset($actions['sa']) && isset($txt['whoall_' . $actions['action'] . '_' . $actions['sa']])) {
                $data[$k] = $preferred_prefix && isset($txt[$preferred_prefix . $actions['action'] . '_' . $actions['sa']]) ? $txt[$preferred_prefix . $actions['action'] . '_' . $actions['sa']] : $txt['whoall_' . $actions['action'] . '_' . $actions['sa']];
            } elseif (isset($txt['whoall_' . $actions['action']])) {
                $data[$k] = $preferred_prefix && isset($txt[$preferred_prefix . $actions['action']]) ? $txt[$preferred_prefix . $actions['action']] : replaceBasicActionUrl($txt['whoall_' . $actions['action']]);
            } elseif (isset($txt['whotopic_' . $actions['action']])) {
                // Find out what topic they are accessing.
                $topic = (int) (isset($actions['topic']) ? $actions['topic'] : (isset($actions['from']) ? $actions['from'] : 0));
                $data[$k] = $txt['who_hidden'];
                $topic_ids[$topic][$k] = $txt['whotopic_' . $actions['action']];
            } elseif (isset($actions['sa']) && isset($txt['whotopic_' . $actions['action'] . '_' . $actions['sa']])) {
                // Find out what topic they are accessing.
                $topic = (int) (isset($actions['topic']) ? $actions['topic'] : (isset($actions['from']) ? $actions['from'] : 0));
                $data[$k] = $txt['who_hidden'];
                $topic_ids[$topic][$k] = $txt['whotopic_' . $actions['action'] . '_' . $actions['sa']];
            } elseif (isset($txt['whopost_' . $actions['action']])) {
                // Find out what message they are accessing.
                $msgid = (int) (isset($actions['msg']) ? $actions['msg'] : (isset($actions['quote']) ? $actions['quote'] : 0));
                $result = $db->query('', '
					SELECT m.id_topic, m.subject
					FROM {db_prefix}messages AS m
						INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board)
						INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic' . ($modSettings['postmod_active'] ? ' AND t.approved = {int:is_approved}' : '') . ')
					WHERE m.id_msg = {int:id_msg}
						AND {query_see_board}' . ($modSettings['postmod_active'] ? '
						AND m.approved = {int:is_approved}' : '') . '
					LIMIT 1', array('is_approved' => 1, 'id_msg' => $msgid));
                list($id_topic, $subject) = $db->fetch_row($result);
                $data[$k] = sprintf($txt['whopost_' . $actions['action']], $scripturl . '?topic=' . $id_topic . '.0', $subject);
                $db->free_result($result);
                if (empty($id_topic)) {
                    $data[$k] = $txt['who_hidden'];
                }
            } elseif (allowedTo('moderate_forum') && isset($txt['whoadmin_' . $actions['action']])) {
                $data[$k] = $txt['whoadmin_' . $actions['action']];
            } elseif (isset($allowedActions[$actions['action']])) {
                if (allowedTo($allowedActions[$actions['action']])) {
                    if (isset($actions['sa']) && isset($txt['whoallow_' . $actions['action'] . '_' . $actions['sa']])) {
                        $data[$k] = replaceBasicActionUrl($txt['whoallow_' . $actions['action'] . '_' . $actions['sa']]);
                    } else {
                        $data[$k] = replaceBasicActionUrl($txt['whoallow_' . $actions['action']]);
                    }
                } elseif (in_array('moderate_forum', $allowedActions[$actions['action']])) {
                    $data[$k] = $txt['who_moderate'];
                } elseif (in_array('admin_forum', $allowedActions[$actions['action']])) {
                    $data[$k] = $txt['who_admin'];
                } else {
                    $data[$k] = $txt['who_hidden'];
                }
            } elseif (!empty($actions['action'])) {
                $data[$k] = sprintf($txt['who_generic'], $actions['action']);
            } else {
                $data[$k] = $txt['who_unknown'];
            }
        }
        // Maybe the action is integrated into another system?
        if (count($integrate_actions = call_integration_hook('integrate_whos_online', array($actions))) > 0) {
            // Try each integraion hook with this url and see if they can fill in the details
            foreach ($integrate_actions as $integrate_action) {
                if (!empty($integrate_action)) {
                    // Found it, all done then
                    $data[$k] = $integrate_action;
                    break;
                }
            }
        }
    }
    // Load topic names.
    if (!empty($topic_ids)) {
        require_once SUBSDIR . '/Topic.subs.php';
        $topics_data = topicsList(array_keys($topic_ids));
        foreach ($topics_data as $topic) {
            // Show the topic's subject for each of the members looking at this...
            foreach ($topic_ids[$topic['id_topic']] as $k => $session_text) {
                $data[$k] = sprintf($session_text, $scripturl . '?topic=' . $topic['id_topic'] . '.0', $topic['subject']);
            }
        }
    }
    // Load board names.
    if (!empty($board_ids)) {
        require_once SUBSDIR . '/Boards.subs.php';
        $boards_list = getBoardList(array('included_boards' => array_keys($board_ids)), true);
        foreach ($boards_list as $board) {
            // Put the board name into the string for each member...
            foreach ($board_ids[$board['id_board']] as $k => $session_text) {
                $data[$k] = sprintf($session_text, $scripturl . '?board=' . $board['id_board'] . '.0', $board['board_name']);
            }
        }
    }
    // Load member names for the profile.
    if (!empty($profile_ids) && (allowedTo('profile_view_any') || allowedTo('profile_view_own'))) {
        require_once SUBSDIR . '/Members.subs.php';
        $result = getBasicMemberData(array_keys($profile_ids));
        foreach ($result as $row) {
            // If they aren't allowed to view this person's profile, skip it.
            if (!allowedTo('profile_view_any') && $user_info['id'] != $row['id_member']) {
                continue;
            }
            // Set their action on each - session/text to sprintf.
            foreach ($profile_ids[$row['id_member']] as $k => $session_text) {
                $data[$k] = sprintf($session_text, $scripturl . '?action=profile;u=' . $row['id_member'], $row['real_name']);
            }
        }
    }
    if (!is_array($urls)) {
        return isset($data[0]) ? $data[0] : false;
    } else {
        return $data;
    }
}
Beispiel #24
0
/**
 * Gets the moderation log entries that match the specified parameters.
 * Callback for createList() in Modlog::action_log().
 *
 * @param int $start
 * @param int $items_per_page
 * @param string $sort
 * @param string|null $query_string
 * @param mixed[] $query_params
 * @param int $log_type
 */
function list_getModLogEntries($start, $items_per_page, $sort, $query_string = '', $query_params = array(), $log_type = 1)
{
    global $context, $scripturl, $txt, $user_info;
    $db = database();
    $modlog_query = allowedTo('admin_forum') || $user_info['mod_cache']['bq'] == '1=1' ? '1=1' : ($user_info['mod_cache']['bq'] == '0=1' ? 'lm.id_board = 0 AND lm.id_topic = 0' : strtr($user_info['mod_cache']['bq'], array('id_board' => 'b.id_board')) . ' AND ' . strtr($user_info['mod_cache']['bq'], array('id_board' => 't.id_board')));
    // Do a little bit of self protection.
    if (!isset($context['hoursdisable'])) {
        $context['hoursdisable'] = 24;
    }
    // Can they see the IP address?
    $seeIP = allowedTo('moderate_forum');
    // Here we have the query getting the log details.
    $result = $db->query('', '
		SELECT
			lm.id_action, lm.id_member, lm.ip, lm.log_time, lm.action, lm.id_board, lm.id_topic, lm.id_msg, lm.extra,
			mem.real_name, mg.group_name
		FROM {db_prefix}log_actions AS lm
			LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lm.id_member)
			LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = CASE WHEN mem.id_group = {int:reg_group_id} THEN mem.id_post_group ELSE mem.id_group END)
			LEFT JOIN {db_prefix}boards AS b ON (b.id_board = lm.id_board)
			LEFT JOIN {db_prefix}topics AS t ON (t.id_topic = lm.id_topic)
			WHERE id_log = {int:log_type}
				AND {raw:modlog_query}' . (!empty($query_string) ? '
				AND ' . $query_string : '') . '
		ORDER BY ' . $sort . '
		LIMIT ' . $start . ', ' . $items_per_page, array_merge($query_params, array('reg_group_id' => 0, 'log_type' => $log_type, 'modlog_query' => $modlog_query)));
    // Arrays for decoding objects into.
    $topics = array();
    $boards = array();
    $members = array();
    $messages = array();
    $entries = array();
    while ($row = $db->fetch_assoc($result)) {
        $row['extra'] = @unserialize($row['extra']);
        // Corrupt?
        $row['extra'] = is_array($row['extra']) ? $row['extra'] : array();
        // Add on some of the column stuff info
        if (!empty($row['id_board'])) {
            if ($row['action'] == 'move') {
                $row['extra']['board_to'] = $row['id_board'];
            } else {
                $row['extra']['board'] = $row['id_board'];
            }
        }
        if (!empty($row['id_topic'])) {
            $row['extra']['topic'] = $row['id_topic'];
        }
        if (!empty($row['id_msg'])) {
            $row['extra']['message'] = $row['id_msg'];
        }
        // Is this associated with a topic?
        if (isset($row['extra']['topic'])) {
            $topics[(int) $row['extra']['topic']][] = $row['id_action'];
        }
        if (isset($row['extra']['new_topic'])) {
            $topics[(int) $row['extra']['new_topic']][] = $row['id_action'];
        }
        // How about a member?
        if (isset($row['extra']['member'])) {
            // Guests don't have names!
            if (empty($row['extra']['member'])) {
                $row['extra']['member'] = $txt['modlog_parameter_guest'];
            } else {
                // Try to find it...
                $members[(int) $row['extra']['member']][] = $row['id_action'];
            }
        }
        // Associated with a board?
        if (isset($row['extra']['board_to'])) {
            $boards[(int) $row['extra']['board_to']][] = $row['id_action'];
        }
        if (isset($row['extra']['board_from'])) {
            $boards[(int) $row['extra']['board_from']][] = $row['id_action'];
        }
        if (isset($row['extra']['board'])) {
            $boards[(int) $row['extra']['board']][] = $row['id_action'];
        }
        // A message?
        if (isset($row['extra']['message'])) {
            $messages[(int) $row['extra']['message']][] = $row['id_action'];
        }
        // IP Info?
        if (isset($row['extra']['ip_range'])) {
            if ($seeIP) {
                $row['extra']['ip_range'] = '<a href="' . $scripturl . '?action=trackip;searchip=' . $row['extra']['ip_range'] . '">' . $row['extra']['ip_range'] . '</a>';
            } else {
                $row['extra']['ip_range'] = $txt['logged'];
            }
        }
        // Email?
        if (isset($row['extra']['email'])) {
            $row['extra']['email'] = '<a href="mailto:' . $row['extra']['email'] . '">' . $row['extra']['email'] . '</a>';
        }
        // Bans are complex.
        if ($row['action'] == 'ban') {
            if (!isset($row['extra']['new']) || $row['extra']['new'] == 1) {
                $row['action_text'] = $txt['modlog_ac_ban'];
            } elseif ($row['extra']['new'] == 0) {
                $row['action_text'] = $txt['modlog_ac_ban_update'];
            } else {
                $row['action_text'] = $txt['modlog_ac_ban_remove'];
            }
            foreach (array('member', 'email', 'ip_range', 'hostname') as $type) {
                if (isset($row['extra'][$type])) {
                    $row['action_text'] .= $txt['modlog_ac_ban_trigger_' . $type];
                }
            }
        }
        // The array to go to the template. Note here that action is set to a "default" value of the action doesn't match anything in the descriptions. Allows easy adding of logging events with basic details.
        $entries[$row['id_action']] = array('id' => $row['id_action'], 'ip' => $seeIP ? $row['ip'] : $txt['logged'], 'position' => empty($row['real_name']) && empty($row['group_name']) ? $txt['guest'] : $row['group_name'], 'moderator_link' => $row['id_member'] ? '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>' : (empty($row['real_name']) ? $txt['guest'] . (!empty($row['extra']['member_acted']) ? ' (' . $row['extra']['member_acted'] . ')' : '') : $row['real_name']), 'time' => standardTime($row['log_time']), 'html_time' => htmlTime($row['log_time']), 'timestamp' => forum_time(true, $row['log_time']), 'editable' => time() > $row['log_time'] + $context['hoursdisable'] * 3600, 'extra' => $row['extra'], 'action' => $row['action'], 'action_text' => isset($row['action_text']) ? $row['action_text'] : '');
    }
    $db->free_result($result);
    if (!empty($boards)) {
        require_once SUBSDIR . '/Boards.subs.php';
        $boards_info = fetchBoardsInfo(array('boards' => array_keys($boards)));
        foreach ($boards_info as $row) {
            foreach ($boards[$row['id_board']] as $action) {
                // Make the board number into a link - dealing with moving too.
                if (isset($entries[$action]['extra']['board_to']) && $entries[$action]['extra']['board_to'] == $row['id_board']) {
                    $entries[$action]['extra']['board_to'] = '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['name'] . '</a>';
                } elseif (isset($entries[$action]['extra']['board_from']) && $entries[$action]['extra']['board_from'] == $row['id_board']) {
                    $entries[$action]['extra']['board_from'] = '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['name'] . '</a>';
                } elseif (isset($entries[$action]['extra']['board']) && $entries[$action]['extra']['board'] == $row['id_board']) {
                    $entries[$action]['extra']['board'] = '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['name'] . '</a>';
                }
            }
        }
    }
    if (!empty($topics)) {
        $request = $db->query('', '
			SELECT ms.subject, t.id_topic
			FROM {db_prefix}topics AS t
				INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg)
			WHERE t.id_topic IN ({array_int:topic_list})
			LIMIT ' . count(array_keys($topics)), array('topic_list' => array_keys($topics)));
        while ($row = $db->fetch_assoc($request)) {
            foreach ($topics[$row['id_topic']] as $action) {
                $this_action =& $entries[$action];
                // This isn't used in the current theme.
                $this_action['topic'] = array('id' => $row['id_topic'], 'subject' => $row['subject'], 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.0', 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0">' . $row['subject'] . '</a>');
                // Make the topic number into a link - dealing with splitting too.
                if (isset($this_action['extra']['topic']) && $this_action['extra']['topic'] == $row['id_topic']) {
                    $this_action['extra']['topic'] = '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.' . (isset($this_action['extra']['message']) ? 'msg' . $this_action['extra']['message'] . '#msg' . $this_action['extra']['message'] : '0') . '">' . $row['subject'] . '</a>';
                } elseif (isset($this_action['extra']['new_topic']) && $this_action['extra']['new_topic'] == $row['id_topic']) {
                    $this_action['extra']['new_topic'] = '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.' . (isset($this_action['extra']['message']) ? 'msg' . $this_action['extra']['message'] . '#msg' . $this_action['extra']['message'] : '0') . '">' . $row['subject'] . '</a>';
                }
            }
        }
        $db->free_result($request);
    }
    if (!empty($messages)) {
        $request = $db->query('', '
			SELECT id_msg, subject
			FROM {db_prefix}messages
			WHERE id_msg IN ({array_int:message_list})
			LIMIT ' . count(array_keys($messages)), array('message_list' => array_keys($messages)));
        while ($row = $db->fetch_assoc($request)) {
            foreach ($messages[$row['id_msg']] as $action) {
                $this_action =& $entries[$action];
                // This isn't used in the current theme.
                $this_action['message'] = array('id' => $row['id_msg'], 'subject' => $row['subject'], 'href' => $scripturl . '?msg=' . $row['id_msg'], 'link' => '<a href="' . $scripturl . '?msg=' . $row['id_msg'] . '">' . $row['subject'] . '</a>');
                // Make the message number into a link.
                if (isset($this_action['extra']['message']) && $this_action['extra']['message'] == $row['id_msg']) {
                    $this_action['extra']['message'] = '<a href="' . $scripturl . '?msg=' . $row['id_msg'] . '">' . $row['subject'] . '</a>';
                }
            }
        }
        $db->free_result($request);
    }
    if (!empty($members)) {
        require_once SUBSDIR . '/Members.subs.php';
        // Get the latest activated member's display name.
        $result = getBasicMemberData(array_keys($members));
        foreach ($result as $row) {
            foreach ($members[$row['id_member']] as $action) {
                // Not used currently.
                $entries[$action]['member'] = array('id' => $row['id_member'], 'name' => $row['real_name'], 'href' => $scripturl . '?action=profile;u=' . $row['id_member'], 'link' => '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>');
                // Make the member number into a name.
                $entries[$action]['extra']['member'] = '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>';
            }
        }
    }
    // Do some formatting of the action string.
    $callback = new ModLogEntriesReplacement();
    $callback->entries = $entries;
    foreach ($entries as $k => $entry) {
        // Make any message info links so its easier to go find that message.
        if (isset($entry['extra']['message']) && (empty($entry['message']) || empty($entry['message']['id']))) {
            $entries[$k]['extra']['message'] = '<a href="' . $scripturl . '?msg=' . $entry['extra']['message'] . '">' . $entry['extra']['message'] . '</a>';
        }
        // Mark up any deleted members, topics and boards.
        foreach (array('board', 'board_from', 'board_to', 'member', 'topic', 'new_topic') as $type) {
            if (!empty($entry['extra'][$type]) && is_numeric($entry['extra'][$type])) {
                $entries[$k]['extra'][$type] = sprintf($txt['modlog_id'], $entry['extra'][$type]);
            }
        }
        if (empty($entries[$k]['action_text'])) {
            $entries[$k]['action_text'] = isset($txt['modlog_ac_' . $entry['action']]) ? $txt['modlog_ac_' . $entry['action']] : $entry['action'];
        }
        $callback->key = $k;
        $entries[$k]['action_text'] = preg_replace_callback('~\\{([A-Za-z\\d_]+)\\}~i', array($callback, 'callback'), $entries[$k]['action_text']);
    }
    // Back we go!
    return $entries;
}