Merge in Phergie changes

This commit is contained in:
Luke Fitzgerald 2010-08-04 16:02:24 -07:00
parent 65a741cce2
commit cb34d95197
35 changed files with 1646 additions and 748 deletions

2
plugins/Irc/extlib/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
Settings.php
*.db

View File

@ -254,7 +254,7 @@ class Phergie_Connection
if (!in_array($this->encoding, mb_list_encodings())) {
throw new Phergie_Connection_Exception(
'Encoding ' . $this->encoding . ' is not supported',
Phergie_Connection_Exception::ENCODING_NOT_SUPPORTED
Phergie_Connection_Exception::ERR_ENCODING_NOT_SUPPORTED
);
}

View File

@ -41,4 +41,10 @@ class Phergie_Connection_Exception extends Phergie_Exception
* but that transport is not supported by the current PHP installation
*/
const ERR_TRANSPORT_NOT_SUPPORTED = 2;
/**
* Error indicating that a connection is configured to use an encoding,
* but that encoding is not supported by the current PHP installation
*/
const ERR_ENCODING_NOT_SUPPORTED = 3;
}

View File

@ -243,6 +243,7 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
// Parse the command and arguments
list($cmd, $args) = array_pad(explode(' ', $buffer, 2), 2, null);
$hostmask = new Phergie_Hostmask(null, null, $this->connection->getHost());
} else {
// If the event could be from the server or a user...

View File

@ -270,7 +270,7 @@ abstract class Phergie_Plugin_Abstract
*/
public function getEvent()
{
if (empty($this->connection)) {
if (empty($this->event)) {
throw new Phergie_Plugin_Exception(
'Event cannot be accessed before one is set',
Phergie_Plugin_Exception::ERR_NO_EVENT

View File

@ -1,6 +1,6 @@
<?php
/**
* Phergie
* Phergie
*
* PHP version 5
*
@ -11,7 +11,7 @@
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
* @category Phergie
* @category Phergie
* @package Phergie_Plugin_Acl
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
@ -20,14 +20,48 @@
*/
/**
* Provides an access control system to limit reponses to events based on
* Provides an access control system to limit reponses to events based on
* the users who originate them.
*
* @category Phergie
* Configuration settings:
* acl.whitelist - mapping of user hostmask patterns (optionally by host) to
* plugins and methods where those plugins and methods will
* only be accessible to those users (i.e. and inaccessible
* to other users)
* acl.blacklist - mapping of user hostmasks (optionally by host) to plugins
* and methods where where those plugins and methods will be
* inaccessible to those users but accessible to other users
* acl.ops - TRUE to automatically give access to whitelisted plugins
* and methods to users with ops for events they initiate in
* channels where they have ops
*
* The whitelist and blacklist settings are formatted like so:
* <code>
* 'acl.whitelist' => array(
* 'hostname1' => array(
* 'pattern1' => array(
* 'plugins' => array(
* 'ShortPluginName'
* ),
* 'methods' => array(
* 'methodName'
* )
* ),
* )
* ),
* </code>
*
* The hostname array dimension is optional; if not used, rules will be
* applied across all connections. The pattern is a user hostmask pattern
* where asterisks (*) are used for wildcards. Plugins and methods do not
* need to be set to empty arrays if they are not used; simply exclude them.
*
* @category Phergie
* @package Phergie_Plugin_Acl
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Acl
* @uses Phergie_Plugin_UserInfo pear.phergie.org
*/
class Phergie_Plugin_Acl extends Phergie_Plugin_Abstract
{
@ -38,6 +72,8 @@ class Phergie_Plugin_Acl extends Phergie_Plugin_Abstract
*/
public function onLoad()
{
$this->plugins->getPlugin('UserInfo');
if (!$this->getConfig('acl.blacklist')
&& !$this->getConfig('acl.whitelist')
) {
@ -46,47 +82,105 @@ class Phergie_Plugin_Acl extends Phergie_Plugin_Abstract
}
/**
* Checks permission settings and short-circuits event processing for
* Applies a set of rules to a plugin handler iterator.
*
* @param Phergie_Plugin_Iterator $iterator Iterator to receive rules
* @param array $rules Associate array containing
* either a 'plugins' key pointing to an array containing plugin
* short names to filter, a 'methods' key pointing to an array
* containing method names to filter, or both
*
* @return void
*/
protected function applyRules(Phergie_Plugin_Iterator $iterator, array $rules)
{
if (!empty($rules['plugins'])) {
$iterator->addPluginFilter($rules['plugins']);
}
if (!empty($rules['methods'])) {
$iterator->addMethodFilter($rules['methods']);
}
}
/**
* Checks permission settings and short-circuits event processing for
* blacklisted users.
*
* @return bool FALSE to short-circuit event processing if the user is
* blacklisted, TRUE otherwise
* @return void
*/
public function preEvent()
{
// Ignore server responses
if ($this->event instanceof Phergie_Event_Response) {
return true;
return;
}
// Ignore server-initiated events
if (!$this->event->isFromUser()) {
return true;
return;
}
// Determine whether a whitelist or blacklist is being used
$list = $this->getConfig('acl.whitelist');
$matches = true;
if (!$list) {
$list = $this->getConfig('acl.blacklist');
$matches = false;
}
// Get the iterator used to filter plugins when processing events
$iterator = $this->plugins->getIterator();
// Support host-specific lists
// Get configuration setting values
$whitelist = $this->getConfig('acl.whitelist', array());
$blacklist = $this->getConfig('acl.blacklist', array());
$ops = $this->getConfig('acl.ops', false);
// Support host-specific lists
$host = $this->connection->getHost();
if (isset($list[$host])) {
$list = $list[$host];
}
// Short-circuit event processing if appropriate
$hostmask = $this->event->getHostmask();
foreach ($list as $pattern) {
if ($hostmask->matches($pattern)) {
return $matches;
foreach (array('whitelist', 'blacklist') as $var) {
foreach ($$var as $pattern => $rules) {
$regex = '/^' . str_replace('*', '.*', $pattern) . '$/i';
if (preg_match($regex, $host)) {
${$var} = ${$var}[$pattern];
break;
}
}
}
// Allow event processing if appropriate
return !$matches;
// Get information on the user initiating the current event
$hostmask = $this->event->getHostmask();
$isOp = $ops
&& $this->event->isInChannel()
&& $this->plugins->userInfo->isOp(
$this->event->getNick(),
$this->event->getSource()
);
// Filter whitelisted commands if the user is not on the whitelist
if (!$isOp) {
$whitelisted = false;
foreach ($whitelist as $pattern => $rules) {
if ($hostmask->matches($pattern)) {
$whitelisted = true;
}
}
if (!$whitelisted) {
foreach ($whitelist as $pattern => $rules) {
$this->applyRules($iterator, $rules);
}
}
}
// Filter blacklisted commands if the user is on the blacklist
$blacklisted = false;
foreach ($blacklist as $pattern => $rules) {
if ($hostmask->matches($pattern)) {
$this->applyRules($iterator, $rules);
break;
}
}
}
/**
* Clears filters on the plugin handler iterator.
*
* @return void
*/
public function postDispatch()
{
$this->plugins->getIterator()->clearFilters();
}
}

View File

@ -35,6 +35,7 @@ $beers = $xpath->query('//table[@class="beerlist"]/tr/td[1]');
$db->beginTransaction();
foreach ($beers as $beer) {
$name = iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $beer->textContent);
$name = preg_replace('/\h*\v+\h*/', '', $name);
$link = 'http://beerme.com' . $beer->childNodes->item(1)->getAttribute('href');
$insert->execute(array($name, $link));
}
@ -66,6 +67,7 @@ $db->beginTransaction();
while ($line = fgetcsv($fp, 0, '|')) {
$line = array_combine($columns, $line);
$name = iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $line['name']);
$name = preg_replace('/\h*\v+\h*/', '', $name);
$link = null;
$insert->execute(array($name, $link));
}

View File

@ -0,0 +1,69 @@
<?php
/**
* Phergie
*
* PHP version 5
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
* @category Phergie
* @package Phergie_Plugin_Caffeine
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Caffeine
*/
/**
* Processes requests to serve users caffeinated beverages.
*
* @category Phergie
* @package Phergie_Plugin_Caffeine
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Caffeine
* @uses Phergie_Plugin_Command pear.phergie.org
* @uses Phergie_Plugin_Serve pear.phergie.org
*/
class Phergie_Plugin_Caffeine extends Phergie_Plugin_Abstract
{
/**
* Checks for dependencies.
*
* @return void
*/
public function onLoad()
{
$plugins = $this->plugins;
$plugins->getPlugin('Command');
$plugins->getPlugin('Serve');
}
/**
* Processes requests to serve a user a caffeinated beverage.
*
* @param string $request Request including the target and an optional
* suggestion of what caffeinated beverage to serve
*
* @return void
*/
public function onCommandCaffeine($request)
{
$format = $this->getConfig(
'beer.format',
'throws %target% %article% %item%.'
);
$this->plugins->getPlugin('Serve')->serve(
dirname(__FILE__) . '/Caffeine/caffeine.db',
'caffeine',
$format,
$request
);
}
}

View File

@ -0,0 +1,51 @@
<?php
if (!defined('__DIR__')) {
define('__DIR__', dirname(__FILE__));
}
// Create database schema
echo 'Creating database', PHP_EOL;
$file = __DIR__ . '/caffeine.db';
if (file_exists($file)) {
unlink($file);
}
$db = new PDO('sqlite:' . $file);
$db->exec('CREATE TABLE caffeine (name VARCHAR(255), link VARCHAR(255))');
$db->exec('CREATE UNIQUE INDEX caffeine_name ON caffeine (name)');
$insert = $db->prepare('INSERT INTO caffeine (name, link) VALUES (:name, :link)');
// Get raw energyfiend.com data set
echo 'Downloading energyfiend.com data set', PHP_EOL;
$file = __DIR__ . '/the-caffeine-database.html';
if (!file_exists($file)) {
copy('http://www.energyfiend.com/the-caffeine-database', $file);
}
$contents = file_get_contents($file);
// Extract data from data set
echo 'Processing energyfiend.com data', PHP_EOL;
$contents = tidy_repair_string($contents);
libxml_use_internal_errors(true);
$doc = new DOMDocument;
$doc->loadHTML($contents);
libxml_clear_errors();
$xpath = new DOMXPath($doc);
$caffeine = $xpath->query('//table[@id="caffeinedb"]//tr/td[1]');
$db->beginTransaction();
foreach ($caffeine as $drink) {
$name = iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $drink->textContent);
$name = preg_replace('/\s*\v+\s*/', ' ', $name);
if ($drink->firstChild->nodeName == 'a') {
$link = 'http://energyfiend.com'
. $drink->firstChild->getAttribute('href');
} else {
$link = null;
}
$insert->execute(array($name, $link));
}
$db->commit();
// Clean up
echo 'Cleaning up', PHP_EOL;
unlink($file);

62
plugins/Irc/extlib/phergie/Phergie/Plugin/Command.php Executable file → Normal file
View File

@ -1,6 +1,6 @@
<?php
/**
* Phergie
* Phergie
*
* PHP version 5
*
@ -11,7 +11,7 @@
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
* @category Phergie
* @category Phergie
* @package Phergie_Plugin_Command
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
@ -20,20 +20,28 @@
*/
/**
* Handles parsing and execution of commands sent by users via messages sent
* Handles parsing and execution of commands sent by users via messages sent
* to channels in which the bot is present or directly to the bot.
*
* @category Phergie
* @category Phergie
* @package Phergie_Plugin_Command
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Command
* @uses extension reflection
* @uses Phergie_Plugin_Message pear.phergie.org
*/
class Phergie_Plugin_Command extends Phergie_Plugin_Abstract
{
/**
* Cache for command lookups used to confirm that methods exist and
* Prefix for command method names
*
* @var string
*/
const METHOD_PREFIX = 'onCommand';
/**
* Cache for command lookups used to confirm that methods exist and
* parameter counts match
*
* @var array
@ -41,24 +49,28 @@ class Phergie_Plugin_Command extends Phergie_Plugin_Abstract
protected $methods = array();
/**
* Prefix for command method names
* Load the Message plugin
*
* @var string
* @return void
*/
protected $methodPrefix = 'onCommand';
public function onLoad()
{
$plugins = $this->getPluginHandler();
$plugins->getPlugin('Message');
}
/**
* Populates the methods cache.
*
* @return void
*/
protected function populateMethodCache()
public function populateMethodCache()
{
foreach ($this->getPluginHandler() as $plugin) {
foreach ($this->getPluginHandler()->getPlugins() as $plugin) {
$reflector = new ReflectionClass($plugin);
foreach ($reflector->getMethods() as $method) {
$name = $method->getName();
if (strpos($name, $this->methodPrefix) === 0
if (strpos($name, self::METHOD_PREFIX) === 0
&& !isset($this->methods[$name])
) {
$this->methods[$name] = array(
@ -84,26 +96,26 @@ class Phergie_Plugin_Command extends Phergie_Plugin_Abstract
$this->populateMethodCache();
}
// Get the content of the message
$event = $this->getEvent();
$msg = trim($event->getText());
$prefix = $this->getConfig('command.prefix');
// Check for the command prefix if one is set and needed
if ($prefix && $event->isInChannel()) {
if (strpos($msg, $prefix) !== 0) {
return;
} else {
$msg = substr($msg, strlen($prefix));
}
// Check for a prefixed message
$msg = $this->plugins->message->getMessage();
if ($msg === false) {
return;
}
// Separate the command and arguments
$parsed = preg_split('/\s+/', $msg, 2);
$method = $this->methodPrefix . ucfirst(strtolower(array_shift($parsed)));
$command = strtolower(array_shift($parsed));
$args = count($parsed) ? array_shift($parsed) : '';
// Resolve aliases to their corresponding commands
$aliases = $this->getConfig('command.aliases', array());
$result = preg_grep('/^' . $command . '$/i', array_keys($aliases));
if ($result) {
$command = $aliases[array_shift($result)];
}
// Check to ensure the command exists
$method = self::METHOD_PREFIX . ucfirst($command);
if (empty($this->methods[$method])) {
return;
}
@ -122,7 +134,7 @@ class Phergie_Plugin_Command extends Phergie_Plugin_Abstract
// Parse the arguments
$args = preg_split('/\s+/', $args, $this->methods[$method]['total']);
// If the minimum arguments are passed, call the method
// If the minimum arguments are passed, call the method
if ($this->methods[$method]['required'] <= count($args)) {
call_user_func_array(
array($this->getPluginHandler(), $method),

View File

@ -36,9 +36,6 @@ $cookies = $xpath->query('//table[@width="90%"]/tr/td[1]/a');
foreach ($cookies as $cookie) {
$name = $cookie->textContent;
foreach (range(0, mb_strlen($name) - 1) as $index) {
echo mb_strcut($name, $index, 1), PHP_EOL;
}
$name = str_replace(
array('(',')',"\n", 'cookies'),
array('','', ' ', 'cookie'),

View File

@ -1,6 +1,6 @@
<?php
/**
* Phergie
* Phergie
*
* PHP version 5
*
@ -11,7 +11,7 @@
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
* @category Phergie
* @category Phergie
* @package Phergie_Plugin_Daddy
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
@ -23,7 +23,7 @@
* Simply responds to messages addressed to the bot that contain the phrase
* "Who's your daddy?" and related variations.
*
* @category Phergie
* @category Phergie
* @package Phergie_Plugin_Daddy
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
@ -45,15 +45,11 @@ class Phergie_Plugin_Daddy extends Phergie_Plugin_Abstract
$text = $event->getArgument(1);
$target = $event->getNick();
$source = $event->getSource();
$pattern
= '/' . preg_quote($prefix) .
$pattern
= '/' . preg_quote($prefix) .
'\s*?who\'?s y(?:our|a) ([^?]+)\??/iAD';
if (preg_match($pattern, $text, $m)) {
if ($config['daddy.curses'] && mt_rand(0, 5) === 5) {
$msg = $target . ': I am your ' . $m[1] . ', bitch!';
} else {
$msg = 'You\'re my ' . $m[1] . ', ' . $target . '!';
}
$msg = 'You\'re my ' . $m[1] . ', ' . $target . '!';
$this->doPrivmsg($source, $msg);
}
}

View File

@ -32,24 +32,9 @@
* @uses Phergie_Plugin_Command pear.phergie.org
* @uses Phergie_Plugin_Http pear.phergie.org
* @uses Phergie_Plugin_Temperature pear.phergie.org
*
* @pluginDesc Provide access to some Google services
*/
class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
{
/**
* HTTP plugin
*
* @var Phergie_Plugin_Http
*/
protected $http;
/**
* Language for Google Services
*/
protected $lang;
/**
* Checks for dependencies.
*
@ -59,11 +44,8 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
{
$plugins = $this->getPluginHandler();
$plugins->getPlugin('Command');
$this->http = $plugins->getPlugin('Http');
$plugins->getPlugin('Help')->register($this);
$plugins->getPlugin('Http');
$plugins->getPlugin('Weather');
$this->lang = $this->getConfig('google.lang', 'en');
}
/**
@ -73,8 +55,6 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
*
* @return void
* @todo Implement use of URL shortening here
*
* @pluginCmd [query] do a search on google
*/
public function onCommandG($query)
{
@ -83,7 +63,7 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
'v' => '1.0',
'q' => $query
);
$response = $this->http->get($url, $params);
$response = $this->plugins->http->get($url, $params);
$json = $response->getContent()->responseData;
$event = $this->getEvent();
$source = $event->getSource();
@ -110,8 +90,6 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
* @param string $query Search term
*
* @return void
*
* @pluginCmd [query] Do a search on Google and count the results
*/
public function onCommandGc($query)
{
@ -120,7 +98,7 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
'v' => '1.0',
'q' => $query
);
$response = $this->http->get($url, $params);
$response = $this->plugins->http->get($url, $params);
$json = $response->getContent()->responseData->cursor;
$count = $json->estimatedResultCount;
$event = $this->getEvent();
@ -146,8 +124,6 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
* @param string $query Term to translate
*
* @return void
*
* @pluginCmd [from language] [to language] [text to translate] Do a translation on Google
*/
public function onCommandGt($from, $to, $query)
{
@ -157,7 +133,7 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
'q' => $query,
'langpair' => $from . '|' . $to
);
$response = $this->http->get($url, $params);
$response = $this->plugins->http->get($url, $params);
$json = $response->getContent();
$event = $this->getEvent();
$source = $event->getSource();
@ -180,18 +156,16 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
* between 0 and 3 to get the forecast
*
* @return void
*
* @pluginCmd [location] Show the weather for the specified location
*/
public function onCommandGw($location, $offset = null)
{
$url = 'http://www.google.com/ig/api';
$params = array(
'weather' => $location,
'hl' => $this->lang,
'hl' => $this->getConfig('google.lang', 'en'),
'oe' => 'UTF-8'
);
$response = $this->http->get($url, $params);
$response = $this->plugins->http->get($url, $params);
$xml = $response->getContent()->weather;
$event = $this->getEvent();
@ -280,8 +254,6 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
* @param string $location Location to search for
*
* @return void
*
* @pluginCmd [location] Get the location from Google Maps to the location specified
*/
public function onCommandGmap($location)
{
@ -294,13 +266,13 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
$params = array(
'q' => $location,
'output' => 'json',
'gl' => $this->lang,
'gl' => $this->getConfig('google.lang', 'en'),
'sensor' => 'false',
'oe' => 'utf8',
'mrt' => 'all',
'key' => $this->getConfig('google.key')
);
$response = $this->http->get($url, $params);
$response = $this->plugins->http->get($url, $params);
$json = $response->getContent();
if (!empty($json)) {
$qtd = count($json->Placemark);
@ -345,8 +317,6 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
* @param string $to Destination metric
*
* @return void
*
* @pluginCmd [value] [currency from] [currency to] Converts a monetary value from one currency to another
*/
public function onCommandGconvert($value, $from, $to)
{
@ -356,29 +326,21 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
'from' => $from,
'to' => $to
);
$response = $this->http->get($url, $params);
$response = $this->plugins->http->get($url, $params);
$contents = $response->getContent();
$event = $this->getEvent();
$source = $event->getSource();
$nick = $event->getNick();
if ($contents) {
preg_match(
'#<span class=bld>.*? ' . $to . '</span>#im',
$contents,
$matches
);
if (!$matches[0]) {
$this->doPrivmsg($source, $nick . ', I can\'t do that.');
} else {
$str = str_replace('<span class=bld>', '', $matches[0]);
$str = str_replace($to . '</span>', '', $str);
$text
= number_format($value, 2, ',', '.') . ' ' . $from .
' => ' . number_format($str, 2, ',', '.') . ' ' . $to;
$this->doPrivmsg($source, $text);
}
} else {
$this->doPrivmsg($source, $nick . ', we had a problem.');
libxml_use_internal_errors(true);
$doc = new DOMDocument;
$doc->loadHTML($contents);
libxml_clear_errors();
$xpath = new DOMXPath($doc);
$result = $xpath->query('//div[@id="currency_converter_result"]');
$div = $result->item(0);
$text = rtrim($div->textContent);
$this->doPrivmsg($source, $text);
}
}
@ -395,7 +357,7 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
public function onCommandConvert($query)
{
$url = 'http://www.google.com/search?q=' . urlencode($query);
$response = $this->http->get($url);
$response = $this->plugins->http->get($url);
$contents = $response->getContent();
$event = $this->getEvent();
$source = $event->getSource();
@ -434,49 +396,61 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
*
* @return void
* @todo Implement use of URL shortening here
*
* @pluginCmd [query] do a search of a definition on Google Dictionary
*/
public function onCommandDefine($query)
{
$query = urlencode($query);
$url = 'http://www.google.com/dictionary/json?callback=result'.
'&q='.$query.'&sl='.$this->lang.'&tl='.$this->lang.
'&restrict=pr,de';
$json = file_get_contents($url);
$lang = $this->getConfig('google.lang', 'en');
$url = 'http://www.google.com/dictionary/json';
$params = array(
'callback' => 'result',
'q' => $query,
'sl' => $lang,
'tl' => $lang,
'restrict' => 'pr,de'
);
$response = $this->plugins->http->get($url, $params);
$json = $response->getContent();
//Remove some garbage from the json
$json = str_replace(array("result(", ",200,null)"), "", $json);
//Awesome workaround to remove a lot of slashes from json
// Remove some garbage from the JSON and decode it
$json = str_replace(array('result(', ',200,null)'), '', $json);
$json = str_replace('"', '¿?¿', $json);
$json = strip_tags(stripcslashes($json));
$json = str_replace('"', "'", $json);
$json = str_replace('¿?¿', '"', $json);
$json = json_decode($json);
$event = $this->getEvent();
$source = $event->getSource();
$nick = $event->getNick();
if (!empty($json->webDefinitions)){
$results = count($json->webDefinitions[0]->entries);
$more = $results > 1 ? ($results-1).' ' : NULL;
$lang_code = substr($this->lang, 0, 2);
$msg =
$nick . ': ' .
$json->webDefinitions[0]->entries[0]->terms[0]->text .
' - You can find more '.$more.'results at '.
'http://www.google.com/dictionary?aq=f&langpair='.
$lang_code.'%7C'.$lang_code.'&q='.$query.'&hl='.$lang_code;
if (!empty($json->webDefinitions)) {
$results = 0;
foreach ($json->primaries[0]->entries as $entry) {
if ($entry->type == 'meaning') {
$results++;
if (empty($text)) {
foreach ($entry->terms as $term) {
if ($term->type == 'text') {
$text = trim($term->text);
}
}
}
}
}
$more = $results > 1 ? ($results - 1) . ' ' : '';
$lang_code = substr($lang, 0, 2);
$msg = $nick . ': ' . $text
. ' - You can find ' . $more . 'more results at '
. 'http://www.google.com/dictionary'
. '?aq=f'
. '&langpair=' . $lang_code . '%7C' . $lang_code
. '&q=' . $query
. '&hl=' . $lang_code;
$this->doPrivmsg($source, $msg);
}else{
if ($this->lang != 'en'){
$temp = $this->lang;
$this->lang = 'en';
} else {
if ($lang != 'en'){
$lang = 'en';
$this->onCommandDefine($query);
$this->lang = $temp;
}else{
} else {
$msg = $nick . ': No results for this query.';
$this->doPrivmsg($source, $msg);
}

View File

@ -68,6 +68,14 @@ class Phergie_Plugin_Handler implements IteratorAggregate, Countable
*/
protected $events;
/**
* Iterator used for selectively proxying method calls to contained
* plugins
*
* @var Iterator
*/
protected $iterator;
/**
* Constructor to initialize class properties and add the path for core
* plugins.
@ -328,7 +336,7 @@ class Phergie_Plugin_Handler implements IteratorAggregate, Countable
$plugins = array();
foreach ($names as $name) {
$plugins[$name] = $this->getPlugin($name);
$plugins[strtolower($name)] = $this->getPlugin($name);
}
return $plugins;
}
@ -416,26 +424,39 @@ class Phergie_Plugin_Handler implements IteratorAggregate, Countable
*/
public function getIterator()
{
return new ArrayIterator($this->plugins);
if (empty($this->iterator)) {
$this->iterator = new Phergie_Plugin_Iterator(
new ArrayIterator($this->plugins)
);
}
return $this->iterator;
}
/**
* Proxies method calls to all plugins containing the called method. An
* individual plugin may short-circuit this process by explicitly
* returning FALSE.
* Sets the iterator for all currently loaded plugin instances.
*
* @param Iterator $iterator Plugin iterator
*
* @return Phergie_Plugin_Handler Provides a fluent interface
*/
public function setIterator(Iterator $iterator)
{
$this->iterator = $iterator;
return $this;
}
/**
* Proxies method calls to all plugins containing the called method.
*
* @param string $name Name of the method called
* @param array $args Arguments passed in the method call
*
* @return bool FALSE if a plugin short-circuits processing by returning
* FALSE, TRUE otherwise
* @return void
*/
public function __call($name, array $args)
{
foreach ($this->plugins as $plugin) {
if (call_user_func_array(array($plugin, $name), $args) === false) {
return false;
}
foreach ($this->getIterator() as $plugin) {
call_user_func_array(array($plugin, $name), $args);
}
return true;
}

View File

@ -28,26 +28,16 @@
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Help
* @uses Phergie_Plugin_Command pear.phergie.org
*
* @pluginDesc Provides access to plugin help information
*/
class Phergie_Plugin_Help extends Phergie_Plugin_Abstract
{
/**
* Holds the registry of help data indexed by plugin name
* Registry of help data indexed by plugin name
*
* @var array
*/
protected $registry;
/**
* Whether the registry has been alpha sorted
*
* @var bool
*/
protected $registry_sorted = false;
/**
* Checks for dependencies.
*
@ -56,143 +46,175 @@ class Phergie_Plugin_Help extends Phergie_Plugin_Abstract
public function onLoad()
{
$this->getPluginHandler()->getPlugin('Command');
$this->register($this);
}
/**
* Creates a registry of plugin metadata on connect.
*
* @return void
*/
public function onConnect()
{
$this->populateRegistry();
}
/**
* Creates a registry of plugin metadata.
*
* @return void
*/
public function populateRegistry()
{
$this->registry = array();
foreach ($this->plugins as $plugin) {
$class = new ReflectionClass($plugin);
$pluginName = strtolower($plugin->getName());
// Parse the plugin description
$docblock = $class->getDocComment();
$annotations = $this->getAnnotations($docblock);
if (isset($annotations['pluginDesc'])) {
$pluginDesc = implode(' ', $annotations['pluginDesc']);
} else {
$pluginDesc = $this->parseShortDescription($docblock);
}
$this->registry[$pluginName] = array(
'desc' => $pluginDesc,
'cmds' => array()
);
// Parse command method descriptions
$methodPrefix = Phergie_Plugin_Command::METHOD_PREFIX;
$methodPrefixLength = strlen($methodPrefix);
foreach ($class->getMethods() as $method) {
if (strpos($method->getName(), $methodPrefix) !== 0) {
continue;
}
$cmd = strtolower(substr($method->getName(), $methodPrefixLength));
$docblock = $method->getDocComment();
$annotations = $this->getAnnotations($docblock);
if (isset($annotations['pluginCmd'])) {
$cmdDesc = implode(' ', $annotations['pluginCmd']);
} else {
$cmdDesc = $this->parseShortDescription($docblock);
}
$cmdParams = array();
if (!empty($annotations['param'])) {
foreach ($annotations['param'] as $param) {
$match = null;
if (preg_match('/\h+\$([^\h]+)\h+/', $param, $match)) {
$cmdParams[] = $match[1];
}
}
}
$this->registry[$pluginName]['cmds'][$cmd] = array(
'desc' => $cmdDesc,
'params' => $cmdParams
);
}
if (empty($this->registry[$pluginName]['cmds'])) {
unset($this->registry[$pluginName]);
}
}
}
/**
* Displays a list of plugins with help information available or
* commands available for a specific plugin.
*
* @param string $plugin Short name of the plugin for which commands
* should be returned, else a list of plugins with help
* information available is returned
* @param string $query Optional short name of a plugin for which commands
* should be returned or a command; if unspecified, a list of
* plugins with help information available is returned
*
* @return void
*
* @pluginCmd Show all active plugins with help available
* @pluginCmd [plugin] Shows commands line for a specific plugin
*/
public function onCommandHelp($plugin = null)
public function onCommandHelp($query = null)
{
if ($query == 'refresh') {
$this->populateRegistry();
}
$nick = $this->getEvent()->getNick();
$delay = $this->getConfig('help.delay', 2);
if (!$plugin) {
// protect from sorting the registry each time help is called
if (!$this->registry_sorted) {
asort($this->registry);
$this->registry_sorted = true;
}
// Handle requests for a plugin list
if (!$query) {
$msg = 'These plugins have help information available: '
. implode(', ', array_keys($this->registry));
$this->doPrivmsg($nick, $msg);
return;
}
$msg = 'These plugins below have help information available.';
$this->doPrivMsg($nick, $msg);
// Handle requests for plugin information
$query = strtolower($query);
if (isset($this->registry[$query])
&& empty($this->registry[$query]['cmds'][$query])) {
$msg = $query . ' - ' . $this->registry[$query]['desc'];
$this->doPrivmsg($nick, $msg);
foreach ($this->registry as $plugin => $data) {
$this->doPrivMsg($nick, "{$plugin} - {$data['desc']}");
}
} else {
if (isset($this->getPluginHandler()->{$plugin})
&& isset($this->registry[strtolower($plugin)]['cmd'])
) {
$msg = 'Available commands - '
. implode(', ', array_keys($this->registry[$query]['cmds']));
$this->doPrivmsg($nick, $msg);
if ($this->getConfig('command.prefix')) {
$msg
= 'The ' .
$plugin .
' plugin exposes the commands shown below.';
$this->doPrivMsg($nick, $msg);
if ($this->getConfig('command.prefix')) {
$msg
= 'Note that these commands must be prefixed with "' .
$this->getConfig('command.prefix') .
'" (without quotes) when issued in a public channel.';
$this->doPrivMsg($nick, $msg);
}
foreach ($this->registry[strtolower($plugin)]['cmd']
as $cmd => $descs
) {
foreach ($descs as $desc) {
$this->doPrivMsg($nick, "{$cmd} {$desc}");
}
}
} else {
$this->doPrivMsg($nick, 'That plugin is not loaded.');
= 'Note that these commands must be prefixed with "'
. $this->getConfig('command.prefix')
. '" (without quotes) when issued in a public channel.';
$this->doPrivmsg($nick, $msg);
}
return;
}
// Handle requests for command information
foreach ($this->registry as $plugin => $data) {
if (empty($data['cmds'])) {
continue;
}
$result = preg_grep('/^' . $query . '$/i', array_keys($data['cmds']));
if (!$result) {
continue;
}
$cmd = $data['cmds'][array_shift($result)];
$msg = $query;
if (!empty($cmd['params'])) {
$msg .= ' [' . implode('] [', $cmd['params']) . ']';
}
$msg .= ' - ' . $cmd['desc'];
$this->doPrivmsg($nick, $msg);
}
}
/**
* Sets the description for the plugin instance
* Parses and returns the short description from a docblock.
*
* @param Phergie_Plugin_Abstract $plugin plugin instance
* @param string $description plugin description
* @param string $docblock Docblock comment code
*
* @return void
* @return string Short description (i.e. content from the start of the
* docblock up to the first double-newline)
*/
public function setPluginDescription(
Phergie_Plugin_Abstract $plugin,
$description
) {
$this->registry[strtolower($plugin->getName())]
['desc'] = $description;
}
/**
* Sets the description for the command on the plugin instance
*
* @param Phergie_Plugin_Abstract $plugin plugin instance
* @param string $command from onCommand method
* @param string $description command description
*
* @return void
*/
public function setCommandDescription(
Phergie_Plugin_Abstract $plugin,
$command,
array $description
) {
$this->registry[strtolower($plugin->getName())]
['cmd'][$command] = $description;
}
/**
* registers the plugin with the help plugin. this will parse the docblocks
* for specific annotations that this plugin will respond with when
* queried.
*
* @param Phergie_Plugin_Abstract $plugin plugin instance
*
* @return void
*/
public function register(Phergie_Plugin_Abstract $plugin)
protected function parseShortDescription($docblock)
{
$class = new ReflectionClass($plugin);
$annotations = self::parseAnnotations($class->getDocComment());
if (isset($annotations['pluginDesc'])) {
$this->setPluginDescription(
$plugin,
join(' ', $annotations['pluginDesc'])
);
}
foreach ($class->getMethods() as $method) {
if (strpos($method->getName(), 'onCommand') !== false) {
$annotations = self::parseAnnotations($method->getDocComment());
if (isset($annotations['pluginCmd'])) {
$cmd = strtolower(substr($method->getName(), 9));
$this->setCommandDescription(
$plugin,
$cmd,
$annotations['pluginCmd']
);
}
}
}
$desc = preg_replace(
array('#^\h*\*\h*#m', '#^/\*\*\h*\v+\h*#', '#(?:\r?\n){2,}.*#s', '#\s*\v+\s*#'),
array('', '', '', ' '),
$docblock
);
return $desc;
}
/**
* Taken from PHPUnit/Util/Test.php:243 and modified to fix an issue
* with tag content spanning multiple lines.
* Taken from PHPUnit/Util/Test.php and modified to fix an issue with
* tag content spanning multiple lines.
*
* PHPUnit
*
@ -232,7 +254,7 @@ class Phergie_Plugin_Help extends Phergie_Plugin_Abstract
*
* @return array
*/
protected static function parseAnnotations($docblock)
protected function getAnnotations($docblock)
{
$annotations = array();

View File

@ -184,7 +184,10 @@ class Phergie_Plugin_Http extends Phergie_Plugin_Abstract
$type = $this->response->getHeaders('content-type');
foreach ($this->handlers as $expr => $handler) {
if (preg_match('#^' . $expr . '$#i', $type)) {
$body = call_user_func($handler, $body);
$handled = call_user_func($handler, $body);
if (!empty($handled)) {
$body = $handled;
}
}
}
@ -256,7 +259,7 @@ class Phergie_Plugin_Http extends Phergie_Plugin_Abstract
public function post($url, array $query = array(),
array $post = array(), array $context = array()
) {
if (!empty($params)) {
if (!empty($query)) {
$url .= '?' . http_build_query($query);
}
@ -278,4 +281,4 @@ class Phergie_Plugin_Http extends Phergie_Plugin_Abstract
return $this->request($url, $context);
}
}
}

View File

@ -0,0 +1,180 @@
<?php
/**
* Phergie
*
* PHP version 5
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
* @category Phergie
* @package Phergie_Plugin_Ideone
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Ideone
*/
/**
* Interfaces with ideone.com to execute code and return the result.
*
* @category Phergie
* @package Phergie_Plugin_Ideone
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Ideone
* @uses Phergie_Plugin_Command pear.phergie.org
*/
class Phergie_Plugin_Ideone extends Phergie_Plugin_Abstract
{
/**
* Checks for dependencies.
*
* @return void
*/
public function onLoad()
{
$this->plugins->getPlugin('Command');
}
/**
* Checks a service response for an error, sends a notice to the event
* source if an error has occurred, and returns whether an error was found.
*
* @param array $result Associative array representing the service response
*
* @return boolean TRUE if an error is found, FALSE otherwise
*/
protected function isError($result)
{
if ($result['error'] != 'OK') {
$this->doNotice($this->event->getNick(), 'ideone error: ' . $result['error']);
return true;
}
return false;
}
/**
* Executes a source code sequence in a specified language and returns
* the result.
*
* @param string $language Programming language the source code is in
* @param string $code Source code to execute
*
* @return void
*/
public function onCommandIdeone($language, $code)
{
$source = $this->event->getSource();
$nick = $this->event->getNick();
// Get authentication credentials
$user = $this->getConfig('ideone.user', 'test');
$pass = $this->getConfig('ideone.pass', 'test');
// Normalize the command parameters
$language = strtolower($language);
// Massage PHP code to allow for convenient shorthand
if ($language == 'php') {
if (!preg_match('/^<\?(?:php)?/', $code)) {
$code = '<?php ' . $code;
}
switch (substr($code, -1)) {
case '}':
case ';':
break;
default:
$code .= ';';
break;
}
}
// Identify the language to use
$client = new SoapClient('http://ideone.com/api/1/service.wsdl');
$response = $client->getLanguages($user, $pass);
if ($this->isError($response)) {
return;
}
$languageLength = strlen($language);
foreach ($response['languages'] as $languageId => $languageName) {
if (strncasecmp($language, $languageName, $languageLength) == 0) {
break;
}
}
// Send the paste data
$response = $client->createSubmission(
$user,
$pass,
$code,
$languageId,
null, // string input - data from stdin
true, // boolean run - TRUE to execute the code
false // boolean private - FALSE to make the paste public
);
if ($this->isError($response)) {
return;
}
$link = $response['link'];
// Wait until the paste data is processed or the service fails
$attempts = $this->getConfig('ideone.attempts', 10);
foreach (range(1, $attempts) as $attempt) {
$response = $client->getSubmissionStatus($user, $pass, $link);
if ($this->isError($response)) {
return;
}
if ($response['status'] == 0) {
$result = $response['result'];
break;
} else {
$result = null;
sleep(1);
}
}
if ($result == null) {
$this->doNotice($nick, 'ideone error: Timed out');
return;
}
if ($result != 15) {
$this->doNotice($nick, 'ideone error: Status code ' . $result);
return;
}
// Get details for the created paste
$response = $client->getSubmissionDetails(
$user,
$pass,
$link,
false, // boolean withSource - FALSE to not return the source code
false, // boolean withInput - FALSE to not return stdin data
true, // boolean withOutput - TRUE to include output
true, // boolean withStderr - TRUE to return stderr data
false // boolean withCmpinfo - TRUE to return compilation info
);
if ($this->isError($response)) {
return;
}
// Replace the output if it exceeds a specified maximum length
$outputLimit = $this->getConfig('ideone.output_limit', 100);
var_dump($response);
if ($outputLimit && strlen($response['output']) > $outputLimit) {
$response['output'] = 'Output is too long to post';
}
// Format the message
$msg = $this->getConfig('ideone.format', '%nick%: [ %link% ] %output%');
$response['nick'] = $nick;
$response['link'] = 'http://ideone.com/' . $link;
foreach ($response as $key => $value) {
$msg = str_replace('%' . $key . '%', $value, $msg);
}
$this->doPrivmsg($source, $msg);
}
}

View File

@ -0,0 +1,126 @@
<?php
/**
* Phergie
*
* PHP version 5
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
* @category Phergie
* @package Phergie
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie
*/
/**
* Implements a filtering iterator for limiting executing of methods across
* a group of plugins.
*
* @category Phergie
* @package Phergie
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie
*/
class Phergie_Plugin_Iterator extends FilterIterator
{
/**
* List of short names of plugins to exclude when iterating
*
* @var array
*/
protected $plugins = array();
/**
* List of method names where plugins with these methods will be
* excluded when iterating
*
* @var array
*/
protected $methods = array();
/**
* Adds to a list of plugins to exclude when iterating.
*
* @param mixed $plugins String containing the short name of a single
* plugin to exclude or an array of short names of multiple
* plugins to exclude
*
* @return Phergie_Plugin_Iterator Provides a fluent interface
*/
public function addPluginFilter($plugins)
{
if (is_array($plugins)) {
$this->plugins = array_unique(
array_merge($this->plugins, $plugins)
);
} else {
$this->plugins[] = $plugins;
}
return $this;
}
/**
* Adds to a list of method names where plugins defining these methods
* will be excluded when iterating.
*
* @param mixed $methods String containing the name of a single method
* or an array containing the name of multiple methods
*
* @return Phergie_Plugin_Iterator Provides a fluent interface
*/
public function addMethodFilter($methods)
{
if (is_array($methods)) {
$this->methods = array_merge($this->methods, $methods);
} else {
$this->methods[]= $methods;
}
return $this;
}
/**
* Clears any existing plugin and methods filters.
*
* @return Phergie_Plugin_Iterator Provides a fluent interface
*/
public function clearFilters()
{
$this->plugins = array();
$this->methods = array();
}
/**
* Implements FilterIterator::accept().
*
* @return boolean TRUE to include the current item in those by returned
* during iteration, FALSE otherwise
*/
public function accept()
{
if (!$this->plugins && !$this->methods) {
return true;
}
$current = $this->current();
if (in_array($current->getName(), $this->plugins)) {
return false;
}
foreach ($this->methods as $method) {
if (method_exists($current, $method)) {
return false;
}
}
return true;
}
}

View File

@ -21,427 +21,407 @@
/**
* Handles requests for incrementation or decrementation of a maintained list
* of counters for specified terms and antithrottling to prevent extreme
* inflation or depression of counters by any single individual.
* of counters for specified terms.
*
* @category Phergie
* @package Phergie_Plugin_Karma
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Karma
* @uses extension PDO
* @uses extension pdo_sqlite
* @uses Phergie_Plugin_Command pear.phergie.org
* @uses Phergie_Plugin_Message pear.phergie.org
*/
class Phergie_Plugin_Karma extends Phergie_Plugin_Abstract
{
/**
* Stores the SQLite object
* SQLite object
*
* @var resource
*/
protected $db = null;
/**
* Retains the last garbage collection date
*
* @var array
*/
protected $lastGc = null;
/**
* Logs the karma usages and limits users to one karma change per word
* and per day
*
* @return void
*/
protected $log = array();
/**
* Some fixed karma values, keys must be lowercase
*
* @var array
*/
protected $fixedKarma;
/**
* A list of blacklisted values
*
* @var array
*/
protected $karmaBlacklist;
/**
* Answers for correct assertions
*/
protected $positiveAnswers;
/**
* Answers for incorrect assertions
*/
protected $negativeAnswers;
/**
* Prepared PDO statements
* Prepared statement to add a new karma record
*
* @var PDOStatement
*/
protected $insertKarma;
protected $updateKarma;
protected $fetchKarma;
protected $insertComment;
/**
* Connects to the database containing karma ratings and initializes
* class properties.
* Prepared statement to update an existing karma record
*
* @var PDOStatement
*/
protected $updateKarma;
/**
* Retrieves an existing karma record
*
* @var PDOStatement
*/
protected $fetchKarma;
/**
* Retrieves an existing fixed karma record
*
* @var PDOStatement
*/
protected $fetchFixedKarma;
/**
* Retrieves a positive answer for a karma comparison
*
* @var PDOStatement
*/
protected $fetchPositiveAnswer;
/**
* Retrieves a negative answer for a karma comparison
*
* @var PDOStatement
*/
protected $fetchNegativeAnswer;
/**
* Check for dependencies and initializes a database connection and
* prepared statements.
*
* @return void
*/
public function onLoad()
{
$this->db = null;
$this->lastGc = null;
$this->log = array();
$plugins = $this->getPluginHandler();
$plugins->getPlugin('Command');
$plugins->getPlugin('Message');
if(!defined('M_EULER')) {
define('M_EULER', '0.57721566490153286061');
}
$this->fixedKarma = array(
'phergie' => '%s has karma of awesome',
'pi' => '%s has karma of ' . M_PI,
'Î ' => '%s has karma of ' . M_PI,
'Ï€' => '%s has karma of ' . M_PI,
'chucknorris' => '%s has karma of Warning: Integer out of range',
'chuck norris' => '%s has karma of Warning: Integer out of range',
'c' => '%s has karma of 299 792 458 m/s',
'e' => '%s has karma of ' . M_E,
'euler' => '%s has karma of ' . M_EULER,
'mole' => '%s has karma of 6.02214e23 molecules',
'avogadro' => '%s has karma of 6.02214e23 molecules',
'spoon' => '%s has no karma. There is no spoon',
'mc^2' => '%s has karma of E',
'mc2' => '%s has karma of E',
'mc²' => '%s has karma of E',
'i' => '%s haz big karma',
'karma' => 'The karma law says that all living creatures are responsible for their karma - their actions and the effects of their actions. You should watch yours.'
);
$this->karmaBlacklist = array(
'*',
'all',
'everything'
);
$this->positiveAnswers = array(
'No kidding, %owner% totally kicks %owned%\'s ass !',
'True that.',
'I concur.',
'Yay, %owner% ftw !',
'%owner% is made of WIN!',
'Nothing can beat %owner%!',
);
$this->negativeAnswers = array(
'No sir, not at all.',
'You\'re wrong dude, %owner% wins.',
'I\'d say %owner% is better than %owned%.',
'You must be joking, %owner% ftw!',
'%owned% is made of LOSE!',
'%owned% = Epic Fail',
);
// Load or initialize the database
$class = new ReflectionClass(get_class($this));
$dir = dirname($class->getFileName() . '/' . $this->name);
$this->db = new PDO('sqlite:' . $dir . 'karma.db');
// Check to see if the table exists
$table = $this->db->query('
SELECT COUNT(*)
FROM sqlite_master
WHERE name = ' . $this->db->quote('karmas')
)->fetchColumn();
// Create database tables if necessary
if (!$table) {
$this->db->query('
CREATE TABLE karmas ( word VARCHAR ( 255 ), karma MEDIUMINT );
CREATE UNIQUE INDEX word ON karmas ( word );
CREATE INDEX karmaIndex ON karmas ( karma );
CREATE TABLE comments ( wordid INT , comment VARCHAR ( 255 ) );
CREATE INDEX wordidIndex ON comments ( wordid );
CREATE UNIQUE INDEX commentUnique ON comments ( comment );
');
}
$this->insertKarma = $this->db->prepare('
INSERT INTO karmas (
word,
karma
)
VALUES (
:word,
:karma
)
');
$this->insertComment = $this->db->prepare('
INSERT INTO comments (
wordid,
comment
)
VALUES (
:wordid,
:comment
)
');
$file = dirname(__FILE__) . '/Karma/karma.db';
$this->db = new PDO('sqlite:' . $file);
$this->fetchKarma = $this->db->prepare('
SELECT karma, ROWID id FROM karmas WHERE LOWER(word) = LOWER(:word) LIMIT 1
SELECT karma
FROM karmas
WHERE term = :term
LIMIT 1
');
$this->insertKarma = $this->db->prepare('
INSERT INTO karmas (term, karma)
VALUES (:term, :karma)
');
$this->updateKarma = $this->db->prepare('
UPDATE karmas SET karma = :karma WHERE LOWER(word) = LOWER(:word)
UPDATE karmas
SET karma = :karma
WHERE term = :term
');
$this->fetchFixedKarma = $this->db->prepare('
SELECT karma
FROM fixed_karmas
WHERE term = :term
LIMIT 1
');
$this->fetchPositiveAnswer = $this->db->prepare('
SELECT answer
FROM positive_answers
ORDER BY RANDOM()
LIMIT 1
');
$this->fetchNegativeAnswer = $this->db->prepare('
SELECT answer
FROM negative_answers
ORDER BY RANDOM()
LIMIT 1
');
}
/**
* Checks for dependencies.
* Get the canonical form of a given term.
*
* @return void
* In the canonical form all sequences of whitespace
* are replaced by a single space and all characters
* are lowercased.
*
* @param string $term Term for which a canonical form is required
*
* @return string Canonical term
*/
public static function onLoad()
protected function getCanonicalTerm($term)
{
if (!extension_loaded('PDO') || !extension_loaded('pdo_sqlite')) {
$this->fail('PDO and pdo_sqlite extensions must be installed');
}
$canonicalTerm = strtolower(preg_replace('|\s+|', ' ', trim($term, '()')));
switch ($canonicalTerm) {
case 'me':
$canonicalTerm = strtolower($this->event->getNick());
break;
case 'all':
case '*':
case 'everything':
$canonicalTerm = 'everything';
break;
}
return $canonicalTerm;
}
/**
* Handles requests for incrementation, decrementation, or lookup of karma
* ratings sent via messages from users.
* Intercepts a message and processes any contained recognized commands.
*
* @return void
*/
public function onPrivmsg()
{
$source = $this->event->getSource();
$message = $this->event->getArgument(1);
$target = $this->event->getNick();
$message = $this->getEvent()->getText();
// Command prefix check
$prefix = preg_quote(trim($this->getConfig('command.prefix')));
$bot = preg_quote($this->getConfig('connections.nick'));
$exp = '(?:(?:' . $bot . '\s*[:,>]?\s+(?:' . $prefix . ')?)|(?:' . $prefix . '))';
$termPattern = '\S+?|\([^<>]+?\)+';
$actionPattern = '(?P<action>\+\+|--)';
// Karma status request
if (preg_match('#^' . $exp . 'karma\s+(.+)$#i', $message, $m)) {
// Return user's value if "me" is requested
if (strtolower($m[1]) === 'me') {
$m[1] = $target;
}
// Clean the term
$term = $this->doCleanWord($m[1]);
$modifyPattern = <<<REGEX
{^
(?J) # allow overwriting capture names
\s* # ignore leading whitespace
// Check the blacklist
if (is_array($this->karmaBlacklist) && in_array($term, $this->karmaBlacklist)) {
$this->doNotice($target, $term . ' is blacklisted');
return;
}
(?: # start with ++ or -- before the term
$actionPattern
(?P<term>$termPattern)
| # follow the term with ++ or --
(?P<term>$termPattern)
$actionPattern # allow no whitespace between the term and the action
)
$}ix
REGEX;
// Return fixed value if set
if (isset($this->fixedKarma[$term])) {
$this->doPrivmsg($source, $target . ': ' . sprintf($this->fixedKarma[$term], $m[1]) . '.');
return;
}
$versusPattern = <<<REGEX
{^
(?P<term0>$termPattern)
\s+(?P<method><|>)\s+
(?P<term1>$termPattern)$#
$}ix
REGEX;
// Return current karma or neutral if not set yet
$this->fetchKarma->execute(array(':word'=>$term));
$res = $this->fetchKarma->fetch(PDO::FETCH_ASSOC);
$match = null;
// Sanity check if someone if someone prefixed their conversation with karma
if (!$res && substr_count($term, ' ') > 1 && !(substr($m[1], 0, 1) === '(' && substr($m[1], -1) === ')')) {
return;
}
// Clean the raw term if it was contained within brackets
if (substr($m[1], 0, 1) === '(' && substr($m[1], -1) === ')') {
$m[1] = substr($m[1], 1, -1);
}
if ($res && $res['karma'] != 0) {
$this->doPrivmsg($source, $target . ': ' . $m[1] . ' has karma of ' . $res['karma'] . '.');
} else {
$this->doPrivmsg($source, $target . ': ' . $m[1] . ' has neutral karma.');
}
// Incrementation/decrementation request
} elseif (preg_match('{^' . $exp . '?(?:(\+{2,2}|-{2,2})(\S+?|\(.+?\)+)|(\S+?|\(.+?\)+)(\+{2,2}|-{2,2}))(?:\s+(.*))?$}ix', $message, $m)) {
if (!empty($m[4])) {
$m[1] = $m[4]; // Increment/Decrement
$m[2] = $m[3]; // Word
}
$m[3] = (isset($m[5]) ? $m[5] : null); // Comment
unset($m[4], $m[5]);
list(, $sign, $word, $comment) = array_pad($m, 4, null);
// Clean the word
$word = strtolower($this->doCleanWord($word));
if (empty($word)) {
return;
}
// Do nothing if the karma is fixed or blacklisted
if (isset($this->fixedKarma[$word]) ||
is_array($this->karmaBlacklist) && in_array($word, $this->karmaBlacklist)) {
return;
}
// Force a decrementation if someone tries to update his own karma
if ($word == strtolower($target) && $sign != '--' && !$this->fromAdmin(true)) {
$this->doNotice($target, 'Bad ' . $target . '! You can not modify your own Karma. Shame on you!');
$sign = '--';
}
// Antithrottling check
$host = $this->event->getHost();
$limit = $this->getConfig('karma.limit');
// This is waiting on the Acl plugin from Elazar, being bypassed for now
//if ($limit > 0 && !$this->fromAdmin()) {
if ($limit > 0) {
if (isset($this->log[$host][$word]) && $this->log[$host][$word] >= $limit) {
// Three strikes, you're out, so lets decrement their karma for spammage
if ($this->log[$host][$word] == ($limit+3)) {
$this->doNotice($target, 'Bad ' . $target . '! Didn\'t I tell you that you reached your limit already?');
$this->log[$host][$word] = $limit;
$word = $target;
$sign = '--';
// Toss a notice to the user if they reached their limit
} else {
$this->doNotice($target, 'You have currently reached your limit in modifying ' . $word . ' for this day, please wait a bit.');
$this->log[$host][$word]++;
return;
}
} else {
if (isset($this->log[$host][$word])) {
$this->log[$host][$word]++;
} else {
$this->log[$host][$word] = 1;
}
}
}
// Get the current value then update or create entry
$this->fetchKarma->execute(array(':word'=>$word));
$res = $this->fetchKarma->fetch(PDO::FETCH_ASSOC);
if ($res) {
$karma = ($res['karma'] + ($sign == '++' ? 1 : -1));
$args = array(
':word' => $word,
':karma' => $karma
);
$this->updateKarma->execute($args);
} else {
$karma = ($sign == '++' ? '1' : '-1');
$args = array(
':word' => $word,
':karma' => $karma
);
$this->insertKarma->execute($args);
$this->fetchKarma->execute(array(':word'=>$word));
$res = $this->fetchKarma->fetch(PDO::FETCH_ASSOC);
}
$id = $res['id'];
// Add comment
$comment = preg_replace('{(?:^//(.*)|^#(.*)|^/\*(.*?)\*/$)}', '$1$2$3', $comment);
if (!empty($comment)) {
$this->insertComment->execute(array(':wordid' => $id, ':comment' => $comment));
}
// Perform garbage collection on the antithrottling log if needed
if (date('d') !== $this->lastGc) {
$this->doGc();
}
// Assertion request
} elseif (preg_match('#^' . $exp . '?([^><]+)(<|>)([^><]+)$#', $message, $m)) {
// Trim words
$word1 = strtolower($this->doCleanWord($m[1]));
$word2 = strtolower($this->doCleanWord($m[3]));
$operator = $m[2];
// Do nothing if the karma is fixed
if (isset($this->fixedKarma[$word1]) || isset($this->fixedKarma[$word2]) ||
empty($word1) || empty($word2)) {
return;
}
// Fetch first word
if ($word1 === '*' || $word1 === 'all' || $word1 === 'everything') {
$res = array('karma' => 0);
$word1 = 'everything';
} else {
$this->fetchKarma->execute(array(':word'=>$word1));
$res = $this->fetchKarma->fetch(PDO::FETCH_ASSOC);
}
// If it exists, fetch second word
if ($res) {
if ($word2 === '*' || $word2 === 'all' || $word2 === 'everything') {
$res2 = array('karma' => 0);
$word2 = 'everything';
} else {
$this->fetchKarma->execute(array(':word'=>$word2));
$res2 = $this->fetchKarma->fetch(PDO::FETCH_ASSOC);
}
// If it exists, compare and return value
if ($res2 && $res['karma'] != $res2['karma']) {
$assertion = ($operator === '<' && $res['karma'] < $res2['karma']) || ($operator === '>' && $res['karma'] > $res2['karma']);
// Switch arguments if they are in the wrong order
if ($operator === '<') {
$tmp = $word2;
$word2 = $word1;
$word1 = $tmp;
}
$this->doPrivmsg($source, $assertion ? $this->fetchPositiveAnswer($word1, $word2) : $this->fetchNegativeAnswer($word1, $word2));
// If someone asserts that something is greater or lesser than everything, we increment/decrement that something at the same time
if ($word2 === 'everything') {
$this->event = clone$this->event;
$this->event->setArguments(array($this->event->getArgument(0), '++'.$word1));
$this->onPrivmsg();
} elseif ($word1 === 'everything') {
$this->event = clone$this->event;
$this->event->setArguments(array($this->event->getArgument(0), '--'.$word2));
$this->onPrivmsg();
}
}
}
if (preg_match($modifyPattern, $message, $match)) {
$action = $match['action'];
$term = $this->getCanonicalTerm($match['term']);
$this->modifyKarma($term, $action);
} elseif (preg_match($versusPattern, $message, $match)) {
$term0 = trim($match['term0']);
$term1 = trim($match['term1']);
$method = $match['method'];
$this->compareKarma($term0, $term1, $method);
}
}
protected function fetchPositiveAnswer($owner, $owned)
{
return str_replace(array('%owner%','%owned%'), array($owner, $owned), $this->positiveAnswers[array_rand($this->positiveAnswers,1)]);
}
protected function fetchNegativeAnswer($owned, $owner)
{
return str_replace(array('%owner%','%owned%'), array($owner, $owned), $this->negativeAnswers[array_rand($this->negativeAnswers,1)]);
}
protected function doCleanWord($word)
{
$word = trim($word);
if (substr($word, 0, 1) === '(' && substr($word, -1) === ')') {
$word = trim(substr($word, 1, -1));
}
$word = preg_replace('#\s+#', ' ', strtolower(trim($word)));
return $word;
}
/**
* Performs garbage collection on the antithrottling log.
* Get the karma rating for a given term.
*
* @param string $term Term for which the karma rating needs to be
* retrieved
*
* @return void
*/
public function doGc()
public function onCommandKarma($term)
{
unset($this->log);
$this->log = array();
$this->lastGc = date('d');
$source = $this->getEvent()->getSource();
$nick = $this->getEvent()->getNick();
if (empty($term)) {
return;
}
$canonicalTerm = $this->getCanonicalTerm($term);
$fixedKarma = $this->fetchFixedKarma($canonicalTerm);
if ($fixedKarma) {
$message = $nick . ': ' . $term . $fixedKarma . '.';
$this->doPrivmsg($source, $message);
return;
}
$karma = $this->fetchKarma($canonicalTerm);
$message = $nick . ': ';
if ($term == 'me') {
$message .= 'You have';
} else {
$message .= $term . ' has';
}
$message .= ' ';
if ($karma) {
$message .= 'karma of ' . $karma;
} else {
$message .= 'neutral karma';
}
$message .= '.';
$this->doPrivmsg($source, $message);
}
/**
* Resets the karma for a term to 0.
*
* @param string $term Term for which to reset the karma rating
*
* @return void
*/
public function onCommandReincarnate($term)
{
$data = array(
':term' => $term,
':karma' => 0
);
$this->updateKarma->execute($data);
}
/**
* Compares the karma between two terms. Optionally increases/decreases
* the karma of either term.
*
* @param string $term0 First term
* @param string $term1 Second term
* @param string $method Comparison method (< or >)
*
* @return void
*/
protected function compareKarma($term0, $term1, $method)
{
$event = $this->getEvent();
$nick = $event->getNick();
$source = $event->getSource();
$canonicalTerm0 = $this->getCanonicalTerm($term0);
$canonicalTerm1 = $this->getCanonicalTerm($term1);
$fixedKarma0 = $this->fetchFixedKarma($canonicalTerm0);
$fixedKarma1 = $this->fetchFixedKarma($canonicalTerm1);
if ($fixedKarma0
|| $fixedKarma1
|| empty($canonicalTerm0)
|| empty($canonicalTerm1)
) {
return;
}
if ($canonicalTerm0 == 'everything') {
$change = $method == '<' ? '++' : '--';
$this->modifyKarma($canonicalTerm1, $change);
$karma0 = 0;
$karma1 = $this->fetchKarma($canonicalTerm1);
} elseif ($canonicalTerm1 == 'everything') {
$change = $method == '<' ? '--' : '++';
$this->modifyKarma($canonicalTerm0, $change);
$karma0 = $this->fetchKarma($canonicalTerm1);
$karma1 = 0;
} else {
$karma0 = $this->fetchKarma($canonicalTerm0);
$karma1 = $this->fetchKarma($canonicalTerm1);
}
if (($method == '<'
&& $karma0 < $karma1)
|| ($method == '>'
&& $karma0 > $karma1)) {
$replies = $this->fetchPositiveAnswer;
} else {
$replies = $this->fetchNegativeAnswer;
}
$replies->execute();
$reply = $replies->fetchColumn();
if (max($karma0, $karma1) == $karma1) {
list($canonicalTerm0, $canonicalTerm1) =
array($canonicalTerm1, $canonicalTerm0);
}
$message = str_replace(
array('%owner%','%owned%'),
array($canonicalTerm0, $canonicalTerm1),
$reply
);
$this->doPrivmsg($source, $message);
}
/**
* Modifes a term's karma.
*
* @param string $term Term to modify
* @param string $action Karma action (either ++ or --)
*
* @return void
*/
protected function modifyKarma($term, $action)
{
if (empty($term)) {
return;
}
$karma = $this->fetchKarma($term);
if ($karma !== false) {
$statement = $this->updateKarma;
} else {
$statement = $this->insertKarma;
}
$karma += ($action == '++') ? 1 : -1;
$args = array(
':term' => $term,
':karma' => $karma
);
$statement->execute($args);
}
/**
* Returns the karma rating for a specified term for which the karma
* rating can be modified.
*
* @param string $term Term for which to fetch the corresponding karma
* rating
*
* @return integer|boolean Integer value denoting the term's karma or
* FALSE if there is the specified term has no associated karma
* rating
*/
protected function fetchKarma($term)
{
$this->fetchKarma->execute(array(':term' => $term));
$result = $this->fetchKarma->fetch(PDO::FETCH_ASSOC);
if ($result === false) {
return false;
}
return (int) $result['karma'];
}
/**
* Returns a phrase describing the karma rating for a specified term for
* which the karma rating is fixed.
*
* @param string $term Term for which to fetch the corresponding karma
* rating
*
* @return string Phrase describing the karma rating, which may be append
* to the term to form a complete response
*/
protected function fetchFixedKarma($term)
{
$this->fetchFixedKarma->execute(array(':term' => $term));
$result = $this->fetchFixedKarma->fetch(PDO::FETCH_ASSOC);
if ($result === false) {
return false;
}
return $result['karma'];
}
}

View File

@ -0,0 +1,112 @@
<?php
/**
* Phergie
*
* PHP version 5
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
* @category Phergie
* @package Phergie_Plugin_Message
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Message
*/
/**
* Generalized plugin providing utility methods for
* prefix and bot named based message extraction.
*
* @category Phergie
* @package Phergie_Plugin_Message
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Message
*/
class Phergie_Plugin_Message extends Phergie_Plugin_Abstract
{
/**
* Check whether a message is specifically targeted at the bot.
* This is the case when the message starts with the bot's name
* followed by [,:>] or when it is a private message.
*
* @return boolean true when the message is specifically targeted at the bot,
* false otherwise.
*/
public function isTargetedMessage()
{
$event = $this->getEvent();
$self = preg_quote($this->connection->getNick());
$targetPattern = <<<REGEX
{^
\s*{$self}\s*[:>,].* # expect the bots name, followed by a [:>,]
$}ix
REGEX;
return !$event->isInChannel()
|| preg_match($targetPattern, $event->getText()) > 0;
}
/**
* Allow for prefix and bot name aware extraction of a message
*
* @return string|bool $message The message, which is possibly targeted at the
* bot or false if a prefix requirement failed
*/
public function getMessage()
{
$event = $this->getEvent();
$prefix = preg_quote($this->getConfig('command.prefix'));
$self = preg_quote($this->connection->getNick());
$message = $event->getText();
// $prefixPattern matches : Phergie, do command <parameters>
// where $prefix = 'do' : do command <parameters>
// : Phergie, command <parameters>
$prefixPattern = <<<REGEX
{^
(?:
\s*{$self}\s*[:>,]\s* # start with bot name
(?:{$prefix})? # which is optionally followed by the prefix
|
\s*{$prefix} # or start with the prefix
)
\s*(.*) # always end with the message
$}ix
REGEX;
// $noPrefixPattern matches : Phergie, command <parameters>
// : command <parameters>
$noPrefixPattern = <<<REGEX
{^
\s*(?:{$self}\s*[:>,]\s*)? # optionally start with the bot name
(.*?) # always end with the message
$}ix
REGEX;
$pattern = $noPrefixPattern;
// If a prefix is set, force it as a requirement
if ($prefix && $event->isInChannel()) {
$pattern = $prefixPattern;
}
$match = null;
if (!preg_match($pattern, $message, $match)) {
return false;
}
return $match[1];
}
}

View File

@ -87,7 +87,7 @@ class Phergie_Plugin_Ping extends Phergie_Plugin_Abstract
{
$time = time();
if (!empty($this->lastPing)) {
if ($time - $this->lastPing > $this->getConfig('ping.ping', 10)) {
if ($time - $this->lastPing > $this->getConfig('ping.ping', 20)) {
$this->doQuit();
}
} elseif (
@ -112,7 +112,7 @@ class Phergie_Plugin_Ping extends Phergie_Plugin_Abstract
/**
* Set the last ping time
* lastPing needs to be exposed for unit testing
*
*
* @param int|null $ping timestamp of last ping
*
* @return self

View File

@ -1,6 +1,6 @@
<?php
/**
* Phergie
* Phergie
*
* PHP version 5
*
@ -11,7 +11,7 @@
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
* @category Phergie
* @category Phergie
* @package Phergie_Plugin_Quit
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
@ -22,14 +22,12 @@
/**
* Terminates the current connection upon command.
*
* @category Phergie
* @category Phergie
* @package Phergie_Plugin_Quit
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Quit
* @uses Phergie_Plugin_Command pear.phergie.org
*
* @pluginDesc Terminates the current connection upon command.
*/
class Phergie_Plugin_Quit extends Phergie_Plugin_Abstract
{
@ -41,17 +39,13 @@ class Phergie_Plugin_Quit extends Phergie_Plugin_Abstract
public function onLoad()
{
$this->getPluginHandler()->getPlugin('Command');
$help = $this->getPluginHandler()->getPlugin('Help');
$help->register($this);
}
/**
* Issues a quit command when a message is received requesting that the
* Issues a quit command when a message is received requesting that the
* bot terminate the current connection.
*
* @return void
*
* @pluginCmd terminates the connection
*/
public function onCommandQuit()
{

View File

@ -57,6 +57,7 @@ class Phergie_Plugin_Reload extends Phergie_Plugin_Abstract
if (!$this->plugins->hasPlugin($plugin)) {
echo 'DEBUG(Reload): ' . ucfirst($plugin) . ' is not loaded yet, loading', PHP_EOL;
$this->plugins->getPlugin($plugin);
$this->plugins->command->populateMethodCache();
return;
}
@ -79,7 +80,7 @@ class Phergie_Plugin_Reload extends Phergie_Plugin_Abstract
}
$contents = preg_replace(
array('/<\?(?:php)?/', '/class\s+' . $class . '/i'),
array('/^<\?(?:php)?/', '/class\s+' . $class . '/i'),
array('', 'class ' . $newClass),
$contents
);
@ -87,10 +88,16 @@ class Phergie_Plugin_Reload extends Phergie_Plugin_Abstract
$instance = new $newClass;
$instance->setName($plugin);
$instance->setEvent($this->event);
$this->plugins
->removePlugin($plugin)
->addPlugin($instance);
$this->plugins->command->populateMethodCache();
if ($this->plugins->hasPlugin('Help')) {
$this->plugins->help->populateRegistry();
}
echo 'DEBUG(Reload): Reloaded ', $class, ' to ', $newClass, PHP_EOL;
}
}

View File

@ -113,20 +113,21 @@ class Phergie_Plugin_Serve extends Phergie_Plugin_Abstract
$item = $this->getItem($database, $table, $match);
// Reprocess the request for censorship if required
$attempts = 0;
while ($censor && $attempts < 3) {
if ($this->plugins->hasPlugin('Censor')) {
$plugin = $this->plugins->getPlugin('Censor');
$clean = $plugin->cleanString($item->name);
if ($item->name != $clean) {
$attempts++;
$item = $this->getItem($database, $table, $match);
} else {
$censor = false;
$attempts = 0;
while ($censor && $attempts < 3) {
$clean = $plugin->cleanString($item->name);
if ($item->name != $clean) {
$attempts++;
$item = $this->getItem($database, $table, $match);
} else {
$censor = false;
}
}
if ($censor && $attempts == 3) {
$this->doAction($this->event->getSource(), 'shrugs.');
}
}
if ($censor && $attempts == 3) {
$this->doAction($this->event->getSource(), 'shrugs.');
}
// Derive the proper article for the item

View File

@ -0,0 +1,69 @@
<?php
/**
* Phergie
*
* PHP version 5
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
* @category Phergie
* @package Phergie_Plugin_Tea
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Tea
*/
/**
* Processes requests to serve users tea.
*
* @category Phergie
* @package Phergie_Plugin_Tea
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Tea
* @uses Phergie_Plugin_Command pear.phergie.org
* @uses Phergie_Plugin_Serve pear.phergie.org
*/
class Phergie_Plugin_Tea extends Phergie_Plugin_Abstract
{
/**
* Checks for dependencies.
*
* @return void
*/
public function onLoad()
{
$plugins = $this->plugins;
$plugins->getPlugin('Command');
$plugins->getPlugin('Serve');
}
/**
* Processes requests to serve a user tea.
*
* @param string $request Request including the target and an optional
* suggestion of what tea to serve
*
* @return void
*/
public function onCommandTea($request)
{
$format = $this->getConfig(
'tea.format',
'serves %target% a cup of %item% tea.'
);
$this->plugins->getPlugin('Serve')->serve(
dirname(__FILE__) . '/Tea/tea.db',
'tea',
$format,
$request
);
}
}

View File

@ -0,0 +1,49 @@
<?php
if (!defined('__DIR__')) {
define('__DIR__', dirname(__FILE__));
}
// Create database schema
echo 'Creating database', PHP_EOL;
$file = __DIR__ . '/tea.db';
if (file_exists($file)) {
unlink($file);
}
$db = new PDO('sqlite:' . $file);
$db->exec('CREATE TABLE tea (name VARCHAR(255), link VARCHAR(255))');
$db->exec('CREATE UNIQUE INDEX tea_name ON tea (name)');
$insert = $db->prepare('INSERT INTO tea (name, link) VALUES (:name, :link)');
// Get raw teacuppa.com data set
echo 'Downloading teacuppa.com data set', PHP_EOL;
$file = __DIR__ . '/tea-list.html';
if (!file_exists($file)) {
copy('http://www.teacuppa.com/tea-list.asp', $file);
}
$contents = file_get_contents($file);
// Extract data from data set
echo 'Processing teacuppa.com data', PHP_EOL;
$contents = tidy_repair_string($contents);
libxml_use_internal_errors(true);
$doc = new DOMDocument;
$doc->loadHTML($contents);
libxml_clear_errors();
$xpath = new DOMXPath($doc);
$teas = $xpath->query('//p[@class="page_title"]/following-sibling::table//a');
$db->beginTransaction();
foreach ($teas as $tea) {
$name = preg_replace(
array('/\s*\v+\s*/', '/\s+tea\s*$/i'),
array(' ', ''),
$tea->textContent
);
$link = 'http://teacuppa.com/' . $tea->getAttribute('href');
$insert->execute(array($name, $link));
}
$db->commit();
// Clean up
echo 'Cleaning up', PHP_EOL;
unlink($file);

View File

@ -31,9 +31,6 @@
* @link http://thefuckingweather.com
* @uses Phergie_Plugin_Command pear.phergie.org
* @uses Phergie_Plugin_Http pear.phergie.org
*
* @pluginDesc Detects and responds to requests for current weather
* conditions in a particular location.
*/
class Phergie_Plugin_TheFuckingWeather extends Phergie_Plugin_Abstract
@ -71,8 +68,6 @@ class Phergie_Plugin_TheFuckingWeather extends Phergie_Plugin_Abstract
*
* @return void
* @todo Implement use of URL shortening here
* @pluginCmd [location] Detects and responds to requests for current
* weather conditions in a particular location.
*/
public function onCommandThefuckingweather($location)
{
@ -92,7 +87,6 @@ class Phergie_Plugin_TheFuckingWeather extends Phergie_Plugin_Abstract
* @param string $location Location term
*
* @return void
* @pluginCmd [location] Alias for thefuckingweather command.
*/
public function onCommandTfw($location)
{

View File

@ -31,31 +31,32 @@
* @link http://pear.phergie.org/package/Phergie_Plugin_Tld
* @uses extension PDO
* @uses extension pdo_sqlite
*
* @pluginDesc Provides information for a top level domain.
*/
class Phergie_Plugin_Tld extends Phergie_Plugin_Abstract
{
/**
* connection to the database
* Connection to the database
*
* @var PDO
*/
protected $db;
/**
* Prepared statement for selecting a single tld
* Prepared statement for selecting a single TLD
*
* @var PDOStatement
*/
protected $select;
/**
* Prepared statement for selecting all tlds
* Prepared statement for selecting all TLDs
*
* @var PDOStatement
*/
protected $selectAll;
/**
* Checks for dependencies, sets up database and hard coded values
* Checks for dependencies and sets up the database and hard-coded values.
*
* @return void
*/
@ -65,9 +66,6 @@ class Phergie_Plugin_Tld extends Phergie_Plugin_Abstract
$this->fail('PDO and pdo_sqlite extensions must be installed');
}
$help = $this->getPluginHandler()->getPlugin('Help');
$help->register($this);
$dbFile = dirname(__FILE__) . '/Tld/tld.db';
try {
$this->db = new PDO('sqlite:' . $dbFile);
@ -93,8 +91,6 @@ class Phergie_Plugin_Tld extends Phergie_Plugin_Abstract
* @param string $tld tld to process
*
* @return null
*
* @pluginCmd .[tld] request details about the tld
*/
public function onCommandTld($tld)
{

View File

@ -148,7 +148,7 @@ class Phergie_Plugin_Youtube extends Phergie_Plugin_Abstract
{
switch ($parsed['host']) {
case 'youtu.be':
$v = ltrim('/', $parsed['path']);
$v = ltrim($parsed['path'], '/');
break;
case 'youtube.com':
case 'www.youtube.com':

View File

@ -1,6 +1,6 @@
<?php
/**
* Phergie
* Phergie
*
* PHP version 5
*
@ -11,7 +11,7 @@
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
* @category Phergie
* @category Phergie
* @package Phergie
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
@ -22,7 +22,7 @@
/**
* Base class for obtaining and processing incoming events.
*
* @category Phergie
* @category Phergie
* @package Phergie
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
@ -38,9 +38,9 @@ abstract class Phergie_Process_Abstract
protected $driver;
/**
* Current connection handler instance
* Current connection handler instance
*
* @var Phergie_Connection_Handler
* @var Phergie_Connection_Handler
*/
protected $connections;
@ -75,9 +75,9 @@ abstract class Phergie_Process_Abstract
/**
* Gets the required class refences from Phergie_Bot.
*
* @param Phergie_Bot $bot Current bot instance in use
* @param Phergie_Bot $bot Current bot instance in use
* @param array $options Optional processor arguments
*
*
* @return void
*/
public function __construct(Phergie_Bot $bot, array $options = array())
@ -99,8 +99,8 @@ abstract class Phergie_Process_Abstract
*/
protected function processEvents(Phergie_Connection $connection)
{
$this->plugins->preDispatch();
if (count($this->events)) {
$this->plugins->preDispatch();
foreach ($this->events as $event) {
$this->ui->onCommand($event, $connection);
@ -110,15 +110,15 @@ abstract class Phergie_Process_Abstract
$event->getArguments()
);
}
$this->plugins->postDispatch();
if ($this->events->hasEventOfType(Phergie_Event_Request::TYPE_QUIT)) {
$this->ui->onQuit($connection);
$this->connections->removeConnection($connection);
}
$this->events->clearEvents();
}
$this->plugins->postDispatch();
if ($this->events->hasEventOfType(Phergie_Event_Request::TYPE_QUIT)) {
$this->ui->onQuit($connection);
$this->connections->removeConnection($connection);
}
$this->events->clearEvents();
}
/**

View File

@ -117,11 +117,7 @@ class Phergie_Process_Async extends Phergie_Process_Abstract
if ($event = $this->driver->getEvent()) {
$this->ui->onEvent($event, $connection);
$this->plugins->setEvent($event);
if (!$this->plugins->preEvent()) {
continue;
}
$this->plugins->preEvent();
$this->plugins->{'on' . ucfirst($event->getType())}();
}

View File

@ -1,6 +1,6 @@
<?php
/**
* Phergie
* Phergie
*
* PHP version 5
*
@ -11,7 +11,7 @@
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
* @category Phergie
* @category Phergie
* @package Phergie
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
@ -23,7 +23,7 @@
* Connection data processor which reads all connections looking
* for a response.
*
* @category Phergie
* @category Phergie
* @package Phergie
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
@ -32,7 +32,7 @@
class Phergie_Process_Standard extends Phergie_Process_Abstract
{
/**
* Obtains and processes incoming events, then sends resulting outgoing
* Obtains and processes incoming events, then sends resulting outgoing
* events.
*
* @return void
@ -47,11 +47,7 @@ class Phergie_Process_Standard extends Phergie_Process_Abstract
if ($event = $this->driver->getEvent()) {
$this->ui->onEvent($event, $connection);
$this->plugins->setEvent($event);
if (!$this->plugins->preEvent()) {
continue;
}
$this->plugins->preEvent();
$this->plugins->{'on' . ucfirst($event->getType())}();
}

View File

@ -178,35 +178,11 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
/**
* Tests the plugin handler executing a callback on all contained
* plugins where one plugin short-circuits the process.
* plugins.
*
* @return void
*/
public function testImplementsCallWithShortCircuit()
{
$plugin1 = $this->getMockPlugin('TestPlugin1', array('callback'));
$plugin1
->expects($this->once())
->method('callback')
->will($this->returnValue(false));
$this->handler->addPlugin($plugin1);
$plugin2 = $this->getMockPlugin('TestPlugin2', array('callback'));
$plugin2
->expects($this->exactly(0))
->method('callback');
$this->handler->addPlugin($plugin2);
$this->assertFalse($this->handler->callback());
}
/**
* Tests the plugin handler executing a callback on all contained
* plugins where no plugins short-circuit the process.
*
* @return void
*/
public function testImplementsCallWithoutShortCircuit()
public function testImplementsCall()
{
foreach (range(1, 2) as $index) {
$plugin = $this->getMockPlugin('TestPlugin' . $index, array('callback'));
@ -736,4 +712,25 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
$actual = $this->handler->getPlugins(array('testplugin1', 'testplugin2'));
$this->assertEquals($expected, $actual);
}
/**
* Tests the plugin receiving and using a predefined iterator instance.
*
* @depends testGetPlugins
* @return void
*/
public function testSetIterator()
{
$plugin = $this->getMockPlugin('TestPlugin');
$this->handler->addPlugin($plugin);
$plugins = $this->handler->getPlugins();
$iterator = new ArrayIterator($plugins);
$this->handler->setIterator($iterator);
$this->assertSame($this->handler->getIterator(), $iterator);
$iterated = array();
foreach ($this->handler as $plugin) {
$iterated[strtolower($plugin->getName())] = $plugin;
}
$this->assertEquals($iterated, $plugins);
}
}

View File

@ -0,0 +1,151 @@
<?php
/**
* Phergie
*
* PHP version 5
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.
* It is also available through the world-wide-web at this URL:
* http://phergie.org/license
*
* @category Phergie
* @package Phergie_Tests
* @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Tests
*/
/**
* Unit test suite for Pherge_Plugin_Iterator.
*
* @category Phergie
* @package Phergie_Tests
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Tests
*/
class Phergie_Plugin_IteratorTest extends PHPUnit_Framework_TestCase
{
/**
* Iterator instance being tested
*
* @var Phergie_Plugin_Iterator
*/
protected $iterator;
/**
* List of mock plugin instances to be iterated
*
* @var array
*/
protected $plugins;
/**
* Initializes the iterator instance being tested.
*
* @return void
*/
public function setUp()
{
$this->plugins = array();
foreach (range(0, 4) as $index) {
$plugin = $this->getMock('Phergie_Plugin_Abstract');
$plugin
->expects($this->any())
->method('getName')
->will($this->returnValue($index));
$this->plugins[] = $plugin;
}
$this->iterator = new Phergie_Plugin_Iterator(
new ArrayIterator($this->plugins)
);
}
/**
* Tests that all plugins are iterated when no filters are applied.
*/
public function testIteratesAllPluginsWithNoFilters()
{
$expected = range(0, 4);
$actual = array();
foreach ($this->iterator as $plugin) {
$actual[] = $plugin->getName();
}
$this->assertEquals($expected, $actual);
}
/**
* Tests that appropriate plugins are iterated when plugin name filters
* are applied.
*/
public function testIteratesPluginsWithNameFilters()
{
// Test acceptance of strings and fluent interface implementation
$returned = $this->iterator->addPluginFilter('0');
$this->assertSame($this->iterator, $returned);
// Test acceptance of arrays
$this->iterator->addPluginFilter(array('1', '3'));
// Test application of filters to iteration
$expected = array('2', '4');
$actual = array();
foreach ($this->iterator as $plugin) {
$actual[] = $plugin->getName();
}
$this->assertEquals($expected, $actual);
}
/**
* Tests that appropriate plugins are iterated when method name filters
* are applied.
*
* The same method name is used in all cases here because mocked methods
* of mock objects do not appear to be detected by method_exists() or
* ReflectionClass, so filtering by a method defined in the base plugin
* class seems the easiest way to test that method filtering really
* works.
*/
public function testIteratesPluginsWithMethodFilters()
{
// Tests acceptance of strings and fluent interface implementation
$returned = $this->iterator->addMethodFilter('getName');
$this->assertSame($this->iterator, $returned);
// Test acceptance of arrays
$this->iterator->addMethodFilter(array('getName', 'getName'));
// Test application of filters to iteration
$expected = array();
$actual = array();
foreach ($this->iterator as $plugin) {
$actual[] = $plugin->getName();
}
$this->assertEquals($expected, $actual);
}
/**
* Tests that all plugins are iterated after filters are cleared.
*
* @depends testIteratesPluginsWithNameFilters
* @depends testIteratesPluginsWithMethodFilters
*/
public function testIteratesPluginsAfterClearingFilters()
{
$this->iterator->addPluginFilter('0');
$this->iterator->addMethodFilter('method1');
$this->iterator->clearFilters();
$expected = range(0, 4);
$actual = array();
foreach ($this->iterator as $plugin) {
$actual[] = $plugin->getName();
}
$this->assertEquals($expected, $actual);
}
}