alecpl
2010-01-28 b5846eed4ddd8e2a3f5f0fee42d91d5243c2afec
program/include/rcube_imap.php
@@ -105,14 +105,15 @@
    if ($use_ssl && extension_loaded('openssl'))
      $ICL_SSL = $use_ssl == 'imaps' ? 'ssl' : $use_ssl;
    else if ($use_ssl) {
      raise_error(array('code' => 403, 'type' => 'imap', 'file' => __FILE__,
                        'message' => 'Open SSL not available;'), TRUE, FALSE);
      raise_error(array('code' => 403, 'type' => 'imap',
        'file' => __FILE__, 'line' => __LINE__,
        'message' => "Open SSL not available"), TRUE, FALSE);
      $port = 143;
    }
    $ICL_PORT = $port;
    $IMAP_USE_INTERNAL_DATE = false;
    $attempt = 0;
    do {
      $data = rcmail::get_instance()->plugins->exec_hook('imap_connect', array('host' => $host, 'user' => $user, 'attempt' => ++$attempt));
@@ -136,21 +137,21 @@
    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);
      raise_error(array('code' => 403, 'type' => 'imap',
        'file' => __FILE__, 'line' => __LINE__,
        'message' => $GLOBALS['iil_error']), TRUE, FALSE);
      }
    // get server properties
    if ($this->conn)
      {
      if (!empty($this->conn->delimiter))
        $this->delimiter = $this->conn->delimiter;
      if (!empty($this->conn->rootdir))
        {
        $this->set_rootdir($this->conn->rootdir);
        $this->root_ns = preg_replace('/[.\/]$/', '', $this->conn->rootdir);
        }
      if (empty($this->delimiter))
   $this->get_hierarchy_delimiter();
      }
    return $this->conn ? TRUE : FALSE;
@@ -602,21 +603,24 @@
    if ($this->index_sort && $this->sort_field == 'date')
      {
        if ($this->skip_deleted) {
          $msg_index = $this->_search_index($mailbox, 'ALL');
          $max = max($msg_index);
          list($begin, $end) = $this->_get_message_range(count($msg_index), $page);
          $msg_index = array_slice($msg_index, $begin, $end-$begin);
          // @TODO: this could be cached
     if ($msg_index = $this->_search_index($mailbox, 'ALL UNDELETED')) {
            $max = max($msg_index);
            list($begin, $end) = $this->_get_message_range(count($msg_index), $page);
            $msg_index = array_slice($msg_index, $begin, $end-$begin);
       }
   } else if ($max = iil_C_CountMessages($this->conn, $mailbox)) {
          list($begin, $end) = $this->_get_message_range($max, $page);
     $msg_index = range($begin+1, $end);
   } else
     return array();
     $msg_index = array();
        if ($slice)
          $msg_index = array_slice($msg_index, ($this->sort_order == 'DESC' ? 0 : -$slice), $slice);
        // fetch reqested headers from server
        $this->_fetch_headers($mailbox, join(",", $msg_index), $a_msg_headers, $cache_key);
   if ($msg_index)
          $this->_fetch_headers($mailbox, join(",", $msg_index), $a_msg_headers, $cache_key);
      }
    // use SORT command
    else if ($this->get_capability('sort') && ($msg_index = iil_C_Sort($this->conn, $mailbox, $this->sort_field, $this->skip_deleted ? 'UNDELETED' : '')))
@@ -632,13 +636,8 @@
      $this->_fetch_headers($mailbox, join(',', $msg_index), $a_msg_headers, $cache_key);
      }
    // fetch specified header for all messages and sort
    else
    else if ($a_index = iil_C_FetchHeaderIndex($this->conn, $mailbox, "1:*", $this->sort_field, $this->skip_deleted))
      {
      $a_index = iil_C_FetchHeaderIndex($this->conn, $mailbox, "1:*", $this->sort_field, $this->skip_deleted);
      if (empty($a_index))
        return array();
      asort($a_index); // ASC
      $msg_index = array_keys($a_index);
      $max = max($msg_index);
@@ -1225,17 +1224,15 @@
      else
        $this->struct_charset = $this->_structure_charset($structure);
      /*
        @TODO: here we can recognize malformed BODYSTRUCTURE and parse
   the message in other way to create our own message structure.
   Example of structure for malformed MIME message:
   ("text" "plain" ("charset" "us-ascii") NIL NIL "7bit" 2154 70 NIL NIL NIL)
   if ($headers->ctype != 'text/plain'
     && !is_array($structure[0]) && $structure[0] == 'text'
     && !is_array($structure[1]) && $structure[1] == 'plain')
     { }
      */
      // Here we can recognize malformed BODYSTRUCTURE and
      // 1. [@TODO] parse the message in other way to create our own message structure
      // 2. or just show the raw message body.
      // Example of structure for malformed MIME message:
      // ("text" "plain" ("charset" "us-ascii") NIL NIL "7bit" 2154 70 NIL NIL NIL)
      if ($headers->ctype && $headers->ctype != 'text/plain'
     && $structure[0] == 'text' && $structure[1] == 'plain') {
   return false;
   }
      $struct = &$this->_structure_part($structure);
      $struct->headers = get_object_vars($headers);
@@ -1262,7 +1259,7 @@
   *
   * @access private
   */
  function &_structure_part($part, $count=0, $parent='', $raw_headers=null)
  function &_structure_part($part, $count=0, $parent='', $mime_headers=null, $raw_headers=null)
    {
    $struct = new rcube_message_part;
    $struct->mime_id = empty($parent) ? (string)$count : "$parent.$count";
@@ -1284,28 +1281,43 @@
      // 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;
       }
        if (is_array($part[$i]) && count($part[$i]) > 3) {
          // fetch message headers if message/rfc822 or named part (could contain Content-Location header)
     if (!is_array($part[$i][0])) {
            $tmp_part_id = $struct->mime_id ? $struct->mime_id.'.'.($i+1) : $i+1;
            if (strtolower($part[$i][0]) == 'message' && strtolower($part[$i][1]) == 'rfc822') {
         $raw_part_headers[] = $tmp_part_id;
         $mime_part_headers[] = $tmp_part_id;
              }
            else if (in_array('name', (array)$part[$i][2]) && (empty($part[$i][3]) || $part[$i][3]=='NIL')) {
         $mime_part_headers[] = $tmp_part_id;
         }
            }
          }
      // 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);
      // @TODO: we could do this before _structure_part() call, to fetch
      // headers for parts on all levels
      if ($mime_part_headers)
        $mime_part_headers = iil_C_FetchMIMEHeaders($this->conn, $this->mailbox,
          $this->_msg_id, $mime_part_headers);
      // we'll need a real content-type of message/rfc822 part
      if ($raw_part_headers)
        $raw_part_headers = iil_C_FetchMIMEHeaders($this->conn, $this->mailbox,
          $this->_msg_id, $raw_part_headers, false);
      $struct->parts = array();
      for ($i=0, $count=0; $i<count($part); $i++)
        if (is_array($part[$i]) && count($part[$i]) > 3) {
          $tmp_part_id = $struct->mime_id ? $struct->mime_id.'.'.($i+1) : $i+1;
          $struct->parts[] = $this->_structure_part($part[$i], ++$count, $struct->mime_id,
      $part_headers[$struct->mime_id ? $struct->mime_id.'.'.($i+1) : $i+1]);
       $mime_part_headers[$tmp_part_id], $raw_part_headers[$tmp_part_id]);
   }
      return $struct;
      }
    // regular part
    $struct->ctype_primary = strtolower($part[0]);
    $struct->ctype_secondary = strtolower($part[1]);
@@ -1366,18 +1378,30 @@
    
    // 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)) {
      if (empty($raw_headers))
        $raw_headers = iil_C_FetchPartHeader($this->conn, $this->mailbox, $this->_msg_id, false, $struct->mime_id);
      $struct->headers = $this->_parse_headers($raw_headers) + $struct->headers;
    }
      if (empty($mime_headers))
        $mime_headers = iil_C_FetchPartHeader($this->conn, $this->mailbox, $this->_msg_id, false, $struct->mime_id);
      $struct->headers = $this->_parse_headers($mime_headers) + $struct->headers;
      // get real headers for message of type 'message/rfc822'
      if ($struct->mimetype == 'message/rfc822') {
        if (empty($raw_headers))
          $raw_headers = iil_C_FetchMIMEHeaders($this->conn, $this->mailbox, $this->_msg_id, (array)$struct->mime_id, false);
        $struct->real_headers = $this->_parse_headers($raw_headers);
        // get real content-type of message/rfc822
        if (preg_match('/^([a-z0-9_\/-]+)/i', $struct->real_headers['content-type'], $matches)) {
          $struct->real_mimetype = strtolower($matches[1]);
          }
        }
      }
    if ($struct->ctype_primary=='message') {
      if (is_array($part[8]) && empty($struct->parts))
      if (is_array($part[8]) && $di != 8 && empty($struct->parts))
        $struct->parts[] = $this->_structure_part($part[8], ++$count, $struct->mime_id);
    }
      }
    // normalize filename property
    $this->_set_part_filename($struct, $raw_headers);
    $this->_set_part_filename($struct, $mime_headers);
    return $struct;
    }
@@ -1715,8 +1739,8 @@
    // make sure mailbox exists
    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);
      if (in_array($tbox, $this->default_folders))
        $this->create_mailbox($tbox, TRUE);
      else
        return FALSE;
      }
@@ -2115,7 +2139,7 @@
   */
  function create_default_folders()
    {
    $a_folders = iil_C_ListMailboxes($this->conn, $this->mod_mailbox(''), '*');
    $a_folders = iil_C_ListMailboxes($this->conn, $this->mod_mailbox(''), 'Drafts');
    $a_subscribed = iil_C_ListSubscribed($this->conn, $this->mod_mailbox(''), '*');
    
    // create default folders if they do not exist
@@ -2870,11 +2894,13 @@
    if ((!empty($this->root_ns) && $this->root_ns == $mbox_name) || $mbox_name == 'INBOX')
      return $mbox_name;
    if (!empty($this->root_dir) && $mode=='in')
      $mbox_name = $this->root_dir.$this->delimiter.$mbox_name;
    else if (strlen($this->root_dir) && $mode=='out')
      $mbox_name = substr($mbox_name, strlen($this->root_dir)+1);
    if (!empty($this->root_dir)) {
      if ($mode=='in')
        $mbox_name = $this->root_dir.$this->delimiter.$mbox_name;
      else if (!empty($mbox_name)) // $mode=='out'
        $mbox_name = substr($mbox_name, strlen($this->root_dir)+1);
      }
    return $mbox_name;
    }
@@ -3085,6 +3111,7 @@
  private function _parse_headers($headers)
    {
    $a_headers = array();
    $headers = preg_replace('/\r?\n(\t| )+/', ' ', $headers);
    $lines = explode("\n", $headers);
    $c = count($lines);
    for ($i=0; $i<$c; $i++)