From 669747a81c4b2ff823d1f20dc50899163c0a8a4a Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Thu, 28 Jun 2012 03:22:31 -0400
Subject: [PATCH] Merge branch 'master' of github.com:roundcube/roundcubemail

---
 skins/default/templates/contactedit.html |    2 
 program/steps/addressbook/edit.inc       |   15 +++
 program/include/rcube_imap_cache.php     |  117 ++++++++++++++---------------
 skins/default/templates/contactadd.html  |    1 
 skins/larry/templates/contactedit.html   |    1 
 skins/default/addressbook.css            |    7 +
 skins/larry/addressbook.css              |   23 +++++
 program/include/rcube_imap_generic.php   |   27 +++++-
 program/js/app.js                        |   35 ++++----
 9 files changed, 146 insertions(+), 82 deletions(-)

diff --git a/program/include/rcube_imap_cache.php b/program/include/rcube_imap_cache.php
index eb2df16..530284a 100644
--- a/program/include/rcube_imap_cache.php
+++ b/program/include/rcube_imap_cache.php
@@ -516,7 +516,6 @@
                     .($uids !== null ? " AND uid IN (".$this->db->array2list((array)$uids, 'integer').")" : ""),
                 $this->userid, $mailbox);
         }
-
     }
 
 
@@ -917,16 +916,15 @@
             return;
         }
 
-        // NOTE: make sure the mailbox isn't selected, before
-        // enabling QRESYNC and invoking SELECT
-        if ($this->imap->conn->selected !== null) {
-            $this->imap->conn->close();
-        }
-
         // Enable QRESYNC
         $res = $this->imap->conn->enable($qresync ? 'QRESYNC' : 'CONDSTORE');
-        if (!is_array($res)) {
+        if ($res === false) {
             return;
+        }
+
+        // Close mailbox if already selected to get most recent data
+        if ($this->imap->conn->selected == $mailbox) {
+            $this->imap->conn->close();
         }
 
         // Get mailbox data (UIDVALIDITY, HIGHESTMODSEQ, counters, etc.)
@@ -952,8 +950,10 @@
             return;
         }
 
-        // Get known uids
-        $uids = array();
+        $uids    = array();
+        $removed = array();
+
+        // Get known UIDs
         $sql_result = $this->db->query(
             "SELECT uid"
             ." FROM ".$this->db->table_name('cache_messages')
@@ -962,74 +962,69 @@
             $this->userid, $mailbox);
 
         while ($sql_arr = $this->db->fetch_assoc($sql_result)) {
-          $uids[] = $sql_arr['uid'];
+            $uids[] = $sql_arr['uid'];
         }
 
-        // No messages in database, nothing to sync
-        if (empty($uids)) {
-            return;
-        }
+        // Synchronize messages data
+        if (!empty($uids)) {
+            // Get modified flags and vanished messages
+            // UID FETCH 1:* (FLAGS) (CHANGEDSINCE 0123456789 VANISHED)
+            $result = $this->imap->conn->fetch($mailbox,
+                $uids, true, array('FLAGS'), $index['modseq'], $qresync);
 
-        // Get modified flags and vanished messages
-        // UID FETCH 1:* (FLAGS) (CHANGEDSINCE 0123456789 VANISHED)
-        $result = $this->imap->conn->fetch($mailbox,
-            !empty($uids) ? $uids : '1:*', true, array('FLAGS'),
-            $index['modseq'], $qresync);
-
-        $invalidated = false;
-
-        if (!empty($result)) {
-            foreach ($result as $id => $msg) {
-                $uid = $msg->uid;
-                // Remove deleted message
-                if ($this->skip_deleted && !empty($msg->flags['DELETED'])) {
-                    $this->remove_message($mailbox, $uid);
-
-                    if (!$invalidated) {
-                        $invalidated = true;
-                        // Invalidate thread indexes (?)
-                        $this->remove_thread($mailbox);
+            if (!empty($result)) {
+                foreach ($result as $id => $msg) {
+                    $uid = $msg->uid;
+                    // Remove deleted message
+                    if ($this->skip_deleted && !empty($msg->flags['DELETED'])) {
+                        $removed[] = $uid;
                         // Invalidate index
                         $index['valid'] = false;
+                        continue;
                     }
-                    continue;
-                }
 
-                $flags = 0;
-                if (!empty($msg->flags)) {
-                    foreach ($this->flags as $idx => $flag)
-                        if (!empty($msg->flags[$flag]))
-                            $flags += $idx;
-                }
+                    $flags = 0;
+                    if (!empty($msg->flags)) {
+                        foreach ($this->flags as $idx => $flag) {
+                            if (!empty($msg->flags[$flag])) {
+                                $flags += $idx;
+                            }
+                        }
+                    }
 
-                $this->db->query(
-                    "UPDATE ".$this->db->table_name('cache_messages')
-                    ." SET flags = ?, changed = ".$this->db->now()
-                    ." WHERE user_id = ?"
-                        ." AND mailbox = ?"
-                        ." AND uid = ?"
-                        ." AND flags <> ?",
-                    $flags, $this->userid, $mailbox, $uid, $flags);
+                    $this->db->query(
+                        "UPDATE ".$this->db->table_name('cache_messages')
+                        ." SET flags = ?, changed = ".$this->db->now()
+                        ." WHERE user_id = ?"
+                            ." AND mailbox = ?"
+                            ." AND uid = ?"
+                            ." AND flags <> ?",
+                        $flags, $this->userid, $mailbox, $uid, $flags);
+                }
             }
-        }
 
-        // Get VANISHED
-        if ($qresync) {
-            $mbox_data = $this->imap->folder_data($mailbox);
+            // VANISHED found?
+            if ($qresync) {
+                $mbox_data = $this->imap->folder_data($mailbox);
 
-            // Removed messages
-            if (!empty($mbox_data['VANISHED'])) {
+                // Removed messages found
                 $uids = rcube_imap_generic::uncompressMessageSet($mbox_data['VANISHED']);
                 if (!empty($uids)) {
-                    // remove messages from database
-                    $this->remove_message($mailbox, $uids);
-
-                    // Invalidate thread indexes (?)
-                    $this->remove_thread($mailbox);
+                    $removed = array_merge($removed, $uids);
                     // Invalidate index
                     $index['valid'] = false;
                 }
             }
+
+            // remove messages from database
+            if (!empty($removed)) {
+                $this->remove_message($mailbox, $removed);
+            }
+        }
+
+        // Invalidate thread index (?)
+        if (!$index['valid']) {
+            $this->remove_thread($mailbox);
         }
 
         $sort_field = $index['sort_field'];
diff --git a/program/include/rcube_imap_generic.php b/program/include/rcube_imap_generic.php
index 959dd9f..197164d 100644
--- a/program/include/rcube_imap_generic.php
+++ b/program/include/rcube_imap_generic.php
@@ -1472,14 +1472,31 @@
      */
     function enable($extension)
     {
-        if (empty($extension))
+        if (empty($extension)) {
             return false;
+        }
 
-        if (!$this->hasCapability('ENABLE'))
+        if (!$this->hasCapability('ENABLE')) {
             return false;
+        }
 
-        if (!is_array($extension))
+        if (!is_array($extension)) {
             $extension = array($extension);
+        }
+
+        if (!empty($this->extensions_enabled)) {
+            // check if all extensions are already enabled
+            $diff = array_diff($extension, $this->extensions_enabled);
+
+            if (empty($diff)) {
+                return $extension;
+            }
+
+            // Make sure the mailbox isn't selected, before enabling extension(s)
+            if ($this->selected !== null) {
+                $this->close();
+            }
+        }
 
         list($code, $response) = $this->execute('ENABLE', $extension);
 
@@ -1487,7 +1504,9 @@
             $response = substr($response, 10); // remove prefix "* ENABLED "
             $result   = (array) $this->tokenizeResponse($response);
 
-            return $result;
+            $this->extensions_enabled = array_unique(array_merge((array)$this->extensions_enabled, $result));
+
+            return $this->extensions_enabled;
         }
 
         return false;
diff --git a/program/js/app.js b/program/js/app.js
index ce75704..a2307fd 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -4715,11 +4715,11 @@
   {
     if (form && form.elements._photo.value) {
       this.async_upload_form(form, 'upload-photo', function(e) {
-        rcmail.set_busy(false, null, rcmail.photo_upload_id);
+        rcmail.set_busy(false, null, rcmail.file_upload_id);
       });
 
       // display upload indicator
-      this.photo_upload_id = this.set_busy(true, 'uploading');
+      this.file_upload_id = this.set_busy(true, 'uploading');
     }
   };
 
@@ -4734,8 +4734,8 @@
 
   this.photo_upload_end = function()
   {
-    this.set_busy(false, null, this.photo_upload_id);
-    delete this.photo_upload_id;
+    this.set_busy(false, null, this.file_upload_id);
+    delete this.file_upload_id;
   };
 
   this.set_photo_actions = function(id)
@@ -6254,7 +6254,7 @@
     // prepare multipart form data composition
     var files = e.target.files || e.dataTransfer.files,
       formdata = window.FormData ? new FormData() : null,
-      fieldname = this.env.filedrop.fieldname || '_file',
+      fieldname = (this.env.filedrop.fieldname || '_file') + (this.env.filedrop.single ? '' : '[]'),
       boundary = '------multipartformboundary' + (new Date).getTime(),
       dashdash = '--', crlf = '\r\n',
       multipart = dashdash + boundary + crlf;
@@ -6269,7 +6269,8 @@
         content = '<span>' + (multiple ? ref.get_label('uploadingmany') : files[0].name) + '</span>';
 
       // add to attachments list
-      ref.add2attachment_list(ts, { name:'', html:content, classname:'uploading', complete:false });
+      if (!ref.add2attachment_list(ts, { name:'', html:content, classname:'uploading', complete:false }))
+        ref.file_upload_id = ref.set_busy(true, 'uploading');
 
       // complete multipart content and post request
       multipart += dashdash + boundary + dashdash + crlf;
@@ -6277,7 +6278,7 @@
       $.ajax({
         type: 'POST',
         dataType: 'json',
-        url: ref.url(ref.env.filedrop.action||'upload', { _id:ref.env.compose_id||'', _uploadid:ts, _remote:1 }),
+        url: ref.url(ref.env.filedrop.action||'upload', { _id:ref.env.compose_id||ref.env.cid||'', _uploadid:ts, _remote:1 }),
         contentType: formdata ? false : 'multipart/form-data; boundary=' + boundary,
         processData: false,
         data: formdata || multipart,
@@ -6289,7 +6290,7 @@
 
     // get contents of all dropped files
     var last = this.env.filedrop.single ? 0 : files.length - 1;
-    for (var i=0, f; i <= last && (f = files[i]); i++) {
+    for (var j=0, i=0, f; j <= last && (f = files[i]); i++) {
       if (!f.name) f.name = f.fileName;
       if (!f.size) f.size = f.fileSize;
       if (!f.type) f.type = 'application/octet-stream';
@@ -6306,8 +6307,8 @@
 
       // do it the easy way with FormData (FF 4+, Chrome 5+, Safari 5+)
       if (formdata) {
-        formdata.append(fieldname + '[]', f);
-        if (i == last)
+        formdata.append(fieldname, f);
+        if (j == last)
           return submit_data();
       }
       // use FileReader supporetd by Firefox 3.6
@@ -6315,33 +6316,35 @@
         var reader = new FileReader();
 
         // closure to pass file properties to async callback function
-        reader.onload = (function(file, i) {
+        reader.onload = (function(file, j) {
           return function(e) {
-            multipart += 'Content-Disposition: form-data; name="' + fieldname + '[]"';
+            multipart += 'Content-Disposition: form-data; name="' + fieldname + '"';
             multipart += '; filename="' + (f.name_bin || file.name) + '"' + crlf;
             multipart += 'Content-Length: ' + file.size + crlf;
             multipart += 'Content-Type: ' + file.type + crlf + crlf;
             multipart += e.target.result + crlf;
             multipart += dashdash + boundary + crlf;
 
-            if (i == last)  // we're done, submit the data
+            if (j == last)  // we're done, submit the data
               return submit_data();
           }
-        })(f,i);
+        })(f,j);
         reader.readAsBinaryString(f);
       }
       // Firefox 3
       else if (f.getAsBinary) {
-        multipart += 'Content-Disposition: form-data; name="' + fieldname + '[]"';
+        multipart += 'Content-Disposition: form-data; name="' + fieldname + '"';
         multipart += '; filename="' + (f.name_bin || f.name) + '"' + crlf;
         multipart += 'Content-Length: ' + f.size + crlf;
         multipart += 'Content-Type: ' + f.type + crlf + crlf;
         multipart += f.getAsBinary() + crlf;
         multipart += dashdash + boundary +crlf;
 
-        if (i == last)
+        if (j == last)
           return submit_data();
       }
+
+      j++;
     }
   };
 
diff --git a/program/steps/addressbook/edit.inc b/program/steps/addressbook/edit.inc
index f96ad67..0f1fd66 100644
--- a/program/steps/addressbook/edit.inc
+++ b/program/steps/addressbook/edit.inc
@@ -262,12 +262,27 @@
 }
 
 
+/**
+ * Register container as active area to drop photos onto
+ */
+function rcmail_photo_drop_area($attrib)
+{
+    global $OUTPUT;
+
+    if ($attrib['id']) {
+        $OUTPUT->add_gui_object('filedrop', $attrib['id']);
+        $OUTPUT->set_env('filedrop', array('action' => 'upload-photo', 'fieldname' => '_photo', 'single' => 1, 'filter' => '^image/.+'));
+    }
+}
+
+
 $OUTPUT->add_handlers(array(
     'contactedithead' => 'rcmail_contact_edithead',
     'contacteditform' => 'rcmail_contact_editform',
     'contactphoto'    => 'rcmail_contact_photo',
     'photouploadform' => 'rcmail_upload_photo_form',
     'sourceselector'  => 'rcmail_source_selector',
+    'filedroparea'    => 'rcmail_photo_drop_area',
 ));
 
 if ($RCMAIL->action == 'add' && $OUTPUT->template_exists('contactadd'))
diff --git a/skins/default/addressbook.css b/skins/default/addressbook.css
index ad7aeff..a398325 100644
--- a/skins/default/addressbook.css
+++ b/skins/default/addressbook.css
@@ -310,6 +310,13 @@
 	width: 60px;
 }
 
+#contactpic.droptarget.hover {
+	background-color: #f0f0ee;
+	box-shadow: 0 0 5px 0 #999;
+	-moz-box-shadow: 0 0 5px 0 #999;
+	-o-box-shadow: 0 0 5px 0 #999;
+}
+
 #contactphoto .formlinks
 {
 	margin-top: 0.5em;
diff --git a/skins/default/templates/contactadd.html b/skins/default/templates/contactadd.html
index 67b7bcd..05cc8aa 100644
--- a/skins/default/templates/contactadd.html
+++ b/skins/default/templates/contactadd.html
@@ -33,6 +33,7 @@
 </div>
 
 <roundcube:object name="photoUploadForm" id="upload-form" size="30" class="popupmenu" />
+<roundcube:object name="fileDropArea" id="contactpic" />
 
 <script type="text/javascript">rcube_init_tabs('contacttabs')</script>
 
diff --git a/skins/default/templates/contactedit.html b/skins/default/templates/contactedit.html
index 77e4661..db8599a 100644
--- a/skins/default/templates/contactedit.html
+++ b/skins/default/templates/contactedit.html
@@ -22,7 +22,6 @@
   </div>
   <roundcube:object name="contactedithead" id="contacthead" size="16" form="editform" />
   <div style="clear:both"></div>
-  
   <div id="contacttabs">
     <roundcube:object name="contacteditform" size="40" textareacols="60" deleteIcon="/images/icons/delete.png" form="editform" />
   </div>
@@ -34,6 +33,7 @@
 </div>
 
 <roundcube:object name="photoUploadForm" id="upload-form" size="30" class="popupmenu" />
+<roundcube:object name="fileDropArea" id="contactpic" />
 
 <script type="text/javascript">rcube_init_tabs('contacttabs')</script>
 
diff --git a/skins/larry/addressbook.css b/skins/larry/addressbook.css
index a9a3c98..9856e28 100644
--- a/skins/larry/addressbook.css
+++ b/skins/larry/addressbook.css
@@ -160,6 +160,29 @@
 
 #contactpic img {
 	width: 112px;
+	visibility: inherit;
+}
+
+#contactpic.droptarget {
+	background-image: url(images/filedrop.png);
+	background-position: center;
+	background-repeat: no-repeat;
+}
+
+#contactpic.droptarget.hover {
+	background-color: #d9ecf4;
+	box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9);
+	-moz-box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9);
+	-webkit-box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9);
+	-o-box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9);
+}
+
+#contactpic.droptarget.active img {
+	opacity: 0.15;
+}
+
+#contactpic.droptarget.hover img {
+	opacity: 0.05;
 }
 
 #contacthead {
diff --git a/skins/larry/templates/contactedit.html b/skins/larry/templates/contactedit.html
index 39d4844..9978c47 100644
--- a/skins/larry/templates/contactedit.html
+++ b/skins/larry/templates/contactedit.html
@@ -19,6 +19,7 @@
 	<div id="contactphoto">
 		<roundcube:object name="contactphoto" id="contactpic" placeholder="/images/contactpic.png" />
 		<roundcube:if condition="env:photocol" />
+		<roundcube:object name="fileDropArea" id="contactpic" />
 		<div class="formlinks">
 			<roundcube:button command="upload-photo" id="uploadformlink" type="link" label="replacephoto" class="iconlink upload disabled" classAct="iconlink upload active" onclick="UI.show_uploadform();return false" condition="env:photocol" /><br/>
 			<roundcube:button command="delete-photo" type="link" label="delete" class="iconlink delete disabled" classAct="iconlink delete active" condition="env:photocol" />

--
Gitblit v1.9.1