Index: privatemsg.api.php
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/privatemsg/Attic/privatemsg.api.php,v
retrieving revision 1.1.2.5
diff -u -r1.1.2.5 privatemsg.api.php
--- privatemsg.api.php	8 Jun 2009 13:38:41 -0000	1.1.2.5
+++ privatemsg.api.php	12 Aug 2009 10:26:15 -0000
@@ -150,43 +150,34 @@
 function hook_privatemsg_sql_list_alter(&$fragment, $account) {
 
 }
-/**
- * Display a list of sent messages.
- *
- * @param $fragments
- *   Query fragments
- * @param $account
- *   User object
- */
-function hook_privatemsg_sql_list_sent_alter(&$fragment, $account) {
-
-}
 
 /**
- * Load a single message.
+ * Query definition to load a message.
  *
  * @param $fragments
- *   Query fragments
+ *   Query fragments array.
  * @param $pmid
- *   message id, pm.mid
- * @param $account
- *   User object
+ *   the id of the message.
+  * @param $account
+ *   User object of account for which to load the message.
  */
-function hook_privatemsg_sql_load_alter(&$fragment, $pmid, $account) {
+function hook_privatemsg_sql_load_alter(&$fragments, $pmid, $account = NULL) {
 
 }
+
 /**
- * Load all message id's of a thread.
+ * Query definition to load messages of one or multiple threads.
  *
  * @param $fragments
- *   Query fragments
- * @param $thread_id
- *   Thread id, pmi.thread_id is the same as the mid of the first
- *   message of that thread
+ *   Query fragments array.
+ * @param $threads
+ *   Array with one or multiple thread id's.
  * @param $account
- *   User object
+ *   User object for which the messages are being loaded.
+ * @param $load_all
+ *   Deleted messages are only loaded if this is set to TRUE.
  */
-function hook_privatemsg_sql_messages_alter(&$fragment, $thread_id, $account) {
+function hook_privatemsg_sql_messages_alter(&$fragments, $threads, $account = NULL, $load_all = FALSE) {
 
 }
 
@@ -294,10 +285,12 @@
  * user.
  * @todo There is no "undelete" hook
  *
- * @param $message
- *   Message array
+ * @param $pmid
+ *   ID of the message that has been deleted
+  * @param $deleted_by_all
+ *   Boolean to show whether the message has been deleted by all users or not
  */
-function hook_privatemsg_message_delete($message) {
+function hook_privatemsg_message_delete($pmid, $deleted_by_all) {
 
 }
 
Index: privatemsg.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/privatemsg/privatemsg.module,v
retrieving revision 1.70.2.30.2.91.2.64
diff -u -r1.70.2.30.2.91.2.64 privatemsg.module
--- privatemsg.module	30 Jul 2009 20:02:05 -0000	1.70.2.30.2.91.2.64
+++ privatemsg.module	12 Aug 2009 10:19:14 -0000
@@ -184,6 +184,15 @@
     'access arguments' => array('read privatemsg'),
     'type'             => MENU_CALLBACK,
   );
+  $items['user/%/messages'] = array(
+    'title' => 'Messages',
+    'page callback'    => 'drupal_get_form',
+    'page arguments'   => array('privatemsg_list', 'list', 1),
+    'access callback'  => 'privatemsg_user_tab_access',
+    'access arguments' => array(1),
+    'type' => MENU_LOCAL_TASK,
+  );
+
   return $items;
 }
 
@@ -214,6 +223,30 @@
   return TRUE;
 }
 
+/**
+ * Function to check if a user can access the messages tab on a user page.
+ *
+ * @param $uid
+ *   the user's id for whom the permission is being checked.
+ */
+function privatemsg_user_tab_access($uid) {
+  global $user;
+  $account = $user;
+  
+  // Disallow anonymous access, regardless of permissions.
+  if (!$account->uid) {
+    return FALSE;
+  }
+  // If a user is viewing own account, allow access.
+  if ($account->uid == $uid && privatemsg_user_access('read privatemsg', $account)) {
+    return TRUE;
+  }
+  // If a user has permission to view other user's messages, then allow access.
+  if (privatemsg_user_access('read all private messages', $account)) {
+    return TRUE;
+  }
+  return FALSE;
+}
 
 /**
  * Check access to the view messages page.
@@ -261,11 +294,23 @@
       global $user;
       $account = drupal_clone($user);
     }
+
+    // Load the list of participants.
+    $query = _privatemsg_assemble_query('participants', $thread_id);
+    $participants = db_query($query['query']);
+    while ($participant = db_fetch_object($participants)) {
+      $thread['participants'][$participant->uid] = $participant;
+    }
+    $thread['read_all'] = FALSE;
+    if (!array_key_exists($account->uid, $thread['participants']) && privatemsg_user_access('read all private messages', $account)) {
+      $thread['read_all'] = TRUE;
+    }
+
     // load messages returned by the messages query with _privatemsg_load().
-    $query = _privatemsg_assemble_query('messages', array($thread_id), $account);
+    $query = _privatemsg_assemble_query('messages', array($thread_id), $thread['read_all'] ? NULL : $account);
     $conversation = db_query($query['query']);
     while ($result = db_fetch_array($conversation)) {
-      if ($message = _privatemsg_load($result['mid'], $account)) {
+      if ($message = _privatemsg_load($result['mid'], $thread['read_all'] ? NULL : $account)) {
         $thread['messages'][$result['mid']] = $message;
       }
     }
@@ -279,12 +324,6 @@
     $message = current($thread['messages']);
     $thread['subject'] = $message['subject'];
 
-    // Load the list of participants.
-    $query = _privatemsg_assemble_query('participants', $thread_id);
-    $participants = db_query($query['query']);
-    while ($participant = db_fetch_object($participants)) {
-      $thread['participants'][$participant->uid] = $participant;
-    }
     return $thread;
   }
   return FALSE;
@@ -570,6 +609,11 @@
 function privatemsg_view($thread) {
   drupal_set_title(check_plain($thread['subject']));
 
+  if ($thread['read_all']) {
+    // User has permission to read all messages AND is not a participant of the current thread.
+    drupal_set_message(t('This conversation is being viewed with escalated priviledges and may not be the same as shown to normal users.'), 'warning');
+  }
+
   // Render the participants.
   $content['participants']['#value'] = theme('privatemsg_recipients', $thread);
   $content['participants']['#weight'] = -5;
@@ -588,7 +632,7 @@
 
   // Display the reply form if user is allowed to use it.
   if (privatemsg_user_access('write privatemsg')) {
-    $content['reply']['#value'] = drupal_get_form('privatemsg_new', $thread['participants'], $thread['subject'], $thread['thread_id']);
+    $content['reply']['#value'] = drupal_get_form('privatemsg_new', $thread['participants'], $thread['subject'], $thread['thread_id'], $thread['read_all']);
     $content['reply']['#weight'] = 5;
   }
 
@@ -598,7 +642,7 @@
 }
 
 
-function privatemsg_new(&$form_state, $recipients = array(), $subject = '', $thread_id = NULL) {
+function privatemsg_new(&$form_state, $recipients = array(), $subject = '', $thread_id = NULL, $read_all = FALSE) {
   global $user;
 
   $recipients_string = '';
@@ -748,6 +792,10 @@
       // If there are no valid recipients, unset the message reply form.
       $form['privatemsg']['#access'] = FALSE;
     }
+    $form['privatemsg']['read_all'] = array(
+      '#type'  => 'value',
+      '#value' => $read_all,
+    );
   }
   return $form;
 }
@@ -759,6 +807,7 @@
   $message['body']      = $form_state['values']['body'];
   $message['subject']   = $form_state['values']['subject'];
   $message['author']    = $form_state['values']['author'];
+  $message['read_all']    = $form_state['values']['read_all'];
   $message['timestamp'] = time();
   if (isset($form_state['values']['thread_id']) && $form_state['values']['thread_id']) {
     $message['thread_id'] = $form_state['values']['thread_id'];
@@ -904,10 +953,16 @@
  */
 
 /**
- * Query function for load.
+ * Query definition to load a message.
+ *
+ * @param $fragments
+ *   Query fragments array.
+ * @param $pmid
+ *   the id of the message.
+  * @param $account
+ *   User object of account for which to load the message.
  */
-function privatemsg_sql_load(&$fragments, $pmid, $account) {
-//  drupal_set_message('<pre>'. print_r(func_get_args(), 1) . '</pre>');
+function privatemsg_sql_load(&$fragments, $pmid, $account = NULL) {
   $fragments['primary_table'] = '{pm_message} pm'; // Our primary table
 
   $fragments['select'][]      = "pm.mid";
@@ -920,29 +975,35 @@
   $fragments['inner_join'][]  = 'INNER JOIN {pm_index} pmi ON pm.mid = pmi.mid';
   $fragments['where'][]       = 'pmi.mid = %d';
   $fragments['query_args']['where'][]  = $pmid;
-  $fragments['where'][]       = 'pmi.uid = %d';
-  $fragments['query_args']['where'][]  = $account->uid;
+  if ($account) {
+    $fragments['where'][]       = 'pmi.uid = %d';
+    $fragments['query_args']['where'][]  = $account->uid;
+  }
 }
+
 /**
  * Query definition to load messages of one or multiple threads.
  *
  * @param $fragments
- *  Query fragments array.
+ *   Query fragments array.
  * @param $threads
- *  Array with one or multiple thread id's.
+ *   Array with one or multiple thread id's.
  * @param $account
- *  User object for which the messages are being loaded.
+ *   User object for which the messages are being loaded.
  * @param $load_all
- *  Deleted messages are only loaded if this is set to TRUE.
+ *   Deleted messages are only loaded if this is set to TRUE.
  */
-function privatemsg_sql_messages(&$fragments, $threads, $account, $load_all = FALSE) {
+function privatemsg_sql_messages(&$fragments, $threads, $account = NULL, $load_all = FALSE) {
   $fragments['primary_table'] = '{pm_index} pmi';
 
   $fragments['select'][]      = 'DISTINCT(pmi.mid) as mid';
   $fragments['where'][]       = 'pmi.thread_id IN ('. db_placeholders($threads) .')';
   $fragments['query_args']['where']   += $threads;
-  $fragments['where'][]       = 'pmi.uid = %d';
-  $fragments['query_args']['where'][]  = $account->uid;
+  if ($account) {
+    // Only load the user's messages.
+    $fragments['where'][]     = 'pmi.uid = %d';
+    $fragments['query_args']['where'][]  = $account->uid;
+  }
   if (!$load_all) {
     $fragments['where'][]       = 'pmi.deleted = 0';
   }
@@ -1133,14 +1194,21 @@
 }
 
 function privatemsg_delete($form_state, $pmid) {
-  global $user;
 
   $form['pmid'] = array(
     '#type' => 'value',
     '#value' => $pmid,
   );
+  if (privatemsg_user_access('read all private messages')) {
+    $form['delete_options'] = array(
+      '#type' => 'checkbox',
+      '#title' => 'Delete this message for all users?',
+      '#description' => 'Tick the box to delete the message for all users.',
+      '#default_value' => FALSE,
+    );
+  }
   return confirm_form($form,
-    t('Are you sure you want to delete the message?'),
+    t('Are you sure you want to delete this message?'),
     isset($_GET['destination']) ? $_GET['destination'] : 'messages/view/'. $pmid,
     t('This action cannot be undone.'),
     t('Delete'),
@@ -1148,6 +1216,23 @@
   );
 }
 
+function privatemsg_delete_submit($form, &$form_state) {
+  global $user;
+  $account = drupal_clone($user);
+  
+  if ($form_state['values']['confirm']) {
+    if ($form_state['values']['delete_options']) {
+      privatemsg_message_change_delete($form_state['values']['pmid'], 1);
+      drupal_set_message(t('Message has been deleted for all users'));
+    }
+    else {
+      privatemsg_message_change_delete($form_state['values']['pmid'], 1, $account);
+      drupal_set_message(t('Message has been deleted'));
+    }
+  }
+  $form_state['redirect'] = 'messages';
+}
+
 /**
  * Delete or restore a message.
  *
@@ -1156,36 +1241,28 @@
  * @param $delete
  *   Either deletes or restores the thread (1 => delete, 0 => restore)
  * @param $account
- *   User acccount for which the message should be deleted.
+ *   User acccount for which the delete action should be carried out - Set to NULL to delete for all users.
  *
  * @ingroup api
  */
 function privatemsg_message_change_delete($pmid, $delete, $account = NULL) {
-  if (is_null($account)) {
-    global $user;
-    $account = drupal_clone($user);
+  if ($account){
+    db_query('UPDATE {pm_index} SET deleted = %d WHERE mid = %d AND uid = %d', $delete, $pmid, $account->uid);
+  }
+  else {
+    // Mark deleted for all users.
+    db_query('UPDATE {pm_index} SET deleted = %d WHERE mid = %d', $delete, $pmid);
   }
-  $message = _privatemsg_load($pmid, $account);
-
-  db_query('UPDATE {pm_index} SET deleted = %d WHERE mid = %d AND uid = %d', $delete, $pmid, $account->uid);
 
   $result = db_query("SELECT MIN(deleted) AS deleted_by_all FROM {pm_index} WHERE mid = %d", $pmid);
   $deleted = db_fetch_array($result);
 
   $deleted_by_all = FALSE;
-  if ($deleted['deleted_by_all'] == 0) {
+  if ($deleted['deleted_by_all'] > 0) {
     $deleted_by_all = TRUE;
   }
 
-  module_invoke_all('privatemsg_message_delete', $message, $deleted_by_all);
-}
-
-function privatemsg_delete_submit($form, &$form_state) {
-  if ($form_state['values']['confirm']) {
-    privatemsg_message_change_delete($form_state['values']['pmid'], 1);
-    drupal_set_message(t('Message has been deleted'));
-  }
-  $form_state['redirect'] = 'messages';
+  module_invoke_all('privatemsg_message_delete', $pmid, $deleted_by_all);
 }
 
 /**
@@ -1431,22 +1508,38 @@
   // Each recipient gets a record in the pm_index table.
   $query = "INSERT INTO {pm_index} (mid, thread_id, uid, is_new, deleted) VALUES (%d, %d, %d, %d, 0)";
   foreach ($message['recipients'] as $recipient) {
-    if ( !db_query($query, $mid, $message['thread_id'], $recipient->uid, 1) ) {
-      return FALSE;  // We assume if one insert failed then the rest may fail too against the same table
+    if (!db_query($query, $mid, $message['thread_id'], $recipient->uid, 1) ) {
+      // We assume if one insert failed then the rest may fail too against the
+      // same table.
+      return FALSE;
+    }
+  }
+
+  if (isset($message['read_all'])) {
+    // The message was sent in read all mode, add the author as recipient to all
+    // existing messages.
+    $query_messages = _privatemsg_assemble_query('messages', array($message['thread_id']), NULL);
+    $conversation = db_query($query_messages['query']);
+    while ($result = db_fetch_array($conversation)) {
+      if (!db_query($query, $result['mid'], $message['thread_id'], $message['author']->uid, 0)) {
+        return FALSE;
+      }
     }
   }
 
-  // When author is also the recipient, we want to set message to UNREAD. all other times his message is set to READ.
+  // When author is also the recipient, we want to set message to UNREAD.
+  // All other times the message is set to READ.
   $is_new = isset($message['recipients'][$message['author']->uid]) ? 1 : 0;
 
   // Also add a record for the author to the pm_index table.
-  if ( !db_query($query, $mid, $message['thread_id'], $message['author']->uid, $is_new)) {
-    return FALSE; // same as above
+  if (!db_query($query, $mid, $message['thread_id'], $message['author']->uid, $is_new)) {
+    return FALSE;
   }
 
   module_invoke_all('privatemsg_message_insert', $message);
 
-  return $message;  // if we reached here that means we were successful at writing all messages to db
+  // If we reached here that means we were successful at writing all messages to db.
+  return $message;
 }
 
 /**
@@ -1511,23 +1604,19 @@
  * @ingroup api
  */
 function _privatemsg_load($pmid, $account = NULL) {
-  if (empty($account)) {
-    global $user;
-    $account = drupal_clone($user);
-  }
-
   $query = _privatemsg_assemble_query('load', $pmid, $account);
 
   $result = db_query($query['query']);
-  $message = db_fetch_array($result);
-  $message['user'] = $account;
-  // Load author of message.
-  $message['author'] = user_load($message['author']);
-  $returned = module_invoke_all('privatemsg_message_load', $message);
-  if (!empty($returned)) {
-    $message = array_merge_recursive($returned, $message);
+  if ($message = db_fetch_array($result)) {
+    // Load author of message.
+    $message['author'] = user_load($message['author']);
+    $returned = module_invoke_all('privatemsg_message_load', $message);
+    if (!empty($returned)) {
+      $message = array_merge_recursive($returned, $message);
+    }
+    return $message;
   }
-  return $message;
+  return FALSE;
 }
 
 /**

