]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Move standalone plugin files into subdirectories so they can have locale data, etc...
authorBrion Vibber <brion@pobox.com>
Wed, 15 Sep 2010 21:09:23 +0000 (14:09 -0700)
committerBrion Vibber <brion@pobox.com>
Wed, 15 Sep 2010 21:10:18 +0000 (14:10 -0700)
38 files changed:
plugins/APC/APCPlugin.php [new file with mode: 0644]
plugins/APCPlugin.php [deleted file]
plugins/BlogspamNet/BlogspamNetPlugin.php [new file with mode: 0644]
plugins/BlogspamNetPlugin.php [deleted file]
plugins/CacheLog/CacheLogPlugin.php [new file with mode: 0644]
plugins/CacheLogPlugin.php [deleted file]
plugins/DiskCache/DiskCachePlugin.php [new file with mode: 0644]
plugins/DiskCachePlugin.php [deleted file]
plugins/Disqus/DisqusPlugin.php [new file with mode: 0644]
plugins/DisqusPlugin.php [deleted file]
plugins/Echo/EchoPlugin.php [new file with mode: 0644]
plugins/EchoPlugin.php [deleted file]
plugins/GeoURL/GeoURLPlugin.php [new file with mode: 0644]
plugins/GeoURLPlugin.php [deleted file]
plugins/Geonames/GeonamesPlugin.php [new file with mode: 0644]
plugins/GeonamesPlugin.php [deleted file]
plugins/GoogleAnalytics/GoogleAnalyticsPlugin.php [new file with mode: 0644]
plugins/GoogleAnalyticsPlugin.php [deleted file]
plugins/Linkback/LinkbackPlugin.php [new file with mode: 0644]
plugins/LinkbackPlugin.php [deleted file]
plugins/Memcache/MemcachePlugin.php [new file with mode: 0644]
plugins/MemcachePlugin.php [deleted file]
plugins/Memcached/MemcachedPlugin.php [new file with mode: 0644]
plugins/MemcachedPlugin.php [deleted file]
plugins/PiwikAnalytics/PiwikAnalyticsPlugin.php [new file with mode: 0644]
plugins/PiwikAnalyticsPlugin.php [deleted file]
plugins/Spotify/SpotifyPlugin.php [new file with mode: 0644]
plugins/SpotifyPlugin.php [deleted file]
plugins/SubscriptionThrottle/SubscriptionThrottlePlugin.php [new file with mode: 0644]
plugins/SubscriptionThrottlePlugin.php [deleted file]
plugins/Template/TemplatePlugin.php [new file with mode: 0644]
plugins/TemplatePlugin.php [deleted file]
plugins/UserLimit/UserLimitPlugin.php [new file with mode: 0644]
plugins/UserLimitPlugin.php [deleted file]
plugins/WikiHashtags/WikiHashtagsPlugin.php [new file with mode: 0644]
plugins/WikiHashtagsPlugin.php [deleted file]
plugins/XCache/XCachePlugin.php [new file with mode: 0644]
plugins/XCachePlugin.php [deleted file]

diff --git a/plugins/APC/APCPlugin.php b/plugins/APC/APCPlugin.php
new file mode 100644 (file)
index 0000000..666f64b
--- /dev/null
@@ -0,0 +1,119 @@
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * Plugin to implement cache interface for APC variable cache
+ *
+ * PHP version 5
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Cache
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    // This check helps protect against security problems;
+    // your code file can't be executed directly from the web.
+    exit(1);
+}
+
+/**
+ * A plugin to use APC's variable cache for the cache interface
+ *
+ * New plugin interface lets us use alternative cache systems
+ * for caching. This one uses APC's variable cache.
+ *
+ * @category  Cache
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+class APCPlugin extends Plugin
+{
+    /**
+     * Get a value associated with a key
+     *
+     * The value should have been set previously.
+     *
+     * @param string &$key   in; Lookup key
+     * @param mixed  &$value out; value associated with key
+     *
+     * @return boolean hook success
+     */
+
+    function onStartCacheGet(&$key, &$value)
+    {
+        $value = apc_fetch($key);
+        Event::handle('EndCacheGet', array($key, &$value));
+        return false;
+    }
+
+    /**
+     * Associate a value with a key
+     *
+     * @param string  &$key     in; Key to use for lookups
+     * @param mixed   &$value   in; Value to associate
+     * @param integer &$flag    in; Flag (passed through to Memcache)
+     * @param integer &$expiry  in; Expiry (passed through to Memcache)
+     * @param boolean &$success out; Whether the set was successful
+     *
+     * @return boolean hook success
+     */
+
+    function onStartCacheSet(&$key, &$value, &$flag, &$expiry, &$success)
+    {
+        $success = apc_store($key, $value, ((is_null($expiry)) ? 0 : $expiry));
+
+        Event::handle('EndCacheSet', array($key, $value, $flag,
+                                           $expiry));
+        return false;
+    }
+
+    /**
+     * Delete a value associated with a key
+     *
+     * @param string  &$key     in; Key to lookup
+     * @param boolean &$success out; whether it worked
+     *
+     * @return boolean hook success
+     */
+
+    function onStartCacheDelete(&$key, &$success)
+    {
+        $success = apc_delete($key);
+        Event::handle('EndCacheDelete', array($key));
+        return false;
+    }
+
+    function onPluginVersion(&$versions)
+    {
+        $versions[] = array('name' => 'APC',
+                            'version' => STATUSNET_VERSION,
+                            'author' => 'Evan Prodromou',
+                            'homepage' => 'http://status.net/wiki/Plugin:APC',
+                            'rawdescription' =>
+                            _m('Use the <a href="http://pecl.php.net/package/apc">APC</a> variable cache to cache query results.'));
+        return true;
+    }
+}
+
diff --git a/plugins/APCPlugin.php b/plugins/APCPlugin.php
deleted file mode 100644 (file)
index 666f64b..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, StatusNet, Inc.
- *
- * Plugin to implement cache interface for APC variable cache
- *
- * PHP version 5
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Cache
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2009 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    // This check helps protect against security problems;
-    // your code file can't be executed directly from the web.
-    exit(1);
-}
-
-/**
- * A plugin to use APC's variable cache for the cache interface
- *
- * New plugin interface lets us use alternative cache systems
- * for caching. This one uses APC's variable cache.
- *
- * @category  Cache
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2009 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-class APCPlugin extends Plugin
-{
-    /**
-     * Get a value associated with a key
-     *
-     * The value should have been set previously.
-     *
-     * @param string &$key   in; Lookup key
-     * @param mixed  &$value out; value associated with key
-     *
-     * @return boolean hook success
-     */
-
-    function onStartCacheGet(&$key, &$value)
-    {
-        $value = apc_fetch($key);
-        Event::handle('EndCacheGet', array($key, &$value));
-        return false;
-    }
-
-    /**
-     * Associate a value with a key
-     *
-     * @param string  &$key     in; Key to use for lookups
-     * @param mixed   &$value   in; Value to associate
-     * @param integer &$flag    in; Flag (passed through to Memcache)
-     * @param integer &$expiry  in; Expiry (passed through to Memcache)
-     * @param boolean &$success out; Whether the set was successful
-     *
-     * @return boolean hook success
-     */
-
-    function onStartCacheSet(&$key, &$value, &$flag, &$expiry, &$success)
-    {
-        $success = apc_store($key, $value, ((is_null($expiry)) ? 0 : $expiry));
-
-        Event::handle('EndCacheSet', array($key, $value, $flag,
-                                           $expiry));
-        return false;
-    }
-
-    /**
-     * Delete a value associated with a key
-     *
-     * @param string  &$key     in; Key to lookup
-     * @param boolean &$success out; whether it worked
-     *
-     * @return boolean hook success
-     */
-
-    function onStartCacheDelete(&$key, &$success)
-    {
-        $success = apc_delete($key);
-        Event::handle('EndCacheDelete', array($key));
-        return false;
-    }
-
-    function onPluginVersion(&$versions)
-    {
-        $versions[] = array('name' => 'APC',
-                            'version' => STATUSNET_VERSION,
-                            'author' => 'Evan Prodromou',
-                            'homepage' => 'http://status.net/wiki/Plugin:APC',
-                            'rawdescription' =>
-                            _m('Use the <a href="http://pecl.php.net/package/apc">APC</a> variable cache to cache query results.'));
-        return true;
-    }
-}
-
diff --git a/plugins/BlogspamNet/BlogspamNetPlugin.php b/plugins/BlogspamNet/BlogspamNetPlugin.php
new file mode 100644 (file)
index 0000000..d52e600
--- /dev/null
@@ -0,0 +1,145 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Plugin to check submitted notices with blogspam.net
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Plugin
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @author    Brion Vibber <brion@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+define('BLOGSPAMNETPLUGIN_VERSION', '0.1');
+
+/**
+ * Plugin to check submitted notices with blogspam.net
+ *
+ * When new notices are saved, we check their text with blogspam.net (or
+ * a compatible service).
+ *
+ * Blogspam.net is supposed to catch blog comment spam, and I found that
+ * some of its tests (min/max size, bayesian match) gave a lot of false positives.
+ * So, I've turned those tests off by default. This may not get as many
+ * hits, but it's better than nothing.
+ *
+ * @category Plugin
+ * @package  StatusNet
+ * @author   Evan Prodromou <evan@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ *
+ * @see      Event
+ */
+
+class BlogspamNetPlugin extends Plugin
+{
+    var $baseUrl = 'http://test.blogspam.net:8888/';
+
+    function __construct($url=null)
+    {
+        parent::__construct();
+        if ($url) {
+            $this->baseUrl = $url;
+        }
+    }
+
+    function onStartNoticeSave($notice)
+    {
+        $args = $this->testArgs($notice);
+        common_debug("Blogspamnet args = " . print_r($args, TRUE));
+        $requestBody = xmlrpc_encode_request('testComment', array($args));
+
+        $request = new HTTPClient($this->baseUrl, HTTPClient::METHOD_POST);
+        $request->setHeader('Content-Type', 'text/xml');
+        $request->setBody($requestBody);
+        $httpResponse = $request->send();
+
+        $response = xmlrpc_decode($httpResponse->getBody());
+        if (xmlrpc_is_fault($response)) {
+            throw new ServerException("$response[faultString] ($response[faultCode])", 500);
+        } else {
+            common_debug("Blogspamnet results = " . $response);
+            if (preg_match('/^ERROR(:(.*))?$/', $response, $match)) {
+                throw new ServerException(sprintf(_("Error from %s: %s"), $this->baseUrl, $match[2]), 500);
+            } else if (preg_match('/^SPAM(:(.*))?$/', $response, $match)) {
+                throw new ClientException(sprintf(_("Spam checker results: %s"), $match[2]), 400);
+            } else if (preg_match('/^OK$/', $response)) {
+                // don't do anything
+            } else {
+                throw new ServerException(sprintf(_("Unexpected response from %s: %s"), $this->baseUrl, $response), 500);
+            }
+        }
+        return true;
+    }
+
+    function testArgs($notice)
+    {
+        $args = array();
+        $args['comment'] = $notice->content;
+        $args['ip'] = $this->getClientIP();
+
+        if (isset($_SERVER) && array_key_exists('HTTP_USER_AGENT', $_SERVER)) {
+            $args['agent'] = $_SERVER['HTTP_USER_AGENT'];
+        }
+
+        $profile = $notice->getProfile();
+
+        if ($profile && $profile->homepage) {
+            $args['link'] = $profile->homepage;
+        }
+
+        if ($profile && $profile->fullname) {
+            $args['name'] = $profile->fullname;
+        } else {
+            $args['name'] = $profile->nickname;
+        }
+
+        $args['site'] = common_root_url();
+        $args['version'] = $this->userAgent();
+
+        $args['options'] = "max-size=" . common_config('site','textlimit') . ",min-size=0,min-words=0,exclude=bayasian";
+
+        return $args;
+    }
+
+    function getClientIP()
+    {
+        if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
+            // Note: order matters here; use proxy-forwarded stuff first
+            foreach (array('HTTP_X_FORWARDED_FOR', 'CLIENT-IP', 'REMOTE_ADDR') as $k) {
+                if (isset($_SERVER[$k])) {
+                    return $_SERVER[$k];
+                }
+            }
+        }
+        return '127.0.0.1';
+    }
+
+    function userAgent()
+    {
+        return 'BlogspamNetPlugin/'.BLOGSPAMNETPLUGIN_VERSION . ' StatusNet/' . STATUSNET_VERSION;
+    }
+}
diff --git a/plugins/BlogspamNetPlugin.php b/plugins/BlogspamNetPlugin.php
deleted file mode 100644 (file)
index d52e600..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Plugin to check submitted notices with blogspam.net
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Plugin
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @author    Brion Vibber <brion@status.net>
- * @copyright 2009 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    exit(1);
-}
-
-define('BLOGSPAMNETPLUGIN_VERSION', '0.1');
-
-/**
- * Plugin to check submitted notices with blogspam.net
- *
- * When new notices are saved, we check their text with blogspam.net (or
- * a compatible service).
- *
- * Blogspam.net is supposed to catch blog comment spam, and I found that
- * some of its tests (min/max size, bayesian match) gave a lot of false positives.
- * So, I've turned those tests off by default. This may not get as many
- * hits, but it's better than nothing.
- *
- * @category Plugin
- * @package  StatusNet
- * @author   Evan Prodromou <evan@status.net>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://status.net/
- *
- * @see      Event
- */
-
-class BlogspamNetPlugin extends Plugin
-{
-    var $baseUrl = 'http://test.blogspam.net:8888/';
-
-    function __construct($url=null)
-    {
-        parent::__construct();
-        if ($url) {
-            $this->baseUrl = $url;
-        }
-    }
-
-    function onStartNoticeSave($notice)
-    {
-        $args = $this->testArgs($notice);
-        common_debug("Blogspamnet args = " . print_r($args, TRUE));
-        $requestBody = xmlrpc_encode_request('testComment', array($args));
-
-        $request = new HTTPClient($this->baseUrl, HTTPClient::METHOD_POST);
-        $request->setHeader('Content-Type', 'text/xml');
-        $request->setBody($requestBody);
-        $httpResponse = $request->send();
-
-        $response = xmlrpc_decode($httpResponse->getBody());
-        if (xmlrpc_is_fault($response)) {
-            throw new ServerException("$response[faultString] ($response[faultCode])", 500);
-        } else {
-            common_debug("Blogspamnet results = " . $response);
-            if (preg_match('/^ERROR(:(.*))?$/', $response, $match)) {
-                throw new ServerException(sprintf(_("Error from %s: %s"), $this->baseUrl, $match[2]), 500);
-            } else if (preg_match('/^SPAM(:(.*))?$/', $response, $match)) {
-                throw new ClientException(sprintf(_("Spam checker results: %s"), $match[2]), 400);
-            } else if (preg_match('/^OK$/', $response)) {
-                // don't do anything
-            } else {
-                throw new ServerException(sprintf(_("Unexpected response from %s: %s"), $this->baseUrl, $response), 500);
-            }
-        }
-        return true;
-    }
-
-    function testArgs($notice)
-    {
-        $args = array();
-        $args['comment'] = $notice->content;
-        $args['ip'] = $this->getClientIP();
-
-        if (isset($_SERVER) && array_key_exists('HTTP_USER_AGENT', $_SERVER)) {
-            $args['agent'] = $_SERVER['HTTP_USER_AGENT'];
-        }
-
-        $profile = $notice->getProfile();
-
-        if ($profile && $profile->homepage) {
-            $args['link'] = $profile->homepage;
-        }
-
-        if ($profile && $profile->fullname) {
-            $args['name'] = $profile->fullname;
-        } else {
-            $args['name'] = $profile->nickname;
-        }
-
-        $args['site'] = common_root_url();
-        $args['version'] = $this->userAgent();
-
-        $args['options'] = "max-size=" . common_config('site','textlimit') . ",min-size=0,min-words=0,exclude=bayasian";
-
-        return $args;
-    }
-
-    function getClientIP()
-    {
-        if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
-            // Note: order matters here; use proxy-forwarded stuff first
-            foreach (array('HTTP_X_FORWARDED_FOR', 'CLIENT-IP', 'REMOTE_ADDR') as $k) {
-                if (isset($_SERVER[$k])) {
-                    return $_SERVER[$k];
-                }
-            }
-        }
-        return '127.0.0.1';
-    }
-
-    function userAgent()
-    {
-        return 'BlogspamNetPlugin/'.BLOGSPAMNETPLUGIN_VERSION . ' StatusNet/' . STATUSNET_VERSION;
-    }
-}
diff --git a/plugins/CacheLog/CacheLogPlugin.php b/plugins/CacheLog/CacheLogPlugin.php
new file mode 100644 (file)
index 0000000..4c47de8
--- /dev/null
@@ -0,0 +1,121 @@
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * Logs cache access
+ *
+ * PHP version 5
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Cache
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    // This check helps protect against security problems;
+    // your code file can't be executed directly from the web.
+    exit(1);
+}
+
+/**
+ * Log cache access
+ *
+ * Note that since most caching plugins return false for StartCache*
+ * methods, you should add this plugin before them, i.e.
+ *
+ *     addPlugin('CacheLog');
+ *     addPlugin('XCache');
+ *
+ * @category  Cache
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link      http://status.net/
+ */
+
+class CacheLogPlugin extends Plugin
+{
+    function onStartCacheGet(&$key, &$value)
+    {
+        $this->log(LOG_INFO, "Fetching key '$key'");
+        return true;
+    }
+
+    function onEndCacheGet($key, &$value)
+    {
+        if ($value === false) {
+            $this->log(LOG_INFO, "Cache MISS for key '$key'");
+        } else {
+            $this->log(LOG_INFO, "Cache HIT for key '$key'");
+        }
+        return true;
+    }
+
+    function onStartCacheSet(&$key, &$value, &$flag, &$expiry, &$success)
+    {
+        if (empty($value)) {
+            if (is_array($value)) {
+                $this->log(LOG_INFO, "Setting empty array for key '$key'");
+            } else if (is_null($value)) {
+                $this->log(LOG_INFO, "Setting null value for key '$key'");
+            } else if (is_string($value)) {
+                $this->log(LOG_INFO, "Setting empty string for key '$key'");
+            } else if (is_integer($value)) {
+                $this->log(LOG_INFO, "Setting integer 0 for key '$key'");
+            } else {
+                $this->log(LOG_INFO, "Setting empty value '$value' for key '$key'");
+            }
+        } else {
+            $this->log(LOG_INFO, "Setting non-empty value for key '$key'");
+        }
+        return true;
+    }
+
+    function onEndCacheSet($key, $value, $flag, $expiry)
+    {
+        $this->log(LOG_INFO, "Done setting cache value for key '$key'");
+        return true;
+    }
+
+    function onStartCacheDelete(&$key, &$success)
+    {
+        $this->log(LOG_INFO, "Deleting cache value for key '$key'");
+        return true;
+    }
+
+    function onEndCacheDelete($key)
+    {
+        $this->log(LOG_INFO, "Done deleting cache value for key '$key'");
+        return true;
+    }
+
+    function onPluginVersion(&$versions)
+    {
+        $versions[] = array('name' => 'CacheLog',
+                            'version' => STATUSNET_VERSION,
+                            'author' => 'Evan Prodromou',
+                            'homepage' => 'http://status.net/wiki/Plugin:CacheLog',
+                            'description' =>
+                            _m('Log reads and writes to the cache'));
+        return true;
+    }
+}
+
diff --git a/plugins/CacheLogPlugin.php b/plugins/CacheLogPlugin.php
deleted file mode 100644 (file)
index 4c47de8..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, StatusNet, Inc.
- *
- * Logs cache access
- *
- * PHP version 5
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Cache
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2009 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    // This check helps protect against security problems;
-    // your code file can't be executed directly from the web.
-    exit(1);
-}
-
-/**
- * Log cache access
- *
- * Note that since most caching plugins return false for StartCache*
- * methods, you should add this plugin before them, i.e.
- *
- *     addPlugin('CacheLog');
- *     addPlugin('XCache');
- *
- * @category  Cache
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2009 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link      http://status.net/
- */
-
-class CacheLogPlugin extends Plugin
-{
-    function onStartCacheGet(&$key, &$value)
-    {
-        $this->log(LOG_INFO, "Fetching key '$key'");
-        return true;
-    }
-
-    function onEndCacheGet($key, &$value)
-    {
-        if ($value === false) {
-            $this->log(LOG_INFO, "Cache MISS for key '$key'");
-        } else {
-            $this->log(LOG_INFO, "Cache HIT for key '$key'");
-        }
-        return true;
-    }
-
-    function onStartCacheSet(&$key, &$value, &$flag, &$expiry, &$success)
-    {
-        if (empty($value)) {
-            if (is_array($value)) {
-                $this->log(LOG_INFO, "Setting empty array for key '$key'");
-            } else if (is_null($value)) {
-                $this->log(LOG_INFO, "Setting null value for key '$key'");
-            } else if (is_string($value)) {
-                $this->log(LOG_INFO, "Setting empty string for key '$key'");
-            } else if (is_integer($value)) {
-                $this->log(LOG_INFO, "Setting integer 0 for key '$key'");
-            } else {
-                $this->log(LOG_INFO, "Setting empty value '$value' for key '$key'");
-            }
-        } else {
-            $this->log(LOG_INFO, "Setting non-empty value for key '$key'");
-        }
-        return true;
-    }
-
-    function onEndCacheSet($key, $value, $flag, $expiry)
-    {
-        $this->log(LOG_INFO, "Done setting cache value for key '$key'");
-        return true;
-    }
-
-    function onStartCacheDelete(&$key, &$success)
-    {
-        $this->log(LOG_INFO, "Deleting cache value for key '$key'");
-        return true;
-    }
-
-    function onEndCacheDelete($key)
-    {
-        $this->log(LOG_INFO, "Done deleting cache value for key '$key'");
-        return true;
-    }
-
-    function onPluginVersion(&$versions)
-    {
-        $versions[] = array('name' => 'CacheLog',
-                            'version' => STATUSNET_VERSION,
-                            'author' => 'Evan Prodromou',
-                            'homepage' => 'http://status.net/wiki/Plugin:CacheLog',
-                            'description' =>
-                            _m('Log reads and writes to the cache'));
-        return true;
-    }
-}
-
diff --git a/plugins/DiskCache/DiskCachePlugin.php b/plugins/DiskCache/DiskCachePlugin.php
new file mode 100644 (file)
index 0000000..b709ea3
--- /dev/null
@@ -0,0 +1,168 @@
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * Plugin to implement cache interface with disk files
+ *
+ * PHP version 5
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Cache
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    // This check helps protect against security problems;
+    // your code file can't be executed directly from the web.
+    exit(1);
+}
+
+/**
+ * A plugin to cache data on local disk
+ *
+ * @category  Cache
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+class DiskCachePlugin extends Plugin
+{
+    var $root = '/tmp';
+
+    function keyToFilename($key)
+    {
+        return $this->root . '/' . str_replace(':', '/', $key);
+    }
+
+    /**
+     * Get a value associated with a key
+     *
+     * The value should have been set previously.
+     *
+     * @param string &$key   in; Lookup key
+     * @param mixed  &$value out; value associated with key
+     *
+     * @return boolean hook success
+     */
+
+    function onStartCacheGet(&$key, &$value)
+    {
+        $filename = $this->keyToFilename($key);
+
+        if (file_exists($filename)) {
+            $data = file_get_contents($filename);
+            if ($data !== false) {
+                $value = unserialize($data);
+            }
+        }
+
+        Event::handle('EndCacheGet', array($key, &$value));
+        return false;
+    }
+
+    /**
+     * Associate a value with a key
+     *
+     * @param string  &$key     in; Key to use for lookups
+     * @param mixed   &$value   in; Value to associate
+     * @param integer &$flag    in; Flag (passed through to Memcache)
+     * @param integer &$expiry  in; Expiry (passed through to Memcache)
+     * @param boolean &$success out; Whether the set was successful
+     *
+     * @return boolean hook success
+     */
+
+    function onStartCacheSet(&$key, &$value, &$flag, &$expiry, &$success)
+    {
+        $filename = $this->keyToFilename($key);
+        $parent = dirname($filename);
+
+        $sofar = '';
+
+        foreach (explode('/', $parent) as $part) {
+            if (empty($part)) {
+                continue;
+            }
+            $sofar .= '/' . $part;
+            if (!is_dir($sofar)) {
+                $this->debug("Creating new directory '$sofar'");
+                $success = mkdir($sofar, 0750);
+                if (!$success) {
+                    $this->log(LOG_ERR, "Can't create directory '$sofar'");
+                    return false;
+                }
+            }
+        }
+
+        if (is_dir($filename)) {
+            $success = false;
+            return false;
+        }
+
+        // Write to a temp file and move to destination
+
+        $tempname = tempnam(null, 'statusnetdiskcache');
+
+        $result = file_put_contents($tempname, serialize($value));
+
+        if ($result === false) {
+            $this->log(LOG_ERR, "Couldn't write '$key' to temp file '$tempname'");
+            return false;
+        }
+
+        $result = rename($tempname, $filename);
+
+        if (!$result) {
+            $this->log(LOG_ERR, "Couldn't move temp file '$tempname' to path '$filename' for key '$key'");
+            @unlink($tempname);
+            return false;
+        }
+
+        Event::handle('EndCacheSet', array($key, $value, $flag,
+                                           $expiry));
+
+        return false;
+    }
+
+    /**
+     * Delete a value associated with a key
+     *
+     * @param string  &$key     in; Key to lookup
+     * @param boolean &$success out; whether it worked
+     *
+     * @return boolean hook success
+     */
+
+    function onStartCacheDelete(&$key, &$success)
+    {
+        $filename = $this->keyToFilename($key);
+
+        if (file_exists($filename) && !is_dir($filename)) {
+            unlink($filename);
+        }
+
+        Event::handle('EndCacheDelete', array($key));
+        return false;
+    }
+}
+
diff --git a/plugins/DiskCachePlugin.php b/plugins/DiskCachePlugin.php
deleted file mode 100644 (file)
index b709ea3..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, StatusNet, Inc.
- *
- * Plugin to implement cache interface with disk files
- *
- * PHP version 5
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Cache
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2009 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    // This check helps protect against security problems;
-    // your code file can't be executed directly from the web.
-    exit(1);
-}
-
-/**
- * A plugin to cache data on local disk
- *
- * @category  Cache
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2009 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-class DiskCachePlugin extends Plugin
-{
-    var $root = '/tmp';
-
-    function keyToFilename($key)
-    {
-        return $this->root . '/' . str_replace(':', '/', $key);
-    }
-
-    /**
-     * Get a value associated with a key
-     *
-     * The value should have been set previously.
-     *
-     * @param string &$key   in; Lookup key
-     * @param mixed  &$value out; value associated with key
-     *
-     * @return boolean hook success
-     */
-
-    function onStartCacheGet(&$key, &$value)
-    {
-        $filename = $this->keyToFilename($key);
-
-        if (file_exists($filename)) {
-            $data = file_get_contents($filename);
-            if ($data !== false) {
-                $value = unserialize($data);
-            }
-        }
-
-        Event::handle('EndCacheGet', array($key, &$value));
-        return false;
-    }
-
-    /**
-     * Associate a value with a key
-     *
-     * @param string  &$key     in; Key to use for lookups
-     * @param mixed   &$value   in; Value to associate
-     * @param integer &$flag    in; Flag (passed through to Memcache)
-     * @param integer &$expiry  in; Expiry (passed through to Memcache)
-     * @param boolean &$success out; Whether the set was successful
-     *
-     * @return boolean hook success
-     */
-
-    function onStartCacheSet(&$key, &$value, &$flag, &$expiry, &$success)
-    {
-        $filename = $this->keyToFilename($key);
-        $parent = dirname($filename);
-
-        $sofar = '';
-
-        foreach (explode('/', $parent) as $part) {
-            if (empty($part)) {
-                continue;
-            }
-            $sofar .= '/' . $part;
-            if (!is_dir($sofar)) {
-                $this->debug("Creating new directory '$sofar'");
-                $success = mkdir($sofar, 0750);
-                if (!$success) {
-                    $this->log(LOG_ERR, "Can't create directory '$sofar'");
-                    return false;
-                }
-            }
-        }
-
-        if (is_dir($filename)) {
-            $success = false;
-            return false;
-        }
-
-        // Write to a temp file and move to destination
-
-        $tempname = tempnam(null, 'statusnetdiskcache');
-
-        $result = file_put_contents($tempname, serialize($value));
-
-        if ($result === false) {
-            $this->log(LOG_ERR, "Couldn't write '$key' to temp file '$tempname'");
-            return false;
-        }
-
-        $result = rename($tempname, $filename);
-
-        if (!$result) {
-            $this->log(LOG_ERR, "Couldn't move temp file '$tempname' to path '$filename' for key '$key'");
-            @unlink($tempname);
-            return false;
-        }
-
-        Event::handle('EndCacheSet', array($key, $value, $flag,
-                                           $expiry));
-
-        return false;
-    }
-
-    /**
-     * Delete a value associated with a key
-     *
-     * @param string  &$key     in; Key to lookup
-     * @param boolean &$success out; whether it worked
-     *
-     * @return boolean hook success
-     */
-
-    function onStartCacheDelete(&$key, &$success)
-    {
-        $filename = $this->keyToFilename($key);
-
-        if (file_exists($filename) && !is_dir($filename)) {
-            unlink($filename);
-        }
-
-        Event::handle('EndCacheDelete', array($key));
-        return false;
-    }
-}
-
diff --git a/plugins/Disqus/DisqusPlugin.php b/plugins/Disqus/DisqusPlugin.php
new file mode 100644 (file)
index 0000000..c07eaaa
--- /dev/null
@@ -0,0 +1,171 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Plugin to add Disqus commenting to notice pages
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Plugin
+ * @package   StatusNet
+ * @author    Zach Copley <zach@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+/**
+ *
+ * This plugin adds Disqus commenting to your notices. Enabling this
+ * plugin will make each notice page display the Disqus widget, and
+ * notice lists will display the number of commments each notice has.
+ *
+ * To use this plugin, you need to first register your site with Disqus
+ * and get a Discus 'shortname' for it.
+ *
+ *    http://disqus.com
+ *
+ * To enable the plugin, put the following in you config.php:
+ *
+ * addPlugin(
+ *   'Disqus', array(
+ *       'shortname' => 'YOURSHORTNAME',
+ *      'div_style' => 'width:675px; padding-top:10px; position:relative; float:left;'
+ *   )
+ * );
+ *
+ * NOTE: the 'div_style' in an optional parameter that passes in some
+ * inline CSS when creating the Disqus widget. It's a shortcut to make
+ * the widget look OK with the default StatusNet theme. If you leave
+ * it out you'll have to edit your theme CSS files to make the widget
+ * look good.  You can also control the way the widget looks by
+ * adding style rules to your theme.
+ *
+ * See: http://help.disqus.com/entries/100878-css-customization
+ *
+ * @category Plugin
+ * @package  StatusNet
+ * @author   Zach Copley <zach@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ *
+ * @see      Event
+ */
+
+class DisqusPlugin extends Plugin
+{
+    function onEndShowContentBlock($action)
+    {
+        if (get_class($action) == 'ShownoticeAction') {
+
+            $attrs = array();
+            $attrs['id'] = 'disqus_thread';
+
+            if ($this->div_style) {
+                $attrs['style'] = $this->div_style;
+            }
+
+            $action->element('div', $attrs, null);
+
+            $script = <<<ENDOFSCRIPT
+var disqus_identifier = %d;
+  (function() {
+   var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
+   dsq.src = 'http://%s.disqus.com/embed.js';
+   (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
+  })();
+ENDOFSCRIPT;
+
+            $action->inlineScript(sprintf($script, $action->notice->id, $this->shortname));
+
+            $attrs = array();
+
+            $attrs['id'] = 'disqus_thread_footer';
+
+            if ($this->div_style) {
+                $attrs['style'] = $this->div_style;
+            }
+
+            $action->elementStart('div', $attrs);
+            $action->elementStart('noscript');
+
+            $action->raw('Please enable JavaScript to view the ');
+            $noscriptUrl = 'http://disqus.com/?ref_noscript=' . $this->shortname;
+            $action->element('a', array('href' => $noscriptUrl), 'comments powered by Disqus.');
+            $action->elementEnd('noscript');
+
+            $action->elementStart('a', array('href' => 'http://disqus.com', 'class' => 'dsq-brlink'));
+            $action->raw('blog comments powered by ');
+            $action->element('span', array('class' => 'logo-disqus'), 'Disqus');
+            $action->elementEnd('a');
+            $action->elementEnd('div');
+        }
+    }
+
+    function onEndShowScripts($action)
+    {
+        // fugly
+        $script = <<<ENDOFSCRIPT
+var disqus_shortname = '%s';
+(function () {
+  var s = document.createElement('script'); s.async = true;
+  s.src = 'http://disqus.com/forums/%s/count.js';
+  (document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
+}());
+ENDOFSCRIPT;
+        $action->inlineScript(sprintf($script, $this->shortname, $this->shortname));
+
+        return true;
+    }
+
+    function onStartShowNoticeItem($noticeListItem)
+    {
+        if (empty($noticeListItem->notice->is_local)) {
+            return true;
+        }
+
+        $noticeListItem->showNotice();
+        $noticeListItem->showNoticeInfo();
+
+        $noticeUrl = $noticeListItem->notice->bestUrl();
+        $noticeUrl .= '#disqus_thread';
+
+        $noticeListItem->out->element(
+            'a', array('href' => $noticeUrl, 'class' => 'disqus_count'), 'Comments'
+        );
+
+        $noticeListItem->showNoticeOptions();
+        Event::handle('EndShowNoticeItem', array($noticeListItem));
+
+        return false;
+    }
+
+    function onPluginVersion(&$versions)
+    {
+        $versions[] = array('name' => 'Disqus',
+                            'version' => STATUSNET_VERSION,
+                            'author' => 'Zach Copley',
+                            'homepage' => 'http://status.net/wiki/Plugin:Disqus',
+                            'rawdescription' =>
+                            _m('Use <a href="http://disqus.com/">Disqus</a>'.
+                               ' to add commenting to notice pages.'));
+        return true;
+    }
+}
diff --git a/plugins/DisqusPlugin.php b/plugins/DisqusPlugin.php
deleted file mode 100644 (file)
index c07eaaa..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Plugin to add Disqus commenting to notice pages
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Plugin
- * @package   StatusNet
- * @author    Zach Copley <zach@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    exit(1);
-}
-
-/**
- *
- * This plugin adds Disqus commenting to your notices. Enabling this
- * plugin will make each notice page display the Disqus widget, and
- * notice lists will display the number of commments each notice has.
- *
- * To use this plugin, you need to first register your site with Disqus
- * and get a Discus 'shortname' for it.
- *
- *    http://disqus.com
- *
- * To enable the plugin, put the following in you config.php:
- *
- * addPlugin(
- *   'Disqus', array(
- *       'shortname' => 'YOURSHORTNAME',
- *      'div_style' => 'width:675px; padding-top:10px; position:relative; float:left;'
- *   )
- * );
- *
- * NOTE: the 'div_style' in an optional parameter that passes in some
- * inline CSS when creating the Disqus widget. It's a shortcut to make
- * the widget look OK with the default StatusNet theme. If you leave
- * it out you'll have to edit your theme CSS files to make the widget
- * look good.  You can also control the way the widget looks by
- * adding style rules to your theme.
- *
- * See: http://help.disqus.com/entries/100878-css-customization
- *
- * @category Plugin
- * @package  StatusNet
- * @author   Zach Copley <zach@status.net>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://status.net/
- *
- * @see      Event
- */
-
-class DisqusPlugin extends Plugin
-{
-    function onEndShowContentBlock($action)
-    {
-        if (get_class($action) == 'ShownoticeAction') {
-
-            $attrs = array();
-            $attrs['id'] = 'disqus_thread';
-
-            if ($this->div_style) {
-                $attrs['style'] = $this->div_style;
-            }
-
-            $action->element('div', $attrs, null);
-
-            $script = <<<ENDOFSCRIPT
-var disqus_identifier = %d;
-  (function() {
-   var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
-   dsq.src = 'http://%s.disqus.com/embed.js';
-   (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
-  })();
-ENDOFSCRIPT;
-
-            $action->inlineScript(sprintf($script, $action->notice->id, $this->shortname));
-
-            $attrs = array();
-
-            $attrs['id'] = 'disqus_thread_footer';
-
-            if ($this->div_style) {
-                $attrs['style'] = $this->div_style;
-            }
-
-            $action->elementStart('div', $attrs);
-            $action->elementStart('noscript');
-
-            $action->raw('Please enable JavaScript to view the ');
-            $noscriptUrl = 'http://disqus.com/?ref_noscript=' . $this->shortname;
-            $action->element('a', array('href' => $noscriptUrl), 'comments powered by Disqus.');
-            $action->elementEnd('noscript');
-
-            $action->elementStart('a', array('href' => 'http://disqus.com', 'class' => 'dsq-brlink'));
-            $action->raw('blog comments powered by ');
-            $action->element('span', array('class' => 'logo-disqus'), 'Disqus');
-            $action->elementEnd('a');
-            $action->elementEnd('div');
-        }
-    }
-
-    function onEndShowScripts($action)
-    {
-        // fugly
-        $script = <<<ENDOFSCRIPT
-var disqus_shortname = '%s';
-(function () {
-  var s = document.createElement('script'); s.async = true;
-  s.src = 'http://disqus.com/forums/%s/count.js';
-  (document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
-}());
-ENDOFSCRIPT;
-        $action->inlineScript(sprintf($script, $this->shortname, $this->shortname));
-
-        return true;
-    }
-
-    function onStartShowNoticeItem($noticeListItem)
-    {
-        if (empty($noticeListItem->notice->is_local)) {
-            return true;
-        }
-
-        $noticeListItem->showNotice();
-        $noticeListItem->showNoticeInfo();
-
-        $noticeUrl = $noticeListItem->notice->bestUrl();
-        $noticeUrl .= '#disqus_thread';
-
-        $noticeListItem->out->element(
-            'a', array('href' => $noticeUrl, 'class' => 'disqus_count'), 'Comments'
-        );
-
-        $noticeListItem->showNoticeOptions();
-        Event::handle('EndShowNoticeItem', array($noticeListItem));
-
-        return false;
-    }
-
-    function onPluginVersion(&$versions)
-    {
-        $versions[] = array('name' => 'Disqus',
-                            'version' => STATUSNET_VERSION,
-                            'author' => 'Zach Copley',
-                            'homepage' => 'http://status.net/wiki/Plugin:Disqus',
-                            'rawdescription' =>
-                            _m('Use <a href="http://disqus.com/">Disqus</a>'.
-                               ' to add commenting to notice pages.'));
-        return true;
-    }
-}
diff --git a/plugins/Echo/EchoPlugin.php b/plugins/Echo/EchoPlugin.php
new file mode 100644 (file)
index 0000000..7b51866
--- /dev/null
@@ -0,0 +1,116 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Plugin to add Echo/JS-Kit commenting to notice pages
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Plugin
+ * @package   StatusNet
+ * @author    Zach Copley <zach@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+/**
+ * Plugin to use Echo (formerly JS-Kit)
+ *
+ * This plugin adds an Echo commenting widget to each notice page on
+ * your site.  To get it to work, first you'll have to sign up for Echo
+ * (a for-pay service) and register your site's URL.
+ *
+ *     http://aboutecho.com/
+ *
+ * Once you've done that it's pretty straight forward to turn the
+ * plugin on; just add this to your config.php:
+ *
+ *     addPlugin(
+ *        'Echo',
+ *        array('div_style' => 'width:675px; padding-top:10px; position:relative; float:left;')
+ *     );
+ *
+ * NOTE: the 'div_style' in an optional parameter that passes in some
+ * inline CSS when creating the Echo widget. It's a shortcut to make
+ * the widget look OK with the default StatusNet theme. If you leave
+ * it out you'll have to edit your theme CSS files to make the widget
+ * look good. You can also control the way the widget looks by
+ * adding style rules to your theme.
+ *
+ * See: http://wiki.js-kit.com/Skinning-Guide#UsingCSSnbsptocustomizefontsandcolors
+ *
+ * @category Plugin
+ * @package  StatusNet
+ * @author   Zach Copley <zach@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ *
+ * @see      Event
+ */
+
+class EchoPlugin extends Plugin
+{
+    // NOTE: The Echo documentation says that this script will change on
+    // a per site basis, but I think that's incorrect. It always seems to
+    // be the same.
+    public $script = 'http://cdn.js-kit.com/scripts/comments.js';
+
+    function onEndShowScripts($action)
+    {
+        if (get_class($action) == 'ShownoticeAction') {
+            $action->script($this->script);
+        }
+
+        return true;
+    }
+
+    function onEndShowContentBlock($action)
+    {
+        if (get_class($action) == 'ShownoticeAction') {
+
+            $attrs = array();
+            $attrs['class'] = 'js-kit-comments';
+            $attrs['permalink'] = $action->notice->uri;
+            $attrs['uniq'] = $action->notice->id;
+
+            // NOTE: there are some other attributes that could be useful
+            // http://wiki.js-kit.com/Echo-Behavior
+
+            if (!empty($this->div_style)) {
+                $attrs['style'] = $this->div_style;
+            }
+
+            $action->element('div', $attrs, null);
+        }
+    }
+
+    function onPluginVersion(&$versions)
+    {
+        $versions[] = array('name' => 'Echo',
+                            'version' => STATUSNET_VERSION,
+                            'author' => 'Zach Copley',
+                            'homepage' => 'http://status.net/wiki/Plugin:Echo',
+                            'rawdescription' =>
+                            _m('Use <a href="http://aboutecho.com/">Echo</a>'.
+                               ' to add commenting to notice pages.'));
+        return true;
+    }
+}
diff --git a/plugins/EchoPlugin.php b/plugins/EchoPlugin.php
deleted file mode 100644 (file)
index 7b51866..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Plugin to add Echo/JS-Kit commenting to notice pages
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Plugin
- * @package   StatusNet
- * @author    Zach Copley <zach@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    exit(1);
-}
-
-/**
- * Plugin to use Echo (formerly JS-Kit)
- *
- * This plugin adds an Echo commenting widget to each notice page on
- * your site.  To get it to work, first you'll have to sign up for Echo
- * (a for-pay service) and register your site's URL.
- *
- *     http://aboutecho.com/
- *
- * Once you've done that it's pretty straight forward to turn the
- * plugin on; just add this to your config.php:
- *
- *     addPlugin(
- *        'Echo',
- *        array('div_style' => 'width:675px; padding-top:10px; position:relative; float:left;')
- *     );
- *
- * NOTE: the 'div_style' in an optional parameter that passes in some
- * inline CSS when creating the Echo widget. It's a shortcut to make
- * the widget look OK with the default StatusNet theme. If you leave
- * it out you'll have to edit your theme CSS files to make the widget
- * look good. You can also control the way the widget looks by
- * adding style rules to your theme.
- *
- * See: http://wiki.js-kit.com/Skinning-Guide#UsingCSSnbsptocustomizefontsandcolors
- *
- * @category Plugin
- * @package  StatusNet
- * @author   Zach Copley <zach@status.net>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://status.net/
- *
- * @see      Event
- */
-
-class EchoPlugin extends Plugin
-{
-    // NOTE: The Echo documentation says that this script will change on
-    // a per site basis, but I think that's incorrect. It always seems to
-    // be the same.
-    public $script = 'http://cdn.js-kit.com/scripts/comments.js';
-
-    function onEndShowScripts($action)
-    {
-        if (get_class($action) == 'ShownoticeAction') {
-            $action->script($this->script);
-        }
-
-        return true;
-    }
-
-    function onEndShowContentBlock($action)
-    {
-        if (get_class($action) == 'ShownoticeAction') {
-
-            $attrs = array();
-            $attrs['class'] = 'js-kit-comments';
-            $attrs['permalink'] = $action->notice->uri;
-            $attrs['uniq'] = $action->notice->id;
-
-            // NOTE: there are some other attributes that could be useful
-            // http://wiki.js-kit.com/Echo-Behavior
-
-            if (!empty($this->div_style)) {
-                $attrs['style'] = $this->div_style;
-            }
-
-            $action->element('div', $attrs, null);
-        }
-    }
-
-    function onPluginVersion(&$versions)
-    {
-        $versions[] = array('name' => 'Echo',
-                            'version' => STATUSNET_VERSION,
-                            'author' => 'Zach Copley',
-                            'homepage' => 'http://status.net/wiki/Plugin:Echo',
-                            'rawdescription' =>
-                            _m('Use <a href="http://aboutecho.com/">Echo</a>'.
-                               ' to add commenting to notice pages.'));
-        return true;
-    }
-}
diff --git a/plugins/GeoURL/GeoURLPlugin.php b/plugins/GeoURL/GeoURLPlugin.php
new file mode 100644 (file)
index 0000000..01178f3
--- /dev/null
@@ -0,0 +1,131 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Plugin to add ICBM metadata to HTML pages and report data to GeoURL.org
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Action
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+/**
+ * Plugin to add ICBM metadata to HTML pages and report data to GeoURL.org
+ *
+ * Adds metadata to notice and profile pages that geourl.org and others
+ * understand. Also, pings geourl.org when a new notice is saved or
+ * a profile is changed.
+ *
+ * @category Plugin
+ * @package  StatusNet
+ * @author   Evan Prodromou <evan@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ *
+ * @seeAlso  Location
+ */
+
+class GeoURLPlugin extends Plugin
+{
+    public $ping = 'http://geourl.org/ping/';
+
+    /**
+     * Add extra <meta> headers for certain pages that geourl.org understands
+     *
+     * @param Action $action page being shown
+     *
+     * @return boolean event handler flag
+     */
+
+    function onEndShowHeadElements($action)
+    {
+        $name = $action->trimmed('action');
+
+        $location = null;
+
+        if ($name == 'showstream') {
+            $profile = $action->profile;
+            if (!empty($profile) && !empty($profile->lat) && !empty($profile->lon)) {
+                $location = $profile->lat . ', ' . $profile->lon;
+            }
+        } else if ($name == 'shownotice') {
+            $notice = $action->profile;
+            if (!empty($notice) && !empty($notice->lat) && !empty($notice->lon)) {
+                $location = $notice->lat . ', ' . $notice->lon;
+            }
+        }
+
+        if (!empty($location)) {
+            $action->element('meta', array('name' => 'ICBM',
+                                           'content' => $location));
+            $action->element('meta', array('name' => 'DC.title',
+                                           'content' => $action->title()));
+        }
+
+        return true;
+    }
+
+    /**
+     * Report local notices to GeoURL.org when they're created
+     *
+     * @param Notice &$notice queued notice
+     *
+     * @return boolean event handler flag
+     */
+
+    function onHandleQueuedNotice(&$notice)
+    {
+        if ($notice->is_local == 1) {
+
+            $request = HTTPClient::start();
+
+            $url = common_local_url('shownotice',
+                                    array('notice' => $notice->id));
+
+            try {
+                $request->post($this->ping,
+                               null,
+                               array('p' => $url));
+            } catch (HTTP_Request2_Exception $e) {
+                common_log(LOG_WARNING,
+                           "GeoURL.org ping failed for '$url' ($this->ping)");
+            }
+        }
+
+        return true;
+    }
+
+    function onPluginVersion(&$versions)
+    {
+        $versions[] = array('name' => 'GeoURL',
+                            'version' => STATUSNET_VERSION,
+                            'author' => 'Evan Prodromou',
+                            'homepage' => 'http://status.net/wiki/Plugin:GeoURL',
+                            'rawdescription' =>
+                            _m('Ping <a href="http://geourl.org/">GeoURL</a> when '.
+                               'new geolocation-enhanced notices are posted.'));
+        return true;
+    }
+}
diff --git a/plugins/GeoURLPlugin.php b/plugins/GeoURLPlugin.php
deleted file mode 100644 (file)
index 01178f3..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Plugin to add ICBM metadata to HTML pages and report data to GeoURL.org
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Action
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2009 StatusNet Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    exit(1);
-}
-
-/**
- * Plugin to add ICBM metadata to HTML pages and report data to GeoURL.org
- *
- * Adds metadata to notice and profile pages that geourl.org and others
- * understand. Also, pings geourl.org when a new notice is saved or
- * a profile is changed.
- *
- * @category Plugin
- * @package  StatusNet
- * @author   Evan Prodromou <evan@status.net>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://status.net/
- *
- * @seeAlso  Location
- */
-
-class GeoURLPlugin extends Plugin
-{
-    public $ping = 'http://geourl.org/ping/';
-
-    /**
-     * Add extra <meta> headers for certain pages that geourl.org understands
-     *
-     * @param Action $action page being shown
-     *
-     * @return boolean event handler flag
-     */
-
-    function onEndShowHeadElements($action)
-    {
-        $name = $action->trimmed('action');
-
-        $location = null;
-
-        if ($name == 'showstream') {
-            $profile = $action->profile;
-            if (!empty($profile) && !empty($profile->lat) && !empty($profile->lon)) {
-                $location = $profile->lat . ', ' . $profile->lon;
-            }
-        } else if ($name == 'shownotice') {
-            $notice = $action->profile;
-            if (!empty($notice) && !empty($notice->lat) && !empty($notice->lon)) {
-                $location = $notice->lat . ', ' . $notice->lon;
-            }
-        }
-
-        if (!empty($location)) {
-            $action->element('meta', array('name' => 'ICBM',
-                                           'content' => $location));
-            $action->element('meta', array('name' => 'DC.title',
-                                           'content' => $action->title()));
-        }
-
-        return true;
-    }
-
-    /**
-     * Report local notices to GeoURL.org when they're created
-     *
-     * @param Notice &$notice queued notice
-     *
-     * @return boolean event handler flag
-     */
-
-    function onHandleQueuedNotice(&$notice)
-    {
-        if ($notice->is_local == 1) {
-
-            $request = HTTPClient::start();
-
-            $url = common_local_url('shownotice',
-                                    array('notice' => $notice->id));
-
-            try {
-                $request->post($this->ping,
-                               null,
-                               array('p' => $url));
-            } catch (HTTP_Request2_Exception $e) {
-                common_log(LOG_WARNING,
-                           "GeoURL.org ping failed for '$url' ($this->ping)");
-            }
-        }
-
-        return true;
-    }
-
-    function onPluginVersion(&$versions)
-    {
-        $versions[] = array('name' => 'GeoURL',
-                            'version' => STATUSNET_VERSION,
-                            'author' => 'Evan Prodromou',
-                            'homepage' => 'http://status.net/wiki/Plugin:GeoURL',
-                            'rawdescription' =>
-                            _m('Ping <a href="http://geourl.org/">GeoURL</a> when '.
-                               'new geolocation-enhanced notices are posted.'));
-        return true;
-    }
-}
diff --git a/plugins/Geonames/GeonamesPlugin.php b/plugins/Geonames/GeonamesPlugin.php
new file mode 100644 (file)
index 0000000..3815a31
--- /dev/null
@@ -0,0 +1,510 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Plugin to convert string locations to Geonames IDs and vice versa
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Action
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+/**
+ * Plugin to convert string locations to Geonames IDs and vice versa
+ *
+ * This handles most of the events that Location class emits. It uses
+ * the geonames.org Web service to convert names like 'Montreal, Quebec, Canada'
+ * into IDs and lat/lon pairs.
+ *
+ * @category Plugin
+ * @package  StatusNet
+ * @author   Evan Prodromou <evan@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ *
+ * @seeAlso  Location
+ */
+
+class GeonamesPlugin extends Plugin
+{
+    const LOCATION_NS = 1;
+
+    public $host     = 'ws.geonames.org';
+    public $username = null;
+    public $token    = null;
+    public $expiry   = 7776000; // 90-day expiry
+    public $timeout  = 2;       // Web service timeout in seconds.
+    public $timeoutWindow = 60; // Further lookups in this process will be disabled for N seconds after a timeout.
+    public $cachePrefix = null; // Optional shared memcache prefix override
+                                // to share lookups between local instances.
+
+    protected $lastTimeout = null; // timestamp of last web service timeout
+
+    /**
+     * convert a name into a Location object
+     *
+     * @param string   $name      Name to convert
+     * @param string   $language  ISO code for anguage the name is in
+     * @param Location &$location Location object (may be null)
+     *
+     * @return boolean whether to continue (results in $location)
+     */
+
+    function onLocationFromName($name, $language, &$location)
+    {
+        $loc = $this->getCache(array('name' => $name,
+                                     'language' => $language));
+
+        if ($loc !== false) {
+            $location = $loc;
+            return false;
+        }
+
+        try {
+            $geonames = $this->getGeonames('search',
+                                           array('maxRows' => 1,
+                                                 'q' => $name,
+                                                 'lang' => $language,
+                                                 'type' => 'xml'));
+        } catch (Exception $e) {
+            $this->log(LOG_WARNING, "Error for $name: " . $e->getMessage());
+            return true;
+        }
+
+        if (count($geonames) == 0) {
+            // no results
+            $this->setCache(array('name' => $name,
+                                  'language' => $language),
+                            null);
+            return true;
+        }
+
+        $n = $geonames[0];
+
+        $location = new Location();
+
+        $location->lat              = $this->canonical($n->lat);
+        $location->lon              = $this->canonical($n->lng);
+        $location->names[$language] = (string)$n->name;
+        $location->location_id      = (string)$n->geonameId;
+        $location->location_ns      = self::LOCATION_NS;
+
+        $this->setCache(array('name' => $name,
+                              'language' => $language),
+                        $location);
+
+        // handled, don't continue processing!
+        return false;
+    }
+
+    /**
+     * convert an id into a Location object
+     *
+     * @param string   $id        Name to convert
+     * @param string   $ns        Name to convert
+     * @param string   $language  ISO code for language for results
+     * @param Location &$location Location object (may be null)
+     *
+     * @return boolean whether to continue (results in $location)
+     */
+
+    function onLocationFromId($id, $ns, $language, &$location)
+    {
+        if ($ns != self::LOCATION_NS) {
+            // It's not one of our IDs... keep processing
+            return true;
+        }
+
+        $loc = $this->getCache(array('id' => $id));
+
+        if ($loc !== false) {
+            $location = $loc;
+            return false;
+        }
+
+        try {
+            $geonames = $this->getGeonames('hierarchy',
+                                           array('geonameId' => $id,
+                                                 'lang' => $language));
+        } catch (Exception $e) {
+            $this->log(LOG_WARNING, "Error for ID $id: " . $e->getMessage());
+            return false;
+        }
+
+        $parts = array();
+
+        foreach ($geonames as $level) {
+            if (in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
+                $parts[] = (string)$level->name;
+            }
+        }
+
+        $last = $geonames[count($geonames)-1];
+
+        if (!in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
+            $parts[] = (string)$last->name;
+        }
+
+        $location = new Location();
+
+        $location->location_id      = (string)$last->geonameId;
+        $location->location_ns      = self::LOCATION_NS;
+        $location->lat              = $this->canonical($last->lat);
+        $location->lon              = $this->canonical($last->lng);
+
+        $location->names[$language] = implode(', ', array_reverse($parts));
+
+        $this->setCache(array('id' => (string)$last->geonameId),
+                        $location);
+
+        // We're responsible for this namespace; nobody else
+        // can resolve it
+
+        return false;
+    }
+
+    /**
+     * convert a lat/lon pair into a Location object
+     *
+     * Given a lat/lon, we try to find a Location that's around
+     * it or nearby. We prefer populated places (cities, towns, villages).
+     *
+     * @param string   $lat       Latitude
+     * @param string   $lon       Longitude
+     * @param string   $language  ISO code for language for results
+     * @param Location &$location Location object (may be null)
+     *
+     * @return boolean whether to continue (results in $location)
+     */
+
+    function onLocationFromLatLon($lat, $lon, $language, &$location)
+    {
+        // Make sure they're canonical
+
+        $lat = $this->canonical($lat);
+        $lon = $this->canonical($lon);
+
+        $loc = $this->getCache(array('lat' => $lat,
+                                     'lon' => $lon));
+
+        if ($loc !== false) {
+            $location = $loc;
+            return false;
+        }
+
+        try {
+          $geonames = $this->getGeonames('findNearbyPlaceName',
+                                         array('lat' => $lat,
+                                               'lng' => $lon,
+                                               'lang' => $language));
+        } catch (Exception $e) {
+            $this->log(LOG_WARNING, "Error for coords $lat, $lon: " . $e->getMessage());
+            return true;
+        }
+
+        if (count($geonames) == 0) {
+            // no results
+            $this->setCache(array('lat' => $lat,
+                                  'lon' => $lon),
+                            null);
+            return true;
+        }
+
+        $n = $geonames[0];
+
+        $parts = array();
+
+        $location = new Location();
+
+        $parts[] = (string)$n->name;
+
+        if (!empty($n->adminName1)) {
+            $parts[] = (string)$n->adminName1;
+        }
+
+        if (!empty($n->countryName)) {
+            $parts[] = (string)$n->countryName;
+        }
+
+        $location->location_id = (string)$n->geonameId;
+        $location->location_ns = self::LOCATION_NS;
+        $location->lat         = $this->canonical($n->lat);
+        $location->lon         = $this->canonical($n->lng);
+
+        $location->names[$language] = implode(', ', $parts);
+
+        $this->setCache(array('lat' => $lat,
+                              'lon' => $lon),
+                        $location);
+
+        // Success! We handled it, so no further processing
+
+        return false;
+    }
+
+    /**
+     * Human-readable name for a location
+     *
+     * Given a location, we try to retrieve a human-readable name
+     * in the target language.
+     *
+     * @param Location $location Location to get the name for
+     * @param string   $language ISO code for language to find name in
+     * @param string   &$name    Place to put the name
+     *
+     * @return boolean whether to continue
+     */
+
+    function onLocationNameLanguage($location, $language, &$name)
+    {
+        if ($location->location_ns != self::LOCATION_NS) {
+            // It's not one of our IDs... keep processing
+            return true;
+        }
+
+        $id = $location->location_id;
+
+        $n = $this->getCache(array('id' => $id,
+                                   'language' => $language));
+
+        if ($n !== false) {
+            $name = $n;
+            return false;
+        }
+
+        try {
+            $geonames = $this->getGeonames('hierarchy',
+                                           array('geonameId' => $id,
+                                                 'lang' => $language));
+        } catch (Exception $e) {
+            $this->log(LOG_WARNING, "Error for ID $id: " . $e->getMessage());
+            return false;
+        }
+
+        if (count($geonames) == 0) {
+            $this->setCache(array('id' => $id,
+                                  'language' => $language),
+                            null);
+            return false;
+        }
+
+        $parts = array();
+
+        foreach ($geonames as $level) {
+            if (in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
+                $parts[] = (string)$level->name;
+            }
+        }
+
+        $last = $geonames[count($geonames)-1];
+
+        if (!in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
+            $parts[] = (string)$last->name;
+        }
+
+        if (count($parts)) {
+            $name = implode(', ', array_reverse($parts));
+            $this->setCache(array('id' => $id,
+                                  'language' => $language),
+                            $name);
+        }
+
+        return false;
+    }
+
+    /**
+     * Human-readable URL for a location
+     *
+     * Given a location, we try to retrieve a geonames.org URL.
+     *
+     * @param Location $location Location to get the url for
+     * @param string   &$url     Place to put the url
+     *
+     * @return boolean whether to continue
+     */
+
+    function onLocationUrl($location, &$url)
+    {
+        if ($location->location_ns != self::LOCATION_NS) {
+            // It's not one of our IDs... keep processing
+            return true;
+        }
+
+        $url = 'http://www.geonames.org/' . $location->location_id;
+
+        // it's been filled, so don't process further.
+        return false;
+    }
+
+    /**
+     * Machine-readable name for a location
+     *
+     * Given a location, we try to retrieve a geonames.org URL.
+     *
+     * @param Location $location Location to get the url for
+     * @param string   &$url     Place to put the url
+     *
+     * @return boolean whether to continue
+     */
+
+    function onLocationRdfUrl($location, &$url)
+    {
+        if ($location->location_ns != self::LOCATION_NS) {
+            // It's not one of our IDs... keep processing
+            return true;
+        }
+
+        $url = 'http://sws.geonames.org/' . $location->location_id . '/';
+
+        // it's been filled, so don't process further.
+        return false;
+    }
+
+    function getCache($attrs)
+    {
+        $c = common_memcache();
+
+        if (empty($c)) {
+            return null;
+        }
+
+        $key = $this->cacheKey($attrs);
+
+        $value = $c->get($key);
+
+        return $value;
+    }
+
+    function setCache($attrs, $loc)
+    {
+        $c = common_memcache();
+
+        if (empty($c)) {
+            return null;
+        }
+
+        $key = $this->cacheKey($attrs);
+
+        $result = $c->set($key, $loc, 0, time() + $this->expiry);
+
+        return $result;
+    }
+
+    function cacheKey($attrs)
+    {
+        $key = 'geonames:' .
+               implode(',', array_keys($attrs)) . ':'.
+               common_keyize(implode(',', array_values($attrs)));
+        if ($this->cachePrefix) {
+            return $this->cachePrefix . ':' . $key;
+        } else {
+            return common_cache_key($key);
+        }
+    }
+
+    function wsUrl($method, $params)
+    {
+        if (!empty($this->username)) {
+            $params['username'] = $this->username;
+        }
+
+        if (!empty($this->token)) {
+            $params['token'] = $this->token;
+        }
+
+        $str = http_build_query($params, null, '&');
+
+        return 'http://'.$this->host.'/'.$method.'?'.$str;
+    }
+
+    function getGeonames($method, $params)
+    {
+        if ($this->lastTimeout && (time() - $this->lastTimeout < $this->timeoutWindow)) {
+            throw new Exception("skipping due to recent web service timeout");
+        }
+
+        $client = HTTPClient::start();
+        $client->setConfig('connect_timeout', $this->timeout);
+        $client->setConfig('timeout', $this->timeout);
+
+        try {
+            $result = $client->get($this->wsUrl($method, $params));
+        } catch (Exception $e) {
+            common_log(LOG_ERR, __METHOD__ . ": " . $e->getMessage());
+            $this->lastTimeout = time();
+            throw $e;
+        }
+
+        if (!$result->isOk()) {
+            throw new Exception("HTTP error code " . $result->getStatus());
+        }
+
+        $body = $result->getBody();
+
+        if (empty($body)) {
+            throw new Exception("Empty HTTP body in response");
+        }
+
+        // This will throw an exception if the XML is mal-formed
+
+        $document = new SimpleXMLElement($body);
+
+        // No children, usually no results
+
+        $children = $document->children();
+
+        if (count($children) == 0) {
+            return array();
+        }
+
+        if (isset($document->status)) {
+            throw new Exception("Error #".$document->status['value']." ('".$document->status['message']."')");
+        }
+
+        // Array of elements, >0 elements
+
+        return $document->geoname;
+    }
+
+    function onPluginVersion(&$versions)
+    {
+        $versions[] = array('name' => 'Geonames',
+                            'version' => STATUSNET_VERSION,
+                            'author' => 'Evan Prodromou',
+                            'homepage' => 'http://status.net/wiki/Plugin:Geonames',
+                            'rawdescription' =>
+                            _m('Uses <a href="http://geonames.org/">Geonames</a> service to get human-readable '.
+                               'names for locations based on user-provided lat/long pairs.'));
+        return true;
+    }
+
+    function canonical($coord)
+    {
+        $coord = rtrim($coord, "0");
+        $coord = rtrim($coord, ".");
+
+        return $coord;
+    }
+}
diff --git a/plugins/GeonamesPlugin.php b/plugins/GeonamesPlugin.php
deleted file mode 100644 (file)
index 3815a31..0000000
+++ /dev/null
@@ -1,510 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Plugin to convert string locations to Geonames IDs and vice versa
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Action
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2009 StatusNet Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    exit(1);
-}
-
-/**
- * Plugin to convert string locations to Geonames IDs and vice versa
- *
- * This handles most of the events that Location class emits. It uses
- * the geonames.org Web service to convert names like 'Montreal, Quebec, Canada'
- * into IDs and lat/lon pairs.
- *
- * @category Plugin
- * @package  StatusNet
- * @author   Evan Prodromou <evan@status.net>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://status.net/
- *
- * @seeAlso  Location
- */
-
-class GeonamesPlugin extends Plugin
-{
-    const LOCATION_NS = 1;
-
-    public $host     = 'ws.geonames.org';
-    public $username = null;
-    public $token    = null;
-    public $expiry   = 7776000; // 90-day expiry
-    public $timeout  = 2;       // Web service timeout in seconds.
-    public $timeoutWindow = 60; // Further lookups in this process will be disabled for N seconds after a timeout.
-    public $cachePrefix = null; // Optional shared memcache prefix override
-                                // to share lookups between local instances.
-
-    protected $lastTimeout = null; // timestamp of last web service timeout
-
-    /**
-     * convert a name into a Location object
-     *
-     * @param string   $name      Name to convert
-     * @param string   $language  ISO code for anguage the name is in
-     * @param Location &$location Location object (may be null)
-     *
-     * @return boolean whether to continue (results in $location)
-     */
-
-    function onLocationFromName($name, $language, &$location)
-    {
-        $loc = $this->getCache(array('name' => $name,
-                                     'language' => $language));
-
-        if ($loc !== false) {
-            $location = $loc;
-            return false;
-        }
-
-        try {
-            $geonames = $this->getGeonames('search',
-                                           array('maxRows' => 1,
-                                                 'q' => $name,
-                                                 'lang' => $language,
-                                                 'type' => 'xml'));
-        } catch (Exception $e) {
-            $this->log(LOG_WARNING, "Error for $name: " . $e->getMessage());
-            return true;
-        }
-
-        if (count($geonames) == 0) {
-            // no results
-            $this->setCache(array('name' => $name,
-                                  'language' => $language),
-                            null);
-            return true;
-        }
-
-        $n = $geonames[0];
-
-        $location = new Location();
-
-        $location->lat              = $this->canonical($n->lat);
-        $location->lon              = $this->canonical($n->lng);
-        $location->names[$language] = (string)$n->name;
-        $location->location_id      = (string)$n->geonameId;
-        $location->location_ns      = self::LOCATION_NS;
-
-        $this->setCache(array('name' => $name,
-                              'language' => $language),
-                        $location);
-
-        // handled, don't continue processing!
-        return false;
-    }
-
-    /**
-     * convert an id into a Location object
-     *
-     * @param string   $id        Name to convert
-     * @param string   $ns        Name to convert
-     * @param string   $language  ISO code for language for results
-     * @param Location &$location Location object (may be null)
-     *
-     * @return boolean whether to continue (results in $location)
-     */
-
-    function onLocationFromId($id, $ns, $language, &$location)
-    {
-        if ($ns != self::LOCATION_NS) {
-            // It's not one of our IDs... keep processing
-            return true;
-        }
-
-        $loc = $this->getCache(array('id' => $id));
-
-        if ($loc !== false) {
-            $location = $loc;
-            return false;
-        }
-
-        try {
-            $geonames = $this->getGeonames('hierarchy',
-                                           array('geonameId' => $id,
-                                                 'lang' => $language));
-        } catch (Exception $e) {
-            $this->log(LOG_WARNING, "Error for ID $id: " . $e->getMessage());
-            return false;
-        }
-
-        $parts = array();
-
-        foreach ($geonames as $level) {
-            if (in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
-                $parts[] = (string)$level->name;
-            }
-        }
-
-        $last = $geonames[count($geonames)-1];
-
-        if (!in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
-            $parts[] = (string)$last->name;
-        }
-
-        $location = new Location();
-
-        $location->location_id      = (string)$last->geonameId;
-        $location->location_ns      = self::LOCATION_NS;
-        $location->lat              = $this->canonical($last->lat);
-        $location->lon              = $this->canonical($last->lng);
-
-        $location->names[$language] = implode(', ', array_reverse($parts));
-
-        $this->setCache(array('id' => (string)$last->geonameId),
-                        $location);
-
-        // We're responsible for this namespace; nobody else
-        // can resolve it
-
-        return false;
-    }
-
-    /**
-     * convert a lat/lon pair into a Location object
-     *
-     * Given a lat/lon, we try to find a Location that's around
-     * it or nearby. We prefer populated places (cities, towns, villages).
-     *
-     * @param string   $lat       Latitude
-     * @param string   $lon       Longitude
-     * @param string   $language  ISO code for language for results
-     * @param Location &$location Location object (may be null)
-     *
-     * @return boolean whether to continue (results in $location)
-     */
-
-    function onLocationFromLatLon($lat, $lon, $language, &$location)
-    {
-        // Make sure they're canonical
-
-        $lat = $this->canonical($lat);
-        $lon = $this->canonical($lon);
-
-        $loc = $this->getCache(array('lat' => $lat,
-                                     'lon' => $lon));
-
-        if ($loc !== false) {
-            $location = $loc;
-            return false;
-        }
-
-        try {
-          $geonames = $this->getGeonames('findNearbyPlaceName',
-                                         array('lat' => $lat,
-                                               'lng' => $lon,
-                                               'lang' => $language));
-        } catch (Exception $e) {
-            $this->log(LOG_WARNING, "Error for coords $lat, $lon: " . $e->getMessage());
-            return true;
-        }
-
-        if (count($geonames) == 0) {
-            // no results
-            $this->setCache(array('lat' => $lat,
-                                  'lon' => $lon),
-                            null);
-            return true;
-        }
-
-        $n = $geonames[0];
-
-        $parts = array();
-
-        $location = new Location();
-
-        $parts[] = (string)$n->name;
-
-        if (!empty($n->adminName1)) {
-            $parts[] = (string)$n->adminName1;
-        }
-
-        if (!empty($n->countryName)) {
-            $parts[] = (string)$n->countryName;
-        }
-
-        $location->location_id = (string)$n->geonameId;
-        $location->location_ns = self::LOCATION_NS;
-        $location->lat         = $this->canonical($n->lat);
-        $location->lon         = $this->canonical($n->lng);
-
-        $location->names[$language] = implode(', ', $parts);
-
-        $this->setCache(array('lat' => $lat,
-                              'lon' => $lon),
-                        $location);
-
-        // Success! We handled it, so no further processing
-
-        return false;
-    }
-
-    /**
-     * Human-readable name for a location
-     *
-     * Given a location, we try to retrieve a human-readable name
-     * in the target language.
-     *
-     * @param Location $location Location to get the name for
-     * @param string   $language ISO code for language to find name in
-     * @param string   &$name    Place to put the name
-     *
-     * @return boolean whether to continue
-     */
-
-    function onLocationNameLanguage($location, $language, &$name)
-    {
-        if ($location->location_ns != self::LOCATION_NS) {
-            // It's not one of our IDs... keep processing
-            return true;
-        }
-
-        $id = $location->location_id;
-
-        $n = $this->getCache(array('id' => $id,
-                                   'language' => $language));
-
-        if ($n !== false) {
-            $name = $n;
-            return false;
-        }
-
-        try {
-            $geonames = $this->getGeonames('hierarchy',
-                                           array('geonameId' => $id,
-                                                 'lang' => $language));
-        } catch (Exception $e) {
-            $this->log(LOG_WARNING, "Error for ID $id: " . $e->getMessage());
-            return false;
-        }
-
-        if (count($geonames) == 0) {
-            $this->setCache(array('id' => $id,
-                                  'language' => $language),
-                            null);
-            return false;
-        }
-
-        $parts = array();
-
-        foreach ($geonames as $level) {
-            if (in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
-                $parts[] = (string)$level->name;
-            }
-        }
-
-        $last = $geonames[count($geonames)-1];
-
-        if (!in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
-            $parts[] = (string)$last->name;
-        }
-
-        if (count($parts)) {
-            $name = implode(', ', array_reverse($parts));
-            $this->setCache(array('id' => $id,
-                                  'language' => $language),
-                            $name);
-        }
-
-        return false;
-    }
-
-    /**
-     * Human-readable URL for a location
-     *
-     * Given a location, we try to retrieve a geonames.org URL.
-     *
-     * @param Location $location Location to get the url for
-     * @param string   &$url     Place to put the url
-     *
-     * @return boolean whether to continue
-     */
-
-    function onLocationUrl($location, &$url)
-    {
-        if ($location->location_ns != self::LOCATION_NS) {
-            // It's not one of our IDs... keep processing
-            return true;
-        }
-
-        $url = 'http://www.geonames.org/' . $location->location_id;
-
-        // it's been filled, so don't process further.
-        return false;
-    }
-
-    /**
-     * Machine-readable name for a location
-     *
-     * Given a location, we try to retrieve a geonames.org URL.
-     *
-     * @param Location $location Location to get the url for
-     * @param string   &$url     Place to put the url
-     *
-     * @return boolean whether to continue
-     */
-
-    function onLocationRdfUrl($location, &$url)
-    {
-        if ($location->location_ns != self::LOCATION_NS) {
-            // It's not one of our IDs... keep processing
-            return true;
-        }
-
-        $url = 'http://sws.geonames.org/' . $location->location_id . '/';
-
-        // it's been filled, so don't process further.
-        return false;
-    }
-
-    function getCache($attrs)
-    {
-        $c = common_memcache();
-
-        if (empty($c)) {
-            return null;
-        }
-
-        $key = $this->cacheKey($attrs);
-
-        $value = $c->get($key);
-
-        return $value;
-    }
-
-    function setCache($attrs, $loc)
-    {
-        $c = common_memcache();
-
-        if (empty($c)) {
-            return null;
-        }
-
-        $key = $this->cacheKey($attrs);
-
-        $result = $c->set($key, $loc, 0, time() + $this->expiry);
-
-        return $result;
-    }
-
-    function cacheKey($attrs)
-    {
-        $key = 'geonames:' .
-               implode(',', array_keys($attrs)) . ':'.
-               common_keyize(implode(',', array_values($attrs)));
-        if ($this->cachePrefix) {
-            return $this->cachePrefix . ':' . $key;
-        } else {
-            return common_cache_key($key);
-        }
-    }
-
-    function wsUrl($method, $params)
-    {
-        if (!empty($this->username)) {
-            $params['username'] = $this->username;
-        }
-
-        if (!empty($this->token)) {
-            $params['token'] = $this->token;
-        }
-
-        $str = http_build_query($params, null, '&');
-
-        return 'http://'.$this->host.'/'.$method.'?'.$str;
-    }
-
-    function getGeonames($method, $params)
-    {
-        if ($this->lastTimeout && (time() - $this->lastTimeout < $this->timeoutWindow)) {
-            throw new Exception("skipping due to recent web service timeout");
-        }
-
-        $client = HTTPClient::start();
-        $client->setConfig('connect_timeout', $this->timeout);
-        $client->setConfig('timeout', $this->timeout);
-
-        try {
-            $result = $client->get($this->wsUrl($method, $params));
-        } catch (Exception $e) {
-            common_log(LOG_ERR, __METHOD__ . ": " . $e->getMessage());
-            $this->lastTimeout = time();
-            throw $e;
-        }
-
-        if (!$result->isOk()) {
-            throw new Exception("HTTP error code " . $result->getStatus());
-        }
-
-        $body = $result->getBody();
-
-        if (empty($body)) {
-            throw new Exception("Empty HTTP body in response");
-        }
-
-        // This will throw an exception if the XML is mal-formed
-
-        $document = new SimpleXMLElement($body);
-
-        // No children, usually no results
-
-        $children = $document->children();
-
-        if (count($children) == 0) {
-            return array();
-        }
-
-        if (isset($document->status)) {
-            throw new Exception("Error #".$document->status['value']." ('".$document->status['message']."')");
-        }
-
-        // Array of elements, >0 elements
-
-        return $document->geoname;
-    }
-
-    function onPluginVersion(&$versions)
-    {
-        $versions[] = array('name' => 'Geonames',
-                            'version' => STATUSNET_VERSION,
-                            'author' => 'Evan Prodromou',
-                            'homepage' => 'http://status.net/wiki/Plugin:Geonames',
-                            'rawdescription' =>
-                            _m('Uses <a href="http://geonames.org/">Geonames</a> service to get human-readable '.
-                               'names for locations based on user-provided lat/long pairs.'));
-        return true;
-    }
-
-    function canonical($coord)
-    {
-        $coord = rtrim($coord, "0");
-        $coord = rtrim($coord, ".");
-
-        return $coord;
-    }
-}
diff --git a/plugins/GoogleAnalytics/GoogleAnalyticsPlugin.php b/plugins/GoogleAnalytics/GoogleAnalyticsPlugin.php
new file mode 100644 (file)
index 0000000..c646bf1
--- /dev/null
@@ -0,0 +1,85 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Plugin to use Google Analytics
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Plugin
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2008 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+/**
+ * Plugin to use Google Analytics
+ *
+ * This plugin will spoot out the correct JavaScript spell to invoke Google Analytics on a page.
+ *
+ * Note that Google Analytics is not compatible with the Franklin Street Statement; consider using
+ * Piwik (http://www.piwik.org/) instead!
+ *
+ * @category Plugin
+ * @package  StatusNet
+ * @author   Evan Prodromou <evan@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ *
+ * @see      Event
+ */
+
+class GoogleAnalyticsPlugin extends Plugin
+{
+    var $code = null;
+
+    function __construct($code=null)
+    {
+        $this->code = $code;
+        parent::__construct();
+    }
+
+    function onEndShowScripts($action)
+    {
+        $js1 = 'var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");'.
+          'document.write(unescape("%3Cscript src=\'" + gaJsHost + "google-analytics.com/ga.js\' type=\'text/javascript\'%3E%3C/script%3E"));';
+        $js2 = sprintf('try{'.
+                       'var pageTracker = _gat._getTracker("%s");'.
+                       'pageTracker._trackPageview();'.
+                       '} catch(err) {}',
+                       $this->code);
+        $action->inlineScript($js1);
+        $action->inlineScript($js2);
+    }
+
+    function onPluginVersion(&$versions)
+    {
+        $versions[] = array('name' => 'GoogleAnalytics',
+                            'version' => STATUSNET_VERSION,
+                            'author' => 'Evan Prodromou',
+                            'homepage' => 'http://status.net/wiki/Plugin:GoogleAnalytics',
+                            'rawdescription' =>
+                            _m('Use <a href="http://www.google.com/analytics/">Google Analytics</a>'.
+                               ' to track Web access.'));
+        return true;
+    }
+}
diff --git a/plugins/GoogleAnalyticsPlugin.php b/plugins/GoogleAnalyticsPlugin.php
deleted file mode 100644 (file)
index c646bf1..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Plugin to use Google Analytics
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Plugin
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2008 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    exit(1);
-}
-
-/**
- * Plugin to use Google Analytics
- *
- * This plugin will spoot out the correct JavaScript spell to invoke Google Analytics on a page.
- *
- * Note that Google Analytics is not compatible with the Franklin Street Statement; consider using
- * Piwik (http://www.piwik.org/) instead!
- *
- * @category Plugin
- * @package  StatusNet
- * @author   Evan Prodromou <evan@status.net>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://status.net/
- *
- * @see      Event
- */
-
-class GoogleAnalyticsPlugin extends Plugin
-{
-    var $code = null;
-
-    function __construct($code=null)
-    {
-        $this->code = $code;
-        parent::__construct();
-    }
-
-    function onEndShowScripts($action)
-    {
-        $js1 = 'var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");'.
-          'document.write(unescape("%3Cscript src=\'" + gaJsHost + "google-analytics.com/ga.js\' type=\'text/javascript\'%3E%3C/script%3E"));';
-        $js2 = sprintf('try{'.
-                       'var pageTracker = _gat._getTracker("%s");'.
-                       'pageTracker._trackPageview();'.
-                       '} catch(err) {}',
-                       $this->code);
-        $action->inlineScript($js1);
-        $action->inlineScript($js2);
-    }
-
-    function onPluginVersion(&$versions)
-    {
-        $versions[] = array('name' => 'GoogleAnalytics',
-                            'version' => STATUSNET_VERSION,
-                            'author' => 'Evan Prodromou',
-                            'homepage' => 'http://status.net/wiki/Plugin:GoogleAnalytics',
-                            'rawdescription' =>
-                            _m('Use <a href="http://www.google.com/analytics/">Google Analytics</a>'.
-                               ' to track Web access.'));
-        return true;
-    }
-}
diff --git a/plugins/Linkback/LinkbackPlugin.php b/plugins/Linkback/LinkbackPlugin.php
new file mode 100644 (file)
index 0000000..8e44bea
--- /dev/null
@@ -0,0 +1,249 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Plugin to do linkbacks for notices containing links
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Plugin
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+require_once('Auth/Yadis/Yadis.php');
+
+define('LINKBACKPLUGIN_VERSION', '0.1');
+
+/**
+ * Plugin to do linkbacks for notices containing URLs
+ *
+ * After new notices are saved, we check their text for URLs. If there
+ * are URLs, we test each URL to see if it supports any
+ *
+ * @category Plugin
+ * @package  StatusNet
+ * @author   Evan Prodromou <evan@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ *
+ * @see      Event
+ */
+
+class LinkbackPlugin extends Plugin
+{
+    var $notice = null;
+
+    function __construct()
+    {
+        parent::__construct();
+    }
+
+    function onHandleQueuedNotice($notice)
+    {
+        if ($notice->is_local == 1) {
+            // Try to avoid actually mucking with the
+            // notice content
+            $c = $notice->content;
+            $this->notice = $notice;
+            // Ignoring results
+            common_replace_urls_callback($c,
+                                         array($this, 'linkbackUrl'));
+        }
+        return true;
+    }
+
+    function linkbackUrl($url)
+    {
+        common_log(LOG_DEBUG,"Attempting linkback for " . $url);
+
+        $orig = $url;
+        $url = htmlspecialchars_decode($orig);
+        $scheme = parse_url($url, PHP_URL_SCHEME);
+        if (!in_array($scheme, array('http', 'https'))) {
+            return $orig;
+        }
+
+        // XXX: Do a HEAD first to save some time/bandwidth
+
+        $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
+
+        $result = $fetcher->get($url,
+                                array('User-Agent: ' . $this->userAgent(),
+                                      'Accept: application/html+xml,text/html'));
+
+        if (!in_array($result->status, array('200', '206'))) {
+            return $orig;
+        }
+
+        $pb = null;
+        $tb = null;
+
+        if (array_key_exists('X-Pingback', $result->headers)) {
+            $pb = $result->headers['X-Pingback'];
+        } else if (preg_match('/<link rel="pingback" href="([^"]+)" ?\/?>/',
+                              $result->body,
+                              $match)) {
+            $pb = $match[1];
+        }
+
+        if (!empty($pb)) {
+            $this->pingback($result->final_url, $pb);
+        } else {
+            $tb = $this->getTrackback($result->body, $result->final_url);
+            if (!empty($tb)) {
+                $this->trackback($result->final_url, $tb);
+            }
+        }
+
+        return $orig;
+    }
+
+    function pingback($url, $endpoint)
+    {
+        $args = array($this->notice->uri, $url);
+
+        if (!extension_loaded('xmlrpc')) {
+            if (!dl('xmlrpc.so')) {
+                common_log(LOG_ERR, "Can't pingback; xmlrpc extension not available.");
+                return;
+            }
+        }
+
+        $request = HTTPClient::start();
+        try {
+            $response = $request->post($endpoint,
+                array('Content-Type: text/xml'),
+                xmlrpc_encode_request('pingback.ping', $args));
+            $response = xmlrpc_decode($response->getBody());
+            if (xmlrpc_is_fault($response)) {
+                common_log(LOG_WARNING,
+                       "Pingback error for '$url' ($endpoint): ".
+                       "$response[faultString] ($response[faultCode])");
+            } else {
+                common_log(LOG_INFO,
+                       "Pingback success for '$url' ($endpoint): ".
+                       "'$response'");
+            }
+        } catch (HTTP_Request2_Exception $e) {
+            common_log(LOG_WARNING,
+                   "Pingback request failed for '$url' ($endpoint)");
+        }
+    }
+
+    // Largely cadged from trackback_cls.php by
+    // Ran Aroussi <ran@blogish.org>, GPL2 or any later version
+    // http://phptrackback.sourceforge.net/
+
+    function getTrackback($text, $url)
+    {
+        if (preg_match_all('/(<rdf:RDF.*?<\/rdf:RDF>)/sm', $text, $match, PREG_SET_ORDER)) {
+            for ($i = 0; $i < count($match); $i++) {
+                if (preg_match('|dc:identifier="' . preg_quote($url) . '"|ms', $match[$i][1])) {
+                    $rdf_array[] = trim($match[$i][1]);
+                }
+            }
+
+            // Loop through the RDFs array and extract trackback URIs
+
+            $tb_array = array(); // <- holds list of trackback URIs
+
+            if (!empty($rdf_array)) {
+
+                for ($i = 0; $i < count($rdf_array); $i++) {
+                    if (preg_match('/trackback:ping="([^"]+)"/', $rdf_array[$i], $array)) {
+                        $tb_array[] = trim($array[1]);
+                        break;
+                    }
+                }
+            }
+
+            // Return Trackbacks
+
+            if (empty($tb_array)) {
+                return null;
+            } else {
+                return $tb_array[0];
+            }
+        }
+
+        if (preg_match_all('/(<a[^>]*?rel=[\'"]trackback[\'"][^>]*?>)/', $text, $match)) {
+            foreach ($match[1] as $atag) {
+                if (preg_match('/href=[\'"]([^\'"]*?)[\'"]/', $atag, $url)) {
+                    return $url[1];
+                }
+            }
+        }
+
+        return null;
+
+    }
+
+    function trackback($url, $endpoint)
+    {
+        $profile = $this->notice->getProfile();
+
+        $args = array('title' => sprintf(_('%1$s\'s status on %2$s'),
+                                         $profile->nickname,
+                                         common_exact_date($this->notice->created)),
+                      'excerpt' => $this->notice->content,
+                      'url' => $this->notice->uri,
+                      'blog_name' => $profile->nickname);
+
+        $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
+
+        $result = $fetcher->post($endpoint,
+                                 http_build_query($args),
+                                 array('User-Agent: ' . $this->userAgent()));
+
+        if ($result->status != '200') {
+            common_log(LOG_WARNING,
+                       "Trackback error for '$url' ($endpoint): ".
+                       "$result->body");
+        } else {
+            common_log(LOG_INFO,
+                       "Trackback success for '$url' ($endpoint): ".
+                       "'$result->body'");
+        }
+    }
+
+    function userAgent()
+    {
+        return 'LinkbackPlugin/'.LINKBACKPLUGIN_VERSION .
+          ' StatusNet/' . STATUSNET_VERSION;
+    }
+
+    function onPluginVersion(&$versions)
+    {
+        $versions[] = array('name' => 'Linkback',
+                            'version' => LINKBACKPLUGIN_VERSION,
+                            'author' => 'Evan Prodromou',
+                            'homepage' => 'http://status.net/wiki/Plugin:Linkback',
+                            'rawdescription' =>
+                            _m('Notify blog authors when their posts have been linked in '.
+                               'microblog notices using '.
+                               '<a href="http://www.hixie.ch/specs/pingback/pingback">Pingback</a> '.
+                               'or <a href="http://www.movabletype.org/docs/mttrackback.html">Trackback</a> protocols.'));
+        return true;
+    }
+}
diff --git a/plugins/LinkbackPlugin.php b/plugins/LinkbackPlugin.php
deleted file mode 100644 (file)
index 8e44bea..0000000
+++ /dev/null
@@ -1,249 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Plugin to do linkbacks for notices containing links
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Plugin
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2009 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    exit(1);
-}
-
-require_once('Auth/Yadis/Yadis.php');
-
-define('LINKBACKPLUGIN_VERSION', '0.1');
-
-/**
- * Plugin to do linkbacks for notices containing URLs
- *
- * After new notices are saved, we check their text for URLs. If there
- * are URLs, we test each URL to see if it supports any
- *
- * @category Plugin
- * @package  StatusNet
- * @author   Evan Prodromou <evan@status.net>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://status.net/
- *
- * @see      Event
- */
-
-class LinkbackPlugin extends Plugin
-{
-    var $notice = null;
-
-    function __construct()
-    {
-        parent::__construct();
-    }
-
-    function onHandleQueuedNotice($notice)
-    {
-        if ($notice->is_local == 1) {
-            // Try to avoid actually mucking with the
-            // notice content
-            $c = $notice->content;
-            $this->notice = $notice;
-            // Ignoring results
-            common_replace_urls_callback($c,
-                                         array($this, 'linkbackUrl'));
-        }
-        return true;
-    }
-
-    function linkbackUrl($url)
-    {
-        common_log(LOG_DEBUG,"Attempting linkback for " . $url);
-
-        $orig = $url;
-        $url = htmlspecialchars_decode($orig);
-        $scheme = parse_url($url, PHP_URL_SCHEME);
-        if (!in_array($scheme, array('http', 'https'))) {
-            return $orig;
-        }
-
-        // XXX: Do a HEAD first to save some time/bandwidth
-
-        $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
-
-        $result = $fetcher->get($url,
-                                array('User-Agent: ' . $this->userAgent(),
-                                      'Accept: application/html+xml,text/html'));
-
-        if (!in_array($result->status, array('200', '206'))) {
-            return $orig;
-        }
-
-        $pb = null;
-        $tb = null;
-
-        if (array_key_exists('X-Pingback', $result->headers)) {
-            $pb = $result->headers['X-Pingback'];
-        } else if (preg_match('/<link rel="pingback" href="([^"]+)" ?\/?>/',
-                              $result->body,
-                              $match)) {
-            $pb = $match[1];
-        }
-
-        if (!empty($pb)) {
-            $this->pingback($result->final_url, $pb);
-        } else {
-            $tb = $this->getTrackback($result->body, $result->final_url);
-            if (!empty($tb)) {
-                $this->trackback($result->final_url, $tb);
-            }
-        }
-
-        return $orig;
-    }
-
-    function pingback($url, $endpoint)
-    {
-        $args = array($this->notice->uri, $url);
-
-        if (!extension_loaded('xmlrpc')) {
-            if (!dl('xmlrpc.so')) {
-                common_log(LOG_ERR, "Can't pingback; xmlrpc extension not available.");
-                return;
-            }
-        }
-
-        $request = HTTPClient::start();
-        try {
-            $response = $request->post($endpoint,
-                array('Content-Type: text/xml'),
-                xmlrpc_encode_request('pingback.ping', $args));
-            $response = xmlrpc_decode($response->getBody());
-            if (xmlrpc_is_fault($response)) {
-                common_log(LOG_WARNING,
-                       "Pingback error for '$url' ($endpoint): ".
-                       "$response[faultString] ($response[faultCode])");
-            } else {
-                common_log(LOG_INFO,
-                       "Pingback success for '$url' ($endpoint): ".
-                       "'$response'");
-            }
-        } catch (HTTP_Request2_Exception $e) {
-            common_log(LOG_WARNING,
-                   "Pingback request failed for '$url' ($endpoint)");
-        }
-    }
-
-    // Largely cadged from trackback_cls.php by
-    // Ran Aroussi <ran@blogish.org>, GPL2 or any later version
-    // http://phptrackback.sourceforge.net/
-
-    function getTrackback($text, $url)
-    {
-        if (preg_match_all('/(<rdf:RDF.*?<\/rdf:RDF>)/sm', $text, $match, PREG_SET_ORDER)) {
-            for ($i = 0; $i < count($match); $i++) {
-                if (preg_match('|dc:identifier="' . preg_quote($url) . '"|ms', $match[$i][1])) {
-                    $rdf_array[] = trim($match[$i][1]);
-                }
-            }
-
-            // Loop through the RDFs array and extract trackback URIs
-
-            $tb_array = array(); // <- holds list of trackback URIs
-
-            if (!empty($rdf_array)) {
-
-                for ($i = 0; $i < count($rdf_array); $i++) {
-                    if (preg_match('/trackback:ping="([^"]+)"/', $rdf_array[$i], $array)) {
-                        $tb_array[] = trim($array[1]);
-                        break;
-                    }
-                }
-            }
-
-            // Return Trackbacks
-
-            if (empty($tb_array)) {
-                return null;
-            } else {
-                return $tb_array[0];
-            }
-        }
-
-        if (preg_match_all('/(<a[^>]*?rel=[\'"]trackback[\'"][^>]*?>)/', $text, $match)) {
-            foreach ($match[1] as $atag) {
-                if (preg_match('/href=[\'"]([^\'"]*?)[\'"]/', $atag, $url)) {
-                    return $url[1];
-                }
-            }
-        }
-
-        return null;
-
-    }
-
-    function trackback($url, $endpoint)
-    {
-        $profile = $this->notice->getProfile();
-
-        $args = array('title' => sprintf(_('%1$s\'s status on %2$s'),
-                                         $profile->nickname,
-                                         common_exact_date($this->notice->created)),
-                      'excerpt' => $this->notice->content,
-                      'url' => $this->notice->uri,
-                      'blog_name' => $profile->nickname);
-
-        $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
-
-        $result = $fetcher->post($endpoint,
-                                 http_build_query($args),
-                                 array('User-Agent: ' . $this->userAgent()));
-
-        if ($result->status != '200') {
-            common_log(LOG_WARNING,
-                       "Trackback error for '$url' ($endpoint): ".
-                       "$result->body");
-        } else {
-            common_log(LOG_INFO,
-                       "Trackback success for '$url' ($endpoint): ".
-                       "'$result->body'");
-        }
-    }
-
-    function userAgent()
-    {
-        return 'LinkbackPlugin/'.LINKBACKPLUGIN_VERSION .
-          ' StatusNet/' . STATUSNET_VERSION;
-    }
-
-    function onPluginVersion(&$versions)
-    {
-        $versions[] = array('name' => 'Linkback',
-                            'version' => LINKBACKPLUGIN_VERSION,
-                            'author' => 'Evan Prodromou',
-                            'homepage' => 'http://status.net/wiki/Plugin:Linkback',
-                            'rawdescription' =>
-                            _m('Notify blog authors when their posts have been linked in '.
-                               'microblog notices using '.
-                               '<a href="http://www.hixie.ch/specs/pingback/pingback">Pingback</a> '.
-                               'or <a href="http://www.movabletype.org/docs/mttrackback.html">Trackback</a> protocols.'));
-        return true;
-    }
-}
diff --git a/plugins/Memcache/MemcachePlugin.php b/plugins/Memcache/MemcachePlugin.php
new file mode 100644 (file)
index 0000000..c3ca5c1
--- /dev/null
@@ -0,0 +1,256 @@
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * Plugin to implement cache interface for memcache
+ *
+ * PHP version 5
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Cache
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    // This check helps protect against security problems;
+    // your code file can't be executed directly from the web.
+    exit(1);
+}
+
+/**
+ * A plugin to use memcache for the cache interface
+ *
+ * This used to be encoded as config-variable options in the core code;
+ * it's now broken out to a separate plugin. The same interface can be
+ * implemented by other plugins.
+ *
+ * @category  Cache
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+class MemcachePlugin extends Plugin
+{
+    static $cacheInitialized = false;
+
+    private $_conn  = null;
+    public $servers = array('127.0.0.1;11211');
+
+    public $compressThreshold = 20480;
+    public $compressMinSaving = 0.2;
+
+    public $persistent = null;
+
+    public $defaultExpiry = 86400; // 24h
+
+    /**
+     * Initialize the plugin
+     *
+     * Note that onStartCacheGet() may have been called before this!
+     *
+     * @return boolean flag value
+     */
+
+    function onInitializePlugin()
+    {
+        if (self::$cacheInitialized) {
+            $this->persistent = true;
+        } else {
+            // If we're a parent command-line process we need
+            // to be able to close out the connection after
+            // forking, so disable persistence.
+            //
+            // We'll turn it back on again the second time
+            // through which will either be in a child process,
+            // or a single-process script which is switching
+            // configurations.
+            $this->persistent = (php_sapi_name() == 'cli') ? false : true;
+        }
+        $this->_ensureConn();
+        self::$cacheInitialized = true;
+        return true;
+    }
+
+    /**
+     * Get a value associated with a key
+     *
+     * The value should have been set previously.
+     *
+     * @param string &$key   in; Lookup key
+     * @param mixed  &$value out; value associated with key
+     *
+     * @return boolean hook success
+     */
+
+    function onStartCacheGet(&$key, &$value)
+    {
+        $this->_ensureConn();
+        $value = $this->_conn->get($key);
+        Event::handle('EndCacheGet', array($key, &$value));
+        return false;
+    }
+
+    /**
+     * Associate a value with a key
+     *
+     * @param string  &$key     in; Key to use for lookups
+     * @param mixed   &$value   in; Value to associate
+     * @param integer &$flag    in; Flag empty or Cache::COMPRESSED
+     * @param integer &$expiry  in; Expiry (passed through to Memcache)
+     * @param boolean &$success out; Whether the set was successful
+     *
+     * @return boolean hook success
+     */
+
+    function onStartCacheSet(&$key, &$value, &$flag, &$expiry, &$success)
+    {
+        $this->_ensureConn();
+        if ($expiry === null) {
+            $expiry = $this->defaultExpiry;
+        }
+        $success = $this->_conn->set($key, $value, $this->flag(intval($flag)), $expiry);
+        Event::handle('EndCacheSet', array($key, $value, $flag,
+                                           $expiry));
+        return false;
+    }
+
+    /**
+     * Atomically increment an existing numeric key value.
+     * Existing expiration time will not be changed.
+     *
+     * @param string &$key    in; Key to use for lookups
+     * @param int    &$step   in; Amount to increment (default 1)
+     * @param mixed  &$value  out; Incremented value, or false if key not set.
+     *
+     * @return boolean hook success
+     */
+    function onStartCacheIncrement(&$key, &$step, &$value)
+    {
+        $this->_ensureConn();
+        $value = $this->_conn->increment($key, $step);
+        Event::handle('EndCacheIncrement', array($key, $step, $value));
+        return false;
+    }
+
+    /**
+     * Delete a value associated with a key
+     *
+     * @param string  &$key     in; Key to lookup
+     * @param boolean &$success out; whether it worked
+     *
+     * @return boolean hook success
+     */
+
+    function onStartCacheDelete(&$key, &$success)
+    {
+        $this->_ensureConn();
+        $success = $this->_conn->delete($key);
+        Event::handle('EndCacheDelete', array($key));
+        return false;
+    }
+
+    function onStartCacheReconnect(&$success)
+    {
+        if (empty($this->_conn)) {
+            // nothing to do
+            return true;
+        }
+        if ($this->persistent) {
+            common_log(LOG_ERR, "Cannot close persistent memcached connection");
+            $success = false;
+        } else {
+            common_log(LOG_INFO, "Closing memcached connection");
+            $success = $this->_conn->close();
+            $this->_conn = null;
+        }
+        return false;
+    }
+
+    /**
+     * Ensure that a connection exists
+     *
+     * Checks the instance $_conn variable and connects
+     * if it is empty.
+     *
+     * @return void
+     */
+
+    private function _ensureConn()
+    {
+        if (empty($this->_conn)) {
+            $this->_conn = new Memcache();
+
+            if (is_array($this->servers)) {
+                $servers = $this->servers;
+            } else {
+                $servers = array($this->servers);
+            }
+            foreach ($servers as $server) {
+                if (strpos($server, ';') !== false) {
+                    list($host, $port) = explode(';', $server);
+                } else {
+                    $host = $server;
+                    $port = 11211;
+                }
+
+                $this->_conn->addServer($host, $port, $this->persistent);
+            }
+
+            // Compress items stored in the cache if they're over threshold in size
+            // (default 2KiB) and the compression would save more than min savings
+            // ratio (default 0.2).
+
+            // Allows the cache to store objects larger than 1MB (if they
+            // compress to less than 1MB), and improves cache memory efficiency.
+
+            $this->_conn->setCompressThreshold($this->compressThreshold,
+                                               $this->compressMinSaving);
+        }
+    }
+
+    /**
+     * Translate general flags to Memcached-specific flags
+     * @param int $flag
+     * @return int
+     */
+    protected function flag($flag)
+    {
+        $out = 0;
+        if ($flag & Cache::COMPRESSED == Cache::COMPRESSED) {
+            $out |= MEMCACHE_COMPRESSED;
+        }
+        return $out;
+    }
+
+    function onPluginVersion(&$versions)
+    {
+        $versions[] = array('name' => 'Memcache',
+                            'version' => STATUSNET_VERSION,
+                            'author' => 'Evan Prodromou, Craig Andrews',
+                            'homepage' => 'http://status.net/wiki/Plugin:Memcache',
+                            'rawdescription' =>
+                            _m('Use <a href="http://memcached.org/">Memcached</a> to cache query results.'));
+        return true;
+    }
+}
+
diff --git a/plugins/MemcachePlugin.php b/plugins/MemcachePlugin.php
deleted file mode 100644 (file)
index c3ca5c1..0000000
+++ /dev/null
@@ -1,256 +0,0 @@
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, StatusNet, Inc.
- *
- * Plugin to implement cache interface for memcache
- *
- * PHP version 5
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Cache
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2009 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    // This check helps protect against security problems;
-    // your code file can't be executed directly from the web.
-    exit(1);
-}
-
-/**
- * A plugin to use memcache for the cache interface
- *
- * This used to be encoded as config-variable options in the core code;
- * it's now broken out to a separate plugin. The same interface can be
- * implemented by other plugins.
- *
- * @category  Cache
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2009 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-class MemcachePlugin extends Plugin
-{
-    static $cacheInitialized = false;
-
-    private $_conn  = null;
-    public $servers = array('127.0.0.1;11211');
-
-    public $compressThreshold = 20480;
-    public $compressMinSaving = 0.2;
-
-    public $persistent = null;
-
-    public $defaultExpiry = 86400; // 24h
-
-    /**
-     * Initialize the plugin
-     *
-     * Note that onStartCacheGet() may have been called before this!
-     *
-     * @return boolean flag value
-     */
-
-    function onInitializePlugin()
-    {
-        if (self::$cacheInitialized) {
-            $this->persistent = true;
-        } else {
-            // If we're a parent command-line process we need
-            // to be able to close out the connection after
-            // forking, so disable persistence.
-            //
-            // We'll turn it back on again the second time
-            // through which will either be in a child process,
-            // or a single-process script which is switching
-            // configurations.
-            $this->persistent = (php_sapi_name() == 'cli') ? false : true;
-        }
-        $this->_ensureConn();
-        self::$cacheInitialized = true;
-        return true;
-    }
-
-    /**
-     * Get a value associated with a key
-     *
-     * The value should have been set previously.
-     *
-     * @param string &$key   in; Lookup key
-     * @param mixed  &$value out; value associated with key
-     *
-     * @return boolean hook success
-     */
-
-    function onStartCacheGet(&$key, &$value)
-    {
-        $this->_ensureConn();
-        $value = $this->_conn->get($key);
-        Event::handle('EndCacheGet', array($key, &$value));
-        return false;
-    }
-
-    /**
-     * Associate a value with a key
-     *
-     * @param string  &$key     in; Key to use for lookups
-     * @param mixed   &$value   in; Value to associate
-     * @param integer &$flag    in; Flag empty or Cache::COMPRESSED
-     * @param integer &$expiry  in; Expiry (passed through to Memcache)
-     * @param boolean &$success out; Whether the set was successful
-     *
-     * @return boolean hook success
-     */
-
-    function onStartCacheSet(&$key, &$value, &$flag, &$expiry, &$success)
-    {
-        $this->_ensureConn();
-        if ($expiry === null) {
-            $expiry = $this->defaultExpiry;
-        }
-        $success = $this->_conn->set($key, $value, $this->flag(intval($flag)), $expiry);
-        Event::handle('EndCacheSet', array($key, $value, $flag,
-                                           $expiry));
-        return false;
-    }
-
-    /**
-     * Atomically increment an existing numeric key value.
-     * Existing expiration time will not be changed.
-     *
-     * @param string &$key    in; Key to use for lookups
-     * @param int    &$step   in; Amount to increment (default 1)
-     * @param mixed  &$value  out; Incremented value, or false if key not set.
-     *
-     * @return boolean hook success
-     */
-    function onStartCacheIncrement(&$key, &$step, &$value)
-    {
-        $this->_ensureConn();
-        $value = $this->_conn->increment($key, $step);
-        Event::handle('EndCacheIncrement', array($key, $step, $value));
-        return false;
-    }
-
-    /**
-     * Delete a value associated with a key
-     *
-     * @param string  &$key     in; Key to lookup
-     * @param boolean &$success out; whether it worked
-     *
-     * @return boolean hook success
-     */
-
-    function onStartCacheDelete(&$key, &$success)
-    {
-        $this->_ensureConn();
-        $success = $this->_conn->delete($key);
-        Event::handle('EndCacheDelete', array($key));
-        return false;
-    }
-
-    function onStartCacheReconnect(&$success)
-    {
-        if (empty($this->_conn)) {
-            // nothing to do
-            return true;
-        }
-        if ($this->persistent) {
-            common_log(LOG_ERR, "Cannot close persistent memcached connection");
-            $success = false;
-        } else {
-            common_log(LOG_INFO, "Closing memcached connection");
-            $success = $this->_conn->close();
-            $this->_conn = null;
-        }
-        return false;
-    }
-
-    /**
-     * Ensure that a connection exists
-     *
-     * Checks the instance $_conn variable and connects
-     * if it is empty.
-     *
-     * @return void
-     */
-
-    private function _ensureConn()
-    {
-        if (empty($this->_conn)) {
-            $this->_conn = new Memcache();
-
-            if (is_array($this->servers)) {
-                $servers = $this->servers;
-            } else {
-                $servers = array($this->servers);
-            }
-            foreach ($servers as $server) {
-                if (strpos($server, ';') !== false) {
-                    list($host, $port) = explode(';', $server);
-                } else {
-                    $host = $server;
-                    $port = 11211;
-                }
-
-                $this->_conn->addServer($host, $port, $this->persistent);
-            }
-
-            // Compress items stored in the cache if they're over threshold in size
-            // (default 2KiB) and the compression would save more than min savings
-            // ratio (default 0.2).
-
-            // Allows the cache to store objects larger than 1MB (if they
-            // compress to less than 1MB), and improves cache memory efficiency.
-
-            $this->_conn->setCompressThreshold($this->compressThreshold,
-                                               $this->compressMinSaving);
-        }
-    }
-
-    /**
-     * Translate general flags to Memcached-specific flags
-     * @param int $flag
-     * @return int
-     */
-    protected function flag($flag)
-    {
-        $out = 0;
-        if ($flag & Cache::COMPRESSED == Cache::COMPRESSED) {
-            $out |= MEMCACHE_COMPRESSED;
-        }
-        return $out;
-    }
-
-    function onPluginVersion(&$versions)
-    {
-        $versions[] = array('name' => 'Memcache',
-                            'version' => STATUSNET_VERSION,
-                            'author' => 'Evan Prodromou, Craig Andrews',
-                            'homepage' => 'http://status.net/wiki/Plugin:Memcache',
-                            'rawdescription' =>
-                            _m('Use <a href="http://memcached.org/">Memcached</a> to cache query results.'));
-        return true;
-    }
-}
-
diff --git a/plugins/Memcached/MemcachedPlugin.php b/plugins/Memcached/MemcachedPlugin.php
new file mode 100644 (file)
index 0000000..77b989b
--- /dev/null
@@ -0,0 +1,227 @@
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * Plugin to implement cache interface for memcached
+ *
+ * PHP version 5
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Cache
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @author    Craig Andrews <candrews@integralblue.com>
+ * @copyright 2009 StatusNet, Inc.
+ * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    // This check helps protect against security problems;
+    // your code file can't be executed directly from the web.
+    exit(1);
+}
+
+/**
+ * A plugin to use memcached for the cache interface
+ *
+ * This used to be encoded as config-variable options in the core code;
+ * it's now broken out to a separate plugin. The same interface can be
+ * implemented by other plugins.
+ *
+ * @category  Cache
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @author    Craig Andrews <candrews@integralblue.com>
+ * @copyright 2009 StatusNet, Inc.
+ * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+class MemcachedPlugin extends Plugin
+{
+    static $cacheInitialized = false;
+
+    private $_conn  = null;
+    public $servers = array('127.0.0.1;11211');
+
+    public $defaultExpiry = 86400; // 24h
+
+    /**
+     * Initialize the plugin
+     *
+     * Note that onStartCacheGet() may have been called before this!
+     *
+     * @return boolean flag value
+     */
+
+    function onInitializePlugin()
+    {
+        $this->_ensureConn();
+        self::$cacheInitialized = true;
+        return true;
+    }
+
+    /**
+     * Get a value associated with a key
+     *
+     * The value should have been set previously.
+     *
+     * @param string &$key   in; Lookup key
+     * @param mixed  &$value out; value associated with key
+     *
+     * @return boolean hook success
+     */
+
+    function onStartCacheGet(&$key, &$value)
+    {
+        $this->_ensureConn();
+        $value = $this->_conn->get($key);
+        Event::handle('EndCacheGet', array($key, &$value));
+        return false;
+    }
+
+    /**
+     * Associate a value with a key
+     *
+     * @param string  &$key     in; Key to use for lookups
+     * @param mixed   &$value   in; Value to associate
+     * @param integer &$flag    in; Flag empty or Cache::COMPRESSED
+     * @param integer &$expiry  in; Expiry (passed through to Memcache)
+     * @param boolean &$success out; Whether the set was successful
+     *
+     * @return boolean hook success
+     */
+
+    function onStartCacheSet(&$key, &$value, &$flag, &$expiry, &$success)
+    {
+        $this->_ensureConn();
+        if ($expiry === null) {
+            $expiry = $this->defaultExpiry;
+        }
+        $success = $this->_conn->set($key, $value, $expiry);
+        Event::handle('EndCacheSet', array($key, $value, $flag,
+                                           $expiry));
+        return false;
+    }
+
+    /**
+     * Atomically increment an existing numeric key value.
+     * Existing expiration time will not be changed.
+     *
+     * @param string &$key    in; Key to use for lookups
+     * @param int    &$step   in; Amount to increment (default 1)
+     * @param mixed  &$value  out; Incremented value, or false if key not set.
+     *
+     * @return boolean hook success
+     */
+    function onStartCacheIncrement(&$key, &$step, &$value)
+    {
+        $this->_ensureConn();
+        $value = $this->_conn->increment($key, $step);
+        Event::handle('EndCacheIncrement', array($key, $step, $value));
+        return false;
+    }
+
+    /**
+     * Delete a value associated with a key
+     *
+     * @param string  &$key     in; Key to lookup
+     * @param boolean &$success out; whether it worked
+     *
+     * @return boolean hook success
+     */
+
+    function onStartCacheDelete(&$key, &$success)
+    {
+        $this->_ensureConn();
+        $success = $this->_conn->delete($key);
+        Event::handle('EndCacheDelete', array($key));
+        return false;
+    }
+
+    function onStartCacheReconnect(&$success)
+    {
+        // nothing to do
+        return true;
+    }
+
+    /**
+     * Ensure that a connection exists
+     *
+     * Checks the instance $_conn variable and connects
+     * if it is empty.
+     *
+     * @return void
+     */
+
+    private function _ensureConn()
+    {
+        if (empty($this->_conn)) {
+            $this->_conn = new Memcached(common_config('site', 'nickname'));
+
+            if (!count($this->_conn->getServerList())) {
+            if (is_array($this->servers)) {
+                $servers = $this->servers;
+            } else {
+                $servers = array($this->servers);
+            }
+            foreach ($servers as $server) {
+                if (strpos($server, ';') !== false) {
+                    list($host, $port) = explode(';', $server);
+                } else {
+                    $host = $server;
+                    $port = 11211;
+                }
+
+                $this->_conn->addServer($host, $port);
+            }
+
+            // Compress items stored in the cache.
+
+            // Allows the cache to store objects larger than 1MB (if they
+            // compress to less than 1MB), and improves cache memory efficiency.
+
+            $this->_conn->setOption(Memcached::OPT_COMPRESSION, true);
+            }
+        }
+    }
+
+    /**
+     * Translate general flags to Memcached-specific flags
+     * @param int $flag
+     * @return int
+     */
+    protected function flag($flag)
+    {
+        //no flags are presently supported
+        return $flag;
+    }
+
+    function onPluginVersion(&$versions)
+    {
+        $versions[] = array('name' => 'Memcached',
+                            'version' => STATUSNET_VERSION,
+                            'author' => 'Evan Prodromou, Craig Andrews',
+                            'homepage' => 'http://status.net/wiki/Plugin:Memcached',
+                            'rawdescription' =>
+                            _m('Use <a href="http://memcached.org/">Memcached</a> to cache query results.'));
+        return true;
+    }
+}
+
diff --git a/plugins/MemcachedPlugin.php b/plugins/MemcachedPlugin.php
deleted file mode 100644 (file)
index 77b989b..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, StatusNet, Inc.
- *
- * Plugin to implement cache interface for memcached
- *
- * PHP version 5
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Cache
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @author    Craig Andrews <candrews@integralblue.com>
- * @copyright 2009 StatusNet, Inc.
- * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    // This check helps protect against security problems;
-    // your code file can't be executed directly from the web.
-    exit(1);
-}
-
-/**
- * A plugin to use memcached for the cache interface
- *
- * This used to be encoded as config-variable options in the core code;
- * it's now broken out to a separate plugin. The same interface can be
- * implemented by other plugins.
- *
- * @category  Cache
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @author    Craig Andrews <candrews@integralblue.com>
- * @copyright 2009 StatusNet, Inc.
- * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-class MemcachedPlugin extends Plugin
-{
-    static $cacheInitialized = false;
-
-    private $_conn  = null;
-    public $servers = array('127.0.0.1;11211');
-
-    public $defaultExpiry = 86400; // 24h
-
-    /**
-     * Initialize the plugin
-     *
-     * Note that onStartCacheGet() may have been called before this!
-     *
-     * @return boolean flag value
-     */
-
-    function onInitializePlugin()
-    {
-        $this->_ensureConn();
-        self::$cacheInitialized = true;
-        return true;
-    }
-
-    /**
-     * Get a value associated with a key
-     *
-     * The value should have been set previously.
-     *
-     * @param string &$key   in; Lookup key
-     * @param mixed  &$value out; value associated with key
-     *
-     * @return boolean hook success
-     */
-
-    function onStartCacheGet(&$key, &$value)
-    {
-        $this->_ensureConn();
-        $value = $this->_conn->get($key);
-        Event::handle('EndCacheGet', array($key, &$value));
-        return false;
-    }
-
-    /**
-     * Associate a value with a key
-     *
-     * @param string  &$key     in; Key to use for lookups
-     * @param mixed   &$value   in; Value to associate
-     * @param integer &$flag    in; Flag empty or Cache::COMPRESSED
-     * @param integer &$expiry  in; Expiry (passed through to Memcache)
-     * @param boolean &$success out; Whether the set was successful
-     *
-     * @return boolean hook success
-     */
-
-    function onStartCacheSet(&$key, &$value, &$flag, &$expiry, &$success)
-    {
-        $this->_ensureConn();
-        if ($expiry === null) {
-            $expiry = $this->defaultExpiry;
-        }
-        $success = $this->_conn->set($key, $value, $expiry);
-        Event::handle('EndCacheSet', array($key, $value, $flag,
-                                           $expiry));
-        return false;
-    }
-
-    /**
-     * Atomically increment an existing numeric key value.
-     * Existing expiration time will not be changed.
-     *
-     * @param string &$key    in; Key to use for lookups
-     * @param int    &$step   in; Amount to increment (default 1)
-     * @param mixed  &$value  out; Incremented value, or false if key not set.
-     *
-     * @return boolean hook success
-     */
-    function onStartCacheIncrement(&$key, &$step, &$value)
-    {
-        $this->_ensureConn();
-        $value = $this->_conn->increment($key, $step);
-        Event::handle('EndCacheIncrement', array($key, $step, $value));
-        return false;
-    }
-
-    /**
-     * Delete a value associated with a key
-     *
-     * @param string  &$key     in; Key to lookup
-     * @param boolean &$success out; whether it worked
-     *
-     * @return boolean hook success
-     */
-
-    function onStartCacheDelete(&$key, &$success)
-    {
-        $this->_ensureConn();
-        $success = $this->_conn->delete($key);
-        Event::handle('EndCacheDelete', array($key));
-        return false;
-    }
-
-    function onStartCacheReconnect(&$success)
-    {
-        // nothing to do
-        return true;
-    }
-
-    /**
-     * Ensure that a connection exists
-     *
-     * Checks the instance $_conn variable and connects
-     * if it is empty.
-     *
-     * @return void
-     */
-
-    private function _ensureConn()
-    {
-        if (empty($this->_conn)) {
-            $this->_conn = new Memcached(common_config('site', 'nickname'));
-
-            if (!count($this->_conn->getServerList())) {
-            if (is_array($this->servers)) {
-                $servers = $this->servers;
-            } else {
-                $servers = array($this->servers);
-            }
-            foreach ($servers as $server) {
-                if (strpos($server, ';') !== false) {
-                    list($host, $port) = explode(';', $server);
-                } else {
-                    $host = $server;
-                    $port = 11211;
-                }
-
-                $this->_conn->addServer($host, $port);
-            }
-
-            // Compress items stored in the cache.
-
-            // Allows the cache to store objects larger than 1MB (if they
-            // compress to less than 1MB), and improves cache memory efficiency.
-
-            $this->_conn->setOption(Memcached::OPT_COMPRESSION, true);
-            }
-        }
-    }
-
-    /**
-     * Translate general flags to Memcached-specific flags
-     * @param int $flag
-     * @return int
-     */
-    protected function flag($flag)
-    {
-        //no flags are presently supported
-        return $flag;
-    }
-
-    function onPluginVersion(&$versions)
-    {
-        $versions[] = array('name' => 'Memcached',
-                            'version' => STATUSNET_VERSION,
-                            'author' => 'Evan Prodromou, Craig Andrews',
-                            'homepage' => 'http://status.net/wiki/Plugin:Memcached',
-                            'rawdescription' =>
-                            _m('Use <a href="http://memcached.org/">Memcached</a> to cache query results.'));
-        return true;
-    }
-}
-
diff --git a/plugins/PiwikAnalytics/PiwikAnalyticsPlugin.php b/plugins/PiwikAnalytics/PiwikAnalyticsPlugin.php
new file mode 100644 (file)
index 0000000..b353d72
--- /dev/null
@@ -0,0 +1,112 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Plugin to use Piwik Analytics
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Plugin
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @author    Tobias Diekershoff <tobias.diekershoff@gmx.net>
+ * @copyright 2008 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+/**
+ * Plugin to use Piwik Analytics (based on the Google Analytics plugin by Evan)
+ *
+ * This plugin will spoot out the correct JavaScript spell to invoke
+ * Piwik Analytics on a page.
+ *
+ * To use this plugin add the following to your config.php
+ *
+ *  addPlugin('PiwikAnalytics', array('piwikroot' => 'example.com/piwik/',
+ *                                    'piwikId' => 'id'));
+ *
+ * Replace 'example.com/piwik/' with the URL to your Piwik installation and
+ * make sure you don't forget the final /.
+ * Replace 'id' with the ID your statusnet installation has in your Piwik
+ * analytics setup - for example '8'.
+ *
+ */
+
+class PiwikAnalyticsPlugin extends Plugin
+{
+    /** the base of your Piwik installation */
+    public $piwikroot = null;
+    /** the Piwik Id of your statusnet installation */
+    public $piwikId   = null;
+
+    /**
+     * constructor
+     *
+     * @param string $root Piwik root URL
+     * @param string $id   Piwik ID of this app
+     */
+
+    function __construct($root=null, $id=null)
+    {
+        $this->piwikroot = $root;
+        $this->piwikId   = $id;
+        parent::__construct();
+    }
+
+    /**
+     * Called when all scripts have been shown
+     *
+     * @param Action $action Current action
+     *
+     * @return boolean ignored
+     */
+
+    function onEndShowScripts($action)
+    {
+        $piwikCode1 = <<<ENDOFPIWIK
+var pkBaseURL = (("https:" == document.location.protocol) ? "https://{$this->piwikroot}" : "http://{$this->piwikroot}");
+document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
+ENDOFPIWIK;
+        $piwikCode2 = <<<ENDOFPIWIK
+try {
+    var piwikTracker = Piwik.getTracker(pkBaseURL + "piwik.php", {$this->piwikId});
+    piwikTracker.trackPageView();
+    piwikTracker.enableLinkTracking();
+} catch( err ) {}
+ENDOFPIWIK;
+
+        $action->inlineScript($piwikCode1);
+        $action->inlineScript($piwikCode2);
+        return true;
+    }
+
+    function onPluginVersion(&$versions)
+    {
+        $versions[] = array('name' => 'PiwikAnalytics',
+                            'version' => STATUSNET_VERSION,
+                            'author' => 'Tobias Diekershoff, Evan Prodromou',
+                            'homepage' => 'http://status.net/wiki/Plugin:Piwik',
+                            'rawdescription' =>
+                            _m('Use <a href="http://piwik.org/">Piwik</a> Open Source Web analytics software.'));
+        return true;
+    }
+
+}
diff --git a/plugins/PiwikAnalyticsPlugin.php b/plugins/PiwikAnalyticsPlugin.php
deleted file mode 100644 (file)
index b353d72..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Plugin to use Piwik Analytics
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Plugin
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @author    Tobias Diekershoff <tobias.diekershoff@gmx.net>
- * @copyright 2008 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    exit(1);
-}
-
-/**
- * Plugin to use Piwik Analytics (based on the Google Analytics plugin by Evan)
- *
- * This plugin will spoot out the correct JavaScript spell to invoke
- * Piwik Analytics on a page.
- *
- * To use this plugin add the following to your config.php
- *
- *  addPlugin('PiwikAnalytics', array('piwikroot' => 'example.com/piwik/',
- *                                    'piwikId' => 'id'));
- *
- * Replace 'example.com/piwik/' with the URL to your Piwik installation and
- * make sure you don't forget the final /.
- * Replace 'id' with the ID your statusnet installation has in your Piwik
- * analytics setup - for example '8'.
- *
- */
-
-class PiwikAnalyticsPlugin extends Plugin
-{
-    /** the base of your Piwik installation */
-    public $piwikroot = null;
-    /** the Piwik Id of your statusnet installation */
-    public $piwikId   = null;
-
-    /**
-     * constructor
-     *
-     * @param string $root Piwik root URL
-     * @param string $id   Piwik ID of this app
-     */
-
-    function __construct($root=null, $id=null)
-    {
-        $this->piwikroot = $root;
-        $this->piwikId   = $id;
-        parent::__construct();
-    }
-
-    /**
-     * Called when all scripts have been shown
-     *
-     * @param Action $action Current action
-     *
-     * @return boolean ignored
-     */
-
-    function onEndShowScripts($action)
-    {
-        $piwikCode1 = <<<ENDOFPIWIK
-var pkBaseURL = (("https:" == document.location.protocol) ? "https://{$this->piwikroot}" : "http://{$this->piwikroot}");
-document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
-ENDOFPIWIK;
-        $piwikCode2 = <<<ENDOFPIWIK
-try {
-    var piwikTracker = Piwik.getTracker(pkBaseURL + "piwik.php", {$this->piwikId});
-    piwikTracker.trackPageView();
-    piwikTracker.enableLinkTracking();
-} catch( err ) {}
-ENDOFPIWIK;
-
-        $action->inlineScript($piwikCode1);
-        $action->inlineScript($piwikCode2);
-        return true;
-    }
-
-    function onPluginVersion(&$versions)
-    {
-        $versions[] = array('name' => 'PiwikAnalytics',
-                            'version' => STATUSNET_VERSION,
-                            'author' => 'Tobias Diekershoff, Evan Prodromou',
-                            'homepage' => 'http://status.net/wiki/Plugin:Piwik',
-                            'rawdescription' =>
-                            _m('Use <a href="http://piwik.org/">Piwik</a> Open Source Web analytics software.'));
-        return true;
-    }
-
-}
diff --git a/plugins/Spotify/SpotifyPlugin.php b/plugins/Spotify/SpotifyPlugin.php
new file mode 100644 (file)
index 0000000..e7a5a53
--- /dev/null
@@ -0,0 +1,113 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+  *
+ * Plugin to create pretty Spotify URLs
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Plugin
+ * @package   StatusNet
+ * @author    Nick Holliday <n.g.holliday@gmail.com>
+ * @copyright Nick Holliday
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ *
+ * @see      Event
+ */
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+define('SPOTIFYPLUGIN_VERSION', '0.1');
+
+/**
+ * Plugin to create pretty Spotify URLs
+ *
+ * The Spotify API is called before the notice is saved to gather artist and track information.
+ *
+ * @category  Plugin
+ * @package   StatusNet
+ * @author    Nick Holliday <n.g.holliday@gmail.com>
+ * @copyright Nick Holliday
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ *
+ * @see       Event
+ */
+
+class SpotifyPlugin extends Plugin
+{
+
+    function __construct()
+    {
+        parent::__construct();
+    }
+
+    function onStartNoticeSave($notice)
+    {
+        $notice->rendered = preg_replace_callback('/spotify:[a-z]{5,6}:[a-z0-9]{22}/i',
+                                                  "renderSpotifyURILink",
+                                                  $notice->rendered);
+
+        $notice->rendered = preg_replace_callback('/<a href="http:\/\/open.spotify.com\/[a-z]{5,6}\/[a-z0-9]{22}" title="http:\/\/open.spotify.com\/[a-z]{5,6}\/[a-z0-9]{22}" rel="external">http:\/\/open.spotify.com\/[a-z]{5,6}\/[a-z0-9]{22}<\/a>/i',
+                                                  "renderSpotifyHTTPLink",
+                                                  $notice->rendered);
+
+        return true;
+    }
+
+    function userAgent()
+    {
+        return 'SpotifyPlugin/'.SPOTIFYPLUGIN_VERSION .
+               ' StatusNet/' . STATUSNET_VERSION;
+    }
+}
+
+function doSpotifyLookup($uri, $isArtist)
+{
+    $request = HTTPClient::start();
+    $response = $request->get('http://ws.spotify.com/lookup/1/?uri=' . $uri);
+    if ($response->isOk()) {
+        $xml = simplexml_load_string($response->getBody());
+
+        if($isArtist)
+            return $xml->name;
+        else
+            return $xml->artist->name . ' - ' . $xml->name;
+    }
+}
+
+function renderSpotifyURILink($match)
+{
+    $isArtist = false;
+    if(preg_match('/artist/', $match[0]) > 0) $isArtist = true;
+
+    $name = doSpotifyLookup($match[0], $isArtist);
+    return "<a href=\"{$match[0]}\">" . $name . "</a>";
+}
+
+function renderSpotifyHTTPLink($match)
+{
+    $match[0] = preg_replace('/<a href="http:\/\/open.spotify.com\/[a-z]{5,6}\/[a-z0-9]{22}" title="http:\/\/open.spotify.com\/[a-z]{5,6}\/[a-z0-9]{22}" rel="external">http:\/\/open.spotify.com\//i', 'spotify:', $match[0]);
+    $match[0] = preg_replace('/<\/a>/', '', $match[0]);
+    $match[0] = preg_replace('/\//', ':', $match[0]);
+
+    $isArtist = false;
+    if(preg_match('/artist/', $match[0]) > 0) $isArtist = true;
+
+    $name = doSpotifyLookup($match[0], $isArtist);
+    return "<a href=\"{$match[0]}\">" . $name . "</a>";
+}
diff --git a/plugins/SpotifyPlugin.php b/plugins/SpotifyPlugin.php
deleted file mode 100644 (file)
index e7a5a53..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
-  *
- * Plugin to create pretty Spotify URLs
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Plugin
- * @package   StatusNet
- * @author    Nick Holliday <n.g.holliday@gmail.com>
- * @copyright Nick Holliday
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- *
- * @see      Event
- */
-if (!defined('STATUSNET')) {
-    exit(1);
-}
-define('SPOTIFYPLUGIN_VERSION', '0.1');
-
-/**
- * Plugin to create pretty Spotify URLs
- *
- * The Spotify API is called before the notice is saved to gather artist and track information.
- *
- * @category  Plugin
- * @package   StatusNet
- * @author    Nick Holliday <n.g.holliday@gmail.com>
- * @copyright Nick Holliday
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- *
- * @see       Event
- */
-
-class SpotifyPlugin extends Plugin
-{
-
-    function __construct()
-    {
-        parent::__construct();
-    }
-
-    function onStartNoticeSave($notice)
-    {
-        $notice->rendered = preg_replace_callback('/spotify:[a-z]{5,6}:[a-z0-9]{22}/i',
-                                                  "renderSpotifyURILink",
-                                                  $notice->rendered);
-
-        $notice->rendered = preg_replace_callback('/<a href="http:\/\/open.spotify.com\/[a-z]{5,6}\/[a-z0-9]{22}" title="http:\/\/open.spotify.com\/[a-z]{5,6}\/[a-z0-9]{22}" rel="external">http:\/\/open.spotify.com\/[a-z]{5,6}\/[a-z0-9]{22}<\/a>/i',
-                                                  "renderSpotifyHTTPLink",
-                                                  $notice->rendered);
-
-        return true;
-    }
-
-    function userAgent()
-    {
-        return 'SpotifyPlugin/'.SPOTIFYPLUGIN_VERSION .
-               ' StatusNet/' . STATUSNET_VERSION;
-    }
-}
-
-function doSpotifyLookup($uri, $isArtist)
-{
-    $request = HTTPClient::start();
-    $response = $request->get('http://ws.spotify.com/lookup/1/?uri=' . $uri);
-    if ($response->isOk()) {
-        $xml = simplexml_load_string($response->getBody());
-
-        if($isArtist)
-            return $xml->name;
-        else
-            return $xml->artist->name . ' - ' . $xml->name;
-    }
-}
-
-function renderSpotifyURILink($match)
-{
-    $isArtist = false;
-    if(preg_match('/artist/', $match[0]) > 0) $isArtist = true;
-
-    $name = doSpotifyLookup($match[0], $isArtist);
-    return "<a href=\"{$match[0]}\">" . $name . "</a>";
-}
-
-function renderSpotifyHTTPLink($match)
-{
-    $match[0] = preg_replace('/<a href="http:\/\/open.spotify.com\/[a-z]{5,6}\/[a-z0-9]{22}" title="http:\/\/open.spotify.com\/[a-z]{5,6}\/[a-z0-9]{22}" rel="external">http:\/\/open.spotify.com\//i', 'spotify:', $match[0]);
-    $match[0] = preg_replace('/<\/a>/', '', $match[0]);
-    $match[0] = preg_replace('/\//', ':', $match[0]);
-
-    $isArtist = false;
-    if(preg_match('/artist/', $match[0]) > 0) $isArtist = true;
-
-    $name = doSpotifyLookup($match[0], $isArtist);
-    return "<a href=\"{$match[0]}\">" . $name . "</a>";
-}
diff --git a/plugins/SubscriptionThrottle/SubscriptionThrottlePlugin.php b/plugins/SubscriptionThrottle/SubscriptionThrottlePlugin.php
new file mode 100644 (file)
index 0000000..1141133
--- /dev/null
@@ -0,0 +1,175 @@
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * Plugin to throttle subscriptions by a user
+ *
+ * PHP version 5
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Throttle
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    // This check helps protect against security problems;
+    // your code file can't be executed directly from the web.
+    exit(1);
+}
+
+/**
+ * Subscription throttle
+ *
+ * @category  Throttle
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link      http://status.net/
+ */
+
+class SubscriptionThrottlePlugin extends Plugin
+{
+    public $subLimits = array(86400 => 100,
+                              3600 => 50);
+
+    public $groupLimits = array(86400 => 50,
+                                3600 => 25);
+
+    /**
+     * Filter subscriptions to see if they're coming too fast.
+     *
+     * @param User $user  The user subscribing
+     * @param User $other The user being subscribed to
+     *
+     * @return boolean hook value
+     */
+
+    function onStartSubscribe($user, $other)
+    {
+        foreach ($this->subLimits as $seconds => $limit) {
+            $sub = $this->_getNthSub($user, $limit);
+
+            if (!empty($sub)) {
+                $subtime = strtotime($sub->created);
+                $now     = time();
+                if ($now - $subtime < $seconds) {
+                    throw new Exception(_("Too many subscriptions. Take a break and try again later."));
+                }
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Filter group joins to see if they're coming too fast.
+     *
+     * @param Group $group The group being joined
+     * @param User  $user  The user joining
+     *
+     * @return boolean hook value
+     */
+
+    function onStartJoinGroup($group, $user)
+    {
+        foreach ($this->groupLimits as $seconds => $limit) {
+            $mem = $this->_getNthMem($user, $limit);
+            if (!empty($mem)) {
+
+                $jointime = strtotime($mem->created);
+                $now      = time();
+                if ($now - $jointime < $seconds) {
+                    throw new Exception(_("Too many memberships. Take a break and try again later."));
+                }
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Get the Nth most recent subscription for this user
+     *
+     * @param User    $user The user to get subscriptions for
+     * @param integer $n    How far to count back
+     *
+     * @return Subscription a subscription or null
+     */
+
+    private function _getNthSub($user, $n)
+    {
+        $sub = new Subscription();
+
+        $sub->subscriber = $user->id;
+        $sub->orderBy('created DESC');
+        $sub->limit($n - 1, 1);
+
+        if ($sub->find(true)) {
+            return $sub;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Get the Nth most recent group membership for this user
+     *
+     * @param User    $user The user to get memberships for
+     * @param integer $n    How far to count back
+     *
+     * @return Group_member a membership or null
+     */
+
+    private function _getNthMem($user, $n)
+    {
+        $mem = new Group_member();
+
+        $mem->profile_id = $user->id;
+        $mem->orderBy('created DESC');
+        $mem->limit($n - 1, 1);
+
+        if ($mem->find(true)) {
+            return $mem;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Return plugin version data for display
+     *
+     * @param array &$versions Array of version arrays
+     *
+     * @return boolean hook value
+     */
+
+    function onPluginVersion(&$versions)
+    {
+        $versions[] = array('name' => 'SubscriptionThrottle',
+                            'version' => STATUSNET_VERSION,
+                            'author' => 'Evan Prodromou',
+                            'homepage' => 'http://status.net/wiki/Plugin:SubscriptionThrottle',
+                            'rawdescription' =>
+                            _m('Configurable limits for subscriptions and group memberships.'));
+        return true;
+    }
+}
+
diff --git a/plugins/SubscriptionThrottlePlugin.php b/plugins/SubscriptionThrottlePlugin.php
deleted file mode 100644 (file)
index 1141133..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * Plugin to throttle subscriptions by a user
- *
- * PHP version 5
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Throttle
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    // This check helps protect against security problems;
-    // your code file can't be executed directly from the web.
-    exit(1);
-}
-
-/**
- * Subscription throttle
- *
- * @category  Throttle
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link      http://status.net/
- */
-
-class SubscriptionThrottlePlugin extends Plugin
-{
-    public $subLimits = array(86400 => 100,
-                              3600 => 50);
-
-    public $groupLimits = array(86400 => 50,
-                                3600 => 25);
-
-    /**
-     * Filter subscriptions to see if they're coming too fast.
-     *
-     * @param User $user  The user subscribing
-     * @param User $other The user being subscribed to
-     *
-     * @return boolean hook value
-     */
-
-    function onStartSubscribe($user, $other)
-    {
-        foreach ($this->subLimits as $seconds => $limit) {
-            $sub = $this->_getNthSub($user, $limit);
-
-            if (!empty($sub)) {
-                $subtime = strtotime($sub->created);
-                $now     = time();
-                if ($now - $subtime < $seconds) {
-                    throw new Exception(_("Too many subscriptions. Take a break and try again later."));
-                }
-            }
-        }
-
-        return true;
-    }
-
-    /**
-     * Filter group joins to see if they're coming too fast.
-     *
-     * @param Group $group The group being joined
-     * @param User  $user  The user joining
-     *
-     * @return boolean hook value
-     */
-
-    function onStartJoinGroup($group, $user)
-    {
-        foreach ($this->groupLimits as $seconds => $limit) {
-            $mem = $this->_getNthMem($user, $limit);
-            if (!empty($mem)) {
-
-                $jointime = strtotime($mem->created);
-                $now      = time();
-                if ($now - $jointime < $seconds) {
-                    throw new Exception(_("Too many memberships. Take a break and try again later."));
-                }
-            }
-        }
-
-        return true;
-    }
-
-    /**
-     * Get the Nth most recent subscription for this user
-     *
-     * @param User    $user The user to get subscriptions for
-     * @param integer $n    How far to count back
-     *
-     * @return Subscription a subscription or null
-     */
-
-    private function _getNthSub($user, $n)
-    {
-        $sub = new Subscription();
-
-        $sub->subscriber = $user->id;
-        $sub->orderBy('created DESC');
-        $sub->limit($n - 1, 1);
-
-        if ($sub->find(true)) {
-            return $sub;
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Get the Nth most recent group membership for this user
-     *
-     * @param User    $user The user to get memberships for
-     * @param integer $n    How far to count back
-     *
-     * @return Group_member a membership or null
-     */
-
-    private function _getNthMem($user, $n)
-    {
-        $mem = new Group_member();
-
-        $mem->profile_id = $user->id;
-        $mem->orderBy('created DESC');
-        $mem->limit($n - 1, 1);
-
-        if ($mem->find(true)) {
-            return $mem;
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Return plugin version data for display
-     *
-     * @param array &$versions Array of version arrays
-     *
-     * @return boolean hook value
-     */
-
-    function onPluginVersion(&$versions)
-    {
-        $versions[] = array('name' => 'SubscriptionThrottle',
-                            'version' => STATUSNET_VERSION,
-                            'author' => 'Evan Prodromou',
-                            'homepage' => 'http://status.net/wiki/Plugin:SubscriptionThrottle',
-                            'rawdescription' =>
-                            _m('Configurable limits for subscriptions and group memberships.'));
-        return true;
-    }
-}
-
diff --git a/plugins/Template/TemplatePlugin.php b/plugins/Template/TemplatePlugin.php
new file mode 100644 (file)
index 0000000..80625c5
--- /dev/null
@@ -0,0 +1,357 @@
+<?php
+/**
+ * Plugin to render old skool templates
+ *
+ * Captures rendered parts from the output buffer, passes them through a template file: tpl/index.html
+ * Adds an API method at index.php/template/update which lets you overwrite the template file
+ * Requires username/password and a single POST parameter called "template"
+ * The method is disabled unless the user is #1, the first user of the system
+ *
+ * @category  Plugin
+ * @package   StatusNet
+ * @author    Brian Hendrickson <brian@megapump.com>
+ * @copyright 2009 Megapump, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://megapump.com/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+define('TEMPLATEPLUGIN_VERSION', '0.1');
+
+class TemplatePlugin extends Plugin {
+
+  var $blocks = array();
+
+  function __construct() {
+    parent::__construct();
+  }
+
+  // capture the RouterInitialized event
+  // and connect a new API method
+  // for updating the template
+  function onRouterInitialized( $m ) {
+    $m->connect( 'template/update', array(
+      'action'      => 'template',
+    ));
+  }
+
+  // <%styles%>
+  // <%scripts%>
+  // <%search%>
+  // <%feeds%>
+  // <%description%>
+  // <%head%>
+  function onStartShowHead( &$act ) {
+    $this->clear_xmlWriter($act);
+    $act->extraHead();
+    $this->blocks['head'] = $act->xw->flush();
+    $act->showStylesheets();
+    $this->blocks['styles'] = $act->xw->flush();
+    $act->showScripts();
+    $this->blocks['scripts'] = $act->xw->flush();
+    $act->showFeeds();
+    $this->blocks['feeds'] = $act->xw->flush();
+    $act->showOpenSearch();
+    $this->blocks['search'] = $act->xw->flush();
+    $act->showDescription();
+    $this->blocks['description'] = $act->xw->flush();
+    return false;
+  }
+
+  // <%bodytext%>
+  function onStartShowContentBlock( &$act ) {
+    $this->clear_xmlWriter($act);
+    return true;
+  }
+  function onEndShowContentBlock( &$act ) {
+    $this->blocks['bodytext'] = $act->xw->flush();
+  }
+
+  // <%localnav%>
+  function onStartShowLocalNavBlock( &$act ) {
+    $this->clear_xmlWriter($act);
+    return true;
+  }
+  function onEndShowLocalNavBlock( &$act ) {
+    $this->blocks['localnav'] = $act->xw->flush();
+  }
+
+  // <%export%>
+  function onStartShowExportData( &$act ) {
+    $this->clear_xmlWriter($act);
+    return true;
+  }
+  function onEndShowExportData( &$act ) {
+    $this->blocks['export'] = $act->xw->flush();
+  }
+
+  // <%subscriptions%>
+  // <%subscribers%>
+  // <%groups%>
+  // <%statistics%>
+  // <%cloud%>
+  // <%groupmembers%>
+  // <%groupstatistics%>
+  // <%groupcloud%>
+  // <%popular%>
+  // <%groupsbyposts%>
+  // <%featuredusers%>
+  // <%groupsbymembers%>
+  function onStartShowSections( &$act ) {
+    global $action;
+    $this->clear_xmlWriter($act);
+    switch ($action) {
+      case "showstream":
+        $act->showSubscriptions();
+        $this->blocks['subscriptions'] = $act->xw->flush();
+        $act->showSubscribers();
+        $this->blocks['subscribers'] = $act->xw->flush();
+        $act->showGroups();
+        $this->blocks['groups'] = $act->xw->flush();
+        $act->showStatistics();
+        $this->blocks['statistics'] = $act->xw->flush();
+        $cloud = new PersonalTagCloudSection($act, $act->user);
+        $cloud->show();
+        $this->blocks['cloud'] = $act->xw->flush();
+        break;
+      case "showgroup":
+        $act->showMembers();
+        $this->blocks['groupmembers'] = $act->xw->flush();
+        $act->showStatistics();
+        $this->blocks['groupstatistics'] = $act->xw->flush();
+        $cloud = new GroupTagCloudSection($act, $act->group);
+        $cloud->show();
+        $this->blocks['groupcloud'] = $act->xw->flush();
+        break;
+      case "public":
+        $pop = new PopularNoticeSection($act);
+        $pop->show();
+        $this->blocks['popular'] = $act->xw->flush();
+        $gbp = new GroupsByPostsSection($act);
+        $gbp->show();
+        $this->blocks['groupsbyposts'] = $act->xw->flush();
+        $feat = new FeaturedUsersSection($act);
+        $feat->show();
+        $this->blocks['featuredusers'] = $act->xw->flush();
+        break;
+      case "groups":
+        $gbp = new GroupsByPostsSection($act);
+        $gbp->show();
+        $this->blocks['groupsbyposts'] = $act->xw->flush();
+        $gbm = new GroupsByMembersSection($act);
+        $gbm->show();
+        $this->blocks['groupsbymembers'] = $act->xw->flush();
+        break;
+    }
+    return false;
+  }
+
+  // <%logo%>
+  // <%nav%>
+  // <%notice%>
+  // <%noticeform%>
+  function onStartShowHeader( &$act ) {
+    $this->clear_xmlWriter($act);
+    $act->showLogo();
+    $this->blocks['logo'] = $act->xw->flush();
+    $act->showPrimaryNav();
+    $this->blocks['nav'] = $act->xw->flush();
+    $act->showSiteNotice();
+    $this->blocks['notice'] = $act->xw->flush();
+    if (common_logged_in()) {
+        $act->showNoticeForm();
+    } else {
+        $act->showAnonymousMessage();
+    }
+    $this->blocks['noticeform'] = $act->xw->flush();
+    return false;
+  }
+
+  // <%secondarynav%>
+  // <%licenses%>
+  function onStartShowFooter( &$act ) {
+    $this->clear_xmlWriter($act);
+    $act->showSecondaryNav();
+    $this->blocks['secondarynav'] = $act->xw->flush();
+    $act->showLicenses();
+    $this->blocks['licenses'] = $act->xw->flush();
+    return false;
+  }
+
+  // capture the EndHTML event
+  // and include the template
+  function onEndEndHTML($act) {
+
+    global $action, $tags;
+
+    // set the action and title values
+    $vars = array(
+      'action'=>$action,
+      'title'=>$act->title(). " - ". common_config('site', 'name')
+    );
+
+    // use the PHP template
+    // unless statusnet config:
+    //   $config['template']['mode'] = 'html';
+    if (!(common_config('template', 'mode') == 'html')) {
+      $tpl_file = $this->templateFolder() . '/index.php';
+      $tags = array_merge($vars,$this->blocks);
+      include $tpl_file;
+      return;
+    }
+
+    $tpl_file = $this->templateFolder() . '/index.html';
+
+    // read the static template
+    $output = file_get_contents( $tpl_file );
+
+    $tags = array();
+
+    // get a list of the <%tags%> in the template
+    $pattern='/<%([a-z]+)%>/';
+
+    if ( 1 <= preg_match_all( $pattern, $output, $found ))
+      $tags[] = $found;
+
+    // for each found tag, set its value from the rendered blocks
+    foreach( $tags[0][1] as $pos=>$tag ) {
+      if (isset($this->blocks[$tag]))
+        $vars[$tag] = $this->blocks[$tag];
+
+      // didn't find a block for the tag
+      elseif (!isset($vars[$tag]))
+        $vars[$tag] = '';
+    }
+
+    // replace the tags in the template
+    foreach( $vars as $key=>$val )
+      $output = str_replace( '<%'.$key.'%>', $val, $output );
+
+    echo $output;
+
+    return true;
+
+  }
+  function templateFolder() {
+    return 'tpl';
+  }
+
+  // catching the StartShowHTML event to halt the rendering
+  function onStartShowHTML( &$act ) {
+    $this->clear_xmlWriter($act);
+    return true;
+  }
+
+  // clear the xmlWriter
+  function clear_xmlWriter( &$act ) {
+    $act->xw->openMemory();
+    $act->xw->setIndent(true);
+  }
+
+}
+
+/**
+ * Action for updating the template remotely
+ *
+ * "template/update" -- a POST method that requires a single
+ * parameter "template", containing the new template code
+ *
+ * @category Plugin
+ * @package  StatusNet
+ * @author   Brian Hendrickson <brian@megapump.com>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://megapump.com/
+ *
+ */
+
+class TemplateAction extends Action
+{
+
+  function prepare($args) {
+    parent::prepare($args);
+    return true;
+  }
+
+  function handle($args) {
+
+    parent::handle($args);
+
+    if (!isset($_SERVER['PHP_AUTH_USER'])) {
+
+      // not authenticated, show login form
+      header('WWW-Authenticate: Basic realm="StatusNet API"');
+
+      // cancelled the browser login form
+      $this->clientError(_('Authentication error!'), $code = 401);
+
+    } else {
+
+      $nick = $_SERVER['PHP_AUTH_USER'];
+      $pass = $_SERVER['PHP_AUTH_PW'];
+
+      // check username and password
+      $user = common_check_user($nick,$pass);
+
+      if ($user) {
+
+        // verify that user is admin
+        if (!($user->id == 1))
+          $this->clientError(_('Only User #1 can update the template.'), $code = 401);
+
+        // open the old template
+        $tpl_file = $this->templateFolder() . '/index.html';
+        $fp = fopen( $tpl_file, 'w+' );
+
+        // overwrite with the new template
+        fwrite($fp, $this->arg('template'));
+        fclose($fp);
+
+        header('HTTP/1.1 200 OK');
+        header('Content-type: text/plain');
+        print "Template Updated!";
+
+      } else {
+
+        // bad username and password
+        $this->clientError(_('Authentication error!'), $code = 401);
+
+      }
+
+    }
+  }
+    function onPluginVersion(&$versions)
+    {
+        $versions[] = array('name' => 'Template',
+                            'version' => TEMPLATEPLUGIN_VERSION,
+                            'author' => 'Brian Hendrickson',
+                            'homepage' => 'http://status.net/wiki/Plugin:Template',
+                            'rawdescription' =>
+                            _m('Use an HTML template for Web output.'));
+        return true;
+    }
+
+}
+
+/**
+ * Function for retrieving a statusnet display section
+ *
+ * requires one parameter, the name of the section
+ * section names are listed in the comments of the TemplatePlugin class
+ *
+ * @category Plugin
+ * @package  StatusNet
+ * @author   Brian Hendrickson <brian@megapump.com>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://megapump.com/
+ *
+ */
+
+function section($tagname) {
+  global $tags;
+  if (isset($tags[$tagname]))
+    return $tags[$tagname];
+}
+
diff --git a/plugins/TemplatePlugin.php b/plugins/TemplatePlugin.php
deleted file mode 100644 (file)
index 80625c5..0000000
+++ /dev/null
@@ -1,357 +0,0 @@
-<?php
-/**
- * Plugin to render old skool templates
- *
- * Captures rendered parts from the output buffer, passes them through a template file: tpl/index.html
- * Adds an API method at index.php/template/update which lets you overwrite the template file
- * Requires username/password and a single POST parameter called "template"
- * The method is disabled unless the user is #1, the first user of the system
- *
- * @category  Plugin
- * @package   StatusNet
- * @author    Brian Hendrickson <brian@megapump.com>
- * @copyright 2009 Megapump, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://megapump.com/
- */
-
-if (!defined('STATUSNET')) {
-    exit(1);
-}
-
-define('TEMPLATEPLUGIN_VERSION', '0.1');
-
-class TemplatePlugin extends Plugin {
-
-  var $blocks = array();
-
-  function __construct() {
-    parent::__construct();
-  }
-
-  // capture the RouterInitialized event
-  // and connect a new API method
-  // for updating the template
-  function onRouterInitialized( $m ) {
-    $m->connect( 'template/update', array(
-      'action'      => 'template',
-    ));
-  }
-
-  // <%styles%>
-  // <%scripts%>
-  // <%search%>
-  // <%feeds%>
-  // <%description%>
-  // <%head%>
-  function onStartShowHead( &$act ) {
-    $this->clear_xmlWriter($act);
-    $act->extraHead();
-    $this->blocks['head'] = $act->xw->flush();
-    $act->showStylesheets();
-    $this->blocks['styles'] = $act->xw->flush();
-    $act->showScripts();
-    $this->blocks['scripts'] = $act->xw->flush();
-    $act->showFeeds();
-    $this->blocks['feeds'] = $act->xw->flush();
-    $act->showOpenSearch();
-    $this->blocks['search'] = $act->xw->flush();
-    $act->showDescription();
-    $this->blocks['description'] = $act->xw->flush();
-    return false;
-  }
-
-  // <%bodytext%>
-  function onStartShowContentBlock( &$act ) {
-    $this->clear_xmlWriter($act);
-    return true;
-  }
-  function onEndShowContentBlock( &$act ) {
-    $this->blocks['bodytext'] = $act->xw->flush();
-  }
-
-  // <%localnav%>
-  function onStartShowLocalNavBlock( &$act ) {
-    $this->clear_xmlWriter($act);
-    return true;
-  }
-  function onEndShowLocalNavBlock( &$act ) {
-    $this->blocks['localnav'] = $act->xw->flush();
-  }
-
-  // <%export%>
-  function onStartShowExportData( &$act ) {
-    $this->clear_xmlWriter($act);
-    return true;
-  }
-  function onEndShowExportData( &$act ) {
-    $this->blocks['export'] = $act->xw->flush();
-  }
-
-  // <%subscriptions%>
-  // <%subscribers%>
-  // <%groups%>
-  // <%statistics%>
-  // <%cloud%>
-  // <%groupmembers%>
-  // <%groupstatistics%>
-  // <%groupcloud%>
-  // <%popular%>
-  // <%groupsbyposts%>
-  // <%featuredusers%>
-  // <%groupsbymembers%>
-  function onStartShowSections( &$act ) {
-    global $action;
-    $this->clear_xmlWriter($act);
-    switch ($action) {
-      case "showstream":
-        $act->showSubscriptions();
-        $this->blocks['subscriptions'] = $act->xw->flush();
-        $act->showSubscribers();
-        $this->blocks['subscribers'] = $act->xw->flush();
-        $act->showGroups();
-        $this->blocks['groups'] = $act->xw->flush();
-        $act->showStatistics();
-        $this->blocks['statistics'] = $act->xw->flush();
-        $cloud = new PersonalTagCloudSection($act, $act->user);
-        $cloud->show();
-        $this->blocks['cloud'] = $act->xw->flush();
-        break;
-      case "showgroup":
-        $act->showMembers();
-        $this->blocks['groupmembers'] = $act->xw->flush();
-        $act->showStatistics();
-        $this->blocks['groupstatistics'] = $act->xw->flush();
-        $cloud = new GroupTagCloudSection($act, $act->group);
-        $cloud->show();
-        $this->blocks['groupcloud'] = $act->xw->flush();
-        break;
-      case "public":
-        $pop = new PopularNoticeSection($act);
-        $pop->show();
-        $this->blocks['popular'] = $act->xw->flush();
-        $gbp = new GroupsByPostsSection($act);
-        $gbp->show();
-        $this->blocks['groupsbyposts'] = $act->xw->flush();
-        $feat = new FeaturedUsersSection($act);
-        $feat->show();
-        $this->blocks['featuredusers'] = $act->xw->flush();
-        break;
-      case "groups":
-        $gbp = new GroupsByPostsSection($act);
-        $gbp->show();
-        $this->blocks['groupsbyposts'] = $act->xw->flush();
-        $gbm = new GroupsByMembersSection($act);
-        $gbm->show();
-        $this->blocks['groupsbymembers'] = $act->xw->flush();
-        break;
-    }
-    return false;
-  }
-
-  // <%logo%>
-  // <%nav%>
-  // <%notice%>
-  // <%noticeform%>
-  function onStartShowHeader( &$act ) {
-    $this->clear_xmlWriter($act);
-    $act->showLogo();
-    $this->blocks['logo'] = $act->xw->flush();
-    $act->showPrimaryNav();
-    $this->blocks['nav'] = $act->xw->flush();
-    $act->showSiteNotice();
-    $this->blocks['notice'] = $act->xw->flush();
-    if (common_logged_in()) {
-        $act->showNoticeForm();
-    } else {
-        $act->showAnonymousMessage();
-    }
-    $this->blocks['noticeform'] = $act->xw->flush();
-    return false;
-  }
-
-  // <%secondarynav%>
-  // <%licenses%>
-  function onStartShowFooter( &$act ) {
-    $this->clear_xmlWriter($act);
-    $act->showSecondaryNav();
-    $this->blocks['secondarynav'] = $act->xw->flush();
-    $act->showLicenses();
-    $this->blocks['licenses'] = $act->xw->flush();
-    return false;
-  }
-
-  // capture the EndHTML event
-  // and include the template
-  function onEndEndHTML($act) {
-
-    global $action, $tags;
-
-    // set the action and title values
-    $vars = array(
-      'action'=>$action,
-      'title'=>$act->title(). " - ". common_config('site', 'name')
-    );
-
-    // use the PHP template
-    // unless statusnet config:
-    //   $config['template']['mode'] = 'html';
-    if (!(common_config('template', 'mode') == 'html')) {
-      $tpl_file = $this->templateFolder() . '/index.php';
-      $tags = array_merge($vars,$this->blocks);
-      include $tpl_file;
-      return;
-    }
-
-    $tpl_file = $this->templateFolder() . '/index.html';
-
-    // read the static template
-    $output = file_get_contents( $tpl_file );
-
-    $tags = array();
-
-    // get a list of the <%tags%> in the template
-    $pattern='/<%([a-z]+)%>/';
-
-    if ( 1 <= preg_match_all( $pattern, $output, $found ))
-      $tags[] = $found;
-
-    // for each found tag, set its value from the rendered blocks
-    foreach( $tags[0][1] as $pos=>$tag ) {
-      if (isset($this->blocks[$tag]))
-        $vars[$tag] = $this->blocks[$tag];
-
-      // didn't find a block for the tag
-      elseif (!isset($vars[$tag]))
-        $vars[$tag] = '';
-    }
-
-    // replace the tags in the template
-    foreach( $vars as $key=>$val )
-      $output = str_replace( '<%'.$key.'%>', $val, $output );
-
-    echo $output;
-
-    return true;
-
-  }
-  function templateFolder() {
-    return 'tpl';
-  }
-
-  // catching the StartShowHTML event to halt the rendering
-  function onStartShowHTML( &$act ) {
-    $this->clear_xmlWriter($act);
-    return true;
-  }
-
-  // clear the xmlWriter
-  function clear_xmlWriter( &$act ) {
-    $act->xw->openMemory();
-    $act->xw->setIndent(true);
-  }
-
-}
-
-/**
- * Action for updating the template remotely
- *
- * "template/update" -- a POST method that requires a single
- * parameter "template", containing the new template code
- *
- * @category Plugin
- * @package  StatusNet
- * @author   Brian Hendrickson <brian@megapump.com>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://megapump.com/
- *
- */
-
-class TemplateAction extends Action
-{
-
-  function prepare($args) {
-    parent::prepare($args);
-    return true;
-  }
-
-  function handle($args) {
-
-    parent::handle($args);
-
-    if (!isset($_SERVER['PHP_AUTH_USER'])) {
-
-      // not authenticated, show login form
-      header('WWW-Authenticate: Basic realm="StatusNet API"');
-
-      // cancelled the browser login form
-      $this->clientError(_('Authentication error!'), $code = 401);
-
-    } else {
-
-      $nick = $_SERVER['PHP_AUTH_USER'];
-      $pass = $_SERVER['PHP_AUTH_PW'];
-
-      // check username and password
-      $user = common_check_user($nick,$pass);
-
-      if ($user) {
-
-        // verify that user is admin
-        if (!($user->id == 1))
-          $this->clientError(_('Only User #1 can update the template.'), $code = 401);
-
-        // open the old template
-        $tpl_file = $this->templateFolder() . '/index.html';
-        $fp = fopen( $tpl_file, 'w+' );
-
-        // overwrite with the new template
-        fwrite($fp, $this->arg('template'));
-        fclose($fp);
-
-        header('HTTP/1.1 200 OK');
-        header('Content-type: text/plain');
-        print "Template Updated!";
-
-      } else {
-
-        // bad username and password
-        $this->clientError(_('Authentication error!'), $code = 401);
-
-      }
-
-    }
-  }
-    function onPluginVersion(&$versions)
-    {
-        $versions[] = array('name' => 'Template',
-                            'version' => TEMPLATEPLUGIN_VERSION,
-                            'author' => 'Brian Hendrickson',
-                            'homepage' => 'http://status.net/wiki/Plugin:Template',
-                            'rawdescription' =>
-                            _m('Use an HTML template for Web output.'));
-        return true;
-    }
-
-}
-
-/**
- * Function for retrieving a statusnet display section
- *
- * requires one parameter, the name of the section
- * section names are listed in the comments of the TemplatePlugin class
- *
- * @category Plugin
- * @package  StatusNet
- * @author   Brian Hendrickson <brian@megapump.com>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://megapump.com/
- *
- */
-
-function section($tagname) {
-  global $tags;
-  if (isset($tags[$tagname]))
-    return $tags[$tagname];
-}
-
diff --git a/plugins/UserLimit/UserLimitPlugin.php b/plugins/UserLimit/UserLimitPlugin.php
new file mode 100644 (file)
index 0000000..ab31872
--- /dev/null
@@ -0,0 +1,92 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Plugin to limit number of users that can register (best for cloud providers)
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Action
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+/**
+ * Plugin to limit number of users that can register (best for cloud providers)
+ *
+ * For cloud providers whose freemium model is based on how many
+ * users can register. We use it on the StatusNet Cloud.
+ *
+ * @category Plugin
+ * @package  StatusNet
+ * @author   Evan Prodromou <evan@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ *
+ * @seeAlso  Location
+ */
+
+class UserLimitPlugin extends Plugin
+{
+    public $maxUsers = null;
+
+    function onStartUserRegister(&$user, &$profile)
+    {
+        $this->_checkMaxUsers();
+        return true;
+    }
+
+    function onStartRegistrationTry($action)
+    {
+        $this->_checkMaxUsers();
+        return true;
+    }
+
+    function _checkMaxUsers()
+    {
+        if (!is_null($this->maxUsers)) {
+
+            $cls = new User();
+
+            $cnt = $cls->count();
+
+            if ($cnt >= $this->maxUsers) {
+                $msg = sprintf(_('Cannot register; maximum number of users (%d) reached.'),
+                               $this->maxUsers);
+
+                throw new ClientException($msg);
+            }
+        }
+    }
+
+    function onPluginVersion(&$versions)
+    {
+        $versions[] = array('name' => 'UserLimit',
+                            'version' => STATUSNET_VERSION,
+                            'author' => 'Evan Prodromou',
+                            'homepage' => 'http://status.net/wiki/Plugin:UserLimit',
+                            'description' =>
+                            _m('Limit the number of users who can register.'));
+        return true;
+    }
+}
diff --git a/plugins/UserLimitPlugin.php b/plugins/UserLimitPlugin.php
deleted file mode 100644 (file)
index ab31872..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Plugin to limit number of users that can register (best for cloud providers)
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Action
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2009 StatusNet Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    exit(1);
-}
-
-/**
- * Plugin to limit number of users that can register (best for cloud providers)
- *
- * For cloud providers whose freemium model is based on how many
- * users can register. We use it on the StatusNet Cloud.
- *
- * @category Plugin
- * @package  StatusNet
- * @author   Evan Prodromou <evan@status.net>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://status.net/
- *
- * @seeAlso  Location
- */
-
-class UserLimitPlugin extends Plugin
-{
-    public $maxUsers = null;
-
-    function onStartUserRegister(&$user, &$profile)
-    {
-        $this->_checkMaxUsers();
-        return true;
-    }
-
-    function onStartRegistrationTry($action)
-    {
-        $this->_checkMaxUsers();
-        return true;
-    }
-
-    function _checkMaxUsers()
-    {
-        if (!is_null($this->maxUsers)) {
-
-            $cls = new User();
-
-            $cnt = $cls->count();
-
-            if ($cnt >= $this->maxUsers) {
-                $msg = sprintf(_('Cannot register; maximum number of users (%d) reached.'),
-                               $this->maxUsers);
-
-                throw new ClientException($msg);
-            }
-        }
-    }
-
-    function onPluginVersion(&$versions)
-    {
-        $versions[] = array('name' => 'UserLimit',
-                            'version' => STATUSNET_VERSION,
-                            'author' => 'Evan Prodromou',
-                            'homepage' => 'http://status.net/wiki/Plugin:UserLimit',
-                            'description' =>
-                            _m('Limit the number of users who can register.'));
-        return true;
-    }
-}
diff --git a/plugins/WikiHashtags/WikiHashtagsPlugin.php b/plugins/WikiHashtags/WikiHashtagsPlugin.php
new file mode 100644 (file)
index 0000000..c6c976b
--- /dev/null
@@ -0,0 +1,113 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Plugin to show WikiHashtags content in the sidebar
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Plugin
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2008 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+/**
+ * Plugin to use WikiHashtags
+ *
+ * @category Plugin
+ * @package  StatusNet
+ * @author   Evan Prodromou <evan@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ *
+ * @see      Event
+ */
+
+class WikiHashtagsPlugin extends Plugin
+{
+    const VERSION = '0.1';
+
+    function __construct($code=null)
+    {
+        parent::__construct();
+    }
+
+    function onStartShowSections($action)
+    {
+        $name = $action->trimmed('action');
+
+        if ($name == 'tag') {
+
+            $taginput = $action->trimmed('tag');
+            $tag = common_canonical_tag($taginput);
+
+            if (!empty($tag)) {
+
+                $url = sprintf('http://hashtags.wikia.com/index.php?title=%s&action=render',
+                               urlencode($tag));
+                $editurl = sprintf('http://hashtags.wikia.com/index.php?title=%s&action=edit',
+                                   urlencode($tag));
+
+                $request = HTTPClient::start();
+                $response = $request->get($url);
+                $html = $response->getBody();
+
+                $action->elementStart('div', array('id' => 'wikihashtags', 'class' => 'section'));
+
+                if ($response->isOk() && !empty($html)) {
+                    $action->element('style', null,
+                                     "span.editsection { display: none }\n".
+                                     "table.toc { display: none }");
+                    $action->raw($html);
+                    $action->elementStart('p');
+                    $action->element('a', array('href' => $editurl,
+                                                'title' => sprintf(_('Edit the article for #%s on WikiHashtags'), $tag)),
+                                     _('Edit'));
+                    $action->element('a', array('href' => 'http://www.gnu.org/copyleft/fdl.html',
+                                                'title' => _('Shared under the terms of the GNU Free Documentation License'),
+                                                'rel' => 'license'),
+                                     'GNU FDL');
+                    $action->elementEnd('p');
+                } else {
+                    $action->element('a', array('href' => $editurl),
+                                     sprintf(_('Start the article for #%s on WikiHashtags'), $tag));
+                }
+
+                $action->elementEnd('div');
+            }
+        }
+
+        return true;
+    }
+
+    function onPluginVersion(&$versions)
+    {
+        $versions[] = array('name' => 'WikiHashtags',
+                            'version' => self::VERSION,
+                            'author' => 'Evan Prodromou',
+                            'homepage' => 'http://status.net/wiki/Plugin:WikiHashtags',
+                            'rawdescription' =>
+                            _m('Gets hashtag descriptions from <a href="http://hashtags.wikia.com/">WikiHashtags</a>.'));
+        return true;
+    }
+}
diff --git a/plugins/WikiHashtagsPlugin.php b/plugins/WikiHashtagsPlugin.php
deleted file mode 100644 (file)
index c6c976b..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Plugin to show WikiHashtags content in the sidebar
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Plugin
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2008 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    exit(1);
-}
-
-/**
- * Plugin to use WikiHashtags
- *
- * @category Plugin
- * @package  StatusNet
- * @author   Evan Prodromou <evan@status.net>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://status.net/
- *
- * @see      Event
- */
-
-class WikiHashtagsPlugin extends Plugin
-{
-    const VERSION = '0.1';
-
-    function __construct($code=null)
-    {
-        parent::__construct();
-    }
-
-    function onStartShowSections($action)
-    {
-        $name = $action->trimmed('action');
-
-        if ($name == 'tag') {
-
-            $taginput = $action->trimmed('tag');
-            $tag = common_canonical_tag($taginput);
-
-            if (!empty($tag)) {
-
-                $url = sprintf('http://hashtags.wikia.com/index.php?title=%s&action=render',
-                               urlencode($tag));
-                $editurl = sprintf('http://hashtags.wikia.com/index.php?title=%s&action=edit',
-                                   urlencode($tag));
-
-                $request = HTTPClient::start();
-                $response = $request->get($url);
-                $html = $response->getBody();
-
-                $action->elementStart('div', array('id' => 'wikihashtags', 'class' => 'section'));
-
-                if ($response->isOk() && !empty($html)) {
-                    $action->element('style', null,
-                                     "span.editsection { display: none }\n".
-                                     "table.toc { display: none }");
-                    $action->raw($html);
-                    $action->elementStart('p');
-                    $action->element('a', array('href' => $editurl,
-                                                'title' => sprintf(_('Edit the article for #%s on WikiHashtags'), $tag)),
-                                     _('Edit'));
-                    $action->element('a', array('href' => 'http://www.gnu.org/copyleft/fdl.html',
-                                                'title' => _('Shared under the terms of the GNU Free Documentation License'),
-                                                'rel' => 'license'),
-                                     'GNU FDL');
-                    $action->elementEnd('p');
-                } else {
-                    $action->element('a', array('href' => $editurl),
-                                     sprintf(_('Start the article for #%s on WikiHashtags'), $tag));
-                }
-
-                $action->elementEnd('div');
-            }
-        }
-
-        return true;
-    }
-
-    function onPluginVersion(&$versions)
-    {
-        $versions[] = array('name' => 'WikiHashtags',
-                            'version' => self::VERSION,
-                            'author' => 'Evan Prodromou',
-                            'homepage' => 'http://status.net/wiki/Plugin:WikiHashtags',
-                            'rawdescription' =>
-                            _m('Gets hashtag descriptions from <a href="http://hashtags.wikia.com/">WikiHashtags</a>.'));
-        return true;
-    }
-}
diff --git a/plugins/XCache/XCachePlugin.php b/plugins/XCache/XCachePlugin.php
new file mode 100644 (file)
index 0000000..2baa290
--- /dev/null
@@ -0,0 +1,124 @@
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * Plugin to implement cache interface for XCache variable cache
+ *
+ * PHP version 5
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Cache
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    // This check helps protect against security problems;
+    // your code file can't be executed directly from the web.
+    exit(1);
+}
+
+/**
+ * A plugin to use XCache's variable cache for the cache interface
+ *
+ * New plugin interface lets us use alternative cache systems
+ * for caching. This one uses XCache's variable cache.
+ *
+ * @category  Cache
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+class XCachePlugin extends Plugin
+{
+    /**
+     * Get a value associated with a key
+     *
+     * The value should have been set previously.
+     *
+     * @param string &$key   in; Lookup key
+     * @param mixed  &$value out; value associated with key
+     *
+     * @return boolean hook success
+     */
+
+    function onStartCacheGet(&$key, &$value)
+    {
+        if (!xcache_isset($key)) {
+            $value = false;
+        } else {
+            $value = xcache_get($key);
+            $value = unserialize($value);
+        }
+        Event::handle('EndCacheGet', array($key, &$value));
+        return false;
+    }
+
+    /**
+     * Associate a value with a key
+     *
+     * @param string  &$key     in; Key to use for lookups
+     * @param mixed   &$value   in; Value to associate
+     * @param integer &$flag    in; Flag (passed through to Memcache)
+     * @param integer &$expiry  in; Expiry (passed through to Memcache)
+     * @param boolean &$success out; Whether the set was successful
+     *
+     * @return boolean hook success
+     */
+
+    function onStartCacheSet(&$key, &$value, &$flag, &$expiry, &$success)
+    {
+        $success = xcache_set($key, serialize($value));
+
+        Event::handle('EndCacheSet', array($key, $value, $flag,
+                                           $expiry));
+        return false;
+    }
+
+    /**
+     * Delete a value associated with a key
+     *
+     * @param string  &$key     in; Key to lookup
+     * @param boolean &$success out; whether it worked
+     *
+     * @return boolean hook success
+     */
+
+    function onStartCacheDelete(&$key, &$success)
+    {
+        $success = xcache_unset($key);
+        Event::handle('EndCacheDelete', array($key));
+        return false;
+    }
+
+    function onPluginVersion(&$versions)
+    {
+        $versions[] = array('name' => 'XCache',
+                            'version' => STATUSNET_VERSION,
+                            'author' => 'Craig Andrews',
+                            'homepage' => 'http://status.net/wiki/Plugin:XCache',
+                            'rawdescription' =>
+                            _m('Use the <a href="http://xcache.lighttpd.net/">XCache</a> variable cache to cache query results.'));
+        return true;
+    }
+}
+
diff --git a/plugins/XCachePlugin.php b/plugins/XCachePlugin.php
deleted file mode 100644 (file)
index 2baa290..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, StatusNet, Inc.
- *
- * Plugin to implement cache interface for XCache variable cache
- *
- * PHP version 5
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Cache
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2009 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    // This check helps protect against security problems;
-    // your code file can't be executed directly from the web.
-    exit(1);
-}
-
-/**
- * A plugin to use XCache's variable cache for the cache interface
- *
- * New plugin interface lets us use alternative cache systems
- * for caching. This one uses XCache's variable cache.
- *
- * @category  Cache
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2009 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-class XCachePlugin extends Plugin
-{
-    /**
-     * Get a value associated with a key
-     *
-     * The value should have been set previously.
-     *
-     * @param string &$key   in; Lookup key
-     * @param mixed  &$value out; value associated with key
-     *
-     * @return boolean hook success
-     */
-
-    function onStartCacheGet(&$key, &$value)
-    {
-        if (!xcache_isset($key)) {
-            $value = false;
-        } else {
-            $value = xcache_get($key);
-            $value = unserialize($value);
-        }
-        Event::handle('EndCacheGet', array($key, &$value));
-        return false;
-    }
-
-    /**
-     * Associate a value with a key
-     *
-     * @param string  &$key     in; Key to use for lookups
-     * @param mixed   &$value   in; Value to associate
-     * @param integer &$flag    in; Flag (passed through to Memcache)
-     * @param integer &$expiry  in; Expiry (passed through to Memcache)
-     * @param boolean &$success out; Whether the set was successful
-     *
-     * @return boolean hook success
-     */
-
-    function onStartCacheSet(&$key, &$value, &$flag, &$expiry, &$success)
-    {
-        $success = xcache_set($key, serialize($value));
-
-        Event::handle('EndCacheSet', array($key, $value, $flag,
-                                           $expiry));
-        return false;
-    }
-
-    /**
-     * Delete a value associated with a key
-     *
-     * @param string  &$key     in; Key to lookup
-     * @param boolean &$success out; whether it worked
-     *
-     * @return boolean hook success
-     */
-
-    function onStartCacheDelete(&$key, &$success)
-    {
-        $success = xcache_unset($key);
-        Event::handle('EndCacheDelete', array($key));
-        return false;
-    }
-
-    function onPluginVersion(&$versions)
-    {
-        $versions[] = array('name' => 'XCache',
-                            'version' => STATUSNET_VERSION,
-                            'author' => 'Craig Andrews',
-                            'homepage' => 'http://status.net/wiki/Plugin:XCache',
-                            'rawdescription' =>
-                            _m('Use the <a href="http://xcache.lighttpd.net/">XCache</a> variable cache to cache query results.'));
-        return true;
-    }
-}
-