/** * Check if a user is allowed to send a message based on various criteria * * @param \Destiny\Common\SessionCredentials $user * @param int $targetuserid * @return boolean */ public function canSend($user, $targetuserid) { if ($user->hasRole(UserRole::ADMIN)) { return true; } $userid = $user->getUserId(); $conn = Application::instance()->getConnection(); $stmt = $conn->prepare("\n SELECT\n userid,\n targetuserid,\n isread,\n UNIX_TIMESTAMP(timestamp) AS timestamp\n FROM privatemessages\n WHERE\n (\n userid = :userid OR\n targetuserid = :userid\n ) AND\n DATE_SUB(NOW(), INTERVAL 1 HOUR) < timestamp\n ORDER BY id ASC\n "); $stmt->bindValue('userid', $userid, \PDO::PARAM_INT); $stmt->execute(); $now = time(); $cansend = true; $timelimit = 60 * 60 * 1; $messagelimit = 3; $general_unread_count = 0; $target_unread_count = 0; while ($row = $stmt->fetch()) { if ($row['userid'] == $userid && !$row['isread']) { // $userid sent a message that was NOT read $general_unread_count += 1; // immediatly throttle if sent more than $messagelimit unread // messages to the same $targetuserid in the last $timelimit minutes // ONLY a reply can cancel this, otherwise it would `return false` if ($row['targetuserid'] != $targetuserid) { continue; } $target_unread_count += 1; if ($target_unread_count > $messagelimit && $now - $row['timestamp'] < $timelimit) { $cansend = false; } } else { if ($row['userid'] == $targetuserid) { $target_unread_count -= $messagelimit; $general_unread_count -= $messagelimit; $cansend = true; // avoid rate limiting quick replies // received a message in the last $timelimit minutes, reset if ($now - $row['timestamp'] < $timelimit) { return true; } } else { // $userid sent a message that was read OR // $userid recieved a message from someone unrelated to this conversation $general_unread_count -= 2; } } } // sent message count outweighs the received message count, deny // considering this is the last hour, and most people don't mark as read if ($target_unread_count > 7 || $general_unread_count > 21) { $cansend = false; } return $cansend; }