Implement $MDNSent keyword support (RFC 3503)
authorMichael M Slusarz <slusarz@curecanti.org>
Wed, 1 Apr 2009 19:11:54 +0000 (13:11 -0600)
committerMichael M Slusarz <slusarz@curecanti.org>
Wed, 1 Apr 2009 19:12:34 +0000 (13:12 -0600)
imp/ajax.php
imp/docs/CHANGES
imp/docs/RFCS
imp/lib/Compose.php
imp/lib/UI/Message.php
imp/lib/Views/ShowMessage.php
imp/message.php

index 1125294..8ab58ac 100644 (file)
@@ -685,7 +685,7 @@ case 'SendMDN':
     }
 
     $imp_ui = new IMP_UI_Message();
-    $imp_ui->MDNCheck(reset($fetch_ret[$index]['headertext']), true);
+    $imp_ui->MDNCheck($mbox, $index, $reset($fetch_ret[$index]['headertext']), true);
     break;
 
 case 'PGPSymmetric':
index e8570ee..759a861 100644 (file)
@@ -2,6 +2,7 @@
 v5.0-git
 --------
 
+[mms] Support $MDNSent keyword (RFC 3503) on IMAP server.
 [mms] Link URLs/e-mails in subjects in message views (Request #7487).
 [mms] Implement spellcheck on send in DIMP.
 [mms] Sanity check - don't do message operations reliant on UID list if
index e1b45b7..57775b8 100644 (file)
@@ -25,6 +25,7 @@ RFC 2595/4616   TLS & AUTH=PLAIN
 RFC 2831        DIGEST-MD5 authentication mechanism.
 RFC 2971        ID
 RFC 3502        MULTIAPPEND
+RFC 3503        $MDNSent keyword
 RFC 3516        BINARY
 RFC 3691        UNSELECT
 RFC 4315        UIDPLUS
index ef3dffe..b023716 100644 (file)
@@ -236,6 +236,10 @@ class IMP_Compose
             $append_flags[] = '\\seen';
         }
 
+        /* RFC 3503 [3.4] states that when saving a draft, the client MUST
+         * set the $MDNSent keyword. However, IMP doesn't write MDN headers
+         * until send time so no need to set the flag here. */
+
         /* Get the message ID. */
         $headers = Horde_Mime_Headers::parseHeaders($data);
 
@@ -433,6 +437,7 @@ class IMP_Compose
         $headers->addHeader('Date', date('r'));
 
         /* Add Return Receipt Headers. */
+        $mdn = null;
         if (!empty($opts['readreceipt']) &&
             $conf['compose']['allow_receipts']) {
             $mdn = new Horde_Mime_Mdn();
@@ -584,8 +589,15 @@ class IMP_Compose
                 $imp_folder->create($opts['sent_folder'], $prefs->getValue('subscribe'));
             }
 
+            $flags = array('\\seen');
+
+            /* RFC 3503 [3.3] - set $MDNSent flag on sent message. */
+            if ($mdn) {
+                $flags[] = array('$MDNSent');
+            }
+
             try {
-                $GLOBALS['imp_imap']->ob->append(String::convertCharset($opts['sent_folder'], NLS::getCharset(), 'UTF-8'), array(array('data' => $fcc, 'flags' => array('\\seen'))));
+                $GLOBALS['imp_imap']->ob->append(String::convertCharset($opts['sent_folder'], NLS::getCharset(), 'UTF-8'), array(array('data' => $fcc, 'flags' => $flags)));
             } catch (Horde_Imap_Client_Exception $e) {
                 $notification->push(sprintf(_("Message sent successfully, but not saved to %s"), IMP::displayFolder($opts['sent_folder'])));
                 $sent_saved = false;
index 5f0fa6c..782178c 100644 (file)
@@ -57,11 +57,19 @@ class IMP_UI_Message
     }
 
     /**
-     * TODO
+     * Check if we need to send a MDN, and send if needed.
+     *
+     * @param string $mailbox     The mailbox of the message.
+     * @param integer $uid        The UID of the message.
+     * @param array $headers      The headers of the message.
+     * @param boolean $confirmed  Has the MDN request been confirmed?
+     *
+     * @return boolean  True if the MDN request needs to be confirmed.
      */
-    public function MDNCheck($headers, $confirmed = false)
+    public function MDNCheck($mailbox, $uid, $headers, $confirmed = false)
     {
-        if (!$GLOBALS['prefs']->getValue('disposition_send_mdn')) {
+        if (!$GLOBALS['prefs']->getValue('disposition_send_mdn') ||
+            $GLOBALS['imp_imap']->isReadOnly($mailbox)) {
             return false;
         }
 
@@ -73,29 +81,54 @@ class IMP_UI_Message
         }
 
         $msg_id = $headers->getValue('message-id');
+        $mdn_flag = $need_mdn = false;
 
         /* See if we have already processed this message. */
-        if (!IMP_Maillog::sentMDN($msg_id, 'displayed')) {
-            /* See if we need to query the user. */
-            if ($mdn->userConfirmationNeeded() && !$confirmed) {
-                return true;
-            } else {
-                /* Send out the MDN now. */
-                $mail_driver = IMP_Compose::getMailDriver();
-
-                try {
-                    $mdn->generate(false, $confirmed, 'displayed', $mail_driver['driver'], $mail_driver['params']);
-                    IMP_Maillog::log('mdn', $msg_id, 'displayed');
-                    $success = true;
-                } catch (Horde_Mime_Exception $e) {
-                    $success = false;
-                }
+        /* 1st test: $MDNSent keyword (RFC 3503 [3.1]). */
+        try {
+            $status = $GLOBALS['imp_imap']->ob->status($mailbox, Horde_Imap_Client::STATUS_PERMFLAGS);
+            if (in_array('\\*', $status['permflags']) ||
+                in_array('$mdnsent', $status['permflags'])) {
+                $mdn_flag = true;
+                $res = $GLOBALS['imp_imap']->ob->fetch($mailbox, array(
+                        Horde_Imap_Client::FETCH_FLAGS => true
+                    ), array('ids' => array($uid)));
+                $need_mdn = in_array('$mdnsent', $res[$uid]['flags']);
+            }
+        } catch (Horde_Imap_Client_Exception $e) {}
 
-                if ($GLOBALS['conf']['sentmail']['driver'] != 'none') {
-                    $sentmail = IMP_Sentmail::factory();
-                    $sentmail->log('mdn', '', $return_addr, $success);
-                }
+        if (!$mdn_flag) {
+            /* 2nd test: Use Maillog as a fallback. */
+            $need_mdn = !IMP_Maillog::sentMDN($msg_id, 'displayed');
+        }
+
+        if (!$need_mdn) {
+            return false;
+        }
+
+        /* See if we need to query the user. */
+        if ($mdn->userConfirmationNeeded() && !$confirmed) {
+            return true;
+        }
+
+        /* Send out the MDN now. */
+        try {
+            $mail_driver = IMP_Compose::getMailDriver();
+            $mdn->generate(false, $confirmed, 'displayed', $mail_driver['driver'], $mail_driver['params']);
+            IMP_Maillog::log('mdn', $msg_id, 'displayed');
+            $success = true;
+
+            if ($mdn_flag) {
+                $imp_message = &IMP_Message::singleton();
+                $imp_message->flag(array('$MDNSent'), $uid . IMP::IDX_SEP . $mailbox, true);
             }
+        } catch (Horde_Mime_Exception $e) {
+            $success = false;
+        }
+
+        if ($GLOBALS['conf']['sentmail']['driver'] != 'none') {
+            $sentmail = IMP_Sentmail::factory();
+            $sentmail->log('mdn', '', $return_addr, $success);
         }
 
         return false;
index ae23cb9..bb71a49 100644 (file)
@@ -342,7 +342,7 @@ class IMP_Views_ShowMessage
             }
 
             /* Do MDN processing now. */
-            if ($imp_ui->MDNCheck($mime_headers)) {
+            if ($imp_ui->MDNCheck($folder, $index, $mime_headers)) {
                 $confirm_link = Horde::link('', '', '', '', 'DimpCore.doAction(\'SendMDN\',{folder:\'' . $folder . '\',index:' . $index . '}); return false;', '', '') . _("HERE") . '</a>';
                 $GLOBALS['notification']->push(sprintf(_("The sender of this message is requesting a Message Disposition Notification from you when you have read this message. Click %s to send the notification message."), $confirm_link), 'dimp.request', array('content.raw'));
             }
index 7cb3f72..337596a 100644 (file)
@@ -385,7 +385,7 @@ $view_link = IMP::generateIMPUrl('view.php', $imp_mbox['mailbox'], $index, $mail
 /* Retrieve any history information for this message. */
 if (!IMP::$printMode && !empty($conf['maillog']['use_maillog'])) {
     /* Do MDN processing now. */
-    if ($imp_ui->MDNCheck($mime_headers, Util::getFormData('mdn_confirm'))) {
+    if ($imp_ui->MDNCheck($imp_mbox['mailbox'], $index, $mime_headers, Util::getFormData('mdn_confirm'))) {
         $confirm_link = Horde::link(htmlspecialchars(Util::addParameter($selfURL, 'mdn_confirm', 1))) . _("HERE") . '</a>';
         $notification->push(sprintf(_("The sender of this message is requesting a Message Disposition Notification from you when you have read this message. Please click %s to send the notification message."), $confirm_link), 'horde.message', array('content.raw'));
     }