From 742b302739bf31979b3c7f6b41136297264b86d3 Mon Sep 17 00:00:00 2001 From: Luke Fitzgerald Date: Mon, 26 Jul 2010 11:13:00 -0700 Subject: [PATCH] More Irc plugin work --- plugins/Irc/IrcPlugin.php | 12 +- plugins/Irc/README | 1 + .../extlib/phergie/Phergie/Plugin/Beer.php | 82 ++++ .../extlib/phergie/Phergie/Plugin/Beer/db.php | 4 +- .../extlib/phergie/Phergie/Plugin/Censor.php | 14 +- .../phergie/Phergie/Plugin/Cocktail.php | 71 +++ .../phergie/Phergie/Plugin/Cocktail/db.php | 74 +++ .../extlib/phergie/Phergie/Plugin/Cookie.php | 69 +++ .../phergie/Phergie/Plugin/Cookie/db.php | 49 ++ .../extlib/phergie/Phergie/Plugin/Karma.php | 447 ++++++++++++++++++ .../extlib/phergie/Phergie/Plugin/Serve.php | 159 +++++++ .../phergie/Phergie/Plugin/Statusnet.php | 19 +- .../extlib/phergie/Phergie/Plugin/Wine.php | 69 +++ .../extlib/phergie/Phergie/Plugin/Wine/db.php | 53 +++ .../extlib/phergie/Phergie/Process/Async.php | 6 +- .../extlib/phergie/Phergie/StatusnetBot.php | 2 +- plugins/Irc/ircmanager.php | 32 +- 17 files changed, 1133 insertions(+), 30 deletions(-) create mode 100644 plugins/Irc/extlib/phergie/Phergie/Plugin/Beer.php create mode 100644 plugins/Irc/extlib/phergie/Phergie/Plugin/Cocktail.php create mode 100644 plugins/Irc/extlib/phergie/Phergie/Plugin/Cocktail/db.php create mode 100644 plugins/Irc/extlib/phergie/Phergie/Plugin/Cookie.php create mode 100644 plugins/Irc/extlib/phergie/Phergie/Plugin/Cookie/db.php create mode 100644 plugins/Irc/extlib/phergie/Phergie/Plugin/Karma.php create mode 100755 plugins/Irc/extlib/phergie/Phergie/Plugin/Serve.php create mode 100644 plugins/Irc/extlib/phergie/Phergie/Plugin/Wine.php create mode 100644 plugins/Irc/extlib/phergie/Phergie/Plugin/Wine/db.php diff --git a/plugins/Irc/IrcPlugin.php b/plugins/Irc/IrcPlugin.php index d23f5005c0..dec6d7e832 100644 --- a/plugins/Irc/IrcPlugin.php +++ b/plugins/Irc/IrcPlugin.php @@ -55,12 +55,15 @@ class IrcPlugin extends ImPlugin { public $realname = null; public $nick = null; public $password = null; + public $nickservidentifyregexp = null; public $nickservpassword = null; public $channels = null; public $transporttype = null; public $encoding = null; public $regcheck = null; + public $unregregexp = null; + public $regregexp = null; public $transport = 'irc'; public $fake_irc; @@ -249,21 +252,12 @@ class IrcPlugin extends ImPlugin { if (!isset($this->port)) { $this->port = 6667; } - if (!isset($this->password)) { - $this->password = ''; - } if (!isset($this->transporttype)) { $this->transporttype = 'tcp'; } if (!isset($this->encoding)) { $this->encoding = 'UTF-8'; } - if (!isset($this->nickservpassword)) { - $this->nickservpassword = ''; - } - if (!isset($this->channels)) { - $this->channels = array(); - } if (!isset($this->regcheck)) { $this->regcheck = true; diff --git a/plugins/Irc/README b/plugins/Irc/README index 79ce8ff56a..bc45688f1e 100644 --- a/plugins/Irc/README +++ b/plugins/Irc/README @@ -19,6 +19,7 @@ realname*: Real name of bot nick*: Nickname of bot password: Password nickservpassword: NickServ password for identification +nickservidentifyregexp: Override existing regexp matching request for identification from NickServ channels: Channels for bot to idle in transporttype: Set to 'ssl' to enable SSL encoding: Set to change encoding diff --git a/plugins/Irc/extlib/phergie/Phergie/Plugin/Beer.php b/plugins/Irc/extlib/phergie/Phergie/Plugin/Beer.php new file mode 100644 index 0000000000..7213cdee8b --- /dev/null +++ b/plugins/Irc/extlib/phergie/Phergie/Plugin/Beer.php @@ -0,0 +1,82 @@ + + * @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_Beer + */ + +/** + * Processes requests to serve users beer. + * + * @category Phergie + * @package Phergie_Plugin_Beer + * @author Phergie Development Team + * @license http://phergie.org/license New BSD License + * @link http://pear.phergie.org/package/Phergie_Plugin_Beer + * @uses Phergie_Plugin_Command pear.phergie.org + * @uses Phergie_Plugin_Serve pear.phergie.org + */ +class Phergie_Plugin_Beer 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 beer. + * + * @param string $request Request including the target and an optional + * suggestion of what beer to serve + * + * @return void + */ + public function onCommandBeer($request) + { + $format = $this->getConfig( + 'beer.format', + 'throws %target% %article% %item%.' + ); + + $this->plugins->getPlugin('Serve')->serve( + dirname(__FILE__) . '/Beer/beer.db', + 'beer', + $format, + $request + ); + } + + /** + * Adds a "booze" alias for the "beer" command. + * + * @param string $request Request including the target and an optional + * suggestion of what beer to serve + * + * @return void + */ + public function onCommandBooze($request) + { + $this->onCommandBeer($request); + } +} diff --git a/plugins/Irc/extlib/phergie/Phergie/Plugin/Beer/db.php b/plugins/Irc/extlib/phergie/Phergie/Plugin/Beer/db.php index 309d389b55..05ae064ed7 100644 --- a/plugins/Irc/extlib/phergie/Phergie/Plugin/Beer/db.php +++ b/plugins/Irc/extlib/phergie/Phergie/Plugin/Beer/db.php @@ -34,7 +34,7 @@ $xpath = new DOMXPath($doc); $beers = $xpath->query('//table[@class="beerlist"]/tr/td[1]'); $db->beginTransaction(); foreach ($beers as $beer) { - $name = $beer->textContent; + $name = iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $beer->textContent); $link = 'http://beerme.com' . $beer->childNodes->item(1)->getAttribute('href'); $insert->execute(array($name, $link)); } @@ -65,7 +65,7 @@ $columns = fgetcsv($fp, 0, '|'); $db->beginTransaction(); while ($line = fgetcsv($fp, 0, '|')) { $line = array_combine($columns, $line); - $name = $line['name']; + $name = iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $line['name']); $link = null; $insert->execute(array($name, $link)); } diff --git a/plugins/Irc/extlib/phergie/Phergie/Plugin/Censor.php b/plugins/Irc/extlib/phergie/Phergie/Plugin/Censor.php index 3206bdd288..99c69d8734 100755 --- a/plugins/Irc/extlib/phergie/Phergie/Plugin/Censor.php +++ b/plugins/Irc/extlib/phergie/Phergie/Plugin/Censor.php @@ -72,7 +72,19 @@ class Phergie_Plugin_Censor extends Phergie_Plugin_Abstract $this->soap = new SoapClient('http://ws.cdyne.com/ProfanityWS/Profanity.asmx?wsdl'); } $params = array('Text' => $string); - $response = $this->soap->SimpleProfanityFilter($params); + $attempts = 0; + while ($attempts < 3) { + try { + $response = $this->soap->SimpleProfanityFilter($params); + break; + } catch (SoapFault $e) { + $attempts++; + sleep(1); + } + } + if ($attempts == 3) { + return $string; + } return $response->SimpleProfanityFilterResult->CleanText; } diff --git a/plugins/Irc/extlib/phergie/Phergie/Plugin/Cocktail.php b/plugins/Irc/extlib/phergie/Phergie/Plugin/Cocktail.php new file mode 100644 index 0000000000..eafeb657bf --- /dev/null +++ b/plugins/Irc/extlib/phergie/Phergie/Plugin/Cocktail.php @@ -0,0 +1,71 @@ + + * @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_Cocktail + */ + +/** + * Processes requests to serve users cocktail. + * + * @category Phergie + * @package Phergie_Plugin_Cocktail + * @author Phergie Development Team + * @license http://phergie.org/license New BSD License + * @link http://pear.phergie.org/package/Phergie_Plugin_Cocktail + * @uses Phergie_Plugin_Command pear.phergie.org + * @uses Phergie_Plugin_Serve pear.phergie.org + */ +class Phergie_Plugin_Cocktail 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 cocktail. + * + * @param string $request Request including the target and an optional + * suggestion of what cocktail to serve + * + * @return void + */ + public function onCommandCocktail($request) + { + $format = $this->getConfig( + 'cocktail.format', + 'throws %target% %article% %item%.' + ); + + $this->plugins->getPlugin('Serve')->serve( + dirname(__FILE__) . '/Cocktail/cocktail.db', + 'cocktail', + $format, + $request, + true + ); + } +} + diff --git a/plugins/Irc/extlib/phergie/Phergie/Plugin/Cocktail/db.php b/plugins/Irc/extlib/phergie/Phergie/Plugin/Cocktail/db.php new file mode 100644 index 0000000000..2e61dd0bdb --- /dev/null +++ b/plugins/Irc/extlib/phergie/Phergie/Plugin/Cocktail/db.php @@ -0,0 +1,74 @@ +exec('CREATE TABLE cocktail (name VARCHAR(255), link VARCHAR(255))'); +$db->exec('CREATE UNIQUE INDEX cocktail_name ON cocktail (name)'); +$insert = $db->prepare('INSERT INTO cocktail (name, link) VALUES (:name, :link)'); + +// Get raw webtender.com data set +echo 'Downloading webtender.com data set', PHP_EOL; +$start = 1; +do { + $file = __DIR__ . '/' . $start . '.html'; + if (file_exists($file)) { + continue; + } + copy( + 'http://www.webtender.com/db/browse?level=2&dir=drinks&char=%2A&start=' . $start, + $file + ); + if (!isset($limit)) { + $contents = file_get_contents($file); + preg_match('/([0-9]+) found/', $contents, $match); + $limit = $match[1] + (150 - ($match[1] % 150)); + } + echo 'Got records ', $start, ' - ', min($start + 150, $limit), ' of ', $limit, PHP_EOL; + $start += 150; +} while ($start < $limit); + +// Extract data from data set +$start = 1; +while ($start < $limit) { + echo 'Processing ', $start, ' - ', min($start + 150, $limit), ' of ', $limit, PHP_EOL; + + $file = __DIR__ . '/' . $start . '.html'; + $contents = file_get_contents($file); + $contents = tidy_repair_string($contents); + libxml_use_internal_errors(true); + $doc = new DOMDocument; + $doc->loadHTML($contents); + libxml_clear_errors(); + $xpath = new DOMXPath($doc); + + $cocktails = $xpath->query('//li/a'); + $db->beginTransaction(); + foreach ($cocktails as $cocktail) { + $name = $cocktail->nodeValue; + $name = preg_replace('/ The$|^The |\s*\([^)]+\)\s*| #[0-9]+$/', '', $name); + $name = html_entity_decode($name); + $link = 'http://www.webtender.com' . $cocktail->getAttribute('href'); + $insert->execute(array($name, $link)); + } + $db->commit(); + + $start += 150; +} + +// Clean up +echo 'Cleaning up', PHP_EOL; +$start = 1; +while ($start < $limit) { + $file = __DIR__ . '/' . $start . '.html'; + unlink($file); + $start += 150; +} diff --git a/plugins/Irc/extlib/phergie/Phergie/Plugin/Cookie.php b/plugins/Irc/extlib/phergie/Phergie/Plugin/Cookie.php new file mode 100644 index 0000000000..4bc2ceecbc --- /dev/null +++ b/plugins/Irc/extlib/phergie/Phergie/Plugin/Cookie.php @@ -0,0 +1,69 @@ + + * @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_Cookie + */ + +/** + * Processes requests to serve users cookies. + * + * @category Phergie + * @package Phergie_Plugin_Cookie + * @author Phergie Development Team + * @license http://phergie.org/license New BSD License + * @link http://pear.phergie.org/package/Phergie_Plugin_Cookie + * @uses Phergie_Plugin_Command pear.phergie.org + * @uses Phergie_Plugin_Serve pear.phergie.org + */ +class Phergie_Plugin_Cookie 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 cookie. + * + * @param string $request Request including the target and an optional + * suggestion of what cookie to serve + * + * @return void + */ + public function onCommandCookie($request) + { + $format = $this->getConfig( + 'cookie.format', + 'throws %target% %article% %item%.' + ); + + $this->plugins->getPlugin('Serve')->serve( + dirname(__FILE__) . '/Cookie/cookie.db', + 'cookies', + $format, + $request + ); + } +} diff --git a/plugins/Irc/extlib/phergie/Phergie/Plugin/Cookie/db.php b/plugins/Irc/extlib/phergie/Phergie/Plugin/Cookie/db.php new file mode 100644 index 0000000000..4b3d29c53e --- /dev/null +++ b/plugins/Irc/extlib/phergie/Phergie/Plugin/Cookie/db.php @@ -0,0 +1,49 @@ +exec('CREATE TABLE cookies (name VARCHAR(255), link VARCHAR(255))'); +$db->exec('CREATE UNIQUE INDEX cookie_name ON cookies (name)'); +$insert = $db->prepare('INSERT INTO cookies (name, link) VALUES (:name, :link)'); + +// Get Cookies list from http://en.wikipedia.org/wiki/List_of_cookies +echo 'Downloading data from Wikipedia', PHP_EOL; +$file = __DIR__ . '/cookieslist.txt'; +if (!file_exists($file)) { + copy('http://en.wikipedia.org/wiki/List_of_cookies', $file); +} +$contents = file_get_contents($file); + +// Extract data from data set +echo 'Processing Wikipedia\'s cookies list', 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); + +$cookies = $xpath->query('//table[@width="90%"]/tr/td[1]/a'); + +foreach ($cookies as $cookie) { + + $name = str_replace(array('(',')',"\n", 'cookies'), array('','', ' ', 'cookie' ), trim( $cookie->textContent)); + + $link = 'http://en.wikipedia.org' . $cookie->getAttribute('href'); + $insert->execute(array($name, $link)); + print 'added ['.$name.'] -> '. $link . PHP_EOL; +} + +// Clean up +echo 'Cleaning up', PHP_EOL; +unlink($file); + diff --git a/plugins/Irc/extlib/phergie/Phergie/Plugin/Karma.php b/plugins/Irc/extlib/phergie/Phergie/Plugin/Karma.php new file mode 100644 index 0000000000..b7ce48685a --- /dev/null +++ b/plugins/Irc/extlib/phergie/Phergie/Plugin/Karma.php @@ -0,0 +1,447 @@ + + * @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_Karma + */ + +/** + * 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. + * + * @category Phergie + * @package Phergie_Plugin_Karma + * @author Phergie Development Team + * @license http://phergie.org/license New BSD License + * @link http://pear.phergie.org/package/Phergie_Plugin_Karma + */ +class Phergie_Plugin_Karma extends Phergie_Plugin_Abstract +{ + /** + * Stores the 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 + * + * @var PDOStatement + */ + protected $insertKarma; + protected $updateKarma; + protected $fetchKarma; + protected $insertComment; + + /** + * Connects to the database containing karma ratings and initializes + * class properties. + * + * @return void + */ + public function onLoad() + { + $this->db = null; + $this->lastGc = null; + $this->log = array(); + + 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 + ) + '); + + $this->fetchKarma = $this->db->prepare(' + SELECT karma, ROWID id FROM karmas WHERE LOWER(word) = LOWER(:word) LIMIT 1 + '); + + $this->updateKarma = $this->db->prepare(' + UPDATE karmas SET karma = :karma WHERE LOWER(word) = LOWER(:word) + '); + } + + /** + * Checks for dependencies. + * + * @return void + */ + public static function onLoad() + { + if (!extension_loaded('PDO') || !extension_loaded('pdo_sqlite')) { + $this->fail('PDO and pdo_sqlite extensions must be installed'); + } + } + + /** + * Handles requests for incrementation, decrementation, or lookup of karma + * ratings sent via messages from users. + * + * @return void + */ + public function onPrivmsg() + { + $source = $this->event->getSource(); + $message = $this->event->getArgument(1); + $target = $this->event->getNick(); + + // Command prefix check + $prefix = preg_quote(trim($this->getConfig('command.prefix'))); + $bot = preg_quote($this->getConfig('connections.nick')); + $exp = '(?:(?:' . $bot . '\s*[:,>]?\s+(?:' . $prefix . ')?)|(?:' . $prefix . '))'; + + // 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]); + + // Check the blacklist + if (is_array($this->karmaBlacklist) && in_array($term, $this->karmaBlacklist)) { + $this->doNotice($target, $term . ' is blacklisted'); + return; + } + + // Return fixed value if set + if (isset($this->fixedKarma[$term])) { + $this->doPrivmsg($source, $target . ': ' . sprintf($this->fixedKarma[$term], $m[1]) . '.'); + return; + } + + // Return current karma or neutral if not set yet + $this->fetchKarma->execute(array(':word'=>$term)); + $res = $this->fetchKarma->fetch(PDO::FETCH_ASSOC); + + // 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(); + } + } + } + } + } + + 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. + * + * @return void + */ + public function doGc() + { + unset($this->log); + $this->log = array(); + $this->lastGc = date('d'); + } +} diff --git a/plugins/Irc/extlib/phergie/Phergie/Plugin/Serve.php b/plugins/Irc/extlib/phergie/Phergie/Plugin/Serve.php new file mode 100755 index 0000000000..19ecb0c7e4 --- /dev/null +++ b/plugins/Irc/extlib/phergie/Phergie/Plugin/Serve.php @@ -0,0 +1,159 @@ + + * @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_Serve + */ + +/** + * Processes requests to serve a user something from a database. + * + * @category Phergie + * @package Phergie_Plugin_Serve + * @author Phergie Development Team + * @license http://phergie.org/license New BSD License + * @link http://pear.phergie.org/package/Phergie_Plugin_Serve + * @uses extension pdo + * @uses extension pdo_sqlite + */ +class Phergie_Plugin_Serve extends Phergie_Plugin_Abstract +{ + /** + * Checks for dependencies. + * + * @return void + */ + public function onLoad() + { + if (!extension_loaded('PDO') || !extension_loaded('pdo_sqlite')) { + $this->fail('PDO and pdo_sqlite extensions must be installed'); + } + } + + /** + * Retrieves a random item from the database table. + * + * @param string $database Path to the SQLite database file + * @param string $table Name of the database table + * @param array $request Parsed request + * + * @return object Retrieved item + */ + protected function getItem($database, $table, array $request) + { + $db = new PDO('sqlite:' . $database); + if (!empty($request['suggestion'])) { + $query = 'SELECT * FROM ' . $table . ' WHERE name LIKE ? ORDER BY RANDOM() LIMIT 1'; + $stmt = $db->prepare($query); + $stmt->execute(array('%' . $request['suggestion'] . '%')); + $item = $stmt->fetchObject(); + if (!$item) { + $item = new stdClass; + $item->name = $request['suggestion']; + $item->link = null; + } + } else { + $query = 'SELECT * FROM ' . $table . ' ORDER BY RANDOM() LIMIT 1'; + $stmt = $db->query($query); + $item = $stmt->fetchObject(); + } + return $item; + } + + /** + * Processes a request to serve a user something. + * + * @param string $database Path to the SQLite database file + * @param string $table Name of the database table + * @param string $format Format of the response where %target%, + * %item%, %article%', and %link will be replaced with their + * respective data + * @param string $request Request string including the target and an + * optional suggestion of the item to fetch + * @param boolean $censor TRUE to integrate with the Censor plugin, + * defaults to FALSE + * + * @return boolean TRUE if the request was processed successfully, FALSE + * otherwise + */ + public function serve($database, $table, $format, $request, $censor = false) + { + // Parse the request + $result = preg_match( + '/(?P[^\s]+)(\s+an?\s+)?(?P.*)?/', + $request, + $match + ); + + if (!$result) { + return false; + } + + // Resolve the target + $target = $match['target']; + if ($target == 'me') { + $target = $this->event->getNick(); + } + + // Process the request + $item = $this->getItem($database, $table, $match); + + // Reprocess the request for censorship if required + $attempts = 0; + while ($censor && $attempts < 3) { + $plugin = $this->plugins->getPlugin('Censor'); + $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.'); + } + + // Derive the proper article for the item + if (preg_match('/^[aeiou]/i', $item->name)) { + $article = 'an'; + } else { + $article = 'a'; + } + + // Format the message + $replacements = array( + 'target' => $target, + 'item' => $item->name, + 'link' => $item->link, + 'article' => $article + ); + + $msg = $format; + foreach ($replacements as $placeholder => $value) { + $msg = str_replace( + '%' . $placeholder . '%', + $value, + $msg + ); + } + + // Send the message + $this->doAction($this->event->getSource(), $msg); + } +} diff --git a/plugins/Irc/extlib/phergie/Phergie/Plugin/Statusnet.php b/plugins/Irc/extlib/phergie/Phergie/Plugin/Statusnet.php index f0cee28184..3da5fdf4fc 100644 --- a/plugins/Irc/extlib/phergie/Phergie/Plugin/Statusnet.php +++ b/plugins/Irc/extlib/phergie/Phergie/Plugin/Statusnet.php @@ -59,15 +59,8 @@ class Phergie_Plugin_Statusnet extends Phergie_Plugin_Abstract { $this->regCallback = NULL; } - $this->unregRegexp = $this->config['statusnet.unregregexp']; - if (!$this->unregRegexp) { - $this->unregRegexp = '/\x02(.*?)\x02 (?:isn\'t|is not) registered/i'; - } - - $this->regRegexp = $this->config['statusnet.regregexp']; - if (!$this->regRegexp) { - $this->regRegexp = '/(?:\A|\x02)(\w+?)\x02? (?:\(account|is \w+?\z)/i'; - } + $this->unregRegexp = $this->getConfig('statusnet.unregregexp', '/\x02(.*?)\x02 (?:isn\'t|is not) registered/i'); + $this->regRegexp = $this->getConfig('statusnet.regregexp', '/(?:\A|\x02)(\w+?)\x02? (?:\(account|is \w+?\z)/i'); } /** @@ -81,6 +74,10 @@ class Phergie_Plugin_Statusnet extends Phergie_Plugin_Abstract { $source = $event->getSource(); $message = trim($event->getText()); + if ($source == '#statustest') { + $this->doPrivmsg('#statustest', "\001Line1\020nLine2"); + } + call_user_func($this->messageCallback, array('sender' => $source, 'message' => $message)); } } @@ -103,4 +100,8 @@ class Phergie_Plugin_Statusnet extends Phergie_Plugin_Abstract { } } } + + public function onTick() { + echo "\nTICK!\n"; + } } diff --git a/plugins/Irc/extlib/phergie/Phergie/Plugin/Wine.php b/plugins/Irc/extlib/phergie/Phergie/Plugin/Wine.php new file mode 100644 index 0000000000..9aa0845a6a --- /dev/null +++ b/plugins/Irc/extlib/phergie/Phergie/Plugin/Wine.php @@ -0,0 +1,69 @@ + + * @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_Wine + */ + +/** + * Processes requests to serve users wine. + * + * @category Phergie + * @package Phergie_Plugin_Wine + * @author Phergie Development Team + * @license http://phergie.org/license New BSD License + * @link http://pear.phergie.org/package/Phergie_Plugin_Wine + * @uses Phergie_Plugin_Command pear.phergie.org + * @uses Phergie_Plugin_Serve pear.phergie.org + */ +class Phergie_Plugin_Wine 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 wine. + * + * @param string $request Request including the target and an optional + * suggestion of what wine to serve + * + * @return void + */ + public function onCommandWine($request) + { + $format = $this->getConfig( + 'wine.format', + 'serves %target% a glass of %item%.' + ); + + $this->plugins->getPlugin('Serve')->serve( + dirname(__FILE__) . '/Wine/wine.db', + 'wine', + $format, + $request + ); + } +} diff --git a/plugins/Irc/extlib/phergie/Phergie/Plugin/Wine/db.php b/plugins/Irc/extlib/phergie/Phergie/Plugin/Wine/db.php new file mode 100644 index 0000000000..ce01c2d983 --- /dev/null +++ b/plugins/Irc/extlib/phergie/Phergie/Plugin/Wine/db.php @@ -0,0 +1,53 @@ +exec('CREATE TABLE wine (name VARCHAR(255), link VARCHAR(255))'); +$db->exec('CREATE UNIQUE INDEX wine_name ON wine (name)'); +$insert = $db->prepare('INSERT INTO wine (name, link) VALUES (:name, :link)'); + +// Get and decompress lcboapi.com data set +$outer = __DIR__ . '/current.zip'; +if (!file_exists($outer)) { + echo 'Downloading lcboapi.com data set', PHP_EOL; + copy('http://lcboapi.com/download/current.zip', $outer); +} + +echo 'Decompressing lcboapi.com data set', PHP_EOL; +$zip = new ZipArchive; +$zip->open($outer); +$stat = $zip->statIndex(0); +$inner = __DIR__ . '/' . $stat['name']; +$zip->extractTo(__DIR__); +$zip->close(); +$zip = new ZipArchive; +$zip->open($inner); +$stat = $zip->statIndex(0); +$file = __DIR__ . '/' . $stat['name']; +$zip->extractTo(__DIR__); +$zip->close(); + +// Aggregate data set into the database +$lcbo = new PDO('sqlite:' . $file); +$result = $lcbo->query('SELECT product_no, name FROM products WHERE primary_category = "Wine"'); +$wines = $result->fetchAll(); +echo 'Processing lcboapi.com data - ', number_format(count($wines), 0), ' records', PHP_EOL; +$db->beginTransaction(); +foreach ($wines as $wine) { + $name = $wine['name']; + $link = 'http://lcboapi.com/products/' . $wine['product_no']; + $insert->execute(array($name, $link)); +} +$db->commit(); + +// Clean up +echo 'Cleaning up', PHP_EOL; +unset($lcbo); +unlink($outer); +unlink($inner); +unlink($file); diff --git a/plugins/Irc/extlib/phergie/Phergie/Process/Async.php b/plugins/Irc/extlib/phergie/Phergie/Process/Async.php index 4946152bb3..e553ad5a82 100644 --- a/plugins/Irc/extlib/phergie/Phergie/Process/Async.php +++ b/plugins/Irc/extlib/phergie/Phergie/Process/Async.php @@ -37,14 +37,14 @@ class Phergie_Process_Async extends Phergie_Process_Abstract * * @var int */ - protected $sec; + protected $sec = 0; /** * Length of time to poll for stream activity (microseconds) * * @var int */ - protected $usec; + protected $usec = 200000; /** * Length of time to wait between ticks. @@ -87,7 +87,7 @@ class Phergie_Process_Async extends Phergie_Process_Abstract } } - if (isset($this->sec) && isset($this->usec)) { + if (!isset($this->sec) && !isset($this->usec)) { throw new Phergie_Process_Exception( 'One of the processor options "sec" or "usec" must be specified' ); diff --git a/plugins/Irc/extlib/phergie/Phergie/StatusnetBot.php b/plugins/Irc/extlib/phergie/Phergie/StatusnetBot.php index 5fe65444b1..9c1b3a6f18 100644 --- a/plugins/Irc/extlib/phergie/Phergie/StatusnetBot.php +++ b/plugins/Irc/extlib/phergie/Phergie/StatusnetBot.php @@ -62,7 +62,7 @@ class Phergie_StatusnetBot extends Phergie_Bot { * * @return void */ - public function receive() { + public function handleEvents() { $this->getProcessor()->handleEvents(); } diff --git a/plugins/Irc/ircmanager.php b/plugins/Irc/ircmanager.php index 8c04da68fc..933cc03878 100644 --- a/plugins/Irc/ircmanager.php +++ b/plugins/Irc/ircmanager.php @@ -64,6 +64,19 @@ class IrcManager extends ImManager { } } + /** + * Idle processing for io manager's execution loop. + * Send keepalive pings to server. + * + * @return void + */ + public function idle() { + // Call Phergie's doTick methods if necessary + echo "BEGIN IDLE\n"; + $this->conn->handleEvents(); + echo "END IDLE\n"; + } + /** * Process IRC events that have come in over the wire. * @@ -73,7 +86,7 @@ class IrcManager extends ImManager { public function handleInput($socket) { common_log(LOG_DEBUG, 'Servicing the IRC queue.'); $this->stats('irc_process'); - $this->conn->receive(); + $this->conn->handleEvents(); } /** @@ -91,7 +104,7 @@ class IrcManager extends ImManager { 'connections' => array( array( 'host' => $this->plugin->host, - 'port' => $port, + 'port' => $this->plugin->port, 'username' => $this->plugin->username, 'realname' => $this->plugin->realname, 'nick' => $this->plugin->nick, @@ -104,7 +117,7 @@ class IrcManager extends ImManager { 'driver' => 'statusnet', 'processor' => 'async', - 'processor.options' => array('usec' => 0), + 'processor.options' => array('sec' => 0, 'usec' => 0), 'plugins' => array( 'Pong', @@ -118,9 +131,14 @@ class IrcManager extends ImManager { 'ui.enabled' => true, 'nickserv.password' => $this->plugin->nickservpassword, + 'nickserv.identify_message' => $this->plugin->nickservidentifyregexp, + 'autojoin.channels' => $this->plugin->channels, + 'statusnet.messagecallback' => array($this, 'handle_irc_message'), - 'statusnet.regcallback' => array($this, 'handle_reg_response') + 'statusnet.regcallback' => array($this, 'handle_reg_response'), + 'statusnet.unregregexp' => $this->plugin->unregregexp, + 'statusnet.regregexp' => $this->plugin->regregexp ) ); @@ -215,8 +233,12 @@ class IrcManager extends ImManager { $this->regchecksLookup[$usernick] = $screenname; } + $args = $data['data']['args']; + $lines = explode("\n", $args[1]); try { - $this->conn->send($data['data']['command'], $data['data']['args']); + foreach ($lines as $line) { + $this->conn->send($data['data']['command'], array($args[0], $line)); + } } catch (Phergie_Driver_Exception $e) { $this->conn->reconnect(); return false; -- 2.39.5