Index: privatemsg.module
===================================================================
RCS file: /cvs/drupal/contributions/modules/privatemsg/privatemsg.module,v
retrieving revision 1.70.2.30.2.91.2.100
diff -u -p -r1.70.2.30.2.91.2.100 privatemsg.module
--- privatemsg.module	23 Nov 2009 19:54:49 -0000	1.70.2.30.2.91.2.100
+++ privatemsg.module	26 Nov 2009 18:23:19 -0000
@@ -132,9 +132,13 @@ function privatemsg_menu() {
   );
   $items['messages/view/%privatemsg_thread'] = array(
     'title'            => 'Read message',
+    // Set the third argument to TRUE so that we can show access denied instead
+    // of not found.
+    'load arguments'   => array(NULL, NULL, TRUE),
     'page callback'    => 'privatemsg_view',
     'page arguments'   => array(2),
     'access callback'  => 'privatemsg_view_access',
+    'access arguments' => array(2),
     'type'             => MENU_LOCAL_TASK,
     'weight'           => -5,
   );
@@ -233,9 +237,18 @@ function privatemsg_user_access($permiss
  * messages/view/% pages and not to leave tabs artifact on other lower
  * level pages such as the messages/new/%.
  *
+ * @param $thread
+ *   A array containing all information about a specific thread, generated by
+ *   privatemsg_thread_load().
+ *
  * @ingroup api
  */
-function privatemsg_view_access() {
+function privatemsg_view_access($thread) {
+  // Do not allow access to threads without messages.
+  if (empty($thread['messages'])) {
+    // Count all messages, if there
+    return FALSE;
+  }
   if (privatemsg_user_access('read privatemsg') && arg(1) == 'view') {
     return TRUE;
   }
@@ -255,6 +268,10 @@ function privatemsg_view_access() {
  *   the current user.
  * @param $limit
  *   How many messages should be loaded. Note that counting starts from the end.
+ * @param $useAccessDenied
+ *   Set to TRUE if the function should forward to the access denied page
+ *   instead of not found. This is used by the menu system because that does
+ *   load arguments before access checks are made. Defaults to FALSE.
  *
  * @return
  *   $thread object, with keys messages, participants, title and user. messages
@@ -266,7 +283,7 @@ function privatemsg_view_access() {
 
  * @ingroup api
  */
-function privatemsg_thread_load($thread_id, $account = NULL, $limit = NULL) {
+function privatemsg_thread_load($thread_id, $account = NULL, $limit = NULL, $useAccessDenied = FALSE) {
   static $threads = array();
   if ((int)$thread_id > 0) {
     $thread = array('thread_id' => $thread_id);
@@ -325,7 +342,18 @@ function privatemsg_thread_load($thread_
 
       // If there are no messages, don't allow access to the thread.
       if (empty($thread['messages'])) {
-        $thread = FALSE;
+        if ($useAccessDenied) {
+          // Generate new query with read all to see if the thread does exist.
+          $query = _privatemsg_assemble_query('messages', array($thread_id), NULL);
+          $exists = db_result(db_query($query['count']));
+          if (!$exists) {
+            // Thread does not exist, display 404.
+            $thread = FALSE;
+          }
+        }
+        else {
+          $thread = FALSE;
+        }
       }
       else {
         // General data, assume subject is the same for all messages of that thread.
