- Applied fixes from trunk up to r5512
| | |
| | | CHANGELOG Roundcube Webmail |
| | | =========================== |
| | | |
| | | - Fix handling of empty <U> tags in HTML messages (#1488225) |
| | | - Add content filter for embedded attachments to protect from XSS on IE (#1487895) |
| | | - Use strpos() instead of strstr() when possible (#1488211) |
| | | - Fix handling HTML entities when converting HTML to text (#1488212) |
| | | - Fix fit_string_to_size() renders browser and ui unresponsive (#1488207) |
| | |
| | | |
| | | $labels = array(); |
| | | $labels['buttontitle'] = 'Archiver ce message'; |
| | | $labels['archived'] = 'Message archivé avec success'; |
| | | $labels['archived'] = 'Message archivé avec success'; |
| | | $labels['archivefolder'] = 'Archive'; |
| | | |
| | | ?> |
| | |
| | | |
| | | $function = $this->_scope2func($this->prop['scope']); |
| | | $this->ldap_result = @$function($this->conn, $this->base_dn, $this->filter ? $this->filter : '(objectclass=*)', |
| | | array_values($this->fieldmap), 0, (int)$this->prop['sizelimit'], (int)$this->prop['timelimit']); |
| | | array_values($this->fieldmap), 0, $this->page_size, (int)$this->prop['timelimit']); |
| | | |
| | | $this->result = new rcube_result_set(0); |
| | | |
| | |
| | | $replacedata = array(); |
| | | $deletedata = array(); |
| | | |
| | | // flatten composite fields in $record |
| | | if (is_array($record['address'])) { |
| | | foreach ($record['address'] as $i => $struct) { |
| | | foreach ($struct as $col => $val) { |
| | | $record[$col][$i] = $val; |
| | | } |
| | | } |
| | | } |
| | | $ldap_data = $this->_map_data($save_cols); |
| | | $old_data = $record['_raw_attrib']; |
| | | |
| | | foreach ($this->fieldmap as $col => $fld) { |
| | | $val = $save_cols[$col]; |
| | | $val = $ldap_data[$fld]; |
| | | if ($fld) { |
| | | // remove empty array values |
| | | if (is_array($val)) |
| | | $val = array_filter($val); |
| | | // The field does exist compare it to the ldap record. |
| | | if ($record[$col] != $val) { |
| | | if ($old_data[$fld] != $val) { |
| | | // Changed, but find out how. |
| | | if (!isset($record[$col])) { |
| | | if (!isset($old_data[$fld])) { |
| | | // Field was not set prior, need to add it. |
| | | $newdata[$fld] = $val; |
| | | } // end if |
| | | } |
| | | elseif ($val == '') { |
| | | // Field supplied is empty, verify that it is not required. |
| | | if (!in_array($fld, $this->prop['required_fields'])) { |
| | | // It is not, safe to clear. |
| | | $deletedata[$fld] = $record[$col]; |
| | | } // end if |
| | | $deletedata[$fld] = $old_data[$fld]; |
| | | } |
| | | } // end elseif |
| | | else { |
| | | // The data was modified, save it out. |
| | | $replacedata[$fld] = $val; |
| | | } // end else |
| | | } |
| | | } // end if |
| | | } // end if |
| | | } // end foreach |
| | |
| | | for ($i=0; $i < $rec[$lf]['count']; $i++) { |
| | | if (!($value = $rec[$lf][$i])) |
| | | continue; |
| | | |
| | | $out['_raw_attrib'][$lf][$i] = $value; |
| | | |
| | | if ($rf == 'email' && $this->mail_domain && !strpos($value, '@')) |
| | | $out[$rf][] = sprintf('%s@%s', $value, $this->mail_domain); |
| | | else if (in_array($rf, array('street','zipcode','locality','country','region'))) |
| | |
| | | |
| | | // Make sure name fields aren't arrays (#1488108) |
| | | if (is_array($out[$rf]) && in_array($rf, array('name', 'surname', 'firstname', 'middlename', 'nickname'))) { |
| | | $out[$rf] = $out[$rf][0]; |
| | | $out[$rf] = $out['_raw_attrib'][$lf] = $out[$rf][0]; |
| | | } |
| | | } |
| | | |
| | |
| | | */ |
| | | private function _map_data($save_cols) |
| | | { |
| | | // flatten composite fields first |
| | | foreach ($this->coltypes as $col => $colprop) { |
| | | if (is_array($colprop['childs']) && ($values = $this->get_col_values($col, $save_cols, false))) { |
| | | foreach ($values as $subtype => $childs) { |
| | | $subtype = $subtype ? ':'.$subtype : ''; |
| | | foreach ($childs as $i => $child_values) { |
| | | foreach ((array)$child_values as $childcol => $value) { |
| | | $save_cols[$childcol.$subtype][$i] = $value; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | $ldap_data = array(); |
| | | foreach ($this->fieldmap as $col => $fld) { |
| | | $val = $save_cols[$col]; |
| | |
| | | $base_dn = $this->groups_base_dn; |
| | | $new_dn = "cn=$group_name,$base_dn"; |
| | | $new_gid = self::dn_encode($group_name); |
| | | $member_attr = $this->prop['groups']['member_attr']; |
| | | $name_attr = $this->prop['groups']['name_attr']; |
| | | |
| | | $new_entry = array( |
| | | 'objectClass' => $this->prop['groups']['object_classes'], |
| | | $name_attr => $group_name, |
| | | $member_attr => '', |
| | | ); |
| | | |
| | | $this->_debug("C: Add [dn: $new_dn]: ".print_r($new_entry, true)); |
| | |
| | | * @param string $mime_id Part MIME-ID |
| | | * @return string URL or false if part does not exist |
| | | */ |
| | | public function get_part_url($mime_id) |
| | | public function get_part_url($mime_id, $embed = false) |
| | | { |
| | | if ($this->mime_parts[$mime_id]) |
| | | return $this->opt['get_url'] . '&_part=' . $mime_id; |
| | | return $this->opt['get_url'] . '&_part=' . $mime_id . ($embed ? '&_embed=1' : ''); |
| | | else |
| | | return false; |
| | | } |
| | |
| | | $img_regexp = '/^image\/(gif|jpe?g|png|tiff|bmp|svg)/'; |
| | | |
| | | foreach ($this->inline_parts as $inline_object) { |
| | | $part_url = $this->get_part_url($inline_object->mime_id); |
| | | $part_url = $this->get_part_url($inline_object->mime_id, true); |
| | | if ($inline_object->content_id) |
| | | $a_replaces['cid:'.$inline_object->content_id] = $part_url; |
| | | if ($inline_object->content_location) { |
| | |
| | | |
| | | /* Block elements which could be empty but cannot be returned in short form (<tag />) */ |
| | | static $block_elements = array('div', 'p', 'pre', 'blockquote', 'a', 'font', 'center', |
| | | 'table', 'ul', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ol', 'dl', 'strong', 'i', 'b'); |
| | | 'table', 'ul', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ol', 'dl', 'strong', 'i', 'b', 'u'); |
| | | |
| | | /* State for linked objects in HTML */ |
| | | public $extlinks = false; |
| | |
| | | * @param array CID map replaces (inline images) |
| | | * @return string Clean HTML |
| | | */ |
| | | function rcmail_wash_html($html, $p = array(), $cid_replaces) |
| | | function rcmail_wash_html($html, $p, $cid_replaces) |
| | | { |
| | | global $REMOTE_OBJECTS; |
| | | |
| | |
| | | ) { |
| | | $out .= html::tag('hr') . html::p(array('align' => "center"), |
| | | html::img(array( |
| | | 'src' => $MESSAGE->get_part_url($attach_prop->mime_id), |
| | | 'src' => $MESSAGE->get_part_url($attach_prop->mime_id, true), |
| | | 'title' => $attach_prop->filename, |
| | | 'alt' => $attach_prop->filename, |
| | | ))); |
| | |
| | | |
| | | header("Content-Disposition: $disposition; filename=\"$filename\""); |
| | | |
| | | // do content filtering to avoid XSS through fake images |
| | | if (!empty($_REQUEST['_embed']) && $browser->ie && $browser->ver <= 8) { |
| | | if ($part->body) |
| | | echo preg_match('/<(script|iframe|object)/i', $part->body) ? '' : $part->body; |
| | | else if ($part->size) { |
| | | $stdout = fopen('php://output', 'w'); |
| | | stream_filter_register('rcube_content', 'rcube_content_filter') or die('Failed to register content filter'); |
| | | stream_filter_append($stdout, 'rcube_content'); |
| | | $IMAP->get_message_part($MESSAGE->uid, $part->mime_id, $part, false, $stdout); |
| | | } |
| | | } |
| | | else { |
| | | // turn off output buffering and print part content |
| | | if ($part->body) |
| | | echo $part->body; |
| | | else if ($part->size) |
| | | $IMAP->get_message_part($MESSAGE->uid, $part->mime_id, $part, true); |
| | | } |
| | | } |
| | | |
| | | exit; |
| | |
| | | exit; |
| | | |
| | | |
| | | |
| | | /** |
| | | * PHP stream filter to detect html/javascript code in attachments |
| | | */ |
| | | class rcube_content_filter extends php_user_filter |
| | | { |
| | | private $buffer = ''; |
| | | private $cutoff = 2048; |
| | | |
| | | function onCreate() |
| | | { |
| | | $this->cutoff = rand(2048, 3027); |
| | | return true; |
| | | } |
| | | |
| | | function filter($in, $out, &$consumed, $closing) |
| | | { |
| | | while ($bucket = stream_bucket_make_writeable($in)) { |
| | | $this->buffer .= $bucket->data; |
| | | |
| | | // check for evil content and abort |
| | | if (preg_match('/<(script|iframe|object)/i', $this->buffer)) |
| | | return PSFS_ERR_FATAL; |
| | | |
| | | // keep buffer small enough |
| | | if (strlen($this->buffer) > 4096) |
| | | $this->buffer = substr($this->buffer, $this->cutoff); |
| | | |
| | | $consumed += $bucket->datalen; |
| | | stream_bucket_append($out, $bucket); |
| | | } |
| | | |
| | | return PSFS_PASS_ON; |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | $ol .= html::tag('li', null, |
| | | html::a(array( |
| | | 'href' => $MESSAGE->get_part_url($attach_prop->mime_id), |
| | | 'href' => $MESSAGE->get_part_url($attach_prop->mime_id, false), |
| | | 'onclick' => sprintf( |
| | | 'return %s.command(\'load-attachment\',{part:\'%s\', mimetype:\'%s\'},this)', |
| | | JS_OBJECT_NAME, |