From 32ca1f9fc8a78e092565b51cc97faa724bb4e6cf Mon Sep 17 00:00:00 2001
From: alecpl <alec@alec.pl>
Date: Sat, 30 May 2009 05:09:57 -0400
Subject: [PATCH] - css fixes (#1485869)

---
 program/lib/imap.inc | 1262 +++++++++++++++++++++++++++++---------------------------
 1 files changed, 650 insertions(+), 612 deletions(-)

diff --git a/program/lib/imap.inc b/program/lib/imap.inc
index c10c901..2954ecf 100644
--- a/program/lib/imap.inc
+++ b/program/lib/imap.inc
@@ -52,10 +52,8 @@
 		- $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>
-		- RFC3501 [7.1] don't call CAPABILITY if was returned in server 
-		  optional resposne in iil_Connect()
 		- trim(chop()) replaced by trim()
-		- added iil_Escape() with support for " and \ in folder names
+		- 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
@@ -63,6 +61,29 @@
 		- 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 
 
 ********************************************************/
 
@@ -73,9 +94,6 @@
  * @todo Refactor code.
  * @todo Replace echo-debugging (make it adhere to config setting and log)
  */
-
-// changed path to work within roundcube webmail
-include_once 'lib/icl_commons.inc';
 
 
 if (!isset($IMAP_USE_HEADER_DATE) || !$IMAP_USE_HEADER_DATE) {
@@ -99,7 +117,9 @@
     'DRAFT'    => '\\Draft',
     'FLAGGED'  => '\\Flagged',
     'FORWARDED' => '$Forwarded',
-    'MDNSENT'  => '$MDNSent');
+    'MDNSENT'  => '$MDNSent',
+    '*'        => '\\*',
+);
 
 $iil_error;
 $iil_errornum;
@@ -116,15 +136,13 @@
 	var $selected;
 	var $message;
 	var $host;
-	var $cache;
-	var $uid_cache;
-	var $do_cache;
 	var $exists;
 	var $recent;
 	var $rootdir;
 	var $delimiter;
 	var $capability = array();
 	var $permanentflags = array();
+	var $capability_readed = false;
 }
 
 /**
@@ -149,6 +167,7 @@
 	var $flags;
 	var $timestamp;
 	var $f;
+	var $body_structure;
 	var $internaldate;
 	var $references;
 	var $priority;
@@ -162,6 +181,7 @@
 	var $forwarded = false;
 	var $junk = false;
 	var $flagged = false;
+	var $others = array();
 }
 
 /**
@@ -185,11 +205,34 @@
 }
 
 function iil_PutLine($fp, $string, $endln=true) {
-//	console('C: '. $string);
-	return fputs($fp, $string . ($endln ? "\r\n" : ''));
+//      console('C: '. rtrim($string));
+        return fputs($fp, $string . ($endln ? "\r\n" : ''));
 }
 
-function iil_ReadLine($fp, $size) {
+// 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) {
 	$line = '';
 
 	if (!$fp) {
@@ -212,9 +255,9 @@
 	return $line;
 }
 
-function iil_MultLine($fp, $line) {
+function iil_MultLine($fp, $line, $escape=false) {
 	$line = chop($line);
-	if (ereg('\{[0-9]+\}$', $line)) {
+	if (preg_match('/\{[0-9]+\}$/', $line)) {
 		$out = '';
         
 		preg_match_all('/(.*)\{([0-9]+)\}$/', $line, $a);
@@ -223,7 +266,8 @@
 			$line = iil_ReadBytes($fp, $bytes); 
 			$out .= $line;
 		}
-		$line = $a[1][0] . "\"$out\"";
+
+		$line = $a[1][0] . '"' . ($escape ? iil_Escape($out) : $out) . '"';
 //		console('[...] '. $out);
 	}
 	return $line;
@@ -252,7 +296,7 @@
 }
 
 function iil_ParseResult($string) {
-	$a=explode(' ', $string);
+	$a = explode(' ', $string);
 	if (count($a) > 2) {
 		if (strcasecmp($a[1], 'OK') == 0) {
 			return 0;
@@ -260,13 +304,15 @@
 			return -1;
 		} else if (strcasecmp($a[1], 'BAD') == 0) {
 			return -2;
+		} else if (strcasecmp($a[1], 'BYE') == 0) {
+			return -3;
     		}
 	}
-	return -3;
+	return -4;
 }
 
-// check if $string starts with $match
-function iil_StartsWith($string, $match) {
+// check if $string starts with $match (or * BYE/BAD)
+function iil_StartsWith($string, $match, $error=false) {
 	$len = strlen($match);
 	if ($len == 0) {
 		return false;
@@ -274,10 +320,13 @@
 	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) {
+function iil_StartsWithI($string, $match, $bye=false) {
 	$len = strlen($match);
 	if ($len == 0) {
 		return false;
@@ -285,12 +334,61 @@
 	if (strncasecmp($string, $match, $len) == 0) {
 		return true;
 	}
+	if ($bye && strncmp($string, '* BYE ', 6) == 0) {
+		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) {
@@ -321,15 +419,20 @@
     $line = iil_ReadLine($conn->fp, 1024);
     
     // process result
-    if (iil_ParseResult($line) == 0) {
+    $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  = -2;
-    return false;
+    $conn->errorNum  = $result;
+
+    return $result;
 }
 
 function iil_C_Login(&$conn, $user, $password) {
@@ -341,20 +444,22 @@
         if ($line === false) {
             break;
         }
-    } while (!iil_StartsWith($line, "a001 "));
-    $a = explode(' ', $line);
-    if (strcmp($a[1], 'OK') == 0) {
-        $result          = $conn->fp;
+    } while (!iil_StartsWith($line, 'a001 ', true));
+    
+    // process result
+    $result = iil_ParseResult($line);
+
+    if ($result == 0) {
         $conn->error    .= '';
         $conn->errorNum  = 0;
-        return $result;
+        return $conn->fp;
     }
-    $result = false;
+
     fclose($conn->fp);
     
     $conn->error    .= 'Authentication for ' . $user . ' failed (LOGIN): "';
     $conn->error    .= htmlspecialchars($line)."\"";
-    $conn->errorNum  = -2;
+    $conn->errorNum  = $result;
 
     return $result;
 }
@@ -396,13 +501,14 @@
 
 function iil_C_NameSpace(&$conn) {
 	global $my_prefs;
-	
-	if (!in_array('NAMESPACE', $conn->capability)) {
-	    return false;
+
+	if (isset($my_prefs['rootdir']) && is_string($my_prefs['rootdir'])) {
+    		$conn->rootdir = $my_prefs['rootdir'];
+		return true;
 	}
-    
-	if ($my_prefs["rootdir"]) {
-	    return true;
+	
+	if (!iil_C_GetCapability($conn, 'NAMESPACE')) {
+	    return false;
 	}
     
 	iil_PutLine($conn->fp, "ns1 NAMESPACE");
@@ -410,9 +516,10 @@
 		$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"));
+	} while (!iil_StartsWith($line, 'ns1', true));
 	
 	if (!is_array($data)) {
 	    return false;
@@ -430,49 +537,47 @@
     
 	$conn->rootdir       = $first_userspace[0];
 	$conn->delimiter     = $first_userspace[1];
-	$my_prefs["rootdir"] = substr($conn->rootdir, 0, -1);
+	$my_prefs['rootdir'] = substr($conn->rootdir, 0, -1);
+	$my_prefs['delimiter'] = $conn->delimiter;
 	
 	return true;
 }
 
-function iil_Connect($host, $user, $password) {	
+function iil_Connect($host, $user, $password, $options=null) {	
 	global $iil_error, $iil_errornum;
 	global $ICL_SSL, $ICL_PORT;
-	global $IMAP_NO_CACHE;
 	global $my_prefs, $IMAP_USE_INTERNAL_DATE;
 	
 	$iil_error = '';
 	$iil_errornum = 0;
-	
-	//strip slashes
-	// $user = stripslashes($user);
-	// $password = stripslashes($password);
-	
-	//set auth method
-	$auth_method = 'plain';
-	if (func_num_args() >= 4) {
-		$auth_array = func_get_arg(3);
-		if (is_array($auth_array)) {
-			$auth_method = $auth_array['imap'];
-    		}
-		if (empty($auth_method)) {
-        		$auth_method = "plain";
-    		}
+
+	// set some imap options
+	if (is_array($options)) {
+		foreach($options as $optkey => $optval) {
+			if ($optkey == 'imap') {
+				$auth_method = $optval;
+			} else if ($optkey == 'rootdir') {
+    				$my_prefs['rootdir'] = $optval;
+			} else if ($optkey == 'delimiter') {
+    				$my_prefs['delimiter'] = $optval;
+			}
+		}
 	}
+
+	if (empty($auth_method))
+    		$auth_method = 'check';
+		
 	$message = "INITIAL: $auth_method\n";
 		
 	$result = false;
 	
-	//initialize connection
+	// initialize connection
 	$conn              = new iilConnection;
 	$conn->error       = '';
 	$conn->errorNum    = 0;
 	$conn->selected    = '';
 	$conn->user        = $user;
 	$conn->host        = $host;
-	$conn->cache       = array();
-	$conn->do_cache    = (function_exists("cache_write")&&!$IMAP_NO_CACHE);
-	$conn->cache_dirty = array();
 	
 	if ($my_prefs['sort_field'] == 'INTERNALDATE') {
 		$IMAP_USE_INTERNAL_DATE = true;
@@ -483,71 +588,88 @@
 	
 	//check input
 	if (empty($host)) {
-		$iil_error .= "Invalid host\n";
-	}
-	if (empty($user)) {
-		$iil_error .= "Invalid user\n";
-	}
-	if (empty($password)) {
-		$iil_error .= "Invalid password\n";
-	}
-	if (!empty($iil_error)) {
+		$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) {
+	if ($ICL_SSL && $ICL_SSL != 'tls') {
 		$host = $ICL_SSL . '://' . $host;
 	}
-	
-	//open socket connection
+
 	$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 = -1;
+    		$iil_errornum = -2;
 		return false;
 	}
 
-	$iil_error .= "Socket connection established\r\n";
-	$line       = iil_ReadLine($conn->fp, 1024);
+	stream_set_timeout($conn->fp, 10);
+	$line = stream_get_line($conn->fp, 8192, "\r\n");
 
+	// 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
-	// commented out, because it's not working always as should
-//	if (preg_match('/\[CAPABILITY ([^]]+)\]/i', $line, $matches)) {
-//		$conn->capability = explode(' ', $matches[1]);
-//	} else {
-		iil_PutLine($conn->fp, "cp01 CAPABILITY");
-		do {
-			$line = trim(iil_ReadLine($conn->fp, 1024));
+	if (preg_match('/\[CAPABILITY ([^]]+)\]/i', $line, $matches)) {
+		$conn->capability = explode(' ', strtoupper($matches[1]));
+	}
 
-			$conn->message .= "$line\n";
+	$conn->message .= $line;
 
-			$a = explode(' ', $line);
-			if ($line[0] == '*') {
-				while (list($k, $w) = each($a)) {
-					if ($w != '*' && $w != 'CAPABILITY')
-    					$conn->capability[] = $w;
-				}
+	// 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;
 			}
-		} while ($a[0] != 'cp01');
-//	}
+			
+			// Now we're authenticated, capabilities need to be reread
+			iil_C_ClearCapability($conn);
+        	}
+	}
 
 	if (strcasecmp($auth_method, "check") == 0) {
 		//check for supported auth methods
-		
-		//default to plain text auth
-		$auth_method = 'plain';
-			
-		//check for CRAM-MD5
-		foreach ($conn->capability as $c)
-			if (strcasecmp($c, 'AUTH=CRAM_MD5') == 0 ||
-				strcasecmp($c, 'AUTH=CRAM-MD5') == 0) {
-				$auth_method = 'auth';
-				break;
-			}
+		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 (strcasecmp($auth_method, 'auth') == 0) {
@@ -564,7 +686,13 @@
 
 			//got a challenge string, try CRAM-5
 			$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;
+			}
 			$conn->message .= "Tried CRAM-MD5: $result \n";
 		} else {
 			$conn->message .='No challenge ('.htmlspecialchars($line)."), try plain\n";
@@ -575,12 +703,12 @@
 	if ((!$result)||(strcasecmp($auth, "plain") == 0)) {
 		//do plain text auth
 		$result = iil_C_Login($conn, $user, $password);
-		$conn->message.="Tried PLAIN: $result \n";
+		$conn->message .= "Tried PLAIN: $result \n";
 	}
 		
 	$conn->message .= $auth;
 			
-	if ($result) {
+	if (!is_int($result)) {
 		iil_C_Namespace($conn);
 		return $conn;
 	} else {
@@ -591,7 +719,6 @@
 }
 
 function iil_Close(&$conn) {
-	iil_C_WriteCache($conn);
 	if (iil_PutLine($conn->fp, "I LOGOUT")) {
 		fgets($conn->fp, 1024);
 		fclose($conn->fp);
@@ -599,100 +726,21 @@
 	}
 }
 
-function iil_ClearCache($user, $host) {
-}
-
-function iil_C_WriteCache(&$conn) {
-	//echo "<!-- doing iil_C_WriteCache //-->\n";
-	if (!$conn->do_cache) return false;
-	
-	if (is_array($conn->cache)) {
-		while (list($folder,$data)=each($conn->cache)) {
-			if ($folder && is_array($data) && $conn->cache_dirty[$folder]) {
-				$key = $folder.".imap";
-				$result = cache_write($conn->user, $conn->host, $key, $data, true);
-				//echo "<!-- writing $key $data: $result //-->\n";
-			}
-		}
-	}
-}
-
-function iil_C_EnableCache(&$conn) {
-	$conn->do_cache = true;
-}
-
-function iil_C_DisableCache(&$conn) {
-	$conn->do_cache = false;
-}
-
-function iil_C_LoadCache(&$conn, $folder) {
-	if (!$conn->do_cache) {
-	    return false;
-	}
-    
-	$key = $folder.'.imap';
-	if (!is_array($conn->cache[$folder])) {
-		$conn->cache[$folder]       = cache_read($conn->user, $conn->host, $key);
-		$conn->cache_dirty[$folder] = false;
-	}
-}
-
-function iil_C_ExpireCachedItems(&$conn, $folder, $message_set) {
-	
-	if (!$conn->do_cache) {
-		return;	//caching disabled
-	}
-	if (!is_array($conn->cache[$folder])) {
-    		return;	//cache not initialized|empty
-	}
-	if (count($conn->cache[$folder]) == 0) {
-    		return;	//cache not initialized|empty
-	}
-    
-	$uids = iil_C_FetchHeaderIndex($conn, $folder, $message_set, 'UID');
-	$num_removed = 0;
-	if (is_array($uids)) {
-		//echo "<!-- unsetting: ".implode(",",$uids)." //-->\n";
-		while (list($n,$uid)=each($uids)) {
-			unset($conn->cache[$folder][$uid]);
-			//$conn->cache[$folder][$uid] = false;
-			//$num_removed++;
-		}
-		$conn->cache_dirty[$folder] = true;
-
-		//echo '<!--'."\n";
-		//print_r($conn->cache);
-		//echo "\n".'//-->'."\n";
-	} else {
-		echo "<!-- failed to get uids: $message_set //-->\n";
-	}
-	
-	/*
-	if ($num_removed>0) {
-		$new_cache;
-		reset($conn->cache[$folder]);
-		while (list($uid,$item)=each($conn->cache[$folder])) {
-			if ($item) $new_cache[$uid] = $conn->cache[$folder][$uid];
-		}
-		$conn->cache[$folder] = $new_cache;
-	}
-	*/
-}
-
 function iil_ExplodeQuotedString($delimiter, $string) {
-	$quotes=explode('"', $string);
-	while ( list($key, $val) = each($quotes)) {
-		if (($key % 2) == 1) {
-			$quotes[$key] = str_replace($delimiter, "_!@!_", $quotes[$key]);
-    		}
+	$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;
+		}
 	}
-	$string=implode('"', $quotes);
-	
-	$result=explode($delimiter, $string);
-	while ( list($key, $val) = each($result) ) {
-		$result[$key] = str_replace('_!@!_', $delimiter, $result[$key]);
-	}
-    
+
+	$result[] = substr($string, $p);
 	return $result;
 }
 
@@ -710,8 +758,8 @@
 			$a=explode(' ', $line);
 			if (($a[0] == '*') && (strcasecmp($a[2], 'RECENT') == 0)) {
 			    $result = (int) $a[1];
-            }
-		} while (!iil_StartsWith($a[0], 'a002'));
+        		}
+		} while (!iil_StartsWith($a[0], 'a002', true));
 
 		iil_PutLine($fp, "a003 LOGOUT");
 		fclose($fp);
@@ -731,8 +779,6 @@
 		return true;
 	}
     
-	iil_C_LoadCache($conn, $mailbox);
-	
 	if (iil_PutLine($conn->fp, "sel1 SELECT \"".iil_Escape($mailbox).'"')) {
 		do {
 			$line = chop(iil_ReadLine($conn->fp, 300));
@@ -748,7 +794,7 @@
 			else if (preg_match('/\[?PERMANENTFLAGS\s+\(([^\)]+)\)\]/U', $line, $match)) {
 				$conn->permanentflags = explode(' ', $match[1]);
 			}
-		} while (!iil_StartsWith($line, 'sel1'));
+		} while (!iil_StartsWith($line, 'sel1', true));
 
 		$a = explode(' ', $line);
 
@@ -774,7 +820,7 @@
 
 function iil_C_CountMessages(&$conn, $mailbox, $refresh = false) {
 	if ($refresh) {
-		$conn->selected= '';
+		$conn->selected = '';
 	}
 	
 	iil_C_Select($conn, $mailbox);
@@ -796,7 +842,7 @@
 
 function iil_StrToTime($str) {
 	$IMAP_MONTHS    = $GLOBALS['IMAP_MONTHS'];
-	$IMAP_SERVER_TZ = $GLOBALS['IMAP_SERVER_TR'];
+	$IMAP_SERVER_TZ = $GLOBALS['IMAP_SERVER_TZ'];
 		
 	if ($str) {
     	    $time1 = strtotime($str);
@@ -838,10 +884,7 @@
 
 function iil_C_Sort(&$conn, $mailbox, $field, $add='', $is_uid=FALSE,
     $encoding = 'US-ASCII') {
-	/*  Do "SELECT" command */
-	if (!iil_C_Select($conn, $mailbox)) {
-	    return false;
-	}
+
 	$field = strtoupper($field);
 	if ($field == 'INTERNALDATE') {
 	    $field = 'ARRIVAL';
@@ -853,6 +896,11 @@
 	if (!$fields[$field]) {
 	    return false;
 	}
+
+	/*  Do "SELECT" command */
+	if (!iil_C_Select($conn, $mailbox)) {
+	    return false;
+	}
     
 	$is_uid = $is_uid ? 'UID ' : '';
 	
@@ -860,24 +908,27 @@
 	    $add = " $add";
 	}
 
-	$fp       = $conn->fp;
 	$command  = 's ' . $is_uid . 'SORT (' . $field . ') ';
 	$command .= $encoding . ' ALL' . $add;
 	$line     = $data = '';
 	
-	if (!iil_PutLine($fp, $command)) {
+	if (!iil_PutLineC($conn->fp, $command)) {
 	    return false;
 	}
 	do {
-		$line = chop(iil_ReadLine($fp, 1024));
+		$line = chop(iil_ReadLine($conn->fp, 1024));
 		if (iil_StartsWith($line, '* SORT')) {
-			$data .= ($data?' ':'') . substr($line, 7);
-    		}
-	} while ($line[0]!='s');
+			$data .= ($data ? ' ' : '') . substr($line, 7);
+    		} else if (preg_match('/^[0-9 ]+$/', $line)) {
+			$data .= $line;
+		}
+	} while (!iil_StartsWith($line, 's ', true));
 	
-	if (empty($data)) {
-		$conn->error = $line;
-		return false;
+	$result_code = iil_ParseResult($line);
+	
+	if ($result_code != 0) {
+                $conn->error = 'iil_C_Sort: ' . $line . "\n";
+                return false;
 	}
 	
 	$out = explode(' ',$data);
@@ -995,7 +1046,7 @@
 				//one line response, not expected so ignore				
 			}
 			*/
-		} while (!iil_StartsWith($line, $key));
+		} while (!iil_StartsWith($line, $key, true));
 
 	}else if ($mode == 6) {
 
@@ -1026,7 +1077,7 @@
 			} else {
 				$a = explode(' ', $line);
 			}
-		} while (!iil_StartsWith($a[0], $key));
+		} while (!iil_StartsWith($a[0], $key, true));
 	} else {
 		if ($mode >= 3) {
 		    $field_name = 'FLAGS';
@@ -1068,7 +1119,7 @@
 					$result[$id] = (strpos($haystack, $index_field) > 0 ? "F" : "N");
 				}
 			}
-		} while (!iil_StartsWith($line, $key));
+		} while (!iil_StartsWith($line, $key, true));
 	}
 
 	//check number of elements...
@@ -1158,50 +1209,7 @@
 	}
 	$message_set = '1' . ($num>1?':' . $num:'');
 	
-	//if cache not enabled, just call iil_C_FetchHeaderIndex on 'UID' field
-	if (!$conn->do_cache)
-		return iil_C_FetchHeaderIndex($conn, $mailbox, $message_set, 'UID');
-
-	//otherwise, let's check cache first
-	$key        = $mailbox.'.uids';
-	$cache_good = true;
-	if ($conn->uid_cache) {
-	    $data = $conn->uid_cache;
-	} else {
-	    $data = cache_read($conn->user, $conn->host, $key);
-	}
-    
-	//was anything cached at all?
-	if ($data === false) {
-	    $cache_good = -1;
-	}
-    
-	//make sure number of messages were the same
-	if ($cache_good > 0 && $data['n'] != $num) {
-	    $cache_good = -2;
-	}
-    
-	//if everything's okay so far...
-	if ($cache_good > 0) {
-		//check UIDs of highest mid with current and cached
-		$temp = iil_C_Search($conn, $mailbox, 'UID ' . $data['d'][$num]);
-		if (!$temp || !is_array($temp) || $temp[0] != $num) {
-		    $cache_good = -3;
-    		}
-	}
-
-	//if cached data's good, return it
-	if ($cache_good > 0) {
-		return $data['d'];
-	}
-
-	//otherwise, we need to fetch it
-	$data      = array('n' => $num, 'd' => array());
-	$data['d'] = iil_C_FetchHeaderIndex($conn, $mailbox, $message_set, 'UID');
-    
-	cache_write($conn->user, $conn->host, $key, $data);
-	$conn->uid_cache = $data;
-	return $data['d'];
+	return iil_C_FetchHeaderIndex($conn, $mailbox, $message_set, 'UID');
 }
 
 function iil_SortThreadHeaders($headers, $index_a, $uids) {
@@ -1228,30 +1236,7 @@
 	$uids   = iil_C_FetchUIDs($conn, $mailbox);
 	$debug  = false;
 	
-	/* Get cached records where possible */
-	if ($conn->do_cache) {
-		$cached = cache_read($conn->user, $conn->host, $mailbox.'.thhd');
-		if ($cached && is_array($uids) && count($uids)>0) {
-			$needed_set = '';
-			foreach ($uids as $id=>$uid) {
-				if ($cached[$uid]) {
-					$result[$uid]     = $cached[$uid];
-					$result[$uid]->id = $id;
-				} else {
-				    $needed_set .= ($needed_set ? ',' : '') . $id;
-            			}
-			}
-			if ($needed_set) {
-			    $message_set = $needed_set;
-			} else {
-			    $message_set = '';
-        		}
-		}
-	}
 	$message_set = iil_CompressMessageSet($message_set);
-	if ($debug) {
-	    echo "Still need: ".$message_set;
-	}
     
 	/* if we're missing any, get them */
 	if ($message_set) {
@@ -1269,7 +1254,7 @@
 			if ($debug) {
 			    echo $line . "\n";
         		}
-			if (ereg('\{[0-9]+\}$', $line)) {
+			if (preg_match('/\{[0-9]+\}$/', $line)) {
 				$a 	 = explode(' ', $line);
 				$new = array();
 
@@ -1287,7 +1272,7 @@
 
 						$new[strtoupper($field_name)] = trim($field_val);
 
-					} else if (ereg('^[[:space:]]', $line)) {
+					} else if (preg_match('/^\s+/', $line)) {
 						$new[strtoupper($field_name)] .= trim($line);
 					}
 				} while ($line[0] != ')');
@@ -1304,13 +1289,6 @@
 	/* sort headers */
 	if (is_array($index_a)) {
 		$result = iil_SortThreadHeaders($result, $index_a, $uids);	
-	}
-	
-	/* write new set to cache */
-	if ($conn->do_cache) {
-		if (count($result)!=count($cached)) {
-			cache_write($conn->user, $conn->host, $mailbox . '.thhd', $result);
-    		}
 	}
 	
 	//echo 'iil_FetchThreadHeaders:'."\n";
@@ -1337,7 +1315,7 @@
 	$fp        = $conn->fp;
 	$debug     = false;
 	
-	$sbj_filter_pat = '[a-zA-Z]{2,3}(\[[0-9]*\])?:([[:space:]]*)';
+	$sbj_filter_pat = '/[a-z]{2,3}(\[[0-9]*\])?:(\s*)/i';
 	
 	/*  Do "SELECT" command */
 	if (!iil_C_Select($conn, $mailbox)) {
@@ -1374,18 +1352,18 @@
 		}
         
 		/* if subject contains 'RE:' or has in-reply-to header, it's a reply */
-		$sbj_pre ='';
+		$sbj_pre = '';
 		$has_re = false;
-		if (eregi($sbj_filter_pat, $new['SUBJECT'])) {
+		if (preg_match($sbj_filter_pat, $new['SUBJECT'])) {
 		    $has_re = true;
 		}
-    		if ($has_re||$new['IN-REPLY-TO']) {
+    		if ($has_re || $new['IN-REPLY-TO']) {
         	    $sbj_pre = 'RE:';
 		}
         
 		/* strip out 're:', 'fw:' etc */
 		if ($has_re) {
-		    $sbj = ereg_replace($sbj_filter_pat, '', $new['SUBJECT']);
+		    $sbj = preg_replace($sbj_filter_pat, '', $new['SUBJECT']);
 		} else {
 		    $sbj = $new['SUBJECT'];
 		}
@@ -1535,11 +1513,10 @@
 	return $t_index;
 }
 
-function iil_C_FetchHeaders(&$conn, $mailbox, $message_set, $uidfetch=false)
+function iil_C_FetchHeaders(&$conn, $mailbox, $message_set, $uidfetch=false, $bodystr=false, $add='')
 {
 	global $IMAP_USE_INTERNAL_DATE;
 	
-	$c      = 0;
 	$result = array();
 	$fp     = $conn->fp;
 	
@@ -1554,43 +1531,28 @@
 		$conn->error = "Couldn't select $mailbox";
 		return false;
 	}
-		
-	/* Get cached records where possible */
-	if ($conn->do_cache) {
-		$uids = iil_C_FetchHeaderIndex($conn, $mailbox, $message_set, "UID");
-		if (is_array($uids) && count($conn->cache[$mailbox]>0)) {
-			$needed_set = '';
-			while (list($id,$uid)=each($uids)) {
-				if ($conn->cache[$mailbox][$uid]) {
-					$result[$id]     = $conn->cache[$mailbox][$uid];
-					$result[$id]->id = $id;
-				} else {
-				    $needed_set.=($needed_set ? ',': '') . $id;
-				}
-			}
-			//echo "<!-- iil_C_FetchHeader\nMessage Set: $message_set\nNeeded Set:$needed_set\n//-->\n";
-			if ($needed_set) {
-				$message_set = iil_CompressMessageSet($needed_set);
-			} else {
-				return $result;
-			}
-		}
-	}
 
-	/* FETCH date,from,subject headers */
-	$key	  = 'fh' . ($c++);
-	$prefix	  = $uidfetch?' UID':'';
-	$request  = $key . $prefix;
-	$request .= " FETCH $message_set (BODY.PEEK[HEADER.FIELDS ";
+	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 .= "REFERENCES DISPOSITION-NOTIFICATION-TO X-PRIORITY".$add.")])";
 
 	if (!iil_PutLine($fp, $request)) {
 		return false;
 	}
 	do {
-		$line = chop(iil_ReadLine($fp, 200));
+		$line = iil_ReadLine($fp, 1024);
+		$line = iil_MultLine($fp, $line);
+
 		$a    = explode(' ', $line);
 		if (($line[0] == '*') && ($a[2] == 'FETCH')) {
 			$id = $a[1];
@@ -1600,41 +1562,124 @@
 			$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 (strcasecmp($a[$i],'UID') == 0)
+							$result[$id]->uid = $a[$i+1];
+						else if (strcasecmp($a[$i],'RFC822.SIZE') == 0)
+							$result[$id]->size = $a[$i+1];
+						else if (strcasecmp($a[$i],'INTERNALDATE') == 0)
+							$time_str = $a[$i+1];
+						else if (strcasecmp($a[$i],'FLAGS') == 0)
+							$flags_str = $a[$i+1];
+					}
+
+					$time_str = str_replace('"', '', $time_str);
+					
+					// if time is gmt...
+		                        $time_str = str_replace('GMT','+0000',$time_str);
+					
+					//get timezone
+					$time_str      = substr($time_str, 0, -1);
+					$time_zone_str = substr($time_str, -5); // extract timezone
+					$time_str      = substr($time_str, 0, -5); // remove timezone
+					$time_zone     = (float)substr($time_zone_str, 1, 2); // get first two digits
+			
+					if ($time_zone_str[3] != '0') {
+					         $time_zone += 0.5;  //handle half hour offset
+					}
+					if ($time_zone_str[0] == '-') {
+					        $time_zone = $time_zone * -1.0; //minus?
+					}
+					
+					//calculate timestamp
+                                        $timestamp     = strtotime($time_str); //return's server's time
+					$timestamp    -= $time_zone * 3600; //compensate for tz, get GMT
+
+					$result[$id]->internaldate = $time_str;
+					$result[$id]->timestamp = $timestamp;
+					$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);
+					}
+					$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 $line) {
+					if (ord($line[0])<=32) {
+						$lines[$ln] .= (empty($lines[$ln])?'':"\n").trim($line);
+					} else {
+						$lines[++$ln] = trim($line);
+					}
+				}
+			}
+
 			/*
 				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.
 			*/
-			$i     = 0;
-			$lines = array();
+	
 			do {
 				$line = chop(iil_ReadLine($fp, 300), "\r\n");
-				if (ord($line[0])<=32) {
-				    $lines[$i] .= (empty($lines[$i])?'':"\n").trim($line);
-				} else {
-					$i++;
-					$lines[$i] = trim($line);
-				}
-				/* 
-					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.
-				*/
+
+				// 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 (trim($line[0]) != ')' && strncmp($line, $key, strlen($key)));
-			
+
 			if (strncmp($line, $key, strlen($key))) { 
-				//process header, fill iilBasicHeader obj.
-				//	initialize
+				// process header, fill iilBasicHeader obj.
+				// initialize
 				if (is_array($headers)) {
 					reset($headers);
 					while (list($k, $bar) = each($headers)) {
@@ -1642,23 +1687,25 @@
 					}
 				}
 	
-				//	create array with header field:data
+				// create array with header field:data
 				while ( list($lines_key, $str) = each($lines) ) {
 					list($field, $string) = iil_SplitHeaderLine($str);
 					
 					$field  = strtolower($field);
-                                        $string = ereg_replace("\n[[:space:]]*"," ",$string); 
+					$string = preg_replace('/\n\s*/', ' ', $string);
 					
 					switch ($field) {
 					case 'date';
-						$result[$id]->date = $string;
-						$result[$id]->timestamp = iil_StrToTime($string);
+						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 = $string;
+						$result[$id]->to = preg_replace('/undisclosed-recipients:[;,]*/', '', $string);
 						break;
 					case 'subject':
 						$result[$id]->subject = $string;
@@ -1686,7 +1733,7 @@
 						}
 						break;
 					case 'in-reply-to':
-						$result[$id]->in_reply_to = ereg_replace("[\n<>]", '', $string);
+						$result[$id]->in_reply_to = preg_replace('/[\n<>]/', '', $string);
 						break;
 					case 'references':
 						$result[$id]->references = $string;
@@ -1703,131 +1750,54 @@
 						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);
 			}
-		}
-	} while (strcmp($a[0], $key) != 0);
 
-	/* 
-		FETCH uid, size, flags
-		Sample reply line: "* 3 FETCH (UID 2417 RFC822.SIZE 2730 FLAGS (\Seen \Deleted))"
-	*/
-	$command_key = 'fh' . ($c++);
-	$request     = $command_key . $prefix;
-	$request    .= " FETCH $message_set (UID RFC822.SIZE FLAGS INTERNALDATE)";
-	
-	if (!iil_PutLine($fp, $request)) {
-	    return false;
-	}
-	do {
-		$line = chop(iil_ReadLine($fp, 200));
-		//$a = explode(' ', $line);
-		//if (($line[0]=="*") && ($a[2]=="FETCH")) {
-		if ($line[0] == '*') {
-			//echo "<!-- $line //-->\n";
-			//get outter most parens
-			$open_pos = strpos($line, "(") + 1;
-			$close_pos = strrpos($line, ")");
-			if ($open_pos && $close_pos) {
-				//extract ID from pre-paren
-				$pre_str = substr($line, 0, $open_pos);
-				$pre_a = explode(' ', $line);
-				$id = $pre_a[1];
-				
-				//get data
-				$len = $close_pos - $open_pos;
-				$str = substr($line, $open_pos, $len);
-				
-				//swap parents with quotes, then explode
-				$str = eregi_replace("[()]", "\"", $str);
-				$a = iil_ExplodeQuotedString(' ', $str);
-				
-				//did we get the right number of replies?
-				$parts_count = count($a);
-				if ($parts_count>=8) {
-					for ($i=0;$i<$parts_count;$i=$i+2) {
-						if (strcasecmp($a[$i],"UID") == 0) $result[$id]->uid=$a[$i+1];
-						else if (strcasecmp($a[$i],"RFC822.SIZE") == 0) $result[$id]->size=$a[$i+1];
-						else if (strcasecmp($a[$i],"INTERNALDATE") == 0) $time_str = $a[$i+1];
-						else if (strcasecmp($a[$i],"FLAGS") == 0) $flags_str = $a[$i+1];
-					}
-
-					// process flags
-					$flags_str = eregi_replace('[\\\"]', '', $flags_str);
-					$flags_a   = explode(' ', $flags_str);
+			// 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);
-						while (list($key,$val)=each($flags_a)) {
-							if (strcasecmp($val,'Seen') == 0) {
-							    $result[$id]->seen = true;
-							} else if (strcasecmp($val, 'Deleted') == 0) {
-							    $result[$id]->deleted=true;
-							} else if (strcasecmp($val, 'Recent') == 0) {
-							    $result[$id]->recent = true;
-							} else if (strcasecmp($val, 'Answered') == 0) {
-							    $result[$id]->answered = true;
-							} else if (strcasecmp($val, '$Forwarded') == 0) {
-							    $result[$id]->forwarded = true;
-							} else if (strcasecmp($val, 'Draft') == 0) {
-							    $result[$id]->is_draft = true;
-							} else if (strcasecmp($val, '$MDNSent') == 0) {
-							    $result[$id]->mdn_sent = true;
-							} else if (strcasecmp($val, 'Flagged') == 0) {
-							     $result[$id]->flagged = true;
-							}
+				if (is_array($flags_a)) {
+					reset($flags_a);
+					while (list(,$val)=each($flags_a)) {
+						if (strcasecmp($val,'Seen') == 0) {
+						    $result[$id]->seen = true;
+						} else if (strcasecmp($val, 'Deleted') == 0) {
+						    $result[$id]->deleted=true;
+						} else if (strcasecmp($val, 'Recent') == 0) {
+						    $result[$id]->recent = true;
+						} else if (strcasecmp($val, 'Answered') == 0) {
+							$result[$id]->answered = true;
+						} else if (strcasecmp($val, '$Forwarded') == 0) {
+							$result[$id]->forwarded = true;
+						} else if (strcasecmp($val, 'Draft') == 0) {
+							$result[$id]->is_draft = true;
+						} else if (strcasecmp($val, '$MDNSent') == 0) {
+							$result[$id]->mdn_sent = true;
+						} else if (strcasecmp($val, 'Flagged') == 0) {
+						         $result[$id]->flagged = true;
 						}
-						$result[$id]->flags = $flags_a;
 					}
-			
-					// if time is gmt...	
-					$time_str = str_replace('GMT','+0000',$time_str);
-					
-					//get timezone
-					$time_str      = substr($time_str, 0, -1);
-					$time_zone_str = substr($time_str, -5); //extract timezone
-					$time_str      = substr($time_str, 1, -6); //remove quotes
-					$time_zone     = (float)substr($time_zone_str, 1, 2); //get first two digits
-					if ($time_zone_str[3] != '0') {
-					    $time_zone += 0.5;  //handle half hour offset
-					}
-					if ($time_zone_str[0] == '-') {
-						$time_zone = $time_zone * -1.0; //minus?
-					}
-					$result[$id]->internaldate = $time_str;
-					
-					if ($IMAP_USE_INTERNAL_DATE || empty($result[$id]->date)) {
-						//calculate timestamp
-						$timestamp     = strtotime($time_str); //return's server's time
-						$na_timestamp  = $timestamp;
-						$timestamp    -= $time_zone * 3600; //compensate for tz, get GMT
-						
-						$result[$id]->timestamp = $timestamp;
-						$result[$id]->date = $time_str;
-					}
-						
-					if ($conn->do_cache) {
-						$uid = $result[$id]->uid;
-						$conn->cache[$mailbox][$uid] = $result[$id];
-						$conn->cache_dirty[$mailbox] = true;
-					}
-					//echo "<!-- ID: $id : $time_str -- local: $na_timestamp (".date("F j, Y, g:i a", $na_timestamp).") tz: $time_zone -- GMT: ".$timestamp." (".date("F j, Y, g:i a", $timestamp).")  //-->\n";
-				} else {
-					//echo "<!-- ERROR: $id : $str //-->\n";
+					$result[$id]->flags = $flags_a;
 				}
 			}
 		}
-	} while (strpos($line, $command_key) === false);
-		
+	} while (strcmp($a[0], $key) != 0);
+
 	return $result;
 }
 
-function iil_C_FetchHeader(&$conn, $mailbox, $id, $uidfetch=false) {
-	$fp = $conn->fp;
-	$a  = iil_C_FetchHeaders($conn, $mailbox, $id, $uidfetch);
+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);
 	}
@@ -1897,17 +1867,19 @@
 	return $result;
 }
 
-function iil_C_Expunge(&$conn, $mailbox) {
+function iil_C_Expunge(&$conn, $mailbox, $messages=NULL) {
 
 	if (iil_C_Select($conn, $mailbox)) {
 		$c = 0;
-		iil_PutLine($conn->fp, "exp1 EXPUNGE");
+		$command = $messages ? "UID EXPUNGE $messages" : "EXPUNGE";
+
+		iil_PutLine($conn->fp, "exp1 $command");
 		do {
 			$line=chop(iil_ReadLine($conn->fp, 100));
 			if ($line[0] == '*') {
             			$c++;
         		}
-		} while (!iil_StartsWith($line, 'exp1'));
+		} while (!iil_StartsWith($line, 'exp1', true));
 		
 		if (iil_ParseResult($line) == 0) {
 			$conn->selected = ''; //state has changed, need to reselect			
@@ -1933,16 +1905,15 @@
     
 	if (iil_C_Select($conn, $mailbox)) {
 		$c = 0;
-		iil_PutLine($fp, "flg STORE $messages " . $mod . "FLAGS (" . $flag . ")");
+		iil_PutLine($fp, "flg UID STORE $messages " . $mod . "FLAGS (" . $flag . ")");
 		do {
 			$line=chop(iil_ReadLine($fp, 100));
 			if ($line[0] == '*') {
 			    $c++;
         		}
-		} while (!iil_StartsWith($line, 'flg'));
+		} while (!iil_StartsWith($line, 'flg', true));
 
 		if (iil_ParseResult($line) == 0) {
-			iil_C_ExpireCachedItems($conn, $mailbox, $messages);
 			return $c;
 		}
 		$conn->error = $line;
@@ -1982,7 +1953,7 @@
 	if (iil_C_Select($conn, $from)) {
 		$c=0;
 		
-		iil_PutLine($fp, "cpy1 COPY $messages \"".iil_Escape($to)."\"");
+		iil_PutLine($fp, "cpy1 UID COPY $messages \"".iil_Escape($to)."\"");
 		$line=iil_ReadReply($fp);
 		return iil_ParseResult($line);
 	} else {
@@ -1999,11 +1970,9 @@
 function iil_C_CountUnseen(&$conn, $folder) {
 	$index = iil_C_Search($conn, $folder, 'ALL UNSEEN');
 	if (is_array($index)) {
-		$str = implode(',', $index);
-		if (empty($str)) {
-		    return false;
-    		}
-		return count($index);
+		if (($cnt = count($index)) && $index[0] != '') {
+			return $cnt;
+		}
 	}
 	return false;
 }
@@ -2011,11 +1980,7 @@
 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 = count($id_a);
-			if ($count > 1) {
-			    return false;
-        		}
+		if (is_array($id_a) && count($id_a) == 1) {
 			return $id_a[0];
 		}
 	}
@@ -2033,7 +1998,7 @@
 		if (iil_PutLine($fp, "$key FETCH $id (UID)")) {
 			do {
 				$line=chop(iil_ReadLine($fp, 1024));
-				if (eregi("^\* $id FETCH \(UID (.*)\)", $line, $r)) {
+				if (preg_match("/^\* $id FETCH \(UID (.*)\)/i", $line, $r)) {
 					$result = $r[1];
 				}
 			} while (!preg_match("/^$key/", $line));
@@ -2048,15 +2013,17 @@
 		$c = 0;
 		
 		$query = 'srch1 SEARCH ' . chop($criteria);
-		iil_PutLine($fp, $query);
+		if (!iil_PutLineC($fp, $query)) {
+			return false;
+		}
 		do {
 			$line=trim(iil_ReadLine($fp, 10000));
-			if (eregi("^\* SEARCH", $line)) {
+			if (preg_match('/^\* SEARCH/i', $line)) {
 				$str = trim(substr($line, 8));
 				$messages = explode(' ', $str);
 			}
-		} while (!iil_StartsWith($line, 'srch1'));
-		
+		} while (!iil_StartsWith($line, 'srch1', true));
+
 		$result_code = iil_ParseResult($line);
 		if ($result_code == 0) {
 		    return $messages;
@@ -2069,12 +2036,13 @@
 }
 
 function iil_C_Move(&$conn, $messages, $from, $to) {
-    $fp = $conn->fp;
 
     if (!$from || !$to) {
         return -1;
     }
-    $r = iil_C_Copy($conn, $messages, $from,$to);
+    
+    $r = iil_C_Copy($conn, $messages, $from, $to);
+
     if ($r==0) {
         return iil_C_Delete($conn, $from, $messages);
     }
@@ -2092,8 +2060,14 @@
  * @see iil_Connect()
  */
 function iil_C_GetHierarchyDelimiter(&$conn) {
+
+	global $my_prefs;
+	
 	if ($conn->delimiter) {
-        return $conn->delimiter;
+    		return $conn->delimiter;
+	}
+	if (!empty($my_prefs['delimiter'])) {
+    	    return ($conn->delimiter = $my_prefs['delimiter']);
 	}
     
 	$fp        = $conn->fp;
@@ -2108,17 +2082,17 @@
 		$line=iil_ReadLine($fp, 500);
 		if ($line[0] == '*') {
 			$line = rtrim($line);
-			$a=iil_ExplodeQuotedString(' ', $line);
+			$a=iil_ExplodeQuotedString(' ', iil_UnEscape($line));
 			if ($a[0] == '*') {
 			    $delimiter = str_replace('"', '', $a[count($a)-2]);
         		}
 		}
-	} while (!iil_StartsWith($line, 'ghd'));
+	} 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");
@@ -2126,9 +2100,10 @@
 		$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'));
+	} while (!iil_StartsWith($line, 'ns1', true));
 		
 	if (!is_array($data)) {
 	    return false;
@@ -2176,7 +2151,7 @@
 	// get folder list
 	do {
 		$line = iil_ReadLine($fp, 500);
-		$line = iil_MultLine($fp, $line);
+		$line = iil_MultLine($fp, $line, true);
 
 		$a = explode(' ', $line);
 		if (($line[0] == '*') && ($a[1] == 'LIST')) {
@@ -2184,10 +2159,10 @@
         		// split one line
 			$a = iil_ExplodeQuotedString(' ', $line);
         		// last string is folder name
-			$folder = trim($a[count($a)-1], '"');
+			$folder = preg_replace(array('/^"/', '/"$/'), '', iil_UnEscape($a[count($a)-1]));
             
         		if (empty($ignore) || (!empty($ignore)
-            			&& !eregi($ignore, $folder))) {
+            			&& !preg_match('/'.preg_quote(ignore, '/').'/i', $folder))) {
             			$folders[$i] = $folder;
         		}
             
@@ -2196,7 +2171,7 @@
         		// is it a container?
         		$i++;
 		}
-	} while (!iil_StartsWith($line, 'lmb'));
+	} while (!iil_StartsWith($line, 'lmb', true));
 
 	if (is_array($folders)) {
     	    if (!empty($ref)) {
@@ -2241,7 +2216,7 @@
 	// get folder list
 	do {
 		$line = iil_ReadLine($fp, 500);
-		$line = iil_MultLine($fp, $line);
+		$line = iil_MultLine($fp, $line, true);
 		$a    = explode(' ', $line);
         
 		if (($line[0] == '*') && ($a[1] == 'LSUB' || $a[1] == 'LIST')) {
@@ -2249,13 +2224,11 @@
             
         		// split one line
 			$a = iil_ExplodeQuotedString(' ', $line);
-            
         		// last string is folder name
-        		//$folder = UTF7DecodeString(str_replace('"', '', $a[count($a)-1]));
-        		$folder = trim($a[count($a)-1], '"');
-            
+    			$folder = preg_replace(array('/^"/', '/"$/'), '', iil_UnEscape($a[count($a)-1]));
+        
 			if ((!in_array($folder, $folders)) && (empty($ignore)
-            			|| (!empty($ignore) && !eregi($ignore, $folder)))) {
+            			|| (!empty($ignore) && !preg_match('/'.preg_quote(ignore, '/').'/i', $folder)))) {
 			    $folders[$i] = $folder;
         		}
             
@@ -2265,7 +2238,7 @@
         		// is it a container?
         		$i++;
 		}
-	} while (!iil_StartsWith($line, 'lsb'));
+	} while (!iil_StartsWith($line, 'lsb', true));
 
 	if (is_array($folders)) {
     	    if (!empty($ref)) {
@@ -2304,68 +2277,95 @@
 	return iil_ParseResult($line);
 }
 
-function iil_C_FetchPartHeader(&$conn, $mailbox, $id, $part) {
+function iil_C_FetchMIMEHeaders(&$conn, $mailbox, $id, $parts) {
+	
 	$fp     = $conn->fp;
-	$result = false;
-	if (($part == 0) || (empty($part))) {
-	    $part = 'HEADER';
-	} else {
-    	    $part .= '.MIME';
-	}
-    
-	if (iil_C_Select($conn, $mailbox)) {
-		$key     = 'fh' . ($c++);
-		$request = $key . " FETCH $id (BODY.PEEK[$part])";
-		if (!iil_PutLine($fp, $request)) return false;
-		do {
-			$line = chop(iil_ReadLine($fp, 200));
-			$a    = explode(' ', $line);
-			if (($line[0] == '*') && ($a[2] == 'FETCH')
-                && ($line[strlen($line)-1] != ')')) {
-				$line=iil_ReadLine($fp, 300);
-				while (trim($line) != ')') {
-					$result .= $line;
-					$line=iil_ReadLine($fp, 300);
-				}
-			}
-		} while (strcmp($a[0], $key) != 0);
+
+	if (!iil_C_Select($conn, $mailbox)) {
+		return false;
 	}
 	
+	$result = false;
+	$parts = (array) $parts;
+	$key = 'fmh0';
+	$peeks = '';
+	$idx = 0;
+
+	// format request
+	foreach($parts as $part)
+		$peeks[] = "BODY.PEEK[$part.MIME]";
+	
+	$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\.]+)\.MIME\]/', $line, $matches)) {
+			$idx = $matches[1];
+			$result[$idx] = preg_replace('/^(\* '.$id.' FETCH \()?\s*BODY\['.$idx.'\.MIME\]\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_HandlePartBody(&$conn, $mailbox, $id, $part, $mode) {
-	/* modes:
-        1: return string
-        2: print
-        3: base64 and print
-	*/
+function iil_C_FetchPartHeader(&$conn, $mailbox, $id, $part) {
+
+	$part = empty($part) ? 'HEADER' : $part.'.MIME';
+
+        return iil_C_HandlePartBody($conn, $mailbox, $id, $part);
+}
+
+function iil_C_HandlePartBody(&$conn, $mailbox, $id, $part='', $encoding=NULL, $print=NULL, $file=NULL) {
 	
 	$fp     = $conn->fp;
 	$result = false;
-	if (($part == 0) || empty($part)) {
-	    $part = 'TEXT';
+	
+	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     = 'ftch' . ($c++) . ' ';
-		$request = $key . "FETCH $id (BODY.PEEK[$part])";
+		$key     = 'ftch0';
+		$request = $key . " 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 ($a[2] != 'FETCH');
+    		} while (!($end = iil_StartsWith($line, $key, true)) && $a[2] != 'FETCH');
     		$len = strlen($line);
-    
-    		if ($line[$len-1] == ')') {
+
+		// 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
@@ -2377,11 +2377,13 @@
 				$result = substr($line, $from, $len);
 			}
 	    
-	                if ($mode == 2) {
-        		        echo $result;
-	                } else if ($mode == 3) {
-        		        echo base64_decode($result);
-	                }
+        		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;
@@ -2389,57 +2391,94 @@
         		$len      = $to - $from;
 	                $sizeStr  = substr($line, $from, $len);
         		$bytes    = (int)$sizeStr;
-	                $received = 0;
-
-        		while ($received < $bytes) {
-            			$remaining = $bytes - $received;
-		                $line      = iil_ReadLine($fp, 1024);
+			$prev	  = '';
+			
+        		while ($bytes > 0) {
+    		                $line      = iil_ReadLine($fp, 1024);
             			$len       = strlen($line);
                 
-		                if ($len > $remaining) {
-            			        $line = substr($line, 0, $remaining);
+		                if ($len > $bytes) {
+            			        $line = substr($line, 0, $bytes);
 		                }
-            			$received += strlen($line);
+            			$bytes -= strlen($line);
+
 		                if ($mode == 1) {
-            			        $result .= rtrim($line, "\t\r\n\0\x0B") . "\n";
-		                } else if ($mode == 2) {
-            			        echo rtrim($line, "\t\r\n\0\x0B") . "\n";
-		                } else if ($mode == 3) {
-            				echo base64_decode($line);
-            			}
+					$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 'til last line
-		do {
-        		$line = iil_ReadLine($fp, 1024);
-		} while (!iil_StartsWith($line, $key));
+
+	        // read in anything up until last line
+		if (!$end)
+			do {
+        			$line = iil_ReadLine($fp, 1024);
+			} while (!iil_StartsWith($line, $key, true));
         
     		if ($result) {
 	    		$result = rtrim($result, "\t\r\n\0\x0B");
-        		return $result; // substr($result, 0, strlen($result)-1);
+			if ($file) {
+				fwrite($file, $result);
+			} else if ($print) {
+				echo $result;
+			} else
+				return $result; // substr($result, 0, strlen($result)-1);
     		}
     		
-		return false;
-	} else {
-		echo 'Select failed.';
+		return true;
 	}
     
-	if ($mode==1) {
-    		return $result;
-	}
-	return $received;
+	return false;
 }
 
-function iil_C_FetchPartBody(&$conn, $mailbox, $id, $part) {
-	return iil_C_HandlePartBody($conn, $mailbox, $id, $part, 1);
+function iil_C_FetchPartBody(&$conn, $mailbox, $id, $part, $file=NULL) {
+	return iil_C_HandlePartBody($conn, $mailbox, $id, $part, NULL, NULL, $file);
 }
 
 function iil_C_PrintPartBody(&$conn, $mailbox, $id, $part) {
-	iil_C_HandlePartBody($conn, $mailbox, $id, $part, 2);
-}
-
-function iil_C_PrintBase64Body(&$conn, $mailbox, $id, $part) {
-	iil_C_HandlePartBody($conn, $mailbox, $id, $part, 3);
+	iil_C_HandlePartBody($conn, $mailbox, $id, $part, NULL, true, NULL);
 }
 
 function iil_C_CreateFolder(&$conn, $folder) {
@@ -2587,47 +2626,46 @@
 	return $result;
 }
 
-function iil_C_PrintSource(&$conn, $folder, $id, $part) {
-	$header = iil_C_FetchPartHeader($conn, $folder, $id, $part);
-	//echo str_replace("\r", '', $header);
-	echo $header;
-	echo iil_C_PrintPartBody($conn, $folder, $id, $part);
-}
-
 function iil_C_GetQuota(&$conn) {
 /*
  * GETQUOTAROOT "INBOX"
  * QUOTAROOT INBOX user/rchijiiwa1
  * QUOTA user/rchijiiwa1 (STORAGE 654 9765)
- b OK Completed
+ * OK Completed
  */
 	$fp         = $conn->fp;
 	$result     = false;
-	$quota_line = '';
+	$quota_lines = array();
 	
-	//get line containing quota info
+	// 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_line = $line;
+				$quota_lines[] = $line;
         		}
-		} while (!iil_StartsWith($line, 'QUOT1'));
+		} while (!iil_StartsWith($line, 'QUOT1', true));
 	}
 	
-	//return false if not found, parse if found
-	if (!empty($quota_line)) {
-		$quota_line   = eregi_replace('[()]', '', $quota_line);
+	// 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 > 0) {
-			$result = array();
-			$used   = $parts[$storage_part+1];
-			$total  = $parts[$storage_part+2];
-            
+		
+		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']   = (empty($total)?"??":$total);
-			$result['percent'] = (empty($total)?"??":round(($used/$total)*100));
+			$result['total']   = $total;
+			$result['percent'] = min(100, round(($used/max(1,$total))*100));
 			$result['free']    = 100 - $result['percent'];
 		}
 	}
@@ -2637,7 +2675,7 @@
 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:' . $num_in_trash);
+		iil_C_Delete($conn, $folder, '1:*');
 	}
 	return (iil_C_Expunge($conn, $folder) >= 0);
 }

--
Gitblit v1.9.1