Login   Register  
PHP Classes
elePHPant
Icontem

File: cIMSPABook.php

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of Michael Rubinsky  >  IMSP Client Classes  >  cIMSPABook.php  >  Download  
File: cIMSPABook.php
Role: ???
Content type: text/plain
Description: IMSPAddressBook class Description. Provides the means for working with IMSP Addressbooks
Class: IMSP Client Classes
Deprecated classes for dealing with IMSP servers.
Author: By
Last change:
Date: 2002-04-17 21:48
Size: 35,560 bytes
 

Contents

Class file image Download
<?php
 /******************************************************************************************************
 * Project: PHP IMSP CLIENT LIBRARY 
 * File: cIMSPABook.PHP
 * Purpose: This file provides the means to work with IMSP ADDRESSBOOKS
 *
 * Copyright 2002 Michael Rubinsky <mike@theupstairsroom.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *
 * The file "IMSPStream.PHP" must be present in the same directory for this to work
 * since this class extends the IMSPStream Class
 *
 *
 ********************************************************************************************************
 *IMPLEMENTATION STATUS:
 *	GENERAL
 *		-LOGIN-----------------------------DONE (Done with the plaintext LOGIN command)
 *		-LOGOUT----------------------------DONE									
 *	ADDRESSBOOKS
 *		-ADDRESSBOOK-----------------------DONE
 *		-CREATEADDRESSBOOK-----------------DONE
 *		-DELETEADDRESSBOOK-----------------DONE
 *		-RENAMEADDRESSBOOK-----------------DONE
 *		-SEARCHADDRES----------------------DONE
 *		-FETCHADDRESS----------------------DONE
 *		-STOREADDRESS----------------------DONE
 *		-DELETEADDRESS---------------------DONE
 *	LOCKING
 *		-LOCKADDRESSBOOK-------------------DONE
 *		-UNLOCKADDRESSBOOK-----------------DONE
 *	ACL
 *		-SETACL ADDRESSBOOK----------------DONE
 *		-DELETEACL ADDRESSBOOK-------------DONE
 *		-GETACL ADDRESSBOOK----------------DONE
 *		-MYRIGHTS ADDRESSBOOK--------------DONE
 *******************************************************************************************************
 * Change Log:
 *  4/17/02: mjr Version 1.12
 *		
 *		-Fixed a bug that caused the getAddressBookList() method to hang under some circumstances.  This was
 *		 due to an attempt to read from the imsp stream an extra time.
 *	
 *		-Fixed an error where the addAddress() method would fail if any of the fields contained a \t (tab)
 *		 Fixed it by causing tabs within the text to be converted to CRLF and removing all trailing whitespace.
 *		 		
 *      -Fixed an error where locking a non-existing entry would fail which would also cause adding a NEW
 *		 entry to fail since addAddress() attempts to lock the entry in case we are simply updating it.
 *
 *		-Added support for ACL and MYRIGHTS commands
 *		-Improved error handling hooks to make use of the imspError() method calls available in parent class.
 *		-Released this project under the GNU GPL License.
 *		
 *  3/31/02:mjr
 *
 * 		-Changed getAddressBookList(), searchAddressBook() to use the new imspSend() and imspRecieve() methods
 *		 of the parent IMSPStream object.
 *
 *		-Changed addAddress() function to attempt to acquire a lock on the addressbook entry in case
 *	  	 we are updating an entry
 *
 * 3/29/02: mjr
 *		-Added support for the UNLOCK ADDRESSBOOK functionality
 *		-Added support for the RENAMEADDRESSBOOK functionality
 *		-Added support for the DELETEADDRESS functionality
 *		-Made changes to support the new, more efficient imspRecieve() return values
 *		
 * 3/27/02: mjr
 *		-Added support for the LOCK ADDRESSBOOK and STOREADDRESS functionality
 ********************************************************************************************************
 *Example of use:
 *
 *	$myABook = new IMSPAddressBook([imsp_server_name],[port]);      //Create an instance (if no server/port is passed, then it 
 *																	//defaults to localhost 406
 *	$myABook->logging = TRUE;										//Turn logging on or off (on by default)
 *  $myABook->log_level = 1;										//Level 1(default)= normal logging Level 2 will show entire client/server dialog (except for the LOGIN command)
 *  $myABook->log_name = "path_to_log_file"	;						//note that this directory will have to be writable by the web server (nobody)
 *  $myABook->logon("username","password");							//Note that password is plaintext.
 *	
 *  $entry = $myABook->getAddressBookEntry("abookName","entryName"); 
 *	.
 *  .
 *  .
 *  $myABook->logout();
 *
 ******************************************************************************************************
 *See the sample files for examples on how to use this class or look at the comments in the function
 *headers for more information.
 *****************************************************************************************************/
 
 //Include the parent Class description
 require("cIMSPStream.php");

//These define regExp that should match the respective server response strings
define ("IMSP_ADDRESSBOOK_RESPONSE","^\* ADDRESSBOOK");
define ("IMSP_SEARCHADDRESS_RESPONSE","^\* SEARCHADDRESS");
define ("IMSP_FETCHADDRESS_RESPONSE","^\* FETCHADDRESS");
define ("IMSP_ACL_RESPONSE","^\* ACL ADDRESSBOOK");
define ("IMSP_MYRIGHTS_RESPONSE","^\* MYRIGHTS ADDRESSBOOK");

//string of supported ACL rights
define ("IMSP_ACL_RIGHTS","lrwcda");

									
class IMSPAddressBook extends IMSPStream {
 
 // Method Definitions
 
 /***************************************************************************************
  *Contructor Function
 /***************************************************************************************/
 function IMSPAddressBook($local_imsp_server="", $local_port="") {
 	
	//Simply delegate this method to the parent.
	if (!$this->IMSPStream($local_imsp_server,$local_port)) {
		//login failure...the parent class will handle these errors.
		return FALSE;
	} else {
		return TRUE;
	}
} 	
 	


/****************************************************************************************
 *getAddressBookList() - Returns an array containing the names of all the addressbooks
 *available to the logged in user.
 *
 *TODO: Perform checking of returned tag response after the ADDRESSBOOK list is finished 
 *being sent to ensure everything finished 'OK'
 *****************************************************************************************/
function getAddressBookList() {
	
		$command_string = "ADDRESSBOOK *";											//Build the command.
		
		if (!$this->imspSend($command_string)) {
				$this->imspError($command_string);
				return FALSE;	
		} 
			
			//iterate through the response and populate an array of addressbook names
			$server_response = $this->imspRecieve();
			
			while (ereg(IMSP_ADDRESSBOOK_RESPONSE,$server_response)){
				
				/*************************************************************************************
				 *If this is a ADDRESSBOOK response, then this will split the resonse into the
				 *
				 * [0] and [1] can be discarded
				 * [2] = attributes
				 * [3] = delimiter
				 * [4] = addressbook name
				 **************************************************************************************/
				$entry = split(" ",$server_response);
				$abooks[] = $entry[4];							//Store it in the array to return later				
				$server_response = $this->imspRecieve();	
			}
			
			if ($server_response != "OK") {
				$this->exitCode = IMSP_EXIT_UNEXPECTED_RESPONSE;
				$this->imspError("Error in getAddressBookList() call");
				return FALSE;
			}
			
			
			if ($this->log_stream) {
 				$this->write_to_log("ADDRESSBOOK command OK.");
 			}
 			
			return $abooks;		
	
}

/****************************************************************************************
 *searchAddressBook() - returns an array containing the names that
 *match $search critera in the addressbook named $abook
 *
 *TODO: Check for the server's response tag to make sure it matches and finished 'OK'
 ***************************************************************************************/
function searchAddressBook($abook,$search){
	
		
		$command_text = "SEARCHADDRESS $abook name \"$search\"";
		
		if (!$this->imspSend($command_text)) {
			//Something is wrong!
			$this->imspError($command_text);
			return FALSE;
		} 
			
		$list_complete = FALSE;
		while (!$list_complete){
			$server_response = $this->imspRecieve();
			//$server_response=fgets($this->stream,IMSP_DEFAULT_RESPONSE_LENGTH);
						
			if(ereg(IMSP_SEARCHADDRESS_RESPONSE,$server_response)) {
				$chopped_response = ereg_replace(IMSP_SEARCHADDRESS_RESPONSE,"",$server_response);		//Remove any lingering white space in front or behind.
				$chopped_response = ereg_replace("\"","",$chopped_response);							//Get rid of any lingering quotes.
				$abookNames[] = trim($chopped_response);
			} else{
				$list_complete = TRUE;
				break;
			}
		}
		
		//Should check for OK or BAD here just to be certain...
		
		if($this->log_stream) {
			$this->write_to_log("SEARCHADDRESS command OK");
		}
				
		return $abookNames;
		
	
}

/****************************************************************************************************
 * getAddressBookEntry() - Returns an associative array containing key - values pairs that corespond
 * to the addressbook fields and values.  Note that there will always be a "name" entry and also note
 * that the resulting values may need to be escaped for display in a web browser becuase they may 
 * contain email addresses in the form :: myName <myname@somewhere.com> 
 *****************************************************************************************************/

function getAddressBookEntry($abook,$name){
	
	$command_text = "FETCHADDRESS $abook \"$name\"";										//Build the command string
	
	if (!$this->imspSend($command_text,TRUE,TRUE)) {										//Send the command
		$this->imspError($command_text);
		return FALSE;
	}
	
	$server_response = $this->imspRecieve();												//Retrieve server response
	
	//Should allow for a "BAD" or "NO" response here as well.
		//
		//
	$entry = $this->parseFetchAddressResponse($server_response);							//Get the data in an associative array
	
	
	//Get the next server response -- this should be the OK response.
	//$server_response = fgets($this->stream,IMSP_DEFAULT_RESPONSE_LENGTH);
	$server_response = $this->imspRecieve();
	
	
	if(!$server_response == "OK"){
		//Unexpected response
		$this->exitCode = IMSP_NOT_EXPECTED_RESPONSE;
		$this->imspError();
	}
	
	if ($this->log_stream) {
		$this->write_to_log("FETCHADDRESS completed OK");
	}
	
	return $entry;
				
}

/****************************************************************************************************
* Creates a new addressbook.  Takes the name of the new book. Note that this should be the 
* FULLY QUALIFIED heirarchy such as "jdoe.public" or "jdoe.clients" etc...
/****************************************************************************************************/
function createAddressBook($abookName){
	$command_text = "CREATEADDRESSBOOK $abookName";								//create the command to send

	if(!$this->imspSend($command_text)){										//send the command and test for failure
		//something failed
		$this->imspError($command_text);
		return FALSE;
	}
	
	
	$server_response = $this->imspRecieve();									//recieve the results from the server
	
	if(!$server_response){														//and check for failure
		//response did not come
		$this->imspError($command_text);
		return FALSE;
	}
	
	switch ($server_response) {
		case "OK":
			$this->exitCode = IMSP_EXIT_OK;
		
			if ($this->log_stream) {
				$this->write_to_log("CREATEADDRESSBOOK completed OK");
			}

			return TRUE;															//report success!
		
		case "NO":
			//Could not create abook
			$this->exitCode = IMSP_EXIT_BAD_MAILBOX_NAME;
			$this->imspError();
			return FALSE;
		
		case "BAD":
			$this->imspError();
			return FALSE;
		
		
		default:
			//something unexpected!
			$this->exitCode = IMSP_EXIT_UNEXPECTED_RESPONSE;
			$this->imspError($server_response);
			return FALSE;
	}
		
}

/****************************************************************************************************
* Deletes an addressbook completely!  Returns true or false.
*
/****************************************************************************************************/
function deleteAddressBook($abookName) {
	
	$command_text = "DELETEADDRESSBOOK $abookName" ;
	
	if(!$this->imspSend($command_text)){										//send the command and test for failure
		//something failed
		$this->imspError($command_text);
		return FALSE;
	}
	
	$server_response = $this->imspRecieve();									//recieve the results from the server
	
	if(!$server_response){														//and check for failure
		//response did not come
		$this->imspError($command_text);
		return FALSE;
	}
	
	switch ($server_response) {
		case "OK":
			$this->exitCode = IMSP_EXIT_OK;
		
			if ($this->log_stream) {
				$this->write_to_log("DELETEADDRESSBOOK completed OK");
			}

			return TRUE;															//report success!
		
		case "NO":
			//Could not DELETE abook
			$this->exitCode = IMSP_EXIT_BAD_MAILBOX_NAME;
			$this->imspError("Addressbook name: $abookName");
			return FALSE;
		
		case "BAD":
			$this->imspError();
			return FALSE;
		
		
		default:
			//something unexpected!
			$this->exitCode = IMSP_EXIT_UNEXPECTED_RESPONSE;
			$this->imspError($server_response);
			return FALSE;
	}
}
/****************************************************************************************************
* Renames an addressbook.  Takes the Oldname and the NewName 
* Returns true or false.
/****************************************************************************************************/
function renameAddressBook($abookOldName, $abookNewName) {

	//make sure the new name is OK
	if (ereg(" ",$abookNewName)) {
		//spaces in names of abooks not valid?
		$this->exitCode = IMSP_SYNTAX_ERROR;
		return FALSE;
	}
	
	$command_text = "RENAMEADDRESSBOOK $abookOldName $abookNewName";				//build the command
	
	if (!$this->imspSend($command_text,TRUE,TRUE))	{
		//Something wrong with sending command
		$this->imspError($command_text);
		return FALSE;
	}
	
	$server_response = $this->imspRecieve();										//Get server response
	
	switch ($server_response) {
		case "NO":
			//sorry, can't do it...maybe the addressbook doesnot exist or the new name is taken already
			$this->imspError("Perhapes the addressbook $abookOldName doesn't exist or $abookNewName is already taken.");
			return FALSE;
			
		case "BAD":
			//Syntax prob
			$this->imspError($command_text);
			return FALSE;
			
		case "OK":
			if ($this->log_stream) {
				$this->write_to_log("Addressbook $abookOldName successfully changed to $abookNewName");
			}
			return TRUE;
		
		default:
			//something unexpected
			$this->exitCode = IMSP_NOT_EXPECTED_RESPONSE;
			$this->imspError();
			return FALSE;
	}		

}


/****************************************************************************************************
* 
*	$entryInfo should be an associative array containing the entry field names.
*	 there MUST be a KEY named "name" that contains the name of the entry in the abook.
/****************************************************************************************************/

function addAddress($abook,$entryInfo) {
	
	//$entryInfo must be an array
	if (getType($entryInfo) != "array") {
		
		//if ($this->log_stream) {
			//$this->write_to_log("[CLIENT ERROR] $entryInfo argument must be an array");
		//}
		
		$this->exitCode = IMSP_EXIT_BAD_ARGUEMENT;
		$this->imspError("In method ->addAddress() \$entryInfo must be an array.");
		return FALSE;
	}
	
	//First, we should lock the entry if it already exists
	if (!$this->lockABook($abook,$entryInfo["name"])) {
		//Could not obtain a lock on this entry.
		//Error codes would have been dealt with already in the lockABook() call.
		return FALSE;
	}
	
	
	//Start building the command string
	$entryName = "\"" . $entryInfo["name"] . "\"";
	
	$command_text = "STOREADDRESS $abook $entryName ";
	
	//start sending the stream (include a new tag, but don't end with CRLF)
	$this->imspSend($command_text,TRUE,FALSE);
	
	$command_text ="";
	
	while (list($key,$value) = each($entryInfo)) {
	
		//Do not sent the key name "name"
		
		if ($key != "name") {														
			
			//Protect from extraneous white space
			$value = trim($value);
			
			//For some reason, tabs seem to break this so we should replace them with spaces?
			$value = ereg_replace("\t","\n\r",$value);
			
			//Check for CR to see if we need {}
			if (ereg("[\n\r]",$value)){
				$literalString = $value;
				$command_text .= $key . " {" . strlen($literalString) . "}";
				$this->imspSend($command_text,FALSE,TRUE);								//send what we have so far with the octet count at the end
				$server_response = $this->imspRecieve();								//hopefully this will be "+";
				
				$command_text = "";														//Clear the command_text buffer
				
				if (!ereg(IMSP_COMMAND_CONTINUATION_RESPONSE,$server_response)) {
					//not expected
					$this->exitCode = IMSP_EXIT_UNEXPECTED_RESPONSE;
					$this->imspError($server_response);
					return FALSE;
				}
				
				//Send the string of octets and be sure to end with CRLF
				$this->imspSend($literalString,FALSE,FALSE);								//Now send the string literal	
				
			} else {
				//If we are here, then we don't need to send a string literal (yet)
				 
				 
				 
				//check for spaces (do we need to enclose in quotes?)		
				if (ereg(" ",$value)) {
					$value = "\"" . $value . "\"";
				}
		
				 $command_text .= $key . " " . $value . " ";								
			}
		}
			
	} //End while
	
	//Send anything that is left of the command
	
	if (!$this->imspSend($command_text,FALSE,TRUE)) {
		//trouble sending command.
		$this->imspError();
		return FALSE;
	}
	
	//Check on success
	$server_response = $this->imspRecieve();
	
	
	//Decide on the response...
	switch ($server_response) {
		case "NO":
			//Sorry...can't do it.
			$this->imspError("Can not add the requested address.");
			return FALSE;
			
		case "BAD":
			//Sorry...didn't understand you
			$this->imspError($command_text);
			return FALSE;
	}
	
	if ($server_response != "OK") {
		//Cyrus-IMSP server sends a FETCHADDRESS Response here.  Do others?	This was not in the RFC.
		$dummy_array = $this->parseFetchAddressResponse($server_response);									//Should we keep this info?
		$server_response = $this->imspRecieve();															//Is there more?
														
		
		//Check it again
		switch ($server_response) {
			case "NO":
				//Sorry..can't do it
				$this->imspError("Can not add the requested address.");
				return FALSE;
			case "BAD":
				//Don't know what your talking about
				$this->imspError($command_text);
				return FALSE;
			case "OK":
				//everything is ok!!
			
				if ($this->log_stream) {
					$this->write_to_log("STOREADDRESS Completed successfully.");
				}
				
				
				//we were successful...so release the lock on the entry
				if (!$this->unlockABook($abook,$entryInfo["name"])) {
					//could not release lock
					$this->exitCode = IMSP_ENTRY_LOCKED;
					$this->imspError();
					return FALSE;
				}
				
				return TRUE;
		}
	}
}


/****************************************************************************************************
* Deletes an abook entry.  Takes the name of the abook and the name of the entry ($bookEntry)
* Returns true / false
/****************************************************************************************************/
function deleteAddress($abook,$bookEntry) {
	
	$bookEntry = $this->quoteSpacedString($bookEntry);					//Get it quoted if it contains spaces
	$command_text = "DELETEADDRESS $abook $bookEntry";					//Build the command;
	
	if (!$this->imspSend($command_text)) {
		//Something wrong
		$this->imspError($command_text);
		return FALSE;
	}
	
	$server_response = $this->imspRecieve();
	
	switch ($server_response) {
		case "NO":
			//Sorry..can't do it
			$this->imspError($command_text);
			return FALSE;
		case "BAD":
			//Don't know what your talking about
			$this->imspError($command_text);
			return FALSE;
		case "OK":
			//everything is ok!!
			
			if ($this->log_stream) {
				$this->write_to_log("DELETE Completed successfully.");
			}
	
			return TRUE;
	}

}

/****************************************************************************************************
* function lockABook - attempts to acquire a semephore on the addressbook entry, $bookEntry in 
* addressbook $abook.  Will return TRUE || $dummy on success.  Will return FALSE on failure.
*****************************************************************************************************/
function lockABook($abook,$bookEntry) {
	 
	 $bookEntry = $this->quoteSpacedString($bookEntry);
	 
	 $command_text = "LOCK ADDRESSBOOK $abook $bookEntry";
	 
	 if (!$this->imspSend($command_text)) {
	 	//problem!
	 	$this->imspError($command_text);
	 	return false;
	 }
	 
	 $server_response = $this->imspRecieve();
	
	 do  {
		 switch($server_response) {
		 	case "NO":
		 		//Could not acquire lock..maybe someone else has it....we should report this in future versions.
		 		$this->exitCode = IMSP_ENTRY_LOCKED;
		 		$this->imspError();
		 		return FALSE;
		 	case "BAD":
		 		//Syntax problem
		 		$this->imspError();
		 		return FALSE;
		 }
	
	
		//Check to see if this is a FETCHADDRESS resonse
		//Do all IMSP implementations return a FETCHADDRESS here?
		$dummy = $this->parseFetchAddressResponse($server_response);
		
		
		//If there was an entry, it will return a FETCHADDRESS response, which we will just
		//toss out and get the next server_response.
		if ($dummy) {
			$server_response = $this->imspRecieve();
		}
		
		
		
	} while($server_response != "OK");
	
	//tell the log.
	if ($this->log_stream) {
		$this->write_to_log("LOCK ADDRESSBOOK on $abook $bookEntry OK");
	}
	
	if (!$dummy) {
		return true;
	} else {
		return $dummy;
	}

}


/****************************************************************************************************
* Unlocks a previously locked abook.  Takes the name of the addressbook and the name of the entry.
* Returns True or False on success or failure.
/****************************************************************************************************/
function unlockABook($abook,$bookEntry) {
	
	$bookEntry = $this->quoteSpacedString($bookEntry);			//Quote the entry name if needed
	$command_text = "UNLOCK ADDRESSBOOK $abook $bookEntry";		//Build the command string
	
	if (!$this->imspSend($command_text,TRUE,TRUE)) {				//...and send it.
		//Problem
		$this->imspError($command_text);
		return FALSE;
	}
	
	$response = $this->imspRecieve();
	//echo $response;
	switch ($response) {
	
		case "NO":
			//Could not release the lock for some strange reason...maybe we don't own it?
			$this->imspError("Could not release the lock...perhaps we are not the owner of the lock.");
			return FALSE;
		case "BAD":
			//Some type of syntax error
			$this->imspError();
			return FALSE;
		case "OK":
			//Tell the log
		if ($this->log_stream) {
			$this->write_to_log("UNLOCK ADDRESSBOOK on $abook $bookEntry OK");
		}
		
		return TRUE;
	}
}		

/****************************************************************************************************
* Access Control List (ACL)  Methods.
*  
* The following characters are recognized ACL characters: lrwcda
* l - "lookup" 	(allows user to see the name and existence of the addressbook)
* r - "read" 	(allows searching and retreiving addresses from addressbook)
* w - "write"	(allows creating/editing new addressbook entries - not deleting)
* c - "create"  (allows creating new addressbooks under the current addressbook hierarchy)
* d - "delete"  (may delete entries or entire book)
* a - "admin"   (privledge to set ACL lists for this addressbook - usually only allowed for the owner of the addressbook)
*
*examples:
* "lr" would be read only for that user
* "lrw" would be read/write
****************************************************************************************************/


/****************************************************************************************************
* Sets an Access Control List for an abook.
* takes the abook name, the username ($ident) and a string containing the ACL characters ($acl)
* The ACL string should be a standard ACL type listing of characters such as "lrw" for read/write
/****************************************************************************************************/

function setACL($abook,$ident,$acl) {
	
	//Verify that $acl looks good...
	if (ereg("[^" . IMSP_ACL_RIGHTS . "]",$acl)) {
		//error...acl list contained unrecoginzed options
		$this->exitCode = IMSP_BAD_ARGUMENT;
		$this->imspError("the setACL() method only accepts the following characters in the ACL " . IMSP_ACL_RIGHTS . ".");
		return FALSE;
	}
	
		
	$command_text = "SETACL ADDRESSBOOK $abook $ident $acl";
	
	if(!$this->imspSend($command_text)) {
		//problem
		$this->imspError($command_text);
		return FALSE;
	}
	
	$response = $this->imspRecieve();
	
	switch ($response) {
		case "NO":
			//Could not set ACL
			$this->imspError("$ident ACL could not be set for addressbook $abook");
			return FALSE;
		case "BAD":
			//Bad syntax
			$this->imspError();
			return FALSE;
		case "OK":
			//COOL!!
			return TRUE;
		default:
			//don't know why we would make it down here, so return FALSE for now
			$this->exitCode = IMSP_EXIT_UNEXPECTED_RESPONSE;
			$this->imspError();
			return FALSE;
	}
	


}


/****************************************************************************************************
* Retrieves an addressbook's ACL. 
* This function returns an associatve array containing the name of the user as the key and the
* ACL string as the value so you would get an array such as this:
*
* $result['jsmith'] = "lrw"
* $result['jdoe'] = "r"
/****************************************************************************************************/


function getACL($abook) {	
	$command_text = "GETACL ADDRESSBOOK $abook";
	
	if (!$this->imspSend($command_text,TRUE,TRUE)) {
		//PROBLEM
		$this->imspError($command_text);
		return FALSE;
	}
	
	$response = $this->imspRecieve();
	
	switch($response) {
		
		case "NO":
			//Could not complete?
			$this->imspError("Could not retrieve ACL. Perhaps the addressbook does not exist?");
			return FALSE;
		case "BAD":
			//Don't know what you said!
			$this->imspError();
			return FALSE;
	}
	
	//If we are here, we need to recieve the * ACL Responses
		do {
			
			/* Get an array of responses. 
			 * The [3] element should be the addressbook name
			 * [4] and [5] will be user/group name and permissions etc...
			 */
			$acl = split(" ",$response);												
			
			
			for ($i = 4 ; $i < count($acl) ; $i += 2) {
				$results[$acl[$i]] = $acl[$i+1];
			}
			
			$response = $this->imspRecieve();
			
		
		} while (ereg(IMSP_ACL_RESPONSE,$response));
		
		//Hopefully we can recieve an OK response here
		
		if ($response != "OK") {
			//some weird problem
			$this->exitCode = IMSP_EXIT_UNEXPECTED_RESPONSE;
			$this->imspError();
			return FALSE;
		}
		
		return $results;
		
}


/****************************************************************************************************
* Deletes an ACL entry for a abook.  Takes the abook name and the username whose ACL should be deleted.
*
****************************************************************************************************/


function deleteACL($abook,$ident) {
	$command_text = "DELETEACL ADDRESSBOOK $abook $ident";
	
	if(!$this->imspSend($command_text)) {
		//PROBLEM
		$this->imspError($command_text);
		return FALSE;
	}
	
	$server_response = $this->imspRecieve();
	
	switch($response) {
		case "NO":
			//could not complete
			$this->imspError("Could not delete the ACL for $ident on addressbook $abook.");
			return FALSE;
		case "BAD":
			//Don't understand!
			$this->imspError();
			return FALSE;
		case "OK":
			//COOL!
			return TRUE;
		
		default:
			//Don't know why we would be here?
			$this->exitCode = IMSP_EXIT_UNEXPECTED_RESPONSE;
			$this->imspError();
			return FALSE;
	}
	
}


/****************************************************************************************************
 * Returns an ACL string containing the rights for the currently logged in user for the addressbook
 * passed in $abook.  Returns FALSE on failure.
/****************************************************************************************************/
function myRights($abook) {
	$command_text = "MYRIGHTS ADDRESSBOOK $abook";
	
	if(!$this->imspSend($command_text)) {
		$this->imspError($command_text);
		return FALSE;
	}
	
	$server_response = $this->imspRecieve();
	
	switch($response) {
		case "NO":
			//could not complete
			$this->imspError("Could not retrieve the ACL for the current user ($this->user)");
			return FALSE;
		case "BAD":
			//Don't understand!
			$this->imspError();
			return FALSE;
	}
	
	if (!ereg(IMSP_MYRIGHTS_RESPONSE,$server_response)) {
		$this->exitCode = IMSP_EXIT_UNEXPECTED_RESPONSE;
		$this->imspError();
		return FALSE;
	}	
	
	$temp = split(" ",$server_response);			
			
	$acl = $temp[4];	
	
	//Get the OK response
	$server_response = $this->imspRecieve();
	
	//Check for OK?
	if ($server_response != "OK") {
		$this->exitCode = IMSP_EXIT_UNEXPECTED_RESPONSE;
		$this->imspError();
		return FALSE;
	} else {
		return $acl;
	}	
	
}	
/****************************************************************************************************
* Utility Functions to support the class
* These would be considered "Private" but PHP has no support for this distinction.
/****************************************************************************************************/

function parseFetchAddressResponse($server_response) {
	
	/*
	 * Expects a FETCHADDRESS response to be passed.  Parses it out into an associative array
	 * with name-value pairs from the address book entry
	 *
	 */
	
	if(!ereg(IMSP_FETCHADDRESS_RESPONSE,$server_response)) {
		
		if($this->log_stream) {
			$this->write_to_log("[ERROR] Did not recieve expected FETCHADDRESS response from server.");
		}
		
		//Try to decide what the response was here.
		$this->exitCode = IMSP_EXIT_UNEXPECTED_RESPONSE;
		return FALSE;
	} 
	
	/****************************************************************************************************
	 *Parse out the server response string
	*
	* After choping off the server command response tags and split()'ing the server_response string using
	* a " " as the delimiter, the $parts array contains the chunks of the server returned data.
	*
	* The predifined "name" field starts in $parts[1].  The server should return any single item of data
	* that contains spaces within it as a double quoted string.  So we can interpret the existence of a 
	* double quote at the beginning of a chunk to mean that the next chunk(s) are to be considered part of 
	* the same value.  A double quote at the end of a chunk signifies the end of that value and the chunk
	* following that can be interpreted as a key name.
	*
	* We also need to watch for the server returning a {} response for the value of the key as well.
	*****************************************************************************************************/
	$chopped_response = trim(ereg_replace(IMSP_FETCHADDRESS_RESPONSE,"",$server_response));						//Take off the stuff from the beginning of the response we don't need.	
	$parts = split(" ",$chopped_response);
	$numOfParts = count($parts);
	$name = $parts[1];																							//This is the name - possibly only the first part.
				
	$firstChar = substr($name,0,1);																				//Get the first char of the name string
				
	/* Check to see if the first char of the name string is a double quote so */
	/* we know if we have to extract more of the name in the following chunks */
				 
	if($firstChar == "\"") {
		
		for($i = 2 ; $i < $numOfParts; $i++){
			$name .=  " " . $parts[$i];
			$lastChar = substr($parts[$i],strlen($parts[$i]) - 1,1);
			if($lastChar == "\""){
				$nextKey = $i + 1;
				break;
			}
		}
	} else {
	
		/* If only one chunk for 'name' then we just have to point to the */
		/* next chunk in the array...which will hopefully be '2'.         */
		$nextKey = 2;
	}
									
	$lastChar="";																				
				
	
	$entry["name"] = $name;																					//Fill in the name into the array we will return.														
				
	//Start parsing the rest of the response.
	for($i = $nextKey ; $i < $numOfParts ; $i += 2) {
		$key = $parts[$i];
					
		
		if(ereg("(^{)([0-9]{1,})(\}$)",$parts[$i+1],$tempArray)) {											//Check for a literal string response {}.
			
			$dataSize = $tempArray[2];																		//The size given to us by the server
			
		
			$server_data = $this->recieveStringLiteral($dataSize);											//Get the data (we need fread so we don't stop at CRLF's	
			$entry[$key] = $server_data;
						
			//Read any remaining data from the stream and reset the counter variables
			//so the loop will continue correctly. Note we set $i to -2 because it will
			//be incremented by 2 before the loop will run again.
			
			$parts = $this->getServerResponseChunks();
			$i= -2;
			$numOfParts = count($parts);
			
		} else {																							//not a string literal response
					
			$entry[$key] = $parts[$i + 1];
					
			/*Check to see if the value started with a double quote.     */
			/*This signifies that the value continues to the next element*/
					 
			if (substr($parts[$i+1],0,1) == "\""){
						
				do{
					$nextElement = $parts[$i+2];
					$entry[$key] .= " " . $nextElement;
						
					//Was this element the last one?
					$lastChar = substr($nextElement,strlen($nextElement) - 1,1);
					if ($lastChar=="\"") {
						$done = TRUE;
						$i++;
						break;
					} else {							
						//Check to see if the next element is the last one
						//If so, the do loop will terminate.
						$done = FALSE;
						$lastChar = substr($parts[$i+3],strlen($parts[$i+3]) - 1,1);
						$i++;
					}
										
				}while ($lastChar != "\"");
						
				//Do we need to add the final element, or was there only two total?
				if(!$done){
					$nextElement = $parts[$i+2];
					$entry[$key] .= " " . $nextElement;
					$i++;
				}
			}	
					 
		}//end of else clause (not literal string)\
	}//end of for i loop			
	
	return $entry;
}


} //End IMSPABook Class

?>