<?php
/*
PHPTOCLIB: A library for AIM connectivity through PHP using the TOC protocal.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
include ("errors.php");
set_time_limit(0);
//06-07-04: pickle- Added some more types to be used
define("AIM_TYPE_WARN",74);
define("AIM_TYPE_MSG",75);
define("AIM_TYPE_UPDATEBUDDY",76);
define("AIM_TYPE_SIGNON",77);
define("AIM_TYPE_NICK",78);
define("AIM_TYPE_ERROR",79);
define("AIM_TYPE_CHATJ",80);
define("AIM_TYPE_CHATI",81);
define("AIM_TYPE_CHATUPDBUD",82);
define("AIM_TYPE_CHATINV",83);
define("AIM_TYPE_CHATLE",84);
define("AIM_TYPE_URL",85);
define("AIM_TYPE_NICKSTAT",86);
define("AIM_TYPE_PASSSTAT",87);
define("AIM_TYPE_NOT_IMPLEMENTED",666);
define("MAX_PACKLENGTH",2048);
define("SFLAP_TYPE_SIGNON",1);
define("SFLAP_TYPE_DATA",2);
define("SFLAP_TYPE_ERROR",3);
define("SFLAP_TYPE_SIGNOFF",4);
define("SFLAP_TYPE_KEEPALIVE",5);
define("SFLAP_MAX_LENGTH",1024);
define("SFLAP_SUCCESS",0);
define("SFLAP_ERR_UNKNOWN",1);
define("SFLAP_ERR_ARGS",2);
define("SFLAP_ERR_LENGTH",3);
define("SFLAP_ERR_READ",4);
define("SFLAP_ERR_SEND",5);
define("SFLAP_FLAP_VERSION",1);
define("SFLAP_TLV_TAG",1);
define("SFLAP_HEADER_LEN",6);
$Silent = false; //True means nothing should be printed (Use sEcho instead of echo)
class Aim
{
var $myScreenName; //Screen name of the bot(normalized)
var $myPassword; //Password for the bot (plain text)
var $sql_user; //The user for the sql database
var $sql_pass; //The password for the sql database
var $sql_db; //The database that the bots info is in
var $sql_server; //The sql server/The database that the bots info is in
var $myServer="toc.oscar.aol.com"; //The server to connect on
var $myPort="5190"; //The servers port
var $myProfile="Powered by phpTOCLib. Please visit http://sourceforge.net/projects/phptoclib for more information"; //The profile of the bot
var $myLogging=0; //Put messages and commands into a log file
var $myDebugOut=0; //Show most commands in the console window
var $myConnection; //Connection resource ID
var $myRoastedPass; //The password. roasted
var $myLastReceived;//The last message received from the server
var $mySeqNum; //The currecnt seq number used to communicate with the server
var $myLogHandler; //THe handler for the log file, is 0 if logging is off
var $mySQLHandle;
var $myWarnLevel; //Warning Level of the bot
var $myAuthCode;
var $myBuddyList;
var $myBlockedList;
var $myPermitList;
var $myPdMode; //Permit deny mode
//Below variables added 4-29 by Jeremy: Implementing chat
var $acceptchat; //Should we accept chat invitations?
var $chatrooms; //Array containing chat romm info $chatrooms['roomid'] = people in room
var $numchats=0; //How many chats are we in?
var $chatqueue; //Make a queue for which chats to join when we leave one
//End of chat implementation
var $signonrcv = false; //This will be set to true when we receive the SIGN_ON message
//This should keep other functions from being called that
//aren't related to signon
//Below are event handlers Added for beta 1 by Jeremy
var $onSignOnf="none";
var $onConfigf="none";
var $onNickf="none";
var $onImInf="none";
var $onUpdateBuddyf="none";
var $onErrorf="none";
var $onWarnf="none";
var $onChatJoinf="none";
var $onChatUpdatef="none";
var $onChatInvitef="none";
var $onChatLeftf="none";
var $onGotoURLf="none";
var $onDirStatusf="none";
var $onAdminNickf="none";
var $onAdminPasswdf="none";
var $onPausef="none";
var $onRvousf="none";
var $CatchAllf="none";
//End of event handler block
//Constructor
function Aim($sn,$password,$pdmode, $silent=false)
{
//Constructor assignment
$this->myScreenName=$this->normalize($sn);
$this->myPassword=$password;
$this->myRoastedPass=$this->roast_pass($password);
$this->mySeqNum=1;
$this->myConnection=0;
$this->myWarnLevel=0;
$this->myAuthCode=$this->make_code();
$this->myPdMode=$pdmode;
$GLOBALS["Silent"] = $silent;
if($silent){
error_reporting(E_ERROR);
}
//else
//error_reporting(E_ALL);
sEcho("PHPTOCLIB v0.4 Object Created");
}
function roast_pass($password)
{
$roaststring = 'Tic/Toc';
$roasted_password = '0x';
for ($i = 0; $i < strlen($password); $i++)
$roasted_password .= bin2hex($password[$i] ^ $roaststring[($i % 7)]);
return $roasted_password;
}
function make_code()
{
$sn=base_convert(bin2hex($this->myScreenName[0]),16,10) - 96;
$pw=base_convert(bin2hex($this->myPassword[0]),16,10) - 96;
$a= $sn * 7696 + 738816;
$b= $sn * 746512;
$c= $pw * $a;
return $c-$a+$b+71665152;
}
//Public function designed to set the sql information
function sql_connect($host,$username,$password,$database)
{
@$this->mySQLHandle=mysql_connect($host,$username,$password) or die("Could not connect to the database. The host may not exist, or the supplied username and password were incorrect");
@mysql_select_db($database) or die("Error selecting database. It is possible it does not exist, or you may bot have permission to access it");
$this->sql_user=$username;
$this->sql_pass=$password;
$this->sql_server=$host;
$this->sql_db=$database;
sEcho("Connected to MySQL Database: " . $this->sql_db . " by " . $this->sql_user . "@" . $this->sql_server);
}
function sflap_read()
{
if(socketcheck($this->myConnection))
{
sEcho("Disconnected.... Reconnecting in 60 seconds");
sleep(60);
$this->signon();
}
$sockinfo=socket_get_status($this->myConnection);
//sEcho($sockinfo['unread_bytes'] . " " . $sockinfo['blocked']);
//if($sockinfo['unread_bytes'] < SFLAP_HEADER_LEN && !$sockinfo['blocked'])
//if(feof($this->myConnection) && $sockinfo['blocking'])
// return "";
$header=fread($this->myConnection,SFLAP_HEADER_LEN);
//or $this->derror("Could not read header");
//if(strlen($header)<SFLAP_HEADER_LEN && $sockinfo['blocked'])
//{
//fclose($this->myConnection);
// $this->derror("Error reading header.. attempting to reconnect");
//sleep(60);
//$this->signon();
//}
//else
if(strlen($header)==0)
{
$this->myLastReceived="";
return "";
}
$header_data=unpack("aast/Ctype/nseq/ndlen", $header);
//print_r($header_data);
sEcho(" . ", false);
$packet=fread($this->myConnection,$header_data['dlen']);
if(strlen($packet)<=0 && $sockinfo['blocked'])
$this->derror("Could not read data");
if($header_data['type']==SFLAP_TYPE_SIGNON)
{
$packet_data=unpack("Ndecoded",$packet);
}
if($header_data['type']==SFLAP_TYPE_KEEPALIVE)
{
$this->myLastReceived='';
return 0;
}
else if(strlen($packet)>0)
{
$packet_data=unpack("a*decoded",$packet);
}
sEcho("socketcheck check now");
if(socketcheck($this->myConnection))
{
$this->derror("Connection ended unexpectedly");
}
$data=array_merge($header_data,$packet_data);
$this->myLastReceived=$data;
//SEcho("data " . $data);
return $data;
}
function sflap_send($sflap_type,$sflap_data,$no_null,$formatted)
{
$packet="";
if(strlen($sflap_data)>=MAX_PACKLENGTH)
$sflap_data=substr($sflap_data,0,MAX_PACKLENGTH);
if($formatted)
{
$len=strlen($sflap_len);
$sflap_header=pack("aCnn",'*',$sflap_type,$this->mySeqNum,$len);
$packet=$sflap_header . $sflap_data;
} else {
if(!$no_null)
{
$sflap_data=str_replace("\0","",$sflap_data);
$sflap_data.="\0";
}
$data=pack("a*",$sflap_data);
$len=strlen($sflap_data);
$header=pack("aCnn","*",$sflap_type,$this->mySeqNum,$len);
$packet=$header . $data;
}
//Make sure we are still connected
if(socketcheck($this->myConnection))
{
sEcho("Disconnected.... reconnecting in 60 seconds");
sleep(60);
$this->signon();
}
$sent=fputs($this->myConnection,$packet) or $this->derror("Error sending packet to AIM");
$this->mySeqNum++;
sleep(ceil($this->myWarnLevel/10));
}
//Escape the thing that TOC doesn't like,that would be
//",',$,{,},[,]
function encode_data($data)
{
$data=str_replace('"','\"',$data);
$data=str_replace('$','\$',$data);
$data=str_replace("'","\'",$data);
$data=str_replace('{','\{',$data);
$data=str_replace('}','\}',$data);
$data=str_replace('[','\[',$data);
$data=str_replace(']','\]',$data);
return $data;
}
function decode($data)
{
$data=str_replace('\"','"',$data);
$data=str_replace('\$','$',$data);
$data=str_replace("\'","'",$data);
$data=str_replace('\{','{',$data);
$data=str_replace('\}','}',$data);
$data=str_replace('\[','[',$data);
$data=str_replace('\]',']',$data);
$data=str_replace('"','"',$data);
$data=str_replace('&','&',$data);
return $data;
}
//"normalize" the nickname, that means no spaces and all lowercase
function normalize($nick)
{
$nick=str_replace(" ","",$nick);
$nick=strtolower($nick);
return $nick;
}
function set_my_info()
{
//Sets internal values bvase on the update buddy command
sEcho("Setting my warning level ...");
$this->sflap_send(SFLAP_TYPE_DATA,"toc_get_status " . $this->normalize($this->myScreenName),0,0);
//The rest of this will now be handled by the other functions. It is assumed
//that we may have other data queued in the socket, do we should just add this
//message to the queue instead of trying to set it in here
}
function signon()
{
sEcho("Ready to sign on to the server");
$this->myConnection=fsockopen($this->myServer,$this->myPort,$errno,$errstr,10) or die("$errorno:$errstr");
sEcho("Connected to server");
$this->mySeqNum=(time() % 65536); //Select an arbitrary starting point for
//sequence numbers
if(!$this->myConnection)
$this->derror("Error connecting to toc.oscar.aol.com");
sEcho("Connected to AOL");
//Send the flapon packet
fputs($this->myConnection,"FLAPON\r\n\n\0"); //send the initial handshake
sEcho("Sent flapon");
$this->sflap_read(); //Make sure the server responds with what we expect
if(!$this->myLastReceived)
$this->derror("Error sending the initialization string");
//send the FLAP SIGNON packet back with what it needs
//There are 2 parts to the signon packet. They are sent in succession, there
//is no indication if either packet was correctly sent
$signon_packet=pack("Nnna".strlen($this->myScreenName),1,1,strlen($this->myScreenName),$this->myScreenName);
$this->sflap_send(SFLAP_TYPE_SIGNON,$signon_packet,1,0);
sEcho("sent signon packet part one");
$signon_packet_part2='toc2_signon login.oscar.aol.com 29999 ' . $this->myScreenName . ' ' . $this->myRoastedPass . ' english-US "TIC:TOC2:REVISION" 160 ' . $this->myAuthCode;
sEcho($signon_packet_part2 . "");
$this->sflap_send(SFLAP_TYPE_DATA,$signon_packet_part2,0,0);
sEcho("Sent signon packet part 2... Awaiting response...");
$this->sflap_read();
sEcho("Received Sign on packet, beginning initilization...");
$message=$this->getLastReveived();
sEcho($message . "\n");
if(strstr($message,"ERROR:"))
{
$this->onError($message);
die("Fatal signon error");
}
//The information sent before the config2 command is utterly useless to us
//So we will just skim through them until we reach it
//UPDATED 4/12/03: Now this will use the receive function and send the
//received messaged to the assigned handlers. This is where the signon
//method has no more use
sEcho("Done with signon proccess");
//socket_set_blocking($this->myConnection,false);
}
function parse_buddy_change($message)
{
//This will update buddy info when I get around to it
//TODO: SQL buddy storage
}
function send_im($to,$message,$auto=false)
{
if($auto) $auto="auto";
else $auto="";
$to=$this->normalize($to);
$message=$this->encode_data($message);
$command='toc2_send_im "' . $to . '" "' . $message . '" ' . $auto;
$this->sflap_send(SFLAP_TYPE_DATA,$command,0,0);
$cleanedmessage = str_replace("<br>", " ", $this->decode($message));
$cleanedmessage = strip_tags($cleanedmessage);
sEcho("TO - " . $to . " : " . $cleanedmessage);
}
function get_buddy_list()
{
//THis better be the right message
$message=$this->myLastReceived['decoded'];
if(strpos($message,"CONFIG2:")===false)
{
sEcho("get_buddy_list cannot be called at this time");
return false;
}
$people=explode("\n",trim($message,"\n"));
//The first 3 elements of the array are who knows what, element 3 should be
//a letter followed by a person
for($i=1;$i<sizeof($people);$i++)
{
@list($mode,$name)=explode(":",$people[$i]);
switch($mode)
{
case 'p':
$this->myPermitList[]=$name;
break;
case 'd':
$this->myBlockedList[]=$name;
break;
case 'b':
$this->myBuddyList[]=$name;
break;
case 'done':
break;
default:
//
}
}
}
function add_permit($buddy)
{
$this->sflap_send(SFLAP_TYPE_DATA,"toc2_add_permit " . $this->normalize($buddy),0,0);
$this->myPermitList[]=$this->normalize($buddy);
return 1;
}
function block_buddy($buddy)
{
$this->sflap_send(SFLAP_TYPE_DATA,"toc2_add_deny " . $this->normalize($buddy),0,0);
$this->myBlockedList[]=$this->normalize($buddy);
return 1;
}
function getMessage()
{
$in = $this->read_from_aim();
$cmd = msg_type($in);
$in = msg_parse($cmd);
$out = $in;
$out['type'] = $cmd['type'];
if($out['type'] == AIM_TYPE_WARN){
$this->setWarning($out['warnlevel']);
}
if($out['type'] == AIM_TYPE_MSG){
sEcho("" . $out['from'] . ": " . strip_tags($out['message']));
$out['cleanmessage'] = strip_tags($out['message']);
}
return $out;
}
function getLastReveived()
{
if(@$instuff=$this->myLastReceived['decoded']){
return $this->myLastReceived['decoded'];
}else{
return;
}
}
function getBuddies()
{
return $this->myBuddyList;
}
function getPermit()
{
return $this->myPermitList;
}
function getBlocked()
{
return $this->myBlockedList;
}
function read_from_aim()
{
$this->sflap_read();
$returnme= $this->getLastReveived();
return $returnme;
}
function setWarning($warnlevel)
{
$this->myWarnLevel=$warnlevel;
}
function warn_user($to,$anon=false)
{
if(!$anon)
$anon='"norm"';
else
$anon='"anon"';
$this->sflap_send(SFLAP_TYPE_DATA,"toc_evil " . $this->normalize($to) . " $anon",0,0);
}
function update_profile($profiledata, $poweredby=false)
{
if($poweredby==false){
$this->myProfile = $profiledata;
}else{
$this->myProfile = $profiledata . "<font size=1 face=tahoma><br><br>Powered by phpTOCLib<br>http://sourceforge.net/projects/phptoclib</font>";
}
$this->sflap_send(SFLAP_TYPE_DATA,"toc_set_info \"" . $this->encode_data($this->myProfile) . "\"",0,0);
$this->set_my_info();
sEcho("Profile has been updated...");
}
//Added 4/29/04 by Jeremy:
//Various chat related methods
function join_chat($chatid)
{
$this->sflap_send(SFLAP_TYPE_DATA,"toc_chat_accept " . $chatid,0,0);
}
function leave_chat($chatid)
{
$this->sflap_send(SFLAP_TYPE_DATA,"toc_chat_leave " . $chatid,0,0);
}
function chat_say($chatid,$message)
{
$this->sflap_send(SFLAP_TYPE_DATA,"toc_chat_send " . $chatid . " \"" . $this->encode_data($message) . "\"",0,0);
}
function chat_invite($chatid,$who,$message)
{
$this->sflap_send(SFLAP_TYPE_DATA,"toc_chat_invite " . $chatid . " \"" . $this->encode_data($message) . "\" " . $who,0,0);
}
function join_new_chat($name,$exchange)
{
//Creates a new chat
$this->sflap_send(SFLAP_TYPE_DATA,"toc_chat_join " . $exchange . " \"" . $name . "\"",0,0);
}
function derror($message)
{
sEcho($message);
sEcho("Error");
fclose($this->myConnection);
if((time() - $GLOBALS['errortime']) < 600){
sEcho("Reconnecting in 60 Seconds");
sleep(60);
}
$this->signon();
$GLOBALS['errortime'] = time();
}
function recieve()
{
//This function will be used to get the incoming data
//and it will be used to call the event handlers
//First step:Get the data sitting in the socket
$message=$this->read_from_aim();
if(strlen($message) <= 0)
{
return;
}
//Second step: Get the command from the server
@list($cmd,$rest)=explode(":",$message);
//Third step, take the command, test the type, and pass it off
//to the correct internal handler. The internal handler will
//do what needs to be done on the class internals to allow
//it to work, then proceed to pass it off to the user created handle
//if there is one
sEcho($cmd);
switch($cmd)
{
case 'SIGN_ON':
$this->onSignOn($message);
break;
case 'CONFIG2':
$this->onConfig($message);
break;
case 'ERROR':
$this->onError($message);
break;
case 'NICK':
$this->onNick($message);
break;
case 'IM_IN2':
echo("Calling onImIn()");
$this->onImIn($message);
break;
case 'UPDATE_BUDDY2':
$this->onUpdateBuddy($message);
break;
case 'EVILED':
$this->onWarn($message);
break;
case 'CHAT_JOIN':
$this->onChatJoin($message);
break;
case 'CHAT_IN':
$this->onChatJoin($message);
break;
case 'CHAT_UPDATE_BUDDY':
$this->onChatUpdate($message);
break;
case 'CHAT_INVITE':
$this->onChatInvite($message);
break;
case 'CHAT_LEFT':
$this->onChatLeft($message);
break;
case 'GOTO_URL':
$this->onGotoURL($message);
break;
case 'DIR_STATUS':
$this->onDirStatus($message);
break;
case 'ADMIN_NICK_STATUS':
$this->onAdminNick($message);
break;
case 'ADMIN_PASSWD_STATUS':
$this->onAdminPasswd($message);
break;
case 'PAUSE':
$this->onPause($message);
break;
case 'RVOUS_PROPOSE':
$this->onRvous($message);
break;
default:
sEcho("Fell through :(");
$this->CatchAll($message);
break;
}
//Now get out of this function becuase the handlers should take care
//of everything
}
//The next block of code is all the event handlers needed by the class
//Some are left blank and only call the users handler because the class
//either does not support the command, or cannot do anything with it
function onSignOn($message)
{
$this->signonrcv=true;
$function=$this->onSignOnf . "(\$message);";
eval($function);
}
function onConfig($message)
{
if(strpos($message,"CONFIG2:")===false)
{
sEcho("get_buddy_list cannot be called at this time");
return false;
}
$people=explode("\n",trim($message,"\n"));
//The first 3 elements of the array are who knows what, element 3 should be
//a letter followed by a person
for($i=1;$i<sizeof($people);$i++)
{
@list($mode,$name)=explode(":",$people[$i]);
switch($mode)
{
case 'p':
$this->myPermitList[]=$name;
break;
case 'd':
$this->myBlockedList[]=$name;
break;
case 'b':
$this->myBuddyList[]=$name;
break;
case 'done':
break;
default:
}
}
//We only get the config message once, so now we should send our pd mode
$this->sflap_send(SFLAP_TYPE_DATA,"toc2_set_pdmode " . $this->myPdMode,0,0);
//Adds yourself to the permit list
//This is to fix an odd behavior if you have nobody on your list
//the server won't send the config command... so this takes care of it
$this->sflap_send(SFLAP_TYPE_DATA,"toc2_add_permit " . $this->normalize($this->myScreenName),0,0);
//Now we allow the user to send a list, update anything they want, etc
$function=$this->onConfigf . "(\$message);";
eval($function);
//Now that we have taken care of what the user wants, send the init_done message
$this->sflap_send(SFLAP_TYPE_DATA,"toc_init_done",0,0);
}
function onError($message)
{
global $ERRORS;
@list($cmd,$errornum,$errargs)=explode(":",$message);
eval("\$errorstring=\"\$ERRORS[" . $errornum . "]\";");
$string="\$errorstring=\"\$ERRORS[$errornum]\";";
//This is important information! We need
// a A different outputter for errors
// b Just to echo it
//I'm just going to do a straight echo here, becuse we assume that
//the user will NEED to see this error. An option to supress it will
//come later I think. Perhaps if we did an error reporting level, similar
//to PHP's, and we could probably even use PHP's error outputting system
//I think that may be an idea....
echo($errorstring . "\n");
$function=$this->onErrorf . "(\$message);";
eval($function);
}
function onNick($message)
{
//This is our nick, so set a feild called "mySNick" which will represent
//the actual name given by the server to us, NOT the normalized screen name
@list($cmd,$nick)=explode(":",$message);
$this->mySNick=$nick;
$function=$this->onNickf . "(\$message);";
eval($function);
}
function onImIn($message)
{
//Perhaps we should add an internal log for debugging purposes??
//But now, this should probably be handled by the user purely
$function=$this->onImInf . "(\$message);";
eval($function);
}
function onUpdateBuddy($message)
{
//Again, since our class currently does not deal with other people without
//outside help, then this is also probably best left to the user. Though
//we should probably allow this to replace the set_my_info function above
//by handling the input if and only if it is us
//Check and see that this is the command expected
if(strpos($message,"UPDATE_BUDDY2:")==-1)
{
sEcho("A different message than expected was received");
return false;
}
@list($cmd,$sn,$online,$warning,$starttime,$idletime,$uc)=explode(":",$message);
if($this->normalize($sn) == $this->normalize($this->myScreenName))
{
$warning=rtrim($warning,"%");
$this->myWarnLevel=$warning;
sEcho("My warning level is $this->myWarnLevel %");
}
$function=$this->onUpdateBuddyf . "(\$message);";
eval($function);
}
function onWarn($message)
{
//SImply update our warning level
@list($cmd,$newwarn,$user)=explode(":",$message);
$this->setWarning(trim($newwarn,"%"));
$function=$this->onWarnf . "(\$message);";
eval($function);
}
function onChatJoin($message)
{
@list($cmd,$rmid,$rmname)=explode(":",$message);
$this->chatrooms[$rmid]=0;
$this->numchats++;
$function=$this->onChatJoinf . "(\$message);";
eval($function);
}
function onChatUpdate($message)
{
$stuff=explode(":",$message);
$people=sizeof($stuff);
$people-=2;
$function=$this->onChatUpdatef. "(\$message);";
eval($function);
}
function onChatInvite($message)
{
@list($cmd,$name,$id,$from,$message)=explode(":",$message,6);
$this->join_chat($id);
$function=$this->onChatInvitef . "(\$message);";
eval($function);
}
function onChatLeft($message)
{
//We are not currently supporting chat
$function=$this->onChatLeftf . "(\$message);";
eval($function);
}
function onGotoURL($message)
{
//This is of no use to the internal class
$function=$this->onGotoURLf . "(\$message);";
eval($function);
}
function onDirStatus($message)
{
//This is not currently suported
$function=$this->onDirStatusf . "(\$message);";
eval($function);
}
function onAdminNick($message)
{
//NOt particularly useful to us
$function=$this->onAdminNickf . "(\$message);";
eval($function);
}
function onAdminPasswd($message)
{
//Also not particlualry useful to the internals
$function=$this->onAdminPasswdf . "(\$message);";
eval($function);
}
function onPause($message)
{
//This is pretty useless to us too...
$function=$this->onPausef . "(\$message);";
eval($function);
}
function onRvous($message)
{
//This may not be of any use to us at all, because currently it does
//not appear that direct connecting is enabled from the current client
//to any TOC client
$function=$this->onRvousf . "(\$message);";
eval($function);
}
function CatchAll($message)
{
//Add to a log of unsupported messages.
$this->unsupported[]=$message;
//sEcho($message);
//print_r($message);
$function=$this->CatchAllf . "(\$message);";
eval($function);
}
//This next block of code is for the handle registering
function registerHandler($command,$function)
{
switch($command)
{
case 'SIGN_ON':
$this->onSignOnf=$function;
break;
case 'CONFIG2':
$this->onConfigf=$function;
break;
case 'ERROR':
$this->onErrorf=$function;
break;
case 'NICK':
$this->onNickf=$function;
break;
case 'IM_IN2':
$this->onImInf=$function;
break;
case 'UPDATE_BUDDY2':
$this->onUpdateBuddyf=$function;
break;
case 'EVILED':
$this->onWarnf=$function;
break;
case 'CHAT_JOIN':
$this->onChatJoinf=$function;
break;
case 'CHAT_IN':
$this->onChatJoinf=$function;
break;
case 'CHAT_UPDATE_BUDDY':
$this->onChatUpdatef=$function;
break;
case 'CHAT_INVITE':
$this->onChatInvitef=$function;
break;
case 'CHAT_LEFT':
$this->onChatLeftf=$function;
break;
case 'GOTO_URL':
$this->onGotoURLf=$function;
break;
case 'DIR_STATUS':
$this->onDirStatusf=$function;
break;
case 'ADMIN_NICK_STATUS':
$this->onAdminNickf=$function;
break;
case 'ADMIN_PASSWD_STATUS':
$this->onAdminPasswdf=$function;
break;
case 'PAUSE':
$this->onPausef=$function;
break;
case 'RVOUS_PROPOSE':
$this->onRvousf=$function;
break;
case 'other':
$this->CatchAllf=$function;
break;
default:
sEcho("This command does not exist");
}
}
}
//GLOBAL FUNCTIONS
//6/07/04: pickle- Added funtionality (hopefully) for all messages sent by TOC
function msg_type($message)
{
$command=array();
@list($cmd,$rest)=explode(":",$message);
switch($cmd)
{
case 'IM_IN2':
$type=AIM_TYPE_MSG;
break;
case 'UPDATE_BUDDY2':
$type=AIM_TYPE_UPDATEBUDDY;
break;
case 'EVILED':
$type=AIM_TYPE_WARN;
break;
case 'SIGN_ON':
$type=AIM_TYPE_SIGNON;
break;
case 'NICK':
$type=AIM_TYPE_NICK;
break;
case 'ERROR':
$type=AIM_TYPE_ERROR;
break;
case 'CHAT_JOIN':
$type=AIM_TYPE_CHATJ;
break;
case 'CHAT_IN':
$type=AIM_TYPE_CHATI;
break;
case 'CHAT_UPDATE_BUDDY':
$type=AIM_TYPE_CHATUPDBUD;
break;
case 'CHAT_INVITE':
$type=AIM_TYPE_CHATINV;
break;
case 'CHAT_LEFT':
$type=AIM_TYPE_CHATLE;
break;
case 'GOTO_URL':
$type=AIM_TYPE_URL;
break;
case 'ADMIN_NICK_STATUS':
$type=AIM_TYPE_NICKSTAT;
break;
case 'ADMIN_PASSWD_STATUS':
$type=AIM_TYPE_PASSSTAT;
break;
default:
$type=AIM_TYPE_NOT_IMPLEMENTED;
break;
}
$command['type']=$type;
$command['incoming']=$message;
return $command;
}
function msg_parse($command)
{
$info=array();
switch($command['type'])
{
case AIM_TYPE_WARN:
$command['incoming'].=":0";
$it=explode(":",$command['incoming']);
$info['warnlevel']=$it[1];
$info['from']=$it[2];
break;
case AIM_TYPE_MSG:
$it=explode(":",$command['incoming'],5);
$info['auto']=$it[2];
$info['from']=$it[1];
$info['message']=$it[4];
break;
case AIM_TYPE_UPDATEBUDDY:
@list($cmd,$info['sn'],$info['online'],$info['warnlevel'],$info['signon'],$info['idle'],$info['uc'])=explode(":",$command['incoming']);
break;
case AIM_TYPE_SIGNON:
@list($cmd,$info['version'])=explode(":",$command['incoming']);
break;
case AIM_TYPE_NICK:
@list($cmd,$info['nickname'])=explode(":",$command['incoming']);
break;
case AIM_TYPE_ERROR:
@list($cmd,$info['errorcode'],$info['args'])=explode(":",$command['incoming']);
break;
case AIM_TYPE_CHATJ:
@list($cmd,$info['chatid'],$info['chatname'])=explode(":",$command['incoming']);
break;
case AIM_TYPE_CHATI:
@list($cmd,$info['chatid'],$info['user'],$info['whisper'],$info['message'])=explode(":",$command['incoming'],5);
break;
case AIM_TYPE_CHATUPDBUD:
@list($cmd,$info['chatid'],$info['inside'],$info['userlist'])=explode(":",$command['incoming'],3);
break;
case AIM_TYPE_CHATINV:
@list($cmd,$info['chatname'],$info['chatid'],$info['from'],$info['message'])=explode(":",$command['incoming'],5);
break;
case AIM_TYPE_CHATLE:
@list($cmd,$info['chatid'])=explode(":",$command['incoming']);
break;
case AIM_TYPE_URL:
@list($cmd,$info['windowname'],$info['url'])=explode(":",$command['incoming'],3);
break;
case AIM_TYPE_NICKSTAT:
case AIM_TYPE_PASSSTAT:
@list($cmd,$info['returncode'],$info['opt'])=explode(":",$command['incoming'],3);
break;
default:
$info['command']=$command['incoming'];
}
return $info;
}
function sEcho($out, $newline=true){
if($newline){
echo("\n");
}
if(!$GLOBALS["Silent"]){
print_r($out);
}
}
function socketcheck($socket){
$info = stream_get_meta_data($socket);
return $info['eof'];
//return(feof($socket));
}
function none($message)
{
//This function intentionally left blank
//This is where the handlers will fall to for now. I plan on including a more
//efficent check to avoid the apparent stack jumps that this code will produce
//But for now, just fall into here, and be happy
return;
}
?>