From 55c2a4e23e2a2382720043a1753e5601adfbb56d Mon Sep 17 00:00:00 2001
From: alecpl <alec@alec.pl>
Date: Fri, 06 Mar 2009 04:12:41 -0500
Subject: [PATCH] - Fix FETCH result parsing for servers returning flags at the end of result (#1485763)

---
 CHANGELOG            |    1 
 program/lib/imap.inc |   99 ++++++++++++++++++++++++++-----------------------
 2 files changed, 54 insertions(+), 46 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 431ae06..722b626 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -4,6 +4,7 @@
 2009/03/06 (alec)
 ----------
 - Fix errors handling in IMAP command continuations (#1485762)
+- Fix FETCH result parsing for servers returning flags at the end of result (#1485763)
 
 2009/03/04 (alec)
 ----------
diff --git a/program/lib/imap.inc b/program/lib/imap.inc
index f50abea..67a2b7b 100644
--- a/program/lib/imap.inc
+++ b/program/lib/imap.inc
@@ -1690,7 +1690,7 @@
 	do {
 		$line = iil_ReadLine($fp, 1024);
 		$line = iil_MultLine($fp, $line);
-		
+
 		$a    = explode(' ', $line);
 		if (($line[0] == '*') && ($a[2] == 'FETCH')) {
 			$id = $a[1];
@@ -1718,7 +1718,7 @@
 
 				// did we get the right number of replies?
 				$parts_count = count($a);
-				if ($parts_count>=8) {
+				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];
@@ -1728,34 +1728,6 @@
 							$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);
-					
-					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;
 					}
 
 					$time_str = str_replace('"', '', $time_str);
@@ -1800,7 +1772,7 @@
 				// re-parse (see below)
 				foreach ($reslines as $line) {
 					if (ord($line[0])<=32) {
-					    $lines[$ln] .= (empty($lines[$ln])?'':"\n").trim($line);
+						$lines[$ln] .= (empty($lines[$ln])?'':"\n").trim($line);
 					} else {
 						$lines[++$ln] = trim($line);
 					}
@@ -1817,23 +1789,28 @@
 			do {
 				$line = chop(iil_ReadLine($fp, 300), "\r\n");
 
-				if (ord($line[0])<=32) {
-				    $lines[$ln] .= (empty($lines[$ln])?'':"\n").trim($line);
-				} else {
-					$lines[++$ln] = 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)));
@@ -1922,6 +1899,36 @@
 			} else {
 				$a = explode(' ', $line);
 			}
+
+			// process flags
+			if (!empty($flags_str)) {
+				$flags_str = eregi_replace('[\\\"]', '', $flags_str);
+				$flags_a   = explode(' ', $flags_str);
+					
+				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;
+				}
+			}
 		}
 	} while (strcmp($a[0], $key) != 0);
 

--
Gitblit v1.9.1