alecpl
2010-10-07 f22ea7ba1875863890b486db3e5f448f99c1debc
- Support SMTP Delivery Status Notifications - RFC3461 (#1486142)


14 files modified
113 ■■■■ changed files
CHANGELOG 1 ●●●● patch | view | raw | blame | history
config/main.inc.php.dist 19 ●●●●● patch | view | raw | blame | history
program/include/rcube_message.php 4 ●●●● patch | view | raw | blame | history
program/include/rcube_smtp.php 33 ●●●●● patch | view | raw | blame | history
program/localization/en_US/labels.inc 2 ●●●●● patch | view | raw | blame | history
program/localization/en_US/messages.inc 1 ●●●● patch | view | raw | blame | history
program/localization/pl_PL/labels.inc 2 ●●●●● patch | view | raw | blame | history
program/localization/pl_PL/messages.inc 1 ●●●● patch | view | raw | blame | history
program/steps/mail/compose.inc 23 ●●●●● patch | view | raw | blame | history
program/steps/mail/func.inc 5 ●●●●● patch | view | raw | blame | history
program/steps/mail/sendmail.inc 8 ●●●● patch | view | raw | blame | history
program/steps/settings/func.inc 10 ●●●●● patch | view | raw | blame | history
program/steps/settings/save_prefs.inc 1 ●●●● patch | view | raw | blame | history
skins/default/templates/compose.html 3 ●●●●● patch | view | raw | blame | history
CHANGELOG
@@ -21,6 +21,7 @@
- Add unique index on users.username+users.mail_host
- Make htmleditor option more consistent and add option to use HTML on reply to HTML message (#1485840)
- Use empty envelope sender address for message disposition notifications (RFC2298.3)
- Support SMTP Delivery Status Notifications - RFC3461 (#1486142)
RELEASE 0.4.2
-------------
config/main.inc.php.dist
@@ -334,12 +334,6 @@
// if in your system 0 quota means no limit set this option to true 
$rcmail_config['quota_zero_as_unlimited'] = false;
// Behavior if a received message requests a message delivery notification (read receipt)
// 0 = ask the user, 1 = send automatically, 2 = ignore (never send or ask)
// 3 = send automatically if sender is in addressbook, otherwise ask the user
// 4 = send automatically if sender is in addressbook, otherwise ignore
$rcmail_config['mdn_requests'] = 0;
// Make use of the built-in spell checker. It is based on GoogieSpell.
// Since Google only accepts connections over https your PHP installatation
// requires to be compiled with Open SSL support
@@ -571,5 +565,16 @@
// when user is over quota and Trash is included in the quota.
$rcmail_config['delete_always'] = false;
// end of config file
// Behavior if a received message requests a message delivery notification (read receipt)
// 0 = ask the user, 1 = send automatically, 2 = ignore (never send or ask)
// 3 = send automatically if sender is in addressbook, otherwise ask the user
// 4 = send automatically if sender is in addressbook, otherwise ignore
$rcmail_config['mdn_requests'] = 0;
// Return receipt checkbox default state
$rcmail_config['mdn_default'] = 0;
// Delivery Status Notification checkbox default state
$rcmail_config['dsn_default'] = 0;
// end of config file
program/include/rcube_message.php
@@ -399,9 +399,9 @@
                    if ($part_orig_mimetype == 'message/rfc822' && !empty($mail_part->filename))
                        $this->attachments[] = $mail_part;
                }
                // part text/[plain|html] OR message/delivery-status
                // part text/[plain|html] or delivery status
                else if ((($part_mimetype == 'text/plain' || $part_mimetype == 'text/html') && $mail_part->disposition != 'attachment') ||
                    $part_mimetype == 'message/delivery-status' || $part_mimetype == 'message/disposition-notification'
                    in_array($part_mimetype, array('message/delivery-status', 'text/rfc822-headers', 'message/disposition-notification'))
                ) {
                    // Allow plugins to handle also this part
                    $plugin = $this->app->plugins->exec_hook('message_part_structure',
program/include/rcube_smtp.php
@@ -153,17 +153,16 @@
   *               each RFC822 valid. This may contain recipients not
   *               specified in the headers, for Bcc:, resending
   *               messages, etc.
   *
   * @param mixed  The message headers to send with the mail
   *               Either as an associative array or a finally
   *               formatted string
   *
   * @param mixed  The full text of the message body, including any Mime parts
   *               or file handle
   * @param array  Delivery options (e.g. DSN request)
   *
   * @return bool  Returns true on success, or false on error
   */
  public function send_mail($from, $recipients, &$headers, &$body)
  public function send_mail($from, $recipients, &$headers, &$body, $opts=null)
  {
    if (!is_object($this->conn))
      return false;
@@ -183,7 +182,7 @@
    else
    {
      $this->reset();
      $this->response[] .= "Invalid message headers";
      $this->response[] = "Invalid message headers";
      return false;
    }
@@ -191,8 +190,22 @@
    if (!isset($from))
    {
      $this->reset();
      $this->response[] .= "No From address has been provided";
      $this->response[] = "No From address has been provided";
      return false;
    }
    // RFC3461: Delivery Status Notification
    if ($opts['dsn']) {
      $exts = $this->conn->getServiceExtensions();
      if (!isset($exts['DSN'])) {
        $this->error = array('label' => 'smtpdsnerror');
        $this->response[] = "DSN not supported";
        return false;
      }
      $from_params      = 'RET=HDRS';
      $recipient_params = 'NOTIFY=SUCCESS,FAILURE';
    }
    // RFC2298.3: remove envelope sender address
@@ -203,12 +216,12 @@
    }
    // set From: address
    if (PEAR::isError($this->conn->mailFrom($from)))
    if (PEAR::isError($this->conn->mailFrom($from, $from_params)))
    {
      $err = $this->conn->getResponse();
      $this->error = array('label' => 'smtpfromerror', 'vars' => array(
        'from' => $from, 'code' => $this->conn->_code, 'msg' => $err[1]));
      $this->response[] .= "Failed to set sender '$from'";
      $this->response[] = "Failed to set sender '$from'";
      $this->reset();
      return false;
    }
@@ -225,11 +238,11 @@
    // set mail recipients
    foreach ($recipients as $recipient)
    {
      if (PEAR::isError($this->conn->rcptTo($recipient))) {
      if (PEAR::isError($this->conn->rcptTo($recipient, $recipient_params))) {
        $err = $this->conn->getResponse();
        $this->error = array('label' => 'smtptoerror', 'vars' => array(
          'to' => $recipient, 'code' => $this->conn->_code, 'msg' => $err[1]));
        $this->response[] .= "Failed to add recipient '$recipient'";
        $this->response[] = "Failed to add recipient '$recipient'";
        $this->reset();
        return false;
      }
@@ -261,7 +274,7 @@
        $msg = $result->getMessage();
      $this->error = array('label' => 'smtperror', 'vars' => array('msg' => $msg));
      $this->response[] .= "Failed to send data";
      $this->response[] = "Failed to send data";
      $this->reset();
      return false;
    }
program/localization/en_US/labels.inc
@@ -209,6 +209,7 @@
$labels['charset']        = 'Charset';
$labels['editortype']     = 'Editor type';
$labels['returnreceipt']  = 'Return receipt';
$labels['dsn']            = 'Delivery status notification';
$labels['editidents']    = 'Edit identities';
$labels['checkspelling'] = 'Check spelling';
@@ -374,6 +375,7 @@
$labels['previewpanemarkread']  = 'Mark previewed messages as read';
$labels['afternseconds']  = 'after $n seconds';
$labels['reqmdn'] = 'Always request a return receipt';
$labels['reqdsn'] = 'Always request a delivery status notification';
$labels['folder']  = 'Folder';
$labels['folders']  = 'Folders';
program/localization/en_US/messages.inc
@@ -109,6 +109,7 @@
$messages['smtpfromerror'] = 'SMTP Error ($code): Failed to set sender "$from" ($msg)';
$messages['smtptoerror'] = 'SMTP Error ($code): Failed to add recipient "$to" ($msg)';
$messages['smtprecipientserror'] = 'SMTP Error: Unable to parse recipients list';
$messages['smtpdsnerror'] = 'SMTP Error: No support for Delivery Status Notifications';
$messages['smtperror'] = 'SMTP Error: $msg';
$messages['emailformaterror'] = 'Invalid e-mail address: $email';
$messages['toomanyrecipients'] = 'Too many recipients. Reduce the number of recipients to $max.';
program/localization/pl_PL/labels.inc
@@ -360,5 +360,7 @@
$labels['editidents'] = 'Edytuj tożsamości';
$labels['addmailreplyto'] = 'Dodaj Mail-Reply-To';
$labels['addmailfollowupto'] = 'Dodaj Mail-Followup-To';
$labels['dsn'] = 'Status dostarczenia (DSN)';
$labels['reqdsn'] = 'Zawsze żądaj statusu dostarczenia (DSN)';
?>
program/localization/pl_PL/messages.inc
@@ -114,6 +114,7 @@
$messages['smtpfromerror'] = 'Błąd SMTP ($code): Nie można ustawić nadawcy "$from" ($msg)';
$messages['smtptoerror'] = 'Błąd SMTP ($code): Nie można dodać odbiorcy "$to" ($msg)';
$messages['smtprecipientserror'] = 'Błąd SMTP: Parsowanie listy odbiorców nie powiodło się';
$messages['smtpdsnerror'] = 'Błąd SMTP: Statusy dostarczenia (DSN) nie są obsługiwane przez serwer';
$messages['smtperror'] = 'Błąd SMTP: $msg';
$messages['emailformaterror'] = 'Błędny adres e-mail: $email';
$messages['toomanyrecipients'] = 'Zbyt wielu odbiorców. Zmniejsz ich liczbę do $max.';
program/steps/mail/compose.inc
@@ -1174,6 +1174,28 @@
}
function rcmail_dsn_checkbox($attrib)
{
  global $RCMAIL;
  list($form_start, $form_end) = get_form_tags($attrib);
  unset($attrib['form']);
  if (!isset($attrib['id']))
    $attrib['id'] = 'dsn';
  $attrib['name'] = '_dsn';
  $attrib['value'] = '1';
  $checkbox = new html_checkbox($attrib);
  $out = $form_start ? "$form_start\n" : '';
  $out .= $checkbox->show($RCMAIL->config->get('dsn_default'));
  $out .= $form_end ? "\n$form_end" : '';
  return $out;
}
function rcmail_editor_selector($attrib)
{
  global $CONFIG, $MESSAGE, $compose_mode;
@@ -1251,6 +1273,7 @@
  'priorityselector' => 'rcmail_priority_selector',
  'editorselector' => 'rcmail_editor_selector',
  'receiptcheckbox' => 'rcmail_receipt_checkbox',
  'dsncheckbox' => 'rcmail_dsn_checkbox',
  'storetarget' => 'rcmail_store_target_selection',
));
program/steps/mail/func.inc
@@ -1478,10 +1478,11 @@
 * @param array  $mailto     Array of recipient address strings
 * @param array  $smtp_error SMTP error array (reference)
 * @param string $body_file  Location of file with saved message body (reference)
 * @param array  $smtp_opts  SMTP options (e.g. DSN request)
 *
 * @return boolean Send status.
 */
function rcmail_deliver_message(&$message, $from, $mailto, &$smtp_error, &$body_file)
function rcmail_deliver_message(&$message, $from, $mailto, &$smtp_error, &$body_file, $smtp_opts=null)
{
  global $CONFIG, $RCMAIL;
@@ -1525,7 +1526,7 @@
    if (!is_object($RCMAIL->smtp))
      $RCMAIL->smtp_init(true);
    $sent = $RCMAIL->smtp->send_mail($from, $a_recipients, $smtp_headers, $msg_body);
    $sent = $RCMAIL->smtp->send_mail($from, $a_recipients, $smtp_headers, $msg_body, $smtp_opts);
    $smtp_response = $RCMAIL->smtp->get_response();
    $smtp_error = $RCMAIL->smtp->get_error();
program/steps/mail/sendmail.inc
@@ -546,7 +546,13 @@
    $OUTPUT->send('iframe'); 
  }
  $sent = rcmail_deliver_message($MAIL_MIME, $from, $mailto, $smtp_error, $mailbody_file);
  // Handle Delivery Status Notification request
  if (!empty($_POST['_dsn'])) {
    $smtp_opts['dsn'] = true;
  }
  $sent = rcmail_deliver_message($MAIL_MIME, $from, $mailto,
    $smtp_error, $mailbody_file, $smtp_opts);
  // return to compose page if sending failed
  if (!$sent)
program/steps/settings/func.inc
@@ -524,6 +524,16 @@
      );
    }
    if (!isset($no_override['dsn_default'])) {
      $field_id = 'rcmfd_dsn_default';
      $input_dsn = new html_checkbox(array('name' => '_dsn_default', 'id' => $field_id, 'value' => 1));
      $blocks['main']['options']['dsn_default'] = array(
        'title' => html::label($field_id, Q(rcube_label('reqdsn'))),
        'content' => $input_dsn->show($config['dsn_default']?1:0),
      );
    }
    if (!isset($no_override['top_posting'])) {
      $field_id = 'rcmfd_top_posting';
      $select_replymode = new html_select(array('name' => '_top_posting', 'id' => $field_id, 'onchange' => "\$('#rcmfd_sig_above').attr('disabled',this.selectedIndex==0)"));
program/steps/settings/save_prefs.inc
@@ -66,6 +66,7 @@
      'mime_param_folding' => isset($_POST['_mime_param_folding']) ? intval($_POST['_mime_param_folding']) : 0,
      'force_7bit'         => isset($_POST['_force_7bit']) ? TRUE : FALSE,
      'mdn_default'        => isset($_POST['_mdn_default']) ? TRUE : FALSE,
      'dsn_default'        => isset($_POST['_dsn_default']) ? TRUE : FALSE,
      'show_sig'           => isset($_POST['_show_sig']) ? intval($_POST['_show_sig']) : 1,
      'top_posting'        => !empty($_POST['_top_posting']),
      'strip_existing_sig' => isset($_POST['_strip_existing_sig']),
skins/default/templates/compose.html
@@ -137,6 +137,9 @@
        <td><label for="rcmcomposereceipt"><roundcube:label name="returnreceipt" />:</label></td>
        <td><roundcube:object name="receiptCheckBox" form="form" id="rcmcomposereceipt" /></td>
    </tr><tr>
        <td><label for="rcmcomposedsn"><roundcube:label name="dsn" />:</label></td>
        <td><roundcube:object name="dsnCheckBox" form="form" id="rcmcomposedsn" /></td>
    </tr><tr>
        <td><label for="rcmcomposepriority"><roundcube:label name="priority" />:</label></td>
        <td><roundcube:object name="prioritySelector" form="form" id="rcmcomposepriority" /></td>
    </tr><tr>