- Apply fixes from trunk (up to r4756)
| | |
| | | CHANGELOG Roundcube Webmail |
| | | =========================== |
| | | |
| | | - Fix some CSS issues in Settings for Internet Explorer |
| | | - Fixed handling of folder with name "0" in folder selector |
| | | - Fix bug where messages were deleted instead moved to trash folder after Shift key was used (#1487902) |
| | | - Fix relative URLs handling according to a <base> in HTML (#1487889) |
| | | - Fix handling of top-level domains with more than 5 chars or unicode chars (#1487883) |
| | | - Fix usage of non-standard HTTP error codes (#1487797) |
| | |
| | | $table->add(null, html::tag('input', array( |
| | | 'type' => 'text', |
| | | 'name' => '_email', |
| | | 'value' => idn_to_utf8($identity['email']), |
| | | 'value' => rcube_idn_to_utf8($identity['email']), |
| | | 'disabled' => ($identities_level == 1 || $identities_level == 3) |
| | | ))); |
| | | |
| | |
| | | if ($identities_level == 1 || $identities_level == 3) |
| | | $save_data['email'] = $identity['email']; |
| | | else |
| | | $save_data['email'] = idn_to_ascii($save_data['email']); |
| | | $save_data['email'] = rcube_idn_to_ascii($save_data['email']); |
| | | |
| | | // save data if not empty |
| | | if (!empty($save_data['name']) && !empty($save_data['email'])) { |
| | |
| | | <email>roundcube@gmail.com</email> |
| | | <active>yes</active> |
| | | </lead> |
| | | <date>2010-12-02</date> |
| | | <time>12:00:00</time> |
| | | <date>2011-05-12</date> |
| | | <time>10:00</time> |
| | | <version> |
| | | <release>1.3</release> |
| | | <release>1.4</release> |
| | | <api>1.0</api> |
| | | </version> |
| | | <stability> |
| | |
| | | </stability> |
| | | <license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license> |
| | | <notes> |
| | | - Added setting of focus on name input |
| | | - Added gl_ES translation |
| | | - Fixed IDNA encoding/decoding of e-mail addresses (#1487909) |
| | | </notes> |
| | | <contents> |
| | | <dir baseinstalldir="/" name="/"> |
| | |
| | | - Fix possible error on form submission (#1486103) |
| | | </notes> |
| | | </release> |
| | | <release> |
| | | <date>2010-12-02</date> |
| | | <time>12:00:00</time> |
| | | <version> |
| | | <release>1.3</release> |
| | | <api>1.0</api> |
| | | </version> |
| | | <stability> |
| | | <release>stable</release> |
| | | <api>stable</api> |
| | | </stability> |
| | | <license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license> |
| | | <notes> |
| | | - Added setting of focus on name input |
| | | - Added gl_ES translation |
| | | </notes> |
| | | </release> |
| | | </changelog> |
| | | </package> |
| | |
| | | { |
| | | global $RCMAIL; |
| | | static $a_mailboxes; |
| | | |
| | | |
| | | $attrib += array('maxlength' => 100, 'realnames' => false); |
| | | |
| | | // add some labels to client |
| | | $RCMAIL->output->add_label('purgefolderconfirm', 'deletemessagesconfirm'); |
| | | |
| | | |
| | | $type = $attrib['type'] ? $attrib['type'] : 'ul'; |
| | | unset($attrib['type']); |
| | | |
| | |
| | | |
| | | // get mailbox list |
| | | $mbox_name = $RCMAIL->imap->get_mailbox_name(); |
| | | |
| | | |
| | | // build the folders tree |
| | | if (empty($a_mailboxes)) { |
| | | // get mailbox list |
| | |
| | | // allow plugins to alter the folder tree or to localize folder names |
| | | $hook = $RCMAIL->plugins->exec_hook('render_mailboxlist', array('list' => $a_mailboxes, 'delimiter' => $delimiter)); |
| | | |
| | | if ($type=='select') { |
| | | if ($type == 'select') { |
| | | $select = new html_select($attrib); |
| | | |
| | | |
| | | // add no-selection option |
| | | if ($attrib['noselection']) |
| | | $select->add(rcube_label($attrib['noselection']), '0'); |
| | | |
| | | $select->add(rcube_label($attrib['noselection']), ''); |
| | | |
| | | rcmail_render_folder_tree_select($hook['list'], $mbox_name, $attrib['maxlength'], $select, $attrib['realnames']); |
| | | $out = $select->show(); |
| | | } |
| | | else { |
| | | $js_mailboxlist = array(); |
| | | $out = html::tag('ul', $attrib, rcmail_render_folder_tree_html($hook['list'], $mbox_name, $js_mailboxlist, $attrib), html::$common_attrib); |
| | | |
| | | |
| | | $RCMAIL->output->add_gui_object('mailboxlist', $attrib['id']); |
| | | $RCMAIL->output->set_env('mailboxes', $js_mailboxlist); |
| | | $RCMAIL->output->set_env('collapsed_folders', $RCMAIL->config->get('collapsed_folders')); |
| | |
| | | function rcmail_mailbox_select($p = array()) |
| | | { |
| | | global $RCMAIL; |
| | | |
| | | |
| | | $p += array('maxlength' => 100, 'realnames' => false); |
| | | $a_mailboxes = array(); |
| | | |
| | |
| | | if (strlen($subFolders)) |
| | | rcmail_build_folder_tree($arrFolders[$currentFolder]['folders'], $subFolders, $delm, $path.$delm); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Return html for a structured list <ul> for the mailbox tree |
| | |
| | | function rcmail_render_folder_tree_html(&$arrFolders, &$mbox_name, &$jslist, $attrib, $nestLevel=0) |
| | | { |
| | | global $RCMAIL, $CONFIG; |
| | | |
| | | |
| | | $maxlength = intval($attrib['maxlength']); |
| | | $realnames = (bool)$attrib['realnames']; |
| | | $msgcounts = $RCMAIL->imap->get_cache('messagecount'); |
| | |
| | | $classes[] = 'inbox'; |
| | | else |
| | | $classes[] = '_'.asciiwords($folder_class ? $folder_class : strtolower($folder['id']), true); |
| | | |
| | | |
| | | $classes[] = $zebra_class; |
| | | |
| | | |
| | | if ($folder['id'] == $mbox_name) |
| | | $classes[] = 'selected'; |
| | | |
| | | $collapsed = preg_match('/&'.rawurlencode($folder['id']).'&/', $RCMAIL->config->get('collapsed_folders')); |
| | | $unread = $msgcounts ? intval($msgcounts[$folder['id']]['UNSEEN']) : 0; |
| | | |
| | | |
| | | if ($folder['virtual']) |
| | | $classes[] = 'virtual'; |
| | | else if ($unread) |
| | |
| | | 'style' => "position:absolute", |
| | | 'onclick' => sprintf("%s.command('collapse-folder', '%s')", JS_OBJECT_NAME, $js_name) |
| | | ), ' ') : '')); |
| | | |
| | | |
| | | $jslist[$folder_id] = array('id' => $folder['id'], 'name' => $foldername, 'virtual' => $folder['virtual']); |
| | | |
| | | |
| | | if (!empty($folder['folders'])) { |
| | | $out .= html::tag('ul', array('style' => ($collapsed ? "display:none;" : null)), |
| | | rcmail_render_folder_tree_html($folder['folders'], $mbox_name, $jslist, $attrib, $nestLevel+1)); |
| | |
| | | * @return string |
| | | */ |
| | | function rcmail_render_folder_tree_select(&$arrFolders, &$mbox_name, $maxlength, &$select, $realnames=false, $nestLevel=0) |
| | | { |
| | | $idx = 0; |
| | | { |
| | | $out = ''; |
| | | foreach ($arrFolders as $key=>$folder) |
| | | { |
| | | |
| | | foreach ($arrFolders as $key=>$folder) { |
| | | if (!$realnames && ($folder_class = rcmail_folder_classname($folder['id']))) |
| | | $foldername = rcube_label($folder_class); |
| | | else |
| | | { |
| | | else { |
| | | $foldername = $folder['name']; |
| | | |
| | | |
| | | // shorten the folder name to a given length |
| | | if ($maxlength && $maxlength>1) |
| | | $foldername = abbreviate_string($foldername, $maxlength); |
| | | } |
| | | } |
| | | |
| | | $select->add(str_repeat(' ', $nestLevel*4) . $foldername, $folder['id']); |
| | | |
| | | if (!empty($folder['folders'])) |
| | | $out .= rcmail_render_folder_tree_select($folder['folders'], $mbox_name, $maxlength, $select, $realnames, $nestLevel+1); |
| | | |
| | | $idx++; |
| | | } |
| | | } |
| | | |
| | | return $out; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | |
| | | return $this->conn->setMetadata($mailbox, $entries); |
| | | } |
| | | else if ($this->get_capability('ANNOTATEMORE') || $this->get_capability('ANNOTATEMORE2')) { |
| | | foreach ($entries as $entry => $value) { |
| | | foreach ((array)$entries as $entry => $value) { |
| | | list($ent, $attr) = $this->md2annotate($entry); |
| | | $entries[$entry] = array($ent, $attr, $value); |
| | | } |
| | |
| | | return $this->conn->deleteMetadata($mailbox, $entries); |
| | | } |
| | | else if ($this->get_capability('ANNOTATEMORE') || $this->get_capability('ANNOTATEMORE2')) { |
| | | foreach ($entries as $idx => $entry) { |
| | | foreach ((array)$entries as $idx => $entry) { |
| | | list($ent, $attr) = $this->md2annotate($entry); |
| | | $entries[$idx] = array($ent, $attr, NULL); |
| | | } |
| | |
| | | $mailbox = $this->mod_mailbox($mailbox); |
| | | |
| | | if ($this->get_capability('METADATA') || |
| | | !strlen(($mailbox) && $this->get_capability('METADATA-SERVER')) |
| | | (!strlen($mailbox) && $this->get_capability('METADATA-SERVER')) |
| | | ) { |
| | | return $this->conn->getMetadata($mailbox, $entries, $options); |
| | | } |
| | |
| | | $res = array(); |
| | | |
| | | // Convert entry names |
| | | foreach ($entries as $entry) { |
| | | foreach ((array)$entries as $entry) { |
| | | list($ent, $attr) = $this->md2annotate($entry); |
| | | $queries[$attr][] = $ent; |
| | | } |
| | |
| | | * Converts the METADATA extension entry name into the correct |
| | | * entry-attrib names for older ANNOTATEMORE version. |
| | | * |
| | | * @param string Entry name |
| | | * @param string $entry Entry name |
| | | * |
| | | * @return array Entry-attribute list, NULL if not supported (?) |
| | | */ |
| | | private function md2annotate($name) |
| | | private function md2annotate($entry) |
| | | { |
| | | if (substr($entry, 0, 7) == '/shared') { |
| | | return array(substr($entry, 7), 'value.shared'); |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Set page title variable |
| | | */ |
| | |
| | | { |
| | | $this->pagetitle = $title; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Getter for the current page title |
| | |
| | | |
| | | return $title; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Set skin |
| | |
| | | $this->js_commands[] = $cmd; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Add a localized label to the client environment |
| | | */ |
| | |
| | | $this->command('add_label', $name, rcube_label($name)); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Invoke display_message command |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Delete all stored env variables and commands |
| | | * |
| | |
| | | parent::reset(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Redirect to a certain url |
| | | * |
| | |
| | | header('Location: ' . $location); |
| | | exit; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Send the request output to the client. |
| | |
| | | } |
| | | |
| | | /** |
| | | * Parse a specific skin template and deliver to stdout |
| | | * |
| | | * Either returns nothing, or exists hard (exit();) |
| | | * Parse a specific skin template and deliver to stdout (or return) |
| | | * |
| | | * @param string Template name |
| | | * @param boolean Exit script |
| | | * @return void |
| | | * @param boolean Don't write to stdout, return parsed content instead |
| | | * |
| | | * @link http://php.net/manual/en/function.exit.php |
| | | */ |
| | | private function parse($name = 'main', $exit = true) |
| | | function parse($name = 'main', $exit = true, $write = true) |
| | | { |
| | | $skin_path = $this->config['skin_path']; |
| | | $plugin = false; |
| | |
| | | // trigger generic hook where plugins can put additional content to the page |
| | | $hook = $this->app->plugins->exec_hook("render_page", array('template' => $realname, 'content' => $output)); |
| | | |
| | | // add debug console |
| | | if ($this->config['debug_level'] & 8) { |
| | | $this->add_footer('<div id="console" style="position:absolute;top:5px;left:5px;width:405px;padding:2px;background:white;z-index:9000;"> |
| | | <a href="#toggle" onclick="con=$(\'#dbgconsole\');con[con.is(\':visible\')?\'hide\':\'show\']();return false">console</a> |
| | | <textarea name="console" id="dbgconsole" rows="20" cols="40" wrap="off" style="display:none;width:400px;border:none;font-size:10px" spellcheck="false"></textarea></div>' |
| | | ); |
| | | $output = $this->parse_with_globals($hook['content']); |
| | | |
| | | if ($write) { |
| | | // add debug console |
| | | if ($this->config['debug_level'] & 8) { |
| | | $this->add_footer('<div id="console" style="position:absolute;top:5px;left:5px;width:405px;padding:2px;background:white;z-index:9000;"> |
| | | <a href="#toggle" onclick="con=$(\'#dbgconsole\');con[con.is(\':visible\')?\'hide\':\'show\']();return false">console</a> |
| | | <textarea name="console" id="dbgconsole" rows="20" cols="40" wrap="off" style="display:none;width:400px;border:none;font-size:10px" spellcheck="false"></textarea></div>' |
| | | ); |
| | | } |
| | | $this->write(trim($output)); |
| | | } |
| | | else { |
| | | return $output; |
| | | } |
| | | |
| | | $output = $this->parse_with_globals($hook['content']); |
| | | $this->write(trim($output)); |
| | | if ($exit) { |
| | | exit; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Return executable javascript code for all registered commands |
| | |
| | | |
| | | case 'delete': |
| | | // mail task |
| | | if (this.task=='mail') |
| | | if (this.task == 'mail') |
| | | this.delete_messages(); |
| | | // addressbook task |
| | | else if (this.task=='addressbook') |
| | | else if (this.task == 'addressbook') |
| | | this.delete_contacts(); |
| | | // user settings task |
| | | else if (this.task=='settings') |
| | | else if (this.task == 'settings') |
| | | this.delete_identity(); |
| | | break; |
| | | |
| | |
| | | |
| | | this.doc_mouse_up = function(e) |
| | | { |
| | | var model, list, li; |
| | | var model, list, li, id; |
| | | |
| | | if (this.message_list) { |
| | | if (!rcube_mouse_is_over(e, this.message_list.list.parentNode)) |
| | | this.message_list.blur(); |
| | | if (list = this.message_list) { |
| | | if (!rcube_mouse_is_over(e, list.list.parentNode)) |
| | | list.blur(); |
| | | else |
| | | this.message_list.focus(); |
| | | list = this.message_list; |
| | | list.focus(); |
| | | model = this.env.mailboxes; |
| | | } |
| | | else if (this.contact_list) { |
| | | if (!rcube_mouse_is_over(e, this.contact_list.list.parentNode)) |
| | | this.contact_list.blur(); |
| | | else if (list = this.contact_list) { |
| | | if (!rcube_mouse_is_over(e, list.list.parentNode)) |
| | | list.blur(); |
| | | else |
| | | this.contact_list.focus(); |
| | | list = this.contact_list; |
| | | list.focus(); |
| | | model = this.env.contactfolders; |
| | | } |
| | | else if (this.ksearch_value) { |
| | |
| | | |
| | | // reset 'pressed' buttons |
| | | if (this.buttons_sel) { |
| | | for (var id in this.buttons_sel) |
| | | for (id in this.buttons_sel) |
| | | if (typeof id != 'function') |
| | | this.button_out(this.buttons_sel[id], id); |
| | | this.buttons_sel = {}; |
| | |
| | | this.command('previouspage'); |
| | | else if (list.key_pressed == 34) |
| | | this.command('nextpage'); |
| | | else |
| | | list.shiftkey = false; |
| | | }; |
| | | |
| | | this.msglist_get_preview = function() |
| | |
| | | // delete selected messages from the current mailbox |
| | | this.delete_messages = function() |
| | | { |
| | | var selection = this.message_list ? $.merge([], this.message_list.get_selection()) : []; |
| | | var uid, i, len, trash = this.env.trash_mailbox, |
| | | list = this.message_list, |
| | | selection = list ? $.merge([], list.get_selection()) : []; |
| | | |
| | | // exit if no mailbox specified or if selection is empty |
| | | if (!this.env.uid && !selection.length) |
| | | return; |
| | | |
| | | // also select childs of collapsed rows |
| | | for (var uid, i=0, len=selection.length; i<len; i++) { |
| | | for (i=0, len=selection.length; i<len; i++) { |
| | | uid = selection[i]; |
| | | if (this.message_list.rows[uid].has_children && !this.message_list.rows[uid].expanded) |
| | | this.message_list.select_childs(uid); |
| | | if (list.rows[uid].has_children && !list.rows[uid].expanded) |
| | | list.select_childs(uid); |
| | | } |
| | | |
| | | // if config is set to flag for deletion |
| | |
| | | return false; |
| | | } |
| | | // if there isn't a defined trash mailbox or we are in it |
| | | else if (!this.env.trash_mailbox || this.env.mailbox == this.env.trash_mailbox) |
| | | // @TODO: we should check if defined trash mailbox exists |
| | | else if (!trash || this.env.mailbox == trash) |
| | | this.permanently_remove_messages(); |
| | | // if there is a trash mailbox defined and we're not currently in it |
| | | else { |
| | | // if shift was pressed delete it immediately |
| | | if (this.message_list && this.message_list.shiftkey) { |
| | | if (list && list.shiftkey) { |
| | | if (confirm(this.get_label('deletemessagesconfirm'))) |
| | | this.permanently_remove_messages(); |
| | | } |
| | | else |
| | | this.move_messages(this.env.trash_mailbox); |
| | | this.move_messages(trash); |
| | | } |
| | | |
| | | return true; |
| | |
| | | init_row: function(row) |
| | | { |
| | | // make references in internal array and set event handlers |
| | | if (row && String(row.id).match(/rcmrow([a-z0-9\-_=\+\/]+)/i)) { |
| | | if (row && String(row.id).match(/^rcmrow([a-z0-9\-_=\+\/]+)/i)) { |
| | | var self = this, |
| | | uid = RegExp.$1; |
| | | row.uid = uid; |
| | |
| | | var i, len, rows = this.list.tBodies[0].rows; |
| | | |
| | | for (i=0, len=rows.length-1; i<len; i++) |
| | | if (rows[i].id && String(rows[i].id).match(/rcmrow([a-z0-9\-_=\+\/]+)/i) && this.rows[RegExp.$1] != null) |
| | | if (rows[i].id && String(rows[i].id).match(/^rcmrow([a-z0-9\-_=\+\/]+)/i) && this.rows[RegExp.$1] != null) |
| | | return RegExp.$1; |
| | | } |
| | | |
| | |
| | | var i, rows = this.list.tBodies[0].rows; |
| | | |
| | | for (i=rows.length-1; i>=0; i--) |
| | | if (rows[i].id && String(rows[i].id).match(/rcmrow([a-z0-9\-_=\+\/]+)/i) && this.rows[RegExp.$1] != null) |
| | | if (rows[i].id && String(rows[i].id).match(/^rcmrow([a-z0-9\-_=\+\/]+)/i) && this.rows[RegExp.$1] != null) |
| | | return RegExp.$1; |
| | | } |
| | | |
| | |
| | | this.shiftkey = e.shiftKey; |
| | | this.key_pressed = keyCode; |
| | | this.triggerEvent('keypress'); |
| | | // reset shiftkey flag, we need it only for registered events |
| | | this.shiftkey = false; |
| | | |
| | | if (this.key_pressed == this.BACKSPACE_KEY) |
| | | return rcube_event.cancel(e); |
| | |
| | | $labels['replysamefolder'] = 'Umieszczaj odpowiedzi w folderze wiadomości, na którą odpowiadam'; |
| | | $labels['contactproperties'] = 'Właściwości'; |
| | | $labels['properties'] = 'Właściwości'; |
| | | $labels['folderproperties'] = 'Włąściwości folderu'; |
| | | $labels['folderproperties'] = 'Właściwości folderu'; |
| | | $labels['parentfolder'] = 'Folder nadrzędny'; |
| | | $labels['location'] = 'Położenie'; |
| | | $labels['info'] = 'Informacje'; |
| | |
| | | background-image: url(images/messageicons.gif); |
| | | } |
| | | |
| | | body.iframe .boxtitle |
| | | { |
| | | position: absolute; |
| | | } |
| | | |
| | | #subscription-table |
| | | { |
| | | width: auto; |
| | | } |
| | |
| | | width: expression((parseInt(document.documentElement.clientWidth)-240)+'px'); |
| | | } |
| | | |
| | | #subscription-table |
| | | { |
| | | width: auto; |
| | | } |
| | | |
| | | #messagelist |
| | | { |
| | | width: inherit; |
| | |
| | | } |
| | | |
| | | #contacts-box, |
| | | #prefs-box |
| | | #prefs-box, |
| | | #folder-box |
| | | { |
| | | width: expression((parseInt(this.parentNode.offsetWidth)-555)+'px'); |
| | | overflow: hidden; |
| | | } |
| | | |
| | | #rcmdraglayer |
| | |
| | | padding-left: 15px; |
| | | } |
| | | |
| | | #messagetoolbar select.mboxlist option[value="0"] |
| | | #messagetoolbar select.mboxlist option[value=""] |
| | | { |
| | | padding-left: 2px; |
| | | } |