Backporting changes trom trunk (r5357-r5365)
| | |
| | | // I didn't found that SEARCH should return sorted IDs |
| | | if (is_array($a_index)) |
| | | sort($a_index); |
| | | } else if ($max = $this->_messagecount($mailbox)) { |
| | | } else if ($max = $this->_messagecount($mailbox, 'ALL', true, false)) { |
| | | $a_index = range(1, $max); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | if ($orig_criteria == 'ALL') { |
| | | $max = $this->_messagecount($mailbox); |
| | | $max = $this->_messagecount($mailbox, 'ALL', true, false); |
| | | $a_messages = $max ? range(1, $max) : array(); |
| | | } |
| | | else { |
| | |
| | | } |
| | | |
| | | $headers = $this->get_headers($uid, $mailbox); |
| | | |
| | | // message doesn't exist? |
| | | if (empty($headers)) |
| | | return null; |
| | | |
| | | // structure might be cached |
| | | if (!empty($headers->structure)) |
| | |
| | | |
| | | // decode filename |
| | | if (!empty($filename_mime)) { |
| | | $part->filename = rcube_imap::decode_mime_string($filename_mime, |
| | | $part->charset ? $part->charset : ($this->struct_charset ? $this->struct_charset : |
| | | rc_detect_encoding($filename_mime, $this->default_charset))); |
| | | if (!empty($part->charset)) |
| | | $charset = $part->charset; |
| | | else if (!empty($this->struct_charset)) |
| | | $charset = $this->struct_charset; |
| | | else |
| | | $charset = rc_detect_encoding($filename_mime, $this->default_charset); |
| | | |
| | | $part->filename = rcube_imap::decode_mime_string($filename_mime, $charset); |
| | | } |
| | | else if (!empty($filename_encoded)) { |
| | | // decode filename according to RFC 2231, Section 4 |
| | |
| | | $filename_charset = $fmatches[1]; |
| | | $filename_encoded = $fmatches[2]; |
| | | } |
| | | |
| | | $part->filename = rcube_charset_convert(urldecode($filename_encoded), $filename_charset); |
| | | } |
| | | } |
| | |
| | | */ |
| | | function &get_message_part($uid, $part=1, $o_part=NULL, $print=NULL, $fp=NULL, $skip_charset_conv=false) |
| | | { |
| | | // get part encoding if not provided |
| | | // get part data if not provided |
| | | if (!is_object($o_part)) { |
| | | $structure = $this->conn->getStructure($this->mailbox, $uid, true); |
| | | $part_data = rcube_imap_generic::getStructurePartData($structure, $part); |
| | | |
| | | $o_part = new rcube_message_part; |
| | | $o_part->ctype_primary = strtolower(rcube_imap_generic::getStructurePartType($structure, $part)); |
| | | $o_part->encoding = strtolower(rcube_imap_generic::getStructurePartEncoding($structure, $part)); |
| | | $o_part->charset = rcube_imap_generic::getStructurePartCharset($structure, $part); |
| | | $o_part->ctype_primary = $part_data['type']; |
| | | $o_part->encoding = $part_data['encoding']; |
| | | $o_part->charset = $part_data['charset']; |
| | | $o_part->size = $part_data['size']; |
| | | } |
| | | |
| | | // TODO: Add caching for message parts |
| | | |
| | | if (!$part) { |
| | | $part = 'TEXT'; |
| | | if ($o_part && $o_part->size) { |
| | | $body = $this->conn->handlePartBody($this->mailbox, $uid, true, |
| | | $part ? $part : 'TEXT', $o_part->encoding, $print, $fp); |
| | | } |
| | | |
| | | $body = $this->conn->handlePartBody($this->mailbox, $uid, true, $part, |
| | | $o_part->encoding, $print, $fp); |
| | | |
| | | if ($fp || $print) { |
| | | return true; |
| | |
| | | if (!$skip_charset_conv) { |
| | | if (!$o_part->charset || strtoupper($o_part->charset) == 'US-ASCII') { |
| | | // try to extract charset information from HTML meta tag (#1488125) |
| | | if ($o_part->ctype_secondary == 'html' && preg_match('/<meta[^>]+charset=([a-z0-9-]+)/i', $body, $m)) |
| | | if ($o_part->ctype_secondary == 'html' && preg_match('/<meta[^>]+charset=([a-z0-9-_]+)/i', $body, $m)) |
| | | $o_part->charset = strtoupper($m[1]); |
| | | else |
| | | $o_part->charset = $this->default_charset; |
| | |
| | | // @TODO: find better validity check for threaded index |
| | | if ($is_thread) { |
| | | // check messages number... |
| | | if ($mbox_data['EXISTS'] != @max(array_keys($index['depth']))) { |
| | | if (!$this->skip_deleted && $mbox_data['EXISTS'] != @max(array_keys($index['depth']))) { |
| | | return false; |
| | | } |
| | | return true; |
| | |
| | | $len = strlen($line); |
| | | $result = false; |
| | | |
| | | if ($a[2] != 'FETCH') { |
| | | } |
| | | // handle empty "* X FETCH ()" response |
| | | if ($line[$len-1] == ')' && $line[$len-2] != '(') { |
| | | else if ($line[$len-1] == ')' && $line[$len-2] != '(') { |
| | | // one line response, get everything between first and last quotes |
| | | if (substr($line, -4, 3) == 'NIL') { |
| | | // NIL response |
| | |
| | | return false; |
| | | } |
| | | |
| | | static function getStructurePartType($structure, $part) |
| | | /** |
| | | * Returns data of a message part according to specified structure. |
| | | * |
| | | * @param array $structure Message structure (getStructure() result) |
| | | * @param string $part Message part identifier |
| | | * |
| | | * @return array Part data as hash array (type, encoding, charset, size) |
| | | */ |
| | | static function getStructurePartData($structure, $part) |
| | | { |
| | | $part_a = self::getStructurePartArray($structure, $part); |
| | | if (!empty($part_a)) { |
| | | if (is_array($part_a[0])) |
| | | return 'multipart'; |
| | | else if ($part_a[0]) |
| | | return $part_a[0]; |
| | | } |
| | | $data = array(); |
| | | |
| | | return 'other'; |
| | | } |
| | | if (empty($part_a)) { |
| | | return $data; |
| | | } |
| | | |
| | | static function getStructurePartEncoding($structure, $part) |
| | | { |
| | | $part_a = self::getStructurePartArray($structure, $part); |
| | | if ($part_a) { |
| | | if (!is_array($part_a[0])) |
| | | return $part_a[5]; |
| | | } |
| | | // content-type |
| | | if (is_array($part_a[0])) { |
| | | $data['type'] = 'multipart'; |
| | | } |
| | | else { |
| | | $data['type'] = strtolower($part_a[0]); |
| | | |
| | | return ''; |
| | | } |
| | | // encoding |
| | | $data['encoding'] = strtolower($part_a[5]); |
| | | |
| | | static function getStructurePartCharset($structure, $part) |
| | | { |
| | | $part_a = self::getStructurePartArray($structure, $part); |
| | | if ($part_a) { |
| | | if (is_array($part_a[0])) |
| | | return ''; |
| | | else { |
| | | if (is_array($part_a[2])) { |
| | | $name = ''; |
| | | while (list($key, $val) = each($part_a[2])) |
| | | if (strcasecmp($val, 'charset') == 0) |
| | | return $part_a[2][$key+1]; |
| | | } |
| | | } |
| | | } |
| | | // charset |
| | | if (is_array($part_a[2])) { |
| | | while (list($key, $val) = each($part_a[2])) { |
| | | if (strcasecmp($val, 'charset') == 0) { |
| | | $data['charset'] = $part_a[2][$key+1]; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | return ''; |
| | | // size |
| | | $data['size'] = intval($part_a[6]); |
| | | |
| | | return $data; |
| | | } |
| | | |
| | | static function getStructurePartArray($a, $part) |
| | |
| | | return $a; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Creates next command identifier (tag) |
| | |
| | | // special replacements (not properly handled by washtml class) |
| | | $html_search = array( |
| | | '/(<\/nobr>)(\s+)(<nobr>)/i', // space(s) between <NOBR> |
| | | '/<title[^>]*>.*<\/title>/i', // PHP bug #32547 workaround: remove title tag |
| | | '/<title[^>]*>[^<]*<\/title>/i', // PHP bug #32547 workaround: remove title tag |
| | | '/^(\0\0\xFE\xFF|\xFF\xFE\0\0|\xFE\xFF|\xFF\xFE|\xEF\xBB\xBF)/', // byte-order mark (only outlook?) |
| | | '/<html\s[^>]+>/i', // washtml/DOMDocument cannot handle xml namespaces |
| | | ); |
| | |
| | | $html = preg_replace_callback('/(<[\/]*)([^\s>]+)/', 'rcmail_html_tag_callback', $html); |
| | | |
| | | // charset was converted to UTF-8 in rcube_imap::get_message_part(), |
| | | // -> change charset specification in HTML accordingly |
| | | $charset_pattern = '(<meta\s+[^>]*content=)[\'"]?(\w+\/\w+;\s*charset=)([a-z0-9-_]+[\'"]?)'; |
| | | if (preg_match("/$charset_pattern/Ui", $html)) { |
| | | $html = preg_replace("/$charset_pattern/i", '\\1"\\2'.RCMAIL_CHARSET.'"', $html); |
| | | } |
| | | else { |
| | | // add meta content-type to malformed messages, washtml cannot work without that |
| | | if (!preg_match('/<head[^>]*>(.*)<\/head>/Uims', $html)) |
| | | $html = '<head></head>'. $html; |
| | | $html = substr_replace($html, '<meta http-equiv="Content-Type" content="text/html; charset='.RCMAIL_CHARSET.'" />', intval(stripos($html, '<head>')+6), 0); |
| | | // change/add charset specification in HTML accordingly, |
| | | // washtml cannot work without that |
| | | $meta = '<meta http-equiv="Content-Type" content="text/html; charset='.RCMAIL_CHARSET.'" />'; |
| | | |
| | | // remove old meta tag and add the new one, making sure |
| | | // that it is placed in the head (#1488093) |
| | | $html = preg_replace('/<meta[^>]+charset=[a-z0-9-_]+[^>]*>/Ui', '', $html); |
| | | $html = preg_replace('/(<head[^>]*>)/Ui', '\\1'.$meta, $html, -1, $rcount); |
| | | if (!$rcount) { |
| | | $html = '<head>' . $meta . '</head>' . $html; |
| | | } |
| | | |
| | | // turn relative into absolute urls |
| | |
| | | // show page size selection |
| | | if (!isset($no_override['timezone'])) { |
| | | $field_id = 'rcmfd_timezone'; |
| | | $select_timezone = new html_select(array('name' => '_timezone', 'id' => $field_id, 'onchange' => "document.getElementById('rcmfd_dst').disabled=this.selectedIndex==0")); |
| | | $select_timezone = new html_select(array('name' => '_timezone', 'id' => $field_id, 'onchange' => "$('#rcmfd_dst').attr('disabled', this.selectedIndex==0)")); |
| | | $select_timezone->add(rcube_label('autodetect'), 'auto'); |
| | | $select_timezone->add('(GMT -11:00) Midway Island, Samoa', '-11'); |
| | | $select_timezone->add('(GMT -10:00) Hawaii', '-10'); |