Index: privatemsg.module
===================================================================
RCS file: /cvs/drupal/contributions/modules/privatemsg/privatemsg.module,v
retrieving revision 1.70.2.30.2.91.2.13
diff -u -p -r1.70.2.30.2.91.2.13 privatemsg.module
--- privatemsg.module	27 Jan 2009 16:55:18 -0000	1.70.2.30.2.91.2.13
+++ privatemsg.module	28 Jan 2009 23:13:20 -0000
@@ -83,13 +83,15 @@ function privatemsg_menu() {
   $items['messages'] = array(
     'title'            => 'Messages',
     'title callback'  => 'privatemsg_title_callback',
-    'page callback'    => 'privatemsg_list',
+    'page callback'    => 'drupal_get_form',
+    'page arguments'   => array('privatemsg_list'),
     'access arguments' => array('read privatemsg'),
     'type'             => MENU_NORMAL_ITEM,
   );
   $items['messages/inbox'] = array(
     'title'            => 'All messages',
-    'page callback'    => 'privatemsg_list',
+    'page callback'    => 'drupal_get_form',
+    'page arguments'   => array('privatemsg_list'),
     'access arguments' => array('read privatemsg'),
     'type'             => MENU_DEFAULT_LOCAL_TASK,
     'weight'           => -10,
@@ -104,7 +106,8 @@ function privatemsg_menu() {
   );
   $items['messages/sent'] = array(
     'title'            => 'Sent messages',
-    'page callback'    => 'privatemsg_list',
+    'page callback'    => 'drupal_get_form',
+    'page arguments'   => array('privatemsg_list'),
     'access arguments' => array('read privatemsg'),
     'type'             => MENU_LOCAL_TASK,
     'weight'           => -5,
@@ -240,8 +243,8 @@ function privatemsg_theme() {
       'arguments'        => array('recipients' => NULL),
       'template'         => 'privatemsg-between',
     ),
-    'privatemsg_message_row'  => array(
-      'arguments'             => array('row'),
+    'privatemsg_list_messages'  => array(
+      'arguments'             => array('form'),
     ),
     'privatemsg_new_block'  => array(
       'arguments'             => array('count'),
@@ -296,25 +299,8 @@ function privatemsg_list($uid = NULL) {
   }
   // By this point we have figured out for which user we are listing messages and now it is safe to use $account->uid in the listing query.
 
-  $content = array();
-  $content['list']['content'] = privatemsg_list_messages($account);
-  $content['list']['#weight'] = 0;
-
-  drupal_alter('privatemsg_list_messages', $content, $account);
-
-  uasort($content, 'element_sort');
-
-  $expand = '';
-  foreach ($content as $element) {
-    $expand .= $element['content'];
-  }
-  return $expand;
-}
+  drupal_add_css(drupal_get_path('module', 'privatemsg') .'/styles/privatemsg-list.css');
 
-/**
- * Display the list of messages for a given user, called by privatemsg_privatemsg_alter
- */
-function privatemsg_list_messages($account) {
   switch (arg(1)) {
     case 'sent':
       $query = _privatemsg_assemble_query('privatemsg_list_sent', $account);
@@ -325,68 +311,168 @@ function privatemsg_list_messages($accou
   }
   $result = pager_query($query['query'], variable_get('privatemsg_per_page', 25), 0, $query['count']);
 
-  $rows = array();
+  $threads = array();
+  $form['#rows'] = array();
   while ($thread = db_fetch_array($result)) {
-    $rows[] = theme('privatemsg_message_row', $thread);
+    $form['#rows'][] = $thread;
+    $threads[$thread['thread_id']] = '';
   }
 
-  $content = '';
-  if (!empty($rows)) {
-    $head = array();
-    foreach (array_keys($rows[0]) as $index) {
-      $head[$index] =  array('data' => $index);
-      if ($index == t('Last updated') || $index == t('Subject')) {
-        $head[$index] += array('field' => $index, 'sort' => 'desc');
-      }
+  if (!empty($form['#rows'])) {
+    $form['actions'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Actions'),
+      '#prefix' => '<div class="container-inline">',
+      '#suffix' => '</div>',
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+      '#weight' => -1,
+    );
+
+    $options = array();
+    foreach (module_invoke_all('privatemsg_thread_operations') as $operation => $array) {
+      $options[$operation] = $array['label'];
     }
+    $form['actions']['operation'] = array(
+      '#type' => 'select',
+      '#options' => $options,
+      '#default_value' => 'mark as read',
+    );
+    $form['actions']['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Execute'),
+      '#submit' => array('privatemsg_list_submit'),
+    );
+  }
+
+  $form['threads'] = array('#type' => 'checkboxes', '#options' => $threads);
+  $form['pager'] = array('#value' => theme('pager'), '#weight' => 15);
+  $form['#theme'] = 'privatemsg_list_messages';
+  $form['#account'] = $account;
+
+  return $form;
+}
 
-    $content = theme('table', $head, $rows);
-    $content .= theme('pager');
-    drupal_add_css(drupal_get_path('module', 'privatemsg') .'/styles/privatemsg-list.css');
+/**
+ * Implementation of hook_privatemsg_thread_operations().
+ */
+function privatemsg_privatemsg_thread_operations() {
+  $operations = array(
+    'mark as read' => array(
+      'label' => t('Mark as read'),
+      'callback' => '_privatemsg_thread_setnew',
+      'callback arguments' => array('new' => 0),
+    ),
+    'mark as unread' => array(
+      'label' => t('Mark as unread'),
+      'callback' => '_privatemsg_thread_setnew',
+      'callback arguments' => array('new' => 1),
+    ),
+    'delete' => array(
+      'label' => t('Delete'),
+      'callback' => 'privatemsg_thread_delete',
+    ),
+  );
+  return $operations;
+}
+
+function _privatemsg_thread_setnew($threads, $new_status = 0) {
+  global $user;
+
+  foreach ($threads as $thread) {
+    $query = "UPDATE {pm_index} SET is_new = %s WHERE thread_id = %d AND uid = %d";
+    db_query($query, $new_status, $thread, $user->uid);
+  }
+}
+
+/**
+ * Process privatemsg_list form submissions.
+ *
+ * Execute the chosen 'Update option' on the selected nodes. This function is
+ * a copy of node_admin_nodes_submit
+ */
+function privatemsg_list_submit($form, &$form_state) {
+  $operations = module_invoke_all('privatemsg_thread_operations');
+  $operation = $operations[$form_state['values']['operation']];
+  // Filter out unchecked nodes
+  $threads = array_filter($form_state['values']['threads']);
+  if ($function = $operation['callback']) {
+    // Add in callback arguments if present.
+    if (isset($operation['callback arguments'])) {
+      $args = array_merge(array($threads), $operation['callback arguments']);
+    }
+    else {
+      $args = array($threads);
+    }
+    call_user_func_array($function, $args);
   }
   else {
-    drupal_set_message(t('No messages to display.'));
+    // We need to rebuild the form to go to a second step.  For example, to
+    // show the confirmation form for the deletion of nodes.
+    $form_state['rebuild'] = TRUE;
   }
-
-  return $content;
 }
 
-function theme_privatemsg_new_block($count) {
-  $text = format_plural($count, 'You have a new message, click here to read it',
-                        'You have @count new messages, click here to read them',
-                        array('@count' => $count));
+function privatemsg_thread_delete($threads) {
+  global $user;
 
-  return l($text, 'messages', array('attributes' => array('id' => 'privatemsg-new-link')));
+  foreach ($threads as $thread) {
+    db_query('UPDATE {pm_index} SET deleted = 1 WHERE thread_id = %d AND uid = %d', $thread, $user->uid);
+  }
 }
 
 /**
- * Theme a row of messages
- *
+ * Display the list of messages for a given user, called by privatemsg_privatemsg_alter
  */
-function theme_privatemsg_message_row($row) {
-  $themed_row = array();
+function theme_privatemsg_list_messages($form) {
+    // If there are rows in this form, then $form['title'] contains a list of
+  // the title form elements.
+  $has_posts = !empty($form['#rows']);
+  $select_header = $has_posts ? theme('table_select_header_cell') : '';
+  $header = array($select_header, t('Subject'), t('Authors'), t('Last Updated'));
+
+  $themed_rows = array();
+  foreach ($form['#rows'] as $row) {
+    $themed_row = array();
+    $themed_row[] = drupal_render($form['threads'][$row['thread_id']]);
+
+    $unread = '';
+    if (isset($row['is_new']) && $row['is_new'] ) {
+      $unread = ' privatemsg-unread';
+    }
+    $themed_row[t('Subject')] = '<span class="privatemsg-list-subject'. $unread .'">'. l($row['subject'], 'messages/view/'. $row['thread_id']) .'</span>';
+    if (isset($row['author']) && $row['author']) {
+      $authors = _privatemsg_generate_user_array($row['author']);
+      $themed_row[t('Authors')] = '<span class="privatemsg-list-from'.  $unread .'">'. _privatemsg_format_participants($authors, 3, TRUE) .'</span>';
+    }
+    if (array_key_exists('recipient', $row)) {
+      $themed_row[t('Recipients')] = '';
+      if (!empty($row['recipient'])) {
+        $recipients = _privatemsg_generate_user_array($row['recipient']);
+        $themed_row[t('Recipients')] = '<span class="privatemsg-list-to'.  $unread .'">'. _privatemsg_format_participants($recipients, 3, TRUE) .'</span>';
+      }
+    }
+    if ($row['last_updated']) {
+      $themed_row[t('Last updated')] = '<span class="privatemsg-list-date'.  $unread .'">'. format_date($row['last_updated'], 'small') .'</span>';
+    }
+    $themed_rows[] = $themed_row;
+  }
+  unset($form['rows']);
 
-  $unread = '';
-  if (isset($row['is_new']) && $row['is_new'] ) {
-    $unread = ' privatemsg-unread';
-  }
-  $themed_row[t('Subject')] = '<span class="privatemsg-list-subject'. $unread .'">'. l($row['subject'], 'messages/view/'. $row['thread_id']) .'</span>';
-  if (isset($row['author']) && $row['author']) {
-    $authors = _privatemsg_generate_user_array($row['author']);
-    $themed_row[t('Authors')] = '<span class="privatemsg-list-from'.  $unread .'">'. _privatemsg_format_participants($authors, 3, TRUE) .'</span>';
-  }
-  if (array_key_exists('recipient', $row)) {
-    $themed_row[t('Recipients')] = '';
-    if (!empty($row['recipient'])) {
-      $recipients = _privatemsg_generate_user_array($row['recipient']);
-      $themed_row[t('Recipients')] = '<span class="privatemsg-list-to'.  $unread .'">'. _privatemsg_format_participants($recipients, 3, TRUE) .'</span>';
-    }
-  }
-//  drupal_set_message('<pre>'. print_r($row, 1) . '</pre>');
-  if ($row['last_updated']) {
-    $themed_row[t('Last updated')] = '<span class="privatemsg-list-date'.  $unread .'">'. format_date($row['last_updated'], 'small') .'</span>';
+  if (empty($themed_rows)) {
+    $themed_rows[] = array(array('data' => t('No messages available.'), 'colspan' => count($header)));
   }
-  return $themed_row;
+
+  $form['list'] = array('#value' => theme('table', $header, $themed_rows), '#weight' => 5);
+  return drupal_render($form);
+}
+
+function theme_privatemsg_new_block($count) {
+  $text = format_plural($count, 'You have a new message, click here to read it',
+                        'You have @count new messages, click here to read them',
+                        array('@count' => $count));
+
+  return l($text, 'messages', array('attributes' => array('id' => 'privatemsg-new-link')));
 }
 
 /**
Index: privatemsg_filter/privatemsg_filter.module
===================================================================
RCS file: /cvs/drupal/contributions/modules/privatemsg/privatemsg_filter/privatemsg_filter.module,v
retrieving revision 1.1.2.2
diff -u -p -r1.1.2.2 privatemsg_filter.module
--- privatemsg_filter/privatemsg_filter.module	23 Dec 2008 16:46:13 -0000	1.1.2.2
+++ privatemsg_filter/privatemsg_filter.module	28 Jan 2009 23:13:21 -0000
@@ -1,5 +1,6 @@
 <?php
-// $Id: privatemsg_filter.module,v 1.1.2.2 2008/12/23 16:46:13 litwol Exp $
+// $Id: privatemsg_filter.module,v 1.1.2.1 2008/12/19 22:05:19 litwol Exp $
+
 
 /**
  * @file
@@ -156,7 +157,7 @@ function privatemsg_filter_delete_tags_s
 function privatemsg_filter_get_filter($account) {
   $filter = array();
   if (isset($_GET['tags'])) {
-    $tag_data = privatemsg_filter_get_tags_data($account);
+    $tag_data = privatemsg_filter_get_tags_data($account->uid);
     foreach (explode(' ', $_GET['tags']) as $tag) {
       if (isset($tag_data[$tag])) {
         $filter['tags'][$tag] = $tag;
@@ -199,7 +200,7 @@ function privatemsg_filter_get_author_da
   if (is_array($author_data)) {
     return $author_data;
   }
-  $sql = 'SELECT DISTINCT pm.author, u.name FROM {pm_message} pm INNER JOIN {pm_index pmi} ON pm.mid = pmi.mid INNER JOIN {users} u ON pm.author = u.uid WHERE pmi.uid = %d AND u.uid > 0 ORDER BY u.name';
+  $sql = 'SELECT DISTINCT pm.author, u.name FROM {pm_message} pm INNER JOIN {pm_index pmi} ON pm.mid = pmi.mid INNER JOIN {users} u ON pm.author = u.uid WHERE pmi.uid = %d AND u.uid > 0 AND pmi.deleted = 0 ORDER BY u.name';
   $query = db_query($sql, $account->uid);
 
   $author_data = array();
@@ -209,22 +210,27 @@ function privatemsg_filter_get_author_da
   return $author_data;
 }
 
-function privatemsg_filter_get_tags_data($account) {
- static $tag_data;
+function privatemsg_filter_get_tags_data($uid = 0) {
+ static $tag_data = array();
  
-  if (is_array($tag_data)) {
-    return $tag_data;
+  if (isset($tag_data[$uid])) {
+    return $tag_data[$uid];
   }
 
   // Only show the tags that a user has used.
-  $sql = 'SELECT pmt.tag, pmt.tag_id FROM {pm_tags_index} pmti LEFT JOIN {pm_tags} pmt ON pmti.tag_id = pmt.tag_id WHERE pmti.uid = %d GROUP BY pmt.tag_id, pmt.tag';
-  $query = db_query($sql, $account->uid);
+  if ($uid) {
+    $sql = 'SELECT pmt.tag, pmt.tag_id FROM {pm_tags_index} pmti LEFT JOIN {pm_tags} pmt ON pmti.tag_id = pmt.tag_id WHERE pmti.uid = %d GROUP BY pmt.tag_id, pmt.tag';
+    $query = db_query($sql, $uid);
+  } else {
+    $sql = 'SELECT tag, tag_id FROM {pm_tags} ORDER BY tag';
+    $query = db_query($sql);
+  }
 
   $tag_data = array();
   while ($result = db_fetch_object($query)) {
-    $tag_data[$result->tag_id] = $result->tag;
+    $tag_data[$uid][$result->tag_id] = $result->tag;
   }
-  return $tag_data;
+  return $tag_data[$uid];
 }
 
 function privatemsg_filter_dropdown(&$form_state, $account) {
@@ -236,6 +242,7 @@ function privatemsg_filter_dropdown(&$fo
       '#title' => t('Filter Messages'),
       '#collapsible' => TRUE,
       '#collapsed' => TRUE,
+      '#weight' => -10,
   );
   $form['filter']['search'] = array(
       '#type' => 'textfield',
@@ -253,7 +260,7 @@ function privatemsg_filter_dropdown(&$fo
   );
 
   // Only show form if the user has some messages tagged.
-  if (count($tag_data = privatemsg_filter_get_tags_data($account))) {
+  if (count($tag_data = privatemsg_filter_get_tags_data($account->uid))) {
     $form['filter']['tags'] = array(
       '#type' => 'select',
       '#title' => t('Tags'),
@@ -268,6 +275,7 @@ function privatemsg_filter_dropdown(&$fo
       '#value'    => t('Filter'),
       '#prefix'   => '<div id="privatemsg-filter-buttons">',
       '#weight'   => 10,
+      '#submit' => array('privatemsg_filter_dropdown_submit'),
     );
 
     $form['filter']['save'] = array(
@@ -275,6 +283,7 @@ function privatemsg_filter_dropdown(&$fo
       '#value'    => t('Save Filter'),
       '#suffix'   => '</div>',
       '#weight'   => 11,
+      '#submit' => array('privatemsg_filter_dropdown_submit'),
     );
 
     if ($filter = privatemsg_filter_get_filter($account)) {
@@ -302,7 +311,8 @@ function privatemsg_filter_dropdown_set_
       '#type'     => 'submit',
       '#value'    => t('Reset'),
       '#suffix'   => '</div>',
-      '#weight'   => 12
+      '#weight'   => 12,
+      '#submit' => array('privatemsg_filter_dropdown_submit'),
   );
   unset($form['filter']['save']['#suffix']);
 }
@@ -378,16 +388,6 @@ function privatemsg_filter_create_get_qu
   return $query;
 }
 
-/**
- * Implementation of hook_privatemsg_list_messages_alter().
- */
-function privatemsg_filter_privatemsg_list_messages_alter(&$content, $account) {
-  if (!empty($content['list']['content']) || privatemsg_filter_get_filter($account)) {
-    $content['tags']['content'] = drupal_get_form('privatemsg_filter_dropdown', $account);
-    $content['tags']['#weight'] = -5;
-  }
-}
-
 
 /**
  * Hook into the query builder to add the tagging info to the correct query
@@ -423,6 +423,44 @@ function privatemsg_filter_privatemsg_li
   }
 }
 
+function privatemsg_filter_form_alter(&$form, $form_state, $form_id) {
+  if ($form_id == 'privatemsg_list' && count($form['#rows']) > 0) {
+    $form += privatemsg_filter_dropdown($form_state, $form['#account']);
+  }
+}
+
+/**
+ * Implementation of hook_privatemsg_thread_operations().
+ */
+function privatemsg_filter_privatemsg_thread_operations() {
+  $operations = array();
+  $tags = privatemsg_filter_get_tags_data();
+
+  if (!empty($tags)) {
+    $operations['-'] = array(
+      'label' => t('Apply Tag...'),
+    );
+    foreach ($tags as $tag_id => $tag) {
+      $operations[$tag_id] = array(
+        'label' => '- '. $tag,
+        'callback' => '_privatemsg_filter_thread_tag',
+        'callback arguments' => array('tag_id' => $tag_id),
+      );
+    }
+  }
+  return $operations;
+}
+
+function _privatemsg_filter_thread_tag($threads, $tag_id) {
+  global $user;
+
+  foreach ($threads as $thread) {
+    if (db_result(db_query('SELECT COUNT(*) FROM {pm_tags_index} WHERE tag_id = %d AND (uid = %d AND thread_id = %d)', $tag_id, $user->uid, $thread)) == 0) {
+      db_query('INSERT INTO {pm_tags_index} (tag_id, uid, thread_id) VALUES (%d, %d, %d)', $tag_id, $user->uid, $thread);
+    }
+  }
+}
+
 function privatemsg_filter_privatemsg_view_messages_alter(&$content, $count) {
   if ($count > 0) {
     $content['tags']['content'] = drupal_get_form('privatemsg_filter_form');
