summaryrefslogtreecommitdiff
path: root/program/lib
diff options
context:
space:
mode:
authoralecpl <alec@alec.pl>2010-03-26 21:03:22 +0000
committeralecpl <alec@alec.pl>2010-03-26 21:03:22 +0000
commit59c216f3cceaf403ca0a678821eb219b6c41e6ff (patch)
tree6733766f1f87a275fe772543bb38ce25cec48b63 /program/lib
parent5e2014d90a23891a7e17c51356b3fdfce39c2615 (diff)
- Fix bugs on unexpected IMAP connection close (#1486190, #1486270)
- Iloha's imap.inc rewritten into rcube_imap_generic class - rcube_imap code re-formatting
Diffstat (limited to 'program/lib')
-rw-r--r--program/lib/imap.inc2293
1 files changed, 0 insertions, 2293 deletions
diff --git a/program/lib/imap.inc b/program/lib/imap.inc
deleted file mode 100644
index fc55d73ef..000000000
--- a/program/lib/imap.inc
+++ /dev/null
@@ -1,2293 +0,0 @@
-<?php
-/////////////////////////////////////////////////////////
-//
-// Iloha IMAP Library (IIL)
-//
-// (C)Copyright 2002 Ryo Chijiiwa <Ryo@IlohaMail.org>
-//
-// This file is part of IlohaMail. IlohaMail is free software released
-// under the GPL license. See enclosed file COPYING for details, or
-// see http://www.fsf.org/copyleft/gpl.html
-//
-/////////////////////////////////////////////////////////
-
-/********************************************************
-
- FILE: include/imap.inc
- PURPOSE:
- Provide alternative IMAP library that doesn't rely on the standard
- C-Client based version. This allows IlohaMail to function regardless
- of whether or not the PHP build it's running on has IMAP functionality
- built-in.
- USEAGE:
- Function containing "_C_" in name require connection handler to be
- passed as one of the parameters. To obtain connection handler, use
- iil_Connect()
- VERSION:
- IlohaMail-0.9-20050415
- CHANGES:
- File altered by Thomas Bruederli <roundcube@gmail.com>
- to fit enhanced equirements by the RoundCube Webmail:
- - Added list of server capabilites and check these before invoking commands
- - Added junk flag to iilBasicHeader
- - Enhanced error reporting on fsockopen()
- - Additional parameter for SORT command
- - Removed Call-time pass-by-reference because deprecated
- - Parse charset from content-type in iil_C_FetchHeaders()
- - Enhanced heaer sorting
- - Pass message as reference in iil_C_Append (to save memory)
- - Added BCC and REFERENCE to the list of headers to fetch in iil_C_FetchHeaders()
- - Leave messageID unchanged in iil_C_FetchHeaders()
- - Avoid stripslahes in iil_Connect()
- - Escape quotes and backslashes in iil_C_Login()
- - Added patch to iil_SortHeaders() by Richard Green
- - Removed <br> from error messages (better for logging)
- - Added patch to iil_C_Sort() enabling UID SORT commands
- - Added function iil_C_ID2UID()
- - Casting date parts in iil_StrToTime() to avoid mktime() warnings
- - Also acceppt LIST responses in iil_C_ListSubscribed()
- - Sanity check of $message_set in iil_C_FetchHeaders(), iil_C_FetchHeaderIndex(), iil_C_FetchThreadHeaders()
- - Implemented UID FETCH in iil_C_FetchHeaders()
- - Abort do-loop on socket errors (fgets returns false)
- - $ICL_SSL is not boolean anymore but contains the connection schema (ssl or tls)
- - Removed some debuggers (echo ...)
- File altered by Aleksander Machniak <alec@alec.pl>
- - trim(chop()) replaced by trim()
- - added iil_Escape()/iil_UnEscape() with support for " and \ in folder names
- - support \ character in username in iil_C_Login()
- - fixed iil_MultLine(): use iil_ReadBytes() instead of iil_ReadLine()
- - fixed iil_C_FetchStructureString() to handle many literal strings in response
- - removed hardcoded data size in iil_ReadLine()
- - added iil_PutLine() wrapper for fputs()
- - code cleanup and identation fixes
- - removed flush() calls in iil_C_HandlePartBody() to prevent from memory leak (#1485187)
- - don't return "??" from iil_C_GetQuota()
- - RFC3501 [7.1] don't call CAPABILITY if was returned in server
- optional resposne in iil_Connect(), added iil_C_GetCapability()
- - remove 'undisclosed-recipients' string from 'To' header
- - iil_C_HandlePartBody(): added 6th argument and fixed endless loop
- - added iil_PutLineC()
- - fixed iil_C_Sort() to support very long and/or divided responses
- - added BYE/BAD response simple support for endless loop prevention
- - added 3rd argument in iil_StartsWith* functions
- - fix iil_C_FetchPartHeader() in some cases by use of iil_C_HandlePartBody()
- - allow iil_C_HandlePartBody() to fetch whole message
- - optimize iil_C_FetchHeaders() to use only one FETCH command
- - added 4th argument to iil_Connect()
- - allow setting rootdir and delimiter before connect
- - support multiquota result
- - include BODYSTRUCTURE in iil_C_FetchHeaders()
- - added iil_C_FetchMIMEHeaders() function
- - added \* flag support
- - use PREG instead of EREG
- - removed caching functions
- - handling connection startup response
- - added UID EXPUNGE support
- - fixed problem with double quotes and spaces in folder names in LIST and LSUB
- - rewritten iil_C_FetchHeaderIndex()
-
-********************************************************/
-
-/**
- * @todo Possibly clean up more CS.
- * @todo Try to replace most double-quotes with single-quotes.
- * @todo Split this file into smaller files.
- * @todo Refactor code.
- * @todo Replace echo-debugging (make it adhere to config setting and log)
- */
-
-
-if (!isset($IMAP_USE_HEADER_DATE) || !$IMAP_USE_HEADER_DATE) {
- $IMAP_USE_INTERNAL_DATE = true;
-}
-
-$GLOBALS['IMAP_FLAGS'] = array(
- 'SEEN' => '\\Seen',
- 'DELETED' => '\\Deleted',
- 'RECENT' => '\\Recent',
- 'ANSWERED' => '\\Answered',
- 'DRAFT' => '\\Draft',
- 'FLAGGED' => '\\Flagged',
- 'FORWARDED' => '$Forwarded',
- 'MDNSENT' => '$MDNSent',
- '*' => '\\*',
-);
-
-$iil_error;
-$iil_errornum;
-$iil_selected;
-
-/**
- * @todo Change class vars to public/private
- */
-class iilConnection
-{
- var $fp;
- var $error;
- var $errorNum;
- var $selected;
- var $message;
- var $host;
- var $exists;
- var $recent;
- var $rootdir;
- var $delimiter;
- var $capability = array();
- var $permanentflags = array();
- var $capability_readed = false;
-}
-
-/**
- * @todo Change class vars to public/private
- */
-class iilBasicHeader
-{
- var $id;
- var $uid;
- var $subject;
- var $from;
- var $to;
- var $cc;
- var $replyto;
- var $in_reply_to;
- var $date;
- var $messageID;
- var $size;
- var $encoding;
- var $charset;
- var $ctype;
- var $flags;
- var $timestamp;
- var $f;
- var $body_structure;
- var $internaldate;
- var $references;
- var $priority;
- var $mdn_to;
- var $mdn_sent = false;
- var $is_draft = false;
- var $seen = false;
- var $deleted = false;
- var $recent = false;
- var $answered = false;
- var $forwarded = false;
- var $junk = false;
- var $flagged = false;
- var $has_children = false;
- var $depth = 0;
- var $unread_children = 0;
- var $others = array();
-}
-
-function iil_xor($string, $string2) {
- $result = '';
- $size = strlen($string);
- for ($i=0; $i<$size; $i++) {
- $result .= chr(ord($string[$i]) ^ ord($string2[$i]));
- }
- return $result;
-}
-
-function iil_PutLine($fp, $string, $endln=true) {
- global $my_prefs;
-
- if (!empty($my_prefs['debug_mode']))
- write_log('imap', 'C: '. rtrim($string));
-
- return fputs($fp, $string . ($endln ? "\r\n" : ''));
-}
-
-// iil_PutLine replacement with Command Continuation Requests (RFC3501 7.5) support
-function iil_PutLineC($fp, $string, $endln=true) {
- if ($endln)
- $string .= "\r\n";
-
- $res = 0;
- if ($parts = preg_split('/(\{[0-9]+\}\r\n)/m', $string, -1, PREG_SPLIT_DELIM_CAPTURE)) {
- for($i=0, $cnt=count($parts); $i<$cnt; $i++) {
- if(preg_match('/^\{[0-9]+\}\r\n$/', $parts[$i+1])) {
- $res += iil_PutLine($fp, $parts[$i].$parts[$i+1], false);
- $line = iil_ReadLine($fp, 1000);
- // handle error in command
- if ($line[0] != '+')
- return false;
- $i++;
- }
- else
- $res += iil_PutLine($fp, $parts[$i], false);
- }
- }
- return $res;
-}
-
-function iil_ReadLine($fp, $size=1024) {
- global $my_prefs;
-
- $line = '';
-
- if (!$fp) {
- return NULL;
- }
-
- if (!$size) {
- $size = 1024;
- }
-
- do {
- if (feof($fp)) {
- return $line ? $line : NULL;
- }
-
- $buffer = fgets($fp, $size);
-
- if ($buffer === false) {
- break;
- }
- if (!empty($my_prefs['debug_mode']))
- write_log('imap', 'S: '. chop($buffer));
- $line .= $buffer;
- } while ($buffer[strlen($buffer)-1] != "\n");
-
- return $line;
-}
-
-function iil_MultLine($fp, $line, $escape=false) {
- $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 = iil_ReadBytes($fp, $bytes);
- if ($line === NULL)
- break;
- $out .= $line;
- }
-
- $line = $a[1][0] . '"' . ($escape ? iil_Escape($out) : $out) . '"';
- }
- return $line;
-}
-
-function iil_ReadBytes($fp, $bytes) {
- global $my_prefs;
- $data = '';
- $len = 0;
- while ($len < $bytes && !feof($fp))
- {
- $d = fread($fp, $bytes-$len);
- if (!empty($my_prefs['debug_mode']))
- write_log('imap', 'S: '. $d);
- $data .= $d;
- $data_len = strlen($data);
- if ($len == $data_len) {
- break; //nothing was read -> exit to avoid apache lockups
- }
- $len = $data_len;
- };
-
- return $data;
-}
-
-// don't use it in loops, until you exactly know what you're doing
-function iil_ReadReply($fp) {
- do {
- $line = trim(iil_ReadLine($fp, 1024));
- } while ($line[0] == '*');
-
- return $line;
-}
-
-function iil_ParseResult($string) {
- $a = explode(' ', trim($string));
- if (count($a) >= 2) {
- $res = strtoupper($a[1]);
- if ($res == 'OK') {
- return 0;
- } else if ($res == 'NO') {
- return -1;
- } else if ($res == 'BAD') {
- return -2;
- } else if ($res == 'BYE') {
- return -3;
- }
- }
- return -4;
-}
-
-// check if $string starts with $match (or * BYE/BAD)
-function iil_StartsWith($string, $match, $error=false) {
- $len = strlen($match);
- if ($len == 0) {
- return false;
- }
- if (strncmp($string, $match, $len) == 0) {
- return true;
- }
- if ($error && preg_match('/^\* (BYE|BAD) /i', $string)) {
- return true;
- }
- return false;
-}
-
-function iil_StartsWithI($string, $match, $error=false) {
- $len = strlen($match);
- if ($len == 0) {
- return false;
- }
- if (strncasecmp($string, $match, $len) == 0) {
- return true;
- }
- if ($error && preg_match('/^\* (BYE|BAD) /i', $string)) {
- return true;
- }
- return false;
-}
-
-function iil_Escape($string)
-{
- return strtr($string, array('"'=>'\\"', '\\' => '\\\\'));
-}
-
-function iil_UnEscape($string)
-{
- return strtr($string, array('\\"'=>'"', '\\\\' => '\\'));
-}
-
-function iil_C_GetCapability(&$conn, $name)
-{
- if (in_array($name, $conn->capability)) {
- return true;
- }
- else if ($conn->capability_readed) {
- return false;
- }
-
- // get capabilities (only once) because initial
- // optional CAPABILITY response may differ
- $conn->capability = array();
-
- iil_PutLine($conn->fp, "cp01 CAPABILITY");
- do {
- $line = trim(iil_ReadLine($conn->fp, 1024));
- $a = explode(' ', $line);
- if ($line[0] == '*') {
- while (list($k, $w) = each($a)) {
- if ($w != '*' && $w != 'CAPABILITY')
- $conn->capability[] = strtoupper($w);
- }
- }
- } while ($a[0] != 'cp01');
-
- $conn->capability_readed = true;
-
- if (in_array($name, $conn->capability)) {
- return true;
- }
-
- return false;
-}
-
-function iil_C_ClearCapability(&$conn)
-{
- $conn->capability = array();
- $conn->capability_readed = false;
-}
-
-function iil_C_Authenticate(&$conn, $user, $pass, $encChallenge) {
-
- $ipad = '';
- $opad = '';
-
- // initialize ipad, opad
- for ($i=0;$i<64;$i++) {
- $ipad .= chr(0x36);
- $opad .= chr(0x5C);
- }
-
- // pad $pass so it's 64 bytes
- $padLen = 64 - strlen($pass);
- for ($i=0;$i<$padLen;$i++) {
- $pass .= chr(0);
- }
-
- // generate hash
- $hash = md5(iil_xor($pass,$opad) . pack("H*", md5(iil_xor($pass, $ipad) . base64_decode($encChallenge))));
-
- // generate reply
- $reply = base64_encode($user . ' ' . $hash);
-
- // send result, get reply
- iil_PutLine($conn->fp, $reply);
- $line = iil_ReadLine($conn->fp, 1024);
-
- // process result
- $result = iil_ParseResult($line);
- if ($result == 0) {
- $conn->error .= '';
- $conn->errorNum = 0;
- return $conn->fp;
- }
-
- if ($result == -3) fclose($conn->fp); // BYE response
-
- $conn->error .= 'Authentication for ' . $user . ' failed (AUTH): "';
- $conn->error .= htmlspecialchars($line) . '"';
- $conn->errorNum = $result;
-
- return $result;
-}
-
-function iil_C_Login(&$conn, $user, $password) {
-
- iil_PutLine($conn->fp, 'a001 LOGIN "'.iil_Escape($user).'" "'.iil_Escape($password).'"');
-
- $line = iil_ReadReply($conn->fp);
-
- // process result
- $result = iil_ParseResult($line);
-
- if ($result == 0) {
- $conn->error .= '';
- $conn->errorNum = 0;
- return $conn->fp;
- }
-
- fclose($conn->fp);
-
- $conn->error .= 'Authentication for ' . $user . ' failed (LOGIN): "';
- $conn->error .= htmlspecialchars($line)."\"";
- $conn->errorNum = $result;
-
- return $result;
-}
-
-function iil_ParseNamespace2($str, &$i, $len=0, $l) {
- if (!$l) {
- $str = str_replace('NIL', '()', $str);
- }
- if (!$len) {
- $len = strlen($str);
- }
- $data = array();
- $in_quotes = false;
- $elem = 0;
- for ($i;$i<$len;$i++) {
- $c = (string)$str[$i];
- if ($c == '(' && !$in_quotes) {
- $i++;
- $data[$elem] = iil_ParseNamespace2($str, $i, $len, $l++);
- $elem++;
- } else if ($c == ')' && !$in_quotes) {
- return $data;
- } else if ($c == '\\') {
- $i++;
- if ($in_quotes) {
- $data[$elem] .= $c.$str[$i];
- }
- } else if ($c == '"') {
- $in_quotes = !$in_quotes;
- if (!$in_quotes) {
- $elem++;
- }
- } else if ($in_quotes) {
- $data[$elem].=$c;
- }
- }
- return $data;
-}
-
-function iil_C_NameSpace(&$conn) {
- global $my_prefs;
-
- if (isset($my_prefs['rootdir']) && is_string($my_prefs['rootdir'])) {
- $conn->rootdir = $my_prefs['rootdir'];
- return true;
- }
-
- if (!iil_C_GetCapability($conn, 'NAMESPACE')) {
- return false;
- }
-
- iil_PutLine($conn->fp, "ns1 NAMESPACE");
- do {
- $line = iil_ReadLine($conn->fp, 1024);
- if (iil_StartsWith($line, '* NAMESPACE')) {
- $i = 0;
- $line = iil_UnEscape($line);
- $data = iil_ParseNamespace2(substr($line,11), $i, 0, 0);
- }
- } while (!iil_StartsWith($line, 'ns1', true));
-
- if (!is_array($data)) {
- return false;
- }
-
- $user_space_data = $data[0];
- if (!is_array($user_space_data)) {
- return false;
- }
-
- $first_userspace = $user_space_data[0];
- if (count($first_userspace)!=2) {
- return false;
- }
-
- $conn->rootdir = $first_userspace[0];
- $conn->delimiter = $first_userspace[1];
- $my_prefs['rootdir'] = substr($conn->rootdir, 0, -1);
- $my_prefs['delimiter'] = $conn->delimiter;
-
- return true;
-}
-
-function iil_Connect($host, $user, $password, $options=null) {
- global $iil_error, $iil_errornum;
- global $ICL_SSL, $ICL_PORT;
- global $my_prefs, $IMAP_USE_INTERNAL_DATE;
-
- $iil_error = '';
- $iil_errornum = 0;
-
- // set options
- if (is_array($options)) {
- $my_prefs = $options;
- }
- // set auth method
- if (!empty($my_prefs['auth_method'])) {
- $auth_method = strtoupper($my_prefs['auth_method']);
- } else {
- $auth_method = 'CHECK';
- }
-
- $message = "INITIAL: $auth_method\n";
-
- $result = false;
-
- // initialize connection
- $conn = new iilConnection;
- $conn->error = '';
- $conn->errorNum = 0;
- $conn->selected = '';
- $conn->user = $user;
- $conn->host = $host;
-
- if ($my_prefs['sort_field'] == 'INTERNALDATE') {
- $IMAP_USE_INTERNAL_DATE = true;
- } else if ($my_prefs['sort_field'] == 'DATE') {
- $IMAP_USE_INTERNAL_DATE = false;
- }
-
- //check input
- if (empty($host)) {
- $iil_error = "Empty host";
- $iil_errornum = -1;
- return false;
- }
- if (empty($user)) {
- $iil_error = "Empty user";
- $iil_errornum = -1;
- return false;
- }
- if (empty($password)) {
- $iil_error = "Empty password";
- $iil_errornum = -1;
- return false;
- }
-
- if (!$ICL_PORT) {
- $ICL_PORT = 143;
- }
- //check for SSL
- if ($ICL_SSL && $ICL_SSL != 'tls') {
- $host = $ICL_SSL . '://' . $host;
- }
-
- $conn->fp = @fsockopen($host, $ICL_PORT, $errno, $errstr, 10);
- if (!$conn->fp) {
- $iil_error = "Could not connect to $host at port $ICL_PORT: $errstr";
- $iil_errornum = -2;
- return false;
- }
-
- stream_set_timeout($conn->fp, 10);
- $line = trim(fgets($conn->fp, 8192));
-
- if ($my_prefs['debug_mode'] && $line)
- write_log('imap', 'S: '. $line);
-
- // Connected to wrong port or connection error?
- if (!preg_match('/^\* (OK|PREAUTH)/i', $line)) {
- if ($line)
- $iil_error = "Wrong startup greeting ($host:$ICL_PORT): $line";
- else
- $iil_error = "Empty startup greeting ($host:$ICL_PORT)";
- $iil_errornum = -2;
- return false;
- }
-
- // RFC3501 [7.1] optional CAPABILITY response
- if (preg_match('/\[CAPABILITY ([^]]+)\]/i', $line, $matches)) {
- $conn->capability = explode(' ', strtoupper($matches[1]));
- }
-
- $conn->message .= $line;
-
- // TLS connection
- if ($ICL_SSL == 'tls' && iil_C_GetCapability($conn, 'STARTTLS')) {
- if (version_compare(PHP_VERSION, '5.1.0', '>=')) {
- iil_PutLine($conn->fp, 'stls000 STARTTLS');
-
- $line = iil_ReadLine($conn->fp, 4096);
- if (!iil_StartsWith($line, 'stls000 OK')) {
- $iil_error = "Server responded to STARTTLS with: $line";
- $iil_errornum = -2;
- return false;
- }
-
- if (!stream_socket_enable_crypto($conn->fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
- $iil_error = "Unable to negotiate TLS";
- $iil_errornum = -2;
- return false;
- }
-
- // Now we're authenticated, capabilities need to be reread
- iil_C_ClearCapability($conn);
- }
- }
-
- $orig_method = $auth_method;
-
- if ($auth_method == 'CHECK') {
- // check for supported auth methods
- if (iil_C_GetCapability($conn, 'AUTH=CRAM-MD5') || iil_C_GetCapability($conn, 'AUTH=CRAM_MD5')) {
- $auth_method = 'AUTH';
- }
- else {
- // default to plain text auth
- $auth_method = 'PLAIN';
- }
- }
-
- if ($auth_method == 'AUTH') {
- // do CRAM-MD5 authentication
- iil_PutLine($conn->fp, "a000 AUTHENTICATE CRAM-MD5");
- $line = trim(iil_ReadLine($conn->fp, 1024));
-
- if ($line[0] == '+') {
- // got a challenge string, try CRAM-MD5
- $result = iil_C_Authenticate($conn, $user, $password, substr($line,2));
-
- // stop if server sent BYE response
- if ($result == -3) {
- $iil_error = $conn->error;
- $iil_errornum = $conn->errorNum;
- return false;
- }
- }
-
- if (!is_resource($result) && $orig_method == 'CHECK') {
- $auth_method = 'PLAIN';
- }
- }
-
- if ($auth_method == 'PLAIN') {
- // do plain text auth
- $result = iil_C_Login($conn, $user, $password);
- }
-
- if (is_resource($result)) {
- if ($my_prefs['force_caps']) {
- iil_C_ClearCapability($conn);
- }
- iil_C_Namespace($conn);
- return $conn;
- } else {
- $iil_error = $conn->error;
- $iil_errornum = $conn->errorNum;
- return false;
- }
-}
-
-function iil_Close(&$conn) {
- if (iil_PutLine($conn->fp, "I LOGOUT")) {
- if (!feof($conn->fp))
- fgets($conn->fp, 1024);
- fclose($conn->fp);
- $conn->fp = false;
- }
-}
-
-function iil_ExplodeQuotedString($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;
-}
-
-function iil_C_Select(&$conn, $mailbox) {
-
- if (empty($mailbox)) {
- return false;
- }
- if ($conn->selected == $mailbox) {
- return true;
- }
-
- if (iil_PutLine($conn->fp, "sel1 SELECT \"".iil_Escape($mailbox).'"')) {
- do {
- $line = chop(iil_ReadLine($conn->fp, 300));
- $a = explode(' ', $line);
- if (count($a) == 3) {
- $token = strtoupper($a[2]);
- if ($token == 'EXISTS') {
- $conn->exists = (int) $a[1];
- }
- else if ($token == 'RECENT') {
- $conn->recent = (int) $a[1];
- }
- }
- else if (preg_match('/\[?PERMANENTFLAGS\s+\(([^\)]+)\)\]/U', $line, $match)) {
- $conn->permanentflags = explode(' ', $match[1]);
- }
- } while (!iil_StartsWith($line, 'sel1', true));
-
- if (strcasecmp($a[1], 'OK') == 0) {
- $conn->selected = $mailbox;
- return true;
- }
- }
- return false;
-}
-
-function iil_C_CheckForRecent(&$conn, $mailbox) {
- if (empty($mailbox)) {
- $mailbox = 'INBOX';
- }
-
- iil_C_Select($conn, $mailbox);
- if ($conn->selected == $mailbox) {
- return $conn->recent;
- }
- return false;
-}
-
-function iil_C_CountMessages(&$conn, $mailbox, $refresh = false) {
- if ($refresh) {
- $conn->selected = '';
- }
-
- iil_C_Select($conn, $mailbox);
- if ($conn->selected == $mailbox) {
- return $conn->exists;
- }
- return false;
-}
-
-function iil_SplitHeaderLine($string) {
- $pos=strpos($string, ':');
- if ($pos>0) {
- $res[0] = substr($string, 0, $pos);
- $res[1] = trim(substr($string, $pos+1));
- return $res;
- }
- return $string;
-}
-
-function iil_StrToTime($date) {
-
- // support non-standard "GMTXXXX" literal
- $date = preg_replace('/GMT\s*([+-][0-9]+)/', '\\1', $date);
- // if date parsing fails, we have a date in non-rfc format.
- // remove token from the end and try again
- while ((($ts = @strtotime($date))===false) || ($ts < 0))
- {
- $d = explode(' ', $date);
- array_pop($d);
- if (!$d) break;
- $date = implode(' ', $d);
- }
-
- $ts = (int) $ts;
-
- return $ts < 0 ? 0 : $ts;
-}
-
-function iil_C_Sort(&$conn, $mailbox, $field, $add='', $is_uid=FALSE,
- $encoding = 'US-ASCII') {
-
- $field = strtoupper($field);
- if ($field == 'INTERNALDATE') {
- $field = 'ARRIVAL';
- }
-
- $fields = array('ARRIVAL' => 1,'CC' => 1,'DATE' => 1,
- 'FROM' => 1, 'SIZE' => 1, 'SUBJECT' => 1, 'TO' => 1);
-
- if (!$fields[$field]) {
- return false;
- }
-
- /* Do "SELECT" command */
- if (!iil_C_Select($conn, $mailbox)) {
- return false;
- }
-
- $is_uid = $is_uid ? 'UID ' : '';
-
- // message IDs
- if (is_array($add))
- $add = iil_CompressMessageSet(join(',', $add));
-
- if (!empty($add))
- $add = " $add";
-
- $command = 's ' . $is_uid . 'SORT (' . $field . ') ';
- $command .= $encoding . ' ALL' . $add;
- $line = $data = '';
-
- if (!iil_PutLineC($conn->fp, $command)) {
- return false;
- }
- do {
- $line = chop(iil_ReadLine($conn->fp));
- if (iil_StartsWith($line, '* SORT')) {
- $data .= substr($line, 7);
- } else if (preg_match('/^[0-9 ]+$/', $line)) {
- $data .= $line;
- }
- } while (!iil_StartsWith($line, 's ', true));
-
- $result_code = iil_ParseResult($line);
-
- if ($result_code != 0) {
- $conn->error = 'iil_C_Sort: ' . $line . "\n";
- return false;
- }
-
- return preg_split('/\s+/', $data, -1, PREG_SPLIT_NO_EMPTY);
-}
-
-function iil_C_FetchHeaderIndex(&$conn, $mailbox, $message_set, $index_field='', $skip_deleted=true, $uidfetch=false) {
-
- if (is_array($message_set)) {
- if (!($message_set = iil_CompressMessageSet(join(',', $message_set))))
- return false;
- } else {
- list($from_idx, $to_idx) = explode(':', $message_set);
- if (empty($message_set) ||
- (isset($to_idx) && $to_idx != '*' && (int)$from_idx > (int)$to_idx)) {
- return false;
- }
- }
-
- $index_field = empty($index_field) ? 'DATE' : strtoupper($index_field);
-
- $fields_a['DATE'] = 1;
- $fields_a['INTERNALDATE'] = 4;
- $fields_a['ARRIVAL'] = 4;
- $fields_a['FROM'] = 1;
- $fields_a['REPLY-TO'] = 1;
- $fields_a['SENDER'] = 1;
- $fields_a['TO'] = 1;
- $fields_a['CC'] = 1;
- $fields_a['SUBJECT'] = 1;
- $fields_a['UID'] = 2;
- $fields_a['SIZE'] = 2;
- $fields_a['SEEN'] = 3;
- $fields_a['RECENT'] = 3;
- $fields_a['DELETED'] = 3;
-
- if (!($mode = $fields_a[$index_field])) {
- return false;
- }
-
- /* Do "SELECT" command */
- if (!iil_C_Select($conn, $mailbox)) {
- return false;
- }
-
- // build FETCH command string
- $key = 'fhi0';
- $cmd = $uidfetch ? 'UID FETCH' : 'FETCH';
- $deleted = $skip_deleted ? ' FLAGS' : '';
-
- if ($mode == 1 && $index_field == 'DATE')
- $request = " $cmd $message_set (INTERNALDATE BODY.PEEK[HEADER.FIELDS (DATE)]$deleted)";
- else if ($mode == 1)
- $request = " $cmd $message_set (BODY.PEEK[HEADER.FIELDS ($index_field)]$deleted)";
- else if ($mode == 2) {
- if ($index_field == 'SIZE')
- $request = " $cmd $message_set (RFC822.SIZE$deleted)";
- else
- $request = " $cmd $message_set ($index_field$deleted)";
- } else if ($mode == 3)
- $request = " $cmd $message_set (FLAGS)";
- else // 4
- $request = " $cmd $message_set (INTERNALDATE$deleted)";
-
- $request = $key . $request;
-
- if (!iil_PutLine($conn->fp, $request))
- return false;
-
- $result = array();
-
- do {
- $line = chop(iil_ReadLine($conn->fp, 200));
- $line = iil_MultLine($conn->fp, $line);
-
- 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)) {
- $deleted[$id] = $id;
- continue;
- }
- }
-
- if ($mode == 1 && $index_field == 'DATE') {
- if (preg_match('/BODY\[HEADER\.FIELDS \("*DATE"*\)\] (.*)/', $line, $matches)) {
- $value = preg_replace(array('/^"*[a-z]+:/i'), '', $matches[1]);
- $value = trim($value);
- $result[$id] = iil_StrToTime($value);
- }
- // non-existent/empty Date: header, use INTERNALDATE
- if (empty($result[$id])) {
- if (preg_match('/INTERNALDATE "([^"]+)"/', $line, $matches))
- $result[$id] = iil_StrToTime($matches[1]);
- else
- $result[$id] = 0;
- }
- } else if ($mode == 1) {
- if (preg_match('/BODY\[HEADER\.FIELDS \("?(FROM|REPLY-TO|SENDER|TO|SUBJECT)"?\)\] (.*)/', $line, $matches)) {
- $value = preg_replace(array('/^"*[a-z]+:/i', '/\s+$/sm'), array('', ''), $matches[2]);
- $result[$id] = trim($value);
- } else {
- $result[$id] = '';
- }
- } else if ($mode == 2) {
- if (preg_match('/\((UID|RFC822\.SIZE) ([0-9]+)/', $line, $matches)) {
- $result[$id] = trim($matches[2]);
- } else {
- $result[$id] = 0;
- }
- } else if ($mode == 3) {
- if (!$flags && preg_match('/FLAGS \(([^)]+)\)/', $line, $matches)) {
- $flags = explode(' ', $matches[1]);
- }
- $result[$id] = in_array('\\'.$index_field, $flags) ? 1 : 0;
- } else if ($mode == 4) {
- if (preg_match('/INTERNALDATE "([^"]+)"/', $line, $matches)) {
- $result[$id] = iil_StrToTime($matches[1]);
- } else {
- $result[$id] = 0;
- }
- }
- }
- } while (!iil_StartsWith($line, $key, true));
-
- return $result;
-}
-
-function iil_CompressMessageSet($message_set) {
- //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];
-
- foreach ($ids as $id) {
- $incr = $id - $prev;
- if ($incr > 1) { //found a gap
- if ($start == $prev) {
- $result[] = $prev; //push single id
- } else {
- $result[] = $start . ':' . $prev; //push sequence as start_id:end_id
- }
- $start = $id; //start of new sequence
- }
- $prev = $id;
- }
-
- //handle the last sequence/id
- if ($start==$prev) {
- $result[] = $prev;
- } else {
- $result[] = $start.':'.$prev;
- }
-
- //return as comma separated string
- return implode(',', $result);
-}
-
-function iil_C_UIDsToMIDs(&$conn, $mailbox, $uids) {
- if (!is_array($uids) || count($uids) == 0) {
- return array();
- }
- return iil_C_Search($conn, $mailbox, 'UID ' . implode(',', $uids));
-}
-
-function iil_C_UIDToMID(&$conn, $mailbox, $uid) {
- $result = iil_C_UIDsToMIDs($conn, $mailbox, array($uid));
- if (count($result) == 1) {
- return $result[0];
- }
- return false;
-}
-
-function iil_C_FetchUIDs(&$conn, $mailbox, $message_set=null) {
- global $clock;
-
- if (is_array($message_set))
- $message_set = join(',', $message_set);
- else if (empty($message_set))
- $message_set = '1:*';
-
- return iil_C_FetchHeaderIndex($conn, $mailbox, $message_set, 'UID', false);
-}
-
-function iil_C_FetchHeaders(&$conn, $mailbox, $message_set, $uidfetch=false, $bodystr=false, $add='')
-{
- global $IMAP_USE_INTERNAL_DATE;
-
- $result = array();
- $fp = $conn->fp;
-
- /* Do "SELECT" command */
- if (!iil_C_Select($conn, $mailbox)) {
- $conn->error = "Couldn't select $mailbox";
- return false;
- }
-
- if (is_array($message_set))
- $message_set = join(',', $message_set);
-
- $message_set = iil_CompressMessageSet($message_set);
-
- if ($add)
- $add = ' '.strtoupper(trim($add));
-
- /* FETCH uid, size, flags and headers */
- $key = 'FH12';
- $request = $key . ($uidfetch ? ' UID' : '') . " FETCH $message_set ";
- $request .= "(UID RFC822.SIZE FLAGS INTERNALDATE ";
- if ($bodystr)
- $request .= "BODYSTRUCTURE ";
- $request .= "BODY.PEEK[HEADER.FIELDS ";
- $request .= "(DATE FROM TO SUBJECT REPLY-TO IN-REPLY-TO CC BCC ";
- $request .= "CONTENT-TRANSFER-ENCODING CONTENT-TYPE MESSAGE-ID ";
- $request .= "REFERENCES DISPOSITION-NOTIFICATION-TO X-PRIORITY ";
- $request .= "X-DRAFT-INFO".$add.")])";
-
- if (!iil_PutLine($fp, $request)) {
- return false;
- }
- do {
- $line = iil_ReadLine($fp, 1024);
- $line = iil_MultLine($fp, $line);
-
- $a = explode(' ', $line);
- if (($line[0] == '*') && ($a[2] == 'FETCH')) {
- $id = $a[1];
-
- $result[$id] = new iilBasicHeader;
- $result[$id]->id = $id;
- $result[$id]->subject = '';
- $result[$id]->messageID = 'mid:' . $id;
-
- $lines = array();
- $ln = 0;
- /*
- Sample reply line:
- * 321 FETCH (UID 2417 RFC822.SIZE 2730 FLAGS (\Seen)
- INTERNALDATE "16-Nov-2008 21:08:46 +0100" BODYSTRUCTURE (...)
- BODY[HEADER.FIELDS ...
- */
-
- if (preg_match('/^\* [0-9]+ FETCH \((.*) BODY/s', $line, $matches)) {
- $str = $matches[1];
-
- // swap parents with quotes, then explode
- $str = preg_replace('/[()]/', '"', $str);
- $a = iil_ExplodeQuotedString(' ', $str);
-
- // did we get the right number of replies?
- $parts_count = count($a);
- if ($parts_count>=6) {
- for ($i=0; $i<$parts_count; $i=$i+2) {
- if ($a[$i] == 'UID')
- $result[$id]->uid = $a[$i+1];
- else if ($a[$i] == 'RFC822.SIZE')
- $result[$id]->size = $a[$i+1];
- else if ($a[$i] == 'INTERNALDATE')
- $time_str = $a[$i+1];
- else if ($a[$i] == 'FLAGS')
- $flags_str = $a[$i+1];
- }
-
- $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 = iil_StrToTime($time_str);
- $result[$id]->date = $time_str;
- }
-
- // BODYSTRUCTURE
- if($bodystr) {
- while (!preg_match('/ BODYSTRUCTURE (.*) BODY\[HEADER.FIELDS/s', $line, $m)) {
- $line2 = iil_ReadLine($fp, 1024);
- $line .= iil_MultLine($fp, $line2, true);
- }
- $result[$id]->body_structure = $m[1];
- }
-
- // the rest of the result
- preg_match('/ BODY\[HEADER.FIELDS \(.*?\)\]\s*(.*)$/s', $line, $m);
- $reslines = explode("\n", trim($m[1], '"'));
- // re-parse (see below)
- foreach ($reslines as $resln) {
- if (ord($resln[0])<=32) {
- $lines[$ln] .= (empty($lines[$ln])?'':"\n").trim($resln);
- } else {
- $lines[++$ln] = trim($resln);
- }
- }
- }
-
- /*
- Start parsing headers. The problem is, some header "lines" take up multiple lines.
- 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(iil_ReadLine($fp, 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.
- // 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:
- // if (!preg_match("/:/",$line) && preg_match("/\)$/",$line)) break;
- // however, unsure how well this would work with all imap clients.
- if (preg_match("/^\s*UID [0-9]+\)$/", $line)) {
- break;
- }
-
- // handle FLAGS reply after headers (AOL, Zimbra?)
- if (preg_match('/\s+FLAGS \((.*)\)\)$/', $line, $matches)) {
- $flags_str = $matches[1];
- break;
- }
-
- if (ord($line[0])<=32) {
- $lines[$ln] .= (empty($lines[$ln])?'':"\n").trim($line);
- } else {
- $lines[++$ln] = trim($line);
- }
- // patch from "Maksim Rubis" <siburny@hotmail.com>
- } while ($line[0] != ')' && !iil_StartsWith($line, $key, true));
-
- if (strncmp($line, $key, strlen($key))) {
- // process header, fill iilBasicHeader obj.
- // initialize
- if (is_array($headers)) {
- reset($headers);
- while (list($k, $bar) = each($headers)) {
- $headers[$k] = '';
- }
- }
-
- // create array with header field:data
- while ( list($lines_key, $str) = each($lines) ) {
- list($field, $string) = iil_SplitHeaderLine($str);
-
- $field = strtolower($field);
- $string = preg_replace('/\n\s*/', ' ', $string);
-
- switch ($field) {
- case 'date';
- if (!$IMAP_USE_INTERNAL_DATE) {
- $result[$id]->date = $string;
- $result[$id]->timestamp = iil_StrToTime($string);
- }
- break;
- case 'from':
- $result[$id]->from = $string;
- break;
- case 'to':
- $result[$id]->to = preg_replace('/undisclosed-recipients:[;,]*/', '', $string);
- break;
- case 'subject':
- $result[$id]->subject = $string;
- break;
- case 'reply-to':
- $result[$id]->replyto = $string;
- break;
- case 'cc':
- $result[$id]->cc = $string;
- break;
- case 'bcc':
- $result[$id]->bcc = $string;
- break;
- case 'content-transfer-encoding':
- $result[$id]->encoding = $string;
- break;
- case 'content-type':
- $ctype_parts = preg_split('/[; ]/', $string);
- $result[$id]->ctype = array_shift($ctype_parts);
- if (preg_match('/charset\s*=\s*"?([a-z0-9\-\.\_]+)"?/i', $string, $regs)) {
- $result[$id]->charset = $regs[1];
- }
- break;
- case 'in-reply-to':
- $result[$id]->in_reply_to = preg_replace('/[\n<>]/', '', $string);
- break;
- case 'references':
- $result[$id]->references = $string;
- break;
- case 'return-receipt-to':
- case 'disposition-notification-to':
- case 'x-confirm-reading-to':
- $result[$id]->mdn_to = $string;
- break;
- case 'message-id':
- $result[$id]->messageID = $string;
- break;
- case 'x-priority':
- if (preg_match('/^(\d+)/', $string, $matches))
- $result[$id]->priority = intval($matches[1]);
- break;
- default:
- if (strlen($field) > 2)
- $result[$id]->others[$field] = $string;
- break;
- } // end switch ()
- } // end while ()
- } else {
- $a = explode(' ', $line);
- }
-
- // process flags
- 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) {
- $flag = strtoupper($flag);
- if ($flag == 'SEEN') {
- $result[$id]->seen = true;
- } else if ($flag == 'DELETED') {
- $result[$id]->deleted = true;
- } else if ($flag == 'RECENT') {
- $result[$id]->recent = true;
- } else if ($flag == 'ANSWERED') {
- $result[$id]->answered = true;
- } else if ($flag == '$FORWARDED') {
- $result[$id]->forwarded = true;
- } else if ($flag == 'DRAFT') {
- $result[$id]->is_draft = true;
- } else if ($flag == '$MDNSENT') {
- $result[$id]->mdn_sent = true;
- } else if ($flag == 'FLAGGED') {
- $result[$id]->flagged = true;
- }
- }
- $result[$id]->flags = $flags_a;
- }
- }
- }
- } while (!iil_StartsWith($line, $key, true));
-
- return $result;
-}
-
-function iil_C_FetchHeader(&$conn, $mailbox, $id, $uidfetch=false, $bodystr=false, $add='') {
-
- $a = iil_C_FetchHeaders($conn, $mailbox, $id, $uidfetch, $bodystr, $add);
- if (is_array($a)) {
- return array_shift($a);
- }
- return false;
-}
-
-function iil_SortHeaders($a, $field, $flag) {
- if (empty($field)) {
- $field = 'uid';
- }
- $field = strtolower($field);
- if ($field == 'date' || $field == 'internaldate') {
- $field = 'timestamp';
- }
- if (empty($flag)) {
- $flag = 'ASC';
- }
-
- $flag = strtoupper($flag);
- $stripArr = ($field=='subject') ? array('Re: ','Fwd: ','Fw: ','"') : array('"');
-
- $c=count($a);
- if ($c > 0) {
- /*
- Strategy:
- First, we'll create an "index" array.
- Then, we'll use sort() on that array,
- and use that to sort the main array.
- */
-
- // create "index" array
- $index = array();
- reset($a);
- while (list($key, $val)=each($a)) {
-
- if ($field == 'timestamp') {
- $data = iil_StrToTime($val->date);
- if (!$data) {
- $data = $val->timestamp;
- }
- } else {
- $data = $val->$field;
- if (is_string($data)) {
- $data=strtoupper(str_replace($stripArr, '', $data));
- }
- }
- $index[$key]=$data;
- }
-
- // sort index
- $i = 0;
- if ($flag == 'ASC') {
- asort($index);
- } else {
- arsort($index);
- }
-
- // form new array based on index
- $result = array();
- reset($index);
- while (list($key, $val)=each($index)) {
- $result[$key]=$a[$key];
- $i++;
- }
- }
-
- return $result;
-}
-
-function iil_C_Expunge(&$conn, $mailbox, $messages=NULL) {
-
- if (iil_C_Select($conn, $mailbox)) {
- $c = 0;
- $command = $messages ? "UID EXPUNGE $messages" : "EXPUNGE";
-
- iil_PutLine($conn->fp, "exp1 $command");
- do {
- $line = iil_ReadLine($conn->fp, 100);
- if ($line[0] == '*') {
- $c++;
- }
- } while (!iil_StartsWith($line, 'exp1', true));
-
- if (iil_ParseResult($line) == 0) {
- $conn->selected = ''; //state has changed, need to reselect
- //$conn->exists-=$c;
- return $c;
- }
- $conn->error = $line;
- }
-
- return -1;
-}
-
-function iil_C_ModFlag(&$conn, $mailbox, $messages, $flag, $mod) {
- if ($mod != '+' && $mod != '-') {
- return -1;
- }
-
- $flags = $GLOBALS['IMAP_FLAGS'];
- $flag = $flags[strtoupper($flag)];
-
- if (!iil_C_Select($conn, $mailbox)) {
- return -1;
- }
-
- $c = 0;
- iil_PutLine($conn->fp, "flg UID STORE $messages " . $mod . "FLAGS (" . $flag . ")");
- do {
- $line = iil_ReadLine($conn->fp, 1000);
- if ($line[0] == '*') {
- $c++;
- }
- } while (!iil_StartsWith($line, 'flg', true));
-
- if (iil_ParseResult($line) == 0) {
- return $c;
- }
-
- $conn->error = $line;
- return -1;
-}
-
-function iil_C_Flag(&$conn, $mailbox, $messages, $flag) {
- return iil_C_ModFlag($conn, $mailbox, $messages, $flag, '+');
-}
-
-function iil_C_Unflag(&$conn, $mailbox, $messages, $flag) {
- return iil_C_ModFlag($conn, $mailbox, $messages, $flag, '-');
-}
-
-function iil_C_Delete(&$conn, $mailbox, $messages) {
- return iil_C_ModFlag($conn, $mailbox, $messages, 'DELETED', '+');
-}
-
-function iil_C_Copy(&$conn, $messages, $from, $to) {
-
- if (empty($from) || empty($to)) {
- return -1;
- }
-
- if (!iil_C_Select($conn, $from)) {
- return -1;
- }
-
- iil_PutLine($conn->fp, "cpy1 UID COPY $messages \"".iil_Escape($to)."\"");
- $line = iil_ReadReply($conn->fp);
- return iil_ParseResult($line);
-}
-
-function iil_C_CountUnseen(&$conn, $folder) {
- $index = iil_C_Search($conn, $folder, 'ALL UNSEEN');
- if (is_array($index))
- return count($index);
- return false;
-}
-
-function iil_C_UID2ID(&$conn, $folder, $uid) {
- if ($uid > 0) {
- $id_a = iil_C_Search($conn, $folder, "UID $uid");
- if (is_array($id_a) && count($id_a) == 1) {
- return $id_a[0];
- }
- }
- return false;
-}
-
-function iil_C_ID2UID(&$conn, $folder, $id) {
-
- if ($id == 0) {
- return -1;
- }
- $result = -1;
- if (iil_C_Select($conn, $folder)) {
- $key = 'fuid';
- if (iil_PutLine($conn->fp, "$key FETCH $id (UID)")) {
- do {
- $line = chop(iil_ReadLine($conn->fp, 1024));
- if (preg_match("/^\* $id FETCH \(UID (.*)\)/i", $line, $r)) {
- $result = $r[1];
- }
- } while (!iil_StartsWith($line, $key, true));
- }
- }
- return $result;
-}
-
-// Don't be tempted to change $str to pass by reference to speed this up - it will slow it down by about
-// 7 times instead :-) See comments on http://uk2.php.net/references and this article:
-// http://derickrethans.nl/files/phparch-php-variables-article.pdf
-function iil_ParseThread($str, $begin, $end, $root, $parent, $depth, &$depthmap, &$haschildren) {
- $node = array();
- if ($str[$begin] != '(') {
- $stop = $begin + strspn($str, "1234567890", $begin, $end - $begin);
- $msg = substr($str, $begin, $stop - $begin);
- if ($msg == 0)
- return $node;
- if (is_null($root))
- $root = $msg;
- $depthmap[$msg] = $depth;
- $haschildren[$msg] = false;
- if (!is_null($parent))
- $haschildren[$parent] = true;
- if ($stop + 1 < $end)
- $node[$msg] = iil_ParseThread($str, $stop + 1, $end, $root, $msg, $depth + 1, $depthmap, $haschildren);
- else
- $node[$msg] = array();
- } else {
- $off = $begin;
- while ($off < $end) {
- $start = $off;
- $off++;
- $n = 1;
- while ($n > 0) {
- $p = strpos($str, ')', $off);
- if ($p === false) {
- error_log('Mismatched brackets parsing IMAP THREAD response:');
- error_log(substr($str, ($begin < 10) ? 0 : ($begin - 10), $end - $begin + 20));
- error_log(str_repeat(' ', $off - (($begin < 10) ? 0 : ($begin - 10))));
- return $node;
- }
- $p1 = strpos($str, '(', $off);
- if ($p1 !== false && $p1 < $p) {
- $off = $p1 + 1;
- $n++;
- } else {
- $off = $p + 1;
- $n--;
- }
- }
- $node += iil_ParseThread($str, $start + 1, $off - 1, $root, $parent, $depth, $depthmap, $haschildren);
- }
- }
-
- return $node;
-}
-
-function iil_C_Thread(&$conn, $folder, $algorithm='REFERENCES', $criteria='',
- $encoding='US-ASCII') {
-
- if (!iil_C_Select($conn, $folder)) {
- $conn->error = "Couldn't select $folder";
- return false;
- }
-
- $encoding = $encoding ? trim($encoding) : 'US-ASCII';
- $algorithm = $algorithm ? trim($algorithm) : 'REFERENCES';
- $criteria = $criteria ? 'ALL '.trim($criteria) : 'ALL';
-
- if (!iil_PutLineC($conn->fp, "thrd1 THREAD $algorithm $encoding $criteria")) {
- return false;
- }
- do {
- $line = trim(iil_ReadLine($conn->fp, 10000));
- if (preg_match('/^\* THREAD/', $line)) {
- $str = trim(substr($line, 8));
- $depthmap = array();
- $haschildren = array();
- $tree = iil_ParseThread($str, 0, strlen($str), null, null, 0, $depthmap, $haschildren);
- }
- } while (!iil_StartsWith($line, 'thrd1', true));
-
- $result_code = iil_ParseResult($line);
- if ($result_code == 0) {
- return array($tree, $depthmap, $haschildren);
- }
-
- $conn->error = 'iil_C_Thread: ' . $line . "\n";
- return false;
-}
-
-function iil_C_Search(&$conn, $folder, $criteria) {
-
- if (!iil_C_Select($conn, $folder)) {
- $conn->error = "Couldn't select $folder";
- return false;
- }
-
- $data = '';
- $query = 'srch1 SEARCH ' . chop($criteria);
-
- if (!iil_PutLineC($conn->fp, $query)) {
- return false;
- }
- do {
- $line = trim(iil_ReadLine($conn->fp));
- if (iil_StartsWith($line, '* SEARCH')) {
- $data .= substr($line, 8);
- } else if (preg_match('/^[0-9 ]+$/', $line)) {
- $data .= $line;
- }
- } while (!iil_StartsWith($line, 'srch1', true));
-
- $result_code = iil_ParseResult($line);
- if ($result_code == 0) {
- return preg_split('/\s+/', $data, -1, PREG_SPLIT_NO_EMPTY);
- }
-
- $conn->error = 'iil_C_Search: ' . $line . "\n";
- return false;
-}
-
-function iil_C_Move(&$conn, $messages, $from, $to) {
-
- if (!$from || !$to) {
- return -1;
- }
-
- $r = iil_C_Copy($conn, $messages, $from, $to);
-
- if ($r==0) {
- return iil_C_Delete($conn, $from, $messages);
- }
- return $r;
-}
-
-/**
- * Gets the delimiter, for example:
- * INBOX.foo -> .
- * INBOX/foo -> /
- * INBOX\foo -> \
- *
- * @return mixed A delimiter (string), or false.
- * @param object $conn The current connection.
- * @see iil_Connect()
- */
-function iil_C_GetHierarchyDelimiter(&$conn) {
-
- global $my_prefs;
-
- if ($conn->delimiter) {
- return $conn->delimiter;
- }
- if (!empty($my_prefs['delimiter'])) {
- return ($conn->delimiter = $my_prefs['delimiter']);
- }
-
- $fp = $conn->fp;
- $delimiter = false;
-
- //try (LIST "" ""), should return delimiter (RFC2060 Sec 6.3.8)
- if (!iil_PutLine($fp, 'ghd LIST "" ""')) {
- return false;
- }
-
- do {
- $line=iil_ReadLine($fp, 500);
- if ($line[0] == '*') {
- $line = rtrim($line);
- $a=iil_ExplodeQuotedString(' ', iil_UnEscape($line));
- if ($a[0] == '*') {
- $delimiter = str_replace('"', '', $a[count($a)-2]);
- }
- }
- } while (!iil_StartsWith($line, 'ghd', true));
-
- if (strlen($delimiter)>0) {
- return $delimiter;
- }
-
- //if that fails, try namespace extension
- //try to fetch namespace data
- iil_PutLine($conn->fp, "ns1 NAMESPACE");
- do {
- $line = iil_ReadLine($conn->fp, 1024);
- if (iil_StartsWith($line, '* NAMESPACE')) {
- $i = 0;
- $line = iil_UnEscape($line);
- $data = iil_ParseNamespace2(substr($line,11), $i, 0, 0);
- }
- } while (!iil_StartsWith($line, 'ns1', true));
-
- 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)) {
- return false;
- }
-
- //get first element
- $first_userspace = $user_space_data[0];
- if (!is_array($first_userspace)) {
- return false;
- }
-
- //extract delimiter
- $delimiter = $first_userspace[1];
-
- return $delimiter;
-}
-
-function iil_C_ListMailboxes(&$conn, $ref, $mailbox) {
-
- $fp = $conn->fp;
-
- if (empty($mailbox)) {
- $mailbox = '*';
- }
-
- if (empty($ref) && $conn->rootdir) {
- $ref = $conn->rootdir;
- }
-
- // send command
- if (!iil_PutLine($fp, "lmb LIST \"".$ref."\" \"".iil_Escape($mailbox)."\"")) {
- return false;
- }
-
- $i = 0;
- // get folder list
- do {
- $line = iil_ReadLine($fp, 500);
- $line = iil_MultLine($fp, $line, true);
-
- $a = explode(' ', $line);
- if (($line[0] == '*') && ($a[1] == 'LIST')) {
- $line = rtrim($line);
- // split one line
- $a = iil_ExplodeQuotedString(' ', $line);
- // last string is folder name
- $folders[$i] = preg_replace(array('/^"/', '/"$/'), '', iil_UnEscape($a[count($a)-1]));
-
- // second from last is delimiter
- $delim = trim($a[count($a)-2], '"');
- // is it a container?
- $i++;
- }
- } while (!iil_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 (iil_ParseResult($line) == 0) {
- return array('INBOX');
- } else {
- $conn->error = $line;
- return false;
- }
-}
-
-function iil_C_ListSubscribed(&$conn, $ref, $mailbox) {
-
- $fp = $conn->fp;
- if (empty($mailbox)) {
- $mailbox = '*';
- }
- if (empty($ref) && $conn->rootdir) {
- $ref = $conn->rootdir;
- }
- $folders = array();
-
- // send command
- if (!iil_PutLine($fp, 'lsb LSUB "' . $ref . '" "' . iil_Escape($mailbox).'"')) {
- $conn->error = "Couldn't send LSUB command\n";
- return false;
- }
-
- $i = 0;
-
- // get folder list
- do {
- $line = iil_ReadLine($fp, 500);
- $line = iil_MultLine($fp, $line, true);
- $a = explode(' ', $line);
-
- if (($line[0] == '*') && ($a[1] == 'LSUB' || $a[1] == 'LIST')) {
- $line = rtrim($line);
-
- // split one line
- $a = iil_ExplodeQuotedString(' ', $line);
- // last string is folder name
- $folder = preg_replace(array('/^"/', '/"$/'), '', iil_UnEscape($a[count($a)-1]));
-
- // @TODO: do we need this check???
- if (!in_array($folder, $folders)) {
- $folders[$i] = $folder;
- }
-
- // second from last is delimiter
- $delim = trim($a[count($a)-2], '"');
-
- // is it a container?
- $i++;
- }
- } while (!iil_StartsWith($line, 'lsb', 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;
- }
- $conn->error = $line;
- return false;
-}
-
-function iil_C_Subscribe(&$conn, $folder) {
- $fp = $conn->fp;
-
- $query = 'sub1 SUBSCRIBE "' . iil_Escape($folder). '"';
- iil_PutLine($fp, $query);
-
- $line = trim(iil_ReadLine($fp, 512));
- return (iil_ParseResult($line) == 0);
-}
-
-function iil_C_UnSubscribe(&$conn, $folder) {
- $fp = $conn->fp;
-
- $query = 'usub1 UNSUBSCRIBE "' . iil_Escape($folder) . '"';
- iil_PutLine($fp, $query);
-
- $line = trim(iil_ReadLine($fp, 512));
- return (iil_ParseResult($line) == 0);
-}
-
-function iil_C_FetchMIMEHeaders(&$conn, $mailbox, $id, $parts, $mime=true) {
-
- $fp = $conn->fp;
-
- if (!iil_C_Select($conn, $mailbox)) {
- return false;
- }
-
- $result = false;
- $parts = (array) $parts;
- $key = 'fmh0';
- $peeks = '';
- $idx = 0;
- $type = $mime ? 'MIME' : 'HEADER';
-
- // format request
- foreach($parts as $part)
- $peeks[] = "BODY.PEEK[$part.$type]";
-
- $request = "$key FETCH $id (" . implode(' ', $peeks) . ')';
-
- // send request
- if (!iil_PutLine($fp, $request)) {
- return false;
- }
-
- do {
- $line = iil_ReadLine($fp, 1000);
- $line = iil_MultLine($fp, $line);
-
- if (preg_match('/BODY\[([0-9\.]+)\.'.$type.'\]/', $line, $matches)) {
- $idx = $matches[1];
- $result[$idx] = preg_replace('/^(\* '.$id.' FETCH \()?\s*BODY\['.$idx.'\.'.$type.'\]\s+/', '', $line);
- $result[$idx] = trim($result[$idx], '"');
- $result[$idx] = rtrim($result[$idx], "\t\r\n\0\x0B");
- }
- } while (!iil_StartsWith($line, $key, true));
-
- return $result;
-}
-
-function iil_C_FetchPartHeader(&$conn, $mailbox, $id, $is_uid=false, $part=NULL) {
-
- $part = empty($part) ? 'HEADER' : $part.'.MIME';
-
- return iil_C_HandlePartBody($conn, $mailbox, $id, $is_uid, $part);
-}
-
-function iil_C_HandlePartBody(&$conn, $mailbox, $id, $is_uid=false, $part='', $encoding=NULL, $print=NULL, $file=NULL) {
-
- $fp = $conn->fp;
- $result = false;
-
- switch ($encoding) {
- case 'base64':
- $mode = 1;
- break;
- case 'quoted-printable':
- $mode = 2;
- break;
- case 'x-uuencode':
- case 'x-uue':
- case 'uue':
- case 'uuencode':
- $mode = 3;
- break;
- default:
- $mode = 0;
- }
-
- if (iil_C_Select($conn, $mailbox)) {
- $reply_key = '* ' . $id;
-
- // format request
- $key = 'ftch0';
- $request = $key . ($is_uid ? ' UID' : '') . " FETCH $id (BODY.PEEK[$part])";
- // send request
- if (!iil_PutLine($fp, $request)) {
- return false;
- }
-
- // receive reply line
- do {
- $line = chop(iil_ReadLine($fp, 1000));
- $a = explode(' ', $line);
- } while (!($end = iil_StartsWith($line, $key, true)) && $a[2] != 'FETCH');
- $len = strlen($line);
-
- // handle empty "* X FETCH ()" response
- if ($line[$len-1] == ')' && $line[$len-2] != '(') {
- // one line response, get everything between first and last quotes
- if (substr($line, -4, 3) == 'NIL') {
- // NIL response
- $result = '';
- } else {
- $from = strpos($line, '"') + 1;
- $to = strrpos($line, '"');
- $len = $to - $from;
- $result = substr($line, $from, $len);
- }
-
- if ($mode == 1)
- $result = base64_decode($result);
- else if ($mode == 2)
- $result = quoted_printable_decode($result);
- else if ($mode == 3)
- $result = convert_uudecode($result);
-
- } else if ($line[$len-1] == '}') {
- //multi-line request, find sizes of content and receive that many bytes
- $from = strpos($line, '{') + 1;
- $to = strrpos($line, '}');
- $len = $to - $from;
- $sizeStr = substr($line, $from, $len);
- $bytes = (int)$sizeStr;
- $prev = '';
-
- while ($bytes > 0) {
- $line = iil_ReadLine($fp, 1024);
- $len = strlen($line);
-
- if ($len > $bytes) {
- $line = substr($line, 0, $bytes);
- $len = strlen($line);
- }
- $bytes -= $len;
-
- if ($mode == 1) {
- $line = rtrim($line, "\t\r\n\0\x0B");
- // create chunks with proper length for base64 decoding
- $line = $prev.$line;
- $length = strlen($line);
- if ($length % 4) {
- $length = floor($length / 4) * 4;
- $prev = substr($line, $length);
- $line = substr($line, 0, $length);
- }
- else
- $prev = '';
-
- if ($file)
- fwrite($file, base64_decode($line));
- else if ($print)
- echo base64_decode($line);
- else
- $result .= base64_decode($line);
- } else if ($mode == 2) {
- $line = rtrim($line, "\t\r\0\x0B");
- if ($file)
- fwrite($file, quoted_printable_decode($line));
- else if ($print)
- echo quoted_printable_decode($line);
- else
- $result .= quoted_printable_decode($line);
- } else if ($mode == 3) {
- $line = rtrim($line, "\t\r\n\0\x0B");
- if ($line == 'end' || preg_match('/^begin\s+[0-7]+\s+.+$/', $line))
- continue;
- if ($file)
- fwrite($file, convert_uudecode($line));
- else if ($print)
- echo convert_uudecode($line);
- else
- $result .= convert_uudecode($line);
- } else {
- $line = rtrim($line, "\t\r\n\0\x0B");
- if ($file)
- fwrite($file, $line . "\n");
- else if ($print)
- echo $line . "\n";
- else
- $result .= $line . "\n";
- }
- }
- }
- // read in anything up until last line
- if (!$end)
- do {
- $line = iil_ReadLine($fp, 1024);
- } while (!iil_StartsWith($line, $key, true));
-
- if ($result) {
- if ($file) {
- fwrite($file, $result);
- } else if ($print) {
- echo $result;
- } else
- return $result;
-
- return true;
- }
- }
-
- return false;
-}
-
-function iil_C_CreateFolder(&$conn, $folder) {
- $fp = $conn->fp;
- if (iil_PutLine($fp, 'c CREATE "' . iil_Escape($folder) . '"')) {
- do {
- $line=iil_ReadLine($fp, 300);
- } while (!iil_StartsWith($line, 'c ', true));
- return (iil_ParseResult($line) == 0);
- }
- return false;
-}
-
-function iil_C_RenameFolder(&$conn, $from, $to) {
- $fp = $conn->fp;
- if (iil_PutLine($fp, 'r RENAME "' . iil_Escape($from) . '" "' . iil_Escape($to) . '"')) {
- do {
- $line = iil_ReadLine($fp, 300);
- } while (!iil_StartsWith($line, 'r ', true));
- return (iil_ParseResult($line) == 0);
- }
- return false;
-}
-
-function iil_C_DeleteFolder(&$conn, $folder) {
- $fp = $conn->fp;
- if (iil_PutLine($fp, 'd DELETE "' . iil_Escape($folder). '"')) {
- do {
- $line=iil_ReadLine($fp, 300);
- } while (!iil_StartsWith($line, 'd ', true));
- return (iil_ParseResult($line) == 0);
- }
- return false;
-}
-
-function iil_C_Append(&$conn, $folder, &$message) {
- if (!$folder) {
- return false;
- }
- $fp = $conn->fp;
-
- $message = str_replace("\r", '', $message);
- $message = str_replace("\n", "\r\n", $message);
-
- $len = strlen($message);
- if (!$len) {
- return false;
- }
-
- $request = 'a APPEND "' . iil_Escape($folder) .'" (\\Seen) {' . $len . '}';
-
- if (iil_PutLine($fp, $request)) {
- $line = iil_ReadLine($fp, 512);
-
- if ($line[0] != '+') {
- // $errornum = iil_ParseResult($line);
- $conn->error .= "Cannot write to folder: $line\n";
- return false;
- }
-
- iil_PutLine($fp, $message);
-
- do {
- $line = iil_ReadLine($fp);
- } while (!iil_StartsWith($line, 'a ', true));
-
- $result = (iil_ParseResult($line) == 0);
- if (!$result) {
- $conn->error .= $line . "\n";
- }
- return $result;
- }
-
- $conn->error .= "Couldn't send command \"$request\"\n";
- return false;
-}
-
-function iil_C_AppendFromFile(&$conn, $folder, $path, $headers=null, $separator="\n\n") {
- if (!$folder) {
- return false;
- }
-
- //open message file
- $in_fp = false;
- if (file_exists(realpath($path))) {
- $in_fp = fopen($path, 'r');
- }
- if (!$in_fp) {
- $conn->error .= "Couldn't open $path for reading\n";
- return false;
- }
-
- $fp = $conn->fp;
- $len = filesize($path);
- if (!$len) {
- return false;
- }
-
- if ($headers) {
- $headers = preg_replace('/[\r\n]+$/', '', $headers);
- $len += strlen($headers) + strlen($separator);
- }
-
- //send APPEND command
- $request = 'a APPEND "' . iil_Escape($folder) . '" (\\Seen) {' . $len . '}';
- if (iil_PutLine($fp, $request)) {
- $line = iil_ReadLine($fp, 512);
-
- if ($line[0] != '+') {
- //$errornum = iil_ParseResult($line);
- $conn->error .= "Cannot write to folder: $line\n";
- return false;
- }
-
- // send headers with body separator
- if ($headers) {
- iil_PutLine($fp, $headers . $separator, false);
- }
-
- // send file
- while (!feof($in_fp)) {
- $buffer = fgets($in_fp, 4096);
- iil_PutLine($fp, $buffer, false);
- }
- fclose($in_fp);
-
- iil_PutLine($fp, ''); // \r\n
-
- // read response
- do {
- $line = iil_ReadLine($fp);
- } while (!iil_StartsWith($line, 'a ', true));
-
- $result = (iil_ParseResult($line) == 0);
- if (!$result) {
- $conn->error .= $line . "\n";
- }
-
- return $result;
- }
-
- $conn->error .= "Couldn't send command \"$request\"\n";
- return false;
-}
-
-function iil_C_FetchStructureString(&$conn, $folder, $id, $is_uid=false) {
- $fp = $conn->fp;
- $result = false;
-
- if (iil_C_Select($conn, $folder)) {
- $key = 'F1247';
-
- if (iil_PutLine($fp, $key . ($is_uid ? ' UID' : '') ." FETCH $id (BODYSTRUCTURE)")) {
- do {
- $line = iil_ReadLine($fp, 5000);
- $line = iil_MultLine($fp, $line, true);
- if (!preg_match("/^$key/", $line))
- $result .= $line;
- } while (!iil_StartsWith($line, $key, true));
-
- $result = trim(substr($result, strpos($result, 'BODYSTRUCTURE')+13, -1));
- }
- }
- return $result;
-}
-
-function iil_C_GetQuota(&$conn) {
-/*
- * GETQUOTAROOT "INBOX"
- * QUOTAROOT INBOX user/rchijiiwa1
- * QUOTA user/rchijiiwa1 (STORAGE 654 9765)
- * OK Completed
- */
- $fp = $conn->fp;
- $result = false;
- $quota_lines = array();
-
- // get line(s) containing quota info
- if (iil_PutLine($fp, 'QUOT1 GETQUOTAROOT "INBOX"')) {
- do {
- $line=chop(iil_ReadLine($fp, 5000));
- if (iil_StartsWith($line, '* QUOTA ')) {
- $quota_lines[] = $line;
- }
- } while (!iil_StartsWith($line, 'QUOT1', 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;
-
- // return lowest available space from all quotas
- if ($free < $min_free) {
- $min_free = $free;
- $result['used'] = $used;
- $result['total'] = $total;
- $result['percent'] = min(100, round(($used/max(1,$total))*100));
- $result['free'] = 100 - $result['percent'];
- }
- }
- return $result;
-}
-
-function iil_C_ClearFolder(&$conn, $folder) {
- $num_in_trash = iil_C_CountMessages($conn, $folder);
- if ($num_in_trash > 0) {
- iil_C_Delete($conn, $folder, '1:*');
- }
- return (iil_C_Expunge($conn, $folder) >= 0);
-}
-
-?>