Index: pmgrowl.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/pmgrowl/pmgrowl.module,v
retrieving revision 1.7
diff -u -p -r1.7 pmgrowl.module
--- pmgrowl.module	17 Jun 2009 00:25:35 -0000	1.7
+++ pmgrowl.module	24 Nov 2009 22:36:52 -0000
@@ -15,7 +15,7 @@ function pmgrowl_init() {
     drupal_add_css(drupal_get_path('module', 'pmgrowl') .'/jgrowl/jquery.jgrowl.css');
     drupal_add_js(drupal_get_path('module', 'pmgrowl') .'/jgrowl/jquery.jgrowl_minimized.js', 'footer');
     drupal_add_js(drupal_get_path('module', 'pmgrowl') .'/pmgrowl.js', 'footer');
-  
+
     // Pass in the interval for checking messages. Multiply by 1000 to move to milliseconds instead of seconds
     drupal_add_js(array('pmGrowlInterval' => variable_get('pmgrowl_interval', 30) * 1000), 'setting');
   }
@@ -26,24 +26,24 @@ function pmgrowl_init() {
  */
 function pmgrowl_menu() {
   $items['admin/settings/messages/pmgrowl'] = array(
-      'title' => 'Growl notifications',
-      'description' => 'Change the notification settings for private message alerts',
-      'page callback' => 'drupal_get_form',
-      'page arguments' => array('pmgrowl_admin_settings'),
-      'access arguments' => array('administer site configuration'),
-      'type' => MENU_LOCAL_TASK,
-      );
+    'title' => 'Growl notifications',
+    'description' => 'Change the notification settings for private message alerts',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('pmgrowl_admin_settings'),
+    'access arguments' => array('administer site configuration'),
+    'type' => MENU_LOCAL_TASK,
+  );
   $items['messages/pmgrowl_json'] = array(
-      'access callback' => 'user_access',
-      'access arguments' => array('read privatemsg'),
-      'page callback' => 'pmgrowl_json',
-      'type' => MENU_CALLBACK,
-      );
+    'access callback' => 'user_access',
+    'access arguments' => array('read privatemsg'),
+    'page callback' => 'pmgrowl_json',
+    'type' => MENU_CALLBACK,
+  );
   $items['messages/pmgrowl_close'] = array(
-      'page callback' => 'pmgrowl_close',
-      'access callback' => TRUE,
-      'type' => MENU_CALLBACK,
-      );
+    'page callback' => 'pmgrowl_close',
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
+  );
   return $items;
 }
 
@@ -53,24 +53,86 @@ function pmgrowl_menu() {
 function pmgrowl_close() {
   global $user;
 
-  if(variable_get('pmgrowl_operating_mode', 0) == 0) {
-    // build a record to write to the database to signify this message has been closed by the user
-    $table = 'pmgrowl_close';
-    $record = new stdClass();
-    $record->mid = $_POST['mid'];
-    $record->uid = $user->uid;
-    $record->closed = 1;
-
-    if(drupal_write_record($table, $record)) {
-      echo 'message closed';
-    } else {
-      echo 'ERROR: unable to close message';
+  pmgrowl_close_message($user->uid, $_POST['mid']);
+}
+
+/**
+ * Mark a message as closed.
+ *
+ * @param $uid
+ *   User id of the user for which the message should be closed.
+ * @param $mid
+ *   Message id that should be closed.
+ */
+function pmgrowl_close_message($uid, $mid = NULL) {
+  // Build a record containing the generic information.
+  $table = 'pmgrowl_close';
+  $record = new stdClass();
+  $record->uid = $uid;
+  $record->closed = 1;
+
+  if (variable_get('pmgrowl_operating_mode', 0) == 0 && $mid) {
+    // Check if the record has not been entered. Avoid duplicate key errors.
+    $sql = "SELECT 1 FROM {pmgrowl_close} WHERE mid = %d AND uid = %d";
+    if (!db_result(db_query($sql, $mid, $uid))) {
+      // Add mid to the record and store
+      $record->mid = $mid;
+      return drupal_write_record($table, $record);
     }
-  } else {
-    db_query("UPDATE {pmgrowl_close} SET closed = 1 WHERE uid = %s", $user->uid);
   }
+  else {
+    // Check if there is already an entry for the active user.
+    $sql = "SELECT 1 FROM {pmgrowl_close} WHERE uid = %d";
+    if (db_result(db_query($sql, $uid))) {
+      // Update existing entry.
+      drupal_write_record($table, $record, 'uid');
+    }
+    else {
+      // Update existing entry.
+      drupal_write_record($table, $record);
+    }
+  }
+}
 
-  exit();
+/**
+ * Query function to build a query that can be extended/altered.
+ *
+ * @param $fragments
+ *   Query fragment array.
+ * @param $account
+ *   User account for which the messages are loaded.
+ */
+function pmgrowl_sql_unclosed(&$fragments, $account) {
+  // Set the primary table.
+  $fragments['primary_table'] = '{pm_index} pmi';
+
+  // Add all necessary fields.
+  $fragments['select']['thread_id'] = 'pmi.thread_id';
+  $fragments['select']['mid'] = 'pmi.mid';
+  $fragments['select']['subject'] = 'pm.subject';
+  $fragments['select']['body'] = 'pm.body';
+  $fragments['select']['format'] = 'pm.format';
+
+  // Add join to {pm_message}
+  $fragments['inner_join']['pm_message'] = 'INNER JOIN {pm_message} pm ON (pmi.mid = pm.mid)';
+
+  // Select only messages of the current user.
+  $fragments['where'][] = 'pmi.uid = %d';
+  $fragments['query_args']['where'][] = $account->uid;
+
+  // Select only new messages that are not deleted.
+  $fragments['where'][] = 'pmi.is_new = 1';
+  $fragments['where'][] = 'pmi.deleted = 0';
+
+  // Select only messages that are not already closed.
+  $fragments['where'][] = 'pmi.mid NOT IN (SELECT mid FROM {pmgrowl_close} WHERE uid = %d AND closed = 1)';
+  $fragments['query_args']['where'][] = $account->uid;
+
+  // Sometimes recipients are listed more than once, group by mid.
+  $fragements['group_by'][] = 'pmi.mid';
+
+  // Sort by timestamp.
+  $fragements['order_by'][] = 'pm.timestamp ASC';
 }
 
 /**
@@ -79,36 +141,36 @@ function pmgrowl_close() {
 function pmgrowl_json() {
   global $user;
 
-  // This query collects all messages that are new, and have not been closed
-  $query = 'SELECT * FROM {pm_index} i LEFT JOIN {pm_message} m ON m.mid = i.mid ';
-  $query .= 'WHERE (i.uid = %d AND i.is_new = 1) AND i.mid NOT IN (SELECT mid FROM {pmgrowl_close} WHERE uid = %d and closed = 1) ';
-  $query .= 'ORDER BY m.timestamp ASC';
-
-  $result = db_query($query, $user->uid, $user->uid);
-
-  $data = array();
-
-  // for every message that comes back
-  while ($row = db_fetch_object($result)) {
-    // check the operating mode, and return a message accordingly
-    if(variable_get('pmgrowl_operating_mode', 0) == 0) {
-        $row->body = check_markup(truncate_utf8($row->body, 400, FALSE, TRUE));
-        $row->body .= '<p>'. l(t('Open & Reply'), 'messages/view/'. $row->thread_id);
-        $row->body .= ' | '. l(t('View All'), 'messages') .'</p>';
-        $data[] = $row;
-    } else {
-      $message['subject'] = 'You have Mail!';
-      $message['body'] = 'You have '. l(t('unread messages'), 'messages');
+  // Check the operating mode, and return a message accordingly.
+  if (variable_get('pmgrowl_operating_mode', 0) == 0) {
+    // Assemble the query to load the messages.
+    $query = _privatemsg_assemble_query(array('unclosed', 'pmgrowl'), $user);
+    $result = db_query($query['query']);
+    $data = array();
+
+    while ($row = db_fetch_object($result)) {
+      $row->body = check_markup(truncate_utf8($row->body, 400, FALSE, TRUE), $row->format, FALSE);
+      $row->body .= '<p>' . l(t('Open & Reply'), 'messages/view/' . $row->thread_id, array('fragment' => 'new'));
+      $row->body .= ' | ' . l(t('View All'), 'messages') .'</p>';
+      $data[] = $row;
+
+      // If auto-close is enabled, mark messages as closed.
+      if (variable_get('pmgrowl_persistence', 0) == 0) {
+        pmgrowl_close_message($user->uid, $row->mid);
+      }
+    }
+  }
+  else {
+    if ($unread = privatemsg_unread_count()) {
+      $message['subject'] = t('You have mail!');
+      $message['body'] = '<p>' . t('You have received a !received_messages_link!', array('!received_messages_link' => l(t('new message'), 'messages'))) . '</p>';
+      $message['body'] .= '<p>' . t('You have @unread_message_count @unread_messages.', array('@unread_message_count' => $unread, '@unread_messages' => format_plural($unread, 'unread message', 'unread messages'))) . '</p>';
       $data[0] = $message;
 
-      // now mark all of these messages as closed so that there isn't a popup on subsequent messages
+      // If auto-close is enabled, mark all messages as closed.
+      // @todo: This does not have any effect.
       if (variable_get('pmgrowl_persistence', 0) == 0) {
-        $table = 'pmgrowl_close';
-        $record = new stdClass();
-        $record->mid = $row->mid;
-        $record->uid = $row->uid;
-        $record->closed = 1;
-        drupal_write_record($table, $record);
+        pmgrowl_close_message($user->uid);
       }
     }
   }
@@ -124,25 +186,25 @@ function pmgrowl_json() {
  */
 function pmgrowl_admin_settings() {
   $form['pmgrowl_interval'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Check message interval'),
-      '#default_value' => variable_get('pmgrowl_interval', 30),
-      '#description' => t('Choose the number of seconds between checks for new messages. Set this to 0 if you only want to check for new messages when the page first loads.'),
-      );
+    '#type' => 'textfield',
+    '#title' => t('Check message interval'),
+    '#default_value' => variable_get('pmgrowl_interval', 30),
+    '#description' => t('Choose the number of seconds between checks for new messages. Set this to 0 if you only want to check for new messages when the page first loads.'),
+  );
   $form['pmgrowl_operating_mode'] = array(
-      '#type' => 'radios',
-      '#default_value' => variable_get('pmgrowl_operating_mode', 0),
-      '#options' => array(t('Individual Messages'), t('New Message alert')),
-      '#title' => t('Operating Mode'),
-      '#description' => t('Choose the way messages should be alerted. Individual Messages mode will give you every new message that comes in. New Message alert will just give a notification that there are new messages.'),
-      );
+    '#type' => 'radios',
+    '#default_value' => variable_get('pmgrowl_operating_mode', 0),
+    '#options' => array(t('Individual Messages'), t('New Message alert')),
+    '#title' => t('Operating Mode'),
+    '#description' => t('Choose the way messages should be alerted. Individual Messages mode will give you every new message that comes in. New Message alert will just give a notification that there are new messages.'),
+  );
   $form['pmgrowl_persistence'] = array(
-      '#type' => 'radios',
-      '#default_value' => variable_get('pmgrowl_persistence', 0),
-      '#options' => array(t('One time'), t('Close manually')),
-      '#title' => t('Message persistence'),
-      '#description' => t('<em>This setting only applies to Operating mode "New Message alert".</em> If you choose "One time", then the message will appear only once. "Close manually" means that the message will continue to appear every time a page is loaded until the user closes it themselves.'),
-      );
+    '#type' => 'radios',
+    '#default_value' => variable_get('pmgrowl_persistence', 0),
+    '#options' => array(t('One time'), t('Close manually')),
+    '#title' => t('Message persistence'),
+    '#description' => t('<em>This setting only applies to Operating mode "New Message alert".</em> If you choose "One time", then the message will appear only once. "Close manually" means that the message will continue to appear every time a page is loaded until the user closes it themselves.'),
+  );
 
   return system_settings_form($form);
 }
