From 10936fef6496aaa3c10be3f450d6046368d8794f Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Sun, 29 Dec 2013 05:57:39 -0500
Subject: [PATCH] Don't alter Message-ID of a draft when sending (#1489409)

---
 CHANGELOG                       |    1 
 program/steps/mail/compose.inc  |   40 +++++++++++---------
 program/steps/mail/sendmail.inc |   56 +++++++++++++---------------
 program/js/app.js               |   20 +++++----
 4 files changed, 60 insertions(+), 57 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 7a625bc..2e278a8 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
 CHANGELOG Roundcube Webmail
 ===========================
 
+- Don't alter Message-ID of a draft when sending (#1489409)
 - Fix issue where deprecated syntax for HTML lists was not handled properly (#1488768)
 - Display different icons when Trash folder is empty or full (#1485775)
 - Remember last position of more headers switch (#1488323)
diff --git a/program/js/app.js b/program/js/app.js
index e6cc281..44afd5c 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -3607,16 +3607,18 @@
   {
     var rc;
 
-    if (!this.env.draft_id && id && (rc = this.opener())) {
-      // refresh the drafts folder in opener window
-      if (rc.env.task == 'mail' && rc.env.action == '' && rc.env.mailbox == this.env.drafts_mailbox)
-        rc.command('checkmail');
+    if (id && id != this.env.draft_id) {
+      if (rc = this.opener()) {
+        // refresh the drafts folder in opener window
+        if (rc.env.task == 'mail' && rc.env.action == '' && rc.env.mailbox == this.env.drafts_mailbox)
+          rc.command('checkmail');
+      }
+
+      this.env.draft_id = id;
+      $("input[name='_draft_saveid']").val(id);
+
+      this.remove_compose_data(this.env.compose_id);
     }
-
-    this.env.draft_id = id;
-    $("input[name='_draft_saveid']").val(id);
-
-    this.remove_compose_data(this.env.compose_id);
   };
 
   this.auto_save_start = function()
diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc
index d5154ff..ce70819 100644
--- a/program/steps/mail/compose.inc
+++ b/program/steps/mail/compose.inc
@@ -217,32 +217,36 @@
     }
   }
   else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) {
-    if ($compose_mode == RCUBE_COMPOSE_DRAFT && ($draft_info = $MESSAGE->headers->get('x-draft-info'))) {
-      // get reply_uid/forward_uid to flag the original message when sending
-      $info = rcmail_draftinfo_decode($draft_info);
+    if ($compose_mode == RCUBE_COMPOSE_DRAFT) {
+      if ($draft_info = $MESSAGE->headers->get('x-draft-info')) {
+        // get reply_uid/forward_uid to flag the original message when sending
+        $info = rcmail_draftinfo_decode($draft_info);
 
-      if ($info['type'] == 'reply')
-        $COMPOSE['reply_uid'] = $info['uid'];
-      else if ($info['type'] == 'forward')
-        $COMPOSE['forward_uid'] = $info['uid'];
+        if ($info['type'] == 'reply')
+          $COMPOSE['reply_uid'] = $info['uid'];
+        else if ($info['type'] == 'forward')
+          $COMPOSE['forward_uid'] = $info['uid'];
 
-      $COMPOSE['mailbox'] = $info['folder'];
+        $COMPOSE['mailbox'] = $info['folder'];
 
-      // Save the sent message in the same folder of the message being replied to
-      if ($RCMAIL->config->get('reply_same_folder') && ($sent_folder = $info['folder'])
-        && rcmail_check_sent_folder($sent_folder, false)
-      ) {
-        $COMPOSE['param']['sent_mbox'] = $sent_folder;
+        // Save the sent message in the same folder of the message being replied to
+        if ($RCMAIL->config->get('reply_same_folder') && ($sent_folder = $info['folder'])
+          && rcmail_check_sent_folder($sent_folder, false)
+        ) {
+          $COMPOSE['param']['sent_mbox'] = $sent_folder;
+        }
       }
+
+      $COMPOSE['param']['message-id'] = $MESSAGE->headers->get('message-id');
+
+      // use message UID as draft_id
+      $OUTPUT->set_env('draft_id', $msg_uid);
     }
 
     if ($in_reply_to = $MESSAGE->headers->get('in-reply-to'))
       $COMPOSE['reply_msgid'] = '<' . $in_reply_to . '>';
 
     $COMPOSE['references'] = $MESSAGE->headers->references;
-
-    // use message-ID as draft_id, same as in sendmail.inc
-    $OUTPUT->set_env('draft_id', trim($MESSAGE->headers->get('message-id'), '<>'));
   }
 }
 else {
@@ -813,7 +817,7 @@
 
 function rcmail_compose_body($attrib)
 {
-  global $RCMAIL, $CONFIG, $OUTPUT, $MESSAGE, $compose_mode, $HTML_MODE, $MESSAGE_BODY;
+  global $RCMAIL, $CONFIG, $OUTPUT, $HTML_MODE, $MESSAGE_BODY;
 
   list($form_start, $form_end) = get_form_tags($attrib);
   unset($attrib['form']);
@@ -827,7 +831,7 @@
 
   $out = $form_start ? "$form_start\n" : '';
 
-  $saveid = new html_hiddenfield(array('name' => '_draft_saveid', 'value' => $compose_mode==RCUBE_COMPOSE_DRAFT ? str_replace(array('<','>'), "", $MESSAGE->headers->messageID) : ''));
+  $saveid = new html_hiddenfield(array('name' => '_draft_saveid', 'value' => $RCMAIL->output->get_env('draft_id')));
   $out .= $saveid->show();
 
   $drafttoggle = new html_hiddenfield(array('name' => '_draft', 'value' => 'yes'));
diff --git a/program/steps/mail/sendmail.inc b/program/steps/mail/sendmail.inc
index 9f79df3..a9e3d3f 100644
--- a/program/steps/mail/sendmail.inc
+++ b/program/steps/mail/sendmail.inc
@@ -284,10 +284,10 @@
 
 /****** compose message ********/
 
-if (strlen($_POST['_draft_saveid']) > 3)
-  $olddraftmessageid = rcube_utils::get_input_value('_draft_saveid', rcube_utils::INPUT_POST);
-
-$message_id = $RCMAIL->gen_message_id();
+if (empty($COMPOSE['param']['message-id'])) {
+  $COMPOSE['param']['message-id'] = $RCMAIL->gen_message_id();
+}
+$message_id = $COMPOSE['param']['message-id'];
 
 // set default charset
 $message_charset = isset($_POST['_charset']) ? $_POST['_charset'] : $OUTPUT->get_charset();
@@ -817,21 +817,15 @@
     }
   }
 
-  if ($olddraftmessageid) {
+  if ($saved && ($old_id = rcube_utils::get_input_value('_draft_saveid', rcube_utils::INPUT_POST))) {
     // delete previous saved draft
-    // @TODO: use message UID (remember to check UIDVALIDITY) to skip this SEARCH
-    $delete_idx = $RCMAIL->storage->search_once($CONFIG['drafts_mbox'],
-        'HEADER Message-ID '.$olddraftmessageid);
+    $deleted = $RCMAIL->storage->delete_message($old_id, $CONFIG['drafts_mbox']);
 
-    if ($del_uid = $delete_idx->get_element('FIRST')) {
-      $deleted = $RCMAIL->storage->delete_message($del_uid, $CONFIG['drafts_mbox']);
-
-      // raise error if deletion of old draft failed
-      if (!$deleted)
-        rcube::raise_error(array('code' => 800, 'type' => 'imap',
-          'file' => __FILE__, 'line' => __LINE__,
-          'message' => "Could not delete message from ".$CONFIG['drafts_mbox']), TRUE, FALSE);
-    }
+    // raise error if deletion of old draft failed
+    if (!$deleted)
+      rcube::raise_error(array('code' => 800, 'type' => 'imap',
+        'file' => __FILE__, 'line' => __LINE__,
+        'message' => "Could not delete message from ".$CONFIG['drafts_mbox']), TRUE, FALSE);
   }
 }
 // remove temp file
@@ -841,22 +835,24 @@
 
 
 if ($savedraft) {
-  $msgid = strtr($message_id, array('>' => '', '<' => ''));
-
-  // remember new draft-uid ($saved could be an UID or TRUE here)
-  if (is_bool($saved)) {
-    $draft_idx = $RCMAIL->storage->search_once($CONFIG['drafts_mbox'], 'HEADER Message-ID '.$msgid);
-    $saved     = $draft_idx->get_element('FIRST');
+  // remember new draft-uid ($saved could be an UID or true/false here)
+  if ($saved && is_bool($saved)) {
+    $index = $RCMAIL->storage->search_once($CONFIG['drafts_mbox'], 'HEADER Message-ID ' . $message_id);
+    $saved = @max($index->get());
   }
-  $COMPOSE['param']['draft_uid'] = $saved;
-  $plugin = $RCMAIL->plugins->exec_hook('message_draftsaved', array('msgid' => $msgid, 'uid' => $saved, 'folder' => $store_target));
 
-  // display success
-  $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'messagesaved', 'confirmation');
+  if ($saved) {
+    $plugin = $RCMAIL->plugins->exec_hook('message_draftsaved',
+      array('msgid' => $message_id, 'uid' => $saved, 'folder' => $store_target));
 
-  // update "_draft_saveid" and the "cmp_hash" to prevent "Unsaved changes" warning
-  $OUTPUT->command('set_draft_id', $msgid);
-  $OUTPUT->command('compose_field_hash', true);
+    // display success
+    $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'messagesaved', 'confirmation');
+
+    // update "_draft_saveid" and the "cmp_hash" to prevent "Unsaved changes" warning
+    $COMPOSE['param']['draft_uid'] = $plugin['uid'];
+    $OUTPUT->command('set_draft_id', $plugin['uid']);
+    $OUTPUT->command('compose_field_hash', true);
+  }
 
   // start the auto-save timer again
   $OUTPUT->command('auto_save_start');

--
Gitblit v1.9.1