Login   Register  
PHP Classes
elePHPant
Icontem

File: ex_announcements.php

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of sk89q  >  BlueTOC  >  ex_announcements.php  >  Download  
File: ex_announcements.php
Role: Example script
Content type: text/plain
Description: Example PHP AIM IM list
Class: BlueTOC
AIM client using TOC instant messaging protocol
Author: By
Last change: Public
Date: 8 years ago
Size: 16,688 bytes
 

Contents

Class file image Download
 <?php
/*
 * This is a more complex and complete example.
 *
 * This bot is an announcement bot where users may subscribe
 * to an AIM-hosted message list. IM it to use it once it 
 * is running. The list of subscribers will be written to disk, 
 * as well as the archive of messages. Users that are offline
 * will still receive the message (up to three are stored). 
 * This is mostly proof of concept (I think) due to the rate 
 * limiting issues with AIM.
 *
 * There is currently no way to administrate the list of 
 * subscribers or the archive.
 *
 * This is not too well documented yet.
 *
 * To get it working:
 * (1) Configure username and password
 * (2) Non-Windows: Chmod the current directory writable
 * (3) Start up script
 * (4) Talk to bot
 * 
 * Only one instance of this application can be running. 
 * It has not been written to be safe to run with
 * multiple threads.
 */
 
// We must include the BlueToc libraries
require_once "bluetoc/EventHandlers/ObjectBased.php";
require_once "bluetoc/TocProtocol.php";
require_once "bluetoc/AimClient.php";

// We define our own class, extending AimClient
class AnnouncementsBot extends AimClient
{        
    var $name = '';
    var $subscribers_file = '';
    var $messages_file = '';
    var $backlog_file = '';
    var $max_subscribers = 20;
    var $max_message_length = 60;
    var $archive_size = 5;
    var $backlog_user_size = 3;
    var $backlog_cutoff_time = 1209600; // 14 days = 2 weeks
    var $admins = array();
    
    var $subscribers = array();
    var $messages = array();
    var $backlog = array();
    
    var $online = array();
    
    function AnnouncementsBot($user, $pass, $name, $subscribers_file, $messages_file, $backlog_file, $admins)
    {        
        // Debug mode is by default off
        $this->debug_mode = false;
        
        $this->aim_user = $user;
        $this->aim_pass = $pass;
        
        $this->name = $name;
        $this->subscribers_file = $subscribers_file;
        $this->messages_file = $messages_file;
        $this->backlog_file = $backlog_file;
        
        foreach($admins as $user)
        {
            $this->admins[] = $this->normalize_string($user);
        }
        
        $this->subscribers = $this->read_archive($this->subscribers_file);
        $this->messages = $this->read_archive($this->messages_file);
        $this->backlog = $this->read_archive($this->backlog_file);
        
        // Backlog cleanup
        foreach($this->backlog as $user => $bl)
        {
            foreach((array) $this->backlog[$user] as $k => $msg)
            {
                if($msg[0] < time() - $this->backlog_cutoff_time)
                {
                    unset($this->backlog[$user][$k]);
                }
            }
        }
        foreach($this->backlog as $user => $bl)
        {
            if(!$this->backlog[$user]) unset($this->backlog[$user]);
        }
        $this->write_archive($this->backlog_file, $this->backlog);
        
        echo "* The IM list '{$this->name}' is signing on...\n";
        
        $this->connect();
    }
    
    function read_archive($file)
    {
        return (array) @unserialize(@file_get_contents($file));
    }
    
    function write_archive($file, $data)
    {
        $data = serialize($data);
        
        $fp = fopen($file, "w");
        flock($fp, LOCK_EX);
        fwrite($fp, $data);
        flock($fp, LOCK_UN);
        fclose($fp);
    }
    
    function build_reply($message)
    {
        return <<<EOB
<font face=Arial><b><u>{$this->name} IM List</u></b></font><br>
$message
EOB;
    }
    
    // Handle once we've signed on
    function event_sign_on($args)
    {
        // Let's re-add all the subscribers anyway
        foreach($this->subscribers as $user)
        {
            $list .= "\nb:$user";
        }
        if($list)
        {
            $this->add_buddies("g:Subscribers$list");
        }
                
        echo "* The IM list '{$this->name}' has signed online as {$this->aim_user}\n";
        echo "* Buddies:\n{$args['config']}\n";
    }
    
    // Handle when we get an instant message
    function event_im($args)
    {        
        $user = $this->normalize_string($args['user']);
        
        // Remember that AIM IMs usually have HTML
        // so we must strip it so that we can
        // easily parse it
        $message = strip_tags($args['message']);
        
        echo "* Received an instant message from: {$args['user']} -> $message\n";
        
        // Subscription command
        if(strtolower($message) == "subscribe")
        {
            // Check whether the user is already subscribed or not
            if(in_array($user, $this->subscribers))
            {
                $reply = "ERROR! You are already subscribed to this list.";
                $this->send_im($args['user'], $this->build_reply($reply), false);
            }
            // Limit the number of subscribers allowed
            else if(count($this->subscribers) >= $this->max_subscribers)
            {
                $reply = "ERROR! There are already too many people subscribed to this list (max: {$this->max_subscribers})";
                $this->send_im($args['user'], $this->build_reply($reply), false);
            }
            // Subscribe
            else
            {
                // We need to keep track of who is online to track them
                $this->add_buddies("g:Subscribers\nb:$user");
                
                $this->subscribers[] = $user;
                $this->write_archive($this->subscribers_file, $this->subscribers);
                
                $reply = "SUCCESS! You have been subscribed. Tell me <b>unsubscribe</b> to leave this list at any time.";
                $this->send_im($args['user'], $this->build_reply($reply), false);
            }
        }
        // Unsubscribe command
        else if(strtolower($message) == "unsubscribe")
        {
            // Check whether the user is subscribed or not
            if(!in_array($user, $this->subscribers))
            {
                $reply = "ERROR! You <i>aren't</i> subscribed.";
                $this->send_im($args['user'], $this->build_reply($reply), false);
            }
            else
            {
                // Remove from tracking
                $this->remove_buddy($user, "Subscribers");
                
                $this->subscribers = array_diff($this->subscribers, array($user));
                $this->write_archive($this->subscribers_file, $this->subscribers);
                
                unset($this->online[$user]);
                
                $reply = "SUCCESS! We are sorry for you to leave, but you have been removed.";
                $this->send_im($args['user'], $this->build_reply($reply), false);
            }
        }
        // Message archival
        else if(preg_match("#^archive( (.*))?$#is", $message, $m))
        {
            if(!$m[2])
            {
                print_r($this->messages);
                $messages = array();
                foreach($this->messages as $msg)
                {
                    // Command is archive DATETIMESTAMP
                    $messages[] = "{$msg[0]}:<br><strong>archive {$msg[2]}</strong>";
                }
                
                $reply = "Please type the bolded command to read:<br><br>" . implode("<br><br>", $messages);
                $this->send_im($args['user'], $this->build_reply($reply), false);
            }
            else
            {
                // The date timestamp is stored in array key 2
                // We need to look for that
                $i = -1;
                foreach($this->messages as $k => $msg)
                {
                    if($msg[2] == $m[2])
                    {
                        $i = $k;
                        break;
                    }
                }
                
                if($this->messages[$i])
                {
                    $msg = $this->messages[$i];
                    
                    $reply = "Date: {$msg[0]}<br>{$msg[1]}";
                    $this->send_im($args['user'], $this->build_reply($reply), false);
                }
                else
                {
                    $reply = "ERROR! The requested message does not eixst.";
                    $this->send_im($args['user'], $this->build_reply($reply), false);
                }
            }
        }
        // Posting command
        else if(preg_match("#^post( (.*))?$#is", $message, $m))
        {
            if(!in_array($user, $this->admins))
            {
                $reply = "ERROR! You <i>aren't</i> an administrator. You cannot post to this list.";
                $this->send_im($args['user'], $this->build_reply($reply), false);
            }
            else if(strlen($m[2]) > $this->max_message_length)
            {
                $reply = "ERROR! Your message is too long.";
                $this->send_im($args['user'], $this->build_reply($reply), false);
            }
            else if(!$m[2])
            {
                $reply = "ERROR! You must enter a message.";
                $this->send_im($args['user'], $this->build_reply($reply), false);
            }
            else
            {
                $time = time();
                $this->messages[] = array(date("r", $time), "From: {$user}<br>{$m[2]}", $time);
                while(count($this->messages) > $this->archive_size) array_shift($this->messages);
                $this->write_archive($this->messages_file, $this->messages);
                
                $reply = "SUCCESS! The message has been posted!";
                $this->send_im($args['user'], $this->build_reply($reply), false);
                
                // This loops through all the users...
                // And locks up everything =/
                $m = $this->build_reply("From: {$user}<br>{$m[2]}");
                foreach($this->subscribers as $sub)
                {
                    if($this->online[$sub])
                    {
                        $this->send_im($sub, $m, true);
                        usleep(1000000 / 2);
                    }
                    // Send when they're online!
                    else
                    {
                        $this->backlog[$sub][] = array($time, "Date: " . date("r", $time) . "<br>From: {$user}<br>{$m[2]}");
                        while(count($this->backlog[$sub]) > $this->backlog_user_size) array_shift($this->backlog[$sub]);
                    }
                }
                
                $this->write_archive($this->backlog_file, $this->backlog);
            }
        }
        // About command
        else if(strtolower($message) == "about")
        {
            $reply = "This announcement IM list is derived from the <i>ex_announcements.php</i> example from the <a href=\"http://www.therisenrealm.com/scripts/bluetoc/\">BlueTOC</a> PHP AIM connection class";
            $this->send_im($args['user'], $this->build_reply($reply), false);
        }
        else
        {
            $reply = "Welcome to this list. Repeat back the follow commands to interact with me:<br>" .
                     "<b>subscribe</b> - Subscribe to this IM list<br>" .
                     "<b>unsubscribe</b> - Unsubscribe to this IM list<br>" .
                     "<b>archive</b> - View this list's archive<br>" .
                     "<b>post</b> - Post to this list (admins only)<br>" .
                     "<b>about</b> - About this list<br>";
            $this->send_im($args['user'], $this->build_reply($reply), false);
        }
    }
    
    function event_buddy_update($args)
    {
        $user = $this->normalize_string($args['user']);
        
        echo "Online: {$user}: " . ($args['is_online'] ? "Online" : "Offline") . "\n";
        
        if($args['is_online'])
        {
            $this->online[$user] = 1;
            
            // Sends back log
            if($this->backlog[$user])
            {
                // This loops through all the messages...
                // And locks up everything =/
                foreach($this->backlog[$user] as $msg)
                {
                    if($msg[0] < time() - $this->backlog_cutoff_time) continue;
                    $this->send_im($user, $this->build_reply($msg[1]), true);
                    usleep(1000000 / 2);
                }
                
                unset($this->backlog[$user]);
                $this->write_archive($this->backlog_file, $this->backlog);
            }
        }
        else
        {
            unset($this->online[$user]);
        }
    }
    
    function event_error($args)
    {
        // These are a list of errors in English
        // Most, if not all, errors will return an error number
        // and not the error description
        $connection_errors = array(
            100 => 'Data unable to be sent',
            200 => 'Flapon',
            201 => 'Data not received from server after FLAPON packet',
            202 => 'Invalid FLAP SIGNON response from the server',
            203 => 'Invalid response from the server' );
        
        $aim_errors = array(
            0 => 'Success',
            1 => 'AOLIM Error: Unknown Error',
            2 => 'AOLIM Error: Incorrect Arguments',
            3 => 'AOLIM Error: Exceeded Max Packet Length (1024)',
            4 => 'AOLIM Error: Reading from server',
            5 => 'AOLIM Error: Sending to server',
            6 => 'AOLIM Error: Login timeout',
            901 => 'General Error: %s not currently available',
            902 => 'General Error: Warning of %s not currently available',
            903 => 'General Error: A message has been dropped, you are exceeding the 
                    server speed limit',
            950 => 'Chat Error: Chat in %s is unavailable',
            960 => 'IM and Info Error: You are sending messages too fast to %s',
            961 => 'IM and Info Error: You missed an IM from %s because it was too big',
            962 => 'IM and Info Error: You missed an IM from %s because it was sent
                    too fast',
            970 => 'Dir Error: Failure',
            971 => 'Dir Error: Too many matches',
            972 => 'Dir Error: Need more qualifiers',
            973 => 'Dir Error: Dir service temporarily unavailble',
            974 => 'Dir Error: Email lookup restricted',
            975 => 'Dir Error: Keyword ignored',
            976 => 'Dir Error: No keywords',
            977 => 'Dir Error: Language not supported',
            978 => 'Dir Error: Country not supported',
            979 => 'Dir Error: Failure unknown %s',
            980 => 'Auth Error: Incorrect nickname or password',
            981 => 'Auth Error: The service is temporarily unavailable',
            982 => 'Auth Error: Your warning level is too high to sign on',
            983 => 'Auth Error: You have been connecting and disconnecting too frequently.
                    Wait 10 minutes and try again. If you continue to try, you will need to
                    wait even longer.',
            989 => 'Auth Error: An unknown signon error has occurred %s' ); 
            
        // Let's see what kind of error we are faced with
        switch($args['type'])
        {
            // Connection error
            case ERROR_CONNECTION:
                echo "* Connection error: {$connection_errors[$args['number']]} ({$args['number']})\n";
                break;
            // AIM is giving us an error
            case ERROR_AIM:
                echo "* AIM error: {$aim_errors[$args['number']]} ({$args['number']})\n";
                break;
        }
    }
}

// Create a new instance of the bot
$client = new AnnouncementsBot('username1', 'password1',
                               $name = "Latest Updates",
                               $subscribers_file = "ex_announce_subs.txt",
                               $messages_file = "ex_announce_msgs.txt",
                               $backlog_file = "ex_announce_backlog.txt",
                               $admins = array("username2", "username3", "username4"));

// Listen to the bot infinitely
while(true)
{
    $client->listen();
    usleep(150);
}
?>