| | |
| | | | program/include/rcube_imap.inc | |
| | | | | |
| | | | This file is part of the RoundCube Webmail client | |
| | | | Copyright (C) 2005-2006, RoundCube Dev. - Switzerland | |
| | | | Copyright (C) 2005-2007, RoundCube Dev. - Switzerland | |
| | | | Licensed under the GNU GPL | |
| | | | | |
| | | | PURPOSE: | |
| | |
| | | * |
| | | * @package Mail |
| | | * @author Thomas Bruederli <roundcube@gmail.com> |
| | | * @version 1.36 |
| | | * @version 1.40 |
| | | * @link http://ilohamail.org |
| | | */ |
| | | class rcube_imap |
| | |
| | | var $sort_order = 'DESC'; |
| | | var $delimiter = NULL; |
| | | var $caching_enabled = FALSE; |
| | | var $default_charset = 'ISO-8859-1'; |
| | | var $default_folders = array('INBOX'); |
| | | var $default_folders_lc = array('inbox'); |
| | | var $cache = array(); |
| | |
| | | var $search_string = ''; |
| | | var $search_charset = ''; |
| | | var $debug_level = 1; |
| | | var $error_code = 0; |
| | | |
| | | |
| | | /** |
| | |
| | | * @param string Username for IMAP account |
| | | * @param string Password for IMAP account |
| | | * @param number Port to connect to |
| | | * @param boolean Use SSL connection |
| | | * @param string SSL schema (either ssl or tls) or null if plain connection |
| | | * @return boolean TRUE on success, FALSE on failure |
| | | * @access public |
| | | */ |
| | | function connect($host, $user, $pass, $port=143, $use_ssl=FALSE) |
| | | function connect($host, $user, $pass, $port=143, $use_ssl=null) |
| | | { |
| | | global $ICL_SSL, $ICL_PORT, $IMAP_USE_INTERNAL_DATE; |
| | | |
| | | // check for Open-SSL support in PHP build |
| | | if ($use_ssl && in_array('openssl', get_loaded_extensions())) |
| | | $ICL_SSL = TRUE; |
| | | $ICL_SSL = $use_ssl == 'imaps' ? 'ssl' : $use_ssl; |
| | | else if ($use_ssl) |
| | | { |
| | | raise_error(array('code' => 403, 'type' => 'imap', 'file' => __FILE__, |
| | |
| | | // write error log |
| | | else if (!$this->conn && $GLOBALS['iil_error']) |
| | | { |
| | | $this->error_code = $GLOBALS['iil_errornum']; |
| | | raise_error(array('code' => 403, |
| | | 'type' => 'imap', |
| | | 'message' => $GLOBALS['iil_error']), TRUE, FALSE); |
| | |
| | | |
| | | if (empty($this->delimiter)) |
| | | $this->get_hierarchy_delimiter(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Set default message charset |
| | | * |
| | | * This will be used for message decoding if a charset specification is not available |
| | | * |
| | | * @param string Charset string |
| | | * @access public |
| | | */ |
| | | function set_charset($cs) |
| | | { |
| | | $this->default_charset = $ch; |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | $this->search_subject = $subject; |
| | | $this->search_string = $str; |
| | | $this->search_set = is_array($msgs) ? $msgs : NULL; |
| | | $this->search_set = (array)$msgs; |
| | | $this->search_charset = $charset; |
| | | } |
| | | |
| | |
| | | $mailbox = $this->mailbox; |
| | | |
| | | // count search set |
| | | if ($this->search_set && $mailbox == $this->mailbox && $mode == 'ALL') |
| | | return count($this->search_set); |
| | | if ($this->search_string && $mailbox == $this->mailbox && $mode == 'ALL' && !$force) |
| | | return count((array)$this->search_set); |
| | | |
| | | $a_mailbox_cache = $this->get_cache('messagecount'); |
| | | |
| | |
| | | return array(); |
| | | |
| | | // use saved message set |
| | | if ($this->search_set && $mailbox == $this->mailbox) |
| | | if ($this->search_string && $mailbox == $this->mailbox) |
| | | return $this->_list_header_set($mailbox, $this->search_set, $page, $sort_field, $sort_order); |
| | | |
| | | if ($sort_field!=NULL) |
| | | $this->sort_field = $sort_field; |
| | | if ($sort_order!=NULL) |
| | | $this->sort_order = strtoupper($sort_order); |
| | | $this->_set_sort_order($sort_field, $sort_order); |
| | | |
| | | $max = $this->_messagecount($mailbox); |
| | | $start_msg = ($this->list_page-1) * $this->page_size; |
| | |
| | | if (!strlen($mailbox) || empty($msgs)) |
| | | return array(); |
| | | |
| | | if ($sort_field!=NULL) |
| | | $this->sort_field = $sort_field; |
| | | if ($sort_order!=NULL) |
| | | $this->sort_order = strtoupper($sort_order); |
| | | $this->_set_sort_order($sort_field, $sort_order); |
| | | |
| | | $max = count($msgs); |
| | | $start_msg = ($this->list_page-1) * $this->page_size; |
| | |
| | | */ |
| | | function message_index($mbox_name='', $sort_field=NULL, $sort_order=NULL) |
| | | { |
| | | if ($sort_field!=NULL) |
| | | $this->sort_field = $sort_field; |
| | | if ($sort_order!=NULL) |
| | | $this->sort_order = strtoupper($sort_order); |
| | | $this->_set_sort_order($sort_field, $sort_order); |
| | | |
| | | $mailbox = $mbox_name ? $this->_mod_mailbox($mbox_name) : $this->mailbox; |
| | | $key = "$mbox:".$this->sort_field.":".$this->sort_order.".msgi"; |
| | | $key = "{$mailbox}:{$this->sort_field}:{$this->sort_order}:{$this->search_string}.msgi"; |
| | | |
| | | // we have a saved search result. get index from there |
| | | if (!isset($this->cache[$key]) && $this->search_string && $mailbox == $this->mailbox) |
| | | { |
| | | $this->cache[$key] = $a_msg_headers = array(); |
| | | $this->_fetch_headers($mailbox, join(',', $this->search_set), $a_msg_headers, NULL); |
| | | |
| | | foreach (iil_SortHeaders($a_msg_headers, $this->sort_field, $this->sort_order) as $i => $msg) |
| | | $this->cache[$key][] = $msg->uid; |
| | | } |
| | | |
| | | // have stored it in RAM |
| | | if (isset($this->cache[$key])) |
| | |
| | | |
| | | return $this->get_search_set(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Check if the given message ID is part of the current search set |
| | | * |
| | | * @return boolean True on match or if no search request is stored |
| | | */ |
| | | function in_searchset($msgid) |
| | | { |
| | | if (!empty($this->search_string)) |
| | | return in_array("$msgid", (array)$this->search_set, true); |
| | | else |
| | | return true; |
| | | } |
| | | |
| | | |
| | | /** |
| | |
| | | // write headers cache |
| | | if ($headers) |
| | | { |
| | | if ($is_uid) |
| | | $this->uid_id_map[$mbox_name][$uid] = $headers->id; |
| | | if ($headers->uid && $headers->id) |
| | | $this->uid_id_map[$mailbox][$headers->uid] = $headers->id; |
| | | |
| | | $this->add_message_cache($mailbox.'.msg', $headers->id, $headers); |
| | | } |
| | |
| | | if (!empty($structure)) |
| | | { |
| | | $this->_msg_id = $msg_id; |
| | | $headers = $this->get_headers($msg_id, NULL, FALSE); |
| | | $headers = $this->get_headers($uid); |
| | | |
| | | $struct = &$this->_structure_part($structure); |
| | | $struct->headers = get_object_vars($headers); |
| | |
| | | } |
| | | |
| | | // normalize filename property |
| | | if (!empty($struct->d_parameters['filename'])) |
| | | $struct->filename = $this->decode_mime_string($struct->d_parameters['filename']); |
| | | else if (!empty($struct->ctype_parameters['name'])) |
| | | $struct->filename = $this->decode_mime_string($struct->ctype_parameters['name']); |
| | | if ($filename_mime = $struct->d_parameters['filename'] ? $struct->d_parameters['filename'] : $struct->ctype_parameters['name']) |
| | | $struct->filename = rcube_imap::decode_mime_string($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 = $this->decode_mime_string($struct->headers['content-description']); |
| | | $struct->filename = rcube_imap::decode_mime_string($struct->headers['content-description'], $this->default_charset); |
| | | |
| | | return $struct; |
| | | } |
| | |
| | | |
| | | if ($print) |
| | | { |
| | | iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, $part, ($o_part->encoding=='base64'?3:2)); |
| | | $body = TRUE; |
| | | $mode = $o_part->encoding == 'base64' ? 3 : ($o_part->encoding == 'quoted-printable' ? 1 : 2); |
| | | $body = iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, $part, $mode); |
| | | |
| | | // we have to decode the part manually before printing |
| | | if ($mode == 1) |
| | | { |
| | | echo $this->mime_decode($body, $o_part->encoding); |
| | | $body = true; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | $body = iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, $part, 1); |
| | | |
| | | // decode part body |
| | | if ($o_part->encoding=='base64' || $o_part->encoding=='quoted-printable') |
| | | if ($o_part->encoding) |
| | | $body = $this->mime_decode($body, $o_part->encoding); |
| | | |
| | | // convert charset (if text or message part) |
| | | if ($o_part->ctype_primary=='text' || $o_part->ctype_primary=='message') |
| | | { |
| | | // assume ISO-8859-1 if no charset specified |
| | | // assume default if no charset specified |
| | | if (empty($o_part->charset)) |
| | | $o_part->charset = 'ISO-8859-1'; |
| | | $o_part->charset = $this->default_charset; |
| | | |
| | | $body = rcube_charset_convert($body, $o_part->charset); |
| | | } |
| | |
| | | * Set message flag to one or several messages |
| | | * |
| | | * @param mixed Message UIDs as array or as comma-separated string |
| | | * @param string Flag to set: SEEN, UNDELETED, DELETED, RECENT, ANSWERED, DRAFT |
| | | * @param string Flag to set: SEEN, UNDELETED, DELETED, RECENT, ANSWERED, DRAFT, MDNSENT |
| | | * @return boolean True on success, False on failure |
| | | */ |
| | | function set_flag($uids, $flag) |
| | |
| | | // make sure mailbox exists |
| | | if (!in_array($to_mbox, $this->_list_mailboxes())) |
| | | { |
| | | if (in_array(strtolower($to_mbox), $this->default_folders)) |
| | | if (in_array($to_mbox, $this->default_folders)) |
| | | $this->create_mailbox($to_mbox, TRUE); |
| | | else |
| | | return FALSE; |
| | |
| | | |
| | | if ($result>=0 && $clear_cache) |
| | | { |
| | | //$this->clear_message_cache($mailbox.'.msg'); |
| | | $this->clear_message_cache($mailbox.'.msg'); |
| | | $this->_clear_messagecount($mailbox); |
| | | } |
| | | |
| | |
| | | $abs_name = $this->_mod_mailbox($name); |
| | | $a_mailbox_cache = $this->get_cache('mailboxes'); |
| | | |
| | | if (strlen($abs_name) && (!is_array($a_mailbox_cache) || !in_array_nocase($abs_name, $a_mailbox_cache))) |
| | | if (strlen($abs_name) && (!is_array($a_mailbox_cache) || !in_array($abs_name, $a_mailbox_cache))) |
| | | $result = iil_C_CreateFolder($this->conn, $abs_name); |
| | | |
| | | // try to subscribe it |
| | | if ($subscribe) |
| | | if ($result && $subscribe) |
| | | $this->subscribe($name); |
| | | |
| | | return $result ? $name : FALSE; |
| | |
| | | if (strlen($abs_name)) |
| | | $result = iil_C_RenameFolder($this->conn, $mailbox, $abs_name); |
| | | |
| | | // clear cache |
| | | if ($result) |
| | | { |
| | | $delm = $this->get_hierarchy_delimiter(); |
| | | |
| | | // check if mailbox children are subscribed |
| | | foreach ($a_subscribed as $c_subscribed) |
| | | if (preg_match('/^'.preg_quote($mailbox.$delm, '/').'/', $c_subscribed)) |
| | | { |
| | | iil_C_UnSubscribe($this->conn, $c_subscribed); |
| | | iil_C_Subscribe($this->conn, preg_replace('/^'.preg_quote($mailbox, '/').'/', $abs_name, $c_subscribed)); |
| | | } |
| | | |
| | | // clear cache |
| | | $this->clear_message_cache($mailbox.'.msg'); |
| | | $this->clear_cache('mailboxes'); |
| | | } |
| | |
| | | else if (is_string($mbox_name) && strlen($mbox_name)) |
| | | $a_mboxes = explode(',', $mbox_name); |
| | | |
| | | $all_mboxes = iil_C_ListMailboxes($this->conn, $this->_mod_mailbox($root), '*'); |
| | | |
| | | if (is_array($a_mboxes)) |
| | | foreach ($a_mboxes as $mbox_name) |
| | | { |
| | |
| | | $result = iil_C_DeleteFolder($this->conn, $mailbox); |
| | | if ($result>=0) |
| | | $deleted = TRUE; |
| | | |
| | | foreach ($all_mboxes as $c_mbox) |
| | | { |
| | | $regex = preg_quote($mailbox . $this->delimiter, '/'); |
| | | $regex = '/^' . $regex . '/'; |
| | | if (preg_match($regex, $c_mbox)) |
| | | { |
| | | iil_C_UnSubscribe($this->conn, $c_mbox); |
| | | $result = iil_C_DeleteFolder($this->conn, $c_mbox); |
| | | if ($result>=0) |
| | | $deleted = TRUE; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // clear mailboxlist cache |
| | |
| | | foreach ($this->default_folders as $folder) |
| | | { |
| | | $abs_name = $this->_mod_mailbox($folder); |
| | | if (!in_array_nocase($abs_name, $a_subscribed)) |
| | | { |
| | | if (!in_array_nocase($abs_name, $a_folders)) |
| | | $this->create_mailbox($folder, TRUE); |
| | | else |
| | | $this->subscribe($folder); |
| | | } |
| | | else if (!in_array_nocase($abs_name, $a_folders)) |
| | | { |
| | | $this->create_mailbox($folder, FALSE); |
| | | } |
| | | if (!in_array_nocase($abs_name, $a_folders)) |
| | | $this->create_mailbox($folder, TRUE); |
| | | else if (!in_array_nocase($abs_name, $a_subscribed)) |
| | | $this->subscribe($folder); |
| | | } |
| | | } |
| | | |
| | |
| | | { |
| | | $uid = $sql_arr['uid']; |
| | | $this->cache[$cache_key][$uid] = unserialize($sql_arr['headers']); |
| | | |
| | | // featch headers if unserialize failed |
| | | if (empty($this->cache[$cache_key][$uid])) |
| | | $this->cache[$cache_key][$uid] = iil_C_FetchHeader($this->conn, preg_replace('/.msg$/', '', $key), $uid, true); |
| | | } |
| | | } |
| | | |
| | |
| | | */ |
| | | function &get_cached_message($key, $uid, $struct=false) |
| | | { |
| | | if (!$this->caching_enabled) |
| | | return FALSE; |
| | | |
| | | $internal_key = '__single_msg'; |
| | | |
| | | if ($this->caching_enabled && (!isset($this->cache[$internal_key][$uid]) || |
| | | ($struct && empty($this->cache[$internal_key][$uid]->structure)))) |
| | | { |
| | |
| | | */ |
| | | function add_message_cache($key, $index, $headers, $struct=null) |
| | | { |
| | | if (!$this->caching_enabled || empty($key) || !is_object($headers) || empty($headers->uid)) |
| | | if (empty($key) || !is_object($headers) || empty($headers->uid)) |
| | | return; |
| | | |
| | | // add to internal (fast) cache |
| | | $this->cache['__single_msg'][$headers->uid] = $headers; |
| | | $this->cache['__single_msg'][$headers->uid]->structure = $struct; |
| | | |
| | | // no further caching |
| | | if (!$this->caching_enabled) |
| | | return; |
| | | |
| | | |
| | | // check for an existing record (probly headers are cached but structure not) |
| | | $sql_result = $this->db->query( |
| | | "SELECT message_id |
| | |
| | | */ |
| | | function decode_header($input, $remove_quotes=FALSE) |
| | | { |
| | | $str = $this->decode_mime_string((string)$input); |
| | | $str = rcube_imap::decode_mime_string((string)$input, $this->default_charset); |
| | | if ($str{0}=='"' && $remove_quotes) |
| | | $str = str_replace('"', '', $str); |
| | | |
| | |
| | | return rcube_charset_convert($body, $ctype_param['charset']); |
| | | |
| | | // defaults to what is specified in the class header |
| | | return rcube_charset_convert($body, 'ISO-8859-1'); |
| | | return rcube_charset_convert($body, $this->default_charset); |
| | | } |
| | | |
| | | |
| | |
| | | return $mbox_name; |
| | | } |
| | | |
| | | /** |
| | | * Validate the given input and save to local properties |
| | | * @access private |
| | | */ |
| | | function _set_sort_order($sort_field, $sort_order) |
| | | { |
| | | if ($sort_field != null) |
| | | $this->sort_field = asciiwords($sort_field); |
| | | if ($sort_order != null) |
| | | $this->sort_order = strtoupper($sort_order) == 'DESC' ? 'DESC' : 'ASC'; |
| | | } |
| | | |
| | | /** |
| | | * Sort mailboxes first by default folders and then in alphabethical order |
| | |
| | | if ($folder{0}=='.') |
| | | continue; |
| | | |
| | | if (($p = array_search(strtolower($folder), $this->default_folders_lc))!==FALSE) |
| | | if (($p = array_search(strtolower($folder), $this->default_folders_lc)) !== false && !$a_defaults[$p]) |
| | | $a_defaults[$p] = $folder; |
| | | else |
| | | $a_out[] = $folder; |
| | | } |
| | | |
| | | sort($a_out); |
| | | natcasesort($a_out); |
| | | ksort($a_defaults); |
| | | |
| | | return array_merge($a_defaults, $a_out); |
| | |
| | | if (!$mbox_name) |
| | | $mbox_name = $this->mailbox; |
| | | |
| | | return iil_C_ID2UID($this->conn, $mbox_name, $id); |
| | | $index = array_flip((array)$this->uid_id_map[$mbox_name]); |
| | | if (isset($index[$id])) |
| | | $uid = $index[$id]; |
| | | else |
| | | { |
| | | $uid = iil_C_ID2UID($this->conn, $mbox_name, $id); |
| | | $this->uid_id_map[$mbox_name][$uid] = $id; |
| | | } |
| | | |
| | | return $uid; |
| | | } |
| | | |
| | | |