| | |
| | | { |
| | | if (is_array($str) && $msgs == null) |
| | | list($str, $msgs, $charset, $sort_field, $threads) = $str; |
| | | if ($msgs != null && !is_array($msgs)) |
| | | if ($msgs === false) |
| | | $msgs = array(); |
| | | else if ($msgs != null && !is_array($msgs)) |
| | | $msgs = explode(',', $msgs); |
| | | |
| | | $this->search_string = $str; |
| | |
| | | // get message count and store in cache |
| | | if ($mode == 'UNSEEN') |
| | | $search_str .= " UNSEEN"; |
| | | |
| | | // get message count using SEARCH |
| | | // not very performant but more precise (using UNDELETED) |
| | | // disable THREADS for this request |
| | |
| | | else |
| | | $msg_index = array(); |
| | | |
| | | if ($slice) |
| | | if ($slice && $msg_index) |
| | | $msg_index = array_slice($msg_index, ($this->sort_order == 'DESC' ? 0 : -$slice), $slice); |
| | | |
| | | // fetch reqested headers from server |
| | |
| | | return $this->_list_thread_header_set($mailbox, $page, $sort_field, $sort_order, $slice); |
| | | |
| | | // search set is threaded, we need a new one |
| | | if ($this->search_threads) |
| | | if ($this->search_threads) { |
| | | if (empty($this->search_set['tree'])) |
| | | return array(); |
| | | $this->search('', $this->search_string, $this->search_charset, $sort_field); |
| | | } |
| | | |
| | | $msgs = $this->search_set; |
| | | $a_msg_headers = array(); |
| | |
| | | private function _list_thread_header_set($mailbox, $page=NULL, $sort_field=NULL, $sort_order=NULL, $slice=0) |
| | | { |
| | | // update search_set if previous data was fetched with disabled threading |
| | | if (!$this->search_threads) |
| | | if (!$this->search_threads) { |
| | | if (empty($this->search_set)) |
| | | return array(); |
| | | $this->search('', $this->search_string, $this->search_charset, $sort_field); |
| | | } |
| | | |
| | | // empty result |
| | | if (empty($this->search_set['tree'])) |
| | | return array(); |
| | | |
| | | $thread_tree = $this->search_set['tree']; |
| | | $msg_depth = $this->search_set['depth']; |
| | |
| | | $a_index = range(1, $max); |
| | | } |
| | | |
| | | if ($this->sort_order == 'DESC') |
| | | if ($a_index !== false && $this->sort_order == 'DESC') |
| | | $a_index = array_reverse($a_index); |
| | | |
| | | $this->cache[$key] = $a_index; |
| | | } |
| | | // fetch complete message index |
| | | else if ($this->get_capability('SORT')) { |
| | | if ($a_index = $this->conn->sort($mailbox, |
| | | $this->sort_field, $this->skip_deleted ? 'UNDELETED' : '')) { |
| | | if ($this->sort_order == 'DESC') |
| | | $a_index = array_reverse($a_index); |
| | | $a_index = $this->conn->sort($mailbox, |
| | | $this->sort_field, $this->skip_deleted ? 'UNDELETED' : ''); |
| | | |
| | | $this->cache[$key] = $a_index; |
| | | } |
| | | if ($a_index !== false && $this->sort_order == 'DESC') |
| | | $a_index = array_reverse($a_index); |
| | | |
| | | $this->cache[$key] = $a_index; |
| | | } |
| | | else if ($a_index = $this->conn->fetchHeaderIndex( |
| | | $mailbox, "1:*", $this->sort_field, $this->skip_deleted)) { |
| | |
| | | $this->cache[$key] = array_keys($a_index); |
| | | } |
| | | |
| | | return $this->cache[$key]; |
| | | return $this->cache[$key] !== false ? $this->cache[$key] : array(); |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | $results = $this->_search_index($mailbox, $str, $charset, $sort_field); |
| | | |
| | | // 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 != 'US-ASCII') |
| | | { |
| | | // convert strings to US_ASCII |
| | | if(preg_match_all('/\{([0-9]+)\}\r\n/', $str, $matches, PREG_OFFSET_CAPTURE)) { |
| | | $last = 0; $res = ''; |
| | | foreach($matches[1] as $m) |
| | | { |
| | | $string_offset = $m[1] + strlen($m[0]) + 4; // {}\r\n |
| | | $string = substr($str, $string_offset - 1, $m[0]); |
| | | $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; |
| | | } |
| | | if ($last < strlen($str)) |
| | | $res .= substr($str, $last, strlen($str)-$last); |
| | | } |
| | | else // strings for conversion not found |
| | | $res = $str; |
| | | |
| | | $results = $this->search($mbox_name, $res, NULL, $sort_field); |
| | | } |
| | | |
| | | $this->set_search_set($str, $results, $charset, $sort_field, (bool)$this->threading); |
| | | |
| | | return $results; |
| | |
| | | $criteria = 'UNDELETED '.$criteria; |
| | | |
| | | if ($this->threading) { |
| | | list ($thread_tree, $msg_depth, $has_children) = $this->conn->thread( |
| | | $mailbox, $this->threading, $criteria, $charset); |
| | | $a_messages = $this->conn->thread($mailbox, $this->threading, $criteria, $charset); |
| | | |
| | | $a_messages = array( |
| | | 'tree' => $thread_tree, |
| | | 'depth' => $msg_depth, |
| | | 'children' => $has_children |
| | | ); |
| | | // Error, try with US-ASCII (RFC5256: SORT/THREAD must support US-ASCII and UTF-8, |
| | | // but I've seen that Courier doesn't support UTF-8) |
| | | if ($a_messages === false && $charset && $charset != 'US-ASCII') |
| | | $a_messages = $this->conn->thread($mailbox, $this->threading, |
| | | $this->convert_criteria($criteria, $charset), 'US-ASCII'); |
| | | |
| | | if ($a_messages !== false) { |
| | | list ($thread_tree, $msg_depth, $has_children) = $a_messages; |
| | | $a_messages = array( |
| | | 'tree' => $thread_tree, |
| | | 'depth' => $msg_depth, |
| | | 'children' => $has_children |
| | | ); |
| | | } |
| | | } |
| | | else if ($sort_field && $this->get_capability('SORT')) { |
| | | $charset = $charset ? $charset : $this->default_charset; |
| | | $a_messages = $this->conn->sort($mailbox, $sort_field, $criteria, false, $charset); |
| | | |
| | | if (!$a_messages) |
| | | return array(); |
| | | // Error, try with US-ASCII (RFC5256: SORT/THREAD must support US-ASCII and UTF-8, |
| | | // but I've seen that Courier doesn't support UTF-8) |
| | | if ($a_messages === false && $charset && $charset != 'US-ASCII') |
| | | $a_messages = $this->conn->sort($mailbox, $sort_field, |
| | | $this->convert_criteria($criteria, $charset), false, 'US-ASCII'); |
| | | } |
| | | else { |
| | | if ($orig_criteria == 'ALL') { |
| | |
| | | } |
| | | else { |
| | | $a_messages = $this->conn->search($mailbox, |
| | | ($charset ? "CHARSET $charset " : '') . $criteria); |
| | | ($charset ? "CHARSET $charset " : '') . $criteria); |
| | | |
| | | if (!$a_messages) |
| | | return array(); |
| | | // Error, try with US-ASCII (some servers may support only US-ASCII) |
| | | if ($a_messages === false && $charset && $charset != 'US-ASCII') |
| | | $a_messages = $this->conn->search($mailbox, |
| | | 'CHARSET US-ASCII ' . $this->convert_criteria($criteria, $charset)); |
| | | |
| | | // I didn't found that SEARCH always returns sorted IDs |
| | | if (!$this->sort_field) |
| | | sort($a_messages); |
| | | // I didn't found that SEARCH should return sorted IDs |
| | | if (is_array($a_messages) && !$this->sort_field) |
| | | sort($a_messages); |
| | | } |
| | | } |
| | | |
| | |
| | | $mailbox = $mbox_name ? $this->mod_mailbox($mbox_name) : $this->mailbox; |
| | | |
| | | return $this->conn->search($mailbox, $str, $ret_uid); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Converts charset of search criteria string |
| | | * |
| | | * @param string Search string |
| | | * @param string Original charset |
| | | * @param string Destination charset (default US-ASCII) |
| | | * @return string Search string |
| | | * @access private |
| | | */ |
| | | private function convert_criteria($str, $charset, $dest_charset='US-ASCII') |
| | | { |
| | | // convert strings to US_ASCII |
| | | if (preg_match_all('/\{([0-9]+)\}\r\n/', $str, $matches, PREG_OFFSET_CAPTURE)) { |
| | | $last = 0; $res = ''; |
| | | foreach ($matches[1] as $m) { |
| | | $string_offset = $m[1] + strlen($m[0]) + 4; // {}\r\n |
| | | $string = substr($str, $string_offset - 1, $m[0]); |
| | | $string = rcube_charset_convert($string, $charset, $dest_charset); |
| | | 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; |
| | | } |
| | | if ($last < strlen($str)) |
| | | $res .= substr($str, $last, strlen($str)-$last); |
| | | } |
| | | else // strings for conversion not found |
| | | $res = $str; |
| | | |
| | | return $res; |
| | | } |
| | | |
| | | |
| | |
| | | return true; |
| | | |
| | | // convert charset (if text or message part) |
| | | if ($o_part->ctype_primary=='text' || $o_part->ctype_primary=='message') { |
| | | if ($o_part->ctype_primary == 'text' || $o_part->ctype_primary == 'message') { |
| | | // assume default if no charset specified |
| | | if (empty($o_part->charset) || strtolower($o_part->charset) == 'us-ascii') |
| | | $o_part->charset = $this->default_charset; |
| | |
| | | * --------------------------------*/ |
| | | |
| | | /** |
| | | * Public method for mailbox listing. |
| | | * Public method for listing subscribed folders |
| | | * |
| | | * Converts mailbox name with root dir first |
| | | * |
| | |
| | | */ |
| | | private function _list_mailboxes($root='', $filter='*') |
| | | { |
| | | $a_defaults = $a_out = array(); |
| | | |
| | | // get cached folder list |
| | | $a_mboxes = $this->get_cache('mailboxes'); |
| | | if (is_array($a_mboxes)) |
| | | return $a_mboxes; |
| | | |
| | | $a_defaults = $a_out = array(); |
| | | |
| | | // Give plugins a chance to provide a list of mailboxes |
| | | $data = rcmail::get_instance()->plugins->exec_hook('list_mailboxes', |
| | | array('root'=>$root,'filter'=>$filter)); |
| | | array('root' => $root, 'filter' => $filter, 'mode' => 'LSUB')); |
| | | |
| | | if (isset($data['folders'])) { |
| | | $a_folders = $data['folders']; |
| | |
| | | * Get a list of all folders available on the IMAP server |
| | | * |
| | | * @param string IMAP root dir |
| | | * @param string Optional filter for mailbox listing |
| | | * @return array Indexed array with folder names |
| | | */ |
| | | function list_unsubscribed($root='') |
| | | function list_unsubscribed($root='', $filter='*') |
| | | { |
| | | static $a_folders; |
| | | // Give plugins a chance to provide a list of mailboxes |
| | | $data = rcmail::get_instance()->plugins->exec_hook('list_mailboxes', |
| | | array('root' => $root, 'filter' => $filter, 'mode' => 'LIST')); |
| | | |
| | | if (is_array($a_folders)) |
| | | return $a_folders; |
| | | |
| | | // retrieve list of folders from IMAP server |
| | | $a_mboxes = $this->conn->listMailboxes($this->mod_mailbox($root), '*'); |
| | | if (isset($data['folders'])) { |
| | | $a_mboxes = $data['folders']; |
| | | } |
| | | else { |
| | | // retrieve list of folders from IMAP server |
| | | $a_mboxes = $this->conn->listMailboxes($this->mod_mailbox($root), $filter); |
| | | } |
| | | |
| | | $a_folders = array(); |
| | | if (!is_array($a_mboxes)) |
| | | $a_mboxes = array(); |
| | | |
| | | // modify names with root dir |
| | | foreach ($a_mboxes as $idx => $mbox_name) { |
| | |
| | | } |
| | | |
| | | 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); |
| | | |
| | | require_once('lib/tnef_decoder.inc'); |
| | | |
| | | $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; |
| | | } |
| | | |
| | | |