Index: send.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/send/send.inc,v
retrieving revision 1.9.2.4
diff -u -r1.9.2.4 send.inc
--- send.inc	12 Feb 2007 06:05:12 -0000	1.9.2.4
+++ send.inc	10 Oct 2007 06:12:58 -0000
@@ -11,6 +11,14 @@
     '#title'         => t('Allow visitors to send full item text'),
     '#default_value' => _send_value('fulltext', $module, $nodetype, $node),
   );
+  $form["{$module}{$type}_multipleaddresses"] = array (
+    '#type'          => 'textfield',
+    '#title'         => t('Maximum number of \'to\' addresses'),
+    '#default_value' => _send_value('multipleaddresses', $module, $nodetype, $node),
+    '#size'          => 30,
+    '#maxsize'       => 100,
+    '#description'   => t('Leave blank to allow only a single \'to\' address'),
+  );
   $form["{$module}{$type}_linktext"] = array(
     '#type'          => 'textfield',
     '#title'         => t("Link text"),
@@ -277,25 +285,37 @@
     '#default_value' => 0,
   );
   $form['to'] = array();
-  $form['to']['recipient_mail'] = array(
-    '#type'          => 'textfield',
-    '#title'         => t('Email'),
-    '#required'      => true,
-    '#size'          => 30,
-    '#maxsize'       => 100,
-  );
-  $form['to']['recipient_first_name'] = array(
-    '#type'          => 'textfield',
-    '#title'         => t('First Name'),
-    '#size'          => 30,
-    '#maxsize'       => 100,
-  );
-  $form['to']['recipient_last_name'] = array(
-    '#type'          => 'textfield',
-    '#title'         => t('Last Name'),
-    '#size'          => 30,
-    '#maxsize'       => 100,
-  );
+  if (_send_value('multipleaddresses', $module, $type, $node) > 1) {
+    $form['to']['recipient_multi'] = array(
+      '#type'          => 'textarea',
+      '#title'         => t('Email Addresses'),
+      '#required'      => true,
+      '#cols'          => 70,
+      '#rows'          => 10,
+      '#description'   => t('You can enter multiple e-mail addresses separated by commas or one per line. If you use the format <em>Firstname Lastname &lt;email@example.com&gt;</em> your e-mails will be addressed correctly.'),
+    );
+  }
+  else {
+    $form['to']['recipient_mail'] = array(
+      '#type'          => 'textfield',
+      '#title'         => t('Email'),
+      '#required'      => true,
+      '#size'          => 30,
+      '#maxsize'       => 100,
+    );
+    $form['to']['recipient_first_name'] = array(
+      '#type'          => 'textfield',
+      '#title'         => t('First Name'),
+      '#size'          => 30,
+      '#maxsize'       => 100,
+    );
+    $form['to']['recipient_last_name'] = array(
+      '#type'          => 'textfield',
+      '#title'         => t('Last Name'),
+      '#size'          => 30,
+      '#maxsize'       => 100,
+    );
+  }
   
   $subject = _send_value('subject', $module, $type, $node);
   $form['subject'] = array();
@@ -347,9 +367,10 @@
 
   // These values will be computed during the validate phase
   $form['values'] = array(
-    'body'   => array('#type' => 'value', '#value' => ''),
-    'sender' => array('#type' => 'value', '#value' => ''),
-    'sid'    => array('#type' => 'value', '#value' => ''),
+    'body'          => array('#type' => 'value', '#value' => ''),
+    'sender'        => array('#type' => 'value', '#value' => ''),
+    'sid'           => array('#type' => 'value', '#value' => ''),
+    'recipients'    => array('#type' => 'value', '#value' => ''),
   );
   
   $form['buttons'] = array();
@@ -359,7 +380,7 @@
   return $form;
 }
 
-function _send_form_prepare($values, $form) {
+function _send_form_prepare(&$values, $form) {
   $module  = $values['module'];
   $mail    = $values['sender_mail'];
   $first_name = $values['sender_first_name'];
@@ -375,8 +396,73 @@
   if (!$body = theme("{$module}_body", $values)) {
     $body = theme('send_body', $values);
   }
-  form_set_value($form['values']['body'], $body);
-  
+  form_set_value($form['values']['body'], $body); // Stored for _submit
+
+  $recipients = array();
+
+  // recipients are from a single textfield
+  if(isset($values['recipient_mail'])) {
+  	$recipients[] = array('mail' => $values['recipient_mail']);
+  }
+
+  // Recipients are from a comma/line-delimited textarea
+  if (isset($values['recipient_multi'])) {
+    $recipients = array();
+    // Split at anything that looks even remotely like an e-mail address
+    // (basically an '@' with at least one letter either side), capturing the
+    // e-mail address 'delimiter'. Using an e-mail address as a delimiter
+    // means that people can mix and match commas, newlines or even nothing
+    // as separators. We don't validate now, that is done in _send_form_validate().
+    $candidates = preg_split('/([A-Z0-9._%-]+@[A-Z0-9.-]+)/i', $values['recipient_multi'], -1, PREG_SPLIT_DELIM_CAPTURE);
+    $count = count($candidates);
+    // Even numbers are names, odd numbers are e-mail addresses 
+    for ($i = 0; $i <= $count; $i = $i+2) {
+      $recipient = array();
+      $mail = $candidates[$i+1];
+      // Trim any delimiter like characters and remove any newlines
+      $name = str_replace(array("\r\n", "\n", "\r"), '', trim($candidates[$i], " ,;<>"));
+
+      // Pull out some sensible first/last names
+      if (strpos($name, ',') === false) {
+        // First then last format: Joe Alex Blow
+        // Split at the last space, so middle names are grouped with the first name not the last
+        $pos = strrpos($name, ' ')+1;
+        $names = array();
+        $names[] = substr($name, 0, $pos);
+        $names[] = substr($name, $pos);
+      }
+      else {
+        // Last then first format: Blow, Joe Alex
+        // Here we assume the last name is always before the comma, so explode works nicely
+        $names = explode(',', $name, 2);
+        $names = array_reverse($names);
+      }
+
+      // Store the result
+      if (!empty($mail)) {
+        $recipient['mail'] = $mail;
+        $recipient['first_name'] = trim($names[0], " ,;<>");
+        $recipient['last_name'] = trim($names[1], " ,;<>");
+        $recipients[] = $recipient;
+      }
+    }
+  }
+
+  // Recipients expanded into separate form fields
+  // e.g. recipient1_first_name, recipient2_mail,  and so-on
+  if(!count($recipients)) {
+    foreach ($values as $key => $value) {
+      if ($key != ($name = preg_replace('/^recipient(\d*)_/', '\1 ', $key))) {
+        list($i, $name) = explode(' ', $name);
+        if (!$i) $i = 1;
+        $i--;
+        if (!isset($recipients[$i])) $recipients[$i] = array();
+        $recipients[$i][$name] = $value;
+      }
+    }
+  }
+  $values['recipients'] = $recipients; // Returned to validation
+  form_set_value($form['values']['recipients'], $recipients); // Stored for _submit
 }
 
 function _send_form_validate($form_id, $values, $form) {
@@ -387,11 +473,29 @@
     form_set_error('sender_mail',t('Invalid from address'));
     $ret = false;
   }
-    
-  if(isset($values['recipient_mail']) && !valid_email_address($values['recipient_mail'])) {
-    form_set_error('recipient_mail',t('Invalid recipient address'));
-    $ret = false;
+
+  foreach ($values['recipients'] as $recipient) {
+    if (!valid_email_address($recipient['mail'])) {
+      if ($form['to']['recipient_mail']) {
+        form_set_error('recipient_mail',t('Invalid recipient address:') . check_plain($recipient['mail']));
+      }
+      else {
+        form_set_error('recipient_multi',t('Invalid recipient address:') . check_plain($recipient['mail']));
+      }
+      // TODO: Correctly mark field when recipients expanded into separate form fields (recipient1_first_name etc).
+      $ret = false;
+    }
   }
+
+  // Check that the number of addresses is within the configured limit
+  $module  = $values['module'];
+  $node = count($values['nids']) ? node_load($values['nids'][0]) : null;
+  $type = $node->type;
+  $max = _send_value('multipleaddresses', $module, $type, $node);
+  if (count($values['recipients']) > $max) {
+    form_set_error('recipient_multi',t('Too many recipient addresses - the maximum number of addresses is @max.', array('@max' => $max)));
+  }
+  
   return $ret;
 }
 
@@ -432,43 +536,13 @@
   if(!$deliver = module_invoke($module, 'send', 'deliver', $module)) {
     $deliver = module_invoke('send', 'send', 'deliver','send');
   }
-  
-  $recipients = array();
-  // recipients are from a space/line-delimited textarea
-  if (isset($values['recipients'])) {
-    if (!is_array($recipients = $values['recipients'])) {
-      $recipients = array();
-      foreach (explode(',', preg_replace(array("/\s/ms","/,+/"), ',',$values['recipients'])) as $r) {
-        if (valid_email_address($r)) {
-          $recipients[] = array('mail' => $r);
-        }
-        else {
-          $recipients[] = $r;
-        }
-      }
-    }
-  }
-  
-  // recipients expanded into separate form fields
-  // e.g. recipient1_first_name, recipient2_mail,  and so-on
-  if(!count($recipients)) {
-    foreach ($values as $key => $value) {
-      if ($key != ($name = preg_replace('/^recipient(\d*)_/', '\1 ', $key))) {
-        list($i, $name) = explode(' ', $name);
-        if (!$i) $i = 1;
-        $i--;
-        if (!isset($recipients[$i])) $recipients[$i] = array();
-        $recipients[$i][$name] = $value;
-      }
-    }
-  }
 
   // recipient type - for now, 'node' or 'user'
   ($rtype = module_invoke($module, 'send', 'recipient type', $module))
     || ($rtype = module_invoke('send', 'send', 'recipient type', $module));
   
   $ret = true;
-  foreach ($recipients as $r) {
+  foreach ($values['recipients'] as $r) {
     $rid = 0;
 
     switch ($rtype) {
Index: send.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/send/send.module,v
retrieving revision 1.28.2.4
diff -u -r1.28.2.4 send.module
--- send.module	12 Feb 2007 06:05:12 -0000	1.28.2.4
+++ send.module	10 Oct 2007 06:12:58 -0000
@@ -217,7 +217,10 @@
       
     case 'querystring':          // callback that will return name=>value array for return links
       return;
-      
+
+    case 'multiple_addresses':   // callback that returns if multiple 'to' addresses are allowed
+      return;
+
     case 'deliver':              // callback to send the message
       return '_send_deliver';
       
