]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Updated phergie library
authorLuke Fitzgerald <lw.fitzgerald@googlemail.com>
Wed, 30 Jun 2010 16:33:29 +0000 (09:33 -0700)
committerLuke Fitzgerald <lw.fitzgerald@googlemail.com>
Wed, 30 Jun 2010 16:33:29 +0000 (09:33 -0700)
35 files changed:
plugins/Irc/extlib/phergie/Phergie/Autoload.php
plugins/Irc/extlib/phergie/Phergie/Bot.php
plugins/Irc/extlib/phergie/Phergie/Connection.php
plugins/Irc/extlib/phergie/Phergie/Db/Exception.php [new file with mode: 0644]
plugins/Irc/extlib/phergie/Phergie/Db/Manager.php [new file with mode: 0755]
plugins/Irc/extlib/phergie/Phergie/Db/Sqlite.php [new file with mode: 0644]
plugins/Irc/extlib/phergie/Phergie/Driver/Exception.php
plugins/Irc/extlib/phergie/Phergie/Driver/Streams.php
plugins/Irc/extlib/phergie/Phergie/Event/Handler.php
plugins/Irc/extlib/phergie/Phergie/Event/Request.php
plugins/Irc/extlib/phergie/Phergie/Plugin/Abstract.php
plugins/Irc/extlib/phergie/Phergie/Plugin/Censor.php [new file with mode: 0755]
plugins/Irc/extlib/phergie/Phergie/Plugin/Cron.php [new file with mode: 0644]
plugins/Irc/extlib/phergie/Phergie/Plugin/Exception.php
plugins/Irc/extlib/phergie/Phergie/Plugin/Google.php
plugins/Irc/extlib/phergie/Phergie/Plugin/Handler.php
plugins/Irc/extlib/phergie/Phergie/Plugin/Help.php
plugins/Irc/extlib/phergie/Phergie/Plugin/Http/Response.php
plugins/Irc/extlib/phergie/Phergie/Plugin/Php.php
plugins/Irc/extlib/phergie/Phergie/Plugin/Php/Source/Local.php
plugins/Irc/extlib/phergie/Phergie/Plugin/Reload.php [new file with mode: 0755]
plugins/Irc/extlib/phergie/Phergie/Plugin/Remind.php
plugins/Irc/extlib/phergie/Phergie/Plugin/SpellCheck.php [new file with mode: 0644]
plugins/Irc/extlib/phergie/Phergie/Plugin/Tld.php [new file with mode: 0644]
plugins/Irc/extlib/phergie/Phergie/Plugin/Url.php
plugins/Irc/extlib/phergie/Phergie/Plugin/Url/Shorten/Abstract.php
plugins/Irc/extlib/phergie/Phergie/Plugin/Url/Shorten/Trim.php
plugins/Irc/extlib/phergie/Phergie/Plugin/Url/url.tld.txt [new file with mode: 0644]
plugins/Irc/extlib/phergie/Phergie/Plugin/Weather.php [new file with mode: 0755]
plugins/Irc/extlib/phergie/Settings.php.dist
plugins/Irc/extlib/phergie/Tests/Phergie/Plugin/HandlerTest.php
plugins/Irc/extlib/phergie/Tests/Phergie/Plugin/Mock.php
plugins/Irc/extlib/phergie/Tests/Phergie/Plugin/SpellCheckTest.php [new file with mode: 0644]
plugins/Irc/extlib/phergie/Tests/TestHelper.php
plugins/Irc/extlib/phergie/build.xml

index b03fe2ae10cb32ee2829033402d10010d3ca0ee9..0004f44e2211c4a1f1728facbc1d1aeef811ea56 100755 (executable)
@@ -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 @@
 /**
  * Autoloader for Phergie classes.
  *
- * @category Phergie 
+ * @category Phergie
  * @package  Phergie
  * @author   Phergie Development Team <team@phergie.org>
  * @license  http://phergie.org/license New BSD License
@@ -37,9 +37,9 @@ class Phergie_Autoload
      */
     public function __construct()
     {
-        $path = dirname(__FILE__);
+        $path = realpath(dirname(__FILE__) . '/..');
         $includePath = get_include_path();
-        $includePathList = explode(PATH_SEPARATOR, $includePath); 
+        $includePathList = explode(PATH_SEPARATOR, $includePath);
         if (!in_array($path, $includePathList)) {
             self::addPath($path);
         }
@@ -54,9 +54,6 @@ class Phergie_Autoload
      */
     public function load($class)
     {
-        if (substr($class, 0, 8) == 'Phergie_') {
-            $class = substr($class, 8);
-        }
         include str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
     }
 
index 153bd55905e5f00cc464277222bae807050c8865..85e8a00fc97bd57c9f023c30fd029ef32b4b0e3d 100755 (executable)
@@ -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 @@
 /**
  * Composite class for other components to represent the bot.
  *
- * @category Phergie 
+ * @category Phergie
  * @package  Phergie
  * @author   Phergie Development Team <team@phergie.org>
  * @license  http://phergie.org/license New BSD License
@@ -50,9 +50,9 @@ class Phergie_Bot
     protected $config;
 
     /**
-     * Current connection handler instance 
+     * Current connection handler instance
      *
-     * @var Phergie_Connection_Handler 
+     * @var Phergie_Connection_Handler
      */
     protected $connections;
 
@@ -85,7 +85,7 @@ class Phergie_Bot
     protected $processor;
 
     /**
-     * Returns a driver instance, creating one of the default class if 
+     * Returns a driver instance, creating one of the default class if
      * none has been set.
      *
      * @return Phergie_Driver_Abstract
@@ -135,14 +135,14 @@ class Phergie_Bot
     }
 
     /**
-     * Returns the entire configuration in use or the value of a specific 
+     * Returns the entire configuration in use or the value of a specific
      * configuration setting.
      *
-     * @param string $index   Optional index of a specific configuration 
+     * @param string $index   Optional index of a specific configuration
      *        setting for which the corresponding value should be returned
      * @param mixed  $default Value to return if no match is found for $index
      *
-     * @return mixed Value corresponding to $index or the entire 
+     * @return mixed Value corresponding to $index or the entire
      *         configuration if $index is not specified
      */
     public function getConfig($index = null, $default = null)
@@ -219,7 +219,7 @@ class Phergie_Bot
     }
 
     /**
-     * Returns a connection handler instance, creating it if it does not 
+     * Returns a connection handler instance, creating it if it does not
      * already exist and using a default class if none has been set.
      *
      * @return Phergie_Connection_Handler
@@ -246,7 +246,7 @@ class Phergie_Bot
     }
 
     /**
-     * Returns an end-user interface instance, creating it if it does not 
+     * Returns an end-user interface instance, creating it if it does not
      * already exist and using a default class if none has been set.
      *
      * @return Phergie_Ui_Abstract
@@ -273,7 +273,7 @@ class Phergie_Bot
     }
 
     /**
-     * Returns a processer instance, creating one if none exists. 
+     * Returns a processer instance, creating one if none exists.
      *
      * @return Phergie_Process_Abstract
      */
@@ -281,14 +281,14 @@ class Phergie_Bot
     {
         if (empty($this->processor)) {
             $class = 'Phergie_Process_Standard';
-            
+
             $type = $this->getConfig('processor');
             if (!empty($type)) {
                 $class = 'Phergie_Process_' . ucfirst($type);
             }
 
             $this->processor = new $class(
-                $this, 
+                $this,
                 $this->getConfig('processor.options', array())
             );
         }
@@ -318,7 +318,7 @@ class Phergie_Bot
         $config = $this->getConfig();
         $plugins = $this->getPluginHandler();
         $ui = $this->getUi();
-        
+
         $plugins->setAutoload($config['plugins.autoload']);
         foreach ($config['plugins'] as $name) {
             try {
@@ -358,15 +358,15 @@ class Phergie_Bot
     }
 
     /**
-     * Establishes server connections and initiates an execution loop to 
+     * Establishes server connections and initiates an execution loop to
      * continuously receive and process events.
      *
-     * @return Phergie_Bot Provides a fluent interface 
+     * @return Phergie_Bot Provides a fluent interface
      */
     public function run()
     {
         set_time_limit(0);
-        
+
         $timezone = $this->getConfig('timezone', 'UTC');
         date_default_timezone_set($timezone);
 
index 80f91e8da50dd3c8bc447c40665c6a7d3c7dc367..d6c89ea8018159172f28bc0bf44386dacdd28401 100755 (executable)
@@ -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 @@
 /**
  * Data structure for connection metadata.
  *
- * @category Phergie 
+ * @category Phergie
  * @package  Phergie
  * @author   Phergie Development Team <team@phergie.org>
  * @license  http://phergie.org/license New BSD License
@@ -38,7 +38,7 @@ class Phergie_Connection
     protected $host;
 
     /**
-     * Port on which the client will connect, defaults to the standard IRC 
+     * Port on which the client will connect, defaults to the standard IRC
      * port
      *
      * @var int
@@ -46,13 +46,21 @@ class Phergie_Connection
     protected $port;
 
     /**
-     * Transport for the connection, defaults to tcp but can be set to ssl 
+     * Transport for the connection, defaults to tcp but can be set to ssl
      * or variations thereof to connect over SSL
      *
-     * @var string 
+     * @var string
      */
     protected $transport;
 
+    /**
+     * Encoding method for the connection, defaults to ISO-8859-1 but can
+     * be set to UTF8 if necessary
+     *
+     * @var strng
+     */
+    protected $encoding;
+
     /**
      * Nick that the client will use
      *
@@ -91,7 +99,7 @@ class Phergie_Connection
     /**
      * Constructor to initialize instance properties.
      *
-     * @param array $options Optional associative array of property values 
+     * @param array $options Optional associative array of property values
      *        to initialize
      *
      * @return void
@@ -99,6 +107,9 @@ class Phergie_Connection
     public function __construct(array $options = array())
     {
         $this->transport = 'tcp';
+        $this->encoding = 'ISO-8859-1';
+        // @note this may need changed to something different, for broader support.
+        // @note also may need to make use of http://us.php.net/manual/en/function.stream-encoding.php
 
         $this->setOptions($options);
     }
@@ -120,7 +131,7 @@ class Phergie_Connection
             );
         }
     }
+
     /**
      * Returns a hostmask that uniquely identifies the connection.
      *
@@ -136,7 +147,7 @@ class Phergie_Connection
             );
         }
 
-        return $this->hostmask; 
+        return $this->hostmask;
     }
 
     /**
@@ -144,7 +155,7 @@ class Phergie_Connection
      *
      * @param string $host Hostname
      *
-     * @return Phergie_Connection Provides a fluent interface 
+     * @return Phergie_Connection Provides a fluent interface
      */
     public function setHost($host)
     {
@@ -154,9 +165,9 @@ class Phergie_Connection
 
         return $this;
     }
-   
+
     /**
-     * Returns the host to which the client will connect if it is set or 
+     * Returns the host to which the client will connect if it is set or
      * emits an error if it is not set.
      *
      * @return string
@@ -173,7 +184,7 @@ class Phergie_Connection
      *
      * @param int $port Port
      *
-     * @return Phergie_Connection Provides a fluent interface 
+     * @return Phergie_Connection Provides a fluent interface
      */
     public function setPort($port)
     {
@@ -199,9 +210,9 @@ class Phergie_Connection
     }
 
     /**
-     * Sets the transport for the connection to use. 
+     * Sets the transport for the connection to use.
      *
-     * @param string $transport Transport (ex: tcp, ssl, etc.) 
+     * @param string $transport Transport (ex: tcp, ssl, etc.)
      *
      * @return Phergie_Connection Provides a fluent interface
      */
@@ -220,21 +231,52 @@ class Phergie_Connection
     }
 
     /**
-     * Returns the transport in use by the connection. 
+     * Returns the transport in use by the connection.
      *
-     * @return string Transport (ex: tcp, ssl, etc.) 
+     * @return string Transport (ex: tcp, ssl, etc.)
      */
     public function getTransport()
     {
         return $this->transport;
     }
 
+    /**
+     * Sets the encoding for the connection to use.
+     *
+     * @param string $encoding Encoding to use (ex: ASCII, ISO-8859-1, UTF8, etc.)
+     *
+     * @return Phergie_Connection Provides a fluent interface
+     */
+    public function setEncoding($encoding)
+    {
+        $this->encoding = (string) $encoding;
+
+        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
+            );
+        }
+
+        return $this;
+    }
+
+    /**
+     * Returns the encoding in use by the connection.
+     *
+     * @return string Encoding (ex: ASCII, ISO-8859-1, UTF8, etc.)
+     */
+    public function getEncoding()
+    {
+        return $this->encoding;
+    }
+
     /**
      * Sets the nick that the client will use.
      *
      * @param string $nick Nickname
      *
-     * @return Phergie_Connection Provides a fluent interface 
+     * @return Phergie_Connection Provides a fluent interface
      */
     public function setNick($nick)
     {
@@ -262,7 +304,7 @@ class Phergie_Connection
      *
      * @param string $username Username
      *
-     * @return Phergie_Connection Provides a fluent interface 
+     * @return Phergie_Connection Provides a fluent interface
      */
     public function setUsername($username)
     {
@@ -290,7 +332,7 @@ class Phergie_Connection
      *
      * @param string $realname Real name
      *
-     * @return Phergie_Connection Provides a fluent interface 
+     * @return Phergie_Connection Provides a fluent interface
      */
     public function setRealname($realname)
     {
@@ -318,7 +360,7 @@ class Phergie_Connection
      *
      * @param string $password Password
      *
-     * @return Phergie_Connection Provides a fluent interface 
+     * @return Phergie_Connection Provides a fluent interface
      */
     public function setPassword($password)
     {
@@ -342,10 +384,10 @@ class Phergie_Connection
     /**
      * Sets multiple connection settings using an array.
      *
-     * @param array $options Associative array of setting names mapped to 
+     * @param array $options Associative array of setting names mapped to
      *        corresponding values
      *
-     * @return Phergie_Connection Provides a fluent interface 
+     * @return Phergie_Connection Provides a fluent interface
      */
     public function setOptions(array $options)
     {
diff --git a/plugins/Irc/extlib/phergie/Phergie/Db/Exception.php b/plugins/Irc/extlib/phergie/Phergie/Db/Exception.php
new file mode 100644 (file)
index 0000000..7742110
--- /dev/null
@@ -0,0 +1,39 @@
+<?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
+ */
+
+/**
+ * Exceptions related to handling databases for 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_Db_Exception extends Phergie_Exception
+{
+    /**
+     * Error indicating that a directory needed to support database
+     * functionality was unable to be created.
+     */
+    const ERR_UNABLE_TO_CREATE_DIRECTORY = 1;
+}
diff --git a/plugins/Irc/extlib/phergie/Phergie/Db/Manager.php b/plugins/Irc/extlib/phergie/Phergie/Db/Manager.php
new file mode 100755 (executable)
index 0000000..2a8215e
--- /dev/null
@@ -0,0 +1,49 @@
+<?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_Command
+ */
+
+/**
+ * Database management class. Provides a base API for managing databases
+ * within
+ *
+ * @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_Db_Manager
+ */
+abstract class Phergie_Db_Manager
+{
+    /**
+     * Returns a connection to the database.
+     *
+     * @return object
+     */
+    public abstract function getDb();
+
+    /**
+     * Checks if a table/collection exists within the database.
+     *
+     * @param string $table Table/collection name to check for
+     *
+     * @return boolean
+     */
+    public abstract function hasTable($table);
+}
diff --git a/plugins/Irc/extlib/phergie/Phergie/Db/Sqlite.php b/plugins/Irc/extlib/phergie/Phergie/Db/Sqlite.php
new file mode 100644 (file)
index 0000000..14ee520
--- /dev/null
@@ -0,0 +1,117 @@
+<?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
+ */
+
+/**
+ * Provides basic management for SQLite databases
+ *
+ * @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_Db_Sqlite extends Phergie_Db_Manager
+{
+    /**
+     * Database connection
+     *
+     * @var PDO
+     */
+    protected $db;
+
+    /**
+     * Database file path
+     *
+     * @var string
+     */
+    protected $dbFile;
+
+    /**
+     * Allows setting of the database file path when creating the class.
+     *
+     * @param string $dbFile database file path (optional)
+     *
+     * @return void
+     */
+    public function __construct($dbFile = null)
+    {
+        if ($dbFile != null) {
+            $this->setDbFile($dbFile);
+        }
+    }
+
+    /**
+     * Sets the database file path.
+     *
+     * @param string $dbFile SQLite database file path
+     *
+     * @return null
+     */
+    public function setDbFile($dbFile)
+    {
+        if (is_string($dbFile) && !empty($dbFile)) {
+            $this->dbFile = $dbFile;
+        }
+    }
+
+    /**
+     * Returns a configured database connection.
+     *
+     * @return PDO
+     */
+    public function getDb()
+    {
+        if (!empty($this->db)) {
+            return $this->db;
+        }
+
+        $dir = dirname($this->dbFile);
+        if (!is_dir($dir) && !mkdir($dir, 0755, true)) {
+            throw new Phergie_Db_Exception(
+                'Unable to create directory',
+                Phergie_Db_Exception::ERR_UNABLE_TO_CREATE_DIRECTORY
+            );
+        }
+
+        $this->db = new PDO('sqlite:' . $this->dbFile);
+
+        return $this->db;
+    }
+
+
+    /**
+     * Returns whether a given table exists in the database.
+     *
+     * @param string $table Name of the table to check for
+     *
+     * @return boolean TRUE if the table exists, FALSE otherwise
+     */
+    public function hasTable($table)
+    {
+        $db = $this->getDb();
+
+        return (bool) $db->query(
+            'SELECT COUNT(*) FROM sqlite_master WHERE name = '
+            . $db->quote($table)
+        )->fetchColumn();
+    }
+}
index c405522292e49cbf2c20c657077592a44e2c57a9..aa2b838f7e09cd930927b948c7a56739c673b238 100755 (executable)
@@ -46,4 +46,9 @@ class Phergie_Driver_Exception extends Phergie_Exception
      * Error indicating that an attempt to initiate a connection failed
      */
     const ERR_CONNECTION_ATTEMPT_FAILED = 3;
+
+    /**
+     * Error indicating that an attempt to send data via a connection failed
+     */
+    const ERR_CONNECTION_WRITE_FAILED = 4;
 }
index 8fe53aaa2f97b76c89b2204c989dcdba5683907e..bb0c611aa38e032df3eb1ad10ac3279a3e3cc49a 100755 (executable)
@@ -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)
  */
 
 /**
- * Driver that uses the sockets wrapper of the streams extension for 
- * communicating with the server and handles formatting and parsing of 
+ * Driver that uses the sockets wrapper of the streams extension for
+ * communicating with the server and handles formatting and parsing of
  * events using PHP.
  *
- * @category Phergie 
+ * @category Phergie
  * @package  Phergie
  * @author   Phergie Development Team <team@phergie.org>
  * @license  http://phergie.org/license New BSD License
@@ -47,26 +47,29 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
     protected $socket;
 
     /**
-     * Amount of time in seconds to wait to receive an event each time the 
+     * Amount of time in seconds to wait to receive an event each time the
      * socket is polled
      *
-     * @var float 
+     * @var float
      */
     protected $timeout = 0.1;
 
     /**
-     * Handles construction of command strings and their transmission to the 
+     * Handles construction of command strings and their transmission to the
      * server.
      *
      * @param string       $command Command to send
-     * @param string|array $args    Optional string or array of sequential 
+     * @param string|array $args    Optional string or array of sequential
      *        arguments
      *
-     * @return string Command string that was sent 
+     * @return string Command string that was sent
      * @throws Phergie_Driver_Exception
      */
     protected function send($command, $args = '')
     {
+        $connection = $this->getConnection();
+        $encoding = $connection->getEncoding();
+
         // Require an open socket connection to continue
         if (empty($this->socket)) {
             throw new Phergie_Driver_Exception(
@@ -86,20 +89,40 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
                 $end = count($args) - 1;
                 $args[$end] = ':' . $args[$end];
                 $args = implode(' ', $args);
+            } else {
+                $args = ':' . $args;
             }
 
             $buffer .= ' ' . $args;
         }
 
         // Transmit the command over the socket connection
-        fwrite($this->socket, $buffer . "\r\n");
+        $attempts = $written = 0;
+        $temp = $buffer . "\r\n";
+        $is_multibyte = !substr($encoding, 0, 8) === 'ISO-8859' && $encoding !== 'ASCII' && $encoding !== 'CP1252';
+        $length = ($is_multibyte) ? mb_strlen($buffer, '8bit') : strlen($buffer);
+        while (true) {
+            $written += (int) fwrite($this->socket, $temp);
+            if ($written < $length) {
+                $temp = substr($temp, $written);
+                $attempts++;
+                if ($attempts == 3) {
+                    throw new Phergie_Driver_Exception(
+                        'Unable to write to socket',
+                        Phergie_Driver_Exception::ERR_CONNECTION_WRITE_FAILED
+                    );
+                }
+            } else {
+                break;
+            }
+        }
 
         // Return the command string that was transmitted
         return $buffer;
     }
 
     /**
-     * Overrides the parent class to set the currently active socket handler 
+     * Overrides the parent class to set the currently active socket handler
      * when the active connection is changed.
      *
      * @param Phergie_Connection $connection Active connection
@@ -120,11 +143,11 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
 
     /**
      * Returns a list of hostmasks corresponding to sockets with data to read.
-     * 
+     *
      * @param int $sec  Length of time to wait for new data (seconds)
      * @param int $usec Length of time to wait for new data (microseconds)
      *
-     * @return array List of hostmasks or an empty array if none were found 
+     * @return array List of hostmasks or an empty array if none were found
      *         to have data to read
      */
     public function getActiveReadSockets($sec = 0, $usec = 200000)
@@ -147,7 +170,7 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
     }
 
     /**
-     * Sets the amount of time to wait for a new event each time the socket 
+     * Sets the amount of time to wait for a new event each time the socket
      * is polled.
      *
      * @param float $timeout Amount of time in seconds
@@ -164,7 +187,7 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
     }
 
     /**
-     * Returns the amount of time to wait for a new event each time the 
+     * Returns the amount of time to wait for a new event each time the
      * socket is polled.
      *
      * @return float Amount of time in seconds
@@ -175,7 +198,7 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
     }
 
     /**
-     * Supporting method to parse event argument strings where the last 
+     * Supporting method to parse event argument strings where the last
      * argument may contain a colon.
      *
      * @param string $args  Argument string to parse
@@ -191,7 +214,7 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
     /**
      * Listens for an event on the current connection.
      *
-     * @return Phergie_Event_Interface|null Event instance if an event was 
+     * @return Phergie_Event_Interface|null Event instance if an event was
      *         received, NULL otherwise
      */
     public function getEvent()
@@ -217,7 +240,7 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
             // If the event could be from the server or a user...
 
             // Parse the server hostname or user hostmask, command, and arguments
-            list($prefix, $cmd, $args) 
+            list($prefix, $cmd, $args)
                 = array_pad(explode(' ', ltrim($buffer, ':'), 3), 3, null);
             if (strpos($prefix, '@') !== false) {
                 $hostmask = Phergie_Hostmask::fromString($prefix);
@@ -279,17 +302,17 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
         case 'oper':
         case 'topic':
         case 'mode':
-            $args = $this->parseArguments($args); 
+            $args = $this->parseArguments($args);
             break;
 
         case 'part':
         case 'kill':
         case 'invite':
-            $args = $this->parseArguments($args, 2); 
+            $args = $this->parseArguments($args, 2);
             break;
 
         case 'kick':
-            $args = $this->parseArguments($args, 3); 
+            $args = $this->parseArguments($args, 3);
             break;
 
         // Remove the target from responses
@@ -360,14 +383,14 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
         $this->send(
             'USER',
             array(
-                $username, 
-                $hostname, 
-                $hostname, 
+                $username,
+                $hostname,
+                $hostname,
                 $realname
             )
         );
 
-        $this->send('NICK', $nick); 
+        $this->send('NICK', $nick);
 
         // Add the socket handler to the internal array for socket handlers
         $this->sockets[(string) $connection->getHostmask()] = $this->socket;
@@ -395,7 +418,7 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
     /**
      * Joins a channel.
      *
-     * @param string $channels Comma-delimited list of channels to join 
+     * @param string $channels Comma-delimited list of channels to join
      * @param string $keys     Optional comma-delimited list of channel keys
      *
      * @return void
@@ -414,7 +437,7 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
     /**
      * Leaves a channel.
      *
-     * @param string $channels Comma-delimited list of channels to leave 
+     * @param string $channels Comma-delimited list of channels to leave
      *
      * @return void
      */
@@ -600,9 +623,9 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
     /**
      * Sends a CTCP response to a user.
      *
-     * @param string       $nick    User nick 
+     * @param string       $nick    User nick
      * @param string       $command Command to send
-     * @param string|array $args    String or array of sequential arguments 
+     * @param string|array $args    String or array of sequential arguments
      *        (optional)
      *
      * @return void
@@ -615,7 +638,7 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
 
         $buffer = rtrim(strtoupper($command) . ' ' . $args);
 
-        $this->doNotice($nick, chr(1) . $buffer . chr(1)); 
+        $this->doNotice($nick, chr(1) . $buffer . chr(1));
     }
 
     /**
@@ -652,7 +675,7 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
      * Sends a CTCP TIME request to a user.
      *
      * @param string $nick User nick
-     * @param string $time Time string to send for a response 
+     * @param string $time Time string to send for a response
      *
      * @return void
      */
index 7df1fca35a0e1b3cf9caa2f84d40d328417aee8b..e308df8a5633b052b7b45fe6b2b6c14476160c93 100644 (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)
@@ -20,9 +20,9 @@
  */
 
 /**
- * Handles events initiated by plugins. 
+ * Handles events initiated by plugins.
  *
- * @category Phergie 
+ * @category Phergie
  * @package  Phergie
  * @author   Phergie Development Team <team@phergie.org>
  * @license  http://phergie.org/license New BSD License
@@ -51,13 +51,13 @@ class Phergie_Event_Handler implements IteratorAggregate, Countable
      * Adds an event to the queue.
      *
      * @param Phergie_Plugin_Abstract $plugin Plugin originating the event
-     * @param string                  $type   Event type, corresponding to a 
+     * @param string                  $type   Event type, corresponding to a
      *        Phergie_Event_Command::TYPE_* constant
      * @param array                   $args   Optional event arguments
      *
      * @return Phergie_Event_Handler Provides a fluent interface
      */
-    public function addEvent(Phergie_Plugin_Abstract $plugin, $type, 
+    public function addEvent(Phergie_Plugin_Abstract $plugin, $type,
         array $args = array()
     ) {
         if (!defined('Phergie_Event_Command::TYPE_' . strtoupper($type))) {
@@ -102,7 +102,7 @@ class Phergie_Event_Handler implements IteratorAggregate, Countable
     /**
      * Replaces the current event queue with a given queue of events.
      *
-     * @param array $events Ordered list of objects of the class 
+     * @param array $events Ordered list of objects of the class
      *        Phergie_Event_Command
      *
      * @return Phergie_Event_Handler Provides a fluent interface
@@ -116,10 +116,10 @@ class Phergie_Event_Handler implements IteratorAggregate, Countable
     /**
      * Returns whether an event of the given type exists in the queue.
      *
-     * @param string $type Event type from Phergie_Event_Request::TYPE_* 
+     * @param string $type Event type from Phergie_Event_Request::TYPE_*
      *        constants
      *
-     * @return bool TRUE if an event of the specified type exists in the 
+     * @return bool TRUE if an event of the specified type exists in the
      *         queue, FALSE otherwise
      */
     public function hasEventOfType($type)
@@ -135,10 +135,10 @@ class Phergie_Event_Handler implements IteratorAggregate, Countable
     /**
      * Returns a list of events of a specified type.
      *
-     * @param string $type Event type from Phergie_Event_Request::TYPE_* 
+     * @param string $type Event type from Phergie_Event_Request::TYPE_*
      *        constants
      *
-     * @return array Array containing event instances of the specified type 
+     * @return array Array containing event instances of the specified type
      *         or an empty array if no such events were found
      */
     public function getEventsOfType($type)
@@ -152,6 +152,22 @@ class Phergie_Event_Handler implements IteratorAggregate, Countable
         return $events;
     }
 
+    /**
+     * Removes a single event from the event queue.
+     *
+     * @param Phergie_Event_Command $event Event to remove
+     *
+     * @return Phergie_Event_Handler Provides a fluent interface
+     */
+    public function removeEvent(Phergie_Event_Command $event)
+    {
+        $key = array_search($event, $this->events);
+        if ($key !== false) {
+            unset($this->events[$key]);
+        }
+        return $this;
+    }
+
     /**
      * Returns an iterator for the current event queue.
      *
index a559d9dbe5c4f719de0bb1cf41cbf3f693e4380b..647b5acb87bad686eb4b0258b0f282929aeaacaf 100755 (executable)
@@ -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)
 /**
  * Autonomous event originating from a user or the server.
  *
- * @category Phergie 
+ * @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
  * @link     http://www.irchelp.org/irchelp/rfc/chapter4.html
  */
-class Phergie_Event_Request 
-    extends Phergie_Event_Abstract 
+class Phergie_Event_Request
+    extends Phergie_Event_Abstract
     implements ArrayAccess
 {
     /**
@@ -240,6 +240,24 @@ class Phergie_Event_Request
         return $this;
     }
 
+    /**
+     * Sets the value of a single argument for the request.
+     *
+     * @param mixed  $argument Integer position (starting from 0) or the
+     *        equivalent string name of the argument from self::$map
+     * @param string $value    Value to assign to the argument
+     *
+     * @return Phergie_Event_Request Provides a fluent interface
+     */
+    public function setArgument($argument, $value)
+    {
+        $argument = $this->resolveArgument($argument);
+        if ($argument !== null) {
+            $this->arguments[$argument] = (string) $value;
+        }
+        return $this;
+    }
+
     /**
      * Returns the arguments for the request.
      *
@@ -256,13 +274,13 @@ class Phergie_Event_Request
      * @param mixed $argument Integer position (starting from 0) or the
      *        equivalent string name of the argument from self::$map
      *
-     * @return int|null Integer position of the argument or NULL if no 
+     * @return int|null Integer position of the argument or NULL if no
      *         corresponding argument was found
      */
     protected function resolveArgument($argument)
     {
         if (isset($this->arguments[$argument])) {
-            return $argument; 
+            return $argument;
         } else {
             $argument = strtolower($argument);
             if (isset(self::$map[$this->type][$argument])
@@ -285,7 +303,7 @@ class Phergie_Event_Request
     public function getArgument($argument)
     {
         $argument = $this->resolveArgument($argument);
-        if ($argument !== null) { 
+        if ($argument !== null) {
             return $this->arguments[$argument];
         }
         return null;
@@ -325,9 +343,9 @@ class Phergie_Event_Request
     }
 
     /**
-     * Returns the channel name if the event occurred in a channel or the 
-     * user nick if the event was a private message directed at the bot by a 
-     * user. 
+     * Returns the channel name if the event occurred in a channel or the
+     * user nick if the event was a private message directed at the bot by a
+     * user.
      *
      * @return string
      */
@@ -395,7 +413,7 @@ class Phergie_Event_Request
      *
      * @param string|int $offset Argument name or position beginning from 0
      *
-     * @return bool TRUE if the argument has a value, FALSE otherwise 
+     * @return bool TRUE if the argument has a value, FALSE otherwise
      * @see ArrayAccess::offsetExists()
      */
     public function offsetExists($offset)
@@ -428,7 +446,7 @@ class Phergie_Event_Request
     public function offsetSet($offset, $value)
     {
         $offset = $this->resolveArgument($offset);
-        if ($offset !== null) { 
+        if ($offset !== null) {
             $this->arguments[$offset] = $value;
         }
     }
index 294c04ce5213a28184c04580996ad4f5acf6a59d..d7e0d351af4bc79b61faf47628625a0011f56f44 100755 (executable)
@@ -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 @@
  * Base class for plugins to provide event handler stubs and commonly needed
  * functionality.
  *
- * @category Phergie 
+ * @category Phergie
  * @package  Phergie
  * @author   Phergie Development Team <team@phergie.org>
  * @license  http://phergie.org/license New BSD License
@@ -66,6 +66,13 @@ abstract class Phergie_Plugin_Abstract
      */
     protected $event;
 
+    /**
+     * Plugin short name
+     *
+     * @var string
+     */
+    protected $name;
+
     /**
      * Returns the short name for the plugin based on its class name.
      *
@@ -73,14 +80,30 @@ abstract class Phergie_Plugin_Abstract
      */
     public function getName()
     {
-        return substr(strrchr(get_class($this), '_'), 1);
+        if (empty($this->name)) {
+            $this->name = substr(strrchr(get_class($this), '_'), 1);
+        }
+        return $this->name;
+    }
+
+    /**
+     * Sets the short name for the plugin.
+     *
+     * @param string $name Plugin short name
+     *
+     * @return Phergie_Plugin_Abstract Provides a fluent interface
+     */
+    public function setName($name)
+    {
+        $this->name = (string) $name;
+        return $this;
     }
 
     /**
-     * Indicates that the plugin failed to load due to an unsatisfied 
+     * Indicates that the plugin failed to load due to an unsatisfied
      * runtime requirement, such as a missing dependency.
      *
-     * @param string $message Error message to provide more information 
+     * @param string $message Error message to provide more information
      *        about the reason for the failure
      *
      * @return Phergie_Plugin_Abstract Provides a fluent interface
@@ -108,17 +131,17 @@ abstract class Phergie_Plugin_Abstract
     }
 
     /**
-     * Returns the current configuration handler or the value of a single 
+     * Returns the current configuration handler or the value of a single
      * setting from it.
      *
-     * @param string $name    Optional name of a setting for which the value 
+     * @param string $name    Optional name of a setting for which the value
      *        should be returned instead of the entire configuration handler
-     * @param mixed  $default Optional default value to return if no value 
+     * @param mixed  $default Optional default value to return if no value
      *        is set for the setting indicated by $name
      *
-     * @return Phergie_Config|mixed Configuration handler or value of the 
+     * @return Phergie_Config|mixed Configuration handler or value of the
      *         setting specified by $name
-     * @throws Phergie_Plugin_Exception No configuration handler has been set 
+     * @throws Phergie_Plugin_Exception No configuration handler has been set
      */
     public function getConfig($name = null, $default = null)
     {
@@ -154,7 +177,7 @@ abstract class Phergie_Plugin_Abstract
      * Returns the current plugin handler.
      *
      * @return Phergie_Plugin_Handler
-     * @throws Phergie_Plugin_Exception No plugin handler has been set 
+     * @throws Phergie_Plugin_Exception No plugin handler has been set
      */
     public function getPluginHandler()
     {
@@ -184,7 +207,7 @@ abstract class Phergie_Plugin_Abstract
      * Returns the current event handler.
      *
      * @return Phergie_Event_Handler
-     * @throws Phergie_Plugin_Exception No event handler has been set 
+     * @throws Phergie_Plugin_Exception No event handler has been set
      */
     public function getEventHandler()
     {
@@ -214,7 +237,7 @@ abstract class Phergie_Plugin_Abstract
      * Returns the current event connection.
      *
      * @return Phergie_Connection
-     * @throws Phergie_Plugin_Exception No connection has been set 
+     * @throws Phergie_Plugin_Exception No connection has been set
      */
     public function getConnection()
     {
@@ -281,8 +304,8 @@ abstract class Phergie_Plugin_Abstract
     }
 
     /**
-     * Handler for when the plugin is initially loaded - useful for checking 
-     * runtime dependencies or performing any setup necessary for the plugin 
+     * Handler for when the plugin is initially loaded - useful for checking
+     * runtime dependencies or performing any setup necessary for the plugin
      * to function properly such as initializing a database.
      *
      * @return void
@@ -301,8 +324,8 @@ abstract class Phergie_Plugin_Abstract
     }
 
     /**
-     * Handler for each tick, a single iteration of the continuous loop 
-     * executed by the bot to receive, handle, and send events - useful for  
+     * Handler for each tick, a single iteration of the continuous loop
+     * executed by the bot to receive, handle, and send events - useful for
      * repeated execution of tasks on a time interval.
      *
      * @return void
@@ -312,10 +335,10 @@ abstract class Phergie_Plugin_Abstract
     }
 
     /**
-     * Handler for when any event is received but has not yet been dispatched 
+     * Handler for when any event is received but has not yet been dispatched
      * to the plugin handler method specific to its event type.
      *
-     * @return bool|null|void FALSE to short-circuit further event 
+     * @return bool|null|void FALSE to short-circuit further event
      *         processing, TRUE or NULL otherwise
      */
     public function preEvent()
@@ -323,8 +346,8 @@ abstract class Phergie_Plugin_Abstract
     }
 
     /**
-     * Handler for after plugin processing of an event has concluded but 
-     * before any events triggered in response by plugins are sent to the 
+     * Handler for after plugin processing of an event has concluded but
+     * before any events triggered in response by plugins are sent to the
      * server - useful for modifying outgoing events before they are sent.
      *
      * @return void
@@ -334,8 +357,8 @@ abstract class Phergie_Plugin_Abstract
     }
 
     /**
-     * Handler for after any events triggered by plugins in response to a 
-     * received event are sent to the server. 
+     * Handler for after any events triggered by plugins in response to a
+     * received event are sent to the server.
      *
      * @return void
      */
@@ -454,12 +477,12 @@ abstract class Phergie_Plugin_Abstract
     }
 
     /**
-     * Handler for when the bot receives a ping event from a server, at 
-     * which point it is expected to respond with a pong request within 
+     * Handler for when the bot receives a ping event from a server, at
+     * which point it is expected to respond with a pong request within
      * a short period else the server may terminate its connection.
      *
      * @return void
-     * @link http://irchelp.org/irchelp/rfc/chapter4.html#c4_6_2 
+     * @link http://irchelp.org/irchelp/rfc/chapter4.html#c4_6_2
      */
     public function onPing()
     {
@@ -496,7 +519,7 @@ abstract class Phergie_Plugin_Abstract
     }
 
     /**
-     * Handler for when the bot receives a CTCP request of an unknown type. 
+     * Handler for when the bot receives a CTCP request of an unknown type.
      *
      * @return void
      * @link http://www.invlogic.com/irc/ctcp.html
@@ -506,7 +529,7 @@ abstract class Phergie_Plugin_Abstract
     }
 
     /**
-     * Handler for when a reply is received for a CTCP PING request sent by 
+     * Handler for when a reply is received for a CTCP PING request sent by
      * the bot.
      *
      * @return void
@@ -517,7 +540,7 @@ abstract class Phergie_Plugin_Abstract
     }
 
     /**
-     * Handler for when a reply is received for a CTCP TIME request sent by 
+     * Handler for when a reply is received for a CTCP TIME request sent by
      * the bot.
      *
      * @return void
@@ -528,7 +551,7 @@ abstract class Phergie_Plugin_Abstract
     }
 
     /**
-     * Handler for when a reply is received for a CTCP VERSION request sent 
+     * Handler for when a reply is received for a CTCP VERSION request sent
      * by the bot.
      *
      * @return void
@@ -539,7 +562,7 @@ abstract class Phergie_Plugin_Abstract
     }
 
     /**
-     * Handler for when a reply received for a CTCP request of an unknown 
+     * Handler for when a reply received for a CTCP request of an unknown
      * type.
      *
      * @return void
@@ -560,7 +583,7 @@ abstract class Phergie_Plugin_Abstract
     }
 
     /**
-     * Handler for when the bot receives an invitation to join a channel. 
+     * Handler for when the bot receives an invitation to join a channel.
      *
      * @return void
      * @link http://irchelp.org/irchelp/rfc/chapter4.html#c4_2_7
@@ -570,7 +593,7 @@ abstract class Phergie_Plugin_Abstract
     }
 
     /**
-     * Handler for when a server response is received to a command issued by 
+     * Handler for when a server response is received to a command issued by
      * the bot.
      *
      * @return void
diff --git a/plugins/Irc/extlib/phergie/Phergie/Plugin/Censor.php b/plugins/Irc/extlib/phergie/Phergie/Plugin/Censor.php
new file mode 100755 (executable)
index 0000000..3206bdd
--- /dev/null
@@ -0,0 +1,108 @@
+<?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_Censor
+ * @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_Censor
+ */
+
+/**
+ * Facilitates censoring of event content or discardment of events
+ * containing potentially offensive phrases depending on the value of the
+ * configuration setting censor.mode ('off', 'censor', 'discard'). Also
+ * provides access to a web service for detecting censored words so that
+ * other plugins may optionally integrate and adjust behavior accordingly to
+ * prevent discardment of events.
+ *
+ * @category Phergie
+ * @package  Phergie_Plugin_Censor
+ * @author   Phergie Development Team <team@phergie.org>
+ * @license  http://phergie.org/license New BSD License
+ * @link     http://pear.phergie.org/package/Phergie_Plugin_Censor
+ * @uses     extension soap
+ */
+class Phergie_Plugin_Censor extends Phergie_Plugin_Abstract
+{
+    /**
+     * SOAP client to interact with the CDYNE Profanity Filter API
+     *
+     * @var SoapClient
+     */
+    protected $soap;
+
+    /**
+     * Checks for dependencies.
+     *
+     * @return void
+     */
+    public function onLoad()
+    {
+        if (!extension_loaded('soap')) {
+            $this->fail('The PHP soap extension is required');
+        }
+
+        if (!in_array($this->config['censor.mode'], array('censor', 'discard'))) {
+            $this->plugins->removePlugin($this);
+        }
+    }
+
+    /**
+     * Returns a "clean" version of a given string.
+     *
+     * @param string $string String to clean
+     *
+     * @return string Cleaned string
+     */
+    public function cleanString($string)
+    {
+        if (empty($this->soap)) {
+            $this->soap = new SoapClient('http://ws.cdyne.com/ProfanityWS/Profanity.asmx?wsdl');
+        }
+        $params = array('Text' => $string);
+        $response = $this->soap->SimpleProfanityFilter($params);
+        return $response->SimpleProfanityFilterResult->CleanText;
+    }
+
+    /**
+     * Processes events before they are dispatched and either censors their
+     * content or discards them if they contain potentially offensive
+     * content.
+     *
+     * @return void
+     */
+    public function preDispatch()
+    {
+        $events = $this->events->getEvents();
+
+        foreach ($events as $event) {
+            switch ($event->getType()) {
+                case Phergie_Event_Request::TYPE_PRIVMSG:
+                case Phergie_Event_Request::TYPE_ACTION:
+                case Phergie_Event_Request::TYPE_NOTICE:
+                    $text = $event->getArgument(1);
+                    $clean = $this->cleanString($text);
+                    if ($text != $clean) {
+                        if ($this->config['censor.mode'] == 'censor') {
+                            $event->setArgument(1, $clean);
+                        } else {
+                            $this->events->removeEvent($event);
+                        }
+                    }
+                    break;
+            }
+        }
+    }
+}
diff --git a/plugins/Irc/extlib/phergie/Phergie/Plugin/Cron.php b/plugins/Irc/extlib/phergie/Phergie/Plugin/Cron.php
new file mode 100644 (file)
index 0000000..1c27f97
--- /dev/null
@@ -0,0 +1,147 @@
+<?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_Cron
+ * @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_Cron
+ */
+
+/**
+ * Allows callbacks to be registered for asynchronous execution.
+ *
+ * @category Phergie
+ * @package  Phergie_Plugin_Cron
+ * @author   Phergie Development Team <team@phergie.org>
+ * @license  http://phergie.org/license New BSD License
+ * @link     http://pear.phergie.org/package/Phergie_Plugin_Cron
+ */
+class Phergie_Plugin_Cron extends Phergie_Plugin_Abstract
+{
+    /**
+     * Array of all registered callbacks with delays and arguments
+     *
+     * @var array
+     */
+    protected $callbacks;
+
+    /**
+     * Returns a human-readable representation of a callback for debugging
+     * purposes.
+     *
+     * @param callback $callback Callback to analyze
+     *
+     * @return string|boolean String representation of the callback or FALSE
+     *         if the specified value is not a valid callback
+     */
+    protected function getCallbackString($callback)
+    {
+        if (!is_callable($callback)) {
+            return false;
+        }
+
+        if (is_array($callback)) {
+            $class = is_string($callback[0]) ?
+                $callback[0] : get_class($callback[0]);
+            $method = $class . '::' . $callback[1];
+            return $method;
+        }
+
+        return $callback;
+    }
+
+    /**
+     * Registers a callback for execution sometime after a given delay
+     * relative to now.
+     *
+     * @param callback $callback  Callback to be registered
+     * @param int      $delay     Delay in seconds from now when the callback
+     *        will be executed
+     * @param array    $arguments Arguments to pass to the callback when
+     *        it's executed
+     * @param bool     $repeat    TRUE to automatically re-register the
+     *        callback for the same delay after it's executed, FALSE
+     *        otherwise
+     *
+     * @return void
+     */
+    public function registerCallback($callback, $delay,
+        array $arguments = array(), $repeat = false)
+    {
+        $callbackString = $this->getCallbackString($callback);
+        if ($callbackString === false) {
+            echo 'DEBUG(Cron): Invalid callback specified - ',
+                var_export($callback, true), PHP_EOL;
+            return;
+        }
+
+        $registered = time();
+        $scheduled = $registered + $delay;
+
+        $this->callbacks[] = array(
+            'callback'   => $callback,
+            'delay'      => $delay,
+            'arguments'  => $arguments,
+            'registered' => $registered,
+            'scheduled'  => $scheduled,
+            'repeat'     => $repeat,
+        );
+
+        echo 'DEBUG(Cron): Callback ', $callbackString,
+            ' scheduled for ', date('H:i:s', $scheduled), PHP_EOL;
+    }
+
+    /**
+     * Handles callback execution.
+     *
+     * @return void
+     */
+    public function onTick()
+    {
+        $now = time();
+        foreach ($this->callbacks as $key => &$callback) {
+            $callbackString = $this->getCallbackString($callback);
+
+            $scheduled = $callback['scheduled'];
+            if ($time < $scheduled) {
+                continue;
+            }
+
+            if (empty($callback['arguments'])) {
+                call_user_func($callback['callback']);
+            } else {
+                call_user_func_array(
+                    $callback['callback'],
+                    $callback['arguments']
+                );
+            }
+
+            echo 'DEBUG(Cron): Callback ', $callbackString,
+                ' scheduled for ', date('H:i:s', $scheduled), ',',
+                ' executed at ', date('H:i:s', $now), PHP_EOL;
+
+            if ($callback['repeat']) {
+                $callback['scheduled'] = $time + $callback['delay'];
+                echo 'DEBUG(Cron): Callback ', $callbackString,
+                    ' scheduled for ', date('H:i:s', $callback['scheduled']),
+                    PHP_EOL;
+            } else {
+                echo 'DEBUG(Cron): Callback ', $callbackString,
+                    ' removed from callback list', PHP_EOL;
+                unset($this->callbacks[$key]);
+            }
+        }
+    }
+}
index e58734bef9b92bbef35bd61c3a83d1340a64c700..fd07d9d5ea5e180d5a5add7221f80252b655c7dd 100755 (executable)
@@ -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 @@
 /**
  * Exception related to plugin handling.
  *
- * @category Phergie 
+ * @category Phergie
  * @package  Phergie
  * @author   Phergie Development Team <team@phergie.org>
  * @license  http://phergie.org/license New BSD License
 class Phergie_Plugin_Exception extends Phergie_Exception
 {
     /**
-     * Error indicating that a path containing plugins was specified, but 
+     * Error indicating that a path containing plugins was specified, but
      * did not reference a readable directory
      */
     const ERR_DIRECTORY_NOT_READABLE = 1;
 
     /**
-     * Error indicating that an attempt was made to locate the class for a 
+     * Error indicating that an attempt was made to locate the class for a
      * specified plugin, but the class could not be found
      */
     const ERR_CLASS_NOT_FOUND = 2;
 
     /**
-     * Error indicating that an attempt was made to locate the class for a 
-     * specified plugin, but that the found class did not extend the base 
+     * Error indicating that an attempt was made to locate the class for a
+     * specified plugin, but that the found class did not extend the base
      * plugin class
      */
     const ERR_INCORRECT_BASE_CLASS = 3;
 
     /**
-     * Error indicating that an attempt was made to locate the class for a 
+     * Error indicating that an attempt was made to locate the class for a
      * specified plugin, but that the found class cannot be instantiated
      */
     const ERR_CLASS_NOT_INSTANTIABLE = 4;
 
     /**
-     * Error indicating that an attempt was made to access a plugin that had 
+     * Error indicating that an attempt was made to access a plugin that had
      * not been loaded and autoloading was not enabled to load it
      */
     const ERR_PLUGIN_NOT_LOADED = 5;
 
     /**
-     * Error indicating that an attempt was made to access the configuration 
+     * Error indicating that an attempt was made to access the configuration
      * handler before one had been set
      */
     const ERR_NO_CONFIG_HANDLER = 6;
 
     /**
-     * Error indicating that an attempt was made to access the plugin 
+     * Error indicating that an attempt was made to access the plugin
      * handler before one had been set
      */
     const ERR_NO_PLUGIN_HANDLER = 7;
 
     /**
-     * Error indicating that an attempt was made to access the event  
+     * Error indicating that an attempt was made to access the event
      * handler before one had been set
      */
     const ERR_NO_EVENT_HANDLER = 8;
 
     /**
-     * Error indicating that an attempt was made to access the connection  
+     * Error indicating that an attempt was made to access the connection
      * before one had been set
      */
     const ERR_NO_CONNECTION = 9;
 
     /**
-     * Error indicating that an attempt was made to access the current 
+     * Error indicating that an attempt was made to access the current
      * incoming event before one had been set
      */
     const ERR_NO_EVENT = 10;
 
     /**
-     * Error indicating that a dependency of the plugin was unavailable at  
+     * Error indicating that a dependency of the plugin was unavailable at
      * the time that an attempt was made to load it
      */
     const ERR_REQUIREMENT_UNSATISFIED = 11;
 
     /**
-     * Error indicating that a call was made to a nonexistent plugin method 
-     * and that its __call() implementation did not process that call as an 
-     * attempt to trigger an event - this is intended to aid in debugging of 
+     * Error indicating that a call was made to a nonexistent plugin method
+     * and that its __call() implementation did not process that call as an
+     * attempt to trigger an event - this is intended to aid in debugging of
      * such situations
      */
     const ERR_INVALID_CALL = 12;
 
     /**
-     * Error indicating that a fatal runtime issue was encountered within a 
+     * Error indicating that a fatal runtime issue was encountered within a
      * plugin
      */
     const ERR_FATAL_ERROR = 13;
index 413a93607551913944405abb768a727876a75e25..40c203a67238a214fb93aee67d199f26dceecbc5 100644 (file)
@@ -222,7 +222,11 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
      * @pluginCmd [location] Get the location from Google Maps to the location specified
      */
     public function onCommandGmap($location)
-    {
+    {  
+        $event = $this->getEvent();
+        $source = $event->getSource();
+        $nick = $event->getNick();
+       
         $location = utf8_encode($location);
         $url = 'http://maps.google.com/maps/geo';
         $params = array(
@@ -232,20 +236,17 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
             'sensor' => 'false',
             'oe' => 'utf8',
             'mrt' => 'all',
-            'key' => $this->_config['google.key']
+            'key' => $this->getConfig('google.key')
         );
         $response = $this->http->get($url, $params); 
-        $json = (array) $response->getContent();
-        $event = $this->getEvent();
-        $source = $event->getSource();
-        $nick = $event->getNick();
+        $json =  $response->getContent();
         if (!empty($json)) {
-            $qtd = count($json['Placemark']);
+            $qtd = count($json->Placemark);
             if ($qtd > 1) {
                 if ($qtd <= 3) {
-                    foreach ($json['Placemark'] as $places) {
-                        $xy = $places['Point']['coordinates'];
-                        $address = utf8_decode($places['address']);
+                    foreach ($json->Placemark as $places) {
+                        $xy = $places->Point->coordinates;
+                        $address = utf8_decode($places->address);
                         $url = 'http://maps.google.com/maps?sll=' . $xy[1] . ',' 
                             . $xy[0] . '&z=15';
                         $msg = $nick . ' -> ' . $address . ' - ' . $url;
@@ -259,8 +260,8 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
                     $this->doPrivmsg($source, $msg);
                 }
             } elseif ($qtd == 1) {
-                $xy = $json['Placemark'][0]['Point']['coordinates'];
-                $address = utf8_decode($json['Placemark'][0]['address']);
+                $xy = $json->Placemark[0]->Point->coordinates;
+                $address = utf8_decode($json->Placemark[0]->address);
                 $url = 'http://maps.google.com/maps?sll=' . $xy[1] . ',' . $xy[0] 
                     . '&z=15';
                 $msg = $nick . ' -> ' . $address . ' - ' . $url;
@@ -322,54 +323,44 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
     /**
      * Performs a Google search to convert a value from one unit to another.
      *
-     * @param string $unit  Source metric 
-     * @param string $to    Value to be converted
-     * @param string $unit2 Destination metric 
+     * @param string $query Query of the form "[quantity] [unit] to [unit2]"
      *
      * @return void
      *
-     * @pluginCmd [unit] [to] [unit2] Convert a value from one metric to another
+     * @pluginCmd [quantity] [unit] to [unit2] Convert a value from one 
+     *            metric to another
      */
-    public function onCommandConvert($unit, $to, $unit2)
+    public function onCommandConvert($query)
     {
-        $url = 'http://www.google.com/search?q=' 
-            . urlencode($unit . ' ' . $to . ' ' . $unit2);
+        $url = 'http://www.google.com/search?q=' . urlencode($query);
         $response = $this->http->get($url);
         $contents = $response->getContent();
         $event = $this->getEvent();
         $source = $event->getSource();
         $nick = $event->getNick();
 
-        if (empty($contents)) {
-            $this->doPrivmsg(
-                $target,
-                $nick . ', sorry, I can\'t give you an answer right now.'
-            );
+        if ($response->isError()) {
+            $code = $response->getCode();
+            $message = $response->getMessage();
+            $this->doNotice($nick, 'ERROR: ' . $code . ' ' . $message);
             return;
         }
 
-        $doc = new DomDocument;
-        $doc->loadHTML($contents);
-        foreach ($doc->getElementsByTagName('h2') as $element) {
-            if ($element->getAttribute('class') == 'r') {
-                $children = $element->childNodes;
-                $text = str_replace(
-                    array(chr(195), chr(151), chr(160)),
-                    array('x', '', ' '),
-                    $children->item(0)->nodeValue
-                );
-                if ($children->length >= 3) {
-                    $text
-                        .= '^' . $children->item(1)->nodeValue 
-                        . $children->item(2)->nodeValue;
-                }
-            }
+        $start = strpos($contents, '<h3 class=r>');
+        if ($start !== false) {
+            $end = strpos($contents, '</b>', $start);
+            $text = strip_tags(substr($contents, $start, $end - $start));
+            $text = str_replace(
+                array(chr(195), chr(151), chr(160)),
+                array('x', '', ' '),
+                $text
+            );
         }
 
         if (isset($text)) {
             $this->doPrivmsg($source, $nick . ': ' . $text);
         } else {
-            $this->doPrivmsg($target, $nick . ', sorry I can\'t do that.');
+            $this->doNotice($nick, 'Sorry I couldn\'t find an answer.');
         }
     }
 }
index ee03ae9581e7e13015ff8079b7e43d1ec167d7d6..b2ef089b44cee0071f08126996dcda039216a138 100755 (executable)
@@ -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)
 /**
  * Handles on-demand loading of, iteration over, and access to plugins.
  *
- * @category Phergie 
+ * @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_Handler implements IteratorAggregate
+class Phergie_Plugin_Handler implements IteratorAggregate, Countable
 {
     /**
      * Current list of plugin instances
@@ -45,7 +45,7 @@ class Phergie_Plugin_Handler implements IteratorAggregate
     protected $paths;
 
     /**
-     * Flag indicating whether plugin classes should be instantiated on 
+     * Flag indicating whether plugin classes should be instantiated on
      * demand if they are requested but no instance currently exists
      *
      * @var bool
@@ -69,13 +69,13 @@ class Phergie_Plugin_Handler implements IteratorAggregate
     protected $events;
 
     /**
-     * Constructor to initialize class properties and add the path for core 
+     * Constructor to initialize class properties and add the path for core
      * plugins.
      *
      * @param Phergie_Config        $config configuration to pass to any
-     *                                      instantiated plugin
+     *        instantiated plugin
      * @param Phergie_Event_Handler $events event handler to pass to any
-     *                                      instantiated plugin
+     *        instantiated plugin
      *
      * @return void
      */
@@ -99,7 +99,7 @@ class Phergie_Plugin_Handler implements IteratorAggregate
      * the reverse order in which they are added.
      *
      * @param string $path   Filesystem directory path
-     * @param string $prefix Optional class name prefix corresponding to the 
+     * @param string $prefix Optional class name prefix corresponding to the
      *        path
      *
      * @return Phergie_Plugin_Handler Provides a fluent interface
@@ -123,12 +123,43 @@ class Phergie_Plugin_Handler implements IteratorAggregate
     }
 
     /**
-     * Adds a plugin instance to the handler. 
+     * Returns metadata corresponding to a specified plugin.
      *
-     * @param string|Phergie_Plugin_Abstract $plugin Short name of the 
+     * @param string $plugin Short name of the plugin class
+     * @throws Phergie_Plugin_Exception Class file can't be found
+     *
+     * @return array|boolean Associative array containing the path to the
+     *         class file and its containing directory as well as the full
+     *         class name
+     */
+    public function getPluginInfo($plugin)
+    {
+       foreach (array_reverse($this->paths) as $path) {
+            $file = $path['path'] . $plugin . '.php';
+            if (file_exists($file)) {
+                $path = array(
+                    'dir' => $path['path'],
+                    'file' => $file,
+                    'class' => $path['prefix'] . $plugin,
+                );
+                return $path;
+            }
+        }
+
+        // If the class can't be found, display an error
+        throw new Phergie_Plugin_Exception(
+            'Class file for plugin "' . $plugin . '" cannot be found',
+            Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND
+        );
+    }
+
+    /**
+     * Adds a plugin instance to the handler.
+     *
+     * @param string|Phergie_Plugin_Abstract $plugin Short name of the
      *        plugin class or a plugin object
-     * @param array                          $args   Optional array of 
-     *        arguments to pass to the plugin constructor if a short name is 
+     * @param array                          $args   Optional array of
+     *        arguments to pass to the plugin constructor if a short name is
      *        passed for $plugin
      *
      * @return Phergie_Plugin_Abstract New plugin instance
@@ -143,30 +174,21 @@ class Phergie_Plugin_Handler implements IteratorAggregate
             }
 
             // Attempt to locate and load the class
-            foreach (array_reverse($this->paths) as $path) {
-                $file = $path['path'] . $plugin . '.php';
-                if (file_exists($file)) {
-                    include_once $file;
-                    $class = $path['prefix'] . $plugin;
-                    if (class_exists($class)) {
-                        break;
-                    }
-                    unset($class);
-                }
-            }
-
-            // If the class can't be found, display an error
-            if (!isset($class)) {
+            $info = $this->getPluginInfo($plugin);
+            $file = $info['file'];
+            $class = $info['class'];
+            include_once $file;
+            if (!class_exists($class, false)) {
                 throw new Phergie_Plugin_Exception(
-                    'Class file for plugin "' . $plugin . '" cannot be found',
+                    'File "' . $file . '" does not contain class "' . $class . '"',
                     Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND
                 );
             }
 
-            // Check to ensure the class is a plugin class 
+            // Check to ensure the class is a plugin class
             if (!is_subclass_of($class, 'Phergie_Plugin_Abstract')) {
                 $msg
-                    = 'Class for plugin "' . $plugin . 
+                    = 'Class for plugin "' . $plugin .
                     '" does not extend Phergie_Plugin_Abstract';
                 throw new Phergie_Plugin_Exception(
                     $msg,
@@ -190,11 +212,7 @@ class Phergie_Plugin_Handler implements IteratorAggregate
                 $instance = new $class;
             }
 
-            // Configure and add the instance 
-            $instance->setPluginHandler($this);
-            $instance->setConfig($this->config);
-            $instance->setEventHandler($this->events);
-            $instance->onLoad();
+            // Store the instance
             $this->plugins[$index] = $instance;
             $plugin = $instance;
 
@@ -205,14 +223,20 @@ class Phergie_Plugin_Handler implements IteratorAggregate
             $this->plugins[strtolower($plugin->getName())] = $plugin;
         }
 
+        // Configure and initialize the instance
+        $plugin->setPluginHandler($this);
+        $plugin->setConfig($this->config);
+        $plugin->setEventHandler($this->events);
+        $plugin->onLoad();
+
         return $plugin;
     }
 
     /**
      * Adds multiple plugin instances to the handler.
      *
-     * @param array $plugins List of elements where each is of the form 
-     *        'ShortPluginName' or array('ShortPluginName', array($arg1, 
+     * @param array $plugins List of elements where each is of the form
+     *        'ShortPluginName' or array('ShortPluginName', array($arg1,
      *        ..., $argN))
      *
      * @return Phergie_Plugin_Handler Provides a fluent interface
@@ -233,7 +257,7 @@ class Phergie_Plugin_Handler implements IteratorAggregate
     /**
      * Removes a plugin instance from the handler.
      *
-     * @param string|Phergie_Plugin_Abstract $plugin Short name of the 
+     * @param string|Phergie_Plugin_Abstract $plugin Short name of the
      *        plugin class or a plugin object
      *
      * @return Phergie_Plugin_Handler Provides a fluent interface
@@ -251,7 +275,7 @@ class Phergie_Plugin_Handler implements IteratorAggregate
     }
 
     /**
-     * Returns the corresponding instance for a specified plugin, loading it 
+     * Returns the corresponding instance for a specified plugin, loading it
      * if it is not already loaded and autoloading is enabled.
      *
      * @param string $name Short name of the plugin class
@@ -268,8 +292,8 @@ class Phergie_Plugin_Handler implements IteratorAggregate
 
         // If autoloading is disabled, display an error
         if (!$this->autoload) {
-            $msg 
-                = 'Plugin "' . $name . '" has been requested, ' . 
+            $msg
+                = 'Plugin "' . $name . '" has been requested, ' .
                 'is not loaded, and autoload is disabled';
             throw new Phergie_Plugin_Exception(
                 $msg,
@@ -285,17 +309,23 @@ class Phergie_Plugin_Handler implements IteratorAggregate
     }
 
     /**
-     * Returns the corresponding instances for multiple specified plugins, 
-     * loading them if they are not already loaded and autoloading is 
+     * Returns the corresponding instances for multiple specified plugins,
+     * loading them if they are not already loaded and autoloading is
      * enabled.
      *
-     * @param array $names List of short names of the plugin classes
+     * @param array $names Optional list of short names of the plugin
+     *        classes to which the returned plugin list will be limited,
+     *        defaults to all presently loaded plugins
      *
-     * @return array Associative array mapping plugin class short names to 
-     *         corresponding plugin instances
+     * @return array Associative array mapping lowercased plugin class short
+     *         names to corresponding plugin instances
      */
-    public function getPlugins(array $names)
+    public function getPlugins(array $names = array())
     {
+        if (empty($names)) {
+            return $this->plugins;
+        }
+
         $plugins = array();
         foreach ($names as $name) {
             $plugins[$name] = $this->getPlugin($name);
@@ -304,7 +334,7 @@ class Phergie_Plugin_Handler implements IteratorAggregate
     }
 
     /**
-     * Returns whether or not at least one instance of a specified plugin 
+     * Returns whether or not at least one instance of a specified plugin
      * class is loaded.
      *
      * @param string $name Short name of the plugin class
@@ -317,10 +347,10 @@ class Phergie_Plugin_Handler implements IteratorAggregate
     }
 
     /**
-     * Sets a flag used to determine whether plugins should be loaded 
+     * Sets a flag used to determine whether plugins should be loaded
      * automatically if they have not been explicitly loaded.
      *
-     * @param bool $flag TRUE to have plugins autoload (default), FALSE 
+     * @param bool $flag TRUE to have plugins autoload (default), FALSE
      *        otherwise
      *
      * @return Phergie_Plugin_Handler Provides a fluent interface.
@@ -333,7 +363,7 @@ class Phergie_Plugin_Handler implements IteratorAggregate
     }
 
     /**
-     * Returns the value of a flag used to determine whether plugins should 
+     * Returns the value of a flag used to determine whether plugins should
      * be loaded automatically if they have not been explicitly loaded.
      *
      * @return bool TRUE if autoloading is enabled, FALSE otherwise
@@ -344,7 +374,7 @@ class Phergie_Plugin_Handler implements IteratorAggregate
     }
 
     /**
-     * Allows plugin instances to be accessed as properties of the handler. 
+     * Allows plugin instances to be accessed as properties of the handler.
      *
      * @param string $name Short name of the plugin
      *
@@ -352,7 +382,7 @@ class Phergie_Plugin_Handler implements IteratorAggregate
      */
     public function __get($name)
     {
-        return $this->getPlugin($name); 
+        return $this->getPlugin($name);
     }
 
     /**
@@ -390,14 +420,14 @@ class Phergie_Plugin_Handler implements IteratorAggregate
     }
 
     /**
-     * Proxies method calls to all plugins containing the called method. An  
-     * individual plugin may short-circuit this process by explicitly 
+     * Proxies method calls to all plugins containing the called method. An
+     * individual plugin may short-circuit this process by explicitly
      * returning FALSE.
      *
      * @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 
+     * @return bool FALSE if a plugin short-circuits processing by returning
      *         FALSE, TRUE otherwise
      */
     public function __call($name, array $args)
@@ -409,4 +439,14 @@ class Phergie_Plugin_Handler implements IteratorAggregate
         }
         return true;
     }
+
+    /**
+     * Returns the number of plugins contained within the handler.
+     *
+     * @return int Plugin count
+     */
+    public function count()
+    {
+        return count($this->plugins);
+    }
 }
index 0de13308dbd8521eab7e50d9f10f0f7e1e542c64..7cc8349571656e34b2f551ccad0e24f78208ec63 100644 (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_Help
  * @author    Phergie Development Team <team@phergie.org>
  * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
@@ -22,7 +22,7 @@
 /**
  * Provides access to descriptions of plugins and the commands they provide.
  *
- * @category Phergie 
+ * @category Phergie
  * @package  Phergie_Plugin_Help
  * @author   Phergie Development Team <team@phergie.org>
  * @license  http://phergie.org/license New BSD License
@@ -60,11 +60,11 @@ class Phergie_Plugin_Help extends Phergie_Plugin_Abstract
     }
 
     /**
-     * Displays a list of plugins with help information available or 
+     * 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 
+     * @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
      *
      * @return void
@@ -94,13 +94,13 @@ class Phergie_Plugin_Help extends Phergie_Plugin_Abstract
                 && isset($this->registry[strtolower($plugin)]['cmd'])
             ) {
                 $msg
-                    = 'The ' . 
-                    $plugin . 
+                    = '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 "' .  
+                        = 'Note that these commands must be prefixed with "' .
                         $this->getConfig('command.prefix') .
                         '" (without quotes) when issued in a public channel.';
                     $this->doPrivMsg($nick, $msg);
@@ -122,10 +122,10 @@ class Phergie_Plugin_Help extends Phergie_Plugin_Abstract
 
     /**
      * Sets the description for the plugin instance
-     * 
+     *
      * @param Phergie_Plugin_Abstract $plugin      plugin instance
      * @param string                  $description plugin description
-     * 
+     *
      * @return void
      */
     public function setPluginDescription(
@@ -138,7 +138,7 @@ class Phergie_Plugin_Help extends Phergie_Plugin_Abstract
 
     /**
      * 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
@@ -158,7 +158,7 @@ class Phergie_Plugin_Help extends Phergie_Plugin_Abstract
      * 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
@@ -191,7 +191,8 @@ class Phergie_Plugin_Help extends Phergie_Plugin_Abstract
     }
 
     /**
-     * Taken from PHPUnit/Util/Test.php:436
+     * Taken from PHPUnit/Util/Test.php:243 and modified to fix an issue
+     * with tag content spanning multiple lines.
      *
      * PHPUnit
      *
@@ -235,13 +236,16 @@ class Phergie_Plugin_Help extends Phergie_Plugin_Abstract
     {
         $annotations = array();
 
-        $regex = '/@(?P<name>[A-Za-z_-]+)(?:[ \t]+(?P<value>.*?))?[ \t]*\r?$/m';
+        $regex = '/@(?P<name>[A-Za-z_-]+)(?:[ \t]+(?P<value>.*?))?(?:\*\/|\* @)/ms';
 
         if (preg_match_all($regex, $docblock, $matches)) {
             $numMatches = count($matches[0]);
 
             for ($i = 0; $i < $numMatches; ++$i) {
-                $annotations[$matches['name'][$i]][] = $matches['value'][$i];
+                $annotation = $matches['value'][$i];
+                $annotation = preg_replace('/\s*\v+\s*\*\s*/', ' ', $annotation);
+                $annotation = rtrim($annotation);
+                $annotations[$matches['name'][$i]][] = $annotation;
             }
         }
 
index def9d81c26fdff694c186b605fb6d7a20a9f04f4..80d16c4b858000eaacc79000c747887c2f86a00a 100644 (file)
@@ -37,6 +37,43 @@ class Phergie_Plugin_Http_Response
      */
     protected $code;
 
+    /**
+     * HTTP response strings
+     *
+     * @var array
+     */
+    protected $codeStrings = array(
+        0   => 'No Response',
+        100 => 'Continue',
+        200 => 'OK',
+        201 => 'Created',
+        204 => 'No Content',
+        206 => 'Partial Content',
+        300 => 'Multiple Choices',
+        301 => 'Moved Permanently',
+        302 => 'Found',
+        303 => 'See Other',
+        304 => 'Not Modified',
+        307 => 'Temporary Redirect',
+        400 => 'Bad Request',
+        401 => 'Unauthorized',
+        403 => 'Forbidden',
+        404 => 'Not Found',
+        405 => 'Method Not Allowed',
+        406 => 'Not Acceptable',
+        408 => 'Request Timeout',
+        410 => 'Gone',
+        413 => 'Request Entity Too Large',
+        414 => 'Request URI Too Long',
+        415 => 'Unsupported Media Type',
+        416 => 'Requested Range Not Satisfiable',
+        417 => 'Expectation Failed',
+        500 => 'Internal Server Error',
+        501 => 'Method Not Implemented',
+        503 => 'Service Unavailable',
+        506 => 'Variant Also Negotiates'
+    );
+
     /**
      * Description of the HTTP response code or the error message if no HTTP 
      * response was received
@@ -89,6 +126,22 @@ class Phergie_Plugin_Http_Response
         return $this->code;
     }
 
+    /**
+     * Returns the HTTP response code text.
+     *
+     * @return string Response code text
+     */
+    public function getCodeAsString()
+    {
+        $code = $this->code;
+
+        if (!isset($this->codeStrings[$code])) {
+            return 'Unkown HTTP Status';
+        }
+
+        return $this->codeStrings[$code];
+    }
+
     /**
      * Returns whether the response indicates a client- or server-side error.
      *
index 29d51180237231057ff52335e9c5ffcdd507b766..94abfb031c3f106f35efaf1bbc09a1c71a75633b 100644 (file)
@@ -62,7 +62,6 @@ class Phergie_Plugin_Php extends Phergie_Plugin_Abstract
      */
     public function onConnect()
     {
-        // Construct a new data source
         $this->source = new Phergie_Plugin_Php_Source_Local;
     }
 
@@ -75,14 +74,13 @@ class Phergie_Plugin_Php extends Phergie_Plugin_Abstract
      */
     public function onCommandPhp($functionName)
     {
-        // Search for the function
+        $nick = $this->event->getNick();
         if ($function = $this->source->findFunction($functionName)) {
-            $msg = 'PHP ' . $function['name'] . ': ' . $function['description'];
+            $msg = $nick . ': ' . $function['description'];
+            $this->doPrivmsg($this->event->getSource(), $msg);
         } else {
             $msg = 'Search for function ' . $functionName . ' returned no results.';
+            $this->doNotice($nick, $msg);
         }
-        
-        // Return the result to the source
-        $this->doPrivmsg($this->getEvent()->getSource(), $msg);
     }
 }
index b72443c2e50ea610b710bb0b712ff94659189276..9292bea848f390df941821f0e24aa3ff6bb81a21 100644 (file)
@@ -65,7 +65,8 @@ class Phergie_Plugin_Php_Source_Local implements Phergie_Plugin_Php_Source
             // @todo Modify this to be rethrown as an appropriate 
             //       Phergie_Plugin_Exception and handled in Phergie_Plugin_Php
         } catch (PDOException $e) {
-        }
+            echo 'PDO failure: '.$e->getMessage();
+        } 
     }
 
     /**
@@ -114,12 +115,16 @@ class Phergie_Plugin_Php_Source_Local implements Phergie_Plugin_Php_Source
     protected function buildDatabase($rebuild = false)
     {
         // Check to see if the functions table exists
-        $table = $this->database->exec("SELECT COUNT(*) FROM `sqlite_master` WHERE `name` = 'functions'");
-
+        $checkstmt = $this->database->query("SELECT COUNT(*) FROM `sqlite_master` WHERE `name` = 'functions'");
+        $checkstmt->execute();
+        $result = $checkstmt->fetch(PDO::FETCH_ASSOC);
+        unset( $checkstmt );
+        $table = $result['COUNT(*)'];
+        unset( $result );
         // If the table doesn't exist, create it
         if (!$table) {
-            $this->database->exec('CREATE TABLE `functions` (`name` VARCHAR(255), `description` TEXT)');
-            $this->database->exec('CREATE UNIQUE INDEX `functions_name` ON `functions` (`name`)');
+                $this->database->exec('CREATE TABLE `functions` (`name` VARCHAR(255), `description` TEXT)');
+                $this->database->exec('CREATE UNIQUE INDEX `functions_name` ON `functions` (`name`)');
         }
 
         // If we created a new table, fill it with data
@@ -160,7 +165,7 @@ class Phergie_Plugin_Php_Source_Local implements Phergie_Plugin_Php_Source
                     // ... it's the last part of the complete function description
                     $completeLine = $firstPart . ' ' . $line;
                     $firstPart = '';
-                    if (preg_match('{^([^\s]*)[\s]?([^)]*)\(([^\)]*)\)[\sU]+([\sa-zA-Z0-9\.\-_]*)$}', $completeLine, $matches)) {
+                    if (preg_match('{^([^\s]*)[\s]?([^)]*)\(([^\)]*)\)[\sU]+([\sa-zA-Z0-9\.,\-_()]*)$}', $completeLine, $matches)) {
                         $valid[] = $matches;
                     }
                 }
diff --git a/plugins/Irc/extlib/phergie/Phergie/Plugin/Reload.php b/plugins/Irc/extlib/phergie/Phergie/Plugin/Reload.php
new file mode 100755 (executable)
index 0000000..a2d680d
--- /dev/null
@@ -0,0 +1,96 @@
+<?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_Reload
+ * @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_Reload
+ */
+
+/**
+ * Facilitates reloading of individual plugins for development purposes.
+ * Note that, because existing class definitions cannot be removed from
+ * memory, increased memory usage is an expected result of using this plugin.
+ *
+ * @category Phergie
+ * @package  Phergie_Plugin_Reload
+ * @author   Phergie Development Team <team@phergie.org>
+ * @license  http://phergie.org/license New BSD License
+ * @link     http://pear.phergie.org/package/Phergie_Plugin_Reload
+ * @uses     Phergie_Plugin_Command pear.phergie.org
+ */
+class Phergie_Plugin_Reload extends Phergie_Plugin_Abstract
+{
+    /**
+     * Checks for dependencies.
+     *
+     * @return void
+     */
+    public function onLoad()
+    {
+        $this->getPluginHandler()->getPlugin('Command');
+    }
+
+    /**
+     * Reloads a specified plugin.
+     *
+     * @param string $plugin Short name of the plugin to reload
+     *
+     * @return void
+     */
+    public function onCommandReload($plugin)
+    {
+        $plugin = ucfirst($plugin);
+
+        if (!$this->plugins->hasPlugin($plugin)) {
+            echo 'DEBUG(Reload): ' . ucfirst($plugin) . ' is not loaded yet, loading', PHP_EOL;
+            $this->plugins->getPlugin($plugin);
+            return;
+        }
+
+        try {
+            $info = $this->plugins->getPluginInfo($plugin);
+        } catch (Phergie_Plugin_Exception $e) {
+            $source = $this->event->getSource();
+            $nick = $this->event->getNick();
+            $this->doNotice($source, $nick . ': ' . $e->getMessage());
+            return;
+        }
+
+        $class = $info['class'];
+        $contents = file_get_contents($info['file']);
+        $newClass = $class . '_' . sha1($contents);
+
+        if (class_exists($newClass, false)) {
+            echo 'DEBUG(Reload): Class ', $class, ' has not changed since last reload', PHP_EOL;
+            return;
+        }
+
+        $contents = preg_replace(
+            array('/<\?(?:php)?/', '/class\s+' . $class . '/i'),
+            array('', 'class ' . $newClass),
+            $contents
+        );
+        eval($contents);
+
+        $instance = new $newClass;
+        $instance->setName($plugin);
+        $this->plugins
+            ->removePlugin($plugin)
+            ->addPlugin($instance);
+
+        echo 'DEBUG(Reload): Reloaded ', $class, ' to ', $newClass, PHP_EOL;
+    }
+}
index bfd53336741d694cd4bcf873f54df08b3fdae197..cfb3c07e8c9594da5b61e936f5734b13c60932fd 100644 (file)
  * @package  Phergie_Plugin_Remind
  * @author   Phergie Development Team <team@phergie.org>
  * @license  http://phergie.org/license New BSD License
- * @link     http://pear.phergie.org/package/Phergie_Plugin_Drink
+ * @link     http://pear.phergie.org/package/Phergie_Plugin_Remind
  * @uses     Phergie_Plugin_Command pear.phergie.org
- * @uses     Phergie_Plugin_Helper_Time pear.phergie.org
+ * @uses     Phergie_Plugin_Time pear.phergie.org
  */
 class Phergie_Plugin_Remind extends Phergie_Plugin_Abstract
 {
     /**
      * Number of reminders to show in public.
      */
-    const PUBLIC_REMINDERS = 3;
+    protected $publicReminders = 3;
 
     /**
      * PDO resource for a SQLite database containing the reminders.
@@ -64,11 +64,31 @@ class Phergie_Plugin_Remind extends Phergie_Plugin_Abstract
      */
     public function onLoad()
     {
-        $this->getPluginHandler()->getPlugin('Command');
-        $path = dirname(__FILE__) . '/reminder.db';
+        $plugins = $this->getPluginHandler();
+        $plugins->getPlugin('Command');
+        $plugins->getPlugin('Time');
+    }
+
+    /**
+     * Creates the database if it does not already exist.
+     *
+     * @return void
+     */
+    public function onConnect()
+    {
+        $dir = dirname(__FILE__) . '/' . $this->getName();
+        $path = $dir . '/reminder.db';
+        if (!file_exists($dir)) {
+            mkdir($dir);
+        }
 
         if (isset($this->config['remind.use_memory'])) {
-            $this->keepListInMemory = (bool)$this->config['remind.use_memory'];
+            $this->keepListInMemory = (bool) $this->config['remind.use_memory'];
+        }
+
+        if (isset($this->config['remind.public_reminders'])) {
+            $this->publicReminders = (int) $this->config['remind.public_reminders'];
+            $this->publicReminders = max($this->publicReminders, 0);
         }
 
         try {
@@ -222,19 +242,19 @@ class Phergie_Plugin_Remind extends Phergie_Plugin_Abstract
 
         // fetch and deliver messages
         $reminders = $this->fetchMessages($channel, $nick);
-        if (count($reminders) > self::PUBLIC_REMINDERS) {
-            $msgs = array_slice($reminders, 0, self::PUBLIC_REMINDERS);
-            $privmsgs = array_slice($reminders, self::PUBLIC_REMINDERS);
+        if (count($reminders) > $this->publicReminders) {
+            $msgs = array_slice($reminders, 0, $this->publicReminders);
+            $privmsgs = array_slice($reminders, $this->publicReminders);
         } else {
             $msgs = $reminders;
             $privmsgs = false;
         }
 
         foreach ($msgs as $msg) {
-            $ts = new Phergie_Plugin_Helper_Time($msg['time']);
+            $ts = $this->plugins->time->getCountdown($msg['time']);
             $formatted = sprintf(
                 '%s: (from %s, %s ago) %s',
-                $nick, $msg['sender'], $ts->getCountdown(), $msg['message']
+                $nick, $msg['sender'], $ts, $msg['message']
             );
             $this->doPrivmsg($channel, $formatted);
             $this->deleteMessage($msg['rowid'], $channel, $nick);
@@ -242,10 +262,10 @@ class Phergie_Plugin_Remind extends Phergie_Plugin_Abstract
 
         if ($privmsgs) {
             foreach ($privmsgs as $msg) {
-                $ts = new Phergie_Plugin_Helper_Time($msg['time']);
+                $ts = $this->plugins->time->getCountdown($msg['time']);
                 $formatted = sprintf(
                     'from %s, %s ago: %s',
-                    $msg['sender'], $ts->getCountdown(), $msg['message']
+                    $msg['sender'], $ts, $msg['message']
                 );
                 $this->doPrivmsg($nick, $formatted);
                 $this->deleteMessage($msg['rowid'], $channel, $nick);
diff --git a/plugins/Irc/extlib/phergie/Phergie/Plugin/SpellCheck.php b/plugins/Irc/extlib/phergie/Phergie/Plugin/SpellCheck.php
new file mode 100644 (file)
index 0000000..3324082
--- /dev/null
@@ -0,0 +1,120 @@
+<?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_TerryChay
+ * @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_TerryChay
+ */
+
+/**
+ * Handles requests for checking spelling of specified words and returning
+ * either confirmation of correctly spelled words or potential correct
+ * spellings for misspelled words.
+ *
+ * @category Phergie 
+ * @package  Phergie_Plugin_SpellCheck
+ * @author   Phergie Development Team <team@phergie.org>
+ * @license  http://phergie.org/license New BSD License
+ * @link     http://pear.phergie.org/package/Phergie_Plugin_TerryChay
+ * @uses     Phergie_Plugin_Command pear.phergie.org
+ * @uses     extension pspell
+ */
+class Phergie_Plugin_SpellCheck extends Phergie_Plugin_Abstract
+{
+
+    /**
+     * Spell check dictionary handler
+     *
+     * @var resource
+     */
+    protected $pspell;
+
+    /**
+     * Limit on the number of potential correct spellings returned
+     *
+     * @var int
+     */
+    protected $limit;
+
+    /**
+     * Check for dependencies.
+     *
+     * @return void
+     */
+    public function onLoad()
+    {
+        if (!extension_loaded('pspell')) {
+            $this->fail('pspell php extension is required');
+        }
+
+        if (!$this->getConfig('spellcheck.lang')) {
+            $this->fail('Setting spellcheck.lang must be filled-in');
+        }
+
+        $this->plugins->getPlugin('Command');
+       
+        set_error_handler(array($this, 'loadDictionaryError'));
+        $this->pspell = pspell_new($this->getConfig('spellcheck.lang'));
+        restore_error_handler();
+
+        $this->limit = $this->getConfig('spellcheck.limit', 5);
+    }
+
+    /**
+     * Intercepts and handles requests for spell checks.
+     *
+     * @param string $word the string to perform checks against
+     *
+     * @return void
+     */
+    public function onCommandSpell($word)
+    {
+        $source = $this->event->getSource();
+        $target = $this->event->getNick();
+
+        $message  = $target . ': The word "' . $word;
+        $message .= '" seems to be spelt correctly.';
+        if (!pspell_check($this->pspell, $word)) {
+            $suggestions = pspell_suggest($this->pspell, $word);
+           
+            $message  = $target; 
+            $message .= ': I could not find any suggestions for "' . $word . '".';
+            if (!empty($suggestions)) {
+                $suggestions = array_splice($suggestions, 0, $this->limit);
+                $message     = $target . ': Suggestions for "';
+                $message    .= $word . '": ' . implode(', ', $suggestions) . '.';
+            }
+        }
+         
+        $this->doPrivmsg($source, $message);
+    }
+
+    /**
+     * Handle any errors from loading dictionary
+     *
+     * @param integer $errno   Error code
+     * @param string  $errstr  Error message
+     * @param string  $errfile File that errored
+     * @param integer $errline Line where the error happened
+     *
+     * @return void
+     */
+    protected function loadDictionaryError($errno, $errstr, $errfile, $errline)
+    {
+        $this->fail($errstr);
+    }
+
+}
diff --git a/plugins/Irc/extlib/phergie/Phergie/Plugin/Tld.php b/plugins/Irc/extlib/phergie/Phergie/Plugin/Tld.php
new file mode 100644 (file)
index 0000000..21ba1e6
--- /dev/null
@@ -0,0 +1,261 @@
+<?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_Url
+ * @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_Url
+ */
+
+/**
+ * Responds to a request for a TLD (formatted as .tld where tld is the TLD to
+ * be looked up) with its corresponding description.
+ *
+ * @category Phergie
+ * @package  Phergie_Plugin_Tld
+ * @author   Phergie Development Team <team@phergie.org>
+ * @license  http://phergie.org/license New BSD License
+ * @link     http://pear.phergie.org/package/Phergie_Plugin_Tld
+ * @uses     Phergie_Plugin_Http pear.phergie.org
+ *
+ * @pluginDesc Provides information for a top level domain.
+ */
+class Phergie_Plugin_Tld extends Phergie_Plugin_Abstract
+{
+    /**
+     * connection to the database
+     * @var PDO
+     */
+    protected $db;
+    /**
+     * Some fixed TLD values, keys must be lowercase
+     * @var array
+     */
+    protected static $fixedTlds;
+
+    /**
+     * Prepared statement for selecting a single tld
+     * @var PDOStatement
+     */
+    protected $select;
+
+    /**
+     * Prepared statement for selecting all tlds
+     * @var PDOStatement
+     */
+    protected $selectAll;
+
+    /**
+     * Checks for dependencies, sets up database and hard coded values
+     *
+     * @return void
+     */
+    public function onLoad()
+    {
+        $help = $this->getPluginHandler()->getPlugin('Help');
+        $help->register($this);
+
+        if (!is_array(self::$fixedTlds)) {
+            self::$fixedTlds = array(
+                'phergie' => 'You can find Phergie at http://www.phergie.org',
+                'spoon'   => 'Don\'t you know? There is no spoon!',
+                'poo'     => 'Do you really think that\'s funny?',
+                'root'    => 'Diagnostic marker to indicate '
+                . 'a root zone load was not truncated.'
+            );
+        }
+
+        try {
+            $dbFile = dirname(__FILE__) . '/Tld/tld.db';
+            $dbManager = new Phergie_Db_Sqlite($dbFile);
+            $this->db = $dbManager->getDb();
+            if (!$dbManager->hasTable('tld')) {
+                $query = 'CREATE TABLE tld ('
+                        . 'tld VARCHAR(20), '
+                        . 'type VARCHAR(20), '
+                        . 'description VARCHAR(255))';
+
+                $this->db->exec($query);
+
+                // prepare a statement to populate the table with
+                // tld information
+                $insert = $this->db->prepare(
+                    'INSERT INTO tld
+                    (tld, type, description)
+                    VALUES (:tld, :type, :description)'
+                );
+
+                // grab tld data from iana.org...
+                $contents = file_get_contents(
+                    'http://www.iana.org/domains/root/db/'
+                );
+
+                // ...and then parse it out
+                $regex = '{<tr class="iana-group[^>]*><td><a[^>]*>\s*\.?([^<]+)\s*'
+                        . '(?:<br/><span[^>]*>[^<]*</span>)?</a></td><td>\s*'
+                        . '([^<]+)\s*</td><td>\s*([^<]+)\s*}i';
+                preg_match_all($regex, $contents, $matches, PREG_SET_ORDER);
+
+                foreach ($matches as $match) {
+                    list(, $tld, $type, $description) = array_pad($match, 4, null);
+                    $type = trim(strtolower($type));
+                    if ($type != 'test') {
+                        $tld = trim(strtolower($tld));
+                        $description = trim($description);
+
+                        switch ($tld) {
+
+                        case 'com':
+                            $description = 'Commercial';
+                            break;
+
+                        case 'info':
+                            $description = 'Information';
+                            break;
+
+                        case 'net':
+                            $description = 'Network';
+                            break;
+
+                        case 'org':
+                            $description = 'Organization';
+                            break;
+
+                        case 'edu':
+                            $description = 'Educational';
+                            break;
+
+                        case 'name':
+                            $description = 'Individuals, by name';
+                            break;
+                        }
+
+                        if (empty($tld) || empty($description)) {
+                            continue;
+                        }
+
+                        $regex = '{(^(?:Reserved|Restricted)\s*(?:exclusively\s*)?'
+                                 . '(?:for|to)\s*(?:members of\s*)?(?:the|support)?'
+                                 . '\s*|\s*as advised.*$)}i';
+                        $description = preg_replace($regex, '', $description);
+                        $description = ucfirst(trim($description));
+
+                        $data = array_map(
+                            'html_entity_decode', array(
+                                'tld' => $tld,
+                                'type' => $type,
+                                'description' => $description
+                            )
+                        );
+
+                        $insert->execute($data);
+                    }
+                }
+
+                unset(
+                    $insert,
+                    $matches,
+                    $match,
+                    $contents,
+                    $tld,
+                    $type,
+                    $description,
+                    $data,
+                    $regex
+                );
+            }
+
+            // Create a prepared statements for retrieving TLDs
+            $this->select = $this->db->prepare(
+                'SELECT type, description '
+                . 'FROM tld WHERE LOWER(tld) = LOWER(:tld)'
+            );
+
+            $this->selectAll = $this->db->prepare(
+                'SELECT tld, type, description FROM tld'
+            );
+        } catch (PDOException $e) {
+        }
+    }
+
+    /**
+     * takes a tld in the format '.tld' and returns its related data
+     *
+     * @param string $tld tld to process
+     *
+     * @return null
+     *
+     * @pluginCmd .[tld] request details about the tld
+     */
+    public function onCommandTld($tld)
+    {
+        $tld = ltrim($tld, '.');
+        $description = $this->getTld($tld);
+        $this->doPrivmsg(
+            $this->event->getSource(),
+            "{$this->getEvent()->getNick()}: .{$tld} -> "
+            . ($description ? $description : 'Unknown TLD')
+        );
+    }
+
+    /**
+     * Retrieves the definition for a given TLD if it exists
+     *
+     * @param string $tld TLD to search for
+     *
+     * @return string Definition of the given TLD
+     */
+    public function getTld($tld)
+    {
+        $tld = trim(strtolower($tld));
+        if (isset(self::$fixedTlds[$tld])) {
+            return self::$fixedTlds[$tld];
+        } else {
+            if ($this->select->execute(array('tld' => $tld))) {
+                $tlds = $this->select->fetch();
+                if (is_array($tlds)) {
+                    return '(' . $tlds['type'] . ') ' . $tlds['description'];
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Retrieves a list of all the TLDs and their definitions
+     *
+     * @return array Array of all the TLDs and their definitions
+     */
+    public function getTlds()
+    {
+        if ($this->selectAll->execute()) {
+            $tlds = $this->selectAll->fetchAll();
+            if (is_array($tlds)) {
+                $tldinfo = array();
+                foreach ($tlds as $key => $tld) {
+                    if (!empty($tld['tld'])) {
+                        $tldinfo[$tld['tld']] = "({$tld['type']}) "
+                        . $tld['description'];
+                    }
+                }
+                unset($tlds);
+                return $tldinfo;
+            }
+        }
+        return false;
+    }
+}
+
index 8fc1c3538edc0a54f7966583b9a3cc619ddc9894..2ea33befdf15fb57a4fa66d3cc50a8e493d1cbae 100644 (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_Url
  * @author    Phergie Development Team <team@phergie.org>
  * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
  * Monitors incoming messages for instances of URLs and responds with messages
  * containing relevant information about detected URLs.
  *
- * Has an utility method accessible via 
+ * Has an utility method accessible via
  * $this->getPlugin('Url')->getTitle('http://foo..').
  *
- * @category Phergie 
+ * @category Phergie
  * @package  Phergie_Plugin_Url
  * @author   Phergie Development Team <team@phergie.org>
  * @license  http://phergie.org/license New BSD License
  * @link     http://pear.phergie.org/package/Phergie_Plugin_Url
+ * @uses     Phergie_Plugin_Http pear.phergie.org
  */
 class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
 {
     /**
      * Links output format
      *
-     * Can use the variables %nick%, %title% and %link% in it to display 
+     * Can use the variables %nick%, %title% and %link% in it to display
      * page titles and links
      *
      * @var string
      */
-    protected $baseFormat = '%nick%: %message%';
+    protected $baseFormat = '%message%';
     protected $messageFormat = '[ %link% ] %title%';
 
     /**
-     * Flag indicating whether a single response should be sent for a single 
+     * Flag indicating whether a single response should be sent for a single
      * message containing multiple links
      *
      * @var bool
@@ -61,7 +62,7 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
     protected $titleLength = 40;
 
     /**
-     * Url cache to prevent spamming, especially with multiple bots on the 
+     * Url cache to prevent spamming, especially with multiple bots on the
      * same channel
      *
      * @var array
@@ -88,16 +89,16 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
     protected $limit = 10;
 
     /**
-     * Flag that determines if the plugin will fall back to using an HTTP 
-     * stream when a URL using SSL is detected and OpenSSL support isn't 
-     * available in the PHP installation in use 
+     * Flag that determines if the plugin will fall back to using an HTTP
+     * stream when a URL using SSL is detected and OpenSSL support isn't
+     * available in the PHP installation in use
      *
      * @var bool
      */
     protected $sslFallback = true;
 
     /**
-     * Flag that is set to true by the custom error handler if an HTTP error 
+     * Flag that is set to true by the custom error handler if an HTTP error
      * code has been received
      *
      * @var boolean
@@ -106,7 +107,7 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
     protected $errorMessage = null;
 
     /**
-     * Flag indicating whether or not to display error messages as the title 
+     * Flag indicating whether or not to display error messages as the title
      * if a link posted encounters an error
      *
      * @var boolean
@@ -121,7 +122,7 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
     protected $detectSchemeless = false;
 
     /**
-     * List of error messages to return when the requested URL returns an 
+     * List of error messages to return when the requested URL returns an
      * HTTP error
      *
      * @var array
@@ -184,7 +185,7 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
         // make the shortener configurable
         $shortener = $this->getConfig('url.shortener', 'Trim');
         $shortener = "Phergie_Plugin_Url_Shorten_{$shortener}";
-        $this->shortener = new $shortener;
+        $this->shortener = new $shortener($this->plugins->getPlugin('Http'));
 
         if (!$this->shortener instanceof Phergie_Plugin_Url_Shorten_Abstract) {
             $this->fail("Declared shortener class {$shortener} is not of proper ancestry");
@@ -192,17 +193,9 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
 
         // Get a list of valid TLDs
         if (!is_array($this->tldList) || count($this->tldList) <= 6) {
-            /* Omitted for port
-            if ($this->pluginLoaded('Tld')) {
-                $this->tldList = Phergie_Plugin_Tld::getTlds();
-                if (is_array($this->tldList)) {
-                    $this->tldList = array_keys($this->tldList);
-                }
-            }
-            */
-            if (!is_array($this->tldList) || count($this->tldList) <= 0) {
-                $this->tldList = array('ac', 'ad', 'ae', 'aero', 'af', 'ag', 'ai', 'al', 'am', 'an', 'ao', 'aq', 'ar', 'arpa', 'as', 'asia', 'at', 'au', 'aw', 'ax', 'az', 'ba', 'bb', 'bd', 'be', 'bf', 'bg', 'bh', 'bi', 'biz', 'bj', 'bl', 'bm', 'bn', 'bo', 'br', 'bs', 'bt', 'bv', 'bw', 'by', 'bz', 'ca', 'cat', 'cc', 'cd', 'cf', 'cg', 'ch', 'ci', 'ck', 'cl', 'cm', 'cn', 'co', 'com', 'coop', 'cr', 'cu', 'cv', 'cx', 'cy', 'cz', 'de', 'dj', 'dk', 'dm', 'do', 'dz', 'ec', 'edu', 'ee', 'eg', 'eh', 'er', 'es', 'et', 'eu', 'fi', 'fj', 'fk', 'fm', 'fo', 'fr', 'ga', 'gb', 'gd', 'ge', 'gf', 'gg', 'gh', 'gi', 'gl', 'gm', 'gn', 'gov', 'gp', 'gq', 'gr', 'gs', 'gt', 'gu', 'gw', 'gy', 'hk', 'hm', 'hn', 'hr', 'ht', 'hu', 'id', 'ie', 'il', 'im', 'in', 'info', 'int', 'io', 'iq', 'ir', 'is', 'it', 'je', 'jm', 'jo', 'jobs', 'jp', 'ke', 'kg', 'kh', 'ki', 'km', 'kn', 'kp', 'kr', 'kw', 'ky', 'kz', 'la', 'lb', 'lc', 'li', 'lk', 'lr', 'ls', 'lt', 'lu', 'lv', 'ly', 'ma', 'mc', 'md', 'me', 'mf', 'mg', 'mh', 'mil', 'mk', 'ml', 'mm', 'mn', 'mo', 'mobi', 'mp', 'mq', 'mr', 'ms', 'mt', 'mu', 'museum', 'mv', 'mw', 'mx', 'my', 'mz', 'na', 'name', 'nc', 'ne', 'net', 'nf', 'ng', 'ni', 'nl', 'no', 'np', 'nr', 'nu', 'nz', 'om', 'org', 'pa', 'pe', 'pf', 'pg', 'ph', 'pk', 'pl', 'pm', 'pn', 'pr', 'pro', 'ps', 'pt', 'pw', 'py', 'qa', 're', 'ro', 'rs', 'ru', 'rw', 'sa', 'sb', 'sc', 'sd', 'se', 'sg', 'sh', 'si', 'sj', 'sk', 'sl', 'sm', 'sn', 'so', 'sr', 'st', 'su', 'sv', 'sy', 'sz', 'tc', 'td', 'tel', 'tf', 'tg', 'th', 'tj', 'tk', 'tl', 'tm', 'tn', 'to', 'tp', 'tr', 'travel', 'tt', 'tv', 'tw', 'tz', 'ua', 'ug', 'uk', 'um', 'us', 'uy', 'uz', 'va', 'vc', 've', 'vg', 'vi', 'vn', 'vu', 'wf', 'ws', 'ye', 'yt', 'yu', 'za', 'zm', 'zw');
-            }
+            $tldPath = dirname(__FILE__) . '/Url/url.tld.txt';
+            $this->tldList = explode("\n", file_get_contents($tldPath));
+            $this->debug('Loaded ' . count($this->tldList) . ' tlds');
             rsort($this->tldList);
         }
 
@@ -215,6 +208,7 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
                 'merge_links' => 'mergeLinks',
                 'title_length' => 'titleLength',
                 'show_errors' => 'showErrors',
+                'expire' => 'expire',
             ) as $config => $local) {
             if (isset($this->config["url.{$config}"])) {
                 $this->$local = $this->config["uri.{$config}"];
@@ -227,7 +221,7 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
      * found, responds with its title if it is an HTML document and the
      * shortened equivalent of its original URL if it meets length requirements.
      *
-     * @todo Update this to pull configuration settings from $this->config 
+     * @todo Update this to pull configuration settings from $this->config
      *       rather than caching them as class properties
      * @return void
      */
@@ -306,6 +300,10 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
 
                 // Convert url
                 $shortenedUrl = $this->shortener->shorten($url);
+                if (!$shortenedUrl) {
+                    $this->debug('Invalid Url: Unable to shorten. (' . $url . ')');
+                    continue;
+                }
 
                 // Prevent spamfest
                 if ($this->checkUrlCache($url, $shortenedUrl)) {
@@ -624,73 +622,29 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
      */
     public function getTitle($url)
     {
-        $opts = array(
-            'http' => array(
-                'timeout' => 3.5,
-                'method' => 'GET',
-                'user_agent' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.12) Gecko/20080201 Firefox/2.0.0.12'
-            )
+        $http = $this->plugins->getPlugin('Http');
+        $options = array(
+            'timeout' => 3.5,
+            'user_agent' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.12) Gecko/20080201 Firefox/2.0.0.12'
         );
-        $context = stream_context_create($opts);
-
-        if ($page = fopen($url, 'r', false, $context)) {
-            stream_set_timeout($page, 3.5);
-            $data = stream_get_meta_data($page);
-            foreach ($data['wrapper_data'] as $header) {
-                if (preg_match('/^Content-Type: ([^;]+)/', $header, $match)
-                    && !preg_match('#^(text/x?html|application/xhtml+xml)$#', $match[1])
-                ) {
-                    $title = $match[1];
-                }
-            }
-            if (!isset($title)) {
-                $content = '';
-                $tstamp = time() + 5;
-
-                while ($chunk = fread($page, 64)) {
-                    $data = stream_get_meta_data($page);
-                    if ($data['timed_out']) {
-                        $this->debug('Url Timed Out: ' . $url);
-                        $this->errorStatus = true;
-                        break;
-                    }
-                    $content .= $chunk;
-                    // Check for timeout
-                    if (time() > $tstamp) break;
-                    // Try to read title
-                    if (preg_match('#<title[^>]*>(.*)#is', $content, $m)) {
-                        // Start another loop to grab some more data in order to be sure we have the complete title
-                        $content = $m[1];
-                        $loop = 2;
-                        while (($chunk = fread($page, 64)) && $loop-- && !strstr($content, '<')) {
-                            $content .= $chunk;
-                            // Check for timeout
-                            if (time() > $tstamp) break;
-                        }
-                        preg_match('#^([^<]*)#is', $content, $m);
-                        $title = preg_replace('#\s+#', ' ', $m[1]);
-                        $title = trim($this->decode($title, $this->titleLength));
-                        break;
-                    }
-                    // Title won't appear beyond that point so stop parsing
-                    if (preg_match('#</head>|<body#i', $content)) {
-                        break;
-                    }
-                }
+
+        $response = $http->get($url, array(), $options);
+
+        $header = $response->getHeaders('Content-Type');
+        if (!preg_match('#^(text/x?html|application/xhtml+xml)(?:;.*)?$#', $header)) {
+            $title = $header;
+        }
+
+        $content = $response->getContent();
+        if (empty($title)) {
+            if (preg_match('#<title[^>]*>(.*?)</title>#is', $content, $match)) {
+                $title = html_entity_decode(trim($match[1]));
             }
-            fclose($page);
-        } else if (!$this->errorStatus) {
-            $this->debug('Couldn\t Open Url: ' . $url);
         }
 
         if (empty($title)) {
-            if ($this->errorStatus) {
-                if (!$this->showErrors || empty($this->errorMessage)) {
-                    return;
-                }
-                $title = $this->errorMessage;
-                $this->errorStatus = false;
-                $this->errorMessage = null;
+            if ($response->isError()) {
+                $title = $response->getCodeAsString();
             } else {
                 $title = 'No Title';
             }
index bf5dff0d3b5bf672862f2ac867e075cd01d8dc6b..607d1654c4157bc9e48ff6b328c015d8f450b21b 100644 (file)
  * @author   Phergie Development Team <team@phergie.org>
  * @license  http://phergie.org/license New BSD License
  * @link     http://pear.phergie.org/package/Phergie_Plugin_Url
+ * @uses     Phergie_Plugin_Http pear.phergie.org
  */
 abstract class Phergie_Plugin_Url_Shorten_Abstract
 {
+    protected $http;
+
+    /**
+     * Constructor
+     *
+     * @param Phergie_Plugin_Http $http instance of the http plugin
+     */
+    public function __construct(Phergie_Plugin_Http $http)
+    {
+        $this->http = $http;
+    }
+
     /**
-     * Takes a long url and returns a shortened link
+     * Returns an array of request parameters given a url to shorten. The
+     * following keys are valid request parameters:
+     *
+     *  * 'uri': the URI for the request (required)
+     *  * 'query': an array of key-value pairs sent in a GET request
+     *  * 'post': an array of key-value pairs sent in a POST request
+     *  * 'callback': to be called after the request is finished. Should accept
+     *    a Phergie_Plugin_Http_Response object and return either the shortened
+     *    url or false if an error has occured.
+     *
+     * If the 'post' key is present a POST request shall be made; otherwise
+     * a GET request will be made. The 'post' key can be an empty array and
+     * a post request will still be made.
+     *
+     * If no callback is provided the contents of the response will be returned.
      *
      * @param string $url the url to shorten
      *
-     * @return string string the shortened url
+     * @return array the request parameters
      */
-    public abstract function shorten($url);
+    protected abstract function getRequestParams($url);
+
+    /**
+     * Shortens a given url.
+     *
+     * @param string $url the url to shorten
+     *
+     * @return string the shortened url or false on a failure
+     */
+    public function shorten($url)
+    {
+        $defaults = array('get' => array(), 'post' => array(), 'callback' => null);
+        $options = array('timeout' => 2);
+        $params = $this->getRequestParams($url) + $defaults;
+
+        // Should some kind of notice be thrown? Maybe just if getRequestParams does not return an array?
+        if (!is_array($params) || empty($params['uri'])) {
+            return $url;
+        }
+
+        if (!empty($params['post'])) {
+            $response = $this->http->post($params['uri'], $params['get'], $params['post'], $options);
+        } else {
+            $response = $this->http->get($params['uri'], $params['get'], $options);
+        }
+
+        if (is_callable($params['callback'])) {
+            return call_user_func($params['callback'], $response);
+        }
+
+        $code = $response->getCode();
+        $content = trim($response->getContent);
+        if ($code < 200 || $code >= 300 || empty($content)) {
+            return false;
+        }
+
+        return $response->getContent();
+    }
 }
index a90459b37eeb924d905c162fea0358715b1cf6cb..af7e8a514f5e711ea4e01cd885a669d08d9296a5 100644 (file)
 class Phergie_Plugin_Url_Shorten_Trim extends Phergie_Plugin_Url_Shorten_Abstract
 {
     /**
-     * Short a URL through the tr.im api
+     * Returns an array of request parameters given a url to shorten. The
+     * following keys are valid request parameters:
      *
      * @param string $url the url to shorten
      *
-     * @return string string the shortened url
+     * @return array the request parameters
      */
-    public function shorten($url)
+    protected function getRequestParams($url)
     {
-        return file_get_contents('http://api.tr.im/v1/trim_simple?url=' . rawurlencode($url));
+        return array(
+            'uri' => 'http://api.tr.im/v1/trim_simple?url=' . rawurlencode($url),
+            'callback' => array($this, 'onComplete')
+        );
+    }
+
+    /**
+     * Callback for when the URL has been shortened. Checks for error messages.
+     *
+     * @param Phergie_Plugin_Http_Response $response the response object
+     *
+     * @return string|bool the shortened url or false on failure
+     */
+    protected function onComplete($response)
+    {
+        if (strpos($response->getContent(), 'Error: ') === 0) {
+            return false;
+        }
+
+        return $response->getContent();
     }
 }
diff --git a/plugins/Irc/extlib/phergie/Phergie/Plugin/Url/url.tld.txt b/plugins/Irc/extlib/phergie/Phergie/Plugin/Url/url.tld.txt
new file mode 100644 (file)
index 0000000..cc46fdd
--- /dev/null
@@ -0,0 +1,273 @@
+ac
+ad
+ae
+aero
+af
+ag
+ai
+al
+am
+an
+ao
+aq
+ar
+arpa
+as
+asia
+at
+au
+aw
+ax
+az
+ba
+bb
+bd
+be
+bf
+bg
+bh
+bi
+biz
+bj
+bl
+bm
+bn
+bo
+br
+bs
+bt
+bv
+bw
+by
+bz
+ca
+cat
+cc
+cd
+cf
+cg
+ch
+ci
+ck
+cl
+cm
+cn
+co
+com
+coop
+cr
+cu
+cv
+cx
+cy
+cz
+de
+dj
+dk
+dm
+do
+dz
+ec
+edu
+ee
+eg
+eh
+er
+es
+et
+eu
+fi
+fj
+fk
+fm
+fo
+fr
+ga
+gb
+gd
+ge
+gf
+gg
+gh
+gi
+gl
+gm
+gn
+gov
+gp
+gq
+gr
+gs
+gt
+gu
+gw
+gy
+hk
+hm
+hn
+hr
+ht
+hu
+id
+ie
+il
+im
+in
+info
+int
+io
+iq
+ir
+is
+it
+je
+jm
+jo
+jobs
+jp
+ke
+kg
+kh
+ki
+km
+kn
+kp
+kr
+kw
+ky
+kz
+la
+lb
+lc
+li
+lk
+lr
+ls
+lt
+lu
+lv
+ly
+ma
+mc
+md
+me
+mf
+mg
+mh
+mil
+mk
+ml
+mm
+mn
+mo
+mobi
+mp
+mq
+mr
+ms
+mt
+mu
+museum
+mv
+mw
+mx
+my
+mz
+na
+name
+nc
+ne
+net
+nf
+ng
+ni
+nl
+no
+np
+nr
+nu
+nz
+om
+org
+pa
+pe
+pf
+pg
+ph
+pk
+pl
+pm
+pn
+pr
+pro
+ps
+pt
+pw
+py
+qa
+re
+ro
+rs
+ru
+rw
+sa
+sb
+sc
+sd
+se
+sg
+sh
+si
+sj
+sk
+sl
+sm
+sn
+so
+sr
+st
+su
+sv
+sy
+sz
+tc
+td
+tel
+tf
+tg
+th
+tj
+tk
+tl
+tm
+tn
+to
+tp
+tr
+travel
+tt
+tv
+tw
+tz
+ua
+ug
+uk
+um
+us
+uy
+uz
+va
+vc
+ve
+vg
+vi
+vn
+vu
+wf
+ws
+ye
+yt
+yu
+za
+zm
+zw
diff --git a/plugins/Irc/extlib/phergie/Phergie/Plugin/Weather.php b/plugins/Irc/extlib/phergie/Phergie/Plugin/Weather.php
new file mode 100755 (executable)
index 0000000..7d3cc1d
--- /dev/null
@@ -0,0 +1,132 @@
+<?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_Weather
+ * @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_Weather
+ */
+
+/**
+ * Detects and responds to requests for current weather conditions in a
+ * particular location using data from a web service. Requires registering
+ * with weather.com to obtain authentication credentials, which must be
+ * stored in the configuration settings weather.partner_id and
+ * weather.license_key for the plugin to function.
+ *
+ * @category Phergie
+ * @package  Phergie_Plugin_Weather
+ * @author   Phergie Development Team <team@phergie.org>
+ * @license  http://phergie.org/license New BSD License
+ * @link     http://pear.phergie.org/package/Phergie_Plugin_Weather
+ * @link     http://www.weather.com/services/xmloap.html
+ * @uses     Phergie_Plugin_Command pear.phergie.org
+ * @uses     Phergie_Plugin_Http pear.phergie.org
+ * @uses     extension SimpleXML
+ */
+class Phergie_Plugin_Weather extends Phergie_Plugin_Abstract
+{
+    /**
+     * Checks for dependencies.
+     *
+     * @return void
+     */
+    public function onLoad()
+    {
+        $plugins = $this->getPluginHandler();
+        $plugins->getPlugin('Command');
+        $plugins->getPlugin('Http');
+
+        if (empty($this->config['weather.partner_id'])
+            || empty($this->config['weather.license_key'])) {
+            $this->fail('weather.partner_id and weather.license_key must be specified');
+        }
+    }
+
+    /**
+     * Returns a weather report for a specified location.
+     *
+     * @param string $location Zip code or city/state/country specification
+     *
+     * @return void
+     */
+    public function onCommandWeather($location)
+    {
+        $response = $this->plugins->http->get(
+            'http://xoap.weather.com/search/search',
+            array('where' => $location)
+        );
+
+        if ($response->isError()) {
+            $this->doNotice(
+                $this->event->getNick(),
+                'ERROR: ' . $response->getCode() . ' ' . $response->getMessage()
+            );
+            return;
+        }
+
+        $nick = $this->event->getNick();
+
+        $xml = $response->getContent();
+        if (count($xml->loc) == 0) {
+            $this->doNotice($nick, 'No results for that location.');
+            return;
+        }
+
+        $where = (string) $xml->loc[0]['id'];
+        $response = $this->plugins->http->get(
+            'http://xoap.weather.com/weather/local/' . $where,
+            array(
+                'cc' => '*',
+                'link' => 'xoap',
+                'prod' => 'xoap',
+                'par' => $this->config['weather.partner_id'],
+                'key' => $this->config['weather.license_key'],
+            )
+        );
+
+        if ($response->isError()) {
+            $this->doNotice(
+                $this->event->getNick(),
+                'ERROR: ' . $response->getCode() . ' ' . $response->getMessage()
+            );
+            return;
+        }
+
+        $xml = $response->getContent();
+        $weather = 'Weather for ' . (string) $xml->loc->dnam . ' - ';
+        $weather .= 'Current temperature ' .
+            (string) $xml->cc->tmp .
+            (string) $xml->head->ut . ' / ';
+        if ((string) $xml->head->ut == 'F') {
+            $weather .= round(((((int) $xml->cc->tmp - 32) * 5) / 9)) . 'C';
+        } else {
+            $weather .= round(((((int) $xml->cc->tmp * 9) / 5) + 32)) . 'F';
+        }
+        $weather .=
+            ', Relative humidity ' . (string) $xml->cc->hmid . '%' .
+            ', Current conditions ' . (string) $xml->cc->t .
+            ', Last update ' . (string) $xml->cc->lsup .
+            ' [ http://weather.com/weather/today/' .
+            str_replace(
+                array('(', ')', ',', ' '),
+                array('', '', '', '+'),
+                (string) $xml->loc->dnam
+            ) .
+            ' ]';
+
+        $this->doPrivmsg($this->event->getSource(), $nick . ': ' . $weather);
+    }
+}
index b0450a4bb28ce737540ef1634b24454a8b917577..87b4a95c68e8b043e66339eb951cd61408c7329e 100755 (executable)
@@ -12,61 +12,62 @@ return array(
             'realname' => 'Matthew Turland',
             'nick' => 'Phergie2',
             // 'password' => 'password goes here if needed',
-            // 'transport' => 'ssl' // uncomment to connect using SSL
+            // 'transport' => 'ssl', // uncomment to connect using SSL
+            // 'encoding' => 'UTF8', // uncomment if using UTF8
         )
     ),
-    
-    'processor' => 'async',    
+
+    'processor' => 'async',
     'processor.options' => array('usec' => 200000),
     // Time zone. See: http://www.php.net/manual/en/timezones.php
     'timezone' => 'UTC',
 
     // Whitelist of plugins to load
     'plugins' => array(
-        // To enable a plugin, simply add a string to this array containing 
-        // the short name of the plugin as shown below. 
+        // To enable a plugin, simply add a string to this array containing
+        // the short name of the plugin as shown below.
 
         // 'ShortPluginName',
 
-        // Below is an example of enabling the AutoJoin plugin, for which 
-        // the corresponding PEAR package is Phergie_Plugin_AutoJoin. This 
-        // plugin allows you to set a list of channels in this configuration  
-        // file that the bot will automatically join when it connects to a 
-        // server. If you'd like to enable this plugin, simply install it, 
-        // uncomment the line below, and set a value for the setting 
-        // autojoin.channels (examples for which are located further down in 
+        // Below is an example of enabling the AutoJoin plugin, for which
+        // the corresponding PEAR package is Phergie_Plugin_AutoJoin. This
+        // plugin allows you to set a list of channels in this configuration
+        // file that the bot will automatically join when it connects to a
+        // server. If you'd like to enable this plugin, simply install it,
+        // uncomment the line below, and set a value for the setting
+        // autojoin.channels (examples for which are located further down in
         // this file).
 
         // 'AutoJoin',
 
         // A few other recommended plugins:
 
-        // Servers randomly send PING events to clients to ensure that 
-        // they're still connected and will eventually terminate the 
-        
-        // connection if a PONG response is not received. The Pong plugin 
+        // Servers randomly send PING events to clients to ensure that
+        // they're still connected and will eventually terminate the
+
+        // connection if a PONG response is not received. The Pong plugin
         // handles sending these responses.
 
-        // 'Pong', 
+        // 'Pong',
 
-        // It's sometimes difficult to distinguish between a lack of 
-        // activity on a server and the client not receiving data even 
-        // though a connection remains open. The Ping plugin performs a self 
-        // CTCP PING sporadically to ensure that its connection is still 
+        // It's sometimes difficult to distinguish between a lack of
+        // activity on a server and the client not receiving data even
+        // though a connection remains open. The Ping plugin performs a self
+        // CTCP PING sporadically to ensure that its connection is still
         // functioning and, if not, terminates the bot.
 
         // 'Ping',
 
-        // Sometimes it's desirable to have the bot disconnect gracefully 
-        // when issued a command to do so via a PRIVMSG event. The Quit 
-        // plugin implements this using the Command plugin to intercept the 
+        // Sometimes it's desirable to have the bot disconnect gracefully
+        // when issued a command to do so via a PRIVMSG event. The Quit
+        // plugin implements this using the Command plugin to intercept the
         // command.
 
         // 'Quit',
     ),
 
-    // If set to true, this allows any plugin dependencies for plugins 
-    // listed in the 'plugins' option to be loaded even if they are not 
+    // If set to true, this allows any plugin dependencies for plugins
+    // listed in the 'plugins' option to be loaded even if they are not
     // explicitly included in that list
     'plugins.autoload' => true,
 
@@ -83,13 +84,13 @@ return array(
 
     // Examples of setting values for Ping plugin settings
 
-    // This is the amount of time in seconds that the Ping plugin will wait 
-    // to receive an event from the server before it initiates a self-ping 
+    // This is the amount of time in seconds that the Ping plugin will wait
+    // to receive an event from the server before it initiates a self-ping
 
     // 'ping.event' => 300, // 5 minutes
 
-    // This is the amount of time in seconds that the Ping plugin will wait 
-    // following a self-ping attempt before it assumes that a response will 
+    // This is the amount of time in seconds that the Ping plugin will wait
+    // following a self-ping attempt before it assumes that a response will
     // never be received and terminates the connection
 
     // 'ping.ping' => 10, // 10 seconds
index b359c11554732d42b9cc39cd08bba9fa86e38d97..0d6ac454a8913c8a58df85d8fcba17fd4de81548 100644 (file)
@@ -37,6 +37,41 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
      */
     protected $handler;
 
+    /**
+     * Mock Phergie_Config instance passed to the plugin handler constructor
+     *
+     * @var Phergie_Config
+     */
+    protected $config;
+
+    /**
+     * Mock Phergie_Event_Handler instance passed to the plugin handler
+     * constructor
+     *
+     * @var Phergie_Event_Handler
+     */
+    protected $events;
+
+    /**
+     * Returns a mock plugin instance.
+     *
+     * @param string $name    Optional short name for the mock plugin, defaults
+     *        to 'TestPlugin'
+     * @param array  $methods Optional list of methods to override
+     *
+     * @return Phergie_Plugin_Abstract
+     */
+    protected function getMockPlugin($name = 'TestPlugin', array $methods = array())
+    {
+        $methods[] = 'getName';
+        $plugin = $this->getMock('Phergie_Plugin_Abstract', $methods);
+        $plugin
+            ->expects($this->any())
+            ->method('getName')
+            ->will($this->returnValue($name));
+        return $plugin;
+    }
+
     /**
      * Sets up a new handler instance before each test.
      *
@@ -44,69 +79,191 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
      */
     public function setUp()
     {
+        $this->config = $this->getMock('Phergie_Config');
+        $this->events = $this->getMock('Phergie_Event_Handler');
         $this->handler = new Phergie_Plugin_Handler(
-            new Phergie_Config(),
-            new Phergie_Event_Handler()
+            $this->config,
+            $this->events
         );
     }
 
     /**
-     * Destroys the handler instance after each test
+     * Tests iterability of the plugin handler.
      *
      * @return void
      */
-    public function tearDown()
+    public function testImplementsIteratorAggregate()
     {
-        unset($this->handler);
+        $reflection = new ReflectionObject($this->handler);
+
+        $this->assertTrue(
+            $reflection->implementsInterface('IteratorAggregate'),
+            'Handler does not implement IteratorAggregate'
+        );
+
+        $this->assertType(
+            'Iterator',
+            $this->handler->getIterator(),
+            'getIterator() must return an iterator'
+        );
     }
 
     /**
-     * Ensures that we can iterate over the handler
+     * Tests countability of the plugin handler.
      *
      * @return void
      */
-    public function testImplementsIterator()
+    public function testImplementsCountable()
     {
         $reflection = new ReflectionObject($this->handler);
+
         $this->assertTrue(
-            $reflection->implementsInterface('IteratorAggregate')
+            $reflection->implementsInterface('Countable'),
+            'Handler does not implement Countable'
         );
 
         $this->assertType(
-            'Iterator', $this->handler->getIterator(),
-            'getIterator() must actually return an Iterator'
+            'int',
+            count($this->handler),
+            'count() must return an integer'
         );
     }
 
     /**
-     * Ensures a newly instantiated handler does not have plugins associated
-     * with it
+     * Tests the plugin handler exposing added plugins as instance
+     * properties of the handler via isset().
      *
-     * @depends testImplementsIterator
      * @return void
      */
-    public function testEmptyHandlerHasNoPlugins()
+    public function testImplementsIsset()
+    {
+        $pluginName = 'TestPlugin';
+        $this->assertFalse(isset($this->handler->{$pluginName}));
+        $plugin = $this->getMockPlugin($pluginName);
+        $this->handler->addPlugin($plugin);
+        $this->assertTrue(isset($this->handler->{$pluginName}));
+    }
+
+    /**
+     * Tests the plugin handler exposing added plugins as instance
+     * properties of the handler.
+     *
+     * @depends testImplementsIsset
+     * @return void
+     */
+    public function testImplementsGet()
+    {
+        $plugin = $this->getMockPlugin();
+        $this->handler->addPlugin($plugin);
+        $name = $plugin->getName();
+        $getPlugin = $this->handler->getPlugin($name);
+        $this->assertTrue(isset($this->handler->$name));
+        $get = $this->handler->$name;
+        $this->assertSame($getPlugin, $get);
+    }
+
+    /**
+     * Tests the plugin handler allowing for plugin removal via unset().
+     *
+     * @depends testImplementsGet
+     * @return void
+     */
+    public function testImplementsUnset()
+    {
+        $plugin = $this->getMockPlugin();
+        $this->handler->addPlugin($plugin);
+        unset($this->handler->{$plugin->getName()});
+        $this->assertFalse($this->handler->hasPlugin($plugin->getName()));
+    }
+
+    /**
+     * Tests the plugin handler executing a callback on all contained
+     * plugins where one plugin short-circuits the process.
+     *
+     * @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()
     {
-        $count = 0;
-        foreach ($this->handler as $plugin) {
-            $count++;
+        foreach (range(1, 2) as $index) {
+            $plugin = $this->getMockPlugin('TestPlugin' . $index, array('callback'));
+            $plugin
+                ->expects($this->once())
+                ->method('callback');
+            $this->handler->addPlugin($plugin);
         }
 
-        $this->assertEquals(0, $count);
+        $this->assertTrue($this->handler->callback());
     }
-    
+
     /**
-     * Ensures a newly instantiated handler does not default to autoload
+     * Tests a newly instantiated handler not having plugins associated with
+     * it.
      *
+     * @depends testImplementsCountable
      * @return void
      */
-    public function testDefaultsToNotAutoload()
+    public function testEmptyHandlerHasNoPlugins()
+    {
+        $this->assertEquals(0, count($this->handler));
+    }
+
+    /**
+     * Tests a newly instantiated handler not having autoloading enabled by
+     * default.
+     *
+     * @return void
+     */
+    public function testGetAutoloadDefaultsToNotAutoload()
     {
         $this->assertFalse($this->handler->getAutoload());
     }
 
     /**
-     * addPath provides a fluent interface
+     * Tests setAutoload().
+     *
+     * @depends testGetAutoloadDefaultsToNotAutoload
+     * @return void
+     */
+    public function testSetAutoload()
+    {
+        $this->assertSame(
+            $this->handler->setAutoload(true),
+            $this->handler,
+            'setAutoload() does not provide a fluent interface'
+        );
+
+        $this->assertTrue(
+            $this->handler->getAutoload(),
+            'setAutoload() had no effect on getAutoload()'
+        );
+    }
+
+    /**
+     * Tests addPath() providing a fluent interface.
      *
      * @return void
      */
@@ -117,7 +274,8 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
     }
 
     /**
-     * addPath throws an exception when it cannot read the directory
+     * Tests addPath() throwing an exception when it cannot read the
+     * directory.
      *
      * @return void
      */
@@ -133,122 +291,113 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
             return;
         }
 
-        $this->fail('An expected exception has not been raised.');
+        $this->fail('An expected exception has not been raised');
     }
 
     /**
-     * adds a path into the plugin handler and then ensures that files
-     * in that location can be found
+     * Tests adding a path to the plugin handler.
      *
      * @return void
      */
     public function testAddPath()
     {
-        $plugin_name = 'Mock';
+        $pluginName = 'Mock';
+
         try {
-            $this->handler->addPlugin($plugin_name);
+            $this->handler->addPlugin($pluginName);
         } catch(Phergie_Plugin_Exception $e) {
             $this->assertEquals(
                 Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND,
                 $e->getCode()
             );
-            
-            $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
-
-            try {
-                $this->handler->addPlugin($plugin_name);
-            } catch(Phergie_Plugin_Exception $e) {
-                $this->fail(
-                    'After adding the directory, the plugin was still '
-                    . 'not found.'
-                );
-            }
-            
-            return;
         }
 
-        $this->fail(
-            'Before adding the directory, an expected exception '
-            . 'was not raised'
-        );
+        if (!isset($e)) {
+            $this->fail('Plugin loaded, path was already present');
+        }
+
+        $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
+
+        try {
+            $this->handler->addPlugin($pluginName);
+        } catch(Phergie_Plugin_Exception $e) {
+            $this->fail('Added path, plugin still not found');
+        }
     }
 
     /**
-     * addPlugin returns the plugin instance that was added
+     * Tests addPlugin() returning an added plugin instance.
      *
      * @return void
      */
-    public function testAddPluginByInstanceReturnsPluginInstance() {
-        $plugin = $this->getMock('Phergie_Plugin_Abstract');
-        $plugin
-            ->expects($this->any())
-            ->method('getName')
-            ->will($this->returnValue('TestPlugin'));
-
-        $returned_plugin = $this->handler->addPlugin($plugin);
+    public function testAddPluginByInstanceReturnsPluginInstance()
+    {
+        $plugin = $this->getMockPlugin();
+        $returnedPlugin = $this->handler->addPlugin($plugin);
         $this->assertSame(
-            $returned_plugin,
+            $returnedPlugin,
             $plugin,
-            'addPlugin returns the same instance that is passed to it'
+            'addPlugin() does not return the instance passed to it'
         );
     }
 
     /**
-     * Can add a plugin to the handler by shortname
+     * Tests adding a plugin to the handler using the plugin's short name.
      *
      * @return void
      */
-    public function testAddPluginToHandlerByShortname()
+    public function testAddPluginByShortName()
     {
-        $plugin_name = 'Mock';
+        $pluginName = 'Mock';
         $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
 
-        $returned_plugin = $this->handler->addPlugin($plugin_name);
-        $this->assertTrue($this->handler->hasPlugin($plugin_name));
+        $returnedPlugin = $this->handler->addPlugin($pluginName);
+        $this->assertTrue($this->handler->hasPlugin($pluginName));
+
         $this->assertType(
             'Phergie_Plugin_Mock',
-            $this->handler->getPlugin($plugin_name)
+            $this->handler->getPlugin($pluginName)
         );
+
         $this->assertSame(
-            $this->handler->getPlugin($plugin_name),
-            $returned_plugin,
-            'Handler contains plugin when added by shortname.'
+            $this->handler->getPlugin($pluginName),
+            $returnedPlugin,
+            'Handler does not contain added plugin'
         );
     }
 
 
     /**
-     * Can add a plugin to the handler by instance
+     * Tests adding a plugin instance to the handler.
      *
      * @return void
      */
-    public function testAddPluginToHandlerByInstance()
+    public function testAddPluginByInstance()
     {
-        $plugin = $this->getMock('Phergie_Plugin_Abstract');
-        $plugin
-            ->expects($this->any())
-            ->method('getName')
-            ->will($this->returnValue('TestPlugin'));
-
-        $returned_plugin = $this->handler->addPlugin($plugin);
-
+        $plugin = $this->getMockPlugin();
+        $returnedPlugin = $this->handler->addPlugin($plugin);
         $this->assertTrue($this->handler->hasPlugin('TestPlugin'));
+
         $this->assertSame(
-            $plugin, $returned_plugin,
-            'addPlugin returns the same plugin'
+            $plugin,
+            $returnedPlugin,
+            'addPlugin() does not return added plugin instance'
         );
+
         $this->assertSame(
-            $plugin, $this->handler->getPlugin('TestPlugin'),
-            'getPlugin returns the same plugin'
+            $plugin,
+            $this->handler->getPlugin('TestPlugin'),
+            'getPlugin() does not return added plugin instance'
         );
     }
 
     /**
-     * addPlugin throws an exception when it can't find the plugin
+     * Tests addPlugin() throwing an exception when the plugin class file
+     * can't be found.
      *
      * @return void
      */
-    public function testAddPluginThrowsExceptionIfCannotFindPlugin()
+    public function testAddPluginThrowsExceptionWhenPluginFileNotFound()
     {
         try {
             $this->handler->addPlugin('TestPlugin');
@@ -260,12 +409,68 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
             return;
         }
 
-        $this->fail('An expected exception has not been raised.');
+        $this->fail('An expected exception has not been raised');
+    }
+
+    /**
+     * Recursively removes all files and subdirectories in a directory.
+     *
+     * @param string $path Directory path
+     * @return void
+     */
+    private function removeDirectory($path)
+    {
+        if (file_exists($path)) {
+            $it = new RecursiveIteratorIterator(
+                new RecursiveDirectoryIterator($path),
+                RecursiveIteratorIterator::CHILD_FIRST
+            );
+            foreach ($it as $entry) {
+                if ($it->isDot()) {
+                    continue;
+                }
+                if ($entry->isDir()) {
+                    rmdir($entry->getPathname());
+                } else {
+                    unlink($entry->getPathname());
+                }
+            }
+        }
+    }
+
+    /**
+     * Tests addPlugin() throwing an exception when the plugin class file is
+     * found, but does not contain the plugin class as expected.
+     *
+     * @return void
+     */
+    public function testAddPluginThrowsExceptionWhenPluginClassNotFound()
+    {
+        $path = sys_get_temp_dir() . '/Phergie/Plugin';
+        $this->removeDirectory(dirname($path));
+        mkdir($path, 0777, true);
+        touch($path . '/TestPlugin.php');
+        $this->handler->addPath($path, 'Phergie_Plugin_');
+
+        try {
+            $this->handler->addPlugin('TestPlugin');
+        } catch(Phergie_Plugin_Exception $e) { }
+
+        if (isset($e)) {
+            $this->assertEquals(
+                Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND,
+                $e->getCode()
+            );
+        } else {
+            $this->fail('An expected exception has not been raised');
+        }
+
+        $this->removeDirectory(dirname($path));
     }
 
     /**
-     * addPlugin throws an exception when trying to instantiate a
-     * class that doesn't extend from Phergie_Plugin_Abstract
+     * Tests addPlugin() throwing an exception when trying to instantiate a
+     * class that doesn't extend Phergie_Plugin_Abstract.
      *
      * @return void
      */
@@ -281,11 +486,11 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
             return;
         }
 
-        $this->fail('An expected exception has not been raised.');
+        $this->fail('An expected exception has not been raised');
     }
 
     /**
-     * addPlugin throws an exception when trying to instantiate a
+     * Tests addPlugin() throwing an exception when trying to instantiate a
      * class that can't be instantiated.
      *
      * @return void
@@ -303,143 +508,88 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
             return;
         }
 
-        $this->fail('An expected exception has not been raised.');
+        $this->fail('An expected exception has not been raised');
     }
 
     /**
-     * addPlugin with shortname and arguments passes args to constructor
+     * Tests adding a plugin by its short name with arguments passed to the
+     * plugin constructor.
      *
-     * @return null
+     * @return void
      */
-    public function testAddPluginShortnamePassesArgsToConstructor()
+    public function testAddPluginShortNamePassesArgsToConstructor()
     {
-        $plugin_name = 'Mock';
+        $pluginName = 'Mock';
         $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
 
         $arguments = array('a', 'b', 'c');
+        $plugin = $this->handler->addPlugin($pluginName, $arguments);
 
-        $plugin = $this->handler->addPlugin($plugin_name, $arguments);
         $this->assertAttributeSame(
             $arguments,
-            'args',
+            'arguments',
             $plugin,
-            'Arguments passed in to addPlugin match the arguments '
-            . 'the Mock plugin constructor received'
+            'Arguments do not match'
         );
     }
 
     /**
-     * addPlugin passes Phergie_Config to instantiated plugin
+     * Tests addPlugin() passing Phergie_Config to an instantiated plugin.
      *
-     * @return null
+     * @return void
      */
-    public function testAddPluginPassesPhergieConfigToInstantiatedPlugin()
+    public function testAddPluginPassesConstructorArguments()
     {
-        $my_config = new Phergie_Config();
-        $my_config['my_option'] = 'my_value';
-
-        // create a new handler with this config
-        unset($this->handler);
-        $this->handler = new Phergie_Plugin_Handler(
-            $my_config,
-            new Phergie_Event_Handler()
-        );
-
-        $plugin_name = 'Mock';
+        $pluginName = 'Mock';
         $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
-
-        $plugin = $this->handler->addPlugin($plugin_name);
+        $plugin = $this->handler->addPlugin($pluginName);
 
         $this->assertSame(
-            $my_config,
+            $this->config,
             $plugin->getConfig(),
-            'addPlugin passes Phergie_Config to instantiated plugin'
+            'Phergie_Config instances do not match'
         );
-    }
-
-    /**
-     * addPlugin passes Phergie_Event_Handler to instantiated plugin
-     *
-     * @return null
-     */
-    public function testAddPluginPassesPhergieEventHandlerToInstantiatedPlugin()
-    {
-        $plugin = $this->getMock('Phergie_Plugin_Abstract');
-        $plugin
-            ->expects($this->any())
-            ->method('getName')
-            ->will($this->returnValue('TestPlugin'));
-
-        $my_event_handler = new Phergie_Event_Handler();
-        $my_event_handler->addEvent($plugin, 'ping');
-
-        // create a new plugin handler with this event handler
-        unset($this->handler);
-        $this->handler = new Phergie_Plugin_Handler(
-            new Phergie_Config(),
-            $my_event_handler
-        );
-
-        $plugin_name = 'Mock';
-        $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
-
-        $plugin = $this->handler->addPlugin($plugin_name);
 
         $this->assertSame(
-            $my_event_handler,
+            $this->events,
             $plugin->getEventHandler(),
-            'addPlugin passes Phergie_Event_Handler to instantiated plugin'
+            'Phergie_Event_Handler instances do not match'
         );
     }
 
     /**
-     * @todo addPlugin calls onLoad() to instantiated plugin
-     */
-
-    /**
-     * implements __isset
+     * Tests addPlugin() calling onLoad() on an instantiated plugin.
      *
      * @return void
      */
-    public function testPluginHandlerImplementsIsset()
+    public function testAddPluginCallsOnLoadOnInstantiatedPlugin()
     {
-        $plugin_name = 'TestPlugin';
-
-        $this->assertFalse(isset($this->handler->{$plugin_name}));
-
-        $plugin = $this->getMock('Phergie_Plugin_Abstract');
+        $plugin = $this->getMockPlugin(null, array('onLoad'));
         $plugin
-            ->expects($this->any())
-            ->method('getName')
-            ->will($this->returnValue($plugin_name));
-
+            ->expects($this->once())
+            ->method('onLoad');
         $this->handler->addPlugin($plugin);
-
-        $this->assertTrue(isset($this->handler->{$plugin_name}));
-
     }
 
     /**
-     * addPlugin() returns the same plugin when requested twice
+     * Tests addPlugin() returning the same plugin when called twice.
      *
      * @return void
      */
     public function testAddPluginReturnsSamePluginWhenAskedTwice()
     {
-        $plugin_name = 'Mock';
+        $pluginName = 'Mock';
         $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
-
-        $plugin1 = $this->handler->addPlugin($plugin_name);
-        $plugin2 = $this->handler->addPlugin($plugin_name);
+        $plugin1 = $this->handler->addPlugin($pluginName);
+        $plugin2 = $this->handler->addPlugin($pluginName);
         $this->assertSame($plugin1, $plugin2);
     }
 
-    
     /**
-     * Tests an exception is thrown when trying to get a plugin
-     * that is not already loaded and autoload is off
+     * Tests getPlugin() throwing an exception when trying to get an
+     * unloaded plugin with autoload disabled.
      *
-     * @depends testDefaultsToNotAutoload
+     * @depends testGetAutoloadDefaultsToNotAutoload
      * @return void
      */
     public function testExceptionThrownWhenLoadingPluginWithoutAutoload()
@@ -456,6 +606,134 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
             return;
         }
 
-        $this->fail('An expected exception has not been raised.');
+        $this->fail('An expected exception has not been raised');
+    }
+
+    /**
+     * Tests addPlugins() with a plugin short name and no plugin constructor
+     * arguments.
+     *
+     * @depends testAddPluginByShortName
+     * @depends testAddPluginByInstance
+     * @return void
+     */
+    public function testAddPluginsWithoutArguments()
+    {
+        $prefix = 'Phergie_Plugin_';
+        $this->handler->addPath(dirname(__FILE__), $prefix);
+
+        $plugin = 'Mock';
+        $this->handler->addPlugins(array($plugin));
+        $returnedPlugin = $this->handler->getPlugin($plugin);
+        $this->assertContains(
+            get_class($returnedPlugin),
+            $prefix . $plugin,
+            'Short name plugin not of expected class'
+        );
+    }
+
+    /**
+     * Tests addPlugins() with a plugin short name and plugin constructor
+     * arguments.
+     *
+     * @depends testAddPluginByShortName
+     * @depends testAddPluginByInstance
+     * @return void
+     */
+    public function testAddPluginsWithArguments()
+    {
+        $prefix = 'Phergie_Plugin_';
+        $this->handler->addPath(dirname(__FILE__), $prefix);
+
+        $arguments = array(1, 2, 3);
+        $plugin = array('Mock', $arguments);
+        $this->handler->addPlugins(array($plugin));
+        $returnedPlugin = $this->handler->getPlugin('Mock');
+        $this->assertEquals(
+            $arguments,
+            $returnedPlugin->getArguments(),
+            'Constructor arguments for instance plugin do not match'
+        );
+    }
+
+    /**
+     * Tests removePlugin() with a plugin instance.
+     *
+     * @depends testAddPluginByInstance
+     * @return void
+     */
+    public function testRemovePluginByInstance()
+    {
+        $plugin = $this->getMockPlugin();
+        $this->handler->addPlugin($plugin);
+        $this->handler->removePlugin($plugin);
+        $this->assertFalse(
+            $this->handler->hasPlugin($plugin->getName()),
+            'Plugin was not removed'
+        );
+    }
+
+    /**
+     * Tests removePlugin() with a plugin short name.
+     *
+     * @depends testAddPluginByShortName
+     * @return void
+     */
+    public function testRemovePluginByShortName()
+    {
+        $plugin = 'Mock';
+        $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
+
+        $this->handler->addPlugin($plugin);
+        $this->handler->removePlugin($plugin);
+        $this->assertFalse(
+            $this->handler->hasPlugin($plugin),
+            'Plugin was not removed'
+        );
+    }
+
+    /**
+     * Tests getPlugin() when the plugin is not already loaded and
+     * autoloading is disabled.
+     *
+     * @depends testSetAutoload
+     * @return void
+     */
+    public function testGetPluginWithAutoloadEnabled()
+    {
+        $this->handler->setAutoload(true);
+        $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
+        $plugin = $this->handler->getPlugin('Mock');
+        $this->assertType(
+            'Phergie_Plugin_Mock',
+            $plugin,
+            'Retrieved plugin not of expected class'
+        );
+    }
+
+    /**
+     * Tests getPlugins().
+     *
+     * @depends testGetPluginWithAutoloadEnabled
+     * @return void
+     */
+    public function testGetPlugins()
+    {
+        $plugin1 = $this->getMockPlugin('TestPlugin1');
+        $this->handler->addPlugin($plugin1);
+
+        $plugin2 = $this->getMockPlugin('TestPlugin2');
+        $this->handler->addPlugin($plugin2);
+
+        $expected = array(
+            'testplugin1' => $plugin1,
+            'testplugin2' => $plugin2,
+        );
+
+        $actual = $this->handler->getPlugins();
+        $this->assertEquals($expected, $actual);
+
+        $actual = $this->handler->getPlugins(array('testplugin1', 'testplugin2'));
+        $this->assertEquals($expected, $actual);
     }
 }
index 714e3d9a44c531af24657cc0c509c9951b5f8b5f..44a5d11c7c0597aa2dce9cbde5dbc50701fb9f5f 100755 (executable)
@@ -21,7 +21,7 @@
 
 /**
  * Creates a plugin on the filesystem that can be used by
- * Phergie_Plugin_Handler's addPath utility to be located and loaded.
+ * Phergie_Plugin_Handler::addPath() to be located and loaded.
  *
  * @category Phergie
  * @package  Phergie_Tests
 class Phergie_Plugin_Mock extends Phergie_Plugin_Abstract
 {
     /**
-     * holds the arguments that were passed in to the constructor
+     * Arguments passed to the constructor
+     *
      * @var array
      */
-    protected $args;
+    protected $arguments;
 
     /**
-     * processes a variable number of arguments into the args property
+     * Stores all arguments for later use.
      *
-     * @return null
+     * @return void
      */
     public function __construct()
     {
-        $this->args = func_get_args();
+        $this->arguments = func_get_args();
+    }
+
+    /**
+     * Returns all constructor arguments.
+     *
+     * @return array Enumerated array containing the arguments passed to the
+     *         constructor in order
+     */
+    public function getArguments()
+    {
+        return $this->arguments;
     }
 }
diff --git a/plugins/Irc/extlib/phergie/Tests/Phergie/Plugin/SpellCheckTest.php b/plugins/Irc/extlib/phergie/Tests/Phergie/Plugin/SpellCheckTest.php
new file mode 100644 (file)
index 0000000..8ed9f0d
--- /dev/null
@@ -0,0 +1,205 @@
+<?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
+ */
+
+require_once dirname(__FILE__) . '/TestCase.php';
+
+/**
+ * Unit test suite for Pherge_Plugin_SpellCheck.
+ *
+ * @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
+ */
+class Phergie_Plugin_SpellCheckTest extends Phergie_Plugin_TestCase
+{
+
+    /**
+     * Current SpellCheck plugin instance
+     *
+     * @var Phergie_Plugin_SpellCheck
+     */
+    protected $spell;
+
+    /**
+     * Sets up the fixture, for example, opens a network connection.
+     * This method is called before a test is executed.
+     * 
+     * @return void
+     */
+    protected function setUp()
+    {
+        $this->config = array('spellcheck.lang' => 'en');
+
+        $this->spell = new Phergie_Plugin_SpellCheck();
+        $this->setPlugin(new Phergie_Plugin_Command());
+        
+        $config = $this->plugin->getConfig();
+        
+        $handler = new Phergie_Plugin_Handler($config, $this->handler);
+        $this->plugin->setPluginHandler($handler);
+        
+        $handler->addPlugin($this->plugin);
+        $handler->addPlugin($this->spell);
+
+        $this->spell->setEventHandler($this->handler);
+        $this->spell->setConnection($this->connection);
+    }
+
+    /**
+     * @event Phergie_Event_Request::privmsg
+     * @eventArg #zftalk
+     * @eventArg spell
+     */
+    public function testSpell()
+    {
+        $this->spell->onLoad();
+        
+        $this->copyEvent();
+        $this->plugin->onPrivMsg();
+        $this->assertDoesNotHaveEvent(Phergie_Event_Command::TYPE_PRIVMSG);
+    }
+
+    /**
+     * @event Phergie_Event_Request::privmsg
+     * @eventArg #phergie
+     * @eventArg spell test
+     */
+    public function testSpellTest()
+    {
+        $this->spell->onLoad();
+        
+        $this->copyEvent();
+        $this->plugin->onPrivMsg();
+
+        $events = $this->getResponseEvents(Phergie_Event_Command::TYPE_PRIVMSG);
+        
+        $this->assertEquals(1, count($events));
+        foreach ($events as $event) {
+            $args = $event->getArguments();
+            
+            $this->assertEquals('#phergie', $args[0]);
+            
+            $this->assertContains('CheckSpellUser:', $args[1]);
+            $this->assertContains('test', $args[1]);
+            $this->assertContains('correct', $args[1]);
+        }            
+    }
+
+    /**
+     * @event Phergie_Event_Request::privmsg
+     * @eventArg #phergie
+     * @eventArg spell testz
+     */
+    public function testSpellTestz()
+    {
+        $this->spell->onLoad();
+        
+        $this->copyEvent();
+        $this->plugin->onPrivMsg();
+        
+        $events = $this->getResponseEvents(Phergie_Event_Command::TYPE_PRIVMSG);
+        
+        $this->assertEquals(1, count($events));
+        foreach ($events as $event) {
+            $args = $event->getArguments();
+            
+            $this->assertEquals('#phergie', $args[0]);
+            
+            $this->assertContains('CheckSpellUser:', $args[1]);
+            $this->assertRegExp('/([a-z]+, ){4}/', $args[1]);
+            $this->assertContains('testz', $args[1]);
+            $this->assertContains('test,', $args[1]);
+        }
+    }
+
+    /**
+     * @event Phergie_Event_Request::privmsg
+     * @eventArg #phergie
+     * @eventArg spell testz
+     */
+    public function testSpellMoreSuggestions()
+    {
+        $config = $this->spell->getConfig();
+        
+        $this->copyEvent();
+        $config['spellcheck.limit'] = 6;
+        
+        $this->spell->onLoad();
+        $this->plugin->onPrivMsg();
+        
+        $events = $this->getResponseEvents(Phergie_Event_Command::TYPE_PRIVMSG);
+        
+        $this->assertEquals(1, count($events));
+        foreach ($events as $event) {
+            $args = $event->getArguments();
+            
+            $this->assertEquals('#phergie', $args[0]);
+            
+            $this->assertContains('CheckSpellUser:', $args[1]);
+            $this->assertRegExp('/([a-z]+, ){5}/', $args[1]);
+            $this->assertContains('testz', $args[1]);
+            $this->assertContains('test,', $args[1]);
+        }
+    }
+
+    /**
+     * @event Phergie_Event_Request::privmsg
+     * @eventArg #phergie
+     * @eventArg spell qwertyuiopasdfghjklzxcvbnm
+     */
+    public function testSpellNoSuggestions()
+    {
+        $this->spell->onLoad();
+        
+        $this->copyEvent();
+        $this->plugin->onPrivMsg();
+        
+        $events = $this->getResponseEvents(Phergie_Event_Command::TYPE_PRIVMSG);
+        
+        $this->assertEquals(1, count($events));
+        foreach ($events as $event) {
+            $args = $event->getArguments();
+            
+            $this->assertEquals('#phergie', $args[0]);
+            
+            $this->assertContains('CheckSpellUser:', $args[1]);
+            $this->assertContains('find any suggestions', $args[1]);
+        }
+    }
+    
+    /**
+     * Copy event from command to spell plugin
+     * 
+     * @return void
+     */
+    protected function copyEvent()
+    {
+        $hostmask = Phergie_Hostmask::fromString('CheckSpellUser!test@testing.org');
+
+        $event = $this->plugin->getEvent();
+        $event->setHostmask($hostmask);
+
+        $this->spell->setEvent($event);
+    }
+
+}
index 6593539bc16056fa219b4b2847f4830741f1944b..e70af44562445d8f957bb8ac56a765ee2845845f 100644 (file)
@@ -12,7 +12,7 @@
  * http://phergie.org/license
  *
  * @category  Phergie
- * @package   Phergie_Tests 
+ * @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
index 9b84014ed5c3033accf6a1d4dcd87726297b65e4..7510c75a1509405b89df67aa84a0ab2498b1d998 100644 (file)
@@ -45,6 +45,9 @@
             <include name="Phergie/Connection/Exception.php" />
             <include name="Phergie/Connection/Handler.php" />
             <include name="Phergie/Connection.php" />
+            <include name="Phergie/Db/Exception.php" />
+            <include name="Phergie/Db/Manager.php" />
+            <include name="Phergie/Db/Sqlite.php" />
             <include name="Phergie/Driver/Abstract.php" />
             <include name="Phergie/Driver/Exception.php" />
             <include name="Phergie/Driver/Streams.php" />