From 271efe53e084779a8141228c29b5819d1acd2762 Mon Sep 17 00:00:00 2001
From: Thomas Bruederli <thomas@roundcube.net>
Date: Wed, 17 Oct 2012 16:42:35 -0400
Subject: [PATCH] Add user settings to open message view and compose form in new windows. This natevely implements the compose_newwindow plugin functionslity and more

---
 program/steps/mail/compose.inc            |   19 +++
 program/steps/addressbook/mailto.inc      |    2 
 skins/larry/templates/message.html        |   10 +
 program/steps/addressbook/func.inc        |    1 
 program/steps/mail/show.inc               |    1 
 config/main.inc.php.dist                  |    6 +
 program/include/rcube_message.php         |    9 +
 program/steps/settings/save_prefs.inc     |    2 
 skins/larry/templates/messagepreview.html |    2 
 program/include/rcube_output_html.php     |   11 ++
 program/steps/mail/func.inc               |   17 +--
 program/steps/settings/func.inc           |   24 ++++
 program/localization/en_US/labels.inc     |    2 
 skins/larry/styles.css                    |    4 
 skins/larry/includes/header.html          |   10 +
 program/js/app.js                         |  146 +++++++++++++++++++++--------
 skins/larry/mail.css                      |    4 
 skins/larry/templates/compose.html        |    5 
 18 files changed, 206 insertions(+), 69 deletions(-)

diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist
index a6661c3..15052c3 100644
--- a/config/main.inc.php.dist
+++ b/config/main.inc.php.dist
@@ -724,6 +724,12 @@
 // 2 - Always show inline images
 $rcmail_config['show_images'] = 0;
 
+// open messages in new window
+$rcmail_config['message_extwin'] = false;
+
+// open message compose form in new window
+$rcmail_config['compose_extwin'] = false;
+
 // compose html formatted messages by default
 // 0 - never, 1 - always, 2 - on reply to HTML message, 3 - on forward or reply to HTML message
 $rcmail_config['htmleditor'] = 0;
diff --git a/program/include/rcube_message.php b/program/include/rcube_message.php
index 7bf95d1..c189df5 100644
--- a/program/include/rcube_message.php
+++ b/program/include/rcube_message.php
@@ -210,15 +210,16 @@
                 if (!$recursive) {
                     $level = explode('.', $part->mime_id);
 
-                    // Level too high
-                    if (count($level) > 2) {
+                    // Skip if level too deep or part has a file name
+                    if (count($level) > 2 || $part->filename) {
                         continue;
                     }
 
                     // HTML part can be on the lower level, if not...
                     if (count($level) > 1) {
-                        // It can be an alternative or related message part
-                        $parent = $this->mime_parts[0];
+                        array_pop($level);
+                        $parent = $this->mime_parts[join('.', $level)];
+                        // ... parent isn't multipart/alternative or related
                         if ($parent->mimetype != 'multipart/alternative' && $parent->mimetype != 'multipart/related') {
                             continue;
                         }
diff --git a/program/include/rcube_output_html.php b/program/include/rcube_output_html.php
index 6138e2a..616ab38 100644
--- a/program/include/rcube_output_html.php
+++ b/program/include/rcube_output_html.php
@@ -77,6 +77,9 @@
         $this->set_skin($skin);
         $this->set_env('skin', $skin);
 
+        if (!empty($_REQUEST['_extwin']))
+          $this->set_env('extwin', 1);
+
         // add common javascripts
         $this->add_script('var '.rcmail::JS_OBJECT_NAME.' = new rcube_webmail();', 'head_top');
 
@@ -274,6 +277,8 @@
      */
     public function redirect($p = array(), $delay = 1)
     {
+        if ($this->env['extwin'])
+            $p['extwin'] = 1;
         $location = $this->app->url($p);
         header('Location: ' . $location);
         exit;
@@ -974,7 +979,7 @@
             else if (in_array($attrib['command'], $a_static_commands)) {
                 $attrib['href'] = $this->app->url(array('action' => $attrib['command']));
             }
-            else if ($attrib['command'] == 'permaurl' && !empty($this->env['permaurl'])) {
+            else if (($attrib['command'] == 'permaurl' || $attrib['command'] == 'extwin') && !empty($this->env['permaurl'])) {
               $attrib['href'] = $this->env['permaurl'];
             }
         }
@@ -1319,6 +1324,10 @@
         $hiddenfield = new html_hiddenfield(array('name' => '_framed', 'value' => '1'));
         $hidden = $hiddenfield->show();
       }
+      if ($this->env['extwin']) {
+        $hiddenfield = new html_hiddenfield(array('name' => '_extwin', 'value' => '1'));
+        $hidden = $hiddenfield->show();
+      }
 
       if (!$content)
         $attrib['noclose'] = true;
diff --git a/program/js/app.js b/program/js/app.js
index 06eb929..7e55a33 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -176,10 +176,10 @@
     }
 
     // enable general commands
-    this.enable_command('logout', 'mail', 'addressbook', 'settings', 'save-pref', 'compose', 'undo', 'about', 'switch-task', true);
+    this.enable_command('close', 'logout', 'mail', 'addressbook', 'settings', 'save-pref', 'compose', 'undo', 'about', 'switch-task', true);
 
     if (this.env.permaurl)
-      this.enable_command('permaurl', true);
+      this.enable_command('permaurl', 'extwin', true);
 
     switch (this.task) {
 
@@ -249,7 +249,7 @@
           }
         }
         else if (this.env.action == 'compose') {
-          this.env.compose_commands = ['send-attachment', 'remove-attachment', 'send', 'cancel', 'toggle-editor', 'list-adresses'];
+          this.env.compose_commands = ['send-attachment', 'remove-attachment', 'send', 'cancel', 'toggle-editor', 'list-adresses', 'extwin'];
 
           if (this.env.drafts_mailbox)
             this.env.compose_commands.push('savedraft')
@@ -570,6 +570,19 @@
           parent.location.href = this.env.permaurl;
         break;
 
+      case 'extwin':
+        if (this.env.action == 'compose') {
+          var prevstate = this.env.compose_extwin;
+          $("input[name='_action']", this.gui_objects.messageform).val('compose');
+          this.gui_objects.messageform.action = this.url('mail/compose', { _id: this.env.compose_id, _extwin: 1 });
+          this.gui_objects.messageform.target = this.open_window('about:blank', 1150, 900);
+          this.gui_objects.messageform.submit();
+        }
+        else {
+          this.open_window(this.env.permaurl, 1000, 1200);
+        }
+        break;
+
       case 'menu-open':
       case 'menu-save':
         this.triggerEvent(command, {props:props});
@@ -582,10 +595,18 @@
         }
         break;
 
+      case 'close':
+        if (this.env.extwin)
+          window.close();
+        break;
+
       case 'list':
         if (props && props != '')
           this.reset_qsearch();
-        if (this.task == 'mail') {
+        if (this.env.action == 'compose' && this.env.extwin) {
+          window.close();
+        }
+        else if (this.task == 'mail') {
           this.list_mailbox(props);
           this.set_button_titles();
         }
@@ -641,7 +662,7 @@
           uid = this.get_single_uid();
           if (uid && (!this.env.uid || uid != this.env.uid)) {
             if (this.env.mailbox == this.env.drafts_mailbox)
-              this.goto_url('compose', { _draft_uid: uid, _mbox: this.env.mailbox }, true);
+              this.open_compose_step({ _draft_uid: uid, _mbox: this.env.mailbox });
             else
               this.show_message(uid);
           }
@@ -670,7 +691,7 @@
         else if (this.task == 'mail' && (cid = this.get_single_uid())) {
           url = { _mbox: this.env.mailbox };
           url[this.env.mailbox == this.env.drafts_mailbox && props != 'new' ? '_draft_uid' : '_uid'] = cid;
-          this.goto_url('compose', url, true);
+          this.open_compose_step(url);
         }
         break;
 
@@ -863,47 +884,46 @@
         break;
 
       case 'compose':
-        url = this.url('mail/compose');
+        url = {};
 
         if (this.task == 'mail') {
-          url += '&_mbox='+urlencode(this.env.mailbox);
+          url._mbox = this.env.mailbox;
           if (props)
-             url += '&_to='+urlencode(props);
+             url._to = props;
           // also send search request so we can go back to search result after message is sent
           if (this.env.search_request)
-            url += '&_search='+this.env.search_request;
+            url._search = this.env.search_request;
         }
         // modify url if we're in addressbook
         else if (this.task == 'addressbook') {
           // switch to mail compose step directly
           if (props && props.indexOf('@') > 0) {
-            url = this.get_task_url('mail', url);
-            this.redirect(url + '&_to='+urlencode(props));
+            url._to = props;
+          }
+          else {
+            // use contact_id passed as command parameter
+            var n, len, a_cids = [];
+            if (props)
+              a_cids.push(props);
+            // get selected contacts
+            else if (this.contact_list) {
+              var selection = this.contact_list.get_selection();
+              for (n=0, len=selection.length; n<len; n++)
+                a_cids.push(selection[n]);
+            }
+
+            if (a_cids.length)
+              this.http_post('mailto', { _cid: a_cids.join(','), _source: this.env.source, }, true);
+            else if (this.env.group)
+              this.http_post('mailto', { _gid: this.env.group, _source: this.env.source }, true);
+
             break;
           }
-
-          // use contact_id passed as command parameter
-          var n, len, a_cids = [];
-          if (props)
-            a_cids.push(props);
-          // get selected contacts
-          else if (this.contact_list) {
-            var selection = this.contact_list.get_selection();
-            for (n=0, len=selection.length; n<len; n++)
-              a_cids.push(selection[n]);
-          }
-
-          if (a_cids.length)
-            this.http_post('mailto', { _cid: a_cids.join(','), _source: this.env.source}, true);
-          else if (this.env.group)
-            this.http_post('mailto', { _gid: this.env.group, _source: this.env.source}, true);
-
-          break;
         }
         else if (props)
-          url += '&_to='+urlencode(props);
+          url._to = props;
 
-        this.redirect(url);
+        this.open_compose_step(url);
         break;
 
       case 'spellcheck':
@@ -978,7 +998,7 @@
           else if (command == 'reply-list')
             url._all = 'list';
 
-          this.goto_url('compose', url, true);
+          this.open_compose_step(url);
         }
         break;
 
@@ -988,7 +1008,7 @@
           url = { _forward_uid: uid, _mbox: this.env.mailbox };
           if (command == 'forward-attachment' || (!props && this.env.forward_attachment))
             url._attachment = 1;
-          this.goto_url('compose', url, true);
+          this.open_compose_step(url);
         }
         break;
 
@@ -1562,7 +1582,7 @@
 
     var uid = list.get_single_selection();
     if (uid && this.env.mailbox == this.env.drafts_mailbox)
-      this.goto_url('compose', { _draft_uid: uid, _mbox: this.env.mailbox }, true);
+      this.open_compose_step({ _draft_uid: uid, _mbox: this.env.mailbox });
     else if (uid)
       this.show_message(uid, false, false);
   };
@@ -1642,6 +1662,21 @@
     }
 
     return allow ? (copy ? 2 : 1) : 0;
+  };
+
+  this.open_window = function(url, width, height)
+  {
+    var w = Math.min(width, screen.width - 10),
+      h = Math.min(height, screen.height - 100),
+      l = (screen.width - w) / 2 + (screen.left || 0),
+      t = Math.max(0, (screen.height - h) / 2 + (screen.top || 0) - 20);
+
+    var wname = 'rcmextwin' + new Date().getTime(),
+      extwin = window.open(url + '&_extwin=1', wname, 'width='+w+',height='+h+',top='+t+',left='+l);
+    extwin.moveTo(l,t);
+    window.setTimeout(function(){ extwin.focus(); }, 10);
+
+    return wname;
   };
 
 
@@ -1907,7 +1942,7 @@
       this.list_mailbox('', '', sort_col+'_'+sort_order, post_data);
   };
 
-  // when user doble-clicks on a row
+  // when user double-clicks on a row
   this.show_message = function(id, safe, preview)
   {
     if (!id)
@@ -1932,10 +1967,17 @@
     // add browser capabilities, so we can properly handle attachments
     url += '&_caps='+urlencode(this.browser_capabilities());
 
-    if (preview && String(target.location.href).indexOf(url) >= 0)
+    if (this.env.extwin)
+      url += '&_extwin=1';
+
+    if (preview && String(target.location.href).indexOf(url) >= 0) {
       this.show_contentframe(true);
+    }
     else {
-      this.location_href(this.env.comm_path+url, target, true);
+      if (!preview && this.env.message_extwin && !this.env.extwin)
+        this.open_window(this.env.comm_path+url, 1000, 1200);
+      else
+        this.location_href(this.env.comm_path+url, target, true);
 
       // mark as read and change mbox unread counter
       if (preview && this.message_list && this.message_list.rows[id] && this.message_list.rows[id].unread && this.env.preview_pane_mark_read >= 0) {
@@ -2963,6 +3005,17 @@
   /*********        message compose methods        *********/
   /*********************************************************/
 
+  this.open_compose_step = function(p)
+  {
+    var url = this.url('mail/compose', p);
+
+    // open new compose window
+    if (this.env.compose_extwin)
+      this.open_window(url, 1150, 900);
+    else
+      this.redirect(url);
+  };
+
   // init message compose form: set focus and eventhandlers
   this.init_messageform = function()
   {
@@ -2976,6 +3029,11 @@
       html_mode = $("input[name='_is_html']").val() == '1',
       ac_fields = ['cc', 'bcc', 'replyto', 'followupto'],
       ac_props;
+
+    // copy contents from opener (after opening in a new window)
+    if (window.opener && opener.rcmail && opener.rcmail.env.action == 'compose') {
+      //opener.history.back();
+    }
 
     // configure parallel autocompletion
     if (this.env.autocomplete_threads > 0) {
@@ -3631,8 +3689,16 @@
   this.sent_successfully = function(type, msg)
   {
     this.display_message(msg, type);
-    // before redirect we need to wait some time for Chrome (#1486177)
-    setTimeout(function(){ ref.list_mailbox(); }, 500);
+
+    if (this.env.extwin && window.opener && opener.rcmail) {
+      this.lock_form(this.gui_objects.messageform);
+      opener.rcmail.display_message(msg, type);
+      setTimeout(function(){ window.close() }, 1000);
+    }
+    else {
+      // before redirect we need to wait some time for Chrome (#1486177)
+      setTimeout(function(){ ref.list_mailbox(); }, 500);
+    }
   };
 
 
diff --git a/program/localization/en_US/labels.inc b/program/localization/en_US/labels.inc
index fbc154b..fcf7fac 100644
--- a/program/localization/en_US/labels.inc
+++ b/program/localization/en_US/labels.inc
@@ -383,6 +383,8 @@
 $labels['pagesize']  = 'Rows per page';
 $labels['signature'] = 'Signature';
 $labels['dstactive']  = 'Daylight saving time';
+$labels['showinextwin'] = 'Open message in a new window';
+$labels['composeextwin'] = 'Compose in a new window';
 $labels['htmleditor'] = 'Compose HTML messages';
 $labels['htmlonreply'] = 'on reply to HTML message';
 $labels['htmlonreplyandforward'] = 'on forward or reply to HTML message';
diff --git a/program/steps/addressbook/func.inc b/program/steps/addressbook/func.inc
index 4ef4d1b..3a05080 100644
--- a/program/steps/addressbook/func.inc
+++ b/program/steps/addressbook/func.inc
@@ -87,6 +87,7 @@
     $OUTPUT->set_env('search_mods', $search_mods);
     $OUTPUT->set_env('address_sources', $js_list);
     $OUTPUT->set_env('writable_source', $writeable);
+    $OUTPUT->set_env('compose_extwin', $RCMAIL->config->get('compose_extwin',false));
 
     $OUTPUT->set_pagetitle(rcube_label('addressbook'));
     $_SESSION['addressbooks_count'] = $count;
diff --git a/program/steps/addressbook/mailto.inc b/program/steps/addressbook/mailto.inc
index 3806c2c..c3cbcad 100644
--- a/program/steps/addressbook/mailto.inc
+++ b/program/steps/addressbook/mailto.inc
@@ -68,7 +68,7 @@
     $mailto_str = join(', ', $mailto);
     $mailto_id = substr(md5($mailto_str), 0, 16);
     $_SESSION['mailto'][$mailto_id] = urlencode($mailto_str);
-    $OUTPUT->redirect(array('task' => 'mail', '_action' => 'compose', '_mailto' => $mailto_id));
+    $OUTPUT->command('open_compose_step', array('_mailto' => $mailto_id));
 }
 else {
     $OUTPUT->show_message('nocontactsfound', 'warning');
diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc
index 691eca2..24cd5e4 100644
--- a/program/steps/mail/compose.inc
+++ b/program/steps/mail/compose.inc
@@ -130,6 +130,7 @@
     'fileuploaderror', 'sendmessage');
 
 $OUTPUT->set_env('compose_id', $COMPOSE['id']);
+$OUTPUT->set_pagetitle(rcube_label('compose'));
 
 // add config parameters to client script
 if (!empty($CONFIG['drafts_mbox'])) {
@@ -606,7 +607,10 @@
 
   $html_editor = intval($RCMAIL->config->get('htmleditor'));
 
-  if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) {
+  if (isset($_POST['_is_html'])) {
+    $useHtml = !empty($_POST['_is_html']);
+  }
+  else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) {
     $useHtml = $MESSAGE->has_html_part(false);
   }
   else if ($compose_mode == RCUBE_COMPOSE_REPLY) {
@@ -1445,7 +1449,9 @@
   $attrib['value'] = '1';
   $checkbox = new html_checkbox($attrib);
 
-  if (in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT)))
+  if (isset($_POST['_receipt']))
+    $mdn_default = $_POST['_receipt'];
+  else if (in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT)))
     $mdn_default = (bool) $MESSAGE->headers->mdn_to;
   else
     $mdn_default = $RCMAIL->config->get('mdn_default');
@@ -1472,8 +1478,13 @@
   $attrib['value'] = '1';
   $checkbox = new html_checkbox($attrib);
 
+  if (isset($_POST['_dsn']))
+    $dsn_value = $_POST['_dsn'];
+  else
+    $dsn_value = $RCMAIL->config->get('dsn_default');
+
   $out = $form_start ? "$form_start\n" : '';
-  $out .= $checkbox->show($RCMAIL->config->get('dsn_default'));
+  $out .= $checkbox->show($dsn_value);
   $out .= $form_end ? "\n$form_end" : '';
 
   return $out;
@@ -1520,7 +1531,7 @@
     'folder_filter' => 'mail',
     'folder_rights' => 'w',
   )));
-  return $select->show($COMPOSE['param']['sent_mbox'], $attrib);
+  return $select->show(isset($_POST['_store_target']) ? $_POST['_store_target'] : $COMPOSE['param']['sent_mbox'], $attrib);
 }
 
 
diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index c212025..c18d2cd 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -101,18 +101,11 @@
     $OUTPUT->set_env('quota', true);
   }
 
-  if ($CONFIG['delete_junk'])
-    $OUTPUT->set_env('delete_junk', true);
-  if ($CONFIG['flag_for_deletion'])
-    $OUTPUT->set_env('flag_for_deletion', true);
-  if ($CONFIG['read_when_deleted'])
-    $OUTPUT->set_env('read_when_deleted', true);
-  if ($CONFIG['skip_deleted'])
-    $OUTPUT->set_env('skip_deleted', true);
-  if ($CONFIG['display_next'])
-    $OUTPUT->set_env('display_next', true);
-  if ($CONFIG['forward_attachment'])
-    $OUTPUT->set_env('forward_attachment', true);
+  foreach (array('delete_junk','flag_for_deletion','read_when_deleted','skip_deleted','display_next','message_extwin','compose_extwin','forward_attachment') as $prop) {
+    if ($CONFIG[$prop])
+      $OUTPUT->set_env($prop, true);
+  }
+
   if ($CONFIG['trash_mbox'])
     $OUTPUT->set_env('trash_mailbox', $CONFIG['trash_mbox']);
   if ($CONFIG['drafts_mbox'])
diff --git a/program/steps/mail/show.inc b/program/steps/mail/show.inc
index 029bc5f..f896607 100644
--- a/program/steps/mail/show.inc
+++ b/program/steps/mail/show.inc
@@ -59,6 +59,7 @@
   $OUTPUT->set_env('permaurl', rcmail_url('show', array('_uid' => $MESSAGE->uid, '_mbox' => $mbox_name)));
   $OUTPUT->set_env('delimiter', $RCMAIL->storage->get_hierarchy_delimiter());
   $OUTPUT->set_env('mailbox', $mbox_name);
+  $OUTPUT->set_env('compose_extwin', $RCMAIL->config->get('compose_extwin',false));
 
   // mimetypes supported by the browser (default settings)
   $mimetypes = $RCMAIL->config->get('client_mimetypes', 'text/plain,text/html,text/xml,image/jpeg,image/gif,image/png,image/bmp,image/tiff,application/x-javascript,application/pdf,application/x-shockwave-flash');
diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc
index c60d17f..e946306 100644
--- a/program/steps/settings/func.inc
+++ b/program/steps/settings/func.inc
@@ -129,8 +129,8 @@
 
   $sections['general'] = array('id' => 'general', 'section' => rcube_label('uisettings'));
   $sections['mailbox'] = array('id' => 'mailbox', 'section' => rcube_label('mailboxview'));
-  $sections['compose'] = array('id' => 'compose', 'section' => rcube_label('messagescomposition'));
   $sections['mailview'] = array('id' => 'mailview','section' => rcube_label('messagesdisplaying'));
+  $sections['compose'] = array('id' => 'compose', 'section' => rcube_label('messagescomposition'));
   $sections['addressbook'] = array('id' => 'addressbook','section' => rcube_label('addressbook'));
   $sections['folders'] = array('id' => 'folders', 'section' => rcube_label('specialfolders'));
   $sections['server'] = array('id' => 'server',  'section' => rcube_label('serversettings'));
@@ -414,6 +414,17 @@
       'main' => array('name' => Q(rcube_label('mainoptions'))),
     );
 
+    // show checkbox to open message view in new window
+    if (!isset($no_override['message_extwin'])) {
+      $field_id = 'rcmfd_message_extwin';
+      $input_msgextwin = new html_checkbox(array('name' => '_message_extwin', 'id' => $field_id, 'value' => 1));
+
+      $blocks['main']['options']['message_extwin'] = array(
+        'title' => html::label($field_id, Q(rcube_label('showinextwin'))),
+        'content' => $input_msgextwin->show($config['message_extwin']?1:0),
+      );
+    }
+
     // show checkbox for HTML/plaintext messages
     if (!isset($no_override['prefer_html'])) {
       $field_id = 'rcmfd_htmlmsg';
@@ -483,6 +494,17 @@
       'sig'        => array('name' => Q(rcube_label('signatureoptions'))),
     );
 
+    // show checkbox to compose messages in a new window
+    if (!isset($no_override['compose_extwin'])) {
+      $field_id = 'rcmfdcompose_extwin';
+      $input_compextwin = new html_checkbox(array('name' => '_compose_extwin', 'id' => $field_id, 'value' => 1));
+
+      $blocks['main']['options']['compose_extwin'] = array(
+        'title' => html::label($field_id, Q(rcube_label('composeextwin'))),
+        'content' => $input_compextwin->show($config['compose_extwin']?1:0),
+      );
+    }
+
     if (!isset($no_override['htmleditor'])) {
       $field_id = 'rcmfd_htmleditor';
       $select_htmleditor = new html_select(array('name' => '_htmleditor', 'id' => $field_id));
diff --git a/program/steps/settings/save_prefs.inc b/program/steps/settings/save_prefs.inc
index d1627ec..db7b134 100644
--- a/program/steps/settings/save_prefs.inc
+++ b/program/steps/settings/save_prefs.inc
@@ -59,6 +59,7 @@
 
   case 'mailview':
     $a_user_prefs = array(
+      'message_extwin'  => intval($_POST['_message_extwin']),
       'prefer_html'     => isset($_POST['_prefer_html']) ? TRUE : FALSE,
       'inline_images'   => isset($_POST['_inline_images']) ? TRUE : FALSE,
       'show_images'     => isset($_POST['_show_images']) ? intval($_POST['_show_images']) : 0,
@@ -70,6 +71,7 @@
 
   case 'compose':
     $a_user_prefs = array(
+      'compose_extwin'     => intval($_POST['_compose_extwin']),
       'htmleditor'         => intval($_POST['_htmleditor']),
       'draft_autosave'     => isset($_POST['_draft_autosave']) ? intval($_POST['_draft_autosave']) : 0,
       'mime_param_folding' => isset($_POST['_mime_param_folding']) ? intval($_POST['_mime_param_folding']) : 0,
diff --git a/skins/larry/includes/header.html b/skins/larry/includes/header.html
index 9187c6f..25bcc0b 100644
--- a/skins/larry/includes/header.html
+++ b/skins/larry/includes/header.html
@@ -7,11 +7,16 @@
 		<roundcube:endif />
 	</div>
 	<div class="topright">
-	<span class="username"><roundcube:object name="username" /></span>
-	<roundcube:button command="logout" label="logout" class="button-logout" />
+	<roundcube:if condition="!env:extwin" />
+		<span class="username"><roundcube:object name="username" /></span>
+		<roundcube:button command="logout" label="logout" class="button-logout" />
+	<roundcube:else />
+		<roundcube:button command="close" label="close" class="closelink" />
+	<roundcube:endif />
 	</div>
 </div>
 
+<roundcube:if condition="!env:extwin" />
 <div id="topnav">
 	<div id="taskbar" class="topright">
 	<roundcube:button command="mail" label="mail" class="button-mail" classSel="button-mail button-selected" innerClass="button-inner" />
@@ -21,6 +26,7 @@
 	</div>
 	<roundcube:object name="logo" src="/images/roundcube_logo.png" id="toplogo" border="0" alt="Logo" onclick="rcmail.command('switch-task','mail');return false;" />
 </div>
+<roundcube:endif />
 
 <br style="clear:both" />
 </div>
diff --git a/skins/larry/mail.css b/skins/larry/mail.css
index a275663..b819e77 100644
--- a/skins/larry/mail.css
+++ b/skins/larry/mail.css
@@ -30,6 +30,10 @@
 	z-index: 3;
 }
 
+#mailview-right.fullwidth {
+	left: 0;
+}
+
 #mailview-top {
 	position: absolute;
 	top: 42px;
diff --git a/skins/larry/styles.css b/skins/larry/styles.css
index 3406880..be43668 100644
--- a/skins/larry/styles.css
+++ b/skins/larry/styles.css
@@ -637,6 +637,10 @@
 	bottom: 20px;
 }
 
+.extwin #mainscreen {
+	top: 40px;
+}
+
 #mainscreen.offset {
 	top: 130px;
 }
diff --git a/skins/larry/templates/compose.html b/skins/larry/templates/compose.html
index d29c1bd..33f4ba3 100644
--- a/skins/larry/templates/compose.html
+++ b/skins/larry/templates/compose.html
@@ -7,7 +7,7 @@
 <link rel="stylesheet" type="text/css" href="/googiespell.css" />
 <roundcube:endif />
 </head>
-<body>
+<roundcube:if condition="env:extwin" /><body class="extwin"><roundcube:else /><body><roundcube:endif />
 
 <div class="minwidth">
 <roundcube:include file="/includes/header.html" />
@@ -108,10 +108,11 @@
 </tbody>
 </table>
 
-<div id="composebuttons" class="formbuttons">
+<div id="composebuttons" class="pagenav formbuttons">
 	<roundcube:button type="input" command="send" class="button mainaction" label="sendmessage" tabindex="11" />
 	<roundcube:button type="input" command="savedraft" class="button" label="savemessage" tabindex="12" />
 	<roundcube:button type="input" command="list" class="button" label="cancel" tabindex="13" />
+	<roundcube:button command="extwin" type="link" class="button extwin" classSel="button extwin pressed" innerClass="inner" title="openinextwin" content="[]" condition="!env:extwin" />
 </div>
 
 </div>
diff --git a/skins/larry/templates/message.html b/skins/larry/templates/message.html
index e99f206..92bb358 100644
--- a/skins/larry/templates/message.html
+++ b/skins/larry/templates/message.html
@@ -4,7 +4,7 @@
 <title><roundcube:object name="pagetitle" /></title>
 <roundcube:include file="/includes/links.html" />
 </head>
-<body class="noscroll">
+<roundcube:if condition="env:extwin" /><body class="noscroll extwin"><roundcube:else /><body class="noscroll"><roundcube:endif />
 
 <roundcube:include file="/includes/header.html" />
 
@@ -12,13 +12,17 @@
 
 <!-- toolbar -->
 <div id="messagetoolbar" class="toolbar fullwidth">
+<roundcube:if condition="!env:extwin" />
 	<roundcube:button command="list" type="link" class="button back disabled" classAct="button back" classSel="button back pressed" label="back" />
 	<span class="spacer"></span>
+<roundcube:endif />
 	<roundcube:include file="/includes/mailtoolbar.html" />
 	<div class="toolbarselect">
 		<roundcube:object name="mailboxlist" type="select" noSelection="moveto" maxlength="25" onchange="rcmail.command('moveto', this.options[this.selectedIndex].value)" class="mailboxlist decorated" folder_filter="mail" />
 	</div>
 </div>
+
+<roundcube:if condition="!env:extwin" />
 
 <div id="mailview-left">
 
@@ -32,6 +36,10 @@
 </div>
 
 <div id="mailview-right" class="offset uibox">
+<roundcube:else />
+
+<div id="mailview-right" class="offset fullwidth uibox">
+<roundcube:endif />
 
 <div id="messageheader">
 <span id="previewheaderstoggle"></span>
diff --git a/skins/larry/templates/messagepreview.html b/skins/larry/templates/messagepreview.html
index de02b05..ae1a3ac 100644
--- a/skins/larry/templates/messagepreview.html
+++ b/skins/larry/templates/messagepreview.html
@@ -36,7 +36,7 @@
 	<roundcube:button command="forward" type="link" class="button forward" classSel="button forward pressed" innerClass="inner" title="forwardmessage" content="-&gt;" />
 	&nbsp;
 <roundcube:endif />
-	<roundcube:button command="permaurl" type="link" class="button extwin" classSel="button extwin pressed" innerClass="inner" title="openinextwin" content="[]" target="_blank" />
+	<roundcube:button command="extwin" type="link" class="button extwin" classSel="button extwin pressed" innerClass="inner" title="openinextwin" content="[]" />
 </div>
 
 </div>

--
Gitblit v1.9.1