Index: trunk/prototype/services/ImapServiceAdapter.php
===================================================================
--- trunk/prototype/services/ImapServiceAdapter.php	(revision 5416)
+++ trunk/prototype/services/ImapServiceAdapter.php	(revision 5533)
@@ -7,160 +7,419 @@
     public function open( $config )
     {
-	$this->init();
+		$this->init();
     }
 
 //     public function connect( $config )
 //     {
-// 	$this->init();
+// 			$this->init();
 //     }
 	
     public function find( $URI, $justthese = false, $criteria = false )
 	{ 
-	$context = $justthese['context'];
-	    $URI = $URI['concept'];
-
-	switch( $URI )
-	{
-	    case 'folder':
-	    {
-		$result = $this->to_utf8($this->get_folders_list());
-
-		foreach ($result as $res) {
-
-		    $response[] = array(
-				    'id' => $res['folder_id'],
-				    'commonName' => $res['folder_name'],
-				    'parentFolder' => $res['folder_parent'],
-				    'messageCount' => array('unseen' => isset($res['folder_unseen']) ? $res['folder_unseen'] : null, 'total' => null)
-			    );
+		$context = $justthese['context'];
+		$URI = $URI['concept'];
+
+		switch( $URI )
+		{
+			case 'folder':
+			{
+				$result = $this->to_utf8($this->get_folders_list());
+
+				foreach ($result as $res) {
+
+					$response[] = array(
+							'id' => $res['folder_id'],
+							'commonName' => $res['folder_name'],
+							'parentFolder' => $res['folder_parent'],
+							'messageCount' => array('unseen' => isset($res['folder_unseen']) ? $res['folder_unseen'] : null, 'total' => null)
+						);
+				}
+
+				return $response;
+			}
+			case 'message':
+			{
+				//begin: for grid	
+				$page  = $criteria['page']; //{1}    get the requested page
+				$limit = $criteria['rows']; //{10}   get how many rows we want to have into the grid
+				$sidx  = $criteria['sidx']; //{id}   get index row - i.e. user click to sort
+				$sord  = $criteria['sord']; //{desc} get the direction
+
+				$filter = $criteria['filter'];
+
+				if( !$sidx ) $sidx = 1;
+
+				$folder_name = str_replace( '.', $this->imap_delimiter, $context['folder'] );
+				
+				$count = imap_num_msg( $this->open_mbox( $folder_name ) );
+
+				$total_pages = $count > 0 ? ceil( $count/$limit ) : 0;
+
+				if( $page > $total_pages )
+					$page = $total_pages;
+
+				$start = $limit * $page - $limit;
+
+				// do not put $limit*($page - 1)
+				//end: for grid
+
+				if( $filter )
+				{
+					if( $filter[0] !== 'msgNumber' )
+					{
+					for( $i = 0; $i < count($filter); $i++ )
+					{
+						if( count( $filter[$i] ) === 4 )
+						$criteria['isExact'] = ( array_shift( $filter[$i] ) === 'AND' );
+
+						$criteria[ $filter[$i][0] ] = array( 'criteria' => $filter[$i][2], 'filter' => $filter[$i][1] );
+					}
+
+					return $this->searchSieveRule($criteria);
+					}
+
+					$msgNumber = array();
+
+					for( $i = $start; $i < $start + $limit && isset( $filter[2][$i] ); $i++ )
+					  $msgNumber[] = $filter[2][$i];
+
+					if( empty( $msgNumber ) )
+					return( false );
+
+					$result = $this->get_info_msgs( array( 'folder' => $folder_name, 
+									   'msgs_number' => implode( ',', $msgNumber ) ) );
+
+					foreach( $result as $i => $val )
+					$result[$i] = unserialize( $val );
+
+				}
+				else
+				{
+					$result = $this->get_range_msgs2( 
+						array( 
+							'folder' => $folder_name, //INBOX
+							'msg_range_begin' => $start + 1, //??
+							'msg_range_end' => $start + $limit, //$limit = $_GET['rows']; // get how many rows we want to have into the grid
+							'sort_box_type' => 'SORTARRIVAL', 
+							'search_box_type' => 'ALL',
+							'sort_box_reverse' => 1 
+						) 
+					);
+				}
+				//return var_export($result);
+
+				$response = array( "page" => $page, "total" => $total_pages, "records" => $count );
+				
+				for ($i=0; $i<count($result); $i++)
+				{
+					$flags_enum = array('Recent', 'Unseen',  'Answered',  'Draft',  'Deleted', 'Flagged');
+
+					foreach ($flags_enum as $key => $flag)
+					{
+						if ( !isset($result[$i][$flag]) || !trim($result[$i][$flag]) || trim($result[$i][$flag]) == '') 
+							unset($flags_enum[$key]);
+
+						unset($result[$i][$flag]);
+					}
+
+					if (array_key_exists($i, $result))
+					{
+						$response["rows"][$i] = $result[$i];
+						$response["rows"][$i]['timestamp'] = ( ( $result[$i]['udate'] + $this->functions->CalculateDateOffset() ) * 1000 );
+						$response["rows"][$i]['flags'] = implode(',', $flags_enum);
+						$response["rows"][$i]['size'] = $response["rows"][$i]['Size'];
+						//$response["rows"][$i]['udate'] = ( $result[$i]['udate'] + $this->functions->CalculateDateOffset()  * 1000 );
+						unset($response["rows"][$i]['Size']);
+					}
+				 }
+
+				return $this->to_utf8($response);
+			}
+			
+			/**
+			 * Filtros suportados:
+			 * - ['=', 'folderName', $X]
+			 * - [
+			 * 		'AND',
+			 * 		[
+			 * 			'AND',
+			 * 			['=', 'folderName', $X],
+			 * 			['IN', 'messageNumber', $Ys]
+			 * 		],
+			 * 		['IN', 'labelId', $Zs]
+			 * ]
+			 * - ['=', 'labelId', $X]
+			 * - [
+			 * 		'AND',
+			 * 		['=', 'folderName', $X],
+			 * 		['=', 'labelId', $Y]
+			 * ]
+			 * - ['IN', 'labelId', $Ys]
+			 * - [
+			 * 		'AND',
+			 * 		['=', 'folderName', $X],
+			 * 		['IN', 'labelId', $Ys]
+			 * ]			
+			 */
+			case 'labeled':
+			{
+				$result = array ( );
+				if (isset($criteria["filter"]) && is_array($criteria['filter'])) {
+					//melhorar o tratamento do filter com a lista de todos os labelIds dado pelo interceptor
+					$map = array(
+						'id' => array(),
+						'folderName' => array(),
+						'messageNumber' => array(),
+						'labelId' => array()
+					);
+					
+					self::parseFilter($criteria["filter"], &$map);
+					
+					if (count($map['folderName']) == 0) {
+						$folders = $this->get_folders_list();
+						foreach ($folders as $folder)
+							if (isset($folder['folder_id'])) 
+								$map['folderName'][] = $folder['folder_id'];
+					}
+
+					foreach ($map['folderName'] as $folder) {
+						$this->mbox = $this->open_mbox($folder);
+						
+						foreach ($map['labelId'] as $label) {
+							$messagesLabeleds = imap_search($this->mbox, 'UNDELETED KEYWORD "$Label'.$label.'"', SE_UID);
+							
+							foreach ($messagesLabeleds as $messageLabeled) {
+								if (count($map['messageNumber']) > 0 && !in_array($messageLabeled, $map['messageNumber']))
+									continue;
+									
+								$result[] = array (
+									'id' => $folder . '/' . $messageLabeled . '#' . $label, 
+									'folderName' => $folder,
+									'messageNumber' => $messageLabeled,
+									'labelId' => $label
+								);
+							}
+						}
+						
+						imap_close($this->mbox);
+						$this->mbox = false;
+					}
+				}
+				
+				return $result;
+			}
+			
+			case 'followupflagged':
+			{
+			
+				$result = array ( );
+				if (isset($criteria["filter"]) && is_array($criteria['filter'])) {
+					//melhorar o tratamento do filter com a lista de todos os labelIds dado pelo interceptor
+					$map = array(
+						'id' => array(),
+						'folderName' => array(),
+						'messageNumber' => array()
+					);
+					
+					self::parseFilter($criteria["filter"], &$map);
+					
+					if (empty($map['folderName'])) {
+						$folders = $this->get_folders_list();
+						foreach ($folders as $folder)
+							if (isset($folder['folder_id'])) 
+								$map['folderName'][] = $folder['folder_id'];
+					}
+
+					foreach ($map['folderName'] as $folder) {
+						$this->mbox = $this->open_mbox($folder);
+						
+						foreach ($map['id'] as $followupflagged) {
+							$messagesFlaggeds = imap_search($this->mbox, 'UNDELETED KEYWORD "$Followupflag'.$followupflagged.'"', SE_UID);
+							
+							foreach ($messagesFlaggeds as $messageFlagged) {
+								if (count($map['messageNumber']) > 0 && !in_array($messageFlagged, $map['messageNumber']))
+									continue;
+									
+								$result[] = array (
+									'id' => $folder . '/' . $messageFlagged . '#' . $followupflagged, 
+									'folderName' => $folder,
+									'messageNumber' => $messageFlagged
+								);
+							}
+						}
+						
+						imap_close($this->mbox);
+						$this->mbox = false;
+					}
+				}
+						
+				return $result;				
+			}
 		}
-
-		break;
-	    }
-	    case 'message':
-	    {
-		//begin: for grid	
-		$page  = $criteria['page']; //{1}    get the requested page
-		$limit = $criteria['rows']; //{10}   get how many rows we want to have into the grid
-		$sidx  = $criteria['sidx']; //{id}   get index row - i.e. user click to sort
-		$sord  = $criteria['sord']; //{desc} get the direction
-
-		$filter = $criteria['filter'];
-
-		if( !$sidx ) $sidx = 1;
-
-		$folder_name = str_replace( '.', $this->imap_delimiter, $context['folder'] );
-		
-		$count = imap_num_msg( $this->open_mbox( $folder_name ) );
-
-		$total_pages = $count > 0 ? ceil( $count/$limit ) : 0;
-
-		if( $page > $total_pages )
-		    $page = $total_pages;
-
-		$start = $limit * $page - $limit;
-
-		// do not put $limit*($page - 1)
-		//end: for grid
-
-		if( $filter )
+    }
+
+    public function read( $URI, $justthese = false )
+    {
+
+		switch( $URI['concept'] )
 		{
-		    if( $filter[0] !== 'msgNumber' )
-		    {
-			for( $i = 0; $i < count($filter); $i++ )
-			{
-			    if( count( $filter[$i] ) === 4 )
-				$criteria['isExact'] = ( array_shift( $filter[$i] ) === 'AND' );
-
-			    $criteria[ $filter[$i][0] ] = array( 'criteria' => $filter[$i][2], 'filter' => $filter[$i][1] );
-			}
-
-			return $this->searchSieveRule($criteria);
-		    }
-
-		    $msgNumber = array();
-
-		    for( $i = $start; $i < $start + $limit && isset( $filter[2][$i] ); $i++ )
-			  $msgNumber[] = $filter[2][$i];
-
-		    if( empty( $msgNumber ) )
-			return( false );
-
-		    $result = $this->get_info_msgs( array( 'folder' => $folder_name, 
-							   'msgs_number' => implode( ',', $msgNumber ) ) );
-
-		    foreach( $result as $i => $val )
-			$result[$i] = unserialize( $val );
-
+			case 'message':
+			{
+				return $this->to_utf8( 
+					$this->get_info_msg( array('msg_number'=>$URI['id'],
+					'msg_folder'=>str_replace( '.', $this->imap_delimiter, $justthese['context']['folder'] )) ) 
+				);
+			}
+			case 'labeled':
+			{
+				/**
+				 * id looks like 'folder/subfolder/subsubfolder/65#13', meaning messageId#labelId
+				 */
+				list($messageId, $labelId) = explode('#', $URI['id']);
+				$folderName = basename($messageId);
+				$messageNumber = dirname($messageId);
+				
+				$result = array();
+
+				if ($folderName && $messageNumber && $labelId) {
+					$this->mbox = $this->open_mbox($folderName);
+					$messagesLabeleds = imap_search($this->mbox, 'UNDELETED KEYWORD "$Label'.$labelId.'"', SE_UID);
+					
+					if (in_array($messageNumber, $messagesLabeleds)) {
+						$result = array (
+							'id' => $URI['id'], 
+							'folderName' => $folderName,
+							'messageNumber' => $messageNumber,
+							'labelId' => $labelId
+						);
+					}
+					imap_close($this->mbox);
+					$this->mbox = false;
+				}
+				
+				return $result;
+			}
+			
+			case 'followupflagged':
+			{
+				/**
+				 * id looks like 'folder/subfolder/subsubfolder/65#13', meaning messageId#followupflaggedId
+				 */
+				list($messageId, $followupflaggedId) = explode('#', $URI['id']);
+				$folderName = basename($messageId);
+				$messageNumber = dirname($messageId);
+				
+				$result = array();
+
+				if ($folderName && $messageNumber && $followupflaggedId) {
+					$this->mbox = $this->open_mbox($folderName);
+					$messagesFlaggeds = imap_search($this->mbox, 'UNDELETED KEYWORD "$Followupflag'.$followupflaggedId.'"', SE_UID);
+					
+					if (in_array($messageNumber, $messagesFlaggeds)) {
+						$result = array (
+							'id' => $URI['id'], 
+							'folderName' => $folderName,
+							'messageNumber' => $messageNumber
+						);
+					}
+					imap_close($this->mbox);
+					$this->mbox = false;
+				}
+				
+				return $result;
+			}
 		}
-		else
+    }
+
+    public function create( $URI, $data)
+    {
+
+		switch( $URI['concept'] )
 		{
-		    $result = $this->get_range_msgs2( array( 'folder' => $folder_name, //INBOX
-					 'msg_range_begin' => $start + 1, //??
-					 'msg_range_end' => $start + $limit, //$limit = $_GET['rows']; // get how many rows we want to have into the grid
-					 'sort_box_type' => 'SORTARRIVAL', 
-					 'search_box_type' => 'ALL',
-							     'sort_box_reverse' => 1 ) );
+			case 'labeled':
+			{
+				if (isset($data['folderName']) && isset($data['messageNumber']) && isset($data['labelId'])) {
+					$this->mbox = $this->open_mbox($data['folderName']);
+					imap_setflag_full($this->mbox, $data['messageNumber'], '$Label' . $data['labelId'], ST_UID);
+
+					imap_close($this->mbox);
+					$this->mbox = false;
+
+					return array ('id' => $data['folderName'].'/'.$data['messageNumber'].'#'.$data['labelId']);
+				}
+				return array ();
+			}
+			case 'followupflagged':
+			{
+				//tem que gravar no banco primeiro, obter o id e depois mandar gravar no imap passando o id no data
+				if (isset($data['folderName']) && isset($data['messageNumber']) && isset($data['id'])) {
+					list($messageId, $followupflaggedId) = explode('#', $data['id']);
+					
+					$this->mbox = $this->open_mbox($data['folderName']);
+					imap_setflag_full($this->mbox, $data['messageNumber'], '$Followupflag' . $followupflaggedId, ST_UID);
+
+					imap_close($this->mbox);
+					$this->mbox = false;
+
+					return array ('id' => $data['id']);
+				}
+				return array ();
+			}
 		}
-		//return var_export($result);
-
-		$response = array( "page" => $page, "total" => $total_pages, "records" => $count );
-		
-		for ($i=0; $i<count($result); $i++)
+	}
+
+    public function delete( $URI, $justthese = false, $criteria = false )
+    {
+		switch( $URI['concept'] )
 		{
-		    $flags_enum = array('Recent', 'Unseen',  'Answered',  'Draft',  'Deleted', 'Flagged');
-
-		    foreach ($flags_enum as $key => $flag)
-		    {
-			if ( !isset($result[$i][$flag]) || !trim($result[$i][$flag]) || trim($result[$i][$flag]) == '') 
-				unset($flags_enum[$key]);
-			unset($result[$i][$flag]);
-		    }
-
-		    if (array_key_exists($i, $result))
-		    {
-				$response["rows"][$i] = $result[$i];
-			$response["rows"][$i]['timestamp'] = ( ( $result[$i]['udate'] + $this->functions->CalculateDateOffset() ) * 1000 );
-				$response["rows"][$i]['flags'] = implode(',', $flags_enum);
-				$response["rows"][$i]['size'] = $response["rows"][$i]['Size'];
-// 			$response["rows"][$i]['udate'] = ( $result[$i]['udate'] + $this->functions->CalculateDateOffset()  * 1000 );
-				unset($response["rows"][$i]['Size']);
-		    }
-		 }
-
-		$response = $this->to_utf8($response);
-
-		break;
-	    }
+			case 'labeled':
+			{
+				list($messageId, $labelId) = explode('#', $URI['id']);
+				$folderName = basename($messageId);
+				$messageNumber = dirname($messageId);
+			
+				if ($folderName && $messageNumber && $labelId) {
+					$this->mbox = $this->open_mbox($folderName);
+					imap_clearflag_full($this->mbox, $messageNumber, '$Label' . $labelId, ST_UID);
+
+					imap_close($this->mbox);
+					$this->mbox = false;
+				}
+			}
+			case 'followupflagged':
+			{
+				list($messageId, $followupflaggedId) = explode('#', $URI['id']);
+				$folderName = basename($messageId);
+				$messageNumber = dirname($messageId);
+			
+				if ($folderName && $messageNumber && $followupflaggedId) {
+					$this->mbox = $this->open_mbox($folderName);
+					imap_clearflag_full($this->mbox, $messageNumber, '$Followupflag' . $followupflaggedId, ST_UID);
+
+					imap_close($this->mbox);
+					$this->mbox = false;
+				}
+			}
+		}
+
+		//TODO - return
 	}
-	return $response;
-    }
+
+    public function deleteAll( $URI, $justthese = false, $criteria = false ) // avaliar
+    {}
+
+    public function update( $URI, $data, $criteria = false )
+    {
+		//TODO - remove
+		//TODO - create
+	}
 
 //     public function retrieve( $concept, $id, $parents, $justthese = false, $criteria = false )
 //     {
-// 	return $this->read( array( 'id' => $id, 
+// 			return $this->read( array( 'id' => $id, 
 // 			    'concept' => $concept, 
 // 			    'context' => $parents ), $justthese );
 //     }
 
-    public function read( $URI, $justthese = false )
-    {
-
-	return $this->to_utf8( $this->get_info_msg( array('msg_number'=>$URI['id'],
-													  'msg_folder'=>str_replace( '.', $this->imap_delimiter, $justthese['context']['folder'] )) ) );
-    }
-
-    public function create( $URI, $data )
-    {}
-
-    public function delete( $URI, $justthese = false, $criteria = false )
-    {}
-
-    public function deleteAll( $URI, $justthese = false, $criteria = false ) // avaliar
-    {}
-
-    public function update( $URI, $data, $criteria = false )
-    {}
-
     public function replace( $URI, $data, $criteria = false )
     {}
@@ -187,15 +446,38 @@
     function to_utf8($in) 
     { 
-	if (is_array($in)) { 
-		foreach ($in as $key => $value) { 
-			$out[$this->to_utf8($key)] = $this->to_utf8($value); 
+		if (is_array($in)) { 
+			foreach ($in as $key => $value) { 
+				$out[$this->to_utf8($key)] = $this->to_utf8($value); 
+			} 
+		} elseif(is_string($in)) { 
+				return mb_convert_encoding( $in , 'UTF-8' , 'UTF-8 , ISO-8859-1' ); 
+		} else { 
+			return $in; 
 		} 
-	} elseif(is_string($in)) { 
-			return mb_convert_encoding( $in , 'UTF-8' , 'UTF-8 , ISO-8859-1' ); 
-	} else { 
-		return $in; 
-	} 
-	return $out; 
+		return $out; 
     }
-
+	
+	    
+    private static function parseFilter( $filter ,&$map){
+		
+		if( !is_array( $filter ) || count($filter) <= 0) return null;
+					
+		$op = array_shift( $filter );
+		switch(strtolower($op))
+		{
+			case 'and': {
+				foreach ($filter as $term)
+					self::parseFilter($term ,&$map);
+				return;
+			}
+			case 'in': {
+				$map[$filter[0]] = array_merge($map[$filter[0]], $filter[1]);
+				return;
+			}
+			case '=': {
+				$map[$filter[0]][] = $filter[1];
+			}
+		}
+	}
+	
 }
