Merge branch 'master' of github.com:roundcube/roundcubemail
| | |
| | | .($uids !== null ? " AND uid IN (".$this->db->array2list((array)$uids, 'integer').")" : ""), |
| | | $this->userid, $mailbox); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | |
| | | 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.) |
| | |
| | | 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') |
| | |
| | | $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']; |
| | |
| | | */ |
| | | 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); |
| | | |
| | |
| | | $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; |
| | |
| | | { |
| | | 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'); |
| | | } |
| | | }; |
| | | |
| | |
| | | |
| | | 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) |
| | |
| | | // 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; |
| | |
| | | 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; |
| | |
| | | $.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, |
| | |
| | | |
| | | // 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'; |
| | |
| | | |
| | | // 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 |
| | |
| | | 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++; |
| | | } |
| | | }; |
| | | |
| | |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 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')) |
| | |
| | | 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; |
| | |
| | | </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> |
| | | |
| | |
| | | </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> |
| | |
| | | </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> |
| | | |
| | |
| | | |
| | | #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 { |
| | |
| | | <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" /> |