PHP Classes

File: cIMSPABook.php

Recommend this page to a friend!
  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: 20 years ago
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 ?>