PHP Classes

File: ex_announcements.php

Recommend this page to a friend!
  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: 16 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); } ?>