| | |
| | | */ |
| | | |
| | | |
| | | /** |
| | | * Struct representing an e-mail message header |
| | | * |
| | | * @package Mail |
| | | * @author Aleksander Machniak <alec@alec.pl> |
| | | */ |
| | | class rcube_mail_header |
| | | { |
| | | public $id; |
| | |
| | | public $others = array(); |
| | | } |
| | | |
| | | // For backward compatibility with cached messages (#1486602) |
| | | class iilBasicHeader extends rcube_mail_header |
| | | { |
| | | } |
| | | |
| | | /** |
| | | * PHP based wrapper class to connect to an IMAP server |
| | | * |
| | | * @package Mail |
| | | * @author Aleksander Machniak <alec@alec.pl> |
| | | */ |
| | | class rcube_imap_generic |
| | | { |
| | | public $error; |
| | |
| | | function __construct() |
| | | { |
| | | } |
| | | |
| | | |
| | | private function putLine($string, $endln=true) |
| | | { |
| | | if (!$this->fp) |
| | |
| | | if (!empty($this->prefs['debug_mode'])) { |
| | | write_log('imap', 'C: '. rtrim($string)); |
| | | } |
| | | |
| | | |
| | | return fputs($this->fp, $string . ($endln ? "\r\n" : '')); |
| | | } |
| | | |
| | |
| | | if (!$this->fp) { |
| | | return NULL; |
| | | } |
| | | |
| | | |
| | | if (!$size) { |
| | | $size = 1024; |
| | | } |
| | | |
| | | |
| | | do { |
| | | if (feof($this->fp)) { |
| | | return $line ? $line : NULL; |
| | | } |
| | | |
| | | |
| | | $buffer = fgets($this->fp, $size); |
| | | |
| | | if ($buffer === false) { |
| | | fclose($this->fp); |
| | | $this->fp = null; |
| | | @fclose($this->fp); |
| | | $this->fp = null; |
| | | break; |
| | | } |
| | | if (!empty($this->prefs['debug_mode'])) { |
| | |
| | | $line = chop($line); |
| | | if (preg_match('/\{[0-9]+\}$/', $line)) { |
| | | $out = ''; |
| | | |
| | | |
| | | preg_match_all('/(.*)\{([0-9]+)\}$/', $line, $a); |
| | | $bytes = $a[2][0]; |
| | | while (strlen($out) < $bytes) { |
| | | $line = $this->readBytes($bytes); |
| | | $line = $this->readBytes($bytes); |
| | | if ($line === NULL) |
| | | break; |
| | | $out .= $line; |
| | |
| | | |
| | | $line = $a[1][0] . '"' . ($escape ? $this->Escape($out) : $out) . '"'; |
| | | } |
| | | |
| | | |
| | | return $line; |
| | | } |
| | | |
| | |
| | | } |
| | | $len = $data_len; |
| | | } |
| | | |
| | | |
| | | return $data; |
| | | } |
| | | |
| | | // don't use it in loops, until you exactly know what you're doing |
| | | private function readReply() |
| | | private function readReply(&$untagged=null) |
| | | { |
| | | do { |
| | | $line = trim($this->readLine(1024)); |
| | | // store untagged response lines |
| | | if ($line[0] == '*') |
| | | $untagged[] = $line; |
| | | } while ($line[0] == '*'); |
| | | |
| | | if ($untagged) |
| | | $untagged = join("\n", $untagged); |
| | | |
| | | return $line; |
| | | } |
| | |
| | | } else if ($res == 'BAD') { |
| | | return -2; |
| | | } else if ($res == 'BYE') { |
| | | fclose($this->fp); |
| | | @fclose($this->fp); |
| | | $this->fp = null; |
| | | return -3; |
| | | } |
| | |
| | | } |
| | | if ($error && preg_match('/^\* (BYE|BAD) /i', $string, $m)) { |
| | | if (strtoupper($m[1]) == 'BYE') { |
| | | fclose($this->fp); |
| | | @fclose($this->fp); |
| | | $this->fp = null; |
| | | } |
| | | return true; |
| | |
| | | } |
| | | if ($error && preg_match('/^\* (BYE|BAD) /i', $string, $m)) { |
| | | if (strtoupper($m[1]) == 'BYE') { |
| | | fclose($this->fp); |
| | | @fclose($this->fp); |
| | | $this->fp = null; |
| | | } |
| | | return true; |
| | |
| | | return false; |
| | | } |
| | | |
| | | // get capabilities (only once) because initial |
| | | // get capabilities (only once) because initial |
| | | // optional CAPABILITY response may differ |
| | | $this->capability = array(); |
| | | |
| | |
| | | } |
| | | } |
| | | } while ($a[0] != 'cp01'); |
| | | |
| | | |
| | | $this->capability_readed = true; |
| | | |
| | | if (in_array($name, $this->capability)) { |
| | |
| | | { |
| | | $ipad = ''; |
| | | $opad = ''; |
| | | |
| | | |
| | | // initialize ipad, opad |
| | | for ($i=0; $i<64; $i++) { |
| | | $ipad .= chr(0x36); |
| | |
| | | for ($i=0; $i<$padLen; $i++) { |
| | | $pass .= chr(0); |
| | | } |
| | | |
| | | |
| | | // generate hash |
| | | $hash = md5($this->xor($pass,$opad) . pack("H*", md5($this->xor($pass, $ipad) . base64_decode($encChallenge)))); |
| | | |
| | | $hash = md5($this->_xor($pass,$opad) . pack("H*", md5($this->_xor($pass, $ipad) . base64_decode($encChallenge)))); |
| | | |
| | | // generate reply |
| | | $reply = base64_encode($user . ' ' . $hash); |
| | | |
| | | |
| | | // send result, get reply |
| | | $this->putLine($reply); |
| | | $line = $this->readLine(1024); |
| | | |
| | | |
| | | // process result |
| | | $result = $this->parseResult($line); |
| | | if ($result == 0) { |
| | | $this->error .= ''; |
| | | $this->errornum = 0; |
| | | $this->errornum = 0; |
| | | return $this->fp; |
| | | } |
| | | |
| | | $this->error .= 'Authentication for ' . $user . ' failed (AUTH): "'; |
| | | $this->error .= htmlspecialchars($line) . '"'; |
| | | $this->errornum = $result; |
| | | $this->error = "Authentication for $user failed (AUTH): $line"; |
| | | $this->errornum = $result; |
| | | |
| | | return $result; |
| | | } |
| | |
| | | { |
| | | $this->putLine('a001 LOGIN "'.$this->escape($user).'" "'.$this->escape($password).'"'); |
| | | |
| | | $line = $this->readReply(); |
| | | $line = $this->readReply($untagged); |
| | | |
| | | // re-set capabilities list if untagged CAPABILITY response provided |
| | | if (preg_match('/\* CAPABILITY (.+)/i', $untagged, $matches)) { |
| | | $this->capability = explode(' ', strtoupper($matches[1])); |
| | | } |
| | | |
| | | // process result |
| | | $result = $this->parseResult($line); |
| | | |
| | | if ($result == 0) { |
| | | $this->error .= ''; |
| | | $this->errornum = 0; |
| | | $this->errornum = 0; |
| | | return $this->fp; |
| | | } |
| | | |
| | | fclose($this->fp); |
| | | @fclose($this->fp); |
| | | $this->fp = false; |
| | | |
| | | $this->error .= 'Authentication for ' . $user . ' failed (LOGIN): "'; |
| | | $this->error .= htmlspecialchars($line)."\""; |
| | | $this->errornum = $result; |
| | | |
| | | $this->error = "Authentication for $user failed (LOGIN): $line"; |
| | | $this->errornum = $result; |
| | | |
| | | return $result; |
| | | } |
| | |
| | | $this->rootdir = $this->prefs['rootdir']; |
| | | return true; |
| | | } |
| | | |
| | | |
| | | if (!$this->getCapability('NAMESPACE')) { |
| | | return false; |
| | | } |
| | | |
| | | |
| | | if (!$this->putLine("ns1 NAMESPACE")) { |
| | | return false; |
| | | } |
| | |
| | | if (count($first_userspace)!=2) { |
| | | return false; |
| | | } |
| | | |
| | | |
| | | $this->rootdir = $first_userspace[0]; |
| | | $this->delimiter = $first_userspace[1]; |
| | | $this->prefs['rootdir'] = substr($this->rootdir, 0, -1); |
| | | $this->prefs['delimiter'] = $this->delimiter; |
| | | |
| | | |
| | | return true; |
| | | } |
| | | |
| | |
| | | * INBOX.foo -> . |
| | | * INBOX/foo -> / |
| | | * INBOX\foo -> \ |
| | | * |
| | | * @return mixed A delimiter (string), or false. |
| | | * |
| | | * @return mixed A delimiter (string), or false. |
| | | * @see connect() |
| | | */ |
| | | function getHierarchyDelimiter() |
| | |
| | | if (!$this->putLine('ghd LIST "" ""')) { |
| | | return false; |
| | | } |
| | | |
| | | |
| | | do { |
| | | $line = $this->readLine(500); |
| | | if ($line[0] == '*') { |
| | |
| | | if (!is_array($data)) { |
| | | return false; |
| | | } |
| | | |
| | | |
| | | // extract user space data (opposed to global/shared space) |
| | | $user_space_data = $data[0]; |
| | | if (!is_array($user_space_data)) { |
| | |
| | | } |
| | | |
| | | // extract delimiter |
| | | $delimiter = $first_userspace[1]; |
| | | $delimiter = $first_userspace[1]; |
| | | |
| | | return $delimiter; |
| | | } |
| | |
| | | $message = "INITIAL: $auth_method\n"; |
| | | |
| | | $result = false; |
| | | |
| | | |
| | | // initialize connection |
| | | $this->error = ''; |
| | | $this->errornum = 0; |
| | |
| | | // check input |
| | | if (empty($host)) { |
| | | $this->error = "Empty host"; |
| | | $this->errornum = -1; |
| | | $this->errornum = -2; |
| | | return false; |
| | | } |
| | | if (empty($user)) { |
| | |
| | | $host = $this->prefs['ssl_mode'] . '://' . $host; |
| | | } |
| | | |
| | | $this->fp = @fsockopen($host, $this->prefs['port'], $errno, $errstr, 10); |
| | | // Connect |
| | | if ($this->prefs['timeout'] > 0) |
| | | $this->fp = @fsockopen($host, $this->prefs['port'], $errno, $errstr, $this->prefs['timeout']); |
| | | else |
| | | $this->fp = @fsockopen($host, $this->prefs['port'], $errno, $errstr); |
| | | |
| | | if (!$this->fp) { |
| | | $this->error = sprintf("Could not connect to %s:%d: %s", $host, $this->prefs['port'], $errstr); |
| | | $this->errornum = -2; |
| | | return false; |
| | | } |
| | | |
| | | stream_set_timeout($this->fp, 10); |
| | | if ($this->prefs['timeout'] > 0) |
| | | stream_set_timeout($this->fp, $this->prefs['timeout']); |
| | | |
| | | $line = trim(fgets($this->fp, 8192)); |
| | | |
| | | if ($this->prefs['debug_mode'] && $line) { |
| | |
| | | $this->errornum = -2; |
| | | return false; |
| | | } |
| | | |
| | | |
| | | // Now we're authenticated, capabilities need to be reread |
| | | $this->clearCapability(); |
| | | } |
| | |
| | | if ($line[0] == '+') { |
| | | // got a challenge string, try CRAM-MD5 |
| | | $result = $this->authenticate($user, $password, substr($line,2)); |
| | | |
| | | |
| | | // stop if server sent BYE response |
| | | if ($result == -3) { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | |
| | | if (!is_resource($result) && $orig_method == 'CHECK') { |
| | | $auth_method = 'PLAIN'; |
| | | } |
| | | } |
| | | |
| | | |
| | | if ($auth_method == 'PLAIN') { |
| | | // do plain text auth |
| | | $result = $this->login($user, $password); |
| | |
| | | } |
| | | $this->getNamespace(); |
| | | $this->logged = true; |
| | | |
| | | return true; |
| | | } else { |
| | | return false; |
| | |
| | | if ($this->selected == $mailbox) { |
| | | return true; |
| | | } |
| | | |
| | | |
| | | if ($this->putLine("sel1 SELECT \"".$this->escape($mailbox).'"')) { |
| | | do { |
| | | $line = chop($this->readLine(300)); |
| | |
| | | if (empty($mailbox)) { |
| | | $mailbox = 'INBOX'; |
| | | } |
| | | |
| | | |
| | | $this->select($mailbox); |
| | | if ($this->selected == $mailbox) { |
| | | return $this->recent; |
| | |
| | | if ($refresh) { |
| | | $this->selected = ''; |
| | | } |
| | | |
| | | |
| | | $this->select($mailbox); |
| | | if ($this->selected == $mailbox) { |
| | | return $this->exists; |
| | |
| | | if ($field == 'INTERNALDATE') { |
| | | $field = 'ARRIVAL'; |
| | | } |
| | | |
| | | |
| | | $fields = array('ARRIVAL' => 1,'CC' => 1,'DATE' => 1, |
| | | 'FROM' => 1, 'SIZE' => 1, 'SUBJECT' => 1, 'TO' => 1); |
| | | |
| | |
| | | if (!$this->select($mailbox)) { |
| | | return false; |
| | | } |
| | | |
| | | |
| | | $is_uid = $is_uid ? 'UID ' : ''; |
| | | |
| | | |
| | | // message IDs |
| | | if (is_array($add)) |
| | | $add = $this->compressMessageSet(join(',', $add)); |
| | |
| | | $data .= $line; |
| | | } |
| | | } while (!$this->startsWith($line, 's ', true, true)); |
| | | |
| | | |
| | | $result_code = $this->parseResult($line); |
| | | |
| | | if ($result_code != 0) { |
| | | $this->error = "Sort: $line"; |
| | | return false; |
| | | } |
| | | |
| | | |
| | | return preg_split('/\s+/', $data, -1, PREG_SPLIT_NO_EMPTY); |
| | | } |
| | | |
| | |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | |
| | | $index_field = empty($index_field) ? 'DATE' : strtoupper($index_field); |
| | | |
| | | |
| | | $fields_a['DATE'] = 1; |
| | | $fields_a['INTERNALDATE'] = 4; |
| | | $fields_a['ARRIVAL'] = 4; |
| | |
| | | if (!$this->select($mailbox)) { |
| | | return false; |
| | | } |
| | | |
| | | |
| | | // build FETCH command string |
| | | $key = 'fhi0'; |
| | | $cmd = $uidfetch ? 'UID FETCH' : 'FETCH'; |
| | |
| | | if (preg_match('/^\* ([0-9]+) FETCH/', $line, $m)) { |
| | | $id = $m[1]; |
| | | $flags = NULL; |
| | | |
| | | |
| | | if ($skip_deleted && preg_match('/FLAGS \(([^)]+)\)/', $line, $matches)) { |
| | | $flags = explode(' ', strtoupper($matches[1])); |
| | | if (in_array('\\DELETED', $flags)) { |
| | |
| | | } |
| | | } while (!$this->startsWith($line, $key, true, true)); |
| | | |
| | | return $result; |
| | | return $result; |
| | | } |
| | | |
| | | private function compressMessageSet($message_set) |
| | | { |
| | | // given a comma delimited list of independent mid's, |
| | | // given a comma delimited list of independent mid's, |
| | | // compresses by grouping sequences together |
| | | |
| | | |
| | | // if less than 255 bytes long, let's not bother |
| | | if (strlen($message_set)<255) { |
| | | return $message_set; |
| | | } |
| | | |
| | | |
| | | // see if it's already been compress |
| | | if (strpos($message_set, ':') !== false) { |
| | | return $message_set; |
| | | } |
| | | |
| | | |
| | | // separate, then sort |
| | | $ids = explode(',', $message_set); |
| | | sort($ids); |
| | | |
| | | |
| | | $result = array(); |
| | | $start = $prev = $ids[0]; |
| | | |
| | |
| | | } else { |
| | | $result[] = $start.':'.$prev; |
| | | } |
| | | |
| | | |
| | | // return as comma separated string |
| | | return implode(',', $result); |
| | | } |
| | |
| | | $message_set = join(',', $message_set); |
| | | else if (empty($message_set)) |
| | | $message_set = '1:*'; |
| | | |
| | | |
| | | return $this->fetchHeaderIndex($mailbox, $message_set, 'UID', false); |
| | | } |
| | | |
| | | function fetchHeaders($mailbox, $message_set, $uidfetch=false, $bodystr=false, $add='') |
| | | { |
| | | $result = array(); |
| | | |
| | | |
| | | if (!$this->select($mailbox)) { |
| | | return false; |
| | | } |
| | |
| | | do { |
| | | $line = $this->readLine(1024); |
| | | $line = $this->multLine($line); |
| | | |
| | | |
| | | if (!$line) |
| | | break; |
| | | |
| | | |
| | | $a = explode(' ', $line); |
| | | |
| | | if (($line[0] == '*') && ($a[2] == 'FETCH')) { |
| | | $id = $a[1]; |
| | | |
| | | |
| | | $result[$id] = new rcube_mail_header; |
| | | $result[$id]->id = $id; |
| | | $result[$id]->subject = ''; |
| | |
| | | } |
| | | |
| | | $time_str = str_replace('"', '', $time_str); |
| | | |
| | | |
| | | // if time is gmt... |
| | | $time_str = str_replace('GMT','+0000',$time_str); |
| | | |
| | | |
| | | $result[$id]->internaldate = $time_str; |
| | | $result[$id]->timestamp = $this->StrToTime($time_str); |
| | | $result[$id]->date = $time_str; |
| | | } |
| | | |
| | | // BODYSTRUCTURE |
| | | // BODYSTRUCTURE |
| | | if($bodystr) { |
| | | while (!preg_match('/ BODYSTRUCTURE (.*) BODY\[HEADER.FIELDS/s', $line, $m)) { |
| | | $line2 = $this->readLine(1024); |
| | |
| | | // So, we'll read ahead, and if the one we're reading now is a valid header, we'll |
| | | // process the previous line. Otherwise, we'll keep adding the strings until we come |
| | | // to the next valid header line. |
| | | |
| | | |
| | | do { |
| | | $line = chop($this->readLine(300), "\r\n"); |
| | | |
| | | // The preg_match below works around communigate imap, which outputs " UID <number>)". |
| | | // Without this, the while statement continues on and gets the "FH0 OK completed" message. |
| | | // If this loop gets the ending message, then the outer loop does not receive it from radline on line 1249. |
| | | // If this loop gets the ending message, then the outer loop does not receive it from radline on line 1249. |
| | | // This in causes the if statement on line 1278 to never be true, which causes the headers to end up missing |
| | | // If the if statement was changed to pick up the fh0 from this loop, then it causes the outer loop to spin |
| | | // An alternative might be: |
| | |
| | | // patch from "Maksim Rubis" <siburny@hotmail.com> |
| | | } while ($line[0] != ')' && !$this->startsWith($line, $key, true)); |
| | | |
| | | if (strncmp($line, $key, strlen($key))) { |
| | | if (strncmp($line, $key, strlen($key))) { |
| | | // process header, fill rcube_mail_header obj. |
| | | // initialize |
| | | if (is_array($headers)) { |
| | |
| | | // create array with header field:data |
| | | while ( list($lines_key, $str) = each($lines) ) { |
| | | list($field, $string) = $this->splitHeaderLine($str); |
| | | |
| | | |
| | | $field = strtolower($field); |
| | | $string = preg_replace('/\n\s*/', ' ', $string); |
| | | |
| | | |
| | | switch ($field) { |
| | | case 'date'; |
| | | $result[$id]->date = $string; |
| | |
| | | if (!empty($flags_str)) { |
| | | $flags_str = preg_replace('/[\\\"]/', '', $flags_str); |
| | | $flags_a = explode(' ', $flags_str); |
| | | |
| | | |
| | | if (is_array($flags_a)) { |
| | | // reset($flags_a); |
| | | foreach($flags_a as $flag) { |
| | |
| | | |
| | | $c = count($a); |
| | | if ($c > 0) { |
| | | |
| | | |
| | | // Strategy: |
| | | // First, we'll create an "index" array. |
| | | // Then, we'll use sort() on that array, |
| | | // Then, we'll use sort() on that array, |
| | | // and use that to sort the main array. |
| | | |
| | | |
| | | // create "index" array |
| | | $index = array(); |
| | | reset($a); |
| | |
| | | } |
| | | $index[$key]=$data; |
| | | } |
| | | |
| | | |
| | | // sort index |
| | | $i = 0; |
| | | if ($flag == 'ASC') { |
| | |
| | | arsort($index); |
| | | } |
| | | |
| | | // form new array based on index |
| | | // form new array based on index |
| | | $result = array(); |
| | | reset($index); |
| | | while (list($key, $val) = each($index)) { |
| | |
| | | $i++; |
| | | } |
| | | } |
| | | |
| | | |
| | | return $result; |
| | | } |
| | | |
| | |
| | | if (!$this->select($mailbox)) { |
| | | return -1; |
| | | } |
| | | |
| | | |
| | | $c = 0; |
| | | $command = $messages ? "UID EXPUNGE $messages" : "EXPUNGE"; |
| | | |
| | |
| | | $c++; |
| | | } |
| | | } while (!$this->startsWith($line, 'exp1', true, true)); |
| | | |
| | | |
| | | if ($this->parseResult($line) == 0) { |
| | | $this->selected = ''; // state has changed, need to reselect |
| | | return $c; |
| | |
| | | if ($mod != '+' && $mod != '-') { |
| | | return -1; |
| | | } |
| | | |
| | | |
| | | $flag = $this->flags[strtoupper($flag)]; |
| | | |
| | | |
| | | if (!$this->select($mailbox)) { |
| | | return -1; |
| | | } |
| | | |
| | | |
| | | $c = 0; |
| | | if (!$this->putLine("flg UID STORE $messages {$mod}FLAGS ($flag)")) { |
| | | return false; |
| | |
| | | if (empty($from) || empty($to)) { |
| | | return -1; |
| | | } |
| | | |
| | | |
| | | if (!$this->select($from)) { |
| | | return -1; |
| | | } |
| | | |
| | | |
| | | $this->putLine("cpy1 UID COPY $messages \"".$this->escape($to)."\""); |
| | | $line = $this->readReply(); |
| | | return $this->parseResult($line); |
| | |
| | | { |
| | | $node = array(); |
| | | if ($str[$begin] != '(') { |
| | | $stop = $begin + strspn($str, "1234567890", $begin, $end - $begin); |
| | | $stop = $begin + strspn($str, '1234567890', $begin, $end - $begin); |
| | | $msg = substr($str, $begin, $stop - $begin); |
| | | if ($msg == 0) |
| | | return $node; |
| | |
| | | $node += $this->parseThread($str, $start + 1, $off - 1, $root, $parent, $depth, $depthmap, $haschildren); |
| | | } |
| | | } |
| | | |
| | | |
| | | return $node; |
| | | } |
| | | |
| | | function thread($folder, $algorithm='REFERENCES', $criteria='', $encoding='US-ASCII') |
| | | { |
| | | $old_sel = $this->selected; |
| | | |
| | | if (!$this->select($folder)) { |
| | | return false; |
| | | return false; |
| | | } |
| | | |
| | | // return empty result when folder is empty and we're just after SELECT |
| | | if ($old_sel != $folder && !$this->exists) { |
| | | return array(array(), array(), array()); |
| | | } |
| | | |
| | | $encoding = $encoding ? trim($encoding) : 'US-ASCII'; |
| | | $algorithm = $algorithm ? trim($algorithm) : 'REFERENCES'; |
| | | $criteria = $criteria ? 'ALL '.trim($criteria) : 'ALL'; |
| | | |
| | | $data = ''; |
| | | |
| | | if (!$this->putLineC("thrd1 THREAD $algorithm $encoding $criteria")) { |
| | | return false; |
| | | } |
| | | do { |
| | | $line = trim($this->readLine(10000)); |
| | | if (preg_match('/^\* THREAD/', $line)) { |
| | | $str = trim(substr($line, 8)); |
| | | $depthmap = array(); |
| | | $haschildren = array(); |
| | | $tree = $this->parseThread($str, 0, strlen($str), null, null, 0, $depthmap, $haschildren); |
| | | $line = trim($this->readLine()); |
| | | if ($this->startsWith($line, '* THREAD')) { |
| | | $data .= substr($line, 9); |
| | | } else if (preg_match('/^[0-9() ]+$/', $line)) { |
| | | $data .= $line; |
| | | } |
| | | } while (!$this->startsWith($line, 'thrd1', true, true)); |
| | | |
| | | $result_code = $this->parseResult($line); |
| | | if ($result_code == 0) { |
| | | return array($tree, $depthmap, $haschildren); |
| | | $depthmap = array(); |
| | | $haschildren = array(); |
| | | $tree = $this->parseThread($data, 0, strlen($data), null, null, 0, $depthmap, $haschildren); |
| | | return array($tree, $depthmap, $haschildren); |
| | | } |
| | | |
| | | $this->error = "Thread: $line"; |
| | | return false; |
| | | return false; |
| | | } |
| | | |
| | | function search($folder, $criteria) |
| | | function search($folder, $criteria, $return_uid=false) |
| | | { |
| | | $old_sel = $this->selected; |
| | | |
| | | if (!$this->select($folder)) { |
| | | return false; |
| | | } |
| | | |
| | | // return empty result when folder is empty and we're just after SELECT |
| | | if ($old_sel != $folder && !$this->exists) { |
| | | return array(); |
| | | } |
| | | |
| | | $data = ''; |
| | | $query = "srch1 SEARCH " . chop($criteria); |
| | | $query = 'srch1 ' . ($return_uid ? 'UID ' : '') . 'SEARCH ' . chop($criteria); |
| | | |
| | | if (!$this->putLineC($query)) { |
| | | return false; |
| | | } |
| | | |
| | | do { |
| | | $line = trim($this->readLine()); |
| | | if ($this->startsWith($line, '* SEARCH')) { |
| | |
| | | } |
| | | |
| | | $this->error = "Search: $line"; |
| | | return false; |
| | | return false; |
| | | } |
| | | |
| | | function move($messages, $from, $to) |
| | |
| | | if (!$from || !$to) { |
| | | return -1; |
| | | } |
| | | |
| | | |
| | | $r = $this->copy($messages, $from, $to); |
| | | |
| | | if ($r==0) { |
| | |
| | | |
| | | function listMailboxes($ref, $mailbox) |
| | | { |
| | | if (empty($mailbox)) { |
| | | $mailbox = '*'; |
| | | } |
| | | |
| | | if (empty($ref) && $this->rootdir) { |
| | | $ref = $this->rootdir; |
| | | } |
| | | |
| | | // send command |
| | | if (!$this->putLine("lmb LIST \"". $this->escape($ref) ."\" \"". $this->escape($mailbox) ."\"")) { |
| | | return false; |
| | | } |
| | | |
| | | $i = 0; |
| | | // get folder list |
| | | do { |
| | | $line = $this->readLine(500); |
| | | $line = $this->multLine($line, true); |
| | | |
| | | $a = explode(' ', $line); |
| | | if (($line[0] == '*') && ($a[1] == 'LIST')) { |
| | | $line = rtrim($line); |
| | | // split one line |
| | | $a = rcube_explode_quoted_string(' ', $line); |
| | | // last string is folder name |
| | | $folders[$i] = preg_replace(array('/^"/', '/"$/'), '', $this->unEscape($a[count($a)-1])); |
| | | // second from last is delimiter |
| | | $delim = trim($a[count($a)-2], '"'); |
| | | // is it a container? |
| | | $i++; |
| | | } |
| | | } while (!$this->startsWith($line, 'lmb', true)); |
| | | |
| | | if (is_array($folders)) { |
| | | if (!empty($ref)) { |
| | | // if rootdir was specified, make sure it's the first element |
| | | // some IMAP servers (i.e. Courier) won't return it |
| | | if ($ref[strlen($ref)-1]==$delim) |
| | | $ref = substr($ref, 0, strlen($ref)-1); |
| | | if ($folders[0]!=$ref) |
| | | array_unshift($folders, $ref); |
| | | } |
| | | return $folders; |
| | | } else if ($this->parseResult($line) == 0) { |
| | | return array('INBOX'); |
| | | } |
| | | |
| | | $this->error = $line; |
| | | return false; |
| | | return $this->_listMailboxes($ref, $mailbox, false); |
| | | } |
| | | |
| | | function listSubscribed($ref, $mailbox) |
| | | { |
| | | if (empty($mailbox)) { |
| | | $mailbox = '*'; |
| | | } |
| | | if (empty($ref) && $this->rootdir) { |
| | | $ref = $this->rootdir; |
| | | return $this->_listMailboxes($ref, $mailbox, true); |
| | | } |
| | | |
| | | private function _listMailboxes($ref, $mailbox, $subscribed=false) |
| | | { |
| | | if (empty($mailbox)) { |
| | | $mailbox = '*'; |
| | | } |
| | | |
| | | $folders = array(); |
| | | if (empty($ref) && $this->rootdir) { |
| | | $ref = $this->rootdir; |
| | | } |
| | | |
| | | if ($subscribed) { |
| | | $key = 'lsb'; |
| | | $command = 'LSUB'; |
| | | } |
| | | else { |
| | | $key = 'lmb'; |
| | | $command = 'LIST'; |
| | | } |
| | | |
| | | // send command |
| | | if (!$this->putLine('lsb LSUB "'. $this->escape($ref) . '" "' . $this->escape($mailbox).'"')) { |
| | | $this->error = "Couldn't send LSUB command"; |
| | | return false; |
| | | if (!$this->putLine($key." ".$command." \"". $this->escape($ref) ."\" \"". $this->escape($mailbox) ."\"")) { |
| | | $this->error = "Couldn't send $command command"; |
| | | return false; |
| | | } |
| | | |
| | | $i = 0; |
| | | |
| | | |
| | | // get folder list |
| | | do { |
| | | $line = $this->readLine(500); |
| | | $line = $this->multLine($line, true); |
| | | $a = explode(' ', $line); |
| | | |
| | | if (($line[0] == '*') && ($a[1] == 'LSUB' || $a[1] == 'LIST')) { |
| | | $line = $this->multLine($line, true); |
| | | $a = explode(' ', $line); |
| | | |
| | | if (($line[0] == '*') && ($a[1] == $command)) { |
| | | $line = rtrim($line); |
| | | |
| | | // split one line |
| | | $a = rcube_explode_quoted_string(' ', $line); |
| | | // last string is folder name |
| | | $folder = preg_replace(array('/^"/', '/"$/'), '', $this->UnEscape($a[count($a)-1])); |
| | | // @TODO: do we need this check??? |
| | | if (!in_array($folder, $folders)) { |
| | | $folders[$i] = $folder; |
| | | } |
| | | // second from last is delimiter |
| | | $folders[] = preg_replace(array('/^"/', '/"$/'), '', $this->unEscape($a[count($a)-1])); |
| | | // second from last is delimiter |
| | | $delim = trim($a[count($a)-2], '"'); |
| | | // is it a container? |
| | | $i++; |
| | | } |
| | | } while (!$this->startsWith($line, 'lsb', true)); |
| | | } while (!$this->startsWith($line, $key, true)); |
| | | |
| | | if (is_array($folders)) { |
| | | if (!empty($ref)) { |
| | | // if rootdir was specified, make sure it's the first element |
| | | // some IMAP servers (i.e. Courier) won't return it |
| | | if ($ref[strlen($ref)-1]==$delim) { |
| | | $ref = substr($ref, 0, strlen($ref)-1); |
| | | } |
| | | if ($folders[0]!=$ref) { |
| | | array_unshift($folders, $ref); |
| | | } |
| | | } |
| | | return $folders; |
| | | } |
| | | } else if ($this->parseResult($line) == 0) { |
| | | return array(); |
| | | } |
| | | |
| | | $this->error = $line; |
| | | return false; |
| | | } |
| | |
| | | if (!$this->select($mailbox)) { |
| | | return false; |
| | | } |
| | | |
| | | |
| | | $result = false; |
| | | $parts = (array) $parts; |
| | | $key = 'fmh0'; |
| | |
| | | // format request |
| | | foreach($parts as $part) |
| | | $peeks[] = "BODY.PEEK[$part.$type]"; |
| | | |
| | | |
| | | $request = "$key FETCH $id (" . implode(' ', $peeks) . ')'; |
| | | |
| | | // send request |
| | | if (!$this->putLine($request)) { |
| | | return false; |
| | | } |
| | | |
| | | |
| | | do { |
| | | $line = $this->readLine(1000); |
| | | $line = $this->multLine($line); |
| | |
| | | default: |
| | | $mode = 0; |
| | | } |
| | | |
| | | $reply_key = '* ' . $id; |
| | | $result = false; |
| | | |
| | | // format request |
| | | $key = 'ftch0'; |
| | | $request = $key . ($is_uid ? ' UID' : '') . " FETCH $id (BODY.PEEK[$part])"; |
| | | $reply_key = '* ' . $id; |
| | | $key = 'ftch0'; |
| | | $request = $key . ($is_uid ? ' UID' : '') . " FETCH $id (BODY.PEEK[$part])"; |
| | | |
| | | // send request |
| | | if (!$this->putLine($request)) { |
| | | return false; |
| | |
| | | $a = explode(' ', $line); |
| | | } while (!($end = $this->startsWith($line, $key, true)) && $a[2] != 'FETCH'); |
| | | |
| | | $len = strlen($line); |
| | | $len = strlen($line); |
| | | $result = false; |
| | | |
| | | // handle empty "* X FETCH ()" response |
| | | if ($line[$len-1] == ')' && $line[$len-2] != '(') { |
| | |
| | | $sizeStr = substr($line, $from, $len); |
| | | $bytes = (int)$sizeStr; |
| | | $prev = ''; |
| | | |
| | | |
| | | while ($bytes > 0) { |
| | | $line = $this->readLine(1024); |
| | | $len = strlen($line); |
| | | |
| | | |
| | | if ($len > $bytes) { |
| | | $line = substr($line, 0, $bytes); |
| | | $len = strlen($line); |
| | |
| | | } |
| | | else |
| | | $prev = ''; |
| | | |
| | | |
| | | if ($file) |
| | | fwrite($file, base64_decode($line)); |
| | | else if ($print) |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | // read in anything up until last line |
| | | if (!$end) |
| | | do { |
| | | $line = $this->readLine(1024); |
| | | } while (!$this->startsWith($line, $key, true)); |
| | | |
| | | if ($result) { |
| | | if ($result !== false) { |
| | | if ($file) { |
| | | fwrite($file, $result); |
| | | } else if ($print) { |
| | |
| | | { |
| | | $query = 'usub1 UNSUBSCRIBE "' . $this->escape($folder) . '"'; |
| | | $this->putLine($query); |
| | | |
| | | |
| | | $line = trim($this->readLine(512)); |
| | | return ($this->parseResult($line) == 0); |
| | | } |
| | |
| | | do { |
| | | $line = $this->readLine(); |
| | | } while (!$this->startsWith($line, 'a ', true, true)); |
| | | |
| | | |
| | | $result = ($this->parseResult($line) == 0); |
| | | if (!$result) { |
| | | $this->error = $line; |
| | |
| | | if (!$folder) { |
| | | return false; |
| | | } |
| | | |
| | | |
| | | // open message file |
| | | $in_fp = false; |
| | | if (file_exists(realpath($path))) { |
| | | $in_fp = fopen($path, 'r'); |
| | | } |
| | | if (!$in_fp) { |
| | | if (!$in_fp) { |
| | | $this->error = "Couldn't open $path for reading"; |
| | | return false; |
| | | } |
| | | |
| | | |
| | | $len = filesize($path); |
| | | if (!$len) { |
| | | return false; |
| | |
| | | |
| | | return $result; |
| | | } |
| | | |
| | | |
| | | $this->error = "Couldn't send command \"$request\""; |
| | | return false; |
| | | } |
| | |
| | | */ |
| | | $result = false; |
| | | $quota_lines = array(); |
| | | |
| | | |
| | | // get line(s) containing quota info |
| | | if ($this->putLine('QUOT1 GETQUOTAROOT "INBOX"')) { |
| | | do { |
| | |
| | | } |
| | | } while (!$this->startsWith($line, 'QUOT1', true, true)); |
| | | } |
| | | |
| | | |
| | | // return false if not found, parse if found |
| | | $min_free = PHP_INT_MAX; |
| | | foreach ($quota_lines as $key => $quota_line) { |
| | | $quota_line = preg_replace('/[()]/', '', $quota_line); |
| | | $parts = explode(' ', $quota_line); |
| | | $storage_part = array_search('STORAGE', $parts); |
| | | |
| | | |
| | | if (!$storage_part) |
| | | continue; |
| | | |
| | | |
| | | $used = intval($parts[$storage_part+1]); |
| | | $total = intval($parts[$storage_part+2]); |
| | | $free = $total - $used; |
| | | |
| | | $free = $total - $used; |
| | | |
| | | // return lowest available space from all quotas |
| | | if ($free < $min_free) { |
| | | $min_free = $free; |
| | | if ($free < $min_free) { |
| | | $min_free = $free; |
| | | $result['used'] = $used; |
| | | $result['total'] = $total; |
| | | $result['percent'] = min(100, round(($used/max(1,$total))*100)); |
| | |
| | | return $result; |
| | | } |
| | | |
| | | private function iil_xor($string, $string2) |
| | | private function _xor($string, $string2) |
| | | { |
| | | $result = ''; |
| | | $size = strlen($string); |
| | |
| | | |
| | | $ts = (int) $ts; |
| | | |
| | | return $ts < 0 ? 0 : $ts; |
| | | return $ts < 0 ? 0 : $ts; |
| | | } |
| | | |
| | | private function SplitHeaderLine($string) |
| | |
| | | $data = array(); |
| | | $in_quotes = false; |
| | | $elem = 0; |
| | | |
| | | |
| | | for ($i;$i<$len;$i++) { |
| | | $c = (string)$str[$i]; |
| | | if ($c == '(' && !$in_quotes) { |
| | |
| | | $data[$elem].=$c; |
| | | } |
| | | } |
| | | |
| | | |
| | | return $data; |
| | | } |
| | | |
| | | private function escape($string) |
| | | { |
| | | return strtr($string, array('"'=>'\\"', '\\' => '\\\\')); |
| | | return strtr($string, array('"'=>'\\"', '\\' => '\\\\')); |
| | | } |
| | | |
| | | private function unEscape($string) |
| | | { |
| | | return strtr($string, array('\\"'=>'"', '\\\\' => '\\')); |
| | | return strtr($string, array('\\"'=>'"', '\\\\' => '\\')); |
| | | } |
| | | |
| | | } |
| | | |
| | | ?> |