/** * marks a private message unread when the user clicks the mark pm as unread link * when viewing the private message. Takes a single parameter, which is the msg_id of the pm * being marked as unread */ function mark_unread_pm($msg_id) { global $db, $user, $phpbb_root_path, $phpEx; // redirect the user to the index if the user is not logged in or if user is a bot if ($user->data['user_id'] == ANONYMOUS || $user->data['is_bot']) { redirect(append_sid("{$phpbb_root_path}index.{$phpEx}")); } $user->setup('ucp'); // find out what folder we are talking about so we can confine our actions to that folder $folder_id = request_var('f', PRIVMSGS_INBOX); $sql = 'SELECT msg_id FROM ' . PRIVMSGS_TO_TABLE . ' WHERE msg_id = ' . $msg_id . ' AND user_id = ' . $user->data['user_id'] . ' AND pm_deleted = 0 AND folder_id =' . $folder_id; $result = $db->sql_query($sql); if ($row = $db->sql_fetchrow($result)) { // there is a pm in the relevant mailbox that matches that msg_id // so go ahead and mark it unread $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' SET pm_unread = 1 WHERE msg_id = ' . $msg_id . ' AND user_id = ' . $user->data['user_id'] . ' AND pm_deleted = 0 AND folder_id =' . $folder_id; $db->sql_query($sql); include $phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx; update_pm_counts(); } else { // if we get here, there is no pm in this user's inbox that matches that msg_id trigger_error('NO_MESSAGE'); } $db->sql_freeresult($result); $meta_info = append_sid("{$phpbb_root_path}ucp.{$phpEx}", 'i=pm&folder=inbox'); meta_refresh(3, $meta_info); $message = $user->lang['PM_MARKED_UNREAD'] . '<br /><br />'; $message .= '<a href="' . $meta_info . '">' . $user->lang['RETURN_INBOX'] . '</a><br /><br />'; $message .= sprintf($user->lang['RETURN_INDEX'], '<a href="' . append_sid("{$phpbb_root_path}index.{$phpEx}") . '">', '</a>'); trigger_error($message); }
/** * Place new messages into appropriate folder */ function place_pm_into_folder(&$global_privmsgs_rules, $release = false) { global $db, $user, $config; if (!$user->data['user_new_privmsg']) { return array('not_moved' => 0, 'removed' => 0); } $user_message_rules = (int) $user->data['user_message_rules']; $user_id = (int) $user->data['user_id']; $action_ary = $move_into_folder = array(); $num_removed = 0; // Newly processing on-hold messages if ($release) { $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' SET folder_id = ' . PRIVMSGS_NO_BOX . ' WHERE folder_id = ' . PRIVMSGS_HOLD_BOX . "\n\t\t\t\tAND user_id = {$user_id}"; $db->sql_query($sql); } // Get those messages not yet placed into any box $retrieve_sql = 'SELECT t.*, p.*, u.username, u.user_id, u.group_id FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p, ' . USERS_TABLE . " u\n\t\tWHERE t.user_id = {$user_id}\n\t\t\tAND p.author_id = u.user_id\n\t\t\tAND t.folder_id = " . PRIVMSGS_NO_BOX . ' AND t.msg_id = p.msg_id'; // Just place into the appropriate arrays if no rules need to be checked if (!$user_message_rules) { $result = $db->sql_query($retrieve_sql); while ($row = $db->sql_fetchrow($result)) { $action_ary[$row['msg_id']][] = array('action' => false); } $db->sql_freeresult($result); } else { $user_rules = $zebra = $check_rows = array(); $user_ids = $memberships = array(); // First of all, grab all rules and retrieve friends/foes $sql = 'SELECT * FROM ' . PRIVMSGS_RULES_TABLE . "\n\t\t\tWHERE user_id = {$user_id}"; $result = $db->sql_query($sql); $user_rules = $db->sql_fetchrowset($result); $db->sql_freeresult($result); if (sizeof($user_rules)) { $sql = 'SELECT zebra_id, friend, foe FROM ' . ZEBRA_TABLE . "\n\t\t\t\tWHERE user_id = {$user_id}"; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { $zebra[$row['zebra_id']] = $row; } $db->sql_freeresult($result); } // Now build a bare-bone check_row array $result = $db->sql_query($retrieve_sql); while ($row = $db->sql_fetchrow($result)) { $check_rows[] = array_merge($row, array('to' => explode(':', $row['to_address']), 'bcc' => explode(':', $row['bcc_address']), 'friend' => isset($zebra[$row['author_id']]) ? $zebra[$row['author_id']]['friend'] : 0, 'foe' => isset($zebra[$row['author_id']]) ? $zebra[$row['author_id']]['foe'] : 0, 'user_in_group' => array($user->data['group_id']), 'author_in_group' => array())); $user_ids[] = $row['user_id']; } $db->sql_freeresult($result); // Retrieve user memberships if (sizeof($user_ids)) { $sql = 'SELECT * FROM ' . USER_GROUP_TABLE . ' WHERE ' . $db->sql_in_set('user_id', $user_ids) . ' AND user_pending = 0'; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { $memberships[$row['user_id']][] = $row['group_id']; } $db->sql_freeresult($result); } // Now place into the appropriate folder foreach ($check_rows as $row) { // Add membership if set if (isset($memberships[$row['author_id']])) { $row['author_in_group'] = $memberships[$row['user_id']]; } // Check Rule - this should be very quick since we have all information we need $is_match = false; foreach ($user_rules as $rule_row) { if (($action = check_rule($global_privmsgs_rules, $rule_row, $row, $user_id)) !== false) { $is_match = true; $action_ary[$row['msg_id']][] = $action; } } if (!$is_match) { $action_ary[$row['msg_id']][] = array('action' => false); } } unset($user_rules, $zebra, $check_rows, $user_ids, $memberships); } // We place actions into arrays, to save queries. $sql = $unread_ids = $delete_ids = $important_ids = array(); foreach ($action_ary as $msg_id => $msg_ary) { // It is allowed to execute actions more than once, except placing messages into folder $folder_action = $message_removed = false; foreach ($msg_ary as $pos => $rule_ary) { if ($folder_action && $rule_ary['action'] == ACTION_PLACE_INTO_FOLDER) { continue; } switch ($rule_ary['action']) { case ACTION_PLACE_INTO_FOLDER: // Folder actions have precedence, so we will remove any other ones $folder_action = true; $move_into_folder[(int) $rule_ary['folder_id']][] = $msg_id; break; case ACTION_MARK_AS_READ: if ($rule_ary['pm_unread']) { $unread_ids[] = $msg_id; } break; case ACTION_DELETE_MESSAGE: $delete_ids[] = $msg_id; $message_removed = true; break; case ACTION_MARK_AS_IMPORTANT: if (!$rule_ary['pm_marked']) { $important_ids[] = $msg_id; } break; } } // We place this here because it could happen that the messages are doubled if a rule marks a message and then moves it into a specific // folder. Here we simply move the message into the INBOX if it gets not removed and also not put into a custom folder. if (!$folder_action && !$message_removed) { $move_into_folder[PRIVMSGS_INBOX][] = $msg_id; } } // Do not change the order of processing // The number of queries needed to be executed here highly depends on the defined rules and are // only gone through if new messages arrive. // Delete messages if (sizeof($delete_ids)) { $num_removed += sizeof($delete_ids); delete_pm($user_id, $delete_ids, PRIVMSGS_NO_BOX); } // Set messages to Unread if (sizeof($unread_ids)) { $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' SET pm_unread = 0 WHERE ' . $db->sql_in_set('msg_id', $unread_ids) . "\n\t\t\t\tAND user_id = {$user_id}\n\t\t\t\tAND folder_id = " . PRIVMSGS_NO_BOX; $db->sql_query($sql); } // mark messages as important if (sizeof($important_ids)) { $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' SET pm_marked = 1 - pm_marked WHERE folder_id = ' . PRIVMSGS_NO_BOX . "\n\t\t\t\tAND user_id = {$user_id}\n\t\t\t\tAND " . $db->sql_in_set('msg_id', $important_ids); $db->sql_query($sql); } // Move into folder $folder = array(); if (sizeof($move_into_folder)) { // Determine Full Folder Action - we need the move to folder id later eventually $full_folder_action = $user->data['user_full_folder'] == FULL_FOLDER_NONE ? $config['full_folder_action'] - FULL_FOLDER_NONE * -1 : $user->data['user_full_folder']; $sql_folder = array_keys($move_into_folder); if ($full_folder_action >= 0) { $sql_folder[] = $full_folder_action; } $sql = 'SELECT folder_id, pm_count FROM ' . PRIVMSGS_FOLDER_TABLE . ' WHERE ' . $db->sql_in_set('folder_id', $sql_folder) . "\n\t\t\t\tAND user_id = {$user_id}"; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { $folder[(int) $row['folder_id']] = (int) $row['pm_count']; } $db->sql_freeresult($result); unset($sql_folder); if (isset($move_into_folder[PRIVMSGS_INBOX])) { $sql = 'SELECT COUNT(msg_id) as num_messages FROM ' . PRIVMSGS_TO_TABLE . "\n\t\t\t\tWHERE user_id = {$user_id}\n\t\t\t\t\tAND folder_id = " . PRIVMSGS_INBOX; $result = $db->sql_query($sql); $folder[PRIVMSGS_INBOX] = (int) $db->sql_fetchfield('num_messages'); $db->sql_freeresult($result); } } // Here we have ideally only one folder to move into foreach ($move_into_folder as $folder_id => $msg_ary) { $dest_folder = $folder_id; $full_folder_action = FULL_FOLDER_NONE; // Check Message Limit - we calculate with the complete array, most of the time it is one message // But we are making sure that the other way around works too (more messages in queue than allowed to be stored) if ($user->data['message_limit'] && $folder[$folder_id] && $folder[$folder_id] + sizeof($msg_ary) > $user->data['message_limit']) { $full_folder_action = $user->data['user_full_folder'] == FULL_FOLDER_NONE ? $config['full_folder_action'] - FULL_FOLDER_NONE * -1 : $user->data['user_full_folder']; // If destination folder itself is full... if ($full_folder_action >= 0 && $folder[$full_folder_action] + sizeof($msg_ary) > $user->data['message_limit']) { $full_folder_action = $config['full_folder_action'] - FULL_FOLDER_NONE * -1; } // If Full Folder Action is to move to another folder, we simply adjust the destination folder if ($full_folder_action >= 0) { $dest_folder = $full_folder_action; } else { if ($full_folder_action == FULL_FOLDER_DELETE) { // Delete some messages. NOTE: Ordered by msg_id here instead of message_time! $sql = 'SELECT msg_id FROM ' . PRIVMSGS_TO_TABLE . "\n\t\t\t\t\tWHERE user_id = {$user_id}\n\t\t\t\t\t\tAND folder_id = {$dest_folder}\n\t\t\t\t\tORDER BY msg_id ASC"; $result = $db->sql_query_limit($sql, $folder[$dest_folder] + sizeof($msg_ary) - $user->data['message_limit']); $delete_ids = array(); while ($row = $db->sql_fetchrow($result)) { $delete_ids[] = $row['msg_id']; } $db->sql_freeresult($result); $num_removed += sizeof($delete_ids); delete_pm($user_id, $delete_ids, $dest_folder); } } } // if ($full_folder_action == FULL_FOLDER_HOLD) { $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' SET folder_id = ' . PRIVMSGS_HOLD_BOX . ' WHERE folder_id = ' . PRIVMSGS_NO_BOX . "\n\t\t\t\t\tAND user_id = {$user_id}\n\t\t\t\t\tAND " . $db->sql_in_set('msg_id', $msg_ary); $db->sql_query($sql); } else { $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "\n\t\t\t\tSET folder_id = {$dest_folder}, pm_new = 0\n\t\t\t\tWHERE folder_id = " . PRIVMSGS_NO_BOX . "\n\t\t\t\t\tAND user_id = {$user_id}\n\t\t\t\t\tAND pm_new = 1\n\t\t\t\t\tAND " . $db->sql_in_set('msg_id', $msg_ary); $db->sql_query($sql); if ($dest_folder != PRIVMSGS_INBOX) { $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . ' SET pm_count = pm_count + ' . (int) $db->sql_affectedrows() . "\n\t\t\t\t\tWHERE folder_id = {$dest_folder}\n\t\t\t\t\t\tAND user_id = {$user_id}"; $db->sql_query($sql); } } } if (sizeof($action_ary)) { // Move from OUTBOX to SENTBOX // We are not checking any full folder status here... SENTBOX is a special treatment (old messages get deleted) $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' SET folder_id = ' . PRIVMSGS_SENTBOX . ' WHERE folder_id = ' . PRIVMSGS_OUTBOX . ' AND ' . $db->sql_in_set('msg_id', array_keys($action_ary)); $db->sql_query($sql); } // Update new/unread count update_pm_counts(); // Now check how many messages got not moved... $sql = 'SELECT COUNT(msg_id) as num_messages FROM ' . PRIVMSGS_TO_TABLE . "\n\t\tWHERE user_id = {$user_id}\n\t\t\tAND folder_id = " . PRIVMSGS_HOLD_BOX; $result = $db->sql_query($sql); $num_not_moved = (int) $db->sql_fetchfield('num_messages'); $db->sql_freeresult($result); return array('not_moved' => $num_not_moved, 'removed' => $num_removed); }