| | |
| | | | program/include/rcube_imap.php | |
| | | | | |
| | | | This file is part of the RoundCube Webmail client | |
| | | | Copyright (C) 2005-2008, RoundCube Dev. - Switzerland | |
| | | | Copyright (C) 2005-2009, RoundCube Dev. - Switzerland | |
| | | | Licensed under the GNU GPL | |
| | | | | |
| | | | PURPOSE: | |
| | |
| | | */ |
| | | require_once('lib/imap.inc'); |
| | | require_once('lib/mime.inc'); |
| | | require_once('lib/tnef_decoder.inc'); |
| | | |
| | | |
| | | /** |
| | |
| | | var $delimiter = NULL; |
| | | var $caching_enabled = FALSE; |
| | | var $default_charset = 'ISO-8859-1'; |
| | | var $struct_charset = NULL; |
| | | var $default_folders = array('INBOX'); |
| | | var $default_folders_lc = array('inbox'); |
| | | var $fetch_add_headers = ''; |
| | | var $cache = array(); |
| | | var $cache_keys = array(); |
| | | var $cache_changes = array(); |
| | |
| | | var $search_sort_field = ''; |
| | | var $debug_level = 1; |
| | | var $error_code = 0; |
| | | var $options = array('imap' => 'check'); |
| | | |
| | | |
| | | /** |
| | |
| | | * @return boolean TRUE on success, FALSE on failure |
| | | * @access public |
| | | */ |
| | | function connect($host, $user, $pass, $port=143, $use_ssl=null, $auth_type=null) |
| | | 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())) |
| | | if ($use_ssl && extension_loaded('openssl')) |
| | | $ICL_SSL = $use_ssl == 'imaps' ? 'ssl' : $use_ssl; |
| | | else if ($use_ssl) |
| | | { |
| | |
| | | $ICL_PORT = $port; |
| | | $IMAP_USE_INTERNAL_DATE = false; |
| | | |
| | | $this->conn = iil_Connect($host, $user, $pass, array('imap' => $auth_type ? $auth_type : 'check')); |
| | | $this->conn = iil_Connect($host, $user, $pass, $this->options); |
| | | $this->host = $host; |
| | | $this->user = $user; |
| | | $this->pass = $pass; |
| | |
| | | iil_C_Select($this->conn, $this->mailbox); |
| | | } |
| | | |
| | | /** |
| | | * Set options to be used in iil_Connect() |
| | | */ |
| | | function set_options($opt) |
| | | { |
| | | $this->options = array_merge($this->options, (array)$opt); |
| | | } |
| | | |
| | | /** |
| | | * Set a root folder for the IMAP connection. |
| | |
| | | $root = substr($root, 0, -1); |
| | | |
| | | $this->root_dir = $root; |
| | | $this->options['rootdir'] = $root; |
| | | |
| | | if (empty($this->delimiter)) |
| | | $this->get_hierarchy_delimiter(); |
| | |
| | | $msgs = split(',', $msgs); |
| | | |
| | | $this->search_string = $str; |
| | | $this->search_set = (array)$msgs; |
| | | $this->search_set = $msgs; |
| | | $this->search_charset = $charset; |
| | | $this->search_sort_field = $sort_field; |
| | | } |
| | |
| | | */ |
| | | function check_permflag($flag) |
| | | { |
| | | $flagsmap = $GLOBALS['IMAP_FLAGS']; |
| | | return (($imap_flag = $flagsmap[strtoupper($flag)]) && in_array_nocase($imap_flag, $this->conn->permanentflags)); |
| | | $flag = strtoupper($flag); |
| | | $imap_flag = $GLOBALS['IMAP_FLAGS'][$flag]; |
| | | return (in_array_nocase($imap_flag, $this->conn->permanentflags)); |
| | | } |
| | | |
| | | |
| | |
| | | if (is_array($a_mboxes)) |
| | | return $a_mboxes; |
| | | |
| | | // retrieve list of folders from IMAP server |
| | | $a_folders = iil_C_ListSubscribed($this->conn, $this->_mod_mailbox($root), $filter); |
| | | // Give plugins a chance to provide a list of mailboxes |
| | | $data = rcmail::get_instance()->plugins->exec_hook('list_mailboxes',array('root'=>$root,'filter'=>$filter)); |
| | | if (isset($data['folders'])) { |
| | | $a_folders = $data['folders']; |
| | | } |
| | | else{ |
| | | // retrieve list of folders from IMAP server |
| | | $a_folders = iil_C_ListSubscribed($this->conn, $this->_mod_mailbox($root), $filter); |
| | | } |
| | | |
| | | |
| | | if (!is_array($a_folders) || !sizeof($a_folders)) |
| | | $a_folders = array(); |
| | |
| | | } |
| | | else { // SEARCH searching result, need sorting |
| | | $cnt = count($msgs); |
| | | if ($cnt > 300) { // experimantal best result |
| | | if ($cnt > 300 && $cnt > $this->page_size) { // experimantal value for best result |
| | | // use memory less expensive (and quick) method for big result set |
| | | $a_index = $this->message_index($mailbox, $this->sort_field, $this->sort_order); |
| | | $a_index = $this->message_index('', $this->sort_field, $this->sort_order); |
| | | // get messages uids for one page... |
| | | $msgs = array_slice(array_keys($a_index), $start_msg, min($cnt-$start_msg, $this->page_size)); |
| | | $msgs = array_slice($a_index, $start_msg, min($cnt-$start_msg, $this->page_size)); |
| | | // ...and fetch headers |
| | | $this->_fetch_headers($mailbox, join(',', $msgs), $a_msg_headers, NULL); |
| | | |
| | |
| | | $cache_index = $this->get_message_cache_index($cache_key); |
| | | |
| | | // fetch reuested headers from server |
| | | $a_header_index = iil_C_FetchHeaders($this->conn, $mailbox, $msgs); |
| | | $a_header_index = iil_C_FetchHeaders($this->conn, $mailbox, $msgs, false, $this->fetch_add_headers); |
| | | $deleted_count = 0; |
| | | |
| | | if (!empty($a_header_index)) |
| | |
| | | // 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->cache[$key] = array(); |
| | | |
| | | if ($this->get_capability('sort')) |
| | | { |
| | | if ($this->sort_field && $this->search_sort_field != $this->sort_field) |
| | | $this->search('', $this->search_string, $this->search_charset, $this->sort_field); |
| | | |
| | | if ($this->sort_order == 'DESC') |
| | | if ($this->sort_order == 'DESC') |
| | | $this->cache[$key] = array_reverse($this->search_set); |
| | | else |
| | | $this->cache[$key] = $this->search_set; |
| | | else |
| | | $this->cache[$key] = $this->search_set; |
| | | } |
| | | else |
| | | { |
| | | $a_index = iil_C_FetchHeaderIndex($this->conn, $mailbox, join(',', $this->search_set), $this->sort_field); |
| | | $a_index = iil_C_FetchHeaderIndex($this->conn, $mailbox, join(',', $this->search_set), $this->sort_field, false); |
| | | |
| | | if ($this->sort_order=="ASC") |
| | | asort($a_index); |
| | | else if ($this->sort_order=="DESC") |
| | | arsort($a_index); |
| | | |
| | | $this->cache[$key] = $a_index; |
| | | $this->cache[$key] = array_keys($a_index); |
| | | } |
| | | } |
| | | |
| | |
| | | if ($cache_status>0) |
| | | { |
| | | $a_index = $this->get_message_cache_index($cache_key, TRUE, $this->sort_field, $this->sort_order); |
| | | return array_values($a_index); |
| | | return array_keys($a_index); |
| | | } |
| | | |
| | | |
| | | // fetch complete message index |
| | | $msg_count = $this->_messagecount($mailbox); |
| | |
| | | else if ($this->sort_order=="DESC") |
| | | arsort($a_index); |
| | | |
| | | $this->cache[$key] = $a_index; |
| | | $this->cache[$key] = array_keys($a_index); |
| | | } |
| | | |
| | | return $this->cache[$key]; |
| | |
| | | |
| | | |
| | | // fetch complete headers and add to cache |
| | | $headers = iil_C_FetchHeader($this->conn, $mailbox, $id); |
| | | $headers = iil_C_FetchHeader($this->conn, $mailbox, $id, false, $this->fetch_add_headers); |
| | | $this->add_message_cache($cache_key, $headers->id, $headers); |
| | | } |
| | | |
| | |
| | | |
| | | $results = $this->_search_index($mailbox, $str, $charset, $sort_field); |
| | | |
| | | // try search with ISO charset (should be supported by server) |
| | | // try search with US-ASCII charset (should be supported by server) |
| | | // only if UTF-8 search is not supported |
| | | if (empty($results) && !is_array($results) && !empty($charset) && $charset!='ISO-8859-1') |
| | | if (empty($results) && !is_array($results) && !empty($charset) && $charset!='US-ASCII') |
| | | { |
| | | // convert strings to ISO-8859-1 |
| | | // convert strings to US_ASCII |
| | | if(preg_match_all('/\{([0-9]+)\}\r\n/', $str, $matches, PREG_OFFSET_CAPTURE)) |
| | | { |
| | | $last = 0; $res = ''; |
| | |
| | | { |
| | | $string_offset = $m[1] + strlen($m[0]) + 4; // {}\r\n |
| | | $string = substr($str, $string_offset - 1, $m[0]); |
| | | $string = rcube_charset_convert($string, $charset, 'ISO-8859-1'); |
| | | $string = rcube_charset_convert($string, $charset, 'US-ASCII'); |
| | | if (!$string) continue; |
| | | $res .= sprintf("%s{%d}\r\n%s", substr($str, $last, $m[1] - $last - 1), strlen($string), $string); |
| | | $last = $m[0] + $string_offset - 1; |
| | | } |
| | |
| | | else // strings for conversion not found |
| | | $res = $str; |
| | | |
| | | $results = $this->search($mbox_name, $res, 'ISO-8859-1', $sort_field); |
| | | $results = $this->search($mbox_name, $res, 'US-ASCII', $sort_field); |
| | | } |
| | | |
| | | $this->set_search_set($str, $results, $charset, $sort_field); |
| | |
| | | * @param int Message ID |
| | | * @param string Mailbox to read from |
| | | * @param boolean True if $id is the message UID |
| | | * @param boolean True if we need also BODYSTRUCTURE in headers |
| | | * @return object Message headers representation |
| | | */ |
| | | function get_headers($id, $mbox_name=NULL, $is_uid=TRUE) |
| | | function get_headers($id, $mbox_name=NULL, $is_uid=TRUE, $bodystr=FALSE) |
| | | { |
| | | $mailbox = $mbox_name ? $this->_mod_mailbox($mbox_name) : $this->mailbox; |
| | | $uid = $is_uid ? $id : $this->_id2uid($id); |
| | |
| | | if ($uid && ($headers = &$this->get_cached_message($mailbox.'.msg', $uid))) |
| | | return $headers; |
| | | |
| | | $headers = iil_C_FetchHeader($this->conn, $mailbox, $id, $is_uid); |
| | | $headers = iil_C_FetchHeader($this->conn, $mailbox, $id, $is_uid, $bodystr, $this->fetch_add_headers); |
| | | |
| | | // write headers cache |
| | | if ($headers) |
| | |
| | | * an object structure similar to the one generated by PEAR::Mail_mimeDecode |
| | | * |
| | | * @param int Message UID to fetch |
| | | * @param string Message BODYSTRUCTURE string (optional) |
| | | * @return object rcube_message_part Message part tree or False on failure |
| | | */ |
| | | function &get_structure($uid) |
| | | function &get_structure($uid, $structure_str='') |
| | | { |
| | | $cache_key = $this->mailbox.'.msg'; |
| | | $headers = &$this->get_cached_message($cache_key, $uid, true); |
| | |
| | | return FALSE; |
| | | } |
| | | |
| | | $structure_str = iil_C_FetchStructureString($this->conn, $this->mailbox, $msg_id); |
| | | if (!$structure_str) |
| | | $structure_str = iil_C_FetchStructureString($this->conn, $this->mailbox, $msg_id); |
| | | $structure = iml_GetRawStructureArray($structure_str); |
| | | $struct = false; |
| | | |
| | |
| | | { |
| | | $this->_msg_id = $msg_id; |
| | | $headers = $this->get_headers($uid); |
| | | |
| | | |
| | | // set message charset from message headers |
| | | if ($headers->charset) |
| | | $this->struct_charset = $headers->charset; |
| | | else |
| | | $this->struct_charset = $this->_structure_charset($structure); |
| | | |
| | | $struct = &$this->_structure_part($structure); |
| | | $struct->headers = get_object_vars($headers); |
| | | |
| | |
| | | * |
| | | * @access private |
| | | */ |
| | | function &_structure_part($part, $count=0, $parent='') |
| | | function &_structure_part($part, $count=0, $parent='', $raw_headers=null) |
| | | { |
| | | $struct = new rcube_message_part; |
| | | $struct->mime_id = empty($parent) ? (string)$count : "$parent.$count"; |
| | |
| | | |
| | | $struct->mimetype = 'multipart/'.$struct->ctype_secondary; |
| | | |
| | | // build parts list for headers pre-fetching |
| | | for ($i=0, $count=0; $i<count($part); $i++) |
| | | if (is_array($part[$i]) && count($part[$i]) > 3) |
| | | // fetch message headers if message/rfc822 or named part (could contain Content-Location header) |
| | | if (strtolower($part[$i][0]) == 'message' || |
| | | (in_array('name', (array)$part[$i][2]) && (empty($part[$i][3]) || $part[$i][3]=='NIL'))) { |
| | | $part_headers[] = $struct->mime_id ? $struct->mime_id.'.'.$i+1 : $i+1; |
| | | } |
| | | |
| | | // pre-fetch headers of all parts (in one command for better performance) |
| | | if ($part_headers) |
| | | $part_headers = iil_C_FetchMIMEHeaders($this->conn, $this->mailbox, $this->_msg_id, $part_headers); |
| | | |
| | | $struct->parts = array(); |
| | | for ($i=0, $count=0; $i<count($part); $i++) |
| | | if (is_array($part[$i]) && count($part[$i]) > 3) |
| | | $struct->parts[] = $this->_structure_part($part[$i], ++$count, $struct->mime_id); |
| | | |
| | | $struct->parts[] = $this->_structure_part($part[$i], ++$count, $struct->mime_id, |
| | | $part_headers[$struct->mime_id ? $struck->mime_id.'.'.$i+1 : $i+1]); |
| | | |
| | | return $struct; |
| | | } |
| | | |
| | |
| | | |
| | | // 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; |
| | | if (empty($raw_headers)) |
| | | $raw_headers = iil_C_FetchPartHeader($this->conn, $this->mailbox, $this->_msg_id, $struct->mime_id); |
| | | $struct->headers = $this->_parse_headers($raw_headers) + $struct->headers; |
| | | } |
| | | |
| | | if ($struct->ctype_primary=='message') { |
| | |
| | | } |
| | | |
| | | // normalize filename property |
| | | $this->_set_part_filename($struct); |
| | | $this->_set_part_filename($struct, $raw_headers); |
| | | |
| | | return $struct; |
| | | } |
| | |
| | | * |
| | | * @access private |
| | | * @param object rcube_message_part Part object |
| | | * @param string Part's raw headers |
| | | */ |
| | | function _set_part_filename(&$part) |
| | | function _set_part_filename(&$part, $headers=null) |
| | | { |
| | | if (!empty($part->d_parameters['filename'])) |
| | | $filename_mime = $part->d_parameters['filename']; |
| | |
| | | } |
| | | // some servers (eg. dovecot-1.x) have no support for parameter value continuations |
| | | // we must fetch and parse headers "manually" |
| | | //TODO: fetching headers for a second time is not effecient, this code should be moved somewhere earlier --tensor |
| | | if ($i<2) { |
| | | // TODO: fetch only Content-Type/Content-Disposition header |
| | | $headers = iil_C_FetchPartHeader($this->conn, $this->mailbox, $this->_msg_id, $part->mime_id); |
| | | if (!$headers) |
| | | $headers = iil_C_FetchPartHeader($this->conn, $this->mailbox, $this->_msg_id, $part->mime_id); |
| | | $filename_mime = ''; |
| | | $i = 0; |
| | | while (preg_match('/filename\*'.$i.'\s*=\s*"*([^"\n;]+)[";]*/', $headers, $matches)) { |
| | |
| | | $i++; |
| | | } |
| | | if ($i<2) { |
| | | $headers = iil_C_FetchPartHeader($this->conn, $this->mailbox, $this->_msg_id, $part->mime_id); |
| | | if (!$headers) |
| | | $headers = iil_C_FetchPartHeader($this->conn, $this->mailbox, $this->_msg_id, $part->mime_id); |
| | | $filename_encoded = ''; |
| | | $i = 0; $matches = array(); |
| | | while (preg_match('/filename\*'.$i.'\*\s*=\s*"*([^"\n;]+)[";]*/', $headers, $matches)) { |
| | |
| | | $i++; |
| | | } |
| | | if ($i<2) { |
| | | $headers = iil_C_FetchPartHeader($this->conn, $this->mailbox, $this->_msg_id, $part->mime_id); |
| | | if (!$headers) |
| | | $headers = iil_C_FetchPartHeader($this->conn, $this->mailbox, $this->_msg_id, $part->mime_id); |
| | | $filename_mime = ''; |
| | | $i = 0; $matches = array(); |
| | | while (preg_match('/\s+name\*'.$i.'\s*=\s*"*([^"\n;]+)[";]*/', $headers, $matches)) { |
| | |
| | | $i++; |
| | | } |
| | | if ($i<2) { |
| | | $headers = iil_C_FetchPartHeader($this->conn, $this->mailbox, $this->_msg_id, $part->mime_id); |
| | | if (!$headers) |
| | | $headers = iil_C_FetchPartHeader($this->conn, $this->mailbox, $this->_msg_id, $part->mime_id); |
| | | $filename_encoded = ''; |
| | | $i = 0; $matches = array(); |
| | | while (preg_match('/\s+name\*'.$i.'\*\s*=\s*"*([^"\n;]+)[";]*/', $headers, $matches)) { |
| | |
| | | // 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)); |
| | | $part->charset ? $part->charset : $this->struct_charset ? $this->struct_charset : |
| | | rc_detect_encoding($filename_mime, $this->default_charset)); |
| | | } |
| | | else if (!empty($filename_encoded)) { |
| | | // decode filename according to RFC 2231, Section 4 |
| | |
| | | $part->filename = rcube_charset_convert(urldecode($filename_encoded), $filename_charset); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * Get charset name from message structure (first part) |
| | | * |
| | | * @access private |
| | | * @param array Message structure |
| | | * @return string Charset name |
| | | */ |
| | | function _structure_charset($structure) |
| | | { |
| | | while (is_array($structure)) { |
| | | if (is_array($structure[2]) && $structure[2][0] == 'charset') |
| | | return $structure[2][1]; |
| | | $structure = $structure[0]; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Fetch message body of a specific message from the server |
| | | * |
| | |
| | | } |
| | | |
| | | // TODO: Add caching for message parts |
| | | |
| | | if (!$part) $part = 'TEXT'; |
| | | |
| | | if ($print) |
| | | { |
| | |
| | | if (!($msg_id = $this->_uid2id($uid))) |
| | | return FALSE; |
| | | |
| | | $body = iil_C_FetchPartHeader($this->conn, $this->mailbox, $msg_id, NULL); |
| | | $body .= iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, NULL, 1); |
| | | |
| | | return $body; |
| | | return iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id); |
| | | } |
| | | |
| | | |
| | |
| | | if (!($msg_id = $this->_uid2id($uid))) |
| | | return FALSE; |
| | | |
| | | print iil_C_FetchPartHeader($this->conn, $this->mailbox, $msg_id, NULL); |
| | | flush(); |
| | | iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, NULL, 2); |
| | | } |
| | | |
| | |
| | | function set_flag($uids, $flag) |
| | | { |
| | | $flag = strtoupper($flag); |
| | | $msg_ids = array(); |
| | | if (!is_array($uids)) |
| | | $uids = explode(',',$uids); |
| | | |
| | | foreach ($uids as $uid) { |
| | | $msg_ids[$uid] = $this->_uid2id($uid); |
| | | } |
| | | |
| | | if ($flag=='UNDELETED') |
| | | $result = iil_C_Undelete($this->conn, $this->mailbox, join(',', array_values($msg_ids))); |
| | | $result = iil_C_Undelete($this->conn, $this->mailbox, join(',', $uids)); |
| | | else if ($flag=='UNSEEN') |
| | | $result = iil_C_Unseen($this->conn, $this->mailbox, join(',', array_values($msg_ids))); |
| | | $result = iil_C_Unseen($this->conn, $this->mailbox, join(',', $uids)); |
| | | else if ($flag=='UNFLAGGED') |
| | | $result = iil_C_UnFlag($this->conn, $this->mailbox, join(',', array_values($msg_ids)), 'FLAGGED'); |
| | | $result = iil_C_UnFlag($this->conn, $this->mailbox, join(',', $uids), 'FLAGGED'); |
| | | else |
| | | $result = iil_C_Flag($this->conn, $this->mailbox, join(',', array_values($msg_ids)), $flag); |
| | | $result = iil_C_Flag($this->conn, $this->mailbox, join(',', $uids), $flag); |
| | | |
| | | // reload message headers if cached |
| | | $cache_key = $this->mailbox.'.msg'; |
| | | if ($this->caching_enabled) |
| | | { |
| | | foreach ($msg_ids as $uid => $id) |
| | | foreach ($uids as $uid) |
| | | { |
| | | if ($cached_headers = $this->get_cached_message($cache_key, $uid)) |
| | | $id = $this->_uid2id($uid); |
| | | if ($cached_headers = $this->get_cached_message($cache_key, $id)) |
| | | { |
| | | $this->remove_message_cache($cache_key, $id); |
| | | //$this->get_headers($uid); |
| | |
| | | } |
| | | |
| | | // set nr of messages that were flaged |
| | | $count = count($msg_ids); |
| | | $count = count($uids); |
| | | |
| | | // clear message count cache |
| | | if ($result && $flag=='SEEN') |
| | |
| | | */ |
| | | function save_message($mbox_name, &$message) |
| | | { |
| | | $mbox_name = stripslashes($mbox_name); |
| | | $mailbox = $this->_mod_mailbox($mbox_name); |
| | | |
| | | // make sure mailbox exists |
| | |
| | | */ |
| | | function move_message($uids, $to_mbox, $from_mbox='') |
| | | { |
| | | $to_mbox_in = stripslashes($to_mbox); |
| | | $from_mbox = stripslashes($from_mbox); |
| | | $to_mbox = $this->_mod_mailbox($to_mbox_in); |
| | | $to_mbox = $this->_mod_mailbox($to_mbox); |
| | | $from_mbox = $from_mbox ? $this->_mod_mailbox($from_mbox) : $this->mailbox; |
| | | |
| | | // make sure mailbox exists |
| | | if (!in_array($to_mbox, $this->_list_mailboxes())) |
| | | if ($to_mbox != 'INBOX' && !in_array($to_mbox, $this->_list_mailboxes())) |
| | | { |
| | | if (in_array($to_mbox_in, $this->default_folders)) |
| | | $this->create_mailbox($to_mbox_in, TRUE); |
| | |
| | | $a_uids = is_string($uids) ? explode(',', $uids) : (is_array($uids) ? $uids : NULL); |
| | | |
| | | // exit if no message uids are specified |
| | | if (!is_array($a_uids)) |
| | | if (!is_array($a_uids) || empty($a_uids)) |
| | | return false; |
| | | |
| | | // convert uids to message ids |
| | | $a_mids = array(); |
| | | foreach ($a_uids as $uid) |
| | | $a_mids[] = $this->_uid2id($uid, $from_mbox); |
| | | |
| | | $iil_move = iil_C_Move($this->conn, join(',', $a_mids), $from_mbox, $to_mbox); |
| | | $iil_move = iil_C_Move($this->conn, join(',', $a_uids), $from_mbox, $to_mbox); |
| | | $moved = !($iil_move === false || $iil_move < 0); |
| | | |
| | | // send expunge command in order to have the moved message |
| | |
| | | } |
| | | // moving failed |
| | | else if (rcmail::get_instance()->config->get('delete_always', false)) { |
| | | return iil_C_Delete($this->conn, $from_mbox, join(',', $a_mids)); |
| | | return iil_C_Delete($this->conn, $from_mbox, join(',', $a_uids)); |
| | | } |
| | | |
| | | // remove message ids from search set |
| | | if ($moved && $this->search_set && $from_mbox == $this->mailbox) |
| | | if ($moved && $this->search_set && $from_mbox == $this->mailbox) { |
| | | foreach ($a_uids as $uid) |
| | | $a_mids[] = $this->_uid2id($uid, $from_mbox); |
| | | $this->search_set = array_diff($this->search_set, $a_mids); |
| | | |
| | | } |
| | | // update cached message headers |
| | | $cache_key = $from_mbox.'.msg'; |
| | | if ($moved && ($a_cache_index = $this->get_message_cache_index($cache_key))) |
| | |
| | | */ |
| | | function delete_message($uids, $mbox_name='') |
| | | { |
| | | $mbox_name = stripslashes($mbox_name); |
| | | $mailbox = $mbox_name ? $this->_mod_mailbox($mbox_name) : $this->mailbox; |
| | | |
| | | // convert the list of uids to array |
| | | $a_uids = is_string($uids) ? explode(',', $uids) : (is_array($uids) ? $uids : NULL); |
| | | |
| | | // exit if no message uids are specified |
| | | if (!is_array($a_uids)) |
| | | if (!is_array($a_uids) || empty($a_uids)) |
| | | return false; |
| | | |
| | | // convert uids to message ids |
| | | $a_mids = array(); |
| | | foreach ($a_uids as $uid) |
| | | $a_mids[] = $this->_uid2id($uid, $mailbox); |
| | | |
| | | $deleted = iil_C_Delete($this->conn, $mailbox, join(',', $a_mids)); |
| | | $deleted = iil_C_Delete($this->conn, $mailbox, join(',', $a_uids)); |
| | | |
| | | // send expunge command in order to have the deleted message |
| | | // really deleted from the mailbox |
| | |
| | | } |
| | | |
| | | // remove message ids from search set |
| | | if ($deleted && $this->search_set && $mailbox == $this->mailbox) |
| | | if ($deleted && $this->search_set && $mailbox == $this->mailbox) { |
| | | foreach ($a_uids as $uid) |
| | | $a_mids[] = $this->_uid2id($uid, $mailbox); |
| | | $this->search_set = array_diff($this->search_set, $a_mids); |
| | | |
| | | } |
| | | |
| | | // remove deleted messages from cache |
| | | $cache_key = $mailbox.'.msg'; |
| | | if ($deleted && ($a_cache_index = $this->get_message_cache_index($cache_key))) |
| | |
| | | */ |
| | | function clear_mailbox($mbox_name=NULL) |
| | | { |
| | | $mbox_name = stripslashes($mbox_name); |
| | | $mailbox = !empty($mbox_name) ? $this->_mod_mailbox($mbox_name) : $this->mailbox; |
| | | $msg_count = $this->_messagecount($mailbox, 'ALL'); |
| | | |
| | |
| | | */ |
| | | function expunge($mbox_name='', $clear_cache=TRUE) |
| | | { |
| | | $mbox_name = stripslashes($mbox_name); |
| | | $mailbox = $mbox_name ? $this->_mod_mailbox($mbox_name) : $this->mailbox; |
| | | return $this->_expunge($mailbox, $clear_cache); |
| | | } |
| | |
| | | { |
| | | $result = FALSE; |
| | | |
| | | // replace backslashes |
| | | $name = preg_replace('/[\\\]+/', '-', $name); |
| | | |
| | | // reduce mailbox name to 100 chars |
| | | $name = substr($name, 0, 100); |
| | | |
| | |
| | | { |
| | | $result = FALSE; |
| | | |
| | | // replace backslashes |
| | | $name = preg_replace('/[\\\]+/', '-', $new_name); |
| | | |
| | | // encode mailbox name and reduce it to 100 chars |
| | | $name = substr($new_name, 0, 100); |
| | | |
| | |
| | | { |
| | | $this->db->query( |
| | | "UPDATE ".get_table_name('cache')." |
| | | SET created=".$this->db->now().", |
| | | data=? |
| | | SET created=". $this->db->now().", data=? |
| | | WHERE user_id=? |
| | | AND cache_key=?", |
| | | $data, |
| | |
| | | if ($cache_count==$msg_count) |
| | | { |
| | | // get highest index |
| | | $header = iil_C_FetchHeader($this->conn, $mailbox, "$msg_count"); |
| | | $header = iil_C_FetchHeader($this->conn, $mailbox, "$msg_count", false, $this->fetch_add_headers); |
| | | $cache_uid = array_pop($cache_index); |
| | | |
| | | // uids of highest message matches -> cache seems OK |
| | |
| | | |
| | | // 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); |
| | | $this->cache[$cache_key][$uid] = iil_C_FetchHeader($this->conn, preg_replace('/.msg$/', '', $key), $uid, true, $this->fetch_add_headers); |
| | | } |
| | | } |
| | | |
| | |
| | | { |
| | | 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; |
| | |
| | | |
| | | return $out; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Decode a Microsoft Outlook TNEF part (winmail.dat) |
| | | * |
| | | * @param object rcube_message_part Message part to decode |
| | | * @param string UID of the message |
| | | * @return array List of rcube_message_parts extracted from windmail.dat |
| | | */ |
| | | function tnef_decode(&$part, $uid) |
| | | { |
| | | if (!isset($part->body)) |
| | | $part->body = $this->get_message_part($uid, $part->mime_id, $part); |
| | | |
| | | $pid = 0; |
| | | $tnef_parts = array(); |
| | | $tnef_arr = tnef_decode($part->body); |
| | | foreach ($tnef_arr as $winatt) { |
| | | $tpart = new rcube_message_part; |
| | | $tpart->filename = $winatt["name"]; |
| | | $tpart->encoding = 'stream'; |
| | | $tpart->ctype_primary = $winatt["type0"]; |
| | | $tpart->ctype_secondary = $winatt["type1"]; |
| | | $tpart->mimetype = strtolower($winatt["type0"] . "/" . $winatt["type1"]); |
| | | $tpart->mime_id = "winmail." . $part->mime_id . ".$pid"; |
| | | $tpart->size = $winatt["size"]; |
| | | $tpart->body = $winatt['stream']; |
| | | |
| | | $tnef_parts[] = $tpart; |
| | | $pid++; |
| | | } |
| | | |
| | | return $tnef_parts; |
| | | } |
| | | |
| | | |
| | | /** |
| | |
| | | /** |
| | | * Decode a mime-encoded string to internal charset |
| | | * |
| | | * @param string Header value |
| | | * @param string Fallback charset if none specified |
| | | * @param string $input Header value |
| | | * @param string $fallback Fallback charset if none specified |
| | | * |
| | | * @return string Decoded string |
| | | * @static |
| | | */ |
| | | function decode_mime_string($input, $fallback=null) |
| | | public static function decode_mime_string($input, $fallback=null) |
| | | { |
| | | // Initialize variable |
| | | $out = ''; |
| | |
| | | $folders[$folder] = rc_strtolower(rcube_charset_convert($folder, 'UTF-7')); |
| | | } |
| | | |
| | | // sort folders and place defaults on the top |
| | | asort($folders, SORT_LOCALE_STRING); |
| | | ksort($a_defaults); |
| | | |
| | | $folders = array_merge($a_defaults, array_keys($folders)); |
| | | |
| | | // finally we must rebuild the list to move |
| | | // subfolders of default folders to their place... |
| | | // ...also do this for the rest of folders because |
| | | // asort() is not properly sorting case sensitive names |
| | | |
| | | // set the type of folder name variable (#1485527) |
| | | while (list($key, $folder) = each($folders)) { |
| | | // set the type of folder name variable (#1485527) |
| | | $a_out[] = (string) $folder; |
| | | unset($folders[$key]); |
| | | foreach ($folders as $idx => $f) { |
| | | if (strpos($f, $folder.$delimiter) === 0) { |
| | | $a_out[] = (string) $f; |
| | | unset($folders[$idx]); |
| | | } |
| | | } |
| | | reset($folders); |
| | | $this->_rsort($folder, $delimiter, $folders, $a_out); |
| | | } |
| | | |
| | | return $a_out; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * @access private |
| | | */ |
| | | function _rsort($folder, $delimiter, &$list, &$out) |
| | | { |
| | | while (list($key, $name) = each($list)) { |
| | | if (strpos($name, $folder.$delimiter) === 0) { |
| | | // set the type of folder name variable (#1485527) |
| | | $out[] = (string) $name; |
| | | unset($list[$key]); |
| | | $this->_rsort($name, $delimiter, $list, $out); |
| | | } |
| | | } |
| | | reset($list); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * @access private |
| | |
| | | function _parse_address_list($str, $decode=true) |
| | | { |
| | | // remove any newlines and carriage returns before |
| | | $a = $this->_explode_quoted_string('[,;]', preg_replace( "/[\r\n]/", " ", $str)); |
| | | $a = rcube_explode_quoted_string('[,;]', preg_replace( "/[\r\n]/", " ", $str)); |
| | | $result = array(); |
| | | |
| | | |
| | | foreach ($a as $key => $val) |
| | | { |
| | | $val = preg_replace("/([\"\w])</", "$1 <", $val); |
| | | $sub_a = $this->_explode_quoted_string(' ', $decode ? $this->decode_header($val) : $val); |
| | | $sub_a = rcube_explode_quoted_string(' ', $decode ? $this->decode_header($val) : $val); |
| | | $result[$key]['name'] = ''; |
| | | |
| | | foreach ($sub_a as $k => $v) |
| | | { |
| | | if (strpos($v, '@') > 0) |
| | | $result[$key]['address'] = str_replace('<', '', str_replace('>', '', $v)); |
| | | // use angle brackets in regexp to not handle names with @ sign |
| | | if (preg_match('/^<\S+@\S+>$/', $v)) |
| | | $result[$key]['address'] = trim($v, '<>'); |
| | | else |
| | | $result[$key]['name'] .= (empty($result[$key]['name'])?'':' ').str_replace("\"",'',stripslashes($v)); |
| | | } |
| | | |
| | | if (empty($result[$key]['name'])) |
| | | $result[$key]['name'] = $result[$key]['address']; |
| | | elseif (empty($result[$key]['address'])) |
| | | $result[$key]['address'] = $result[$key]['name']; |
| | | } |
| | | |
| | | return $result; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * @access private |
| | | */ |
| | | function _explode_quoted_string($delimiter, $string) |
| | | { |
| | | $result = array(); |
| | | $strlen = strlen($string); |
| | | for ($q=$p=$i=0; $i < $strlen; $i++) |
| | | { |
| | | if ($string{$i} == "\"" && $string{$i-1} != "\\") |
| | | $q = $q ? false : true; |
| | | else if (!$q && preg_match("/$delimiter/", $string{$i})) |
| | | { |
| | | $result[] = substr($string, $p, $i - $p); |
| | | $p = $i + 1; |
| | | } |
| | | } |
| | | |
| | | $result[] = substr($string, $p); |
| | | return $result; |
| | | } |
| | | |