diff --git a/program/include/rcube_imap_cache.php b/program/include/rcube_imap_cache.php index eb2df165f..530284a58 100644 --- a/program/include/rcube_imap_cache.php +++ b/program/include/rcube_imap_cache.php @@ -516,7 +516,6 @@ class rcube_imap_cache .($uids !== null ? " AND uid IN (".$this->db->array2list((array)$uids, 'integer').")" : ""), $this->userid, $mailbox); } - } @@ -917,18 +916,17 @@ class rcube_imap_cache 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.) $mbox_data = $this->imap->folder_data($mailbox); @@ -952,8 +950,10 @@ class rcube_imap_cache 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 @@ class rcube_imap_cache $this->userid, $mailbox); while ($sql_arr = $this->db->fetch_assoc($sql_result)) { - $uids[] = $sql_arr['uid']; - } - - // No messages in database, nothing to sync - if (empty($uids)) { - return; - } - - // 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); + $uids[] = $sql_arr['uid']; + } + + // 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); + + 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 959dd9fd0..197164dfe 100644 --- a/program/include/rcube_imap_generic.php +++ b/program/include/rcube_imap_generic.php @@ -1472,14 +1472,31 @@ class rcube_imap_generic */ 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 @@ class rcube_imap_generic $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 ce7570468..a2307fd77 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -4715,11 +4715,11 @@ function rcube_webmail() { 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 @@ function rcube_webmail() 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 @@ function rcube_webmail() // 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 @@ function rcube_webmail() content = '' + (multiple ? ref.get_label('uploadingmany') : files[0].name) + ''; // 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 @@ function rcube_webmail() $.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 @@ function rcube_webmail() // 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 @@ function rcube_webmail() // 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 @@ function rcube_webmail() 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 f96ad6747..0f1fd6697 100644 --- a/program/steps/addressbook/edit.inc +++ b/program/steps/addressbook/edit.inc @@ -262,12 +262,27 @@ function rcmail_source_selector($attrib) } +/** + * 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 ad7aeffd8..a398325b4 100644 --- a/skins/default/addressbook.css +++ b/skins/default/addressbook.css @@ -310,6 +310,13 @@ body.iframe, 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 67b7bcd6e..05cc8aa82 100644 --- a/skins/default/templates/contactadd.html +++ b/skins/default/templates/contactadd.html @@ -33,6 +33,7 @@ + diff --git a/skins/default/templates/contactedit.html b/skins/default/templates/contactedit.html index 77e466141..db8599ac6 100644 --- a/skins/default/templates/contactedit.html +++ b/skins/default/templates/contactedit.html @@ -22,7 +22,6 @@
-
@@ -34,6 +33,7 @@ + diff --git a/skins/larry/addressbook.css b/skins/larry/addressbook.css index a9a3c9883..9856e2836 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 39d48440b..9978c4757 100644 --- a/skins/larry/templates/contactedit.html +++ b/skins/larry/templates/contactedit.html @@ -19,6 +19,7 @@
+