Index: privatemsg.module
===================================================================
RCS file: /cvs/drupal/contributions/modules/privatemsg/privatemsg.module,v
retrieving revision 1.70.2.30.2.91.2.25
diff -u -p -r1.70.2.30.2.91.2.25 privatemsg.module
--- privatemsg.module	22 Feb 2009 21:21:08 -0000	1.70.2.30.2.91.2.25
+++ privatemsg.module	2 Mar 2009 22:24:16 -0000
@@ -654,7 +654,6 @@ function privatemsg_new(&$form_state, $a
 }
 
 function pm_send_validate($form, &$form_state) {
-//  drupal_set_message('<pre>'. print_r($form_state['values'], 1) . '</pre>');
   // The actual message that is being sent, we create this during validation and pass to submit to send out.
   $message = array();
 
@@ -698,27 +697,14 @@ function pm_send_validate($form, &$form_
       $invalid[$name] = $name;
     }
   }
-
-  // Verify that our recipients are valid.
-  /**
-   * VALIDATE NAMES
-   * 1) Make sure the name exists.
-   * 2) Make sure he accepts private messages.
-   * 3) Make sure the sender is not on block list of the recipient.
-   */
-  /**
-   * BUILD VALID RECIPIENT LIST
-   * 1) Names that were not valid from previous step will be stripped out.
-   * 2) Names that remain will be put into a recipients array.
-   */
-
-  $errors = _privatemsg_validate_message($message, $message['author'], TRUE);
-  if (!empty($errors)) {
-      foreach ($errors as $error) {
-        form_set_error('body', $error);
-      }
+  if (!empty($invalid)) {
+    drupal_set_message(t('The following recipients are invalid: @invalid', array('@invalid' => implode(", ", $invalid))), 'error');
   }
 
+  $validated = _privatemsg_validate_message($message, TRUE);
+  foreach ($validated['messages'] as $type => $text) {
+    drupal_set_message($text, $type);
+  }
   $form_state['validate_built_message'] = $message;
   if (!empty($invalid)) {
     drupal_set_message(t('The following users will not receive this private message: @invalid', array('@invalid' => implode(", ", $invalid))), 'error');
@@ -1137,33 +1123,38 @@ function privatemsg_delete_submit($form,
  *
  * This functions does send a message in a new thread.
  *
+ * @param array  $recipients Array of recipients (user objects)
  * @param string $subject    The subject of the new message
  * @param string $body       The body text of the new message
- * @param array  $recipients Array of recipients (user objects)
- * @param object $author     The author (user object, defaults to the current user)
+ * @param array  $options    Addition options, like author, timestamp
  *
  * @return boolean|array Either true or an array with validation errors
  */
-function privatemsg_new_thread($subject, $body, $recipients, $author = NULL) {
-  if ($author == NULL) {
-    global $user;
-    $author = drupal_clone($user);
-  }
+function privatemsg_new_thread($recipients, $subject, $body = NULL, $options = array()) {
+  global $user;
+  $author = drupal_clone($user);
 
   $message = array();
   $message['subject'] = $subject;
-  $message['author'] = $author;
   $message['body'] = $body;
-  $message['timestamp'] = time();
   $message['recipients'] = $recipients;
 
-  $errors = _privatemsg_validate_message($message, $author);
-  if (!empty($errors)) {
-    return $errors;
-  }
-  else {
-    return _privatemsg_send($message);
+  // set custom options, if any
+  if (!empty($options)) {
+    $message += $options;
+  }
+  // apply defaults
+  $message += array(
+    'author' => $author,
+    'timestamp' => time(),
+  );
+
+  $validated = _privatemsg_validate_message($message);
+  if ($validated['success']) {
+    $validated['success'] = _privatemsg_send($message);
   }
+
+  return $validated;
 }
 /**
  * Send a reply message
@@ -1172,25 +1163,30 @@ function privatemsg_new_thread($subject,
  *
  * @param int    $thread_id Thread id
  * @param string $body      The body text of the new message
- * @param string $author    The author (user object, defaults to the current user)
+ * @param array  $options    Addition options, like author, timestamp
  *
  * @return boolean|array Either true or an array with validation errors
  */
-function privatemsg_reply($thread_id, $body, $author = NULL) {
-  if ($author == NULL) {
-    global $user;
-    $author = drupal_clone($user);
-  }
+function privatemsg_reply($thread_id, $body = NULL, $options = array()) {
+  global $user;
+  $author = drupal_clone($user);
 
   $message = array();
-  $message['author'] = $author;
   $message['body'] = $body;
-  $message['timestamp'] = time();
-  $message['thread_id'] = $thread_id;
+
+  // set custom options, if any
+  if (!empty($options)) {
+    $message += $options;
+  }
+  // apply defaults
+  $message += array(
+    'author' => $author,
+    'timestamp' => time(),
+  );
 
   // We don't know the subject and the recipients, so we need to load them..
   // thread_id == mid on the first message of the thread
-  $first_message = _privatemsg_load($thread_id, $author);
+  $first_message = _privatemsg_load($thread_id, $message['author']);
   if (!$first_message) {
     return array(t('Thread %thread_id not found, unable to answer', array('%thread_id' => $thread_id)));
   }
@@ -1205,51 +1201,77 @@ function privatemsg_reply($thread_id, $b
 
   $message['subject'] = $first_message['subject'];
 
-  $errors = _privatemsg_validate_message($message, $author);
-  if (!empty($errors)) {
-    return $errors;
-  }
-  else {
-    return _privatemsg_send($message);
+  $validated = _privatemsg_validate_message($message);
+  if ($validated['success']) {
+    $validated['success'] = _privatemsg_send($message);
   }
+  return $validated;
 }
 
-function _privatemsg_validate_message(&$message, $author, $show_warnings = FALSE) {
-
-  $errors = array();
-  if (!privatemsg_user_access('write privatemsg', $author)) {
+function _privatemsg_validate_message(&$message, $form = FALSE) {
+  $messages = array('error' => array(), 'warning' => array());
+  if (!privatemsg_user_access('write privatemsg', $message['author'])) {
     // no need to do further checks in this case...
-    return array(t('User @user is not allowed to write messages', array('@user' => $author->name)));
+    if ($form) {
+      form_set_error('author', t('User @user is not allowed to write messages', array('@user' => $message['author']->name)));
+      return array(
+        'success'  => FALSE,
+        'messages'   => $messages,
+      );
+    }
+    else {
+      $messages['error'][] = t('User @user is not allowed to write messages', array('@user' => $message['author']->name));
+      return array(
+         'success'  => FALSE,
+         'messages'   => $messages,
+      );
+    }
   }
 
   if (empty($message['subject'])) {
-    $errors[] = t('Disallowed to send a message without subject');
+    if ($form) {
+      form_set_error('subject', t('Disallowed to send a message without subject'));
+    }
+    else {
+      $messages['error'][] = t('Disallowed to send a message without subject');
+    }
   }
 
   if (empty($message['recipients']) || !is_array($message['recipients'])) {
-    $errors[] = t('Disallowed to send a message without atleast one recipient');
+    if ($form) {
+      form_set_error('to', t('Disallowed to send a message without atleast one valid recipient'));
+    }
+    else {
+      $messages['error'][] = t('Disallowed to send a message without atleast one valid recipient');
+    }
   }
 
   if (!empty($message['recipients']) && is_array($message['recipients'])) {
     foreach ($message['recipients'] as $uid => $recipient) {
-      $block_results = module_invoke_all('privatemsg_block_message', $author, $recipient);
+      $block_results = module_invoke_all('privatemsg_block_message', $message['author'], $recipient);
       if (count($block_results) > 0) {
         unset($message['recipients'][$uid]);
-        if ($show_warnings) {
-          foreach ($block_results as $block_result) {
-            drupal_set_message($block_result);
-          }
-        }
+        $messages['warning'] += $block_results;
       }
     }
   }
 
   // Check again, give another error message if all recipients are blocked
   if (empty($message['recipients'])) {
-    $errors[] = t('Disallowed to send message because all recipients are blocked');
+    if ($form) {
+      form_set_error('to', t('Disallowed to send message because all recipients are blocked'));
+    }
+    else {
+      $messages['error'][] = t('Disallowed to send message because all recipients are blocked');
+    }
   }
 
-  return $errors += module_invoke_all('privatemsg_message_validate', $message);
+  $messages += module_invoke_all('privatemsg_message_validate', $message, $form);
+  $success = empty($messages['error']);
+  return array(
+    'success'  => $success,
+    'messages'   => $messages,
+  );
 }
 
 function _privatemsg_send($message) {
Index: tests/privatemsgapi.test
===================================================================
RCS file: tests/privatemsgapi.test
diff -N tests/privatemsgapi.test
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/privatemsgapi.test	2 Mar 2009 22:24:16 -0000
@@ -0,0 +1,103 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Privatemsg API tests
+ */
+
+class PrivatemsgAPITestCase extends DrupalWebTestCase {
+  /**
+   * Implementation of getInfo().
+   */
+  function getInfo() {
+    return array(
+      // 'name' should start with what is being tested (menu item) followed by what about it
+      // is being tested (creation/deletion).
+      'name' => t('Privatemsg API functionality.'),
+      // 'description' should be one or more complete sentences that provide more details on what
+      // exactly is being tested.
+      'description' => t('Test sending, receiving, listing, deleting messages and other features via API.'),
+      // 'group' should be a logical grouping of test cases, like a category.  In most cases, that
+      // is the module the test case is for.
+      'group' => t('Privatemsg'),
+    );
+  }
+
+  /**
+   * Implementation of setUp().
+   */
+  function setUp() {
+    parent::setUp('privatemsg');
+  }
+
+  function testPrivatemsgApiNewThread() {
+    $author     = $this->drupalCreateUser(array('write privatemsg'));
+    $recipient1  = $this->drupalCreateUser(array('read privatemsg'));
+    $recipient2  = $this->drupalCreateUser(array('read privatemsg'));
+    $recipient3  = $this->drupalCreateUser(array('read privatemsg'));
+
+    // Reset user_access cache
+    user_access('', $author, TRUE);
+
+    $resultok1 = privatemsg_new_thread(array($recipient1, $recipient2, $recipient3), 'normal message', 'Body text', array('author' => $author));
+    $this->assertTrue($resultok1['success'], 'Private message could be sent successfully');
+
+    $message = $this->getMessageFromSubject('normal message');
+    $this->assertFalse(empty($message), 'Message was saved in database');
+    $this->assertEqual($message['author'], $author->uid, 'Message was sent by author');
+
+    $resultok2 = privatemsg_new_thread(array($recipient1, $recipient2, $recipient3), 'empty body', '', array('author' => $author));
+    $this->assertTrue($resultok2['success'], 'API allowed to send message without body');
+
+    $resultf1 = privatemsg_new_thread(array($recipient1, $recipient2, $recipient3), '', 'No subject', array('author' => $author));
+    $this->assertEqual('Disallowed to send a message without subject', $resultf1['messages']['error'][0], 'API denied to send message without subject');
+
+    $resultf2 = privatemsg_new_thread(array(), 'no recipients', 'Body text', array('author' => $author));
+    $this->assertEqual('Disallowed to send a message without atleast one valid recipient', $resultf2['messages']['error'][0], 'API denied to send message without recipients');
+    $message = $this->getMessageFromSubject('no recipients');
+    $this->assertTrue(empty($message), 'Message was not saved in database');
+
+    $resultf3 = privatemsg_new_thread(array($recipient1, $recipient2, $recipient3), 'not allowed', 'Body text', array('author' => $recipient1));
+    $errormessage = 'User '. $recipient1->name .' is not allowed to write messages';
+    $this->assertEqual($errormessage, $resultf3['messages']['error'][0], 'API denied to send message from user without permission');
+    $message = $this->getMessageFromSubject('not allowed');
+    $this->assertTrue(empty($message), 'Message was not saved in database');
+
+  }
+
+  function getMessageFromSubject($subject) {
+    $result = db_query("SELECT * FROM {pm_message} WHERE subject = '%s'", $subject);
+    return db_fetch_array($result);
+  }
+
+  function testPrivatemsgApiReply() {
+    $author     = $this->drupalCreateUser(array('write privatemsg'));
+    $recipient1  = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg'));
+    $recipient2  = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg'));
+    $recipient3  = $this->drupalCreateUser(array('read privatemsg'));
+
+    // Reset user_access cache
+    user_access('', $author, TRUE);
+
+    $resultok = privatemsg_new_thread( array($recipient2, $recipient1, $recipient3), 'test reply', 'body text', array('author' => $author));
+    $this->assertTrue($resultok['success'], 'Private message could be sent successfully');
+
+    $thread_row = $this->getMessageFromSubject('test reply');
+
+    $resultok = privatemsg_reply($thread_row['mid'], 'Test Body', array('author' => $author));
+    $this->assertTrue($resultok['success'], 'Reply could be sent successfully');
+
+    $resultok = privatemsg_reply($thread_row['mid'], 'Test Body', array('author' => $recipient1));
+    $this->assertTrue($resultok['success'], 'Reply could be sent successfully');
+
+    $resultok = privatemsg_reply($thread_row['mid'], '', array('author' => $recipient2));
+    $this->assertTrue($resultok['success'], 'API allowed to send message without body');
+
+    $resultf2 = privatemsg_reply($thread_row['mid'], 'Test Body', array('author' => $recipient3));
+    $errormessage = 'User '. $recipient3->name .' is not allowed to write messages';
+    $this->assertEqual($errormessage, $resultf2['messages']['error'][0], 'API denied to send message from user without permission');
+
+  }
+}
+?>
