- Applied fixes from trunk up to r5150
| | |
| | | CHANGELOG Roundcube Webmail |
| | | =========================== |
| | | |
| | | - Fix imap_cache setting to values other than 'db' (#1488060) |
| | | - Fix handling of attachments inside message/rfc822 parts (#1488026) |
| | | - Make list of mimetypes that open in preview window configurable (#1487625) |
| | | - Added plugin hook 'message_part_get' for attachment downloads |
| | | - Fixed selecting identity on reply/forward (#1487981) |
| | | - Fix image type check for contact photo uploads |
| | | |
| | |
| | | // 3 - one identity with possibility to edit all params but not email address |
| | | $rcmail_config['identities_level'] = 0; |
| | | |
| | | // Mimetypes supported by the browser. |
| | | // attachments of these types will open in a preview window |
| | | // either a comma-separated list or an array: 'text/plain,text/html,text/xml,image/jpeg,image/gif,image/png,application/pdf' |
| | | $rcmail_config['client_mimetypes'] = null; # null == default |
| | | |
| | | // mime magic database |
| | | $rcmail_config['mime_magic'] = '/usr/share/misc/magic'; |
| | | |
| | |
| | | /** |
| | | * ACL plugin script |
| | | * |
| | | * @version 0.6 |
| | | * @version 0.6.1 |
| | | * @author Aleksander Machniak <alec@alec.pl> |
| | | */ |
| | | |
| | |
| | | rcmail.acl_list_init(); |
| | | // enable autocomplete on user input |
| | | if (rcmail.env.acl_users_source) { |
| | | rcmail.init_address_input_events($('#acluser'), {action:'plugin.acl-autocomplete'}); |
| | | rcmail.init_address_input_events($('#acluser'), {action:'settings/plugin.acl-autocomplete'}); |
| | | // fix inserted value |
| | | rcmail.addEventListener('autocomplete_insert', function(e) { |
| | | if (e.field.id != 'acluser') |
| | |
| | | var users = this.acl_get_usernames(); |
| | | |
| | | if (users && users.length && confirm(this.get_label('acl.deleteconfirm'))) { |
| | | this.http_request('plugin.acl', '_act=delete&_user='+urlencode(users.join(',')) |
| | | this.http_request('settings/plugin.acl', '_act=delete&_user='+urlencode(users.join(',')) |
| | | + '&_mbox='+urlencode(this.env.mailbox), |
| | | this.set_busy(true, 'acl.deleting')); |
| | | } |
| | |
| | | return; |
| | | } |
| | | |
| | | this.http_request('plugin.acl', '_act=save' |
| | | this.http_request('settings/plugin.acl', '_act=save' |
| | | + '&_user='+urlencode(user) |
| | | + '&_acl=' +rights |
| | | + '&_mbox='+urlencode(this.env.mailbox) |
| | |
| | | { |
| | | this.env.acl_advanced = !this.env.acl_advanced; |
| | | this.enable_command('acl-delete', 'acl-edit', false); |
| | | this.http_request('plugin.acl', '_act=list' |
| | | this.http_request('settings/plugin.acl', '_act=list' |
| | | + '&_mode='+(this.env.acl_advanced ? 'advanced' : 'simple') |
| | | + '&_mbox='+urlencode(this.env.mailbox), |
| | | this.set_busy(true, 'loading')); |
| | |
| | | /** |
| | | * Folders Access Control Lists Management (RFC4314, RFC2086) |
| | | * |
| | | * @version 0.6 |
| | | * @version 0.6.1 |
| | | * @author Aleksander Machniak <alec@alec.pl> |
| | | * |
| | | * |
| | |
| | | |
| | | class acl extends rcube_plugin |
| | | { |
| | | public $task = 'settings|addressbook'; |
| | | public $task = 'settings|addressbook|calendar'; |
| | | |
| | | private $rc; |
| | | private $supported = null; |
| | |
| | | $this->add_hook('folder_form', array($this, 'folder_form')); |
| | | // kolab_addressbook plugin |
| | | $this->add_hook('addressbook_form', array($this, 'folder_form')); |
| | | $this->add_hook('calendar_form_kolab', array($this, 'folder_form')); |
| | | // Plugin actions |
| | | $this->register_action('plugin.acl', array($this, 'acl_actions')); |
| | | $this->register_action('plugin.acl-autocomplete', array($this, 'acl_autocomplete')); |
| | |
| | | $list = array(); |
| | | $attrib = array( |
| | | 'name' => 'rcmyrights', |
| | | 'style' => 'padding: 0 15px;', |
| | | 'style' => 'margin:0; padding:0 15px;', |
| | | ); |
| | | |
| | | foreach ($supported as $right) { |
| | |
| | | |
| | | #aclform |
| | | { |
| | | top: 100px; |
| | | top: 80px; |
| | | width: 480px; |
| | | padding: 10px; |
| | | } |
| | |
| | | 'disabled' => ($identities_level == 1 || $identities_level == 3) |
| | | ))); |
| | | |
| | | $table->add('title', $this->gettext('organization')); |
| | | $table->add(null, html::tag('input', array( |
| | | 'type' => 'text', |
| | | 'name' => '_organization', |
| | | 'value' => $identity['organization'] |
| | | ))); |
| | | |
| | | $table->add('title', $this->gettext('signature')); |
| | | $table->add(null, html::tag('textarea', array( |
| | | 'name' => '_signature', |
| | | 'rows' => '3', |
| | | ),$identity['signature'] |
| | | )); |
| | | |
| | | // add overlay input box to html page |
| | | $rcmail->output->add_footer(html::div(array('id' => 'newuseroverlay'), |
| | | html::tag('form', array( |
| | |
| | | $save_data = array( |
| | | 'name' => get_input_value('_name', RCUBE_INPUT_POST), |
| | | 'email' => get_input_value('_email', RCUBE_INPUT_POST), |
| | | 'organization' => get_input_value('_organization', RCUBE_INPUT_POST), |
| | | 'signature' => get_input_value('_signature', RCUBE_INPUT_POST), |
| | | ); |
| | | |
| | | // don't let the user alter the e-mail address if disabled by config |
| | |
| | | |
| | | } |
| | | |
| | | ?> |
| | | ?> |
| | |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | #newuseroverlay table td input |
| | | #newuseroverlay table td input, |
| | | #newuseroverlay table td textarea |
| | | { |
| | | width: 20em; |
| | | } |
| | |
| | | */ |
| | | function format_date($date, $format=NULL) |
| | | { |
| | | global $CONFIG; |
| | | global $RCMAIL, $CONFIG; |
| | | |
| | | $ts = NULL; |
| | | |
| | |
| | | return ''; |
| | | |
| | | // get user's timezone |
| | | if ($CONFIG['timezone'] === 'auto') |
| | | $tz = isset($_SESSION['timezone']) ? $_SESSION['timezone'] : date('Z')/3600; |
| | | else { |
| | | $tz = $CONFIG['timezone']; |
| | | if ($CONFIG['dst_active']) |
| | | $tz++; |
| | | } |
| | | $tz = $RCMAIL->config->get_timezone(); |
| | | |
| | | // convert time to user's timezone |
| | | $timestamp = $ts - date('Z', $ts) + ($tz * 3600); |
| | |
| | | * @param string $from Sender address string |
| | | * @param array $mailto Array of recipient address strings |
| | | * @param array $smtp_error SMTP error array (reference) |
| | | * @param string $body_file Location of file with saved message body (reference) |
| | | * @param string $body_file Location of file with saved message body (reference), |
| | | * used when delay_file_io is enabled |
| | | * @param array $smtp_opts SMTP options (e.g. DSN request) |
| | | * |
| | | * @return boolean Send status. |
| | | */ |
| | | function rcmail_deliver_message(&$message, $from, $mailto, &$smtp_error, &$body_file, $smtp_opts=null) |
| | | function rcmail_deliver_message(&$message, $from, $mailto, &$smtp_error, &$body_file=null, $smtp_opts=null) |
| | | { |
| | | global $CONFIG, $RCMAIL; |
| | | |
| | |
| | | // Returns RFC2822 formatted current date in user's timezone |
| | | function rcmail_user_date() |
| | | { |
| | | global $CONFIG; |
| | | global $RCMAIL, $CONFIG; |
| | | |
| | | // get user's timezone |
| | | if ($CONFIG['timezone'] === 'auto') { |
| | | $tz = isset($_SESSION['timezone']) ? $_SESSION['timezone'] : date('Z')/3600; |
| | | } |
| | | else { |
| | | $tz = $CONFIG['timezone']; |
| | | if ($CONFIG['dst_active']) |
| | | $tz++; |
| | | } |
| | | $tz = $RCMAIL->config->get_timezone(); |
| | | |
| | | $date = time() + $tz * 60 * 60; |
| | | $date = gmdate('r', $date); |
| | |
| | | $id = '0'; |
| | | |
| | | // use existing instance |
| | | if (isset($this->address_books[$id]) && is_a($this->address_books[$id], 'rcube_addressbook') && (!$writeable || !$this->address_books[$id]->readonly)) { |
| | | if (isset($this->address_books[$id]) && is_object($this->address_books[$id]) |
| | | && is_a($this->address_books[$id], 'rcube_addressbook') |
| | | && (!$writeable || !$this->address_books[$id]->readonly) |
| | | ) { |
| | | $contacts = $this->address_books[$id]; |
| | | } |
| | | else if ($id && $ldap_config[$id]) { |
| | |
| | | $this->smtp->disconnect(); |
| | | |
| | | foreach ($this->address_books as $book) { |
| | | if (is_a($book, 'rcube_addressbook')) |
| | | if (is_object($book) && is_a($book, 'rcube_addressbook')) |
| | | $book->close(); |
| | | } |
| | | |
| | |
| | | return $this->prop; |
| | | } |
| | | |
| | | /** |
| | | * Special getter for user's timezone |
| | | */ |
| | | public function get_timezone() |
| | | { |
| | | $tz = $this->get('timezone'); |
| | | if ($tz == 'auto') |
| | | $tz = isset($_SESSION['timezone']) ? $_SESSION['timezone'] : date('Z') / 3600; |
| | | else |
| | | $tz = intval($tz) + intval($this->get('dst_active')); |
| | | |
| | | return $tz; |
| | | } |
| | | |
| | | /** |
| | | * Return requested DES crypto key. |
| | |
| | | if (!empty($this->scripts['docready'])) { |
| | | $this->add_script('$(document).ready(function(){ ' . $this->scripts['docready'] . "\n});", 'foot'); |
| | | } |
| | | |
| | | |
| | | if (is_array($this->script_files['foot'])) { |
| | | foreach ($this->script_files['foot'] as $file) { |
| | | $page_footer .= sprintf($this->script_tag_file, $file); |
| | |
| | | |
| | | // add page hader |
| | | if ($hpos) { |
| | | $output = substr($output,0,$hpos) . $page_header . substr($output,$hpos,strlen($output)); |
| | | $output = substr_replace($output, $page_header, $hpos, 0); |
| | | } |
| | | else { |
| | | $output = $page_header . $output; |
| | |
| | | |
| | | // add page footer |
| | | if (($fpos = strripos($output, '</body>')) || ($fpos = strripos($output, '</html>'))) { |
| | | $output = substr($output, 0, $fpos) . "$page_footer\n" . substr($output, $fpos); |
| | | $output = substr_replace($output, $page_footer."\n", $fpos, 0); |
| | | } |
| | | else { |
| | | $output .= "\n".$page_footer; |
| | |
| | | foreach ($this->css_files as $file) { |
| | | $css .= sprintf($this->link_css_file, $file); |
| | | } |
| | | $output = substr($output, 0, $pos) . $css . substr($output, $pos); |
| | | $output = substr_replace($output, $css, $pos, 0); |
| | | } |
| | | |
| | | $this->base_path = $base_path; |
| | |
| | | echo $hook['content']; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Callback function for preg_replace_callback in write() |
| | | * |
| | |
| | | if (isset($data['folders'])) { |
| | | $a_folders = $data['folders']; |
| | | } |
| | | else if (!$this->conn->connected()) { |
| | | return array(); |
| | | } |
| | | else { |
| | | // Server supports LIST-EXTENDED, we can use selection options |
| | | $config = rcmail::get_instance()->config; |
| | |
| | | /** |
| | | * Enable or disable indexes caching |
| | | * |
| | | * @param boolean $type Cache type (@see rcmail::get_cache) |
| | | * @param string $type Cache type (@see rcmail::get_cache) |
| | | * @access public |
| | | */ |
| | | function set_caching($type) |
| | | { |
| | | if ($type) { |
| | | $this->caching = true; |
| | | $this->caching = $type; |
| | | } |
| | | else { |
| | | if ($this->cache) |
| | |
| | | { |
| | | if ($this->caching && !$this->cache) { |
| | | $rcmail = rcmail::get_instance(); |
| | | $this->cache = $rcmail->get_cache('IMAP', $type); |
| | | $this->cache = $rcmail->get_cache('IMAP', $this->caching); |
| | | } |
| | | |
| | | return $this->cache; |
| | |
| | | if ($message_ctype_primary == 'text' && !$recursive) { |
| | | $structure->type = 'content'; |
| | | $this->parts[] = &$structure; |
| | | |
| | | |
| | | // Parse simple (plain text) message body |
| | | if ($message_ctype_secondary == 'plain') |
| | | foreach ((array)$this->uu_decode($structure) as $uupart) { |
| | |
| | | |
| | | foreach ($structure->parts as $p => $sub_part) { |
| | | $sub_mimetype = $sub_part->mimetype; |
| | | |
| | | |
| | | // check if sub part is |
| | | if ($sub_mimetype == 'text/plain') |
| | | $plain_part = $p; |
| | |
| | | $this->parse_alternative = true; |
| | | $this->parse_structure($structure->parts[$related_part], true); |
| | | $this->parse_alternative = false; |
| | | |
| | | |
| | | // if plain part was found, we should unset it if html is preferred |
| | | if ($this->opt['prefer_html'] && count($this->parts)) |
| | | $plain_part = null; |
| | |
| | | $this->attachments[] = $mail_part; |
| | | } |
| | | // part message/* |
| | | else if ($primary_type=='message') { |
| | | else if ($primary_type == 'message') { |
| | | $this->parse_structure($mail_part, true); |
| | | |
| | | // list as attachment as well (mostly .eml) |
| | |
| | | $this->attachments[] = $mail_part; |
| | | } |
| | | } |
| | | // attachment part as message/rfc822 (#1488026) |
| | | else if ($mail_part->mimetype == 'message/rfc822') { |
| | | $this->parse_structure($mail_part); |
| | | } |
| | | } |
| | | |
| | | // if this was a related part try to resolve references |
| | |
| | | if (is_subclass_of($plugin, 'rcube_plugin')) { |
| | | // ... task, request type and framed mode |
| | | if ((!$plugin->task || preg_match('/^('.$plugin->task.')$/i', $rcmail->task)) |
| | | && (!$plugin->noajax || is_a($rcmail->output, 'rcube_template')) |
| | | && (!$plugin->noajax || (is_object($rcmail->output) && is_a($rcmail->output, 'rcube_template'))) |
| | | && (!$plugin->noframe || empty($_REQUEST['_framed'])) |
| | | ) { |
| | | $plugin->init(); |
| | |
| | | |
| | | this.identifier_expr = new RegExp('[^0-9a-z\-_]', 'gi'); |
| | | |
| | | // mimetypes supported by the browser (default settings) |
| | | this.mimetypes = new Array('text/plain', 'text/html', 'text/xml', |
| | | 'image/jpeg', 'image/gif', 'image/png', |
| | | 'application/x-javascript', 'application/pdf', 'application/x-shockwave-flash'); |
| | | |
| | | // default environment vars |
| | | this.env.keep_alive = 60; // seconds |
| | | this.env.request_timeout = 180; // seconds |
| | |
| | | if (over) button_prop.over = over; |
| | | |
| | | this.buttons[command].push(button_prop); |
| | | |
| | | if (this.loaded) |
| | | init_button(command, button_prop); |
| | | }; |
| | | |
| | | // register a specific gui object |
| | | this.gui_object = function(name, id) |
| | | { |
| | | this.gui_objects[name] = id; |
| | | this.gui_objects[name] = this.loaded ? rcube_find_object(id) : id; |
| | | }; |
| | | |
| | | // register a container object |
| | |
| | | var qstring = '_mbox='+urlencode(this.env.mailbox)+'&_uid='+this.env.uid+'&_part='+props.part; |
| | | |
| | | // open attachment in frame if it's of a supported mimetype |
| | | if (this.env.uid && props.mimetype && $.inArray(props.mimetype, this.mimetypes)>=0) { |
| | | if (this.env.uid && props.mimetype && this.env.mimetypes && $.inArray(props.mimetype, this.env.mimetypes)>=0) { |
| | | if (props.mimetype == 'text/html') |
| | | qstring += '&_safe=1'; |
| | | this.attachment_win = window.open(this.env.comm_path+'&_action=get&'+qstring+'&_frame=1', 'rcubemailattachment'); |
| | |
| | | |
| | | case 27: // escape |
| | | this.ksearch_hide(); |
| | | break; |
| | | return; |
| | | |
| | | case 37: // left |
| | | case 39: // right |
| | |
| | | /********* GUI functionality *********/ |
| | | /*********************************************************/ |
| | | |
| | | var init_button = function(cmd, prop) |
| | | { |
| | | var elm = document.getElementById(prop.id); |
| | | if (!elm) |
| | | return; |
| | | |
| | | var preload = false; |
| | | if (prop.type == 'image') { |
| | | elm = elm.parentNode; |
| | | preload = true; |
| | | } |
| | | |
| | | elm._command = cmd; |
| | | elm._id = prop.id; |
| | | if (prop.sel) { |
| | | elm.onmousedown = function(e){ return rcmail.button_sel(this._command, this._id); }; |
| | | elm.onmouseup = function(e){ return rcmail.button_out(this._command, this._id); }; |
| | | if (preload) |
| | | new Image().src = prop.sel; |
| | | } |
| | | if (prop.over) { |
| | | elm.onmouseover = function(e){ return rcmail.button_over(this._command, this._id); }; |
| | | elm.onmouseout = function(e){ return rcmail.button_out(this._command, this._id); }; |
| | | if (preload) |
| | | new Image().src = prop.over; |
| | | } |
| | | }; |
| | | |
| | | // enable/disable buttons for page shifting |
| | | this.set_page_buttons = function() |
| | | { |
| | |
| | | continue; |
| | | |
| | | for (var i=0; i< this.buttons[cmd].length; i++) { |
| | | var prop = this.buttons[cmd][i]; |
| | | var elm = document.getElementById(prop.id); |
| | | if (!elm) |
| | | continue; |
| | | |
| | | var preload = false; |
| | | if (prop.type == 'image') { |
| | | elm = elm.parentNode; |
| | | preload = true; |
| | | } |
| | | |
| | | elm._command = cmd; |
| | | elm._id = prop.id; |
| | | if (prop.sel) { |
| | | elm.onmousedown = function(e){ return rcmail.button_sel(this._command, this._id); }; |
| | | elm.onmouseup = function(e){ return rcmail.button_out(this._command, this._id); }; |
| | | if (preload) |
| | | new Image().src = prop.sel; |
| | | } |
| | | if (prop.over) { |
| | | elm.onmouseover = function(e){ return rcmail.button_over(this._command, this._id); }; |
| | | elm.onmouseout = function(e){ return rcmail.button_out(this._command, this._id); }; |
| | | if (preload) |
| | | new Image().src = prop.over; |
| | | } |
| | | init_button(cmd, this.buttons[cmd][i]); |
| | | } |
| | | } |
| | | }; |
| | |
| | | var base = this.env.comm_path; |
| | | |
| | | // overwrite task name |
| | | if (query._action.match(/([a-z]+)\/([a-z-_]+)/)) { |
| | | if (query._action.match(/([a-z]+)\/([a-z-_.]+)/)) { |
| | | query._action = RegExp.$2; |
| | | base = base.replace(/\_task=[a-z]+/, '_task='+RegExp.$1); |
| | | } |
| | |
| | | { |
| | | global $RCMAIL, $IMAP; |
| | | |
| | | if (!is_a($message, rcube_message)) |
| | | if (!is_object($message) || !is_a($message, rcube_message)) |
| | | $message = new rcube_message($message); |
| | | |
| | | if ($message->headers->mdn_to && !$message->headers->mdn_sent && |
| | |
| | | $ctype_secondary = strtolower($part->ctype_secondary); |
| | | $mimetype = sprintf('%s/%s', $ctype_primary, $ctype_secondary); |
| | | |
| | | // allow post-processing of the message body |
| | | $plugin = $RCMAIL->plugins->exec_hook('message_part_get', |
| | | array('id' => $part->mime_id, 'mimetype' => $mimetype, 'part' => $part, 'download' => !empty($_GET['_download']))); |
| | | |
| | | if ($plugin['abort']) |
| | | exit; |
| | | |
| | | // overwrite modified vars from plugin |
| | | $mimetype = $plugin['mimetype']; |
| | | list($ctype_primary, $ctype_secondary) = explode('/', $mimetype); |
| | | if ($plugin['body']) |
| | | $part->body = $plugin['body']; |
| | | |
| | | $browser = $RCMAIL->output->browser; |
| | | |
| | | // send download headers |
| | | if ($_GET['_download']) { |
| | | if ($plugin['download']) { |
| | | header("Content-Type: application/octet-stream"); |
| | | if ($browser->ie) |
| | | header("Content-Type: application/force-download"); |
| | |
| | | } |
| | | |
| | | // deliver part content |
| | | if ($ctype_primary == 'text' && $ctype_secondary == 'html' && empty($_GET['_download'])) { |
| | | if ($ctype_primary == 'text' && $ctype_secondary == 'html' && empty($plugin['download'])) { |
| | | // get part body if not available |
| | | if (!$part->body) |
| | | $part->body = $MESSAGE->get_part_content($part->mime_id); |
| | |
| | | else |
| | | $filename = addcslashes($filename, '"'); |
| | | |
| | | $disposition = !empty($_GET['_download']) ? 'attachment' : 'inline'; |
| | | $disposition = !empty($plugin['download']) ? 'attachment' : 'inline'; |
| | | |
| | | header("Content-Disposition: $disposition; filename=\"$filename\""); |
| | | |
| | |
| | | $OUTPUT->set_env('delimiter', $IMAP->get_hierarchy_delimiter()); |
| | | $OUTPUT->set_env('mailbox', $mbox_name); |
| | | |
| | | // mimetypes supported by the browser (default settings) |
| | | $mimetypes = $RCMAIL->config->get('client_mimetypes', 'text/plain,text/html,text/xml,image/jpeg,image/gif,image/png,application/x-javascript,application/pdf,application/x-shockwave-flash'); |
| | | $OUTPUT->set_env('mimetypes', is_string($mimetypes) ? explode(',', $mimetypes) : (array)$mimetypes); |
| | | |
| | | if ($CONFIG['trash_mbox']) |
| | | $OUTPUT->set_env('trash_mailbox', $CONFIG['trash_mbox']); |
| | | if ($CONFIG['flag_for_deletion']) |
| | |
| | | if (isset($CONFIG['max_pagesize']) && ($a_user_prefs['pagesize'] > $CONFIG['max_pagesize'])) |
| | | $a_user_prefs['pagesize'] = (int) $CONFIG['max_pagesize']; |
| | | |
| | | $a_user_prefs['timezone'] = $_SESSION['timezone'] = (string) $a_user_prefs['timezone']; |
| | | $a_user_prefs['timezone'] = (string) $a_user_prefs['timezone']; |
| | | |
| | | break; |
| | | case 'mailbox': |
| | |
| | | color: black; |
| | | } |
| | | |
| | | input.button[disabled], |
| | | input.button[disabled]:hover |
| | | { |
| | | color: #aaa; |
| | | border-color: #ccc; |
| | | } |
| | | |
| | | input.mainaction |
| | | { |
| | | font-weight: bold; |