<?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
?> |