Index: privatemsg.install
===================================================================
RCS file: /cvs/drupal/contributions/modules/privatemsg/privatemsg.install,v
retrieving revision 1.17
diff -u -p -r1.17 privatemsg.install
--- privatemsg.install	12 Jul 2010 06:56:53 -0000	1.17
+++ privatemsg.install	17 Jul 2010 16:40:31 -0000
@@ -51,8 +51,8 @@ function privatemsg_schema() {
         'not null' => TRUE,
         'default' => 'user'
       ),
-
     ),
+    'primary key'     => array('mid', 'recipient', 'type'),
     'indexes'         => array(
       'mid'               => array('mid'),
       'thread_id'         => array('thread_id'),
@@ -562,3 +562,64 @@ function privatemsg_update_6008() {
   )));
   return $ret;
 }
+
+/**
+ * Remove duplicate entries in {pm_index}.
+ */
+function privatemsg_update_6009(&$sandbox) {
+  // First run, initialize sandbox and check if we are ready to run.
+  if (!isset($sandbox['current_thread_id'])) {
+    // If privatemsg_filter is enabled, check if the updates that add the Inbox
+    // tag did already run to make it possible to tag messages users sent to
+    // themself.
+    // We cannot detect if privatemsg_filter_update_6004 has been run, so we
+    // assume that 6004 has been run if 6003 has been.
+    if (module_exists('privatemsg_filter') && (!($tag_id = variable_get('privatemsg_filter_inbox_tag', '')) || (!db_result(db_query('SELECT 1 FROM {pm_tags} WHERE tag_id = %d', $tag_id))))) {
+      drupal_set_message(t('Some updates are still pending. Please return to <a href="@update-php">update.php</a> and run the remaining updates.', array('@update-php' => base_path() .'update.php?op=selection')), 'error', FALSE);
+      $ret['#abort'] = array('success' => FALSE, 'query' => t('Some updates are still pending.<br/>Please re-run the update script.'));
+      return $ret;
+    }
+
+    $sandbox['current_thread_id'] = 0;
+    // Assume that the thread ids are distributed more or less equally over the
+    // whole data set. This allows us to calculate the approximate progress.
+    $sandbox['max'] = db_result(db_query('SELECT MAX(thread_id) FROM {pm_index}'));
+  }
+
+  // Fetch the 10 next thread_ids.
+  $result = db_query_range('SELECT DISTINCT thread_id FROM {pm_index} WHERE thread_id > %d ORDER BY thread_id ASC', $sandbox['current_thread_id'], 0, 20);
+  $threads = array();
+  while ($row = db_fetch_object($result)) {
+    $threads[] = $row->thread_id;
+  }
+
+  if (!empty($threads)) {
+    // By limiting this slow query (having condition) on a specific set of
+    // threads, this allows us to process the slow having part on a relatively
+    // small subset of pm_index that can be selected based on the thread_id
+    // index. There might also be cases where is_new and/or deleted are not
+    // equal, use MAX(is_new) and MIN(deleted) for these cases.
+    $sql = 'SELECT COUNT(*) AS count, pmi.recipient, pmi.type, pmi.mid, pmi.thread_id, MAX(pmi.is_new) As is_new, MIN(pmi.deleted) AS deleted FROM {pm_index} pmi WHERE thread_id IN (' . db_placeholders($threads) . ') GROUP BY pmi.recipient, pmi.type, pmi.mid, pmi.thread_id HAVING COUNT(*) > 1';
+    $result = db_query($sql, $threads);
+    while ($row = db_fetch_object($result)) {
+      // Delete all occurences of these entries.
+      db_query("DELETE FROM {pm_index} WHERE mid = %d AND recipient = %d AND type = '%s'", $row->mid, $row->recipient, $row->type);
+      // Re-insert a single entry. We do this to explicitely keep messages
+      // unread and undeleted if there are conflicting entries.
+      db_query('INSERT INTO {pm_index} (mid, thread_id, recipient, type, is_new, deleted) VALUES (%d, %d, %d, %d, %d)', $row->mid, $row->thread_id, $row->recipient, $row->type, $row->is_new, $row->deleted);
+    }
+    $sandbox['current_thread_id'] = max($threads);
+  }
+  // Set #finished based on sandbox.
+  $ret['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['current_thread_id'] / $sandbox['max']);
+  return $ret;
+}
+
+/**
+ * Add primary key to {pm_index}.
+ */
+function privatemsg_update_6010() {
+  $ret = array();
+  db_add_primary_key($ret, 'pm_index', array('mid', 'recipient', 'type'));
+  return $ret;
+}
Index: privatemsg.module
===================================================================
RCS file: /cvs/drupal/contributions/modules/privatemsg/privatemsg.module,v
retrieving revision 1.141
diff -u -p -r1.141 privatemsg.module
--- privatemsg.module	17 Jul 2010 10:34:43 -0000	1.141
+++ privatemsg.module	17 Jul 2010 16:40:32 -0000
@@ -1591,13 +1591,12 @@ function _privatemsg_send($message) {
     }
   }
 
-  // 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']['user_' . $message['author']->uid]) ? 1 : 0;
-
-  // Also add a record for the author to the pm_index table.
-  if (!db_query($index_sql, $mid, $message['thread_id'], $message['author']->uid, 'user', $is_new)) {
-    return FALSE;
+  // We only want to add the author to the pm_index table, if the message has
+  // not been sent directly to him.
+  if (!isset($message['recipients']['user_' . $message['author']->uid])) {
+    if (!db_query($index_sql, $mid, $message['thread_id'], $message['author']->uid, 'user', 0)) {
+      return FALSE;
+    }
   }
 
   module_invoke_all('privatemsg_message_insert', $message);
