]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/Aim/extlib/phptoclib/aimclassw.php
$related must contain class names, no table names ("all" lower-case) + fixed some...
[quix0rs-gnu-social.git] / plugins / Aim / extlib / phptoclib / aimclassw.php
1 <?php
2 /*
3 *       PHPTOCLIB: A library for AIM connectivity through PHP using the TOC protocal.
4 *
5 *       This library is free software; you can redistribute it and/or
6 *       modify it under the terms of the GNU Lesser General Public
7 *       License as published by the Free Software Foundation; either
8 *       version 2.1 of the License, or (at your option) any later version.
9 *
10 *       This library is distributed in the hope that it will be useful,
11 *       but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *       Lesser General Public License for more details.
14 *
15 *       You should have received a copy of the GNU Lesser General Public
16 *       License along with this library; if not, write to the Free Software
17 *       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 *
19 */
20 /**
21 * The version of PHPTOCLIB we are running right now
22 *
23 * @access private
24 * @var int
25 */
26 define("PHPTOCLIB_VERSION","1.0.0 RC1");
27
28 // Prevents Script from Timing Out
29 //set_time_limit(0);
30
31 // Constant Declarations
32
33 /**
34 * Maximum size for a direct connection IM in bytes
35 *
36 * @access private
37 * @var int
38 */
39
40 define("MAX_DIM_SIZE",3072); //Default to 3kb
41
42 /**
43 * Internally used for message type
44 *
45 * @access private
46 * @var int
47 */
48 define("AIM_TYPE_WARN",74);
49 /**
50 * Internally used for message type
51 *
52 * @access private
53 * @var int
54 */
55 define("AIM_TYPE_MSG",75);
56 /**
57 * Internally used for message type
58 *
59 * @access private
60 * @var int
61 */
62 define("AIM_TYPE_UPDATEBUDDY",76);
63 /**
64 * Internally used for message type
65 *
66 * @access private
67 * @var int
68 */
69 define("AIM_TYPE_SIGNON",77);
70 /**
71 * Internally used for message type
72 *
73 * @access private
74 * @var int
75 */
76 define("AIM_TYPE_NICK",78);
77 /**
78 * Internally used for message type
79 *
80 * @access private
81 * @var int
82 */
83 define("AIM_TYPE_ERROR",79);
84 /**
85 * Internally used for message type
86 *
87 * @access private
88 * @var int
89 */
90 define("AIM_TYPE_CHATJ",80);
91 /**
92 * Internally used for message type
93 *
94 * @access private
95 * @var int
96 */
97 define("AIM_TYPE_CHATI",81);
98 /**
99 * Internally used for message type
100 *
101 * @access private
102 * @var int
103 */
104 define("AIM_TYPE_CHATUPDBUD",82);
105 /**
106 * Internally used for message type
107 *
108 * @access private
109 * @var int
110 */
111 define("AIM_TYPE_CHATINV",83);
112 /**
113 * Internally used for message type
114 *
115 * @access private
116 * @var int
117 */
118 define("AIM_TYPE_CHATLE",84);
119 /**
120 * Internally used for message type
121 *
122 * @access private
123 * @var int
124 */
125 define("AIM_TYPE_URL",85);
126 /**
127 * Internally used for message type
128 *
129 * @access private
130 * @var int
131 */
132 define("AIM_TYPE_NICKSTAT",86);
133 /**
134 * Internally used for message type
135 *
136 * @access private
137 * @var int
138 */
139 define("AIM_TYPE_PASSSTAT",87);
140 /**
141 * Internally used for message type
142 *
143 * @access private
144 * @var int
145 */
146 define("AIM_TYPE_RVOUSP",88);
147 /**
148 * Internally used for message type
149 *
150 * @access private
151 * @var int
152 */
153 define("AIM_TYPE_NOT_IMPLEMENTED",666);
154
155
156
157 /**
158 * Internally used for connection type
159 *
160 * Internal type for a normal connection
161 *
162 * @access private
163 * @var int
164 */
165 define("CONN_TYPE_NORMAL",1);
166 /**
167 * Internally used for connection type
168 *
169 * Internal type of a Dirct Connection
170 *
171 * @access private
172 * @var int
173 */
174 define("CONN_TYPE_DC",2);
175 /**
176 * Internally used for connection type
177 *
178 *Internal type for a file transfer connection
179 *
180 * @access private
181 * @var int
182 */
183 define("CONN_TYPE_FT",3);
184 /**
185 * Internally used for connection type
186 *
187 *Internal type for a file get connection
188 *
189 * @access private
190 * @var int
191 */
192 define("CONN_TYPE_FTG",4);
193
194 /**
195 * Maximum size for a TOC packet
196 *
197 * @access private
198 * @var int
199 */
200 define("MAX_PACKLENGTH",2048);
201
202 /**
203 * TOC packet type
204 *
205 * @access private
206 * @var int
207 */
208 define("SFLAP_TYPE_SIGNON",1);
209 /**
210 * TOC packet type
211 *
212 * @access private
213 * @var int
214 */
215 define("SFLAP_TYPE_DATA",2);
216 /**
217 * TOC packet type
218 *
219 * @access private
220 * @var int
221 */
222 define("SFLAP_TYPE_ERROR",3);
223 /**
224 * TOC packet type
225 *
226 * @access private
227 * @var int
228 */
229 define("SFLAP_TYPE_SIGNOFF",4);
230 /**
231 * TOC packet type
232 *
233 * @access private
234 * @var int
235 */
236 define("SFLAP_TYPE_KEEPALIVE",5);
237 /**
238 * TOC packet type
239 *
240 * @access private
241 * @var int
242 */
243 define("SFLAP_MAX_LENGTH",1024);
244
245
246
247 /**
248 * Service UID for a voice connection
249 *
250 * @access private
251 * @var int
252 */
253 define('VOICE_UID', '09461341-4C7F-11D1-8222-444553540000');
254 /**
255 * Service UID for file sending 
256 *
257 * @access private
258 * @var int
259 */
260 define('FILE_SEND_UID', '09461343-4C7F-11D1-8222-444553540000');
261 /**
262 * Service UID for file getting
263 *
264 * @access private
265 * @var int
266 */
267 define('FILE_GET_UID', '09461348-4C7F-11D1-8222-444553540000');
268 /**
269 * Service UID for Direct connections 
270 *
271 * @access private
272 * @var int
273 */
274 define('IMAGE_UID', '09461345-4C7F-11D1-8222-444553540000');
275 /**
276 * Service UID for Buddy Icons
277 *
278 * @access private
279 * @var int
280 */
281 define('BUDDY_ICON_UID', '09461346-4C7F-11D1-8222-444553540000');
282 /**
283 * Service UID for stocks
284 *
285 * @access private
286 * @var int
287 */
288 define('STOCKS_UID', '09461347-4C7F-11D1-8222-444553540000');
289 /**
290 * Service UID for games
291 *
292 * @access private
293 * @var int
294 */
295 define('GAMES_UID', '0946134a-4C7F-11D1-8222-444553540000');
296
297 /**
298 * FLAP return code
299 *
300 * @access private
301 * @var int
302 */
303 define("SFLAP_SUCCESS",0);
304 /**
305 * FLAP return code
306 *
307 * @access private
308 * @var int
309 */
310 define("SFLAP_ERR_UNKNOWN",1);
311 /**
312 * FLAP return code
313 *
314 * @access private
315 * @var int
316 */
317 define("SFLAP_ERR_ARGS",2);
318 /**
319 * FLAP return code
320 *
321 * @access private
322 * @var int
323 */
324 define("SFLAP_ERR_LENGTH",3);
325 /**
326 * FLAP return code
327 *
328 * @access private
329 * @var int
330 */
331 define("SFLAP_ERR_READ",4);
332 /**
333 * FLAP return code
334 *
335 * @access private
336 * @var int
337 */
338 define("SFLAP_ERR_SEND",5);
339
340 /**
341 * FLAP version number
342 *
343 * @access private
344 * @var int
345 */
346 define("SFLAP_FLAP_VERSION",1);
347 /**
348 * FLAP TLV code
349 *
350 * @access private
351 * @var int
352 */
353 define("SFLAP_TLV_TAG",1);
354 /**
355 * Bytes in a FLAP header
356 *
357 * @access private
358 * @var int
359 */
360 define("SFLAP_HEADER_LEN",6);
361
362 /** 
363  * PHPTocLib AIM Class
364  *
365  * @author Jeremy Bryant <pickleman78@users.sourceforge.net>
366  * @author Rajiv Makhijani <rajiv@blue-tech.org>
367  * @package phptoclib
368  * @version 1.0RC1
369  * @copyright 2005
370  * @access public
371  *
372  */
373 class Aim
374 {
375         /** 
376          * AIM ScreenName
377          *
378          * @var String
379          * @access private
380          */
381         var $myScreenName;
382         
383         /** 
384          * AIM Password (Plain Text)
385          *
386          * @var String
387          * @access private
388          */
389         var $myPassword;
390         
391
392         /** 
393          * AIM TOC Server
394          *
395          * @var String
396          * @access public
397          */
398         var $myServer="toc.oscar.aol.com";
399         
400         /** 
401          * AIM Formatted ScreenName
402          *
403          * @var String
404          * @access private
405          */
406         var $myFormatSN;
407         
408         /** 
409          * AIM TOC Server Port
410          *
411          * @var String
412          * @access public
413          */
414         var $myPort="5190";
415         
416         /** 
417          * Profile Data
418          * Use setProfile() to update
419          *
420          * @var String
421          * @access private
422          */
423         var $myProfile="Powered by phpTOCLib. Please visit http://sourceforge.net/projects/phptoclib for more information";     //The profile of the bot
424
425         /** 
426          * Socket Connection Resource ID
427          *
428          * @var Resource
429          * @access private
430          */
431         var $myConnection;  //Connection resource ID
432         
433         /** 
434          * Roasted AIM Password
435          *
436          * @var String
437          * @access private
438          */
439         var $myRoastedPass;
440         
441         /** 
442          * Last Message Recieved From Server
443          *
444          * @var String
445          * @access private
446          */
447         var $myLastReceived;
448         
449         /** 
450          * Current Seq Number Used to Communicate with Server
451          *
452          * @var Integer
453          * @access private
454          */
455         var $mySeqNum;
456          
457          /** 
458          * Current Warning Level
459          * Getter: getWarning()
460          * Setter: setWarning()
461          *
462          * @var Integer
463          * @access private
464          */
465         var $myWarnLevel;   //Warning Level of the bot
466         
467          /** 
468          * Auth Code
469          *
470          * @var Integer
471          * @access private
472          */
473         var $myAuthCode;
474         
475         /** 
476          * Buddies
477          * Getter: getBuddies()
478          *
479          * @var Array
480          * @access private
481          */
482         var $myBuddyList;
483         
484         /** 
485          * Blocked Buddies
486          * Getter: getBlocked()
487          *
488          * @var Array
489          * @access private
490          */
491         var $myBlockedList;
492         
493         /** 
494          * Permited Buddies
495          * Getter: getBlocked()
496          *
497          * @var Array
498          * @access private
499          */
500         var $myPermitList;
501         
502         /** 
503          * Permit/Deny Mode
504          * 1 - Allow All
505          * 2 - Deny All
506          * 3 - Permit only those on your permit list
507          * 4 - Permit all those not on your deny list
508          *
509          * @var Integer
510          * @access private
511          */
512         var $myPdMode;
513         
514         //Below variables added 4-29 by Jeremy: Implementing chat
515
516         /** 
517          * Contains Chat Room Info
518          * $myChatRooms['roomid'] = people in room
519          *
520          * @var Array
521          * @access private
522          */
523         var $myChatRooms;
524                 
525         //End of chat implementation
526         
527
528         /** 
529          * Event Handler Functions
530          *
531          * @var Array
532          * @access private
533          */
534         var $myEventHandlers = array();
535         
536         /** 
537          * Array of direct connection objects(including file transfers)
538          *
539          * @var Array
540          * @access private
541          */
542         var $myDirectConnections = array();
543         
544         /** 
545          * Array of the actual connections
546          *
547          * @var Array
548          * @access private
549          */
550         var $myConnections = array();
551         
552         /**
553          * The current state of logging
554          * 
555          * @var Boolean
556          * @access private
557          */
558         
559         var $myLogging = false;
560         
561     /** 
562          * Constructor
563          *
564          * Permit/Deny Mode Options
565          * 1 - Allow All
566          * 2 - Deny All
567          * 3 - Permit only those on your permit list
568          * 4 - Permit all those not on your deny list
569          *
570          * @param String $sn AIM Screenname
571          * @param String $password AIM Password
572          * @param Integer $pdmode Permit/Deny Mode
573          * @access public
574          */
575         function Aim($sn, $password, $pdmode)
576     {
577         //Constructor assignment
578                 $this->myScreenName = $this->normalize($sn);
579                 $this->myPassword = $password;
580                 $this->myRoastedPass = $this->roastPass($password);
581                 $this->mySeqNum = 1;
582                 $this->myConnection = 0;
583                 $this->myWarnLevel = 0;
584                 $this->myAuthCode = $this->makeCode();
585                 $this->myPdMode = $pdmode;
586                 $this->myFormatSN = $this->myScreenName;
587                 
588                 $this->log("PHPTOCLIB v" . PHPTOCLIB_VERSION . " Object Created");
589                 
590         }
591
592         /** 
593          * Enables debug logging (Logging is disabled by default)
594          *
595          * 
596          * @access public
597          * @return void
598          */
599
600         function setLogging($enable)
601         {
602                 $this->myLogging=$enable;
603         }
604
605         function log($data)
606         {
607             if($this->myLogging){
608             error_log($data);
609         }
610         }
611         
612          /** 
613          * Logs a packet
614          *
615          * 
616          * @access private
617          * @param Array $packary Packet
618          * @param String $in Prepend
619          * @return void
620          */
621         function logPacket($packary,$in)
622         {
623                 if(!$this->myLogging || sizeof($packary)<=0 || (@strlen($packary['decoded'])<=0 && @isset($packary['decoded'])))
624                    return;
625                 $towrite=$in . ":  ";
626                 foreach($packary as $k=>$d)
627                 {
628                         $towrite.=$k . ":" . $d . "\r\n";
629                 }
630                 $towrite.="\r\n\r\n";
631                 $this->log($towrite);
632         }
633         /** 
634          * Roasts/Hashes Password
635          *
636          * @param String $password Password
637          * @access private
638          * @return String Roasted Password
639          */
640         function roastPass($password)
641         {
642                 $roaststring = 'Tic/Toc';
643                 $roasted_password = '0x';
644                 for ($i = 0; $i < strlen($password); $i++)
645                         $roasted_password .= bin2hex($password[$i] ^ $roaststring[($i % 7)]);
646                 return $roasted_password;
647         }
648         
649         /** 
650          * Access Method for myScreenName
651          *
652          * @access public
653          * @param $formated Returns formatted Screenname if true as returned by server
654          * @return String Screenname
655          */
656         function getMyScreenName($formated = false)
657         {
658                 if ($formated)
659                 {
660                         return $this->myFormatSN;
661                 }
662                 else
663                 {
664                         return $this->normalize($this->myScreenName);
665                 }
666         }
667         
668         /** 
669          * Generated Authorization Code
670          *
671          * @access private
672          * @return Integer Auth Code
673          */
674         function makeCode()
675         {
676                 $sn = ord($this->myScreenName[0]) - 96;
677                 $pw = ord($this->myPassword[0]) - 96;
678                 $a = $sn * 7696 + 738816;
679                 $b = $sn * 746512;
680                 $c = $pw * $a;
681
682                 return $c - $a + $b + 71665152;
683         }
684
685
686         /** 
687          * Reads from Socket
688          *
689          * @access private
690          * @return String Data
691          */
692         function sflapRead()
693         {
694                 if ($this->socketcheck($this->myConnection))
695                 {
696                         $this->log("Disconnected.... Reconnecting in 60 seconds");
697                         sleep(60);
698                         $this->signon();
699                 }
700                 
701                 $header = fread($this->myConnection,SFLAP_HEADER_LEN);
702                 
703                 if (strlen($header) == 0)
704                 {
705                         $this->myLastReceived = "";
706                         return "";
707                 }
708                 $header_data = unpack("aast/Ctype/nseq/ndlen", $header);
709                 $this->log(" . ", false);
710                 $packet = fread($this->myConnection, $header_data['dlen']);
711                 if (strlen($packet) <= 0 && $sockinfo['blocked'])
712                         $this->derror("Could not read data");
713                 
714                 if ($header_data['type'] == SFLAP_TYPE_SIGNON)
715                 {
716                         $packet_data=unpack("Ndecoded", $packet);
717                 }
718                 
719                 if ($header_data['type'] == SFLAP_TYPE_KEEPALIVE)
720                 {
721                         $this->myLastReceived = '';
722                         return 0;
723                 } 
724                 else if (strlen($packet)>0)
725                 {
726                         $packet_data = unpack("a*decoded", $packet);
727                 }
728                 $this->log("socketcheck check now");
729                 if ($this->socketcheck($this->myConnection))
730                 {
731                         $this->derror("Connection ended unexpectedly");
732                 }
733                 
734                 $data = array_merge($header_data, $packet_data);
735                 $this->myLastReceived = $data;
736                 $this->logPacket($data,"in");
737                 return $data;
738     }
739
740         /** 
741          * Sends Data on Socket
742          *
743          * @param String $sflap_type Type
744          * @param String $sflap_data Data
745          * @param boolean $no_null No Null
746          * @param boolean $formatted Format
747          * @access private
748          * @return String Roasted Password
749          */
750         function sflapSend($sflap_type, $sflap_data, $no_null, $formatted)
751         {
752                 $packet = "";
753                 if (strlen($sflap_data) >= MAX_PACKLENGTH)
754                         $sflap_data = substr($sflap_data,0,MAX_PACKLENGTH);
755                         
756                 if ($formatted)
757                 {
758                         $len = strlen($sflap_len);
759                         $sflap_header = pack("aCnn",'*', $sflap_type, $this->mySeqNum, $len);
760                         $packet = $sflap_header . $sflap_data;
761                 } else {
762                         if (!$no_null)
763                         {
764                                 $sflap_data = str_replace("\0","", trim($sflap_data));
765                                 $sflap_data .= "\0";
766                         }
767                         $data = pack("a*", $sflap_data);
768                         $len = strlen($sflap_data);
769                         $header = pack("aCnn","*", $sflap_type, $this->mySeqNum, $len);
770                         $packet = $header . $data;
771                 }
772                 
773                 //Make sure we are still connected
774                 if ($this->socketcheck($this->myConnection))
775                 {
776                         $this->log("Disconnected.... reconnecting in 60 seconds");
777                         sleep(60);
778                         $this->signon();
779                 }
780                 $sent = fputs($this->myConnection, $packet) or $this->derror("Error sending packet to AIM");
781                 $this->mySeqNum++;
782                 sleep(ceil($this->myWarnLevel/10));
783                 $this->logPacket(array($sflap_type,$sflap_data),"out");
784         }
785
786         /** 
787          * Escape the thing that TOC doesn't like,that would be
788          * ",', $,{,},[,]
789          *
790          * @param String $data Data to Escape
791          * @see decodeData
792          * @access private
793          * @return String $data Escaped Data
794          */
795         function encodeData($data)
796         {
797                 $data = str_replace('"','\"', $data);
798                 $data = str_replace('$','\$', $data);
799                 $data = str_replace("'","\'", $data);
800                 $data = str_replace('{','\{', $data);
801                 $data = str_replace('}','\}', $data);
802                 $data = str_replace('[','\[', $data);
803                 $data = str_replace(']','\]', $data);
804                 return $data;
805         }
806         
807         /** 
808          * Unescape data TOC has escaped
809          * ",', $,{,},[,]
810          *
811          * @param String $data Data to Unescape
812          * @see encodeData
813          * @access private
814          * @return String $data Unescape Data
815          */
816         function decodeData($data)
817         {
818                 $data = str_replace('\"','"', $data);
819                 $data = str_replace('\$','$', $data);
820                 $data = str_replace("\'","'", $data);
821                 $data = str_replace('\{','{', $data);
822                 $data = str_replace('\}','}', $data);
823                 $data = str_replace('\[','[', $data);
824                 $data = str_replace('\]',']', $data);
825                 $data = str_replace('&quot;','"', $data);
826                 $data = str_replace('&amp;','&', $data);
827                 return $data;
828         }
829
830         /** 
831          * Normalize ScreenName
832          * no spaces and all lowercase
833          *
834          * @param String $nick ScreenName
835          * @access public
836          * @return String $nick Normalized ScreenName
837          */
838         function normalize($nick)
839         {
840                 $nick = str_replace(" ","", $nick);
841                 $nick = strtolower($nick);
842                 return $nick;
843         }
844
845         /** 
846          * Sets internal info with update buddy
847          * Currently only sets warning level
848          * 
849          * @access public
850          * @return void
851          */
852         function setMyInfo()
853         {
854                 //Sets internal values bvase on the update buddy command
855                 $this->log("Setting my warning level ...");
856                 $this->sflapSend(SFLAP_TYPE_DATA,"toc_get_status " . $this->normalize($this->myScreenName),0,0);
857                 //The rest of this will now be handled by the other functions. It is assumed
858                 //that we may have other data queued in the socket, do we should just add this
859                 //message to the queue instead of trying to set it in here
860         }
861
862         /** 
863          * Connects to AIM and Signs On Using Info Provided in Constructor
864          * 
865          * @access public
866          * @return void
867          */
868         function signon()
869         {
870                 $this->log("Ready to sign on to the server");
871                 $this->myConnection = fsockopen($this->myServer, $this->myPort, $errno, $errstr,10) or die("$errorno:$errstr");
872                 $this->log("Connected to server");
873                 $this->mySeqNum = (time() % 65536); //Select an arbitrary starting point for
874                                                                                   //sequence numbers
875                 if (!$this->myConnection)
876                         $this->derror("Error connecting to toc.oscar.aol.com");
877                 $this->log("Connected to AOL");
878                 //Send the flapon packet
879                 fputs($this->myConnection,"FLAPON\r\n\n\0"); //send the initial handshake
880                 $this->log("Sent flapon");
881                 $this->sflapRead();  //Make sure the server responds with what we expect
882                 if (!$this->myLastReceived)
883                         $this->derror("Error sending the initialization string");
884
885                 //send the FLAP SIGNON packet back with what it needs
886                 //There are 2 parts to the signon packet. They are sent in succession, there
887                 //is no indication if either packet was correctly sent
888                 $signon_packet = pack("Nnna".strlen($this->myScreenName),1,1,strlen($this->myScreenName), $this->myScreenName);
889                 $this->sflapSend(SFLAP_TYPE_SIGNON, $signon_packet,1,0);
890                 $this->log("sent signon packet part one");
891                 
892                 $signon_packet_part2 = 'toc2_signon login.oscar.aol.com 29999 ' . $this->myScreenName . ' ' . $this->myRoastedPass . ' english-US "TIC:TOC2:REVISION" 160 ' . $this->myAuthCode;
893                 $this->log($signon_packet_part2 . "");
894                 $this->sflapSend(SFLAP_TYPE_DATA, $signon_packet_part2,0,0);
895                 $this->log("Sent signon packet part 2... Awaiting response...");
896
897                 $this->sflapRead();
898                 $this->log("Received Sign on packet, beginning initilization...");
899                 $message = $this->getLastReceived();
900                 $this->log($message . "\n");
901                 if (strstr($message,"ERROR:"))
902                 {
903                         $this->onError($message);
904                         die("Fatal signon error");
905                 }
906                 stream_set_timeout($this->myConnection,2);
907                 //The information sent before the config2 command is utterly useless to us
908                 //So we will just skim through them until we reach it
909                 
910                 //Add the first entry to the connection array
911                 $this->myConnections[] = $this->myConnection;
912                 
913                 
914                 //UPDATED 4/12/03: Now this will use the receive function and send the
915                 //received messaged to the assigned handlers. This is where the signon 
916                 //method has no more use
917                 
918                 $this->log("Done with signon proccess");
919                 //socket_set_blocking($this->myConnection,false);
920         }
921         
922         /** 
923          * Sends Instant Message
924          *
925          * @param String $to Message Recipient SN
926          * @param String $message Message to Send
927          * @param boolean $auto Sent as Auto Response / Away Message Style
928          * @access public
929          * @return void
930          */
931         function sendIM($to, $message, $auto = false)
932         {
933                 if ($auto) $auto = "auto";
934                 else $auto = "";
935                 $to = $this->normalize($to);
936                 $message = $this->encodeData($message);
937                 $command = 'toc2_send_im "' . $to . '" "' . $message . '" ' .  $auto;
938                 $this->sflapSend(SFLAP_TYPE_DATA, trim($command),0,0);
939                 $cleanedmessage = str_replace("<br>", "   ", $this->decodeData($message));
940                 $cleanedmessage = strip_tags($cleanedmessage);
941                 $this->log("TO - " . $to . " : " . $cleanedmessage);
942         }
943         
944         /** 
945          * Set Away Message
946          *
947          * @param String $message Away message (some HTML supported).
948          *   Use null to remove the away message
949          * @access public
950          * @return void
951          */
952         function setAway($message)
953         {
954                 $message = $this->encodeData($message);
955                 $command = 'toc_set_away "' . $message . '"';
956                 $this->sflapSend(SFLAP_TYPE_DATA, trim($command),0,0);
957                 $this->log("SET AWAY MESSAGE - " . $this->decodeData($message));
958         }
959
960         /** 
961          * Fills Buddy List
962          * Not implemented fully yet
963          *
964          * @access public
965          * @return void
966          */
967         function setBuddyList()
968         {
969                 //This better be the right message
970                 $message = $this->myLastReceived['decoded'];
971                 if (strpos($message,"CONFIG2:") === false)
972                 {
973                         $this->log("setBuddyList cannot be called at this time because I got $message");
974                         return false;
975                 }
976                 $people = explode("\n",trim($message,"\n"));
977                 //The first 3 elements of the array are who knows what, element 3 should be
978                 //a letter followed by a person
979                 for($i = 1; $i<sizeof($people); $i++)
980                 {
981                         @list($mode, $name) = explode(":", $people[$i]);
982                         switch($mode)
983                         {
984                                 case 'p':
985                                         $this->myPermitList[] = $name;
986                                         break;
987                                 case 'd':
988                                         $this->myBlockedList[] = $name;
989                                         break;
990                                 case 'b':
991                                         $this->myBuddyList[] = $name;
992                                         break;
993                                 case 'done':
994                                         break;
995                                 default:
996                                         //
997                         }
998                 }
999         }
1000         
1001         /** 
1002          * Adds buddy to Permit list
1003          *
1004          * @param String $buddy Buddy's Screenname
1005          * @access public
1006          * @return void
1007          */
1008         function addPermit($buddy)
1009         {
1010                 $this->sflapSend(SFLAP_TYPE_DATA,"toc2_add_permit " . $this->normalize($buddy),0,0);
1011                 $this->myPermitList[] = $this->normalize($buddy);
1012                 return 1;
1013         }
1014         
1015         /** 
1016          * Blocks buddy
1017          *
1018          * @param String $buddy Buddy's Screenname
1019          * @access public
1020          * @return void
1021          */
1022         function blockBuddy($buddy)
1023         {
1024                 $this->sflapSend(SFLAP_TYPE_DATA,"toc2_add_deny " . $this->normalize($buddy),0,0);
1025                 $this->myBlockedList[] = $this->normalize($buddy);
1026                 return 1;
1027         }
1028         
1029         /** 
1030          * Returns last message received from server
1031          *
1032          * @access private
1033          * @return String Last Message from Server
1034          */
1035         function getLastReceived()
1036         {
1037                 if (@$instuff = $this->myLastReceived['decoded']){
1038                         return $this->myLastReceived['decoded'];
1039                 }else{
1040                         return;
1041                 }
1042         }
1043         
1044         /** 
1045          * Returns Buddy List
1046          *
1047          * @access public
1048          * @return array Buddy List
1049          */
1050         function getBuddies()
1051         {
1052                 return $this->myBuddyList;
1053         }
1054         
1055         /** 
1056          * Returns Permit List
1057          *
1058          * @access public
1059          * @return array Permit List
1060          */
1061         function getPermit()
1062         {
1063                 return $this->myPermitList;
1064         }
1065         
1066         /** 
1067          * Returns Blocked Buddies
1068          *
1069          * @access public
1070          * @return array Blocked List
1071          */
1072         function getBlocked()
1073         {
1074                 return $this->myBlockedList;
1075         }
1076         
1077         
1078
1079
1080         /** 
1081          * Reads and returns data from server
1082          *
1083          * This is a wrapper for $Aim->sflap_read(), and only returns the $this->myLastReceived['data']
1084          * portion of the message. It is preferred that you do not call $Aim->sflap_read() and use this
1085          * function instead. This function has a return value. Calling this prevents the need to call
1086          * $Aim->getLastReceived()
1087          *
1088          * @access public
1089          * @return String Data recieved from server
1090          */
1091         function read_from_aim()
1092         {
1093                 $this->sflapRead();
1094                 $returnme = $this->getLastReceived();
1095                 return $returnme;
1096         }
1097         
1098         /** 
1099          * Sets current internal warning level
1100          * 
1101          * This allows you to update the bots warning level when warned.
1102          *
1103          * @param int Warning Level %
1104          * @access private
1105          * @return void
1106          */
1107         function setWarningLevel($warnlevel)
1108         {
1109                 $this->myWarnLevel = $warnlevel;
1110         }
1111         
1112         /** 
1113          * Warns / "Evils" a User
1114          *
1115          * To successfully warn another user they must have sent you a message.
1116          * There is a limit on how much and how often you can warn another user.
1117          * Normally when you warn another user they are aware who warned them,
1118          * however there is the option to warn anonymously.  When warning anon.
1119          * note that the warning is less severe.
1120          *
1121          * @param String $to Screenname to warn
1122          * @param boolean $anon Warn's anonymously if true. (default = false)
1123          * @access public
1124          * @return void
1125          */
1126         function warnUser($to, $anon = false)
1127         {
1128                 if (!$anon)
1129                         $anon = '"norm"';
1130
1131                 else
1132                         $anon = '"anon"';
1133                 $this->sflapSend(SFLAP_TYPE_DATA,"toc_evil " . $this->normalize($to) . " $anon",0,0);
1134         }
1135         
1136         /** 
1137          * Returns warning level of bot
1138          *
1139          * @access public
1140          * @return void
1141          */
1142         function getWarningLevel()
1143         {
1144                 return $this->myWarningLevel;
1145         }
1146         
1147         /** 
1148          * Sets bot's profile/info
1149          *
1150          * Limited to 1024 bytes.
1151          *
1152          * @param String $profiledata Profile Data (Can contain limited html: br,hr,font,b,i,u etc)
1153          * @param boolean $poweredby If true, appends link to phpTOCLib project to profile
1154          * @access public
1155          * @return void
1156          */
1157         function setProfile($profiledata, $poweredby = false)
1158         {
1159                 if ($poweredby == false){
1160                         $this->myProfile = $profiledata;
1161                 }else{
1162                         $this->myProfile = $profiledata . "<font size=1 face=tahoma><br><br>Powered by phpTOCLib<br>http://sourceforge.net/projects/phptoclib</font>";
1163                 }
1164                 
1165                 $this->sflapSend(SFLAP_TYPE_DATA,"toc_set_info \"" . $this->encodeData($this->myProfile) . "\"",0,0);
1166                 $this->setMyInfo();
1167                 $this->log("Profile has been updated...");
1168         }
1169         
1170         //6/29/04 by Jeremy:
1171         //Added mthod to accept a rvous,decline it, and
1172         //read from the rvous socket
1173         
1174         //Decline
1175         
1176         /** 
1177          * Declines a direct connection request (rvous)
1178          *
1179          * @param String $nick ScreenName request was from
1180          * @param String $cookie Request cookie (from server)
1181          * @param String $uuid UUID
1182          * 
1183          * @access public
1184          * @return void
1185          */
1186         function declineRvous($nick, $cookie, $uuid)
1187         {
1188                 $nick = $this->normalize($nick);
1189                 $this->sflapSend(SFLAP_TYPE_DATA,"toc_rvous_cancel $nick $cookie $uuid",0,0);
1190         }
1191         
1192         /** 
1193          * Accepts a direct connection request (rvous)
1194          *
1195          * @param String $nick ScreenName request was from
1196          * @param String $cookie Request cookie (from server)
1197          * @param String $uuid UUID
1198          * @param String $vip IP of User DC with
1199          * @param int $port Port number to connect to
1200          * 
1201          * @access public
1202          * @return void
1203          */
1204         function acceptRvous($nick, $cookie, $uuid, $vip, $port)
1205         {
1206                 $this->sflapSend(SFLAP_TYPE_DATA,"toc_rvous_accept $nick $cookie $uuid",0,0);
1207                 
1208                 //Now open the connection to that user
1209                 if ($uuid == IMAGE_UID)
1210                 {       
1211                         $dcon = new Dconnect($vip, $port);
1212                 }
1213                 else if ($uuid == FILE_SEND_UID)
1214                 {
1215                         $dcon = new FileSendConnect($vip, $port);
1216                 }
1217                 if (!$dcon->connected)
1218                 {
1219                         $this->log("The connection failed");                            
1220                         return false;
1221                 }
1222                 
1223                 //Place this dcon object inside the array
1224                 $this->myDirectConnections[] = $dcon;
1225                 //Place the socket in an array to
1226                 $this->myConnections[] = $dcon->sock;
1227
1228                 
1229                 //Get rid of the first packet because its worthless
1230                 //and confusing
1231                 $dcon->readDIM();
1232                 //Assign the cookie
1233                 $dcon->cookie = $dcon->lastReceived['cookie'];
1234                 $dcon->connectedTo = $this->normalize($nick);
1235                 return $dcon;
1236         }       
1237         
1238         /** 
1239          * Sends a Message over a Direct Connection
1240          *
1241          * Only works if a direct connection is already established with user
1242          *
1243          * @param String $to Message Recipient SN
1244          * @param String $message Message to Send
1245          * 
1246          * @access public
1247          * @return void
1248          */
1249         function sendDim($to, $message)
1250         {
1251                 //Find the connection
1252                 for($i = 0;$i<sizeof($this->myDirectConnections);$i++)
1253                 {
1254                         if ($this->normalize($to) == $this->myDirectConnections[$i]->connectedTo && $this->myDirectConnections[$i]->type == CONN_TYPE_DC)
1255                         {
1256                                 $dcon = $this->myDirectConnections[$i];
1257                                 break;
1258                         }
1259                 }
1260                 if (!$dcon)
1261                 {
1262                         $this->log("Could not find a direct connection to $to");
1263                         return false;
1264                 }
1265                 $dcon->sendMessage($message, $this->normalize($this->myScreenName));
1266                 return true;
1267         }
1268         
1269         /** 
1270          * Closes an established Direct Connection
1271          *
1272          * @param DConnect $dcon Direct Connection Object to Close
1273          * 
1274          * @access public
1275          * @return void
1276          */
1277         function closeDcon($dcon)
1278         {
1279                 
1280                 $nary = array();
1281                 for($i = 0;$i<sizeof($this->myConnections);$i++)
1282                 {
1283                         if ($dcon->sock == $this->myConnections[$i])
1284                                 unset($this->myConnections[$i]);
1285                 }
1286                 
1287                 $this->myConnections = array_values($this->myConnections);
1288                 unset($nary);
1289                 $nary2 = array();
1290                 
1291                 for($i = 0;$i<sizeof($this->myDirectConnections);$i++)
1292                 {
1293                         if ($dcon == $this->myDirectConnections[$i])
1294                                 unset($this->myDirectConnections[$i]);
1295                 }
1296                 $this->myDirectConnections = array_values($this->myDirectConnections);
1297                 $dcon->close();
1298                 unset($dcon);
1299         }
1300         
1301         //Added 4/29/04 by Jeremy:
1302         //Various chat related methods
1303         
1304         /** 
1305          * Accepts a Chat Room Invitation (Joins room)
1306          *
1307          * @param String $chatid ID of Chat Room
1308          * 
1309          * @access public
1310          * @return void
1311          */
1312         function joinChat($chatid)
1313         {
1314                 $this->sflapSend(SFLAP_TYPE_DATA,"toc_chat_accept " . $chatid,0,0);
1315         }
1316         
1317         /** 
1318          * Leaves a chat room
1319          *
1320          * @param String $chatid ID of Chat Room
1321          * 
1322          * @access public
1323          * @return void
1324          */
1325         function leaveChat($chatid)
1326         {
1327                 $this->sflapSend(SFLAP_TYPE_DATA,"toc_chat_leave " . $chatid,0,0);
1328         }
1329         
1330         /** 
1331          * Sends a message in a chat room
1332          *
1333          * @param String $chatid ID of Chat Room
1334          * @param String $message Message to send
1335          * 
1336          * @access public
1337          * @return void
1338          */
1339         function chatSay($chatid, $message)
1340         {
1341                 $this->sflapSend(SFLAP_TYPE_DATA,"toc_chat_send " . $chatid . " \"" . $this->encodeData($message) . "\"",0,0);
1342         }
1343         
1344         /** 
1345          * Invites a user to a chat room
1346          *
1347          * @param String $chatid ID of Chat Room
1348          * @param String $who Screenname of user
1349          * @param String $message Note to include with invitiation
1350          * 
1351          * @access public
1352          * @return void
1353          */
1354         function chatInvite($chatid, $who, $message)
1355         {
1356                 $who = $this->normalize($who);
1357                 $this->sflapSend(SFLAP_TYPE_DATA,"toc_chat_invite " . $chatid . " \"" . $this->encodeData($message) . "\" " . $who,0,0);
1358         }
1359         
1360         /** 
1361          * Joins/Creates a new chat room
1362          *
1363          * @param String $name Name of the new chat room
1364          * @param String $exchange Exchange of new chat room
1365          * 
1366          * @access public
1367          * @return void
1368          */
1369         function joinNewChat($name, $exchange)
1370         {
1371                 //Creates a new chat
1372                 $this->sflapSend(SFLAP_TYPE_DATA,"toc_chat_join " . $exchange . " \"" . $name . "\"",0,0);
1373         }
1374         
1375         /** 
1376          * Disconnect error handler, attempts to reconnect in 60 seconds
1377          *
1378          * @param String $message Error message (desc of where error encountered etc)
1379          * 
1380          * @access private
1381          * @return void
1382          */
1383         function derror($message)
1384         {
1385                 $this->log($message);
1386                 $this->log("Error");
1387                 fclose($this->myConnection);
1388                 if ((time() - $GLOBALS['errortime']) <  600){
1389                         $this->log("Reconnecting in 60 Seconds");
1390                         sleep(60);
1391                 }
1392                 $this->signon();
1393                 $GLOBALS['errortime'] = time();
1394         }
1395         
1396         /** 
1397          * Returns connection type of socket (main or rvous etc)
1398          *
1399          * Helper method for recieve()
1400          *
1401          * @param Resource $sock Socket to determine type for
1402          * 
1403          * @access private
1404          * @return void
1405          * @see receive
1406          */
1407         function connectionType($sock)
1408         {
1409                 //Is it the main connection?
1410                 if ($sock == $this->myConnection)
1411                    return CONN_TYPE_NORMAL;
1412                 else
1413                 {
1414                         for($i = 0;$i<sizeof($this->myDirectConnections);$i++)
1415                         {
1416                                 if ($sock == $this->myDirectConnections[$i]->sock)
1417                                     return $this->myDirectConnections[$i]->type;
1418                         }
1419                 }
1420                 return false;
1421         }
1422         
1423         /** 
1424          * Checks for new data and calls appropriate methods
1425          *
1426          * This method is usually called in an infinite loop to keep checking for new data
1427          * 
1428          * @access public
1429          * @return void
1430          * @see connectionType
1431          */ 
1432         function receive()
1433         {
1434                 //This function will be used to get the incoming data
1435                 //and it will be used to call the event handlers
1436                 
1437                 //First, get an array of sockets that have data that is ready to be read
1438                 $ready = array();
1439                 $ready = $this->myConnections;
1440                 $numrdy = stream_select($ready, $w = NULL, $x = NULL,NULL);
1441                 
1442                 //Now that we've waited for something, go through the $ready
1443                 //array and read appropriately
1444                 
1445                 for($i = 0;$i<sizeof($ready);$i++)
1446                 {
1447                         //Get the type
1448                         $type = $this->connectionType($ready[$i]);
1449                         if ($type == CONN_TYPE_NORMAL)
1450                         {
1451                                 //Next step:Get the data sitting in the socket
1452                                 $message = $this->read_from_aim();
1453                                 if (strlen($message) <= 0)
1454                                 {
1455                                         return;
1456                                 }
1457                                 
1458                                 //Third step: Get the command from the server
1459                                 @list($cmd, $rest) = explode(":", $message);
1460                                 
1461                                 //Fourth step, take the command, test the type, and pass it off
1462                                 //to the correct internal handler. The internal handler will
1463                                 //do what needs to be done on the class internals to allow
1464                                 //it to work, then proceed to pass it off to the user created handle
1465                                 //if there is one
1466                                 $this->log($cmd);
1467                                 switch($cmd)
1468                                 {
1469                                         case 'SIGN_ON':
1470                                                 $this->onSignOn($message);
1471                                                 break;
1472                                         case 'CONFIG2':
1473                                                 $this->onConfig($message);
1474                                                 break;
1475                                         case 'ERROR':
1476                                                 $this->onError($message);
1477                                                 break;
1478                                         case 'NICK':
1479                                                 $this->onNick($message);
1480                                                 break;
1481                                         case 'IM_IN2':
1482                                                 $this->onImIn($message);
1483                                                 break;
1484                                         case 'UPDATE_BUDDY2':
1485                                                 $this->onUpdateBuddy($message);
1486                                                 break;
1487                                         case 'EVILED':
1488                                                 $this->onWarn($message);
1489                                                 break;
1490                                         case 'CHAT_JOIN':
1491                                                 $this->onChatJoin($message);
1492                                                 break;
1493                                         case 'CHAT_IN':
1494                                                 $this->onChatIn($message);
1495                                                 break;
1496                                         case 'CHAT_UPDATE_BUDDY':
1497                                                 $this->onChatUpdate($message);
1498                                                 break;
1499                                         case 'CHAT_INVITE':
1500                                                 $this->onChatInvite($message);
1501                                                 break;
1502                                         case 'CHAT_LEFT':
1503                                                 $this->onChatLeft($message);
1504                                                 break;
1505                                         case 'GOTO_URL':
1506                                                 $this->onGotoURL($message);
1507                                                 break;
1508                                         case 'DIR_STATUS':
1509                                                 $this->onDirStatus($message);
1510                                                 break;
1511                                         case 'ADMIN_NICK_STATUS':
1512                                                 $this->onAdminNick($message);
1513                                                 break;
1514                                         case 'ADMIN_PASSWD_STATUS':
1515                                                 $this->onAdminPasswd($message);
1516                                                 break;
1517                                         case 'PAUSE':
1518                                                 $this->onPause($message);
1519                                                 break;
1520                                         case 'RVOUS_PROPOSE':
1521                                                 $this->onRvous($message);
1522                                                 break;
1523                                         default:
1524                                                 $this->log("Fell through: $message");
1525                                                 $this->CatchAll($message);
1526                                                 break;
1527                                 }
1528                         }
1529                         else
1530                         {
1531                                 for($j = 0;$j<sizeof($this->myDirectConnections);$j++)
1532                                 {
1533                                         if ($this->myDirectConnections[$j]->sock == $ready[$i])
1534                                         {
1535                                                 $dcon = $this->myDirectConnections[$j];
1536                                                 break;
1537                                         }
1538                                 }
1539                                 //Now read from the dcon
1540                                 if ($dcon->type == CONN_TYPE_DC)
1541                                 {
1542                                         if ($dcon->readDIM() == false)
1543                                         {
1544                                                 $this->closeDcon($dcon);
1545                                                 continue;
1546                                         }
1547                                         
1548                                         $message['message'] = $dcon->lastMessage;
1549                                         if ($message['message'] == "too big")
1550                                         {
1551                                                 $this->sendDim("Connection dropped because you sent a message larger that " . MAX_DCON_SIZE . " bytes.", $dcon->connectedTo);
1552                                                 $this->closeDcon($dcon);
1553                                                 continue;
1554                                         }
1555                                         $message['from'] = $dcon->connectedTo;
1556                                         $this->onDimIn($message);
1557                                 }
1558                         }
1559                 }
1560         $this->conn->myLastReceived="";
1561                 //Now get out of this function because the handlers should take care
1562                 //of everything
1563         }
1564         
1565         //The next block of code is all the event handlers needed by the class
1566         //Some are left blank and only call the users handler because the class
1567         //either does not support the command, or cannot do anything with it
1568         // ---------------------------------------------------------------------
1569
1570         /** 
1571          * Direct IM In Event Handler
1572          *
1573          * Called when Direct IM is received.
1574          * Call's user handler (if available) for DimIn.
1575          * 
1576          * @access private
1577          * @param String $data Raw message from server
1578          * @return void
1579          */
1580         function onDimIn($data)
1581         {
1582                 $this->callHandler("DimIn", $data);
1583         }
1584         
1585         /** 
1586          * Sign On Event Handler
1587          *
1588          * Called when Sign On event occurs.
1589          * Call's user handler (if available) for SIGN_ON.
1590          * 
1591          * @access private
1592          * @param String $data Raw message from server
1593          * @return void
1594          */
1595         function onSignOn($data)
1596         {
1597                 $this->callHandler("SignOn", $data);
1598         }
1599         
1600         /** 
1601          * Config Event Handler
1602          *
1603          * Called when Config data received.
1604          * Call's user handler (if available) for Config.
1605          * 
1606          * Loads buddy list and other info
1607          * 
1608          * @access private
1609          * @param String $data Raw message from server
1610          * @return void
1611          */
1612         function onConfig($data)
1613         {
1614                 $this->log("onConfig Message: " . $data);
1615                 
1616                 if (strpos($data,"CONFIG2:") === false)
1617                 {
1618                         $this->log("get_buddy_list cannot be called at this time because I got $data");
1619                         //return false;
1620                 }
1621                 $people = explode("\n",trim($data,"\n"));
1622                 //The first 3 elements of the array are who knows what, element 3 should be
1623                 //a letter followed by a person
1624                 
1625                 //AIM decided to add this wonderful new feature, the recent buddy thing, this kind of
1626                 //messes this funtion up, so we need to adapt it... unfortuneately, its not really
1627                 //clear how this works, so we are just going to add their name to the permit list.
1628                 
1629                 //Recent buddies I believe are in the format
1630                 //number:name:number.... I think the first number counts down from 25 how long its
1631                 //been... but I don't know the second number,,,,
1632                 
1633                 //TODO: Figure out the new recent buddies system
1634                 
1635                 //Note: adding that at the bottom is a quick hack and may have adverse consequences...
1636                 for($i = 1;$i<sizeof($people);$i++)
1637                 {
1638                         @list($mode, $name) = explode(":", $people[$i]);
1639                         switch($mode)
1640                         {
1641                                 case 'p':
1642                                         $this->myPermitList[] = $name;
1643                                         break;
1644                                 case 'd':
1645                                         $this->myBlockedList[] = $name;
1646                                         break;
1647                                 case 'b':
1648                                         $this->myBuddyList[] = $name;
1649                                         break;
1650                                 case 'done':
1651                                         break;
1652                                 default:
1653                                         //This is assumed to be recent buddies...
1654                                         $this->myPermitList[]=$name;
1655                         }
1656                 }
1657                 
1658                 //We only get the config message once, so now we should send our pd mode
1659                 
1660                 $this->sflapSend(SFLAP_TYPE_DATA,"toc2_set_pdmode " . $this->myPdMode,0,0);
1661                 //Adds yourself to the permit list
1662                 //This is to fix an odd behavior if you have nobody on your list
1663                 //the server won't send the config command... so this takes care of it
1664                 $this->sflapSend(SFLAP_TYPE_DATA,"toc2_add_permit " . $this->normalize($this->myScreenName),0,0); 
1665                 
1666                 //Now we allow the user to send a list, update anything they want, etc
1667                 $this->callHandler("Config", $data);
1668                 //Now that we have taken care of what the user wants, send the init_done message
1669                 $this->sflapSend(SFLAP_TYPE_DATA,"toc_init_done",0,0);
1670                 //'VOICE_UID' 
1671                 //'FILE_GET_UID'
1672                 //'IMAGE_UID'
1673                 //'BUDDY_ICON_UID'
1674                 //'STOCKS_UID'
1675                 //'GAMES_UID'
1676                 $this->sflapSend(SFLAP_TYPE_DATA, "toc_set_caps " . IMAGE_UID . " " .  FILE_SEND_UID ." " . FILE_GET_UID . " " . BUDDY_ICON_UID . "",0,0);
1677         }
1678         
1679
1680         /** 
1681          * Error Event Handler
1682          *
1683          * Called when an Error occurs.
1684          * Call's user handler (if available) for Error.
1685          * 
1686          * @access private
1687          * @param String $data Raw message from server
1688          * @return void
1689          */
1690         function onError($data)
1691         {
1692             static $errarg = '';
1693                 static $ERRORS = array(\r
1694             0=>'Success',\r
1695             901 =>'$errarg not currently available',\r
1696             902 =>'Warning of $errarg not currently available',\r
1697             903 =>'A message has been dropped, you are exceeding\r
1698                   the server speed limit',\r
1699             911 =>'Error validating input',\r
1700             912 =>'Invalid account',\r
1701             913 =>'Error encountered while processing request',\r
1702             914 =>'Service unavailable',\r
1703             950 =>'Chat in $errarg is unavailable.',\r
1704             960 =>'You are sending message too fast to $errarg',\r
1705             961 =>'You missed an im from $errarg because it was too big.',\r
1706             962 =>'You missed an im from $errarg because it was sent too fast.',\r
1707             970 =>'Failure',\r
1708             971 =>'Too many matches',\r
1709             972 =>'Need more qualifiers',\r
1710             973 =>'Dir service temporarily unavailable',\r
1711             974 =>'Email lookup restricted',\r
1712             975 =>'Keyword Ignored',\r
1713             976 =>'No Keywords',\r
1714             977 =>'Language not supported',\r
1715             978 =>'Country not supported',\r
1716             979 =>'Failure unknown $errarg',\r
1717             980 =>'Incorrect nickname or password.',\r
1718             981 =>'The service is temporarily unavailable.',\r
1719             982 =>'Your warning level is currently too high to sign on.',\r
1720             983 =>'You have been connecting and\r
1721                    disconnecting too frequently.  Wait 10 minutes and try again.\r
1722                        If you continue to try, you will need to wait even longer.',\r
1723             989 =>'An unknown signon error has occurred $errarg'\r
1724             );
1725                 $data_array = explode(":", $data);
1726                 for($i=0; $i<count($data_array); $i++)
1727                 {
1728             switch($i)
1729             {
1730                 case 0:
1731                     $cmd = $data_array[$i];
1732                     break;
1733                 case 1:
1734                     $errornum = $data_array[$i];
1735                     break;
1736                 case 2:
1737                     $errargs = $data_array[$i];
1738                     break;
1739             }
1740                 }
1741                 eval("\$errorstring=\"\$ERRORS[" . $errornum . "]\";");
1742                 $string = "\$errorstring=\"\$ERRORS[$errornum]\";";
1743                 //This is important information! We need 
1744                 // a A different outputter for errors
1745                 // b Just to echo it
1746                 //I'm just going to do a straight echo here, becuse we assume that
1747                 //the user will NEED to see this error. An option to supress it will
1748                 //come later I think. Perhaps if we did an error reporting level, similar
1749                 //to PHP's, and we could probably even use PHP's error outputting system
1750                 //I think that may be an idea.... 
1751                 
1752                 $this->log($errorstring . "\n");
1753                 
1754                 $this->callHandler("Error", $data);
1755         }
1756         
1757         /** 
1758          * Nick Event Handler
1759          *
1760          * Called when formatted own ScreenName is receieved
1761          * Call's user handler (if available) for Nick.
1762          * 
1763          * @access private
1764          * @param String $data Raw message from server
1765          * @return void
1766          */
1767         function onNick($data)
1768         {
1769                 //This is our nick, so set a field called "myFormatSN" which will represent
1770                 //the actual name given by the server to us, NOT the normalized screen name
1771                 @list($cmd, $nick) = explode(":", $data);
1772                 $this->myFormatSN = $nick;
1773                 
1774                 $this->callHandler("Nick", $data);
1775         }
1776         
1777         /** 
1778          * IM In Event Handler
1779          *
1780          * Called when an Instant Message is received.
1781          * Call's user handler (if available) for IMIn.
1782          * 
1783          * @access private
1784          * @param String $data Raw message from server
1785          * @return void
1786          */
1787         function onImIn($data)
1788         {
1789                 //Perhaps we should add an internal log for debugging purposes??
1790                 //But now, this should probably be handled by the user purely
1791                 
1792                 $this->callHandler("IMIn", $data);
1793         }
1794         
1795         /** 
1796          * UpdateBuddy Event Handler
1797          *
1798          * Called when a Buddy Update is receieved.
1799          * Call's user handler (if available) for UpdateBuddy.
1800          * If info is about self, updates self info (Currently ownly warning).
1801          *
1802          * ToDo: Keep track of idle, warning etc on Buddy List
1803          * 
1804          * @access private
1805          * @param String $data Raw message from server
1806          * @return void
1807          */
1808         function onUpdateBuddy($data)
1809         {
1810                 //Again, since our class currently does not deal with other people without
1811                 //outside help, then this is also probably best left to the user. Though
1812                 //we should probably allow this to replace the setMyInfo function above
1813                 //by handling the input if and only if it is us
1814                 //Check and see that this is the command expected
1815                 if (strpos($data,"UPDATE_BUDDY2:") == -1)
1816                 {
1817                         $this->log("A different message than expected was received");
1818                         return false;
1819                 }
1820                 
1821                 //@list($cmd, $info['sn'], $info['online'], $info['warnlevel'], $info['signon'], $info['idle'], $info['uc']) = explode(":", $command['incoming']);
1822
1823                 //@list($cmd, $sn, $online, $warning, $starttime, $idletime, $uc) = explode(":", $data);
1824                 $info = $this->getMessageInfo($data);
1825                 if ($this->normalize($info['sn']) == $this->normalize($this->myScreenName))
1826                 {
1827                         $warning = rtrim($info['warnlevel'],"%");
1828                         $this->myWarnLevel = $warning;
1829                         $this->log("My warning level is $this->myWarnLevel %");
1830                 }
1831                 
1832                 $this->callHandler("UpdateBuddy", $data);
1833         }
1834         
1835         /** 
1836          * Warning Event Handler
1837          *
1838          * Called when bot is warned.
1839          * Call's user handler (if available) for Warn.
1840          * Updates internal warning level
1841          * 
1842          * @access private
1843          * @param String $data Raw message from server
1844          * @return void
1845          */
1846         function onWarn($data)
1847         {
1848                 /*
1849                 For reference:
1850                         $command['incoming'] .= ":0";
1851                         $it = explode(":", $command['incoming']);
1852                         $info['warnlevel'] = $it[1];
1853                         $info['from'] = $it[2];         
1854                 */
1855                 //SImply update our warning level
1856                 //@list($cmd, $newwarn, $user) = explode(":", $data);
1857                 
1858                 $info = $this->getMessageInfo($data);
1859                 
1860                 $this->setWarningLevel(trim($info['warnlevel'],"%"));
1861                 $this->log("My warning level is $this->myWarnLevel %");
1862                 
1863                 $this->callHandler("Warned", $data);
1864         }
1865         
1866         /** 
1867          * Chat Join Handler
1868          *
1869          * Called when bot joins a chat room.
1870          * Call's user handler (if available) for ChatJoin.
1871          * Adds chat room to internal chat room list.
1872          * 
1873          * @access private
1874          * @param String $data Raw message from server
1875          * @return void
1876          */
1877         function onChatJoin($data)
1878         {
1879                 @list($cmd, $rmid, $rmname) = explode(":", $data);
1880                 $this->myChatRooms[$rmid] = 0;
1881                 
1882                 $this->callHandler("ChatJoin", $data);
1883         }
1884         
1885         /** 
1886          * Returns number of chat rooms bot is in
1887          * 
1888          * @access public
1889          * @param String $data Raw message from server
1890          * @return int
1891          */
1892         function getNumChats()
1893         {
1894                 return count($this->myChatRooms);
1895         }
1896         
1897         /** 
1898          * Chat Update Handler
1899          *
1900          * Called when bot received chat room data (user update).
1901          * Call's user handler (if available) for ChatUpdate.
1902          * 
1903          * @access private
1904          * @param String $data Raw message from server
1905          * @return void
1906          */
1907         function onChatUpdate($data)
1908         {
1909                 $stuff = explode(":", $data);
1910                 $people = sizeof($stuff);
1911                 $people -= 2;
1912                 
1913                 $this->callHandler("ChatUpdate", $data);
1914         }
1915         
1916         /** 
1917          * Chat Message In Handler
1918          *
1919          * Called when chat room message is received.
1920          * Call's user handler (if available) for ChatIn.
1921          * 
1922          * @access private
1923          * @param String $data Raw message from server
1924          * @return void
1925          */
1926         function onChatIn($data)
1927         {
1928                 $this->callHandler("ChatIn", $data);
1929         }
1930         
1931         
1932         /** 
1933          * Chat Invite Handler
1934          *
1935          * Called when bot is invited to a chat room.
1936          * Call's user handler (if available) for ChatInvite.
1937          * 
1938          * @access private
1939          * @param String $data Raw message from server
1940          * @return void
1941          */
1942         function onChatInvite($data)
1943         {
1944                 //@list($cmd, $name, $id, $from, $data) = explode(":", $data,6);
1945                 //$data = explode(":",$data,6);
1946                 //$nm = array();
1947                 //@list($nm['cmd'],$nm['name'],$nm['id'],$nm['from'],$nm['message']) = $data;
1948                 
1949                 
1950                 $this->callHandler("ChatInvite", $data);
1951         }
1952         
1953         /** 
1954          * Chat Left Handler
1955          *
1956          * Called when bot leaves a chat room
1957          * Call's user handler (if available) for ChatLeft.
1958          * 
1959          * @access private
1960          * @param String $data Raw message from server
1961          * @return void
1962          */
1963         function onChatLeft($data)
1964         {
1965                 $info = $this->getMessageInfo($data);
1966                 unset($this->myChatRooms[$info['chatid']]);
1967                 $this->callHandler("ChatLeft", $data);
1968         }
1969         
1970         /** 
1971          * Goto URL Handler
1972          *
1973          * Called on GotoURL.
1974          * Call's user handler (if available) for GotoURL.
1975          * No detailed info available for this / Unsupported.
1976          * 
1977          * @access private
1978          * @param String $data Raw message from server
1979          * @return void
1980          */
1981         function onGotoURL($data)
1982         {
1983                 //This is of no use to the internal class
1984                 
1985                 $this->callHandler("GotoURL", $data);
1986         }
1987         
1988         /** 
1989          * Dir Status Handler
1990          *
1991          * Called on DirStatus.
1992          * Call's user handler (if available) for DirStatus.
1993          * No detailed info available for this / Unsupported.
1994          * 
1995          * @access private
1996          * @param String $data Raw message from server
1997          * @return void
1998          */
1999         function onDirStatus($data)
2000         {
2001                 //This is not currently suported
2002                 
2003                 $this->callHandler("DirStatus", $data);
2004         }
2005         
2006         /** 
2007          * AdminNick Handler
2008          *
2009          * Called on AdminNick.
2010          * Call's user handler (if available) for AdminNick.
2011          * No detailed info available for this / Unsupported.
2012          * 
2013          * @access private
2014          * @param String $data Raw message from server
2015          * @return void
2016          */
2017         function onAdminNick($data)
2018         {
2019                 //NOt particularly useful to us         
2020                 $this->callHandler("AdminNick", $data);
2021         }
2022         
2023         /** 
2024          * AdminPasswd Handler
2025          *
2026          * Called on AdminPasswd.
2027          * Call's user handler (if available) for AdminPasswd.
2028          * No detailed info available for this / Unsupported.
2029          * 
2030          * @access private
2031          * @param String $data Raw message from server
2032          * @return void
2033          */
2034         function onAdminPasswd($data)
2035         {
2036                 //Also not particlualry useful to the internals
2037                 $this->callHandler("AdminPasswd", $data);
2038         }
2039         
2040         /** 
2041          * Pause Handler
2042          *
2043          * Called on Pause.
2044          * Call's user handler (if available) for Pause.
2045          * No detailed info available for this / Unsupported.
2046          * 
2047          * @access private
2048          * @param String $data Raw message from server
2049          * @return void
2050          */
2051         function onPause($data)
2052         {
2053                 //This is pretty useless to us too...
2054                 
2055                 $this->callHandler("Pause", $data);
2056         }
2057         
2058         /** 
2059          * Direct Connection Handler
2060          *
2061          * Called on Direct Connection Request(Rvous).
2062          * Call's user handler (if available) for Rvous.
2063          * 
2064          * @access private
2065          * @param String $data Raw message from server
2066          * @return void
2067          */
2068         function onRvous($data)
2069         {
2070                 $this->callHandler("Rvous", $data);
2071         }
2072         
2073         /** 
2074          * CatchAll Handler
2075          *
2076          * Called for unrecognized commands.
2077          * Logs unsupported messages to array.
2078          * Call's user handler (if available) for CatchAll.
2079          * 
2080          * @access private
2081          * @param String $data Raw message from server
2082          * @return void
2083          */
2084         function CatchAll($data)
2085         {
2086                 //Add to a log of unsupported messages.
2087                 
2088                 $this->unsupported[] = $data;
2089                 //$this->log($data);
2090                 //print_r($data);
2091                 
2092                 $this->callHandler("CatchAll", $data);
2093         }
2094         
2095         /** 
2096          * Calls User Handler
2097          *
2098          * Calls registered handler for a specific event.
2099          * 
2100          * @access private
2101          * @param String $event Command (event) name (Rvous etc)
2102          * @param String $data Raw message from server
2103          * @see registerHandler
2104          * @return void
2105          */
2106         function callHandler($event, $data)
2107         {
2108                 
2109                 if (isset($this->myEventHandlers[$event]))
2110                 {
2111                         //$function = $this->myEventHandlers[$event] . "(\$data);";
2112                         //eval($function);
2113                         call_user_func($this->myEventHandlers[$event], $data);
2114                 }
2115                 else
2116                 {
2117                         $this->noHandler($data);
2118                 }
2119         }
2120         
2121         /** 
2122          * Registers a user handler
2123          * 
2124          * Handler List
2125          * SignOn, Config, ERROR, NICK, IMIn, UpdateBuddy, Eviled, Warned, ChatJoin
2126          * ChatIn, ChatUpdate, ChatInvite, ChatLeft, GotoURL, DirStatus, AdminNick
2127          * AdminPasswd, Pause, Rvous, DimIn, CatchAll
2128          *
2129          * @access private
2130          * @param String $event Event name
2131          * @param String $handler User function to call
2132          * @see callHandler
2133          * @return boolean Returns true if successful
2134          */
2135         function registerHandler($event, $handler)
2136         {
2137                 if (is_callable($handler))
2138                 {
2139                         $this->myEventHandlers[$event] = $handler;
2140                         return true;
2141                 }
2142                 else
2143                 {
2144                         return false;
2145                 }
2146         }
2147
2148     /** 
2149      * No user handler method fall back.
2150      *
2151      * Does nothing with message.
2152      *
2153      * @access public
2154      * @param String $message Raw server message
2155      * @return void
2156      */
2157     function noHandler($message)
2158     {
2159             //This function intentionally left blank
2160             //This is where the handlers will fall to for now. I plan on including a more
2161             //efficent check to avoid the apparent stack jumps that this code will produce
2162             //But for now, just fall into here, and be happy
2163             return;
2164     }
2165
2166     //GLOBAL FUNCTIONS
2167
2168     /** 
2169      * Finds type, and returns as part of array ['type']
2170      * Puts message in ['incoming']
2171      *
2172      * Helper method for getMessageInfo.
2173      *
2174      * @access public
2175      * @param String $message Raw server message
2176      * @see msg_parse
2177      * @see getMessageInfo
2178      * @return array
2179      */
2180     static function msg_type($message)
2181     {
2182             $command = array();
2183             @list($cmd, $rest) = explode(":", $message);
2184             switch($cmd)
2185             {
2186                     case 'IM_IN2':
2187                             $type = AIM_TYPE_MSG;
2188                     break;
2189                 
2190                     case 'UPDATE_BUDDY2':
2191                             $type = AIM_TYPE_UPDATEBUDDY;
2192                     break;
2193                 
2194                     case 'EVILED':
2195                             $type = AIM_TYPE_WARN;
2196                     break;
2197                 
2198                     case 'SIGN_ON':
2199                             $type = AIM_TYPE_SIGNON;
2200                     break;
2201                 
2202                     case 'NICK':
2203                             $type = AIM_TYPE_NICK;
2204                     break;
2205                 
2206                     case 'ERROR':
2207                             $type = AIM_TYPE_ERROR;
2208                     break;
2209                 
2210                     case 'CHAT_JOIN':
2211                             $type = AIM_TYPE_CHATJ;
2212                     break;
2213                 
2214                     case 'CHAT_IN':
2215                             $type = AIM_TYPE_CHATI;
2216                     break;
2217                 
2218                     case 'CHAT_UPDATE_BUDDY':
2219                             $type = AIM_TYPE_CHATUPDBUD;
2220                     break;
2221                 
2222                     case 'CHAT_INVITE':
2223                             $type = AIM_TYPE_CHATINV;
2224                     break;
2225                 
2226                     case 'CHAT_LEFT':
2227                             $type = AIM_TYPE_CHATLE;
2228                     break;
2229                 
2230                     case 'GOTO_URL':
2231                             $type = AIM_TYPE_URL;
2232                     break;
2233                 
2234                     case 'ADMIN_NICK_STATUS':
2235                             $type = AIM_TYPE_NICKSTAT;
2236                     break;
2237                 
2238                     case 'ADMIN_PASSWD_STATUS':
2239                             $type = AIM_TYPE_PASSSTAT;
2240                     break;
2241                 
2242                     case 'RVOUS_PROPOSE':
2243                             $type = AIM_TYPE_RVOUSP;
2244                     break;
2245                 
2246                     default:
2247                             $type = AIM_TYPE_NOT_IMPLEMENTED;
2248                     break;
2249             }
2250             $command['type'] = $type;
2251             $command['incoming'] = $message;
2252             return $command;
2253     }
2254
2255     /** 
2256      * Parses message and splits into info array
2257      *
2258      * Helper method for getMessageInfo.
2259      *
2260      * @access public
2261      * @param String $command Message and type (after msg_type)
2262      * @see msg_type
2263      * @see getMessageInfo
2264      * @return array
2265      */
2266     static function msg_parse($command)
2267     {
2268             $info = array();
2269             switch($command['type'])
2270             {
2271                     case AIM_TYPE_WARN:
2272                             $command['incoming'] .= ":0";
2273                             $it = explode(":", $command['incoming']);
2274                             $info['warnlevel'] = $it[1];
2275                             $info['from'] = $it[2];
2276
2277                     break;
2278                 
2279                     case AIM_TYPE_MSG:
2280                             $it = explode(":", $command['incoming'],5);
2281                             $info['auto'] = $it[2];
2282                             $info['from'] = $it[1];
2283                             $info['message'] = $it[4];
2284                     break;
2285                 
2286                     case AIM_TYPE_UPDATEBUDDY:
2287                             @list($cmd, $info['sn'], $info['online'], $info['warnlevel'], $info['signon'], $info['idle'], $info['uc']) = explode(":", $command['incoming']);
2288                     break;
2289                 
2290                     case AIM_TYPE_SIGNON:
2291                             @list($cmd, $info['version']) = explode(":", $command['incoming']);         
2292                     break;
2293                 
2294                     case AIM_TYPE_NICK:
2295                             @list($cmd, $info['nickname']) = explode(":", $command['incoming']);                
2296                     break;
2297                     case AIM_TYPE_ERROR:
2298                             @list($cmd, $info['errorcode'], $info['args']) = explode(":", $command['incoming']);
2299                     break;
2300                 
2301                     case AIM_TYPE_CHATJ:
2302                             @list($cmd, $info['chatid'], $info['chatname']) = explode(":", $command['incoming']);
2303                     break;
2304                 
2305                     case AIM_TYPE_CHATI:
2306                             @list($cmd, $info['chatid'], $info['user'], $info['whisper'], $info['message']) = explode(":", $command['incoming'],5);
2307                     break;
2308                 
2309                     case AIM_TYPE_CHATUPDBUD:
2310                             @list($cmd, $info['chatid'], $info['inside'], $info['userlist']) = explode(":", $command['incoming'],3);    
2311                     break;
2312                 
2313                     case AIM_TYPE_CHATINV:
2314                             @list($cmd, $info['chatname'], $info['chatid'], $info['from'], $info['message']) = explode(":", $command['incoming'],5);
2315                     break;
2316                 
2317                     case AIM_TYPE_CHATLE:
2318                             @list($cmd, $info['chatid']) = explode(":", $command['incoming']);          
2319                     break;
2320                 
2321                     case AIM_TYPE_URL:
2322                             @list($cmd, $info['windowname'], $info['url']) = explode(":", $command['incoming'],3);
2323                     break;
2324                 
2325                     case AIM_TYPE_RVOUSP:
2326                             @list($cmd,$info['user'],$info['uuid'],$info['cookie'],$info['seq'],$info['rip'],$info['pip'],$info['vip'],$info['port'],$info['tlvs']) = explode(":",$command['incoming'],10);
2327                     break;
2328                 
2329                     case AIM_TYPE_NICKSTAT:
2330                     case AIM_TYPE_PASSSTAT:
2331                             @list($cmd, $info['returncode'], $info['opt']) = explode(":", $command['incoming'],3);              
2332                     break;
2333                 
2334                     default:
2335                     $info['command'] = $command['incoming'];
2336             }
2337             return $info;
2338     }
2339
2340     /** 
2341      * Returns a parsed message
2342      *
2343      * Calls msg_parse(msg_type( to first determine message type and then parse accordingly
2344      *
2345      * @access public
2346      * @param String $command Raw server message
2347      * @see msg_type
2348      * @see msg_parse
2349      * @return array
2350      */
2351     static function getMessageInfo($message)
2352     {
2353             return self::msg_parse(self::msg_type($message));
2354     }
2355
2356     /** 
2357      * Checks socket for end of file
2358      *
2359      * @access public
2360      * @param Resource $socket Socket to check
2361      * @return boolean true if end of file (socket) 
2362      */
2363     static function socketcheck($socket){
2364             $info = stream_get_meta_data($socket);
2365             return $info['eof'];
2366             //return(feof($socket));
2367     }
2368 }
2369
2370 ?>