From 4591de7018414267311b421ef42ef1b4a2f6aa89 Mon Sep 17 00:00:00 2001
From: thomascube <thomas@roundcube.net>
Date: Thu, 10 Mar 2011 15:21:21 -0500
Subject: [PATCH] Prepare for multiple concurrent compose windows

---
 CHANGELOG                          |    1 
 program/js/editor_images.js        |    2 
 program/steps/mail/attachments.inc |    6 ++
 program/steps/mail/compose.inc     |   37 ++++++++++--------
 program/steps/addressbook/save.inc |    3 +
 program/include/rcmail.php         |    4 +
 program/steps/mail/func.inc        |    8 ++--
 program/include/rcube_session.php  |   13 ++++++
 program/steps/mail/sendmail.inc    |    7 ++-
 program/js/app.js                  |    6 +-
 10 files changed, 57 insertions(+), 30 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index df52c54..c01623f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
 CHANGELOG Roundcube Webmail
 ===========================
 
+- Allow multiple concurrent compose sessions
 - Force names of unique constraints in PostgreSQL DDL
 - Add code for prevention from IMAP connection hangs when server closes socket unexpectedly
 - Remove redundant DELETE query (for old session deletion) on login
diff --git a/program/include/rcmail.php b/program/include/rcmail.php
index 980efe4..d9bb30b 100644
--- a/program/include/rcmail.php
+++ b/program/include/rcmail.php
@@ -1078,8 +1078,10 @@
       $this->imap->close();
 
     // before closing the database connection, write session data
-    if ($_SERVER['REMOTE_ADDR'])
+    if ($_SERVER['REMOTE_ADDR']) {
+      $this->session->cleanup();
       session_write_close();
+    }
 
     // write performance stats to logs/console
     if ($this->config->get('devel_mode')) {
diff --git a/program/include/rcube_session.php b/program/include/rcube_session.php
index 1fa3317..8c7adb3 100644
--- a/program/include/rcube_session.php
+++ b/program/include/rcube_session.php
@@ -192,6 +192,19 @@
 
 
   /**
+   * Cleanup session data before saving
+   */
+  public function cleanup()
+  {
+    // current compose information is stored in $_SESSION['compose'], move it to $_SESSION['compose_data']
+    if ($_SESSION['compose']) {
+      $_SESSION['compose_data'][$_SESSION['compose']['id']] = $_SESSION['compose'];
+      $this->remove('compose');
+    }
+  }
+
+
+  /**
    * Register additional garbage collector functions
    *
    * @param mixed Callback function
diff --git a/program/js/app.js b/program/js/app.js
index a155653..fdd9d9c 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -227,7 +227,7 @@
           }
         }
         else if (this.env.action == 'compose') {
-          this.env.compose_commands = ['send-attachment', 'remove-attachment', 'send', 'toggle-editor'];
+          this.env.compose_commands = ['send-attachment', 'remove-attachment', 'send', 'cancel', 'toggle-editor'];
 
           if (this.env.drafts_mailbox)
             this.env.compose_commands.push('savedraft')
@@ -3270,7 +3270,7 @@
   this.remove_attachment = function(name)
   {
     if (name && this.env.attachments[name])
-      this.http_post('remove-attachment', '_file='+urlencode(name));
+      this.http_post('remove-attachment', { _id:this.env.compose_id, _file:name });
 
     return true;
   };
@@ -5408,7 +5408,7 @@
     $(frame_name).bind('load', {ts:ts}, onload);
 
     form.target = frame_name;
-    form.action = this.url(action, { _uploadid:ts });
+    form.action = this.url(action, { _id:this.env.compose_id||'', _uploadid:ts });
     form.setAttribute('enctype', 'multipart/form-data');
     form.submit();
 
diff --git a/program/js/editor_images.js b/program/js/editor_images.js
index 2faafd3..28e6bec 100644
--- a/program/js/editor_images.js
+++ b/program/js/editor_images.js
@@ -7,6 +7,6 @@
    {
       var att = rc_client.env.attachments[id];
       if (att.complete && att.mimetype.indexOf('image/') == 0)
-        tinyMCEImageList.push([att.name, rc_client.env.comm_path+'&_action=display-attachment&_file='+id]);
+        tinyMCEImageList.push([att.name, rc_client.env.comm_path+'&_action=display-attachment&_file='+id+'&_id='+rc_client.env.compose_id]);
    }
 };
diff --git a/program/steps/addressbook/save.inc b/program/steps/addressbook/save.inc
index 2884aa4..8949a23 100644
--- a/program/steps/addressbook/save.inc
+++ b/program/steps/addressbook/save.inc
@@ -57,6 +57,7 @@
                 'size' => $_FILES['_photo']['size'],
                 'name' => $_FILES['_photo']['name'],
                 'mimetype' => 'image/' . $imageprop['type'],
+                'group' => 'contact',
             ));
         }
         else
@@ -156,7 +157,7 @@
         unset($a_record['photo']);
     
     // cleanup session data
-    $RCMAIL->plugins->exec_hook('attachments_cleanup', array());
+    $RCMAIL->plugins->exec_hook('attachments_cleanup', array('group' => 'contact'));
     $RCMAIL->session->remove('contacts');
 }
 
diff --git a/program/steps/mail/attachments.inc b/program/steps/mail/attachments.inc
index 13fb5e0..6b32ad6 100644
--- a/program/steps/mail/attachments.inc
+++ b/program/steps/mail/attachments.inc
@@ -20,6 +20,9 @@
 */
 
 
+$COMPOSE_ID = get_input_value('_id', RCUBE_INPUT_GPC);
+$_SESSION['compose'] = $_SESSION['compose_data'][$COMPOSE_ID];
+
 if (!$_SESSION['compose']) {
   die("Invalid session var!");
 }
@@ -84,7 +87,8 @@
       'path' => $filepath,
       'size' => $_FILES['_attachments']['size'][$i],
       'name' => $_FILES['_attachments']['name'][$i],
-      'mimetype' => rc_mime_content_type($filepath, $_FILES['_attachments']['name'][$i], $_FILES['_attachments']['type'][$i])
+      'mimetype' => rc_mime_content_type($filepath, $_FILES['_attachments']['name'][$i], $_FILES['_attachments']['type'][$i]),
+      'group' => $COMPOSE_ID,
     );
 
     $attachment = $RCMAIL->plugins->exec_hook('attachment_upload', $attachment);
diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc
index 41f7b14..0a94994 100644
--- a/program/steps/mail/compose.inc
+++ b/program/steps/mail/compose.inc
@@ -28,18 +28,15 @@
 $MESSAGE_FORM = NULL;
 $MESSAGE = NULL;
 
+$COMPOSE_ID = get_input_value('_id', RCUBE_INPUT_GET);
+$_SESSION['compose'] = $_SESSION['compose_data'][$COMPOSE_ID];
+
 // Nothing below is called during message composition, only at "new/forward/reply/draft" initialization or
 // if a compose-ID is given (i.e. when the compose step is opened in a new window/tab).
-// Since there are many ways to leave the compose page improperly, it seems necessary to clean-up an old
-// compose when a "new/forward/reply/draft" is called - otherwise the old session attachments will appear
-
-$MESSAGE_ID = get_input_value('_id', RCUBE_INPUT_GET);
-if (!is_array($_SESSION['compose']) || $_SESSION['compose']['id'] != $MESSAGE_ID)
+if (!is_array($_SESSION['compose']))
 {
-  rcmail_compose_cleanup();
-
   // Infinite redirect prevention in case of broken session (#1487028)
-  if ($MESSAGE_ID)
+  if ($COMPOSE_ID)
     raise_error(array('code' => 500, 'type' => 'php',
       'file' => __FILE__, 'line' => __LINE__,
       'message' => "Invalid session"), true, true);
@@ -81,9 +78,10 @@
       else {
         $filename = basename($attach);
         $attachment = array(
+          'group' => $COMPOSE_ID,
           'name' => $filename,
           'mimetype' => rc_mime_content_type($attach, $filename),
-          'path' => $attach
+          'path' => $attach,
         );
       }
       
@@ -115,6 +113,8 @@
     'messagesaved', 'converting', 'editorwarning', 'searching', 'uploading', 'fileuploaderror',
     'autocompletechars');
 
+$OUTPUT->set_env('compose_id', $COMPOSE_ID);
+
 // add config parameters to client script
 if (!empty($CONFIG['drafts_mbox'])) {
   $OUTPUT->set_env('drafts_mailbox', $CONFIG['drafts_mbox']);
@@ -127,16 +127,16 @@
 $OUTPUT->set_env('autocomplete_min_length', $CONFIG['autocomplete_min_length']);
 
 // get reference message and set compose mode
-if ($msg_uid = $_SESSION['compose']['param']['reply_uid'])
+if ($msg_uid = $_SESSION['compose']['param']['draft_uid']) {
+  $RCMAIL->imap->set_mailbox($CONFIG['drafts_mbox']);
+  $compose_mode = RCUBE_COMPOSE_DRAFT;
+}
+else if ($msg_uid = $_SESSION['compose']['param']['reply_uid'])
   $compose_mode = RCUBE_COMPOSE_REPLY;
 else if ($msg_uid = $_SESSION['compose']['param']['forward_uid'])
   $compose_mode = RCUBE_COMPOSE_FORWARD;
 else if ($msg_uid = $_SESSION['compose']['param']['uid'])
   $compose_mode = RCUBE_COMPOSE_EDIT;
-else if ($msg_uid = $_SESSION['compose']['param']['draft_uid']) {
-  $RCMAIL->imap->set_mailbox($CONFIG['drafts_mbox']);
-  $compose_mode = RCUBE_COMPOSE_DRAFT;
-}
 
 $config_show_sig = $RCMAIL->config->get('show_sig', 1);
 if ($config_show_sig == 1)
@@ -620,7 +620,7 @@
     if ($attachment = rcmail_save_image('program/blocked.gif', 'image/gif')) {
       $_SESSION['compose']['attachments'][$attachment['id']] = $attachment;
       $body = preg_replace('#\./program/blocked\.gif#',
-        $RCMAIL->comm_path.'&_action=display-attachment&_file=rcmfile'.$attachment['id'],
+        $RCMAIL->comm_path.'&_action=display-attachment&_file=rcmfile'.$attachment['id'].'&_id='.$_SESSION['compose']['id'],
         $body);
     }
   }
@@ -921,7 +921,7 @@
       if (!$skip && ($attachment = rcmail_save_attachment($message, $pid))) {
         $_SESSION['compose']['attachments'][$attachment['id']] = $attachment;
         if ($bodyIsHtml && ($part->content_id || $part->content_location)) {
-          $url = $RCMAIL->comm_path.'&_action=display-attachment&_file=rcmfile'.$attachment['id'];
+          $url = $RCMAIL->comm_path.'&_action=display-attachment&_file=rcmfile'.$attachment['id'].'&_id='.$_SESSION['compose']['id'];
           if ($part->content_id)
             $cid_map['cid:'.$part->content_id] = $url;
           else
@@ -946,7 +946,7 @@
     if (($part->content_id || $part->content_location) && $part->filename) {
       if ($attachment = rcmail_save_attachment($message, $pid)) {
         $_SESSION['compose']['attachments'][$attachment['id']] = $attachment;
-        $url = $RCMAIL->comm_path.'&_action=display-attachment&_file=rcmfile'.$attachment['id'];
+        $url = $RCMAIL->comm_path.'&_action=display-attachment&_file=rcmfile'.$attachment['id'].'&_id='.$_SESSION['compose']['id'];
         if ($part->content_id)
           $cid_map['cid:'.$part->content_id] = $url;
         else
@@ -980,6 +980,7 @@
   }
 
   $attachment = array(
+    'group' => $_SESSION['compose']['id'],
     'name' => $part->filename ? $part->filename : 'Part_'.$pid.'.'.$part->ctype_secondary,
     'mimetype' => $part->ctype_primary . '/' . $part->ctype_secondary,
     'content_id' => $part->content_id,
@@ -1006,6 +1007,7 @@
   $data = file_get_contents($path);
 
   $attachment = array(
+    'group' => $_SESSION['compose']['id'],
     'name' => rcmail_basename($path),
     'mimetype' => $mimetype ? $mimetype : rc_mime_content_type($path, $name),
     'data' => $data,
@@ -1323,6 +1325,7 @@
   {
     $hiddenfields = new html_hiddenfield(array('name' => '_task', 'value' => $RCMAIL->task));
     $hiddenfields->add(array('name' => '_action', 'value' => 'send'));
+    $hiddenfields->add(array('name' => '_id', 'value' => $_SESSION['compose']['id']));
 
     $form_start = empty($attrib['form']) ? $RCMAIL->output->form_tag(array('name' => "form", 'method' => "post")) : '';
     $form_start .= $hiddenfields->show();
diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index 0903176..18ef2de 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -1419,14 +1419,14 @@
 /**
  * clear message composing settings
  */
-function rcmail_compose_cleanup()
+function rcmail_compose_cleanup($id)
 {
-  if (!isset($_SESSION['compose']))
+  if (!isset($_SESSION['compose_data'][$id]))
     return;
 
   $rcmail = rcmail::get_instance();
-  $rcmail->plugins->exec_hook('attachments_cleanup', array());
-  $rcmail->session->remove('compose');
+  $rcmail->plugins->exec_hook('attachments_cleanup', array('group' => $id));
+  unset($_SESSION['compose_data'][$id]);
 }
 
 
diff --git a/program/steps/mail/sendmail.inc b/program/steps/mail/sendmail.inc
index 118e9ed..a492e93 100644
--- a/program/steps/mail/sendmail.inc
+++ b/program/steps/mail/sendmail.inc
@@ -26,6 +26,9 @@
 
 $savedraft = !empty($_POST['_draft']) ? true : false;
 
+$COMPOSE_ID = get_input_value('_id', RCUBE_INPUT_GPC);
+$_SESSION['compose'] = $_SESSION['compose_data'][$COMPOSE_ID];
+
 /****** checks ********/
 
 if (!isset($_SESSION['compose']['id'])) {
@@ -702,7 +705,7 @@
   
   // remember new draft-uid
   $draftuids = $IMAP->search_once($CONFIG['drafts_mbox'], 'HEADER Message-ID '.$msgid, true);
-  $_SESSION['compose']['param']['_draft_uid'] = $draftuids[0];
+  $_SESSION['compose']['param']['draft_uid'] = $draftuids[0];
 
   // display success
   $OUTPUT->show_message('messagesaved', 'confirmation');
@@ -718,7 +721,7 @@
   }
 else
   {
-  rcmail_compose_cleanup();
+  rcmail_compose_cleanup($COMPOSE_ID);
 
   if ($store_folder && !$saved)
     $OUTPUT->command('sent_successfully', 'error', rcube_label('errorsavingsent'));

--
Gitblit v1.9.1