| | |
| | | | program/include/rcube_imap.php | |
| | | | | |
| | | | This file is part of the Roundcube Webmail client | |
| | | | Copyright (C) 2005-2010, Roundcube Dev. - Switzerland | |
| | | | Copyright (C) 2005-2010, The Roundcube Dev Team | |
| | | | Licensed under the GNU GPL | |
| | | | | |
| | | | PURPOSE: | |
| | |
| | | 'RETURN-PATH', |
| | | ); |
| | | |
| | | const UNKNOWN = 0; |
| | | const NOPERM = 1; |
| | | const READONLY = 2; |
| | | const TRYCREATE = 3; |
| | | const INUSE = 4; |
| | | const OVERQUOTA = 5; |
| | | const ALREADYEXISTS = 6; |
| | | const NONEXISTENT = 7; |
| | | const CONTACTADMIN = 8; |
| | | |
| | | |
| | | /** |
| | | * Object constructor |
| | |
| | | |
| | | $this->options['port'] = $port; |
| | | |
| | | if ($this->options['debug']) { |
| | | $this->conn->setDebug(true, array($this, 'debug_handler')); |
| | | |
| | | $this->options['ident'] = array( |
| | | 'name' => 'Roundcube Webmail', |
| | | 'version' => RCMAIL_VERSION, |
| | | 'php' => PHP_VERSION, |
| | | 'os' => PHP_OS, |
| | | 'command' => $_SERVER['REQUEST_URI'], |
| | | ); |
| | | } |
| | | |
| | | $attempt = 0; |
| | | do { |
| | | $data = rcmail::get_instance()->plugins->exec_hook('imap_connect', |
| | |
| | | $this->ssl = $use_ssl; |
| | | |
| | | if ($this->conn->connected()) { |
| | | // print trace messages |
| | | if ($this->conn->message && ($this->debug_level & 8)) { |
| | | console($this->conn->message); |
| | | } |
| | | // get namespace and delimiter |
| | | $this->set_env(); |
| | | |
| | | return true; |
| | | } |
| | | // write error log |
| | | else if ($this->conn->error) { |
| | | if ($pass && $user) |
| | | if ($pass && $user) { |
| | | $message = sprintf("Login failed for %s from %s. %s", |
| | | $user, rcmail_remote_ip(), $this->conn->error); |
| | | |
| | | raise_error(array('code' => 403, 'type' => 'imap', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => $this->conn->error), true, false); |
| | | 'message' => $message), true, false); |
| | | } |
| | | } |
| | | |
| | | return false; |
| | |
| | | */ |
| | | function reconnect() |
| | | { |
| | | $this->closeConnection(); |
| | | $this->connect($this->host, $this->user, $this->pass, $this->port, $this->ssl); |
| | | $this->conn->closeConnection(); |
| | | $connected = $this->connect($this->host, $this->user, $this->pass, $this->port, $this->ssl); |
| | | |
| | | // issue SELECT command to restore connection status |
| | | if ($this->mailbox) |
| | | if ($connected && strlen($this->mailbox)) |
| | | $this->conn->select($this->mailbox); |
| | | } |
| | | |
| | |
| | | */ |
| | | function get_error_code() |
| | | { |
| | | return ($this->conn) ? $this->conn->errornum : 0; |
| | | return $this->conn->errornum; |
| | | } |
| | | |
| | | |
| | |
| | | */ |
| | | function get_error_str() |
| | | { |
| | | return ($this->conn) ? $this->conn->error : ''; |
| | | return $this->conn->error; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Returns code of last command response |
| | | * |
| | | * @return int Response code |
| | | */ |
| | | function get_response_code() |
| | | { |
| | | switch ($this->conn->resultcode) { |
| | | case 'NOPERM': |
| | | return self::NOPERM; |
| | | case 'READ-ONLY': |
| | | return self::READONLY; |
| | | case 'TRYCREATE': |
| | | return self::TRYCREATE; |
| | | case 'INUSE': |
| | | return self::INUSE; |
| | | case 'OVERQUOTA': |
| | | return self::OVERQUOTA; |
| | | case 'ALREADYEXISTS': |
| | | return self::ALREADYEXISTS; |
| | | case 'NONEXISTENT': |
| | | return self::NONEXISTENT; |
| | | case 'CONTACTADMIN': |
| | | return self::CONTACTADMIN; |
| | | default: |
| | | return self::UNKNOWN; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Returns last command response |
| | | * |
| | | * @return string Response |
| | | */ |
| | | function get_response_str() |
| | | { |
| | | return $this->conn->result; |
| | | } |
| | | |
| | | |
| | |
| | | * @param string $mailbox Mailbox/Folder name |
| | | * @access public |
| | | */ |
| | | function select_mailbox($mailbox) |
| | | function select_mailbox($mailbox=null) |
| | | { |
| | | $mailbox = $this->mod_mailbox($mailbox); |
| | | $mailbox = strlen($mailbox) ? $this->mod_mailbox($mailbox) : $this->mailbox; |
| | | |
| | | $selected = $this->conn->select($mailbox); |
| | | |
| | |
| | | { |
| | | $this->threading = false; |
| | | |
| | | if ($enable) { |
| | | if ($this->get_capability('THREAD=REFS')) |
| | | if ($enable && ($caps = $this->get_capability('THREAD'))) { |
| | | if (in_array('REFS', $caps)) |
| | | $this->threading = 'REFS'; |
| | | else if ($this->get_capability('THREAD=REFERENCES')) |
| | | else if (in_array('REFERENCES', $caps)) |
| | | $this->threading = 'REFERENCES'; |
| | | else if ($this->get_capability('THREAD=ORDEREDSUBJECT')) |
| | | else if (in_array('ORDEREDSUBJECT', $caps)) |
| | | $this->threading = 'ORDEREDSUBJECT'; |
| | | } |
| | | |
| | |
| | | $imap_shared = $config->get('imap_ns_shared'); |
| | | $imap_delimiter = $config->get('imap_delimiter'); |
| | | |
| | | if ($imap_delimiter) { |
| | | $this->delimiter = $imap_delimiter; |
| | | } |
| | | |
| | | if (!$this->conn) |
| | | if (!$this->conn->connected()) |
| | | return; |
| | | |
| | | $ns = $this->conn->getNamespace(); |
| | | |
| | | // NAMESPACE supported |
| | | // Set namespaces (NAMESPACE supported) |
| | | if (is_array($ns)) { |
| | | $this->namespace = $ns; |
| | | |
| | | if (empty($this->delimiter)) |
| | | $this->delimiter = $ns['personal'][0][1]; |
| | | if (empty($this->delimiter)) |
| | | $this->delimiter = $this->conn->getHierarchyDelimiter(); |
| | | if (empty($this->delimiter)) |
| | | $this->delimiter = '/'; |
| | | } |
| | | // not supported, get namespace from config |
| | | else if ($imap_personal !== null || $imap_shared !== null || $imap_other !== null) { |
| | | if (empty($this->delimiter)) |
| | | $this->delimiter = $this->conn->getHierarchyDelimiter(); |
| | | if (empty($this->delimiter)) |
| | | $this->delimiter = '/'; |
| | | |
| | | else { |
| | | $this->namespace = array( |
| | | 'personal' => NULL, |
| | | 'other' => NULL, |
| | | 'shared' => NULL, |
| | | ); |
| | | } |
| | | |
| | | if ($imap_personal !== null) { |
| | | foreach ((array)$imap_personal as $dir) { |
| | | $this->namespace['personal'][] = array($dir, $this->delimiter); |
| | | if ($imap_delimiter) { |
| | | $this->delimiter = $imap_delimiter; |
| | | } |
| | | if (empty($this->delimiter)) { |
| | | $this->delimiter = $this->namespace['personal'][0][1]; |
| | | } |
| | | if (empty($this->delimiter)) { |
| | | $this->delimiter = $this->conn->getHierarchyDelimiter(); |
| | | } |
| | | if (empty($this->delimiter)) { |
| | | $this->delimiter = '/'; |
| | | } |
| | | |
| | | // Overwrite namespaces |
| | | if ($imap_personal !== null) { |
| | | $this->namespace['personal'] = NULL; |
| | | foreach ((array)$imap_personal as $dir) { |
| | | $this->namespace['personal'][] = array($dir, $this->delimiter); |
| | | } |
| | | } |
| | | if ($imap_other !== null) { |
| | | $this->namespace['other'] = NULL; |
| | | foreach ((array)$imap_other as $dir) { |
| | | if ($dir) { |
| | | $this->namespace['other'][] = array($dir, $this->delimiter); |
| | | } |
| | | } |
| | | if ($imap_other !== null) { |
| | | foreach ((array)$imap_other as $dir) { |
| | | if ($dir) { |
| | | $this->namespace['other'][] = array($dir, $this->delimiter); |
| | | } |
| | | } |
| | | } |
| | | if ($imap_shared !== null) { |
| | | foreach ((array)$imap_shared as $dir) { |
| | | if ($dir) { |
| | | $this->namespace['shared'][] = array($dir, $this->delimiter); |
| | | } |
| | | } |
| | | if ($imap_shared !== null) { |
| | | $this->namespace['shared'] = NULL; |
| | | foreach ((array)$imap_shared as $dir) { |
| | | if ($dir) { |
| | | $this->namespace['shared'][] = array($dir, $this->delimiter); |
| | | } |
| | | } |
| | | } |
| | |
| | | return false; |
| | | } |
| | | |
| | | $struct = &$this->_structure_part($structure); |
| | | $struct = &$this->_structure_part($structure, 0, '', $headers); |
| | | $struct->headers = get_object_vars($headers); |
| | | |
| | | // don't trust given content-type |
| | |
| | | $struct->charset = $struct->ctype_parameters['charset']; |
| | | } |
| | | |
| | | // #1487700: workaround for lack of charset in malformed structure |
| | | if (empty($struct->charset) && !empty($mime_headers) && $mime_headers->charset) { |
| | | $struct->charset = $mime_headers->charset; |
| | | } |
| | | |
| | | // read content encoding |
| | | if (!empty($part[5]) && $part[5]!='NIL') { |
| | | $struct->encoding = strtolower($part[5]); |
| | |
| | | $mime_headers = $this->conn->fetchPartHeader( |
| | | $this->mailbox, $this->_msg_id, false, $struct->mime_id); |
| | | } |
| | | $struct->headers = $this->_parse_headers($mime_headers) + $struct->headers; |
| | | |
| | | if (is_string($mime_headers)) |
| | | $struct->headers = $this->_parse_headers($mime_headers) + $struct->headers; |
| | | else if (is_object($mime_headers)) |
| | | $struct->headers = get_object_vars($mime_headers) + $struct->headers; |
| | | |
| | | // get real content-type of message/rfc822 |
| | | if ($struct->mimetype == 'message/rfc822') { |
| | |
| | | * @param rcube_message_part $o_part Part object created by get_structure() |
| | | * @param mixed $print True to print part, ressource to write part contents in |
| | | * @param resource $fp File pointer to save the message part |
| | | * @param boolean $skip_charset_conv Disables charset conversion |
| | | * |
| | | * @return string Message/part body if not printed |
| | | */ |
| | | function &get_message_part($uid, $part=1, $o_part=NULL, $print=NULL, $fp=NULL) |
| | | function &get_message_part($uid, $part=1, $o_part=NULL, $print=NULL, $fp=NULL, $skip_charset_conv=false) |
| | | { |
| | | // get part encoding if not provided |
| | | if (!is_object($o_part)) { |
| | |
| | | |
| | | // TODO: Add caching for message parts |
| | | |
| | | if (!$part) $part = 'TEXT'; |
| | | if (!$part) { |
| | | $part = 'TEXT'; |
| | | } |
| | | |
| | | $body = $this->conn->handlePartBody($this->mailbox, $uid, true, $part, |
| | | $o_part->encoding, $print, $fp); |
| | | |
| | | if ($fp || $print) |
| | | if ($fp || $print) { |
| | | return true; |
| | | } |
| | | |
| | | // convert charset (if text or message part) |
| | | if ($body && ($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') |
| | | if ($body && !$skip_charset_conv && |
| | | preg_match('/^(text|message)$/', $o_part->ctype_primary) |
| | | ) { |
| | | if (!$o_part->charset || strtoupper($o_part->charset) == 'US-ASCII') { |
| | | $o_part->charset = $this->default_charset; |
| | | |
| | | } |
| | | $body = rcube_charset_convert($body, $o_part->charset); |
| | | } |
| | | |
| | |
| | | $a_uids = is_array($uids) ? join(',', $uids) : $uids; |
| | | else |
| | | $a_uids = NULL; |
| | | |
| | | // force mailbox selection and check if mailbox is writeable |
| | | // to prevent a situation when CLOSE is executed on closed |
| | | // or EXPUNGE on read-only mailbox |
| | | $result = $this->conn->select($mailbox); |
| | | if (!$result) { |
| | | return false; |
| | | } |
| | | if (!$this->conn->data['READ-WRITE']) { |
| | | $this->conn->setError(rcube_imap_generic::ERROR_READONLY, "Mailbox is read-only"); |
| | | return false; |
| | | } |
| | | |
| | | // CLOSE(+SELECT) should be faster than EXPUNGE |
| | | if (empty($a_uids) || $a_uids == '1:*') |
| | |
| | | |
| | | |
| | | /** |
| | | * Returns the namespace where the folder is in |
| | | * |
| | | * @param string $mbox_name Folder name |
| | | * |
| | | * @return string One of 'personal', 'other' or 'shared' |
| | | * @access public |
| | | */ |
| | | function mailbox_namespace($mbox_name) |
| | | { |
| | | if ($mbox_name == 'INBOX') { |
| | | return 'personal'; |
| | | } |
| | | |
| | | foreach ($this->namespace as $type => $namespace) { |
| | | if (is_array($namespace)) { |
| | | foreach ($namespace as $ns) { |
| | | if (strlen($ns[0])) { |
| | | if ((strlen($ns[0])>1 && $mbox_name == substr($ns[0], 0, -1)) |
| | | || strpos($mbox_name, $ns[0]) === 0 |
| | | ) { |
| | | return $type; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | return 'personal'; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Modify folder name for input/output according to root dir and namespace |
| | | * |
| | | * @param string $mbox_name Folder name |
| | |
| | | // If folder contains namespace prefix, don't modify it |
| | | if (is_array($this->namespace['shared'])) { |
| | | foreach ($this->namespace['shared'] as $ns) { |
| | | foreach ((array)$ns as $root) { |
| | | if ($root[0] && strpos($mbox_name, $root[0]) === 0) { |
| | | return $mbox_name; |
| | | } |
| | | if ($ns[0] && strpos($mbox_name, $ns[0]) === 0) { |
| | | return $mbox_name; |
| | | } |
| | | } |
| | | } |
| | | if (is_array($this->namespace['other'])) { |
| | | foreach ($this->namespace['other'] as $ns) { |
| | | foreach ((array)$ns as $root) { |
| | | if ($root[0] && strpos($mbox_name, $root[0]) === 0) { |
| | | return $mbox_name; |
| | | } |
| | | if ($ns[0] && strpos($mbox_name, $ns[0]) === 0) { |
| | | return $mbox_name; |
| | | } |
| | | } |
| | | } |
| | | if (is_array($this->namespace['personal'])) { |
| | | foreach ($this->namespace['personal'] as $ns) { |
| | | foreach ((array)$ns as $root) { |
| | | if ($root[0] && strpos($mbox_name, $root[0]) === 0) { |
| | | return $mbox_name; |
| | | } |
| | | if ($ns[0] && strpos($mbox_name, $ns[0]) === 0) { |
| | | return $mbox_name; |
| | | } |
| | | } |
| | | // Add prefix if first personal namespace is non-empty |
| | | if ($this->namespace['personal'][0][0]) { |
| | | if ($mbox_name != 'INBOX' && $this->namespace['personal'][0][0]) { |
| | | return $this->namespace['personal'][0][0].$mbox_name; |
| | | } |
| | | } |
| | |
| | | */ |
| | | public static function decode_mime_string($input, $fallback=null) |
| | | { |
| | | // Initialize variable |
| | | $out = ''; |
| | | if (!empty($fallback)) { |
| | | $default_charset = $fallback; |
| | | } |
| | | else { |
| | | $default_charset = rcmail::get_instance()->config->get('default_charset', 'ISO-8859-1'); |
| | | } |
| | | |
| | | // 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); |
| | | |
| | | // 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) { |
| | | // encoded-word regexp |
| | | $re = '/=\?([^?]+)\?([BbQq])\?([^?\n]*)\?=/'; |
| | | |
| | | // Find all RFC2047's encoded words |
| | | if (preg_match_all($re, $input, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) { |
| | | // Initialize variables |
| | | $tmp = array(); |
| | | $out = ''; |
| | | $start = 0; |
| | | |
| | | foreach ($matches as $idx => $m) { |
| | | $pos = $m[0][1]; |
| | | $charset = $m[1][0]; |
| | | $encoding = $m[2][0]; |
| | | $text = $m[3][0]; |
| | | $length = strlen($m[0][0]); |
| | | |
| | | // Append everything that is before the text to be decoded |
| | | $out .= substr($input, 0, $pos); |
| | | if ($start != $pos) { |
| | | $substr = substr($input, $start, $pos-$start); |
| | | $out .= rcube_charset_convert($substr, $default_charset); |
| | | $start = $pos; |
| | | } |
| | | $start += $length; |
| | | |
| | | // 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); |
| | | // Per RFC2047, each string part "MUST represent an integral number |
| | | // of characters . A multi-octet character may not be split across |
| | | // adjacent encoded-words." However, some mailers break this, so we |
| | | // try to handle characters spanned across parts anyway by iterating |
| | | // through and aggregating sequential encoded parts with the same |
| | | // character set and encoding, then perform the decoding on the |
| | | // aggregation as a whole. |
| | | |
| | | // Extract the encoded string |
| | | $encstr = substr($input, $pos+2, ($end_pos-$pos-2)); |
| | | // Extract the remaining string |
| | | $input = substr($input, $end_pos+2); |
| | | $tmp[] = $text; |
| | | if ($next_match = $matches[$idx+1]) { |
| | | if ($next_match[0][1] == $start |
| | | && $next_match[1][0] == $charset |
| | | && $next_match[2][0] == $encoding |
| | | ) { |
| | | continue; |
| | | } |
| | | } |
| | | |
| | | // Decode the string fragement |
| | | $out .= rcube_imap::_decode_mime_string_part($encstr); |
| | | $count = count($tmp); |
| | | $text = ''; |
| | | |
| | | // Decode and join encoded-word's chunks |
| | | if ($encoding == 'B' || $encoding == 'b') { |
| | | // base64 must be decoded a segment at a time |
| | | for ($i=0; $i<$count; $i++) |
| | | $text .= base64_decode($tmp[$i]); |
| | | } |
| | | else { //if ($encoding == 'Q' || $encoding == 'q') { |
| | | // quoted printable can be combined and processed at once |
| | | for ($i=0; $i<$count; $i++) |
| | | $text .= $tmp[$i]; |
| | | |
| | | $text = str_replace('_', ' ', $text); |
| | | $text = quoted_printable_decode($text); |
| | | } |
| | | |
| | | $out .= rcube_charset_convert($text, $charset); |
| | | $tmp = array(); |
| | | } |
| | | |
| | | // Deocde the rest (if any) |
| | | if (strlen($input) != 0) |
| | | $out .= rcube_imap::decode_mime_string($input, $fallback); |
| | | // add the last part of the input string |
| | | if ($start != strlen($input)) { |
| | | $out .= rcube_charset_convert(substr($input, $start), $default_charset); |
| | | } |
| | | |
| | | // return the results |
| | | return $out; |
| | | } |
| | | |
| | | // no encoding information, use fallback |
| | | return rcube_charset_convert($input, |
| | | !empty($fallback) ? $fallback : rcmail::get_instance()->config->get('default_charset', 'ISO-8859-1')); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Decode a part of a mime-encoded string |
| | | * |
| | | * @param string $str String to decode |
| | | * @return string Decoded string |
| | | * @access private |
| | | */ |
| | | private function _decode_mime_string_part($str) |
| | | { |
| | | $a = explode('?', $str); |
| | | $count = count($a); |
| | | |
| | | // should be in format "charset?encoding?base64_string" |
| | | if ($count >= 3) { |
| | | for ($i=2; $i<$count; $i++) |
| | | $rest .= $a[$i]; |
| | | |
| | | if (($a[1]=='B') || ($a[1]=='b')) |
| | | $rest = base64_decode($rest); |
| | | else if (($a[1]=='Q') || ($a[1]=='q')) { |
| | | $rest = str_replace('_', ' ', $rest); |
| | | $rest = quoted_printable_decode($rest); |
| | | } |
| | | |
| | | return rcube_charset_convert($rest, $a[0]); |
| | | } |
| | | |
| | | // we dont' know what to do with this |
| | | return $str; |
| | | return rcube_charset_convert($input, $default_charset); |
| | | } |
| | | |
| | | |
| | |
| | | private function _parse_address_list($str, $decode=true) |
| | | { |
| | | // remove any newlines and carriage returns before |
| | | $a = rcube_explode_quoted_string('[,;]', preg_replace( "/[\r\n]/", " ", $str)); |
| | | $str = preg_replace('/\r?\n(\s|\t)?/', ' ', $str); |
| | | |
| | | // extract list items, remove comments |
| | | $str = self::explode_header_string(',;', $str, true); |
| | | $result = array(); |
| | | |
| | | foreach ($a as $key => $val) { |
| | | foreach ($str as $key => $val) { |
| | | $name = ''; |
| | | $address = ''; |
| | | $val = trim($val); |
| | |
| | | return $result; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Explodes header (e.g. address-list) string into array of strings |
| | | * using specified separator characters with proper handling |
| | | * of quoted-strings and comments (RFC2822) |
| | | * |
| | | * @param string $separator String containing separator characters |
| | | * @param string $str Header string |
| | | * @param bool $remove_comments Enable to remove comments |
| | | * |
| | | * @return array Header items |
| | | */ |
| | | static function explode_header_string($separator, $str, $remove_comments=false) |
| | | { |
| | | $length = strlen($str); |
| | | $result = array(); |
| | | $quoted = false; |
| | | $comment = 0; |
| | | $out = ''; |
| | | |
| | | for ($i=0; $i<$length; $i++) { |
| | | // we're inside a quoted string |
| | | if ($quoted) { |
| | | if ($str[$i] == '"') { |
| | | $quoted = false; |
| | | } |
| | | else if ($str[$i] == '\\') { |
| | | if ($comment <= 0) { |
| | | $out .= '\\'; |
| | | } |
| | | $i++; |
| | | } |
| | | } |
| | | // we're inside a comment string |
| | | else if ($comment > 0) { |
| | | if ($str[$i] == ')') { |
| | | $comment--; |
| | | } |
| | | else if ($str[$i] == '(') { |
| | | $comment++; |
| | | } |
| | | else if ($str[$i] == '\\') { |
| | | $i++; |
| | | } |
| | | continue; |
| | | } |
| | | // separator, add to result array |
| | | else if (strpos($separator, $str[$i]) !== false) { |
| | | if ($out) { |
| | | $result[] = $out; |
| | | } |
| | | $out = ''; |
| | | continue; |
| | | } |
| | | // start of quoted string |
| | | else if ($str[$i] == '"') { |
| | | $quoted = true; |
| | | } |
| | | // start of comment |
| | | else if ($remove_comments && $str[$i] == '(') { |
| | | $comment++; |
| | | } |
| | | |
| | | if ($comment <= 0) { |
| | | $out .= $str[$i]; |
| | | } |
| | | } |
| | | |
| | | if ($out && $comment <= 0) { |
| | | $result[] = $out; |
| | | } |
| | | |
| | | return $result; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * This is our own debug handler for the IMAP connection |
| | | * @access public |
| | | */ |
| | | public function debug_handler(&$imap, $message) |
| | | { |
| | | write_log('imap', $message); |
| | | } |
| | | |
| | | } // end class rcube_imap |
| | | |
| | | |