| | |
| | | var $cache_changes = array(); |
| | | var $uid_id_map = array(); |
| | | var $msg_headers = array(); |
| | | var $capabilities = array(); |
| | | var $skip_deleted = FALSE; |
| | | var $search_set = NULL; |
| | | var $search_subject = ''; |
| | |
| | | function __construct($db_conn) |
| | | { |
| | | $this->db = $db_conn; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * PHP 4 object constructor |
| | | * |
| | | * @see rcube_imap::__construct |
| | | */ |
| | | function rcube_imap($db_conn) |
| | | { |
| | | $this->__construct($db_conn); |
| | | } |
| | | |
| | | |
| | |
| | | // get server properties |
| | | if ($this->conn) |
| | | { |
| | | $this->_parse_capability($this->conn->capability); |
| | | |
| | | if (!empty($this->conn->delimiter)) |
| | | $this->delimiter = $this->conn->delimiter; |
| | | if (!empty($this->conn->rootdir)) |
| | |
| | | { |
| | | $this->close(); |
| | | $this->connect($this->host, $this->user, $this->pass, $this->port, $this->ssl); |
| | | |
| | | // issue SELECT command to restore connection status |
| | | if ($this->mailbox) |
| | | iil_C_Select($this->conn, $this->mailbox); |
| | | } |
| | | |
| | | |
| | |
| | | */ |
| | | function get_capability($cap) |
| | | { |
| | | $cap = strtoupper($cap); |
| | | return $this->capabilities[$cap]; |
| | | return iil_C_GetCapability($this->conn, strtoupper($cap)); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Checks the PERMANENTFLAGS capability of the current mailbox |
| | | * and returns true if the given flag is supported by the IMAP server |
| | | * |
| | | * @param string Permanentflag name |
| | | * @return mixed True if this flag is supported |
| | | * @access public |
| | | */ |
| | | function check_permflag($flag) |
| | | { |
| | | $flagsmap = $GLOBALS['IMAP_FLAGS']; |
| | | return (($imap_flag = $flagsmap[strtoupper($flag)]) && in_array_nocase($imap_flag, $this->conn->permanentflags)); |
| | | } |
| | | |
| | | |
| | |
| | | if (empty($struct->disposition)) |
| | | $struct->disposition = 'inline'; |
| | | } |
| | | |
| | | // fetch message headers if message/rfc822 or named part (could contain Content-Location header) |
| | | if ($struct->ctype_primary == 'message' || ($struct->ctype_parameters['name'] && !$struct->content_id)) { |
| | | $part_headers = iil_C_FetchPartHeader($this->conn, $this->mailbox, $this->_msg_id, $struct->mime_id); |
| | | $struct->headers = $this->_parse_headers($part_headers) + $struct->headers; |
| | | } |
| | | |
| | | // fetch message headers if message/rfc822 |
| | | if ($struct->ctype_primary=='message') |
| | | { |
| | | $headers = iil_C_FetchPartBody($this->conn, $this->mailbox, $this->_msg_id, $struct->mime_id.'.HEADER'); |
| | | $struct->headers = $this->_parse_headers($headers); |
| | | |
| | | if ($struct->ctype_primary=='message') { |
| | | if (is_array($part[8]) && empty($struct->parts)) |
| | | $struct->parts[] = $this->_structure_part($part[8], ++$count, $struct->mime_id); |
| | | } |
| | | } |
| | | |
| | | // normalize filename property |
| | | if ($filename_mime = $struct->d_parameters['filename'] ? $struct->d_parameters['filename'] : $struct->ctype_parameters['name']) |
| | | { |
| | | $struct->filename = rcube_imap::decode_mime_string($filename_mime, |
| | | $struct->charset ? $struct->charset : rc_detect_encoding($filename_mime, $this->default_charset)); |
| | | } |
| | | else if ($filename_encoded = $struct->d_parameters['filename*'] ? $struct->d_parameters['filename*'] : $struct->ctype_parameters['name*']) |
| | | { |
| | | // decode filename according to RFC 2231, Section 4 |
| | | list($filename_charset,, $filename_urlencoded) = split('\'', $filename_encoded); |
| | | $struct->filename = rcube_charset_convert(urldecode($filename_urlencoded), $filename_charset); |
| | | } |
| | | else if (!empty($struct->headers['content-description'])) |
| | | $struct->filename = rcube_imap::decode_mime_string($struct->headers['content-description'], |
| | | $struct->charset ? $struct->charset : rc_detect_encoding($struct->headers['content-description'],$this->default_charset)); |
| | | |
| | | $this->_set_part_filename($struct); |
| | | |
| | | return $struct; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Set attachment filename from message part structure |
| | | * |
| | | * @access private |
| | | * @param object rcube_message_part Part object |
| | | */ |
| | | function _set_part_filename(&$part) |
| | | { |
| | | if (!empty($part->d_parameters['filename'])) |
| | | $filename_mime = $part->d_parameters['filename']; |
| | | else if (!empty($part->ctype_parameters['name'])) |
| | | $filename_mime = $part->ctype_parameters['name']; |
| | | else if (!empty($part->d_parameters['filename*'])) |
| | | $filename_encoded = $part->d_parameters['filename*']; |
| | | else if (!empty($part->ctype_parameters['name*'])) |
| | | $filename_encoded = $part->ctype_parameters['name*']; |
| | | // RFC2231 value continuations |
| | | // TODO: this should be rewrited to support RFC2231 4.1 combinations |
| | | else if (!empty($part->d_parameters['filename*0'])) { |
| | | $i = 0; |
| | | while (isset($part->d_parameters['filename*'.$i])) { |
| | | $i++; |
| | | $filename_mime .= $part->d_parameters['filename*'.$i]; |
| | | } |
| | | // some servers (eg. dovecot-1.x) have no support for parameter value continuations |
| | | // we must fetch and parse headers "manually" |
| | | if ($i<2) { |
| | | // TODO: fetch only Content-Type/Content-Disposition header |
| | | $headers = iil_C_FetchPartBody($this->conn, $this->mailbox, $this->_msg_id, $struct->mime_id.'.HEADER'); |
| | | $filename_mime = ''; |
| | | $i = 0; |
| | | while (preg_match('/filename\*'.$i.'\s*=\s*"*([^"\n;]+)[";]*/', $headers, $matches)) { |
| | | $filename_mime .= $matches[1]; |
| | | $i++; |
| | | } |
| | | } |
| | | } |
| | | else if (!empty($part->d_parameters['filename*0*'])) { |
| | | $i = 0; |
| | | while (isset($part->d_parameters['filename*'.$i.'*'])) { |
| | | $i++; |
| | | $filename_encoded .= $part->d_parameters['filename*'.$i.'*']; |
| | | } |
| | | if ($i<2) { |
| | | $headers = iil_C_FetchPartBody($this->conn, $this->mailbox, $this->_msg_id, $struct->mime_id.'.HEADER'); |
| | | $filename_encoded = ''; |
| | | $i = 0; |
| | | while (preg_match('/filename\*'.$i.'\*\s*=\s*"*([^"\n;]+)[";]*/', $headers, $matches)) { |
| | | $filename_encoded .= $matches[1]; |
| | | $i++; |
| | | } |
| | | } |
| | | } |
| | | else if (!empty($part->ctype_parameters['name*0'])) { |
| | | $i = 0; |
| | | while (isset($part->ctype_parameters['name*'.$i])) { |
| | | $i++; |
| | | $filename_mime .= $part->ctype_parameters['name*'.$i]; |
| | | } |
| | | if ($i<2) { |
| | | $headers = iil_C_FetchPartBody($this->conn, $this->mailbox, $this->_msg_id, $struct->mime_id.'.HEADER'); |
| | | $filename_mime = ''; |
| | | $i = 0; |
| | | while (preg_match('/\s+name\*'.$i.'\s*=\s*"*([^"\n;]+)[";]*/', $headers, $matches)) { |
| | | $filename_mime .= $matches[1]; |
| | | $i++; |
| | | } |
| | | } |
| | | } |
| | | else if (!empty($part->ctype_parameters['name*0*'])) { |
| | | $i = 0; |
| | | while (isset($part->ctype_parameters['name*'.$i.'*'])) { |
| | | $i++; |
| | | $filename_encoded .= $part->ctype_parameters['name*'.$i.'*']; |
| | | } |
| | | if ($i<2) { |
| | | $headers = iil_C_FetchPartBody($this->conn, $this->mailbox, $this->_msg_id, $struct->mime_id.'.HEADER'); |
| | | $filename_encoded = ''; |
| | | $i = 0; |
| | | while (preg_match('/\s+name\*'.$i.'\*\s*=\s*"*([^"\n;]+)[";]*/', $headers, $matches)) { |
| | | $filename_encoded .= $matches[1]; |
| | | $i++; |
| | | } |
| | | } |
| | | } |
| | | // Content-Disposition |
| | | else if (!empty($part->headers['content-description'])) |
| | | $filename_mime = $part->headers['content-description']; |
| | | else |
| | | return; |
| | | |
| | | // decode filename |
| | | if (!empty($filename_mime)) { |
| | | $part->filename = rcube_imap::decode_mime_string($filename_mime, |
| | | $part->charset ? $part->charset : rc_detect_encoding($filename_mime, $this->default_charset)); |
| | | } |
| | | else if (!empty($filename_encoded)) { |
| | | // decode filename according to RFC 2231, Section 4 |
| | | list($filename_charset,, $filename_urlencoded) = split('\'', $filename_encoded); |
| | | $part->filename = rcube_charset_convert(urldecode($filename_urlencoded), $filename_charset); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Fetch message body of a specific message from the server |
| | |
| | | * @param string Part number |
| | | * @param object rcube_message_part Part object created by get_structure() |
| | | * @param mixed True to print part, ressource to write part contents in |
| | | * @param resource File pointer to save the message part |
| | | * @return string Message/part body if not printed |
| | | */ |
| | | function &get_message_part($uid, $part=1, $o_part=NULL, $print=NULL) |
| | | function &get_message_part($uid, $part=1, $o_part=NULL, $print=NULL, $fp=NULL) |
| | | { |
| | | if (!($msg_id = $this->_uid2id($uid))) |
| | | return FALSE; |
| | |
| | | // get part encoding if not provided |
| | | if (!is_object($o_part)) |
| | | { |
| | | write_log('errors', 'get_message_part: !is_object'); |
| | | $structure_str = iil_C_FetchStructureString($this->conn, $this->mailbox, $msg_id); |
| | | $structure = iml_GetRawStructureArray($structure_str); |
| | | $part_type = iml_GetPartTypeCode($structure, $part); |
| | |
| | | } |
| | | else |
| | | { |
| | | $body = iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, $part, 1); |
| | | if ($fp && $o_part->encoding == 'base64') |
| | | return iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, $part, 3, $fp); |
| | | else |
| | | $body = iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, $part, 1); |
| | | |
| | | // decode part body |
| | | if ($o_part->encoding) |
| | |
| | | |
| | | $body = rcube_charset_convert($body, $o_part->charset); |
| | | } |
| | | |
| | | if ($fp) |
| | | { |
| | | fwrite($fp, $body); |
| | | return true; |
| | | } |
| | | } |
| | | |
| | | |
| | | return $body; |
| | | } |
| | | |
| | |
| | | $body .= iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, NULL, 1); |
| | | |
| | | return $body; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Returns the message headers as string |
| | | * |
| | | * @param int Message UID |
| | | * @return string Message headers string |
| | | */ |
| | | function &get_raw_headers($uid) |
| | | { |
| | | if (!($msg_id = $this->_uid2id($uid))) |
| | | return FALSE; |
| | | |
| | | $headers = iil_C_FetchPartHeader($this->conn, $this->mailbox, $msg_id, NULL); |
| | | |
| | | return $headers; |
| | | } |
| | | |
| | | |
| | |
| | | */ |
| | | function decode_mime_string($input, $fallback=null) |
| | | { |
| | | // Initialize variable |
| | | $out = ''; |
| | | |
| | | $pos = strpos($input, '=?'); |
| | | if ($pos !== false) |
| | | { |
| | | // rfc: all line breaks or other characters not found |
| | | // in the Base64 Alphabet must be ignored by decoding software |
| | | // delete all blanks between MIME-lines, differently we can |
| | | // receive unnecessary blanks and broken utf-8 symbols |
| | | $input = preg_replace("/\?=\s+=\?/", '?==?', $input); |
| | | // Iterate instead of recursing, this way if there are too many values we don't have stack overflows |
| | | // rfc: all line breaks or other characters not found |
| | | // in the Base64 Alphabet must be ignored by decoding software |
| | | // delete all blanks between MIME-lines, differently we can |
| | | // receive unnecessary blanks and broken utf-8 symbols |
| | | $input = preg_replace("/\?=\s+=\?/", '?==?', $input); |
| | | |
| | | $out = substr($input, 0, $pos); |
| | | |
| | | $end_cs_pos = strpos($input, "?", $pos+2); |
| | | $end_en_pos = strpos($input, "?", $end_cs_pos+1); |
| | | $end_pos = strpos($input, "?=", $end_en_pos+1); |
| | | |
| | | $encstr = substr($input, $pos+2, ($end_pos-$pos-2)); |
| | | $rest = substr($input, $end_pos+2); |
| | | // Check if there is stuff to decode |
| | | if (strpos($input, '=?') !== false) { |
| | | // Loop through the string to decode all occurences of =? ?= into the variable $out |
| | | while(($pos = strpos($input, '=?')) !== false) { |
| | | // Append everything that is before the text to be decoded |
| | | $out .= substr($input, 0, $pos); |
| | | |
| | | $out .= rcube_imap::_decode_mime_string_part($encstr); |
| | | $out .= rcube_imap::decode_mime_string($rest, $fallback); |
| | | // Get the location of the text to decode |
| | | $end_cs_pos = strpos($input, "?", $pos+2); |
| | | $end_en_pos = strpos($input, "?", $end_cs_pos+1); |
| | | $end_pos = strpos($input, "?=", $end_en_pos+1); |
| | | |
| | | return $out; |
| | | // Extract the encoded string |
| | | $encstr = substr($input, $pos+2, ($end_pos-$pos-2)); |
| | | // Extract the remaining string |
| | | $input = substr($input, $end_pos+2); |
| | | |
| | | // Decode the string fragement |
| | | $out .= rcube_imap::_decode_mime_string_part($encstr); |
| | | } |
| | | |
| | | // Deocde the rest (if any) |
| | | if (strlen($input) != 0) |
| | | $out .= rcube_imap::decode_mime_string($input, $fallback); |
| | | |
| | | // return the results |
| | | return $out; |
| | | } |
| | | |
| | | // no encoding information, use fallback |
| | | return rcube_charset_convert($input, |
| | |
| | | $folders = array_merge($a_defaults, array_keys($folders)); |
| | | |
| | | // finally we must rebuild the list to move |
| | | // subfolders of default folders to their place |
| | | // subfolders of default folders to their place... |
| | | // ...also do this for the rest of folders because |
| | | // asort() is not properly sorting case sensitive names |
| | | while (list($key, $folder) = each($folders)) { |
| | | $a_out[] = $folder; |
| | | unset($folders[$key]); |
| | | if (in_array(strtolower($folder), $this->default_folders_lc)) { |
| | | foreach ($folders as $idx => $f) { |
| | | if (strpos($f, $folder.$delimiter) === 0) { |
| | | $a_out[] = $f; |
| | | unset($folders[$idx]); |
| | | } |
| | | foreach ($folders as $idx => $f) { |
| | | if (strpos($f, $folder.$delimiter) === 0) { |
| | | $a_out[] = $f; |
| | | unset($folders[$idx]); |
| | | } |
| | | reset($folders); |
| | | } |
| | | } |
| | | reset($folders); |
| | | } |
| | | |
| | | return $a_out; |
| | |
| | | } |
| | | |
| | | return $uid; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Parse string or array of server capabilities and put them in internal array |
| | | * @access private |
| | | */ |
| | | function _parse_capability($caps) |
| | | { |
| | | if (!is_array($caps)) |
| | | $cap_arr = explode(' ', $caps); |
| | | else |
| | | $cap_arr = $caps; |
| | | |
| | | foreach ($cap_arr as $cap) |
| | | { |
| | | if ($cap=='CAPABILITY') |
| | | continue; |
| | | |
| | | if (strpos($cap, '=')>0) |
| | | { |
| | | list($key, $value) = explode('=', $cap); |
| | | if (!is_array($this->capabilities[$key])) |
| | | $this->capabilities[$key] = array(); |
| | | |
| | | $this->capabilities[$key][] = $value; |
| | | } |
| | | else |
| | | $this->capabilities[$cap] = TRUE; |
| | | } |
| | | } |
| | | |
| | | |