Index: /trunk/phpgwapi/inc/class.sector_search_ldap.inc.php
===================================================================
--- /trunk/phpgwapi/inc/class.sector_search_ldap.inc.php	(revision 23)
+++ /trunk/phpgwapi/inc/class.sector_search_ldap.inc.php	(revision 30)
@@ -138,5 +138,5 @@
 				array_pop ( $array_dn_reverse );
 
-				$inverted_dn[$dn] = implode ( ".", $array_dn_reverse );
+				$inverted_dn[$dn] = implode ( ";", $array_dn_reverse );
 			}
 
@@ -150,8 +150,8 @@
                 $display = '';
 
-                $array_dn_reverse = explode ( ".", $invert_ufn );
+                $array_dn_reverse = explode ( ";", $invert_ufn );
                 $array_dn  = array_reverse ( $array_dn_reverse, true );
 
-                $level = count( $array_dn ) - 4;
+                $level = count( $array_dn ) - (int)(count(explode(",", $GLOBALS['phpgw_info']['server']['ldap_context'])) + 1);
 
                 if ($level == 0)
Index: /trunk/expressoAdmin1_2/docs/change_log.txt
===================================================================
--- /trunk/expressoAdmin1_2/docs/change_log.txt	(revision 27)
+++ /trunk/expressoAdmin1_2/docs/change_log.txt	(revision 30)
@@ -59,2 +59,5 @@
 22/05/2007 - [1.240]
 - Criado possibilidade de administrar diversos domínios samba
+
+29/05/2007
+- Ao renomear um usuário, seu sieve script também é renomeado.
Index: /trunk/expressoAdmin1_2/inc/class.user.inc.php
===================================================================
--- /trunk/expressoAdmin1_2/inc/class.user.inc.php	(revision 27)
+++ /trunk/expressoAdmin1_2/inc/class.user.inc.php	(revision 30)
@@ -835,5 +835,5 @@
 					$this->ldap_functions->remove_user_attributes($new_dn, $user_info_mod_remove);
         		
-	        		//Renomeia mailbox e sieve
+	        		//Renomeia mailbox
     	    		$result = $this->imap_functions->rename_mailbox($uid, $new_uid);
 					if (!$result['status'])
@@ -843,5 +843,42 @@
 						$return['msg'] .= "\nErro ao renomear usuário no Cyrus. Processo abortado.";
 					}
-        		
+        			
+        			// Renomeia sieve script
+        			include_once('sieve-php.lib.php');
+        			$sieve=new sieve($sieve_server, $sieve_port, $new_uid, $defaultUserPassword_plain);
+        			
+					if ($sieve->sieve_login())
+					{
+						$sieve->sieve_listscripts();
+						$myactivescript=$sieve->response["ACTIVE"];
+						$sieve->sieve_getscript($myactivescript);
+
+						$script = '';
+						foreach($sieve->response as $result)
+						{
+							$script .= $result;
+						}
+
+        				$scriptname = $new_uid;
+						if($sieve->sieve_sendscript($new_uid,$script))
+						{
+							if ($sieve->sieve_setactivescript($new_uid))
+							{
+								$sieve->sieve_deletescript($myactivescript);
+							}
+						}
+						else 
+						{
+							$return['status'] = false;
+							$return['msg'] .= $result['msg'] . "\nErro ao renomear script sieve, falha no envio do novo script.";
+						}
+						$sieve->sieve_logout();
+					}
+					else
+					{
+							$return['status'] = false;
+							$return['msg'] .= $result['msg'] . "\nErro ao renomear script sieve, falha no Login.";
+					}
+
 					// Retorna senha do usuário
 					$this->ldap_functions->set_user_password($new_uid, $user_password);
Index: /trunk/expressoAdmin1_2/inc/sieve-php.lib.php
===================================================================
--- /trunk/expressoAdmin1_2/inc/sieve-php.lib.php	(revision 30)
+++ /trunk/expressoAdmin1_2/inc/sieve-php.lib.php	(revision 30)
@@ -0,0 +1,905 @@
+<?php
+/**
+ * sieve-php.lib.php
+ *
+ * $Id$ 
+ *
+ * Copyright 2001-2003 Dan Ellis <danellis@rushmore.com>
+ *
+ * This program is released under the GNU Public License.  See the enclosed
+ * file COPYING for license information. If you did not receive this file, see
+ * http://www.fsf.org/copyleft/gpl.html.
+ *
+ * You should have received a copy of the GNU Public License along with this
+ * package; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.        
+ *
+ * See CHANGES for updates since last release
+ *
+ * @author Dan Ellis
+ * @package sieve-php
+ * @copyright Copyright 2002-2003, Dan Ellis, All Rights Reserved.  
+ * @version 0.1.0
+ */
+
+/**
+ * Constants
+ */
+define ("F_NO", 0);		
+define ("F_OK", 1);
+define ("F_DATA", 2);
+define ("F_HEAD", 3);
+
+define ("EC_NOT_LOGGED_IN", 0);
+define ("EC_QUOTA", 10);
+define ("EC_NOSCRIPTS", 20);
+define ("EC_UNKNOWN", 255);
+
+/**
+ * SIEVE class - A Class that implements MANAGESIEVE in PHP4|5.
+ *
+ * This program provides a handy interface into the Cyrus timsieved server
+ * under php4.  It is tested with Sieve server included in Cyrus 2.0, but it
+ * has been upgraded (not tested) to work with older Sieve server versions.
+ *
+ * All functions will return either true or false and will fill in
+ * $sieve->error with a defined error code like EC_QUOTA, raw server errors in
+ * $sieve->error_raw, and successful responses in $sieve->responses.
+ *
+ * NOTE: a major change since version (0.0.5) is the inclusion of a standard
+ * method to retrieve  server responses.  All functions will return either true
+ * or false and will fill in $sieve->error with a defined error code like
+ * EC_QUOTA, raw server errors in $sieve->error_raw, and successful responses
+ * in $sieve->responses.
+ *
+ * Usage is pretty simple.  The basics is login, do what you need and logout.
+ * There are two sample files (which suck) test.php and testsieve.php.
+ * test.php allows you to create/delete/view scripts and testsieve.php is a
+ * very basic sieve server test.
+ *
+ * Please let us know of any bugs, problems or ideas at sieve-php development
+ * list:  sieve-php-devel@lists.sourceforge.net. A web interface to subscribe
+ * to this list is available at:
+ * https://lists.sourceforge.net/mailman/listinfo/sieve-php-devel
+ *
+ * @author Dan Ellis
+ * @example simple_example.php A simple example that shows usage of sieve-php
+ * class.
+ * @example vacationset-sieve.php A more elaborate example of vacation script
+ * handling.
+ * @version 0.1.0
+ * @package sieve-php
+ * @todo Maybe add the NOOP function.
+ * @todo Have timing mechanism when port problems arise.
+ * @todo Provide better error diagnostics. 
+ */
+class sieve {
+  var $host;
+  var $port;
+  var $user;
+  var $pass;
+  /**
+   * a comma seperated list of allowed auth types, in order of preference
+   */
+  var $auth_types;
+  /**
+   * type of authentication attempted
+   */
+  var $auth_in_use;
+  
+  var $line;
+  var $fp;
+  var $retval;
+  var $tmpfile;
+  var $fh;
+  var $len;
+  var $script;
+
+  var $loggedin;
+  var $capabilities;
+  var $error;
+  var $error_raw;
+  var $responses;
+
+  //maybe we should add an errorlvl that the user will pass to new sieve = sieve(,,,,E_WARN)
+  //so we can decide how to handle certain errors?!?
+
+  /**
+   * get response
+   */
+  function get_response()
+  {
+    if($this->loggedin == false or feof($this->fp)){
+        $this->error = EC_NOT_LOGGED_IN;
+        $this->error_raw = "You are not logged in.";
+        return false;
+    }
+
+    unset($this->response);
+    unset($this->error);
+    unset($this->error_raw);
+
+    $this->line=fgets($this->fp,1024);
+    $this->token = split(" ", $this->line, 2);
+
+    if($this->token[0] == "NO"){
+        /* we need to try and extract the error code from here.  There are two possibilites: one, that it will take the form of:
+           NO ("yyyyy") "zzzzzzz" or, two, NO {yyyyy} "zzzzzzzzzzz" */
+        $this->x = 0;
+        list($this->ltoken, $this->mtoken, $this->rtoken) = split(" ", $this->line." ", 3);
+        if($this->mtoken[0] == "{"){
+            while($this->mtoken[$this->x] != "}" or $this->err_len < 1){
+                $this->err_len = substr($this->mtoken, 1, $this->x);
+                $this->x++;    
+            }
+            //print "<br>Trying to receive $this->err_len bytes for result<br>";
+            $this->line = fgets($this->fp,$this->err_len);
+            $this->error_raw[]=substr($this->line, 0, strlen($this->line) -2);    //we want to be nice and strip crlf's
+            $this->err_recv = strlen($this->line);
+
+            while($this->err_recv < $this->err_len){
+                //print "<br>Trying to receive ".($this->err_len-$this->err_recv)." bytes for result<br>";
+                $this->line = fgets($this->fp, ($this->err_len-$this->err_recv));
+                $this->error_raw[]=substr($this->line, 0, strlen($this->line) -2);    //we want to be nice and strip crlf's
+                $this->err_recv += strlen($this->line);
+            } /* end while */
+            $this->line = fgets($this->fp, 1024);	//we need to grab the last crlf, i think.  this may be a bug...
+            $this->error=EC_UNKNOWN;
+      
+        } /* end if */
+        elseif($this->mtoken[0] == "("){
+            switch($this->mtoken){
+                case "(\"QUOTA\")":
+                    $this->error = EC_QUOTA;
+                    $this->error_raw=$this->rtoken;
+                    break;
+                default:
+                    $this->error = EC_UNKNOWN;
+                    $this->error_raw=$this->rtoken;
+                    break;
+            } /* end switch */
+        } /* end elseif */
+        else{
+            $this->error = EC_UNKNOWN;
+            $this->error_raw = $this->line;
+        }     
+        return false;
+
+    } /* end if */
+    elseif(substr($this->token[0],0,2) == "OK"){
+         return true;
+    } /* end elseif */
+    elseif($this->token[0][0] == "{"){
+        
+        /* Unable wild assumption:  that the only function that gets here is the get_script(), doesn't really matter though */       
+
+        /* the first line is the len field {xx}, which we don't care about at this point */
+        $this->line = fgets($this->fp,1024);
+        while(substr($this->line,0,2) != "OK" and substr($this->line,0,2) != "NO"){
+            $this->response[]=$this->line;
+            $this->line = fgets($this->fp, 1024);
+        }
+        if(substr($this->line,0,2) == "OK")
+            return true;
+        else
+            return false;
+    } /* end elseif */
+    elseif($this->token[0][0] == "\""){
+
+        /* I'm going under the _assumption_ that the only function that will get here is the listscripts().
+           I could very well be mistaken here, if I am, this part needs some rework */
+
+        $this->found_script=false;        
+
+        while(substr($this->line,0,2) != "OK" and substr($this->line,0,2) != "NO"){
+            $this->found_script=true;
+            list($this->ltoken, $this->rtoken) = explode(" ", $this->line." ",2);
+		//hmmm, a bug in php, if there is no space on explode line, a warning is generated...
+           
+            if(strcmp(rtrim($this->rtoken), "ACTIVE")==0){
+                $this->response["ACTIVE"] = substr(rtrim($this->ltoken),1,-1);  
+            }
+            else
+                $this->response[] = substr(rtrim($this->ltoken),1,-1);
+            $this->line = fgets($this->fp, 1024);
+        } /* end while */
+        
+        return true;
+        
+    } /* end elseif */
+    else{
+            $this->error = EC_UNKNOWN;
+            $this->error_raw = $this->line;
+	    print '<b><i>UNKNOWN ERROR (Please report this line to <a
+	    href="mailto:sieve-php-devel@lists.sourceforge.net">sieve-php-devel
+	    Mailing List</a> to include in future releases):
+	    '.$this->line.'</i></b><br>';
+
+            return false;
+    } /* end else */   
+  } /* end get_response() */
+
+  /**
+   * Initialization of the SIEVE class.
+   * 
+   * It will return
+   * false if it fails, true if all is well.  This also loads some arrays up
+   * with some handy information:
+   *
+   * @param $host string hostname to connect to. Usually the IMAP server where
+   * a SIEVE daemon, such as timsieved, is listening.
+   *
+   * @param $port string Numeric port to connect to. SIEVE daemons usually
+   * listen to port 2000.
+   *
+   * @param $user string is a super-user or proxy-user that has ACL rights to
+   * login on behalf of the $auth.
+   *
+   * @param $pass string password to use for authentication
+   *
+   * @param $auth string is the authorized user identity for which the SIEVE
+   * scripts will be managed.
+   *
+   * @param $auth_types string a string containing all the allowed
+   * authentication types allowed in order of preference, seperated by spaces.
+   * (ex.  "PLAIN DIGEST-MD5 CRAM-MD5"  The method the library will try first
+   * is PLAIN.) The default for this value is PLAIN.
+   *
+   * Note: $user, if included, is the account name (and $pass will be the
+   * password) of an administrator account that can act on behalf of the user.
+   * If you are using Cyrus, you must make sure that the admin account has
+   * rights to admin the user.  This is to allow admins to edit/view users
+   * scripts without having to know the user's password.  Very handy.
+   */
+  function sieve($host, $port, $user, $pass, $auth="", $auth_types='PLAIN') {
+    $this->host=$host;
+    $this->port=$port;
+    $this->user=$user;
+    $this->pass=$pass;
+    if(!strcmp($auth, ""))		/* If there is no auth user, we deem the user itself to be the auth'd user */
+        $this->auth = $this->user;
+    else
+        $this->auth = $auth;
+    $this->auth_types=$auth_types;	/* Allowed authentication types */
+    $this->fp=0;
+    $this->line="";
+    $this->retval="";
+    $this->tmpfile="";
+    $this->fh=0;
+    $this->len=0;
+    $this->capabilities="";
+    $this->loggedin=false;
+    $this->error= "";
+    $this->error_raw="";
+  }
+
+   /**
+    * Tokenize a line of input by quote marks and return them as an array
+    *
+    * @param $string string Input line to parse for quotes
+    * @return array Array of broken by quotes parts of original string
+    */
+  function parse_for_quotes($string) {
+
+      $start = -1;
+      $index = 0;
+
+      for($ptr = 0; $ptr < strlen($string); $ptr++){
+          if($string[$ptr] == '"' and $string[$ptr] != '\\'){
+              if($start == -1){
+                  $start = $ptr;
+              } /* end if */
+              else{
+                  $token[$index++] = substr($string, $start + 1, $ptr - $start - 1);
+                  $found = true;
+                  $start = -1;
+              } /* end else */
+
+          } /* end if */  
+
+      } /* end for */
+
+      if(isset($token))
+          return $token;
+      else
+          return false;
+  } /* end function */            
+
+  /**
+   * Parser for status responses.
+   *
+   * This should probably be replaced by a smarter parser.
+   *
+   * @param $string string Input that contains status responses.
+   * @todo remove this function and dependencies
+   */
+  function status($string) {
+
+      /*  Need to remove this and all dependencies from the class */
+
+      switch (substr($string, 0,2)){
+          case "NO":
+              return F_NO;		//there should be some function to extract the error code from this line
+					//NO ("quota") "You are oly allowed x number of scripts"
+              break;
+          case "OK":
+              return F_OK;
+              break;
+          default:
+              switch ($string[0]){
+                  case "{":
+                      //do parse here for curly braces - maybe modify
+                      //parse_for_quotes to handle any parse delimiter?
+                      return F_HEAD;
+                      break;
+                  default:
+                      return F_DATA;
+                      break;
+              }
+        }
+  }
+  
+  /**
+   * Attemp to log in to the sieve server.
+   * 
+   * It will return false if it fails, true if all is well.  This also loads
+   * some arrays up with some handy information:
+   *
+   * capabilities["implementation"] contains the sieve version information
+   * 
+   * capabilities["auth"] contains the supported authentication modes by the
+   * SIEVE server.
+   * 
+   * capabilities["modules"] contains the built in modules like "reject",
+   * "redirect", etc.
+   * 
+   * capabilities["starttls"] , if is set and equal to true, will show that the
+   * server supports the STARTTLS extension.
+   * 
+   * capabilities["unknown"] contains miscellaneous/extraneous header info sieve
+   * may have sent
+   *
+   * @return boolean
+   */
+  function sieve_login() {
+    $this->fp=fsockopen($this->host,$this->port);
+    if($this->fp == false)
+        return false;
+
+    $this->line=fgets($this->fp,1024);
+    //Hack for older versions of Sieve Server.  They do not respond with the Cyrus v2. standard
+    //response.  They repsond as follows: "Cyrus timsieved v1.0.0" "SASL={PLAIN,........}"
+    //So, if we see IMLEMENTATION in the first line, then we are done.
+
+    if(ereg("IMPLEMENTATION",$this->line))
+    {
+      //we're on the Cyrus V2 sieve server
+      while(sieve::status($this->line) == F_DATA){
+
+          $this->item = sieve::parse_for_quotes($this->line);
+
+          if(strcmp($this->item[0], "IMPLEMENTATION") == 0)
+              $this->capabilities["implementation"] = $this->item[1];
+        
+          elseif(strcmp($this->item[0], "SIEVE") == 0 or strcmp($this->item[0], "SASL") == 0){
+
+              if(strcmp($this->item[0], "SIEVE") == 0)
+                  $this->cap_type="modules";
+              else
+                  $this->cap_type="auth";            
+
+              $this->modules = split(" ", $this->item[1]);
+              if(is_array($this->modules)){
+                  foreach($this->modules as $this->module)
+                      $this->capabilities[$this->cap_type][$this->module]=true;
+              } /* end if */
+              elseif(is_string($this->modules))
+                  $this->capabilites[$this->cap_type][$this->modules]=true;
+          }    
+          elseif(strcmp($this->item[0], "STARTTLS") == 0) {
+	          $this->capabilities['starttls'] = true;
+	  
+          }
+	  else{ 
+              $this->capabilities["unknown"][]=$this->line;
+          }    
+      $this->line=fgets($this->fp,1024);
+       }// end while
+    }
+    else
+    {
+        //we're on the older Cyrus V1. server  
+        //this version does not support module reporting.  We only have auth types.
+        $this->cap_type="auth";
+       
+        //break apart at the "Cyrus timsieve...." "SASL={......}"
+        $this->item = sieve::parse_for_quotes($this->line);
+
+        $this->capabilities["implementation"] = $this->item[0];
+
+        //we should have "SASL={..........}" now.  Break out the {xx,yyy,zzzz}
+        $this->modules = substr($this->item[1], strpos($this->item[1], "{"),strlen($this->item[1])-1);
+
+        //then split again at the ", " stuff.
+        $this->modules = split($this->modules, ", ");
+ 
+        //fill up our $this->modules property
+        if(is_array($this->modules)){
+            foreach($this->modules as $this->module)
+                $this->capabilities[$this->cap_type][$this->module]=true;
+        } /* end if */
+        elseif(is_string($this->modules))
+            $this->capabilites[$this->cap_type][$this->module]=true;
+    }
+
+
+
+
+    if(sieve::status($this->line) == F_NO){		//here we should do some returning of error codes?
+        $this->error=EC_UNKNOWN;
+        $this->error_raw = "Server not allowing connections.";
+        return false;
+    }
+
+    /* decision login to decide what type of authentication to use... */
+
+
+     /* Loop through each allowed authentication type and see if the server allows the type */
+     foreach(explode(" ", $this->auth_types) as $auth_type)
+     {
+        if ($this->capabilities["auth"][$auth_type])
+        {
+            /* We found an auth type that is allowed. */
+            $this->auth_in_use = $auth_type;
+        }
+     }
+    
+     /* call our authentication program */
+   
+    return sieve::authenticate();
+
+  }
+
+  /**
+   * Log out of the sieve server.
+   *
+   * @return boolean Always returns true at this point.
+   */
+  function sieve_logout() {
+    if($this->loggedin==false)
+        return false;
+
+    fputs($this->fp,"LOGOUT\r\n");
+    fclose($this->fp);
+    $this->loggedin=false;
+    return true;
+  }
+
+  /**
+   * Send the script contained in $script to the server.
+   *
+   * It will return any error results it finds (in $sieve->error and
+   * $sieve->error_raw), and return true if it is successfully sent.  The
+   * function does _not_ automatically make the script the active script.
+   *
+   * @param $scriptname string The name of the SIEVE script.
+   * @param $script The script to be uploaded.
+   * @return boolean Returns true if script has been successfully uploaded.
+   */
+  function sieve_sendscript($scriptname, $script) {
+    if($this->loggedin==false)
+        return false;
+    $this->script=stripslashes($script);
+    $len=strlen($this->script);
+    
+    //fputs($this->fp, "PUTSCRIPT \"$scriptname\" \{$len+}\r\n");
+    
+    fputs($this->fp, 'PUTSCRIPT "' . $scriptname . '" {' . $len . '+}' . "\r\n");
+    fputs($this->fp, "$this->script\r\n");
+  
+    return sieve::get_response();
+
+  }  
+  
+  /**
+   * Check if there is enough space for a script to be uploaded. 
+   *
+   * This function returns true or false based on whether the sieve server will
+   * allow your script to be sent and your quota has not been exceeded.  This
+   * function does not currently work due to a believed bug in timsieved.  It
+   * could be my code too.
+   *
+   * It appears the timsieved does not honor the NUMBER type.  see lex.c in
+   * timsieved src.  don't expect this function to work yet.  I might have
+   * messed something up here, too.
+   *
+   * @param $scriptname string The name of the SIEVE script.
+   * @param $scriptsize integer The size of the SIEVE script.
+   * @return boolean
+   * @todo Does not work; bug fix and test.
+   */
+  function sieve_havespace($scriptname, $scriptsize)   {
+    if($this->loggedin==false)
+        return false;
+    fputs($this->fp, "HAVESPACE \"$scriptname\" $scriptsize\r\n");
+    return sieve::get_response();
+  }  
+
+  /**
+   * Set the script active on the sieve server.
+   *
+   * @param $scriptname string The name of the SIEVE script.
+   * @return boolean
+   */
+  function sieve_setactivescript($scriptname)   {
+    if($this->loggedin==false)
+        return false;
+
+    fputs($this->fp, "SETACTIVE \"$scriptname\"\r\n");   
+    return sieve::get_response();
+
+  }
+  
+  /**
+   * Return the contents of the requested script.
+   * 
+   * If you want to display the script, you will need to change all CrLf to
+   * '.'.
+   *
+   * @param $scriptname string The name of the SIEVE script.
+   * @return arr SIEVE script data.
+   */
+  function sieve_getscript($scriptname) {
+    unset($this->script);
+    if($this->loggedin==false)
+        return false;
+
+    fputs($this->fp, "GETSCRIPT \"$scriptname\"\r\n");
+    return sieve::get_response();
+  }
+
+  /**
+   * Attempt to delete the script requested.
+   *
+   * If the script is currently active, the server will not have any active
+   * script after the deletion.
+   *
+   * @param $scriptname string The name of the SIEVE script.
+   * @return mixed
+   */
+  function sieve_deletescript($scriptname)   {
+    if($this->loggedin==false)
+        return false;
+
+    fputs($this->fp, "DELETESCRIPT \"$scriptname\"\r\n");    
+
+    return sieve::get_response();
+  }
+
+  
+  /**
+   * List available scripts on the SIEVE server.
+   *
+   * This function returns true or false.  $sieve->response will be filled
+   * with the names of the scripts found.  If a script is active, the
+   * $sieve->response["ACTIVE"] will contain the name of the active script.
+   *
+   * @return boolean
+   */
+  function sieve_listscripts() { 
+     fputs($this->fp, "LISTSCRIPTS\r\n"); 
+     sieve::get_response();		//should always return true, even if there are no scripts...
+     if(isset($this->found_script) and $this->found_script)
+         return true;
+     else{
+         $this->error=EC_NOSCRIPTS;	//sieve::getresponse has no way of telling wether a script was found...
+         $this->error_raw="No scripts found for this account.";
+         return false;
+     }
+   }
+
+
+  /**
+   * Check availability of connection to the SIEVE server.
+   *
+   * This function returns true or false based on whether the connection to the
+   * sieve server is still alive.
+   *
+   * @return boolean
+   */
+  function sieve_alive()   {
+      if(!isset($this->fp) or $this->fp==0){
+          $this->error = EC_NOT_LOGGED_IN;
+          return false;
+      }
+      elseif(feof($this->fp)){			
+          $this->error = EC_NOT_LOGGED_IN;
+          return false;
+      }
+      else
+          return true;
+  }
+
+  /**
+   * Perform SASL authentication to SIEVE server.
+   *
+   * Attempts to authenticate to SIEVE, using some SASL authentication method
+   * such as PLAIN or DIGEST-MD5.
+   *
+   */
+  function authenticate() {
+    switch ($this->auth_in_use) {
+
+        case "PLAIN":
+            $auth=base64_encode("$this->auth\0$this->user\0$this->pass");
+            $this->len=strlen($auth);
+			
+            fputs($this->fp, 'AUTHENTICATE "PLAIN" {' . $this->len . '+}' . "\r\n");
+            fputs($this->fp, "$auth\r\n");
+
+            $this->line=fgets($this->fp,1024);
+            while(sieve::status($this->line) == F_DATA)
+               $this->line=fgets($this->fp,1024);
+
+             if(sieve::status($this->line) == F_NO)
+               return false;
+             $this->loggedin=true;
+               return true;    
+	    break;
+	
+        case "DIGEST-MD5":
+	     // SASL DIGEST-MD5 support works with timsieved 1.1.0
+	     // follows rfc2831 for generating the $response to $challenge
+	     fputs($this->fp, "AUTHENTICATE \"DIGEST-MD5\"\r\n");
+	     // $clen is length of server challenge, we ignore it. 
+	     $clen = fgets($this->fp, 1024);
+	     // read for 2048, rfc2831 max length allowed
+	     $challenge = fgets($this->fp, 2048);
+	     // vars used when building $response_value and $response
+	     $cnonce = base64_encode(bin2hex(hmac_md5(microtime())));
+	     $ncount = "00000001";
+	     $qop_value = "auth"; 
+	     $digest_uri_value = "sieve/$this->host";
+	     // decode the challenge string
+	     $result = decode_challenge($challenge);
+	     // verify server supports qop=auth 
+	     $qop = explode(",",$result['qop']);
+	     if (!in_array($qop_value, $qop)) {
+	        // rfc2831: client MUST fail if no qop methods supported
+	        return false;
+	     }
+	     // build the $response_value
+	     $string_a1 = utf8_encode($this->user).":";
+	     $string_a1 .= utf8_encode($result['realm']).":";
+	     $string_a1 .= utf8_encode($this->pass);
+	     $string_a1 = hmac_md5($string_a1);
+	     $A1 = $string_a1.":".$result['nonce'].":".$cnonce.":".utf8_encode($this->auth);
+	     $A1 = bin2hex(hmac_md5($A1));
+	     $A2 = bin2hex(hmac_md5("AUTHENTICATE:$digest_uri_value"));
+	     $string_response = $result['nonce'].":".$ncount.":".$cnonce.":".$qop_value;
+	     $response_value = bin2hex(hmac_md5($A1.":".$string_response.":".$A2));
+	     // build the challenge $response
+	     $reply = "charset=utf-8,username=\"".$this->user."\",realm=\"".$result['realm']."\",";
+	     $reply .= "nonce=\"".$result['nonce']."\",nc=$ncount,cnonce=\"$cnonce\",";
+	     $reply .= "digest-uri=\"$digest_uri_value\",response=$response_value,";
+	     $reply .= "qop=$qop_value,authzid=\"".utf8_encode($this->auth)."\"";
+	     $response = base64_encode($reply);
+	     fputs($this->fp, "\"$response\"\r\n");
+ 	
+             $this->line = fgets($this->fp, 1024);
+             while(sieve::status($this->line) == F_DATA)
+                $this->line = fgets($this->fp,1024);
+
+             if(sieve::status($this->line) == F_NO)
+               return false;
+             $this->loggedin = TRUE;
+               return TRUE;    
+             break;
+	
+        case "CRAM-MD5":
+  	     // SASL CRAM-MD5 support works with timsieved 1.1.0
+	     // follows rfc2195 for generating the $response to $challenge
+	     // CRAM-MD5 does not support proxy of $auth by $user
+	     // requires php mhash extension
+	     fputs($this->fp, "AUTHENTICATE \"CRAM-MD5\"\r\n");
+	     // $clen is the length of the challenge line the server gives us
+	     $clen = fgets($this->fp, 1024);
+	     // read for 1024, should be long enough?
+	     $challenge = fgets($this->fp, 1024);
+	     // build a response to the challenge
+	     $hash = bin2hex(hmac_md5(base64_decode($challenge), $this->pass));
+	     $response = base64_encode($this->user." ".$hash);
+	     // respond to the challenge string
+	     fputs($this->fp, "\"$response\"\r\n");
+	     
+             $this->line = fgets($this->fp, 1024);		
+             while(sieve::status($this->line) == F_DATA)
+                $this->line = fgets($this->fp,1024);
+
+             if(sieve::status($this->line) == F_NO)
+               return false;
+             $this->loggedin = TRUE;
+               return TRUE;    
+             break;
+
+	case "LOGIN":
+ 	     $login=base64_encode($this->user);
+ 	     $pass=base64_encode($this->pass);
+ 	
+ 	     fputs($this->fp, "AUTHENTICATE \"LOGIN\"\r\n");
+ 	     fputs($this->fp, "{".strlen($login)."+}\r\n");
+ 	     fputs($this->fp, "$login\r\n");
+ 	     fputs($this->fp, "{".strlen($pass)."+}\r\n");
+ 	     fputs($this->fp, "$pass\r\n");
+ 
+	     $this->line=fgets($this->fp,1024);
+ 	     while(sieve::status($this->line) == F_HEAD ||
+ 	           sieve::status($this->line) == F_DATA)
+ 	         $this->line=fgets($this->fp,1024);
+ 	
+ 	     if(sieve::status($this->line) == F_NO)
+ 	         return false;
+ 	     $this->loggedin=true;
+ 	     return true;
+ 	     break;
+
+        default:
+            echo 'default';
+            return false;
+            break;
+
+    }//end switch
+  }
+
+  /**
+   * Return an array of available capabilities.
+   *
+   * @return array
+   */
+  function sieve_get_capability() {
+    if($this->loggedin==false)
+        return false;
+    fputs($this->fp, "CAPABILITY\r\n"); 
+    $this->line=fgets($this->fp,1024);
+
+    //Hack for older versions of Sieve Server.  They do not respond with the Cyrus v2. standard
+    //response.  They repsond as follows: "Cyrus timsieved v1.0.0" "SASL={PLAIN,........}"
+    //So, if we see IMLEMENTATION in the first line, then we are done.
+
+    if(ereg("IMPLEMENTATION",$this->line))
+    {
+      //we're on the Cyrus V2 sieve server
+      while(sieve::status($this->line) == F_DATA){
+
+          $this->item = sieve::parse_for_quotes($this->line);
+
+          if(strcmp($this->item[0], "IMPLEMENTATION") == 0)
+              $this->capabilities["implementation"] = $this->item[1];
+        
+          elseif(strcmp($this->item[0], "SIEVE") == 0 or strcmp($this->item[0], "SASL") == 0){
+
+              if(strcmp($this->item[0], "SIEVE") == 0)
+                  $this->cap_type="modules";
+              else
+                  $this->cap_type="auth";            
+
+              $this->modules = split(" ", $this->item[1]);
+              if(is_array($this->modules)){
+                  foreach($this->modules as $this->module)
+                      $this->capabilities[$this->cap_type][$this->module]=true;
+              } /* end if */
+              elseif(is_string($this->modules))
+                  $this->capabilites[$this->cap_type][$this->modules]=true;
+          }    
+          else{ 
+              $this->capabilities["unknown"][]=$this->line;
+          }    
+      $this->line=fgets($this->fp,1024);
+
+       }// end while
+    }
+    else
+    {
+        //we're on the older Cyrus V1. server  
+        //this version does not support module reporting.  We only have auth types.
+        $this->cap_type="auth";
+       
+        //break apart at the "Cyrus timsieve...." "SASL={......}"
+        $this->item = sieve::parse_for_quotes($this->line);
+
+        $this->capabilities["implementation"] = $this->item[0];
+
+        //we should have "SASL={..........}" now.  Break out the {xx,yyy,zzzz}
+        $this->modules = substr($this->item[1], strpos($this->item[1], "{"),strlen($this->item[1])-1);
+
+        //then split again at the ", " stuff.
+        $this->modules = split($this->modules, ", ");
+ 
+        //fill up our $this->modules property
+        if(is_array($this->modules)){
+            foreach($this->modules as $this->module)
+                $this->capabilities[$this->cap_type][$this->module]=true;
+        } /* end if */
+        elseif(is_string($this->modules))
+            $this->capabilites[$this->cap_type][$this->module]=true;
+    }
+
+    return $this->modules;
+  }
+
+}
+
+
+/**
+ * The following functions are support functions and might be handy to the
+ * sieve class.
+ */
+
+if(!function_exists('hmac_md5')) {
+
+/**
+ * Creates a HMAC digest that can be used for auth purposes.
+ * See RFCs 2104, 2617, 2831
+ * Uses mhash() extension if available
+ *
+ * Squirrelmail has this function in functions/auth.php, and it might have been
+ * included already. However, it helps remove the dependancy on mhash.so PHP
+ * extension, for some sites. If mhash.so _is_ available, it is used for its
+ * speed.
+ *
+ * This function is Copyright (c) 1999-2003 The SquirrelMail Project Team
+ * Licensed under the GNU GPL. For full terms see the file COPYING.
+ *
+ * @param string $data Data to apply hash function to.
+ * @param string $key Optional key, which, if supplied, will be used to
+ * calculate data's HMAC.
+ * @return string HMAC Digest string
+ */
+function hmac_md5($data, $key='') {
+    // See RFCs 2104, 2617, 2831
+    // Uses mhash() extension if available
+    if (extension_loaded('mhash')) {
+      if ($key== '') {
+        $mhash=mhash(MHASH_MD5,$data);
+      } else {
+        $mhash=mhash(MHASH_MD5,$data,$key);
+      }
+      return $mhash;
+    }
+    if (!$key) {
+         return pack('H*',md5($data));
+    }
+    $key = str_pad($key,64,chr(0x00));
+    if (strlen($key) > 64) {
+        $key = pack("H*",md5($key));
+    }
+    $k_ipad =  $key ^ str_repeat(chr(0x36), 64) ;
+    $k_opad =  $key ^ str_repeat(chr(0x5c), 64) ;
+    /* Heh, let's get recursive. */
+    $hmac=hmac_md5($k_opad . pack("H*",md5($k_ipad . $data)) );
+    return $hmac;
+}
+}
+
+/**
+ * A hack to decode the challenge from timsieved 1.1.0.
+ * 
+ * This function may not work with other versions and most certainly won't work
+ * with other DIGEST-MD5 implentations
+ *
+ * @param $input string Challenge supplied by timsieved.
+ */
+function decode_challenge ($input) {
+    $input = base64_decode($input);
+    preg_match("/nonce=\"(.*)\"/U",$input, $matches);
+    $resp['nonce'] = $matches[1];
+    preg_match("/realm=\"(.*)\"/U",$input, $matches);
+    $resp['realm'] = $matches[1];
+    preg_match("/qop=\"(.*)\"/U",$input, $matches);
+    $resp['qop'] = $matches[1];
+    return $resp;
+}
+
+// vim:ts=4:et:ft=php
+
+?>
