summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--program/include/rcube_imap_cache.php123
-rw-r--r--program/include/rcube_imap_generic.php27
-rw-r--r--program/js/app.js35
-rw-r--r--program/steps/addressbook/edit.inc15
-rw-r--r--skins/default/addressbook.css7
-rw-r--r--skins/default/templates/contactadd.html1
-rw-r--r--skins/default/templates/contactedit.html2
-rw-r--r--skins/larry/addressbook.css23
-rw-r--r--skins/larry/templates/contactedit.html1
9 files changed, 149 insertions, 85 deletions
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 = '<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 @@ 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 @@
</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 77e466141..db8599ac6 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 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 @@
<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" />