Index: modules/comment/comment-rtl.css
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment-rtl.css,v
retrieving revision 1.1
diff -u -u -p -r1.1 comment-rtl.css
--- modules/comment/comment-rtl.css	27 May 2007 17:57:48 -0000	1.1
+++ modules/comment/comment-rtl.css	28 Jun 2007 20:25:31 -0000
@@ -4,3 +4,9 @@
   margin-left: inherit;
   margin-right: 25px;
 }
+#comment-admin-buttons {
+  float: right;
+  margin-left: inherit;
+  margin-right: 0.5em;
+  clear: left;
+}
Index: modules/comment/comment.css
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.css,v
retrieving revision 1.3
diff -u -u -p -r1.3 comment.css
--- modules/comment/comment.css	27 May 2007 17:57:48 -0000	1.3
+++ modules/comment/comment.css	28 Jun 2007 20:25:31 -0000
@@ -3,3 +3,14 @@
 .indented {
   margin-left: 25px; /* LTR */
 }
+#comment-admin-filter ul {
+  list-style-type: none;
+  padding: 0;
+  margin: 0;
+  width: 100%;
+}
+#comment-admin-buttons {
+  float: left; /* LTR */
+  margin-left: 0.5em; /* LTR */
+  clear: right; /* LTR */
+}
Index: modules/comment/comment.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v
retrieving revision 1.556
diff -u -u -p -r1.556 comment.module
--- modules/comment/comment.module	24 Jun 2007 10:09:52 -0000	1.556
+++ modules/comment/comment.module	28 Jun 2007 20:25:31 -0000
@@ -164,6 +164,12 @@ function comment_theme() {
       'arguments' => array('comment' => NULL, 'node' => NULL, 'links' => array()),
       'file' => 'comment.tpl.php',
     ),
+    'comment_filter_form' => array(
+      'arguments' => array('form' => NULL),
+    ),
+    'comment_filters' => array(
+      'arguments' => array('form' => NULL),
+    ),
     'comment_folded' => array(
       'arguments' => array('comment' => NULL),
     ),
@@ -210,18 +216,6 @@ function comment_menu() {
     'weight' => -10,
   );
 
-  // Subtabs:
-  $items['admin/content/comment/list/new'] = array(
-    'title' => 'Published comments',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-    'weight' => -10,
-  );
-  $items['admin/content/comment/list/approval'] = array(
-    'title' => 'Approval queue',
-    'page arguments' => array('approval'),
-    'type' => MENU_LOCAL_TASK,
-  );
-
   $items['admin/content/comment/settings'] = array(
     'title' => 'Settings',
     'page callback' => 'drupal_get_form',
@@ -1134,77 +1128,92 @@ function comment_delete_post($comment) {
 }
 
 /**
- * Comment operations. We offer different update operations depending on
- * which comment administration page we're on.
+ * Implementation of hook_comment_operations().
  */
-function comment_operations($action = NULL) {
-  if ($action == 'publish') {
-    $operations = array(
-      'publish' => array(t('Publish the selected comments'), 'UPDATE {comments} SET status = '. COMMENT_PUBLISHED .' WHERE cid = %d'),
-      'delete' => array(t('Delete the selected comments'), '')
-    );
-  }
-  else if ($action == 'unpublish') {
-    $operations = array(
-      'unpublish' => array(t('Unpublish the selected comments'), 'UPDATE {comments} SET status = '. COMMENT_NOT_PUBLISHED .' WHERE cid = %d'),
-      'delete' => array(t('Delete the selected comments'), '')
-    );
-  }
-  else {
-    $operations = array(
-      'publish' => array(t('Publish the selected comments'), 'UPDATE {comments} SET status = '. COMMENT_PUBLISHED .' WHERE cid = %d'),
-      'unpublish' => array(t('Unpublish the selected comments'), 'UPDATE {comments} SET status = '. COMMENT_NOT_PUBLISHED .' WHERE cid = %d'),
-      'delete' => array(t('Delete the selected comments'), '')
-    );
-  }
+function comment_comment_operations() {
+  $operations = array(
+    'publish' => array(
+      'label' => t('Publish'),
+      'callback' => 'comment_operations_publish',
+    ),
+    'unpublish' => array(
+      'label' => t('Unpublish'),
+      'callback' => 'comment_operations_unpublish',
+    ),
+    'delete' => array(
+      'label' => t('Delete'),
+    ),
+  );
   return $operations;
 }
 
 /**
+ * Callback function for admin mass publishing comments.
+ */
+function comment_operations_publish($comments) {
+  db_query('UPDATE {comments} SET status = '. COMMENT_PUBLISHED .' WHERE cid IN(%s)', implode(',', $comments));
+}
+
+/**
+ * Callback function for admin mass unpublishing comments.
+ */
+function comment_operations_unpublish($comments) {
+  db_query('UPDATE {comments} SET status = '. COMMENT_NOT_PUBLISHED .' WHERE cid IN(%s)', implode(',', $comments));
+}
+
+/**
  * Menu callback; present an administrative comment listing.
  */
-function comment_admin($type = 'new') {
+function comment_admin() {
   $edit = $_POST;
 
   if (isset($edit['operation']) && ($edit['operation'] == 'delete') && $edit['comments']) {
     return drupal_get_form('comment_multiple_delete_confirm');
   }
   else {
-    return drupal_get_form('comment_admin_overview', $type, arg(4));
+    $output = drupal_get_form('comment_filter_form');
+    $output .= drupal_get_form('comment_admin_overview');
+    return $output;
   }
 }
 
-function comment_admin_overview($type = 'new', $arg) {
+function comment_admin_overview(&$form_state) {
   // build an 'Update options' form
   $form['options'] = array(
     '#type' => 'fieldset', '#title' => t('Update options'),
     '#prefix' => '<div class="container-inline">', '#suffix' => '</div>'
   );
   $options = array();
-  foreach (comment_operations($arg == 'approval' ? 'publish' : 'unpublish') as $key => $value) {
-    $options[$key] = $value[0];
+  foreach (module_invoke_all('comment_operations') as $operation => $array) {
+    $options[$operation] = $array['label'];
   }
   $form['options']['operation'] = array('#type' => 'select', '#options' => $options, '#default_value' => 'publish');
   $form['options']['submit'] = array('#type' => 'submit', '#value' => t('Update'));
 
-  // load the comments that we want to display
-  $status = ($type == 'approval') ? COMMENT_NOT_PUBLISHED : COMMENT_PUBLISHED;
   $form['header'] = array('#type' => 'value', '#value' => array(
     theme('table_select_header_cell'),
     array('data' => t('Subject'), 'field' => 'subject'),
     array('data' => t('Author'), 'field' => 'name'),
+    array('data' => t('Status'), 'field' => 'status'),
     array('data' => t('Time'), 'field' => 'timestamp', 'sort' => 'desc'),
     array('data' => t('Operations'))
   ));
-  $result = pager_query('SELECT c.subject, c.nid, c.cid, c.comment, c.timestamp, c.status, c.name, c.homepage, u.name AS registered_name, u.uid FROM {comments} c INNER JOIN {users} u ON u.uid = c.uid WHERE c.status = %d'. tablesort_sql($form['header']['#value']), 50, 0, NULL, $status);
+
+  $filter = comment_build_filter_query();
+  $sql = 'SELECT c.subject, c.nid, c.cid, c.comment, c.timestamp, c.status, c.name, c.homepage, u.name AS registered_name, u.uid FROM {comments} c INNER JOIN {users} u ON u.uid = c.uid'. $filter['where'];
+  $sql .= tablesort_sql($form['header']['#value']);
+  $result = pager_query($sql, 50, 0, NULL, $filter['args']);
 
   // build a table listing the appropriate comments
   $destination = drupal_get_destination();
+  $published = t('published');
+  $unpublished = t('not published');
   while ($comment = db_fetch_object($result)) {
     $comments[$comment->cid] = '';
     $comment->name = $comment->uid ? $comment->registered_name : $comment->name;
     $form['subject'][$comment->cid] = array('#value' => l($comment->subject, 'node/'. $comment->nid, array('title' => truncate_utf8($comment->comment, 128), 'fragment' => 'comment-'. $comment->cid)));
     $form['username'][$comment->cid] = array('#value' => theme('username', $comment));
+    $form['status'][$comment->cid] = array('#value' => $comment->status == COMMENT_PUBLISHED ? $published : $unpublished);
     $form['timestamp'][$comment->cid] = array('#value' => format_date($comment->timestamp, 'small'));
     $form['operations'][$comment->cid] = array('#value' => l(t('edit'), 'comment/edit/'. $comment->cid, array('query' => $destination)));
   }
@@ -1217,10 +1226,9 @@ function comment_admin_overview($type = 
  * We can't execute any 'Update options' if no comments were selected.
  */
 function comment_admin_overview_validate($form, &$form_state) {
-  $form_state['values']['comments'] = array_diff($form_state['values']['comments'], array(0));
-  if (count($form_state['values']['comments']) == 0) {
+  $comments = array_filter($form_state['values']['comments']);
+  if (count($comments) == 0) {
     form_set_error('', t('Please select one or more comments to perform the update on.'));
-    drupal_goto('admin/content/comment');
   }
 }
 
@@ -1229,25 +1237,32 @@ function comment_admin_overview_validate
  * publishing, unpublishing or deleting.
  */
 function comment_admin_overview_submit($form, &$form_state) {
-  $operations = comment_operations();
-  if ($operations[$form_state['values']['operation']][1]) {
-    // extract the appropriate database query operation
-    $query = $operations[$form_state['values']['operation']][1];
-    foreach ($form_state['values']['comments'] as $cid => $value) {
-      if ($value) {
-        // perform the update action, then refresh node statistics
-        db_query($query, $cid);
-        $comment = _comment_load($cid);
-        _comment_update_node_statistics($comment->nid);
-        // Allow modules to respond to the updating of a comment.
-        comment_invoke_comment($comment, $form_state['values']['operation']);
-        // Add an entry to the watchdog log.
-        watchdog('content', 'Comment: updated %subject.', array('%subject' => $comment->subject), WATCHDOG_NOTICE, l(t('view'), 'node/'. $comment->nid, array('fragment' => 'comment-'. $comment->cid)));
-      }
+  $operations = module_invoke_all('comment_operations');
+  $operation = $operations[$form_state['values']['operation']];
+  // Filter out unchecked comments.
+  $comments = array_filter($form_state['values']['comments']);
+  if ($function = $operation['callback']) {
+    // Add in callback arguments if present.
+    if (isset($operation['callback arguments'])) {
+      $args = array_merge(array($comments), $operation['callback arguments']);
+    }
+    else {
+      $args = array($comments);
     }
+    call_user_func_array($function, $args);
+
+    foreach ($comments as $cid) {
+      // Refresh node statistics
+      $comment = _comment_load($cid);
+      _comment_update_node_statistics($comment->nid);
+      // Allow modules to respond to the updating of a comment.
+      comment_invoke_comment($comment, $operation);
+      // Add an entry to the watchdog log.
+      watchdog('content', 'Comment: updated %subject.', array('%subject' => $comment->subject), WATCHDOG_NOTICE, l(t('view'), 'node/'. $comment->nid, array('fragment' => 'comment-'. $comment->cid)));
+    }
+
     cache_clear_all();
     drupal_set_message(t('The update has been performed.'));
-    drupal_goto('admin/content/comment');
   }
 }
 
@@ -1259,6 +1274,7 @@ function theme_comment_admin_overview($f
       $row[] = drupal_render($form['comments'][$key]);
       $row[] = drupal_render($form['subject'][$key]);
       $row[] = drupal_render($form['username'][$key]);
+      $row[] = drupal_render($form['status'][$key]);
       $row[] = drupal_render($form['timestamp'][$key]);
       $row[] = drupal_render($form['operations'][$key]);
       $rows[] = $row;
@@ -1359,6 +1375,198 @@ function comment_multiple_delete_confirm
 }
 
 /**
+ * List comment administration filters that can be applied.
+ */
+function comment_filters() {
+  // Regular filters
+  $filters = array();
+
+  if (user_access('access user profiles')) {
+    $filters['user'] = array(
+      'title' => t('author'),
+      'where' => "u.name = '%s'",
+      'join' => 'INNER JOIN {user} u ON u.uid = c.uid',
+      'options' => '',
+    );
+  }
+
+  $filters['status'] = array(
+    'title' => t('status'),
+    'where' => 'c.status = %d',
+    'join' => '',
+    'options' => array(COMMENT_PUBLISHED => t('published'), COMMENT_NOT_PUBLISHED => t('not published')),
+  );
+  return $filters;
+}
+
+/**
+ * Build query for comment administration filters based on session.
+ */
+function comment_build_filter_query() {
+  $filters = comment_filters();
+
+  // Build query
+  $where = $args = $join = array();
+  foreach ($_SESSION['comment_overview_filter'] as $filter) {
+    list($key, $value) = $filter;
+    $where[] = $filters[$key]['where'];
+    $args[] = $value;
+    $join[] = $filters[$key]['join'];
+  }
+  $where = !empty($where) ? ' WHERE '. implode(' AND ', $where) : '';
+  $join = !empty($join) ? ' '. implode(' ', array_unique($join)) : '';
+
+  return array('where' => $where,
+           'join' => $join,
+           'args' => $args,
+         );
+}
+
+/**
+ * Return form for comment administration filters.
+ */
+function comment_filter_form() {
+  $session = &$_SESSION['comment_overview_filter'];
+  $session = is_array($session) ? $session : array();
+  $filters = comment_filters();
+
+  $i = 0;
+  $form['filters'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Show only comments where'),
+    '#theme' => 'comment_filters',
+  );
+  foreach ($session as $filter) {
+    list($type, $value) = $filter;
+    // Special case for anonymous user filter
+    if ($type == 'user' && $value == '') {
+      $value = variable_get('anonymous', t('Anonymous'));
+    }
+    $string = ($i++ ? '<em>and</em> where <strong>%a</strong> is <strong>%b</strong>' : '<strong>%a</strong> is <strong>%b</strong>');
+    // Must build an options array on the fly for autocomplete fields.
+    $options = is_array($filters[$type]['options']) ? $filters[$type]['options'] : array($value => $value);
+    $form['filters']['current'][] = array('#value' => t($string, array('%a' => $filters[$type]['title'] , '%b' => $options[$value])));
+  }
+
+  foreach ($filters as $key => $filter) {
+    $names[$key] = $filter['title'];
+    if ($key == 'user') {
+      $form['filters']['status'][$key] = array(
+        '#type' => 'textfield',
+        '#size' => 30,
+        '#maxlength' => 60,
+        '#autocomplete_path' => 'user/autocomplete',
+      );
+    }
+    else {
+      $form['filters']['status'][$key] = array(
+        '#type' => 'select',
+        '#options' => $filter['options'],
+      );
+    }
+  }
+
+  $form['filters']['filter'] = array(
+    '#type' => 'radios',
+    '#options' => $names,
+  );
+  $form['filters']['buttons']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => (count($session) ? t('Refine') : t('Filter'))
+  );
+  if (count($session)) {
+    $form['filters']['buttons']['undo'] = array(
+      '#type' => 'submit',
+      '#value' => t('Undo')
+    );
+    $form['filters']['buttons']['reset'] = array(
+      '#type' => 'submit',
+      '#value' => t('Reset')
+    );
+  }
+
+  return $form;
+}
+
+/**
+ * Theme comment administration filter form.
+ */
+function theme_comment_filter_form($form) {
+  $output = '<div id="comment-admin-filter">';
+  $output .= drupal_render($form['filters']);
+  $output .= '</div>';
+  $output .= drupal_render($form);
+  return $output;
+}
+
+/**
+ * Theme comment administration filter selector.
+ */
+function theme_comment_filters($form) {
+  $output = '<ul class="clear-block">';
+  if (!empty($form['current'])) {
+    foreach (element_children($form['current']) as $key) {
+      $output .= '<li>'. drupal_render($form['current'][$key]) .'</li>';
+    }
+  }
+
+  $output .= '<li><dl class="multiselect">'. (!empty($form['current']) ? '<dt><em>'. t('and') .'</em> '. t('where') .'</dt>' : '') .'<dd class="a">';
+  foreach (element_children($form['filter']) as $key) {
+    $output .= drupal_render($form['filter'][$key]);
+  }
+  $output .= '</dd>';
+
+  $output .= '<dt>'. t('is') .'</dt><dd class="b">';
+
+  foreach (element_children($form['status']) as $key) {
+    $output .= drupal_render($form['status'][$key]);
+  }
+  $output .= '</dd>';
+
+  $output .= '</dl>';
+  $output .= '<div class="container-inline" id="comment-admin-buttons">'. drupal_render($form['buttons']) .'</div>';
+  $output .= '</li></ul>';
+
+  return $output;
+}
+
+/**
+ * Process result from comment administration filter form.
+ */
+function comment_filter_form_submit($form, &$form_state) {
+  $op = $form_state['values']['op'];
+  $filters = comment_filters();
+  switch ($op) {
+    case t('Filter'): case t('Refine'):
+      if (isset($form_state['values']['filter'])) {
+        $filter = $form_state['values']['filter'];
+        $value = $form_state['values'][$filter];
+        // Special case for filtering by anonymous user.
+        if ($filter == 'user' && $value == variable_get('anonymous', t('Anonymous'))) {
+          $value = '';
+        }
+        // Merge an array of arrays into one if necessary.
+        $options = is_array($filters[$filter]['options']) ? $filters[$filter]['options'] : array($value => $value);
+        if (isset($options[$value]) && isset($form_state['values'][$filter])) {
+          $_SESSION['comment_overview_filter'][] = array($filter, $value);
+        }
+      }
+      break;
+    case t('Undo'):
+      array_pop($_SESSION['comment_overview_filter']);
+      break;
+    case t('Reset'):
+      $_SESSION['comment_overview_filter'] = array();
+      break;
+    case t('Update'):
+      return;
+  }
+
+  $form_state['redirect'] = 'admin/content/comment';
+  return;
+}
+
+/**
 *** misc functions: helpers, privates, history
 **/
 
Index: modules/system/system.css
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.css,v
retrieving revision 1.32
diff -u -u -p -r1.32 system.css
--- modules/system/system.css	27 Jun 2007 17:54:49 -0000	1.32
+++ modules/system/system.css	28 Jun 2007 20:25:31 -0000
@@ -158,7 +158,6 @@ tr.merge-up, tr.merge-up td, tr.merge-up
 dl.multiselect dd.b, dl.multiselect dd.b .form-item, dl.multiselect dd.b select {
   font-family: inherit;
   font-size: inherit;
-  width: 14em;
 }
 dl.multiselect dd.a, dl.multiselect dd.a .form-item {
   width: 8em;
