code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Form for silencing a user
 *
 * 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  Form
 * @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);
}

/**
 * Form for silencing a user
 *
 * @category Form
 * @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      UnSilenceForm
 */
class SilenceForm extends ProfileActionForm
{
    /**
     * Action this form provides
     *
     * @return string Name of the action, lowercased.
     */
    function target()
    {
        return 'silence';
    }

    /**
     * Title of the form
     *
     * @return string Title of the form, internationalized
     */
    function title()
    {
        // TRANS: Title of form to silence a user.
        return _m('TITLE','Silence');
    }

    /**
     * Description of the form
     *
     * @return string description of the form, internationalized
     */
    function description()
    {
        // TRANS: Description of form to silence a user.
        return _('Silence this user');
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * A site profile is a set of default settings for a particular style of
 * StatusNet site: public, private, community, etc.
 *
 * 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  Installation
 * @package   StatusNet
 * @author    Zach Copley <zach@status.net>
 * @copyright 2011 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('GNUSOCIAL')) {
    exit(1);
}

/**
 * Helper class for getting the settings for a particular site profile
 */
class SiteProfile
{
    /**
     * Returns the config settings for a site profile by name
     *
     * @param  string $name name of a site profile
     * @return array  config settings
     */
    static public function getSettings($name)
    {
        $sprofileClass = ucfirst($name) . "Site";

        if (class_exists($sprofileClass)) {
            return call_user_func(array($sprofileClass, 'getSettings'));
        } else {
            common_log(
                LOG_ERR,
                "Unknown site profile '{$name}' specified in config file.",
                __FILE__
            );
            return array();
        }
    }
}

/**
 * Site profile settings contain the list of the default settings (and
 * possibly other information for a particular flavor of StatusNet
 * installation). These will overwrite base defaults in $config global.
 *
 * @category Installation
 * @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/
 */
abstract class SiteProfileSettings
{
    static function getSettings()
    {
        throw new MethodNotImplementedException(__METHOD__);
    }

    static function corePlugins() {
        return common_config('plugins', 'core');
    }
    static function defaultPlugins() {
        return common_config('plugins', 'default');
    }
}

/**
 * Settings for a 'public' site
 */
class PublicSite extends SiteProfileSettings
{
    /**
     * Get the settings for this site profile
     *
     * @return type array   an array of settings
     */
    static function getSettings() {
        global $config;
        return array(
            // We only want to change these values, not replace entire 'site' array
            'site' => array_merge(
                $config['site'], array(
                    'inviteonly' => false,
                    'private'    => false,
                    'closed'     => false
                )
            ),
            'plugins' => array(
                'core'    => self::corePlugins(),
                'default' => array_merge(self::defaultPlugins(), array(
                    'ExtendedProfile'         => array(),
                    'RegisterThrottle'        => array(),
                ))
            ),
            'discovery' => array('cors' => true) // Allow Cross-Origin Resource Sharing for service discovery (host-meta, XRD, etc.)
        );
    }
}

/**
 * Settings for a 'private' site
 *
 * // XXX Too business oriented?
 */
class PrivateSite extends SiteProfileSettings
{
    /**
     * Get the settings for this site profile
     *
     * @return type array  an array of settings
     */
    static function getSettings() {
        global $config;
        return array(
            // We only want to change these values, not replace entire 'site' array
            'site' => array_merge(
                $config['site'], array(
                    'inviteonly' => true,
                    'private'    => true,
                )
            ),
            'plugins' => array(
                'core'    => self::corePlugins(),
                'default' => array_merge(self::defaultPlugins(), array(
                    'ExtendedProfile'         => array(),
                    'EmailRegistration'       => array(),
                    'MobileProfile'           => array(),
                )),
                'disable-OStatus' => 1,
                'disable-WebFinger' => 1,
             ),
            'public'        => array('localonly' => true),
            'profile'       => array('delete' => 'true'),
            'license'       => array('type'   => 'private'),
            'attachments'   => array(
                // Only allow uploads of pictures and MS Office files
                'supported' => array(
                    'image/png',
                    'image/jpeg',
                    'image/gif',
                    'image/svg+xml',
                    'application/pdf',
                    'application/msword',
                    'application/vnd.ms-office',
                    'application/vnd.ms-excel',
                    'application/vnd.ms-powerpoint',
                    'application/ogg'
                )
             ),
            'discovery' => array('cors'   => false) // Allow Cross-Origin Resource Sharing for service discovery (host-meta, XRD, etc.)
        );
    }
}

/**
 * Settings for a 'community' site
 */
class CommunitySite extends SiteProfileSettings
{
    /**
     * Get the settings for this site profile
     *
     * @return type array  an array of settings
     */
    static function getSettings() {
        global $config;
        return array(
            // We only want to change these values, not replace entire 'site' array
            'site' => array_merge(
                $config['site'], array(
                    'private'    => false,
                    'inviteonly' => true,
                    'closed'     => false
                )
            ),
            'plugins' => array(
                'core'    => self::corePlugins(),
                'default' => array_merge(self::defaultPlugins(), array(
                ))
            ),
            'public'    => array('localonly' => true),
            'discovery' => array('cors' => true) // Allow Cross-Origin Resource Sharing for service discovery (host-meta, XRD, etc.)
        );
    }

}

/**
 * Settings for a 'singleuser' site
 */
class SingleuserSite extends SiteProfileSettings
{
    /**
     * Get the settings for this site profile
     *
     * @return type array  an array of settings
     */
    static function getSettings() {
        global $config;
        return array(
            'singleuser' => array('enabled' => true),
            // We only want to change these values, not replace entire 'site' array
            'site' => array_merge(
                $config['site'], array(
                    'private'    => false,
                    'closed'     => true,
                    'localonly'  => true,
                )
            ),
            'plugins' => array(
                'core'    => self::corePlugins(),
                'default' => array_merge(self::defaultPlugins(), array(
                    'MobileProfile'           => array(),
                )),
                'disable-Directory' => 1,
            ),
            'public'    => array('localonly' => true),
            'discovery' => array('cors' => true) // Allow Cross-Origin Resource Sharing for service discovery (host-meta, XRD, etc.)
        );
    }

}

license: mit


code:
<?php
/*
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * 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/>.
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Queue handler for pushing new notices to local subscribers using SMS.
 */
class SmsQueueHandler extends QueueHandler
{
    function transport()
    {
        return 'sms';
    }

    function handle($notice)
    {
    	require_once(INSTALLDIR.'/lib/mail.php');
        return mail_broadcast_notice_sms($notice);
    }
}


code:
<?php
/*
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2010, StatusNet, Inc.
 *
 * 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/>.
 */

/**
 * Base class for daemon that can launch one or more processing threads,
 * respawning them if they exit.
 *
 * This is mainly intended for indefinite workloads such as monitoring
 * a queue or maintaining an IM channel.
 *
 * Child classes should implement the
 *
 * We can then pass individual items through the QueueHandler subclasses
 * they belong to. We additionally can handle queues for multiple sites.
 *
 * @package QueueHandler
 * @author Brion Vibber <brion@status.net>
 */
abstract class SpawningDaemon extends Daemon
{
    protected $threads=1;

    const EXIT_OK = 0;
    const EXIT_ERR = 1;
    const EXIT_SHUTDOWN = 100;
    const EXIT_RESTART = 101;

    function __construct($id=null, $daemonize=true, $threads=1)
    {
        parent::__construct($daemonize);

        if ($id) {
            $this->set_id($id);
        }
        $this->threads = $threads;
    }

    /**
     * Perform some actual work!
     *
     * @return int exit code; use self::EXIT_SHUTDOWN to request not to respawn.
     */
    public abstract function runThread();

    /**
     * Spawn one or more background processes and let them start running.
     * Each individual process will execute whatever's in the runThread()
     * method, which should be overridden.
     *
     * Child processes will be automatically respawned when they exit.
     *
     * @todo possibly allow for not respawning on "normal" exits...
     *       though ParallelizingDaemon is probably better for workloads
     *       that have forseeable endpoints.
     */
    function run()
    {
        $this->initPipes();

        $children = array();
        for ($i = 1; $i <= $this->threads; $i++) {
            $pid = pcntl_fork();
            if ($pid < 0) {
                $this->log(LOG_ERROR, "Couldn't fork for thread $i; aborting\n");
                exit(1);
            } else if ($pid == 0) {
                $this->initAndRunChild($i);
            } else {
                $this->log(LOG_INFO, "Spawned thread $i as pid $pid");
                $children[$i] = $pid;
            }
            sleep(common_config('queue', 'spawndelay'));
        }

        $this->log(LOG_INFO, "Waiting for children to complete.");
        while (count($children) > 0) {
            $status = null;
            $pid = pcntl_wait($status);
            if ($pid > 0) {
                $i = array_search($pid, $children);
                if ($i === false) {
                    $this->log(LOG_ERR, "Ignoring exit of unrecognized child pid $pid");
                    continue;
                }
                if (pcntl_wifexited($status)) {
                    $exitCode = pcntl_wexitstatus($status);
                    $info = "status $exitCode";
                } else if (pcntl_wifsignaled($status)) {
                    $exitCode = self::EXIT_ERR;
                    $signal = pcntl_wtermsig($status);
                    $info = "signal $signal";
                }
                unset($children[$i]);

                if ($this->shouldRespawn($exitCode)) {
                    $this->log(LOG_INFO, "Thread $i pid $pid exited with $info; respawing.");

                    $pid = pcntl_fork();
                    if ($pid < 0) {
                        $this->log(LOG_ERROR, "Couldn't fork to respawn thread $i; aborting thread.\n");
                    } else if ($pid == 0) {
                        $this->initAndRunChild($i);
                    } else {
                        $this->log(LOG_INFO, "Respawned thread $i as pid $pid");
                        $children[$i] = $pid;
                    }
                    sleep(common_config('queue', 'spawndelay'));
                } else {
                    $this->log(LOG_INFO, "Thread $i pid $pid exited with status $exitCode; closing out thread.");
                }
            }
        }
        $this->log(LOG_INFO, "All child processes complete.");
        return true;
    }

    /**
     * Create an IPC socket pair which child processes can use to detect
     * if the parent process has been killed.
     */
    function initPipes()
    {
        $sockets = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, 0);
        if ($sockets) {
            $this->parentWriter = $sockets[0];
            $this->parentReader = $sockets[1];
        } else {
            $this->log(LOG_ERROR, "Couldn't create inter-process sockets");
            exit(1);
        }
    }

    /**
     * Build an IOManager that simply ensures that we have a connection
     * to the parent process open. If it breaks, the child process will
     * die.
     *
     * @return ProcessManager
     */
    public function processManager()
    {
        return new ProcessManager($this->parentReader);
    }

    /**
     * Determine whether to respawn an exited subprocess based on its exit code.
     * Otherwise we'll respawn all exits by default.
     *
     * @param int $exitCode
     * @return boolean true to respawn
     */
    protected function shouldRespawn($exitCode)
    {
        if ($exitCode == self::EXIT_SHUTDOWN) {
            // Thread requested a clean shutdown.
            return false;
        } else {
            // Otherwise we should always respawn!
            return true;
        }
    }

    /**
     * Initialize things for a fresh thread, call runThread(), and
     * exit at completion with appropriate return value.
     */
    protected function initAndRunChild($thread)
    {
        // Close the writer end of our parent<->children pipe.
        fclose($this->parentWriter);
        $this->set_id($this->get_id() . "." . $thread);
        $this->resetDb();
        $exitCode = $this->runThread();
        exit($exitCode);
    }

    /**
     * Reconnect to the database for each child process,
     * or they'll get very confused trying to use the
     * same socket.
     */
    protected function resetDb()
    {
        // @fixme do we need to explicitly open the db too
        // or is this implied?
        global $_DB_DATAOBJECT;
        unset($_DB_DATAOBJECT['CONNECTIONS']);

        // Reconnect main memcached, or threads will stomp on
        // each other and corrupt their requests.
        $cache = Cache::instance();
        if ($cache) {
            $cache->reconnect();
        }

        // Also reconnect memcached for status_network table.
        if (!empty(Status_network::$cache)) {
            Status_network::$cache->close();
            Status_network::$cache = null;
        }
    }

    function log($level, $msg)
    {
        common_log($level, get_class($this) . ' ('. $this->get_id() .'): '.$msg);
    }

    function name()
    {
        return strtolower(get_class($this).'.'.$this->get_id());
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2009-2010 StatusNet, Inc.
 *
 * 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/>.
 *
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

global $config, $_server, $_path;

/**
 * Global configuration setup and management.
 */
class StatusNet
{
    protected static $have_config;
    protected static $is_api;
    protected static $is_ajax;
    protected static $plugins = array();

    /**
     * Configure and instantiate a plugin into the current configuration.
     * Class definitions will be loaded from standard paths if necessary.
     * Note that initialization events won't be fired until later.
     *
     * @param string $name class name & plugin file/subdir name
     * @param array $attrs key/value pairs of public attributes to set on plugin instance
     *
     * @throws ServerException if plugin can't be found
     */
    public static function addPlugin($name, array $attrs=array())
    {
        $name = ucfirst($name);

        if (isset(self::$plugins[$name])) {
            // We have already loaded this plugin. Don't try to
            // do it again with (possibly) different values.
            // Försten till kvarn får mala.
            return true;
        }

        $pluginclass = "{$name}Plugin";

        if (!class_exists($pluginclass)) {

            $files = array("local/plugins/{$pluginclass}.php",
                           "local/plugins/{$name}/{$pluginclass}.php",
                           "local/{$pluginclass}.php",
                           "local/{$name}/{$pluginclass}.php",
                           "plugins/{$pluginclass}.php",
                           "plugins/{$name}/{$pluginclass}.php");

            foreach ($files as $file) {
                $fullpath = INSTALLDIR.'/'.$file;
                if (@file_exists($fullpath)) {
                    include_once($fullpath);
                    break;
                }
            }
            if (!class_exists($pluginclass)) {
                throw new ServerException("Plugin $name not found.", 500);
            }
        }

        // Doesn't this $inst risk being garbage collected or something?
        // TODO: put into a static array that makes sure $inst isn't lost.
        $inst = new $pluginclass();
        foreach ($attrs as $aname => $avalue) {
            $inst->$aname = $avalue;
        }

        // Record activated plugins for later display/config dump
        self::$plugins[$name] = $attrs;

        return true;
    }

    public static function delPlugin($name)
    {
        // Remove our plugin if it was previously loaded
        $name = ucfirst($name);
        if (isset(self::$plugins[$name])) {
            unset(self::$plugins[$name]);
        }

        // make sure initPlugins will avoid this
        common_config_set('plugins', 'disable-'.$name, true);

        return true;
    }

    /**
     * Get a list of activated plugins in this process.
     * @return array of (string $name, array $args) pairs
     */
    public static function getActivePlugins()
    {
        return self::$plugins;
    }

    /**
     * Initialize, or re-initialize, StatusNet global configuration
     * and plugins.
     *
     * If switching site configurations during script execution, be
     * careful when working with leftover objects -- global settings
     * affect many things and they may not behave as you expected.
     *
     * @param $server optional web server hostname for picking config
     * @param $path optional URL path for picking config
     * @param $conffile optional configuration file path
     *
     * @throws NoConfigException if config file can't be found
     */
    public static function init($server=null, $path=null, $conffile=null)
    {
        Router::clear();

        self::initDefaults($server, $path);
        self::loadConfigFile($conffile);

        $sprofile = common_config('site', 'profile');
        if (!empty($sprofile)) {
            self::loadSiteProfile($sprofile);
        }
        // Load settings from database; note we need autoload for this
        Config::loadSettings();

        self::initPlugins();
    }

    /**
     * Get identifier of the currently active site configuration
     * @return string
     */
    public static function currentSite()
    {
        return common_config('site', 'nickname');
    }

    /**
     * Change site configuration to site specified by nickname,
     * if set up via Status_network. If not, sites other than
     * the current will fail horribly.
     *
     * May throw exception or trigger a fatal error if the given
     * site is missing or configured incorrectly.
     *
     * @param string $nickname
     */
    public static function switchSite($nickname)
    {
        if ($nickname == StatusNet::currentSite()) {
            return true;
        }

        $sn = Status_network::getKV('nickname', $nickname);
        if (empty($sn)) {
            return false;
            throw new Exception("No such site nickname '$nickname'");
        }

        $server = $sn->getServerName();
        StatusNet::init($server);
    }

    /**
     * Pull all local sites from status_network table.
     *
     * Behavior undefined if site is not configured via Status_network.
     *
     * @return array of nicknames
     */
    public static function findAllSites()
    {
        $sites = array();
        $sn = new Status_network();
        $sn->find();
        while ($sn->fetch()) {
            $sites[] = $sn->nickname;
        }
        return $sites;
    }

    /**
     * Fire initialization events for all instantiated plugins.
     */
    protected static function initPlugins()
    {
        // User config may have already added some of these plugins, with
        // maybe configured parameters. The self::addPlugin function will
        // ignore the new call if it has already been instantiated.

        // Load core plugins
        foreach (common_config('plugins', 'core') as $name => $params) {
            call_user_func('self::addPlugin', $name, $params);
        }

        // Load default plugins
        foreach (common_config('plugins', 'default') as $name => $params) {
            $key = 'disable-' . $name;
            if (common_config('plugins', $key)) {
                continue;
            }

            // TODO: We should be able to avoid this is_null and assume $params
            // is an array, since that's how it is typed in addPlugin
            if (is_null($params)) {
                self::addPlugin($name);
            } else if (is_array($params)) {
                if (count($params) == 0) {
                    self::addPlugin($name);
                } else {
                    $keys = array_keys($params);
                    if (is_string($keys[0])) {
                        self::addPlugin($name, $params);
                    } else {
                        foreach ($params as $paramset) {
                            self::addPlugin($name, $paramset);
                        }
                    }
                }
            }
        }

        // XXX: if plugins should check the schema at runtime, do that here.
        if (common_config('db', 'schemacheck') == 'runtime') {
            Event::handle('CheckSchema');
        }

        // Give plugins a chance to initialize in a fully-prepared environment
        Event::handle('InitializePlugin');
    }

    /**
     * Quick-check if configuration has been established.
     * Useful for functions which may get used partway through
     * initialization to back off from fancier things.
     *
     * @return bool
     */
    public static function haveConfig()
    {
        return self::$have_config;
    }

    public static function isApi()
    {
        return self::$is_api;
    }

    public static function setApi($mode)
    {
        self::$is_api = $mode;
    }

    public static function isAjax()
    {
        return self::$is_ajax;
    }

    public static function setAjax($mode)
    {
        self::$is_ajax = $mode;
    }

    /**
     * Build default configuration array
     * @return array
     */
    protected static function defaultConfig()
    {
        global $_server, $_path;
        require(INSTALLDIR.'/lib/default.php');
        return $default;
    }

    /**
     * Establish default configuration based on given or default server and path
     * Sets global $_server, $_path, and $config
     */
    public static function initDefaults($server, $path)
    {
        global $_server, $_path, $config, $_PEAR;

        Event::clearHandlers();
        self::$plugins = array();

        // try to figure out where we are. $server and $path
        // can be set by including module, else we guess based
        // on HTTP info.

        if (isset($server)) {
            $_server = $server;
        } else {
            $_server = array_key_exists('SERVER_NAME', $_SERVER) ?
              strtolower($_SERVER['SERVER_NAME']) :
            null;
        }

        if (isset($path)) {
            $_path = $path;
        } else {
            $_path = (array_key_exists('SERVER_NAME', $_SERVER) && array_key_exists('SCRIPT_NAME', $_SERVER)) ?
              self::_sn_to_path($_SERVER['SCRIPT_NAME']) :
            null;
        }

        // Set config values initially to default values
        $default = self::defaultConfig();
        $config = $default;

        // default configuration, overwritten in config.php
        // Keep DB_DataObject's db config synced to ours...

        $config['db'] = &$_PEAR->getStaticProperty('DB_DataObject','options');

        $config['db'] = $default['db'];

        if (function_exists('date_default_timezone_set')) {
            /* Work internally in UTC */
            date_default_timezone_set('UTC');
        }
    }

    public static function loadSiteProfile($name)
    {
        global $config;
        $settings = SiteProfile::getSettings($name);
        $config = array_replace_recursive($config, $settings);
    }

    protected static function _sn_to_path($sn)
    {
        $past_root = substr($sn, 1);
        $last_slash = strrpos($past_root, '/');
        if ($last_slash > 0) {
            $p = substr($past_root, 0, $last_slash);
        } else {
            $p = '';
        }
        return $p;
    }

    /**
     * Load the default or specified configuration file.
     * Modifies global $config and may establish plugins.
     *
     * @throws NoConfigException
     */
    protected static function loadConfigFile($conffile=null)
    {
        global $_server, $_path, $config;

        // From most general to most specific:
        // server-wide, then vhost-wide, then for a path,
        // finally for a dir (usually only need one of the last two).

        if (isset($conffile)) {
            $config_files = array($conffile);
        } else {
            $config_files = array('/etc/statusnet/statusnet.php',
                                  '/etc/statusnet/laconica.php',
                                  '/etc/laconica/laconica.php',
                                  '/etc/statusnet/'.$_server.'.php',
                                  '/etc/laconica/'.$_server.'.php');

            if (strlen($_path) > 0) {
                $config_files[] = '/etc/statusnet/'.$_server.'_'.$_path.'.php';
                $config_files[] = '/etc/laconica/'.$_server.'_'.$_path.'.php';
            }

            $config_files[] = INSTALLDIR.'/config.php';
        }

        self::$have_config = false;

        foreach ($config_files as $_config_file) {
            if (@file_exists($_config_file)) {
                // Ignore 0-byte config files
                if (filesize($_config_file) > 0) {
                    common_log(LOG_INFO, "Including config file: " . $_config_file);
                    include($_config_file);
                    self::$have_config = true;
                }
            }
        }

        if (!self::$have_config) {
            throw new NoConfigException("No configuration file found.",
                                        $config_files);
        }

        // Check for database server; must exist!

        if (empty($config['db']['database'])) {
            throw new ServerException("No database server for this site.");
        }
    }

    /**
     * Are we running from the web with HTTPS?
     *
     * @return boolean true if we're running with HTTPS; else false
     */

    static function isHTTPS()
    {
        // There are some exceptions to this; add them here!
        if (empty($_SERVER['HTTPS'])) {
            return false;
        }

        // If it is _not_ "off", it is on, so "true".
        return strtolower($_SERVER['HTTPS']) !== 'off';
    }

    /**
     * Can we use HTTPS? Then do! Only return false if it's not configured ("never").
     */
    static function useHTTPS()
    {
        return self::isHTTPS() || common_config('site', 'ssl') != 'never';
    }
}

class NoConfigException extends Exception
{
    public $configFiles;

    function __construct($msg, $configFiles) {
        parent::__construct($msg);
        $this->configFiles = $configFiles;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Abstract class for queue managers
 *
 * 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  QueueManager
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Sarven Capadisli <csarven@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/
 */

require_once 'Stomp.php';
require_once 'Stomp/Exception.php';

class StompQueueManager extends QueueManager
{
    protected $servers;
    protected $username;
    protected $password;
    protected $base;
    protected $control;

    protected $useTransactions;
    protected $useAcks;

    protected $sites = array();
    protected $subscriptions = array();

    protected $cons = array(); // all open connections
    protected $disconnect = array();
    protected $transaction = array();
    protected $transactionCount = array();
    protected $defaultIdx = 0;

    function __construct()
    {
        parent::__construct();
        $server = common_config('queue', 'stomp_server');
        if (is_array($server)) {
            $this->servers = $server;
        } else {
            $this->servers = array($server);
        }
        $this->username        = common_config('queue', 'stomp_username');
        $this->password        = common_config('queue', 'stomp_password');
        $this->base            = common_config('queue', 'queue_basename');
        $this->control         = common_config('queue', 'control_channel');
        $this->breakout        = common_config('queue', 'breakout');
        $this->useTransactions = common_config('queue', 'stomp_transactions');
        $this->useAcks         = common_config('queue', 'stomp_acks');
    }

    /**
     * Tell the i/o master we only need a single instance to cover
     * all sites running in this process.
     */
    public static function multiSite()
    {
        return IoManager::INSTANCE_PER_PROCESS;
    }

    /**
     * Optional; ping any running queue handler daemons with a notification
     * such as announcing a new site to handle or requesting clean shutdown.
     * This avoids having to restart all the daemons manually to update configs
     * and such.
     *
     * Currently only relevant for multi-site queue managers such as Stomp.
     *
     * @param string $event event key
     * @param string $param optional parameter to append to key
     * @return boolean success
     */
    public function sendControlSignal($event, $param='')
    {
        $message = $event;
        if ($param != '') {
            $message .= ':' . $param;
        }
        $this->_connect();
        $con = $this->cons[$this->defaultIdx];
        $result = $con->send($this->control,
                             $message,
                             array ('created' => common_sql_now()));
        if ($result) {
            $this->_log(LOG_INFO, "Sent control ping to queue daemons: $message");
            return true;
        } else {
            $this->_log(LOG_ERR, "Failed sending control ping to queue daemons: $message");
            return false;
        }
    }

    /**
     * Saves an object into the queue item table.
     *
     * @param mixed $object
     * @param string $queue
     * @param string $siteNickname optional override to drop into another site's queue
     *
     * @return boolean true on success
     * @throws StompException on connection or send error
     */
    public function enqueue($object, $queue, $siteNickname=null)
    {
        $this->_connect();
        if (common_config('queue', 'stomp_enqueue_on')) {
            // We're trying to force all writes to a single server.
            // WARNING: this might do odd things if that server connection dies.
            $idx = array_search(common_config('queue', 'stomp_enqueue_on'),
                                $this->servers);
            if ($idx === false) {
                common_log(LOG_ERR, 'queue stomp_enqueue_on setting does not match our server list.');
                $idx = $this->defaultIdx;
            }
        } else {
            $idx = $this->defaultIdx;
        }
        return $this->_doEnqueue($object, $queue, $idx, $siteNickname);
    }

    /**
     * Saves a notice object reference into the queue item table
     * on the given connection.
     *
     * @return boolean true on success
     * @throws StompException on connection or send error
     */
    protected function _doEnqueue($object, $queue, $idx, $siteNickname=null)
    {
        $rep = $this->logrep($object);
        $envelope = array('site' => $siteNickname ? $siteNickname : common_config('site', 'nickname'),
                          'handler' => $queue,
                          'payload' => $this->encode($object));
        $msg = serialize($envelope);

        $props = array('created' => common_sql_now());
        if ($this->isPersistent($queue)) {
            $props['persistent'] = 'true';
        }

        $con = $this->cons[$idx];
        $host = $con->getServer();
        $target = $this->queueName($queue);
        $result = $con->send($target, $msg, $props);

        if (!$result) {
            $this->_log(LOG_ERR, "Error sending $rep to $queue queue on $host $target");
            return false;
        }

        $this->_log(LOG_DEBUG, "complete remote queueing $rep for $queue on $host $target");
        $this->stats('enqueued', $queue);
        return true;
    }

    /**
     * Determine whether messages to this queue should be marked as persistent.
     * Actual persistent storage depends on the queue server's configuration.
     * @param string $queue
     * @return bool
     */
    protected function isPersistent($queue)
    {
        $mode = common_config('queue', 'stomp_persistent');
        if (is_array($mode)) {
            return in_array($queue, $mode);
        } else {
            return (bool)$mode;
        }
    }

    /**
     * Send any sockets we're listening on to the IO manager
     * to wait for input.
     *
     * @return array of resources
     */
    public function getSockets()
    {
        $sockets = array();
        foreach ($this->cons as $con) {
            if ($con) {
                $sockets[] = $con->getSocket();
            }
        }
        return $sockets;
    }

    /**
     * Get the Stomp connection object associated with the given socket.
     * @param resource $socket
     * @return int index into connections list
     * @throws Exception
     */
    protected function connectionFromSocket($socket)
    {
        foreach ($this->cons as $i => $con) {
            if ($con && $con->getSocket() === $socket) {
                return $i;
            }
        }
        throw new Exception(__CLASS__ . " asked to read from unrecognized socket");
    }

    /**
     * We've got input to handle on our socket!
     * Read any waiting Stomp frame(s) and process them.
     *
     * @param resource $socket
     * @return boolean ok on success
     */
    public function handleInput($socket)
    {
        $idx = $this->connectionFromSocket($socket);
        $con = $this->cons[$idx];
        $host = $con->getServer();
        $this->defaultIdx = $idx;

        $ok = true;
        try {
            $frames = $con->readFrames();
        } catch (StompException $e) {
            $this->_log(LOG_ERR, "Lost connection to $host: " . $e->getMessage());
            fclose($socket); // ???
            $this->cons[$idx] = null;
            $this->transaction[$idx] = null;
            $this->disconnect[$idx] = time();
            return false;
        }
        foreach ($frames as $frame) {
            $dest = $frame->headers['destination'];
            if ($dest == $this->control) {
                if (!$this->handleControlSignal($frame)) {
                    // We got a control event that requests a shutdown;
                    // close out and stop handling anything else!
                    break;
                }
            } else {
                $ok = $this->handleItem($frame) && $ok;
            }
            $this->ack($idx, $frame);
            $this->commit($idx);
            $this->begin($idx);
        }
        return $ok;
    }

    /**
     * Attempt to reconnect in background if we lost a connection.
     */
    function idle()
    {
        $now = time();
        foreach ($this->cons as $idx => $con) {
            if (empty($con)) {
                $age = $now - $this->disconnect[$idx];
                if ($age >= 60) {
                    $this->_reconnect($idx);
                }
            }
        }
        return true;
    }

    /**
     * Initialize our connection and subscribe to all the queues
     * we're going to need to handle... If multiple queue servers
     * are configured for failover, we'll listen to all of them.
     *
     * Side effects: in multi-site mode, may reset site configuration.
     *
     * @param IoMaster $master process/event controller
     * @return bool return false on failure
     */
    public function start($master)
    {
        parent::start($master);
        $this->_connectAll();

        foreach ($this->cons as $i => $con) {
            if ($con) {
                $this->doSubscribe($con);
                $this->begin($i);
            }
        }
        return true;
    }

    /**
     * Close out any active connections.
     *
     * @return bool return false on failure
     */
    public function finish()
    {
        // If there are any outstanding delivered messages we haven't processed,
        // free them for another thread to take.
        foreach ($this->cons as $i => $con) {
            if ($con) {
                $this->rollback($i);
                $con->disconnect();
                $this->cons[$i] = null;
            }
        }
        return true;
    }

    /**
     * Lazy open a single connection to Stomp queue server.
     * If multiple servers are configured, we let the Stomp client library
     * worry about finding a working connection among them.
     */
    protected function _connect()
    {
        if (empty($this->cons)) {
            $list = $this->servers;
            if (count($list) > 1) {
                shuffle($list); // Randomize to spread load
                $url = 'failover://(' . implode(',', $list) . ')';
            } else {
                $url = $list[0];
            }
            $con = $this->_doConnect($url);
            $this->cons = array($con);
            $this->transactionCount = array(0);
            $this->transaction = array(null);
            $this->disconnect = array(null);
        }
    }

    /**
     * Lazy open connections to all Stomp servers, if in manual failover
     * mode. This means the queue servers don't speak to each other, so
     * we have to listen to all of them to make sure we get all events.
     */
    protected function _connectAll()
    {
        if (!common_config('queue', 'stomp_manual_failover')) {
            return $this->_connect();
        }
        if (empty($this->cons)) {
            $this->cons = array();
            $this->transactionCount = array();
            $this->transaction = array();
            foreach ($this->servers as $idx => $server) {
                try {
                    $this->cons[] = $this->_doConnect($server);
                    $this->disconnect[] = null;
                } catch (Exception $e) {
                    // s'okay, we'll live
                    $this->cons[] = null;
                    $this->disconnect[] = time();
                }
                $this->transactionCount[] = 0;
                $this->transaction[] = null;
            }
            if (empty($this->cons)) {
                throw new ServerException("No queue servers reachable...");
                return false;
            }
        }
    }

    /**
     * Attempt to manually reconnect to the Stomp server for the given
     * slot. If successful, set up our subscriptions on it.
     */
    protected function _reconnect($idx)
    {
        try {
            $con = $this->_doConnect($this->servers[$idx]);
        } catch (Exception $e) {
            $this->_log(LOG_ERR, $e->getMessage());
            $con = null;
        }
        if ($con) {
            $this->cons[$idx] = $con;
            $this->disconnect[$idx] = null;

            $this->doSubscribe($con);
            $this->begin($idx);
        } else {
            // Try again later...
            $this->disconnect[$idx] = time();
        }
    }

    protected function _doConnect($server)
    {
        $this->_log(LOG_INFO, "Connecting to '$server' as '$this->username'...");
        $con = new LiberalStomp($server);

        if ($con->connect($this->username, $this->password)) {
            $this->_log(LOG_INFO, "Connected.");
        } else {
            $this->_log(LOG_ERR, 'Failed to connect to queue server');
            throw new ServerException('Failed to connect to queue server');
        }

        return $con;
    }

    /**
     * Set up all our raw queue subscriptions on the given connection
     * @param LiberalStomp $con
     */
    protected function doSubscribe(LiberalStomp $con)
    {
        $host = $con->getServer();
        foreach ($this->subscriptions() as $sub) {
            $this->_log(LOG_INFO, "Subscribing to $sub on $host");
            $con->subscribe($sub);
        }
    }

    /**
     * Grab a full list of stomp-side queue subscriptions.
     * Will include:
     *  - control broadcast channel
     *  - shared group queues for active groups
     *  - per-handler and per-site breakouts from $config['queue']['breakout']
     *    that are rooted in the active groups.
     *
     * @return array of strings
     */
    protected function subscriptions()
    {
        $subs = array();
        $subs[] = $this->control;

        foreach ($this->activeGroups as $group) {
            $subs[] = $this->base . $group;
        }

        foreach ($this->breakout as $spec) {
            $parts = explode('/', $spec);
            if (count($parts) < 2 || count($parts) > 3) {
                common_log(LOG_ERR, "Bad queue breakout specifier $spec");
            }
            if (in_array($parts[0], $this->activeGroups)) {
                $subs[] = $this->base . $spec;
            }
        }
        return array_unique($subs);
    }

    /**
     * Handle and acknowledge an event that's come in through a queue.
     *
     * If the queue handler reports failure, the message is requeued for later.
     * Missing notices or handler classes will drop the message.
     *
     * Side effects: in multi-site mode, may reset site configuration to
     * match the site that queued the event.
     *
     * @param StompFrame $frame
     * @return bool success
     */
    protected function handleItem($frame)
    {
        $host = $this->cons[$this->defaultIdx]->getServer();
        $message = unserialize($frame->body);

        if ($message === false) {
            $this->_log(LOG_ERR, "Can't unserialize frame: {$frame->body}");
            $this->_log(LOG_ERR, "Unserializable frame length: " . strlen($frame->body));
            return false;
        }

        $site = $message['site'];
        $queue = $message['handler'];

        if ($this->isDeadletter($frame, $message)) {
            $this->stats('deadletter', $queue);
	        return false;
        }

        // @fixme detect failing site switches
        $this->switchSite($site);

        try {
            $item = $this->decode($message['payload']);
        } catch (Exception $e) {
            $this->_log(LOG_ERR, "Skipping empty or deleted item in queue $queue from $host");
            $this->stats('baditem', $queue);
            return false;
        }
        $info = $this->logrep($item) . " posted at " .
                $frame->headers['created'] . " in queue $queue from $host";
        $this->_log(LOG_DEBUG, "Dequeued $info");

        $handler = $this->getHandler($queue);
        if (!$handler) {
            $this->_log(LOG_ERR, "Missing handler class; skipping $info");
            $this->stats('badhandler', $queue);
            return false;
        }

        try {
            $ok = $handler->handle($item);
        } catch (Exception $e) {
            $this->_log(LOG_ERR, "Exception on queue $queue: " . $e->getMessage());
            $ok = false;
        }

        if ($ok) {
            $this->_log(LOG_INFO, "Successfully handled $info");
            $this->stats('handled', $queue);
        } else {
            $this->_log(LOG_WARNING, "Failed handling $info");
            // Requeing moves the item to the end of the line for its next try.
            // @fixme add a manual retry count
            $this->enqueue($item, $queue);
            $this->stats('requeued', $queue);
        }

        return $ok;
    }

    /**
     * Check if a redelivered message has been run through enough
     * that we're going to give up on it.
     *
     * @param StompFrame $frame
     * @param array $message unserialized message body
     * @return boolean true if we should discard
     */
    protected function isDeadLetter($frame, $message)
    {
        if (isset($frame->headers['redelivered']) && $frame->headers['redelivered'] == 'true') {
	        // Message was redelivered, possibly indicating a previous failure.
            $msgId = $frame->headers['message-id'];
            $site = $message['site'];
            $queue = $message['handler'];
	        $msgInfo = "message $msgId for $site in queue $queue";

	        $deliveries = $this->incDeliveryCount($msgId);
	        if ($deliveries > common_config('queue', 'max_retries')) {
		        $info = "DEAD-LETTER FILE: Gave up after retry $deliveries on $msgInfo";

		        $outdir = common_config('queue', 'dead_letter_dir');
		        if ($outdir) {
    		        $filename = $outdir . "/$site-$queue-" . rawurlencode($msgId);
    		        $info .= ": dumping to $filename";
    		        file_put_contents($filename, $message['payload']);
		        }

		        common_log(LOG_ERR, $info);
		        return true;
	        } else {
	            common_log(LOG_INFO, "retry $deliveries on $msgInfo");
	        }
        }
        return false;
    }

    /**
     * Update count of times we've re-encountered this message recently,
     * triggered when we get a message marked as 'redelivered'.
     *
     * Requires a CLI-friendly cache configuration.
     *
     * @param string $msgId message-id header from message
     * @return int number of retries recorded
     */
    function incDeliveryCount($msgId)
    {
	    $count = 0;
	    $cache = Cache::instance();
	    if ($cache) {
		    $key = 'statusnet:stomp:message-retries:' . $msgId;
		    $count = $cache->increment($key);
		    if (!$count) {
			    $count = 1;
			    $cache->set($key, $count, null, 3600);
			    $got = $cache->get($key);
		    }
	    }
	    return $count;
    }

    /**
     * Process a control signal broadcast.
     *
     * @param int $idx connection index
     * @param array $frame Stomp frame
     * @return bool true to continue; false to stop further processing.
     */
    protected function handleControlSignal($idx, $frame)
    {
        $message = trim($frame->body);
        if (strpos($message, ':') !== false) {
            list($event, $param) = explode(':', $message, 2);
        } else {
            $event = $message;
            $param = '';
        }

        $shutdown = false;

        if ($event == 'shutdown') {
            $this->master->requestShutdown();
            $shutdown = true;
        } else if ($event == 'restart') {
            $this->master->requestRestart();
            $shutdown = true;
        } else if ($event == 'update') {
            $this->updateSiteConfig($param);
        } else {
            $this->_log(LOG_ERR, "Ignoring unrecognized control message: $message");
        }
        return $shutdown;
    }

    /**
     * Switch site, if necessary, and reset current handler assignments
     * @param string $site
     */
    function switchSite($site)
    {
        if ($site != StatusNet::currentSite()) {
            $this->stats('switch');
            StatusNet::switchSite($site);
            $this->initialize();
        }
    }

    /**
     * (Re)load runtime configuration for a given site by nickname,
     * triggered by a broadcast to the 'statusnet-control' topic.
     *
     * Configuration changes in database should update, but config
     * files might not.
     *
     * @param array $frame Stomp frame
     * @return bool true to continue; false to stop further processing.
     */
    protected function updateSiteConfig($nickname)
    {
        $sn = Status_network::getKV('nickname', $nickname);
        if ($sn) {
            $this->switchSite($nickname);
            if (!in_array($nickname, $this->sites)) {
                $this->addSite();
            }
            $this->stats('siteupdate');
        } else {
            $this->_log(LOG_ERR, "Ignoring ping for unrecognized new site $nickname");
        }
    }

    /**
     * Combines the queue_basename from configuration with the
     * group name for this queue to give eg:
     *
     * /queue/statusnet/main
     * /queue/statusnet/main/distrib
     * /queue/statusnet/xmpp/xmppout/site01
     *
     * @param string $queue
     * @return string
     */
    protected function queueName($queue)
    {
        $group = $this->queueGroup($queue);
        $site = StatusNet::currentSite();

        $specs = array("$group/$queue/$site",
                       "$group/$queue");
        foreach ($specs as $spec) {
            if (in_array($spec, $this->breakout)) {
                return $this->base . $spec;
            }
        }
        return $this->base . $group;
    }

    /**
     * Get the breakout mode for the given queue on the current site.
     *
     * @param string $queue
     * @return string one of 'shared', 'handler', 'site'
     */
    protected function breakoutMode($queue)
    {
        $breakout = common_config('queue', 'breakout');
        if (isset($breakout[$queue])) {
            return $breakout[$queue];
        } else if (isset($breakout['*'])) {
            return $breakout['*'];
        } else {
            return 'shared';
        }
    }

    protected function begin($idx)
    {
        if ($this->useTransactions) {
            if (!empty($this->transaction[$idx])) {
                throw new Exception("Tried to start transaction in the middle of a transaction");
            }
            $this->transactionCount[$idx]++;
            $this->transaction[$idx] = $this->master->id . '-' . $this->transactionCount[$idx] . '-' . time();
            $this->cons[$idx]->begin($this->transaction[$idx]);
        }
    }

    protected function ack($idx, $frame)
    {
        if ($this->useAcks) {
            if ($this->useTransactions) {
                if (empty($this->transaction[$idx])) {
                    throw new Exception("Tried to ack but not in a transaction");
                }
                $this->cons[$idx]->ack($frame, $this->transaction[$idx]);
            } else {
                $this->cons[$idx]->ack($frame);
            }
        }
    }

    protected function commit($idx)
    {
        if ($this->useTransactions) {
            if (empty($this->transaction[$idx])) {
                throw new Exception("Tried to commit but not in a transaction");
            }
            $this->cons[$idx]->commit($this->transaction[$idx]);
            $this->transaction[$idx] = null;
        }
    }

    protected function rollback($idx)
    {
        if ($this->useTransactions) {
            if (empty($this->transaction[$idx])) {
                throw new Exception("Tried to rollback but not in a transaction");
            }
            $this->cons[$idx]->commit($this->transaction[$idx]);
            $this->transaction[$idx] = null;
        }
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Local navigation for subscriptions group of 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  Subs
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2008-2011 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') && !defined('LACONICA')) {
    exit(1);
}

require_once INSTALLDIR.'/lib/widget.php';

/**
 * Local nav menu for subscriptions, subscribers
 *
 * @category Subs
 * @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/
 */
class SubGroupNav extends Menu
{
    var $user = null;

    /**
     * Construction
     *
     * @param Action $action current action, used for output
     * @param User   $user   Current user or NULL if "guest"
     */
    function __construct(Action $action=null, User $user=null)
    {
        parent::__construct($action);
        $this->user = $user;
    }

    /**
     * Show the menu
     *
     * @return void
     */
    function show()
    {
        $cur = common_current_user();
        $action = $this->action->trimmed('action');

        $this->out->elementStart('ul', array('class' => 'nav'));

        if (Event::handle('StartSubGroupNav', array($this))) {

            $this->out->menuItem(common_local_url('showstream', array('nickname' =>
                                                                      $this->user->nickname)),
                                 // TRANS: Menu item in local navigation menu.
                                 _m('MENU','Profile'),
                                 (empty($profile)) ? $this->user->nickname : $profile->getBestName(),
                                 $action == 'showstream',
                                 'nav_profile');
            $this->out->menuItem(common_local_url('subscriptions',
                                                  array('nickname' =>
                                                        $this->user->nickname)),
                                 // TRANS: Menu item in local navigation menu.
                                 _m('MENU','Subscriptions'),
                                 // TRANS: Menu item title in local navigation menu.
                                 // TRANS: %s is a user nickname.
                                 sprintf(_('People %s subscribes to.'),
                                         $this->user->nickname),
                                 $action == 'subscriptions',
                                 'nav_subscriptions');
            $this->out->menuItem(common_local_url('subscribers',
                                                  array('nickname' =>
                                                        $this->user->nickname)),
                                 // TRANS: Menu item in local navigation menu.
                                 _m('MENU','Subscribers'),
                                 // TRANS: Menu item title in local navigation menu.
                                 // TRANS: %s is a user nickname.
                                 sprintf(_('People subscribed to %s.'),
                                         $this->user->nickname),
                                 $action == 'subscribers',
                                 'nav_subscribers');
            if ($cur && $cur->id == $this->user->id) {
                // Possibly site admins should be able to get in here too
                $pending = $this->countPendingSubs();
                if ($pending || $cur->subscribe_policy == User::SUBSCRIBE_POLICY_MODERATE) {
                    $this->out->menuItem(common_local_url('subqueue',
                                                          array('nickname' =>
                                                                $this->user->nickname)),
                                         // TRANS: Menu item in local navigation menu.
                                         // TRANS: %d is the number of pending subscription requests.
                                         sprintf(_m('MENU','Pending (%d)'), $pending),
                                         // TRANS: Menu item title in local navigation menu.
                                         sprintf(_('Approve pending subscription requests.'),
                                                 $this->user->nickname),
                                         $action == 'subqueueaction',
                                         'nav_subscribers');
                }
            }
            $this->out->menuItem(common_local_url('usergroups',
                                                  array('nickname' =>
                                                        $this->user->nickname)),
                                 // TRANS: Menu item in local navigation menu.
                                 _m('MENU','Groups'),
                                 // TRANS: Menu item title in local navigation menu.
                                 // TRANS: %s is a user nickname.
                                 sprintf(_('Groups %s is a member of.'),
                                         $this->user->nickname),
                                 $action == 'usergroups',
                                 'nav_usergroups');
            $this->out->menuItem(common_local_url('peopletagsubscriptions',
                                                  array('nickname' =>
                                                        $this->user->nickname)),
                                 // TRANS: Menu item title in local navigation menu.
                                 _m('MENU','Lists'),
                                 // TRANS: Menu item title in local navigation menu.
                                 // TRANS: %s is a user nickname.
                                 sprintf(_('List subscriptions by %s.'),
                                         $this->user->nickname),
                                 in_array($action, array('peopletagsbyuser', 'peopletagsubscriptions', 'peopletagsforuser')),
                                 'nav_timeline_peopletags');

            if (common_config('invite', 'enabled') && !is_null($cur) && $this->user->id === $cur->id) {
                $this->out->menuItem(common_local_url('invite'),
                                     // TRANS: Menu item in local navigation menu.
                                     _m('MENU','Invite'),
                                     // TRANS: Menu item title in local navigation menu.
                                     // TRANS: %s is the StatusNet sitename.
                                     sprintf(_('Invite friends and colleagues to join you on %s.'),
                                             common_config('site', 'name')),
                                     $action == 'invite',
                                     'nav_invite');
            }

            Event::handle('EndSubGroupNav', array($this));
        }

        $this->out->elementEnd('ul');
    }

    function countPendingSubs()
    {
        $req = new Subscription_queue();
        $req->subscribed = $this->user->id;
        return $req->count();
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Personal tag cloud section
 *
 * 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  Widget
 * @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') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Personal tag cloud section
 *
 * @category Widget
 * @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/
 */

class SubPeopleTagCloudSection extends TagCloudSection
{
    function getTags()
    {
        $qry = $this->query();
        $limit = TAGS_PER_SECTION;
        $offset = 0;

        if (common_config('db','type') == 'pgsql') {
            $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
        } else {
            $qry .= ' LIMIT ' . $offset . ', ' . $limit;
        }

        $profile_tag = Memcached_DataObject::cachedQuery('Profile_tag',
                                                 sprintf($qry,
                                                         $this->out->user->id));
        return $profile_tag;
    }

    function tagUrl($tag) {
        return common_local_url('peopletag', array('tag' => $tag));
    }

    function showTag($tag, $weight, $relative) {
        $rel = 'tag-cloud-';
        $rel .= 1+intval(7 * $relative * $weight - 0.01);

        $this->out->elementStart('li', $rel);
        $this->out->element('a', array('href' => $this->tagUrl($tag)), $tag);
        $this->out->elementEnd('li');
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Form for subscribing to a user
 *
 * 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  Form
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Sarven Capadisli <csarven@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') && !defined('LACONICA')) {
    exit(1);
}

require_once INSTALLDIR.'/lib/form.php';

/**
 * Form for subscribing to a user
 *
 * @category Form
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @author   Sarven Capadisli <csarven@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      UnsubscribeForm
 */
class SubscribeForm extends Form
{
    /**
     * Profile of user to subscribe to
     */
    var $profile = null;

    /**
     * Constructor
     *
     * @param HTMLOutputter $out     output channel
     * @param Profile       $profile profile of user to subscribe to
     */
    function __construct($out=null, $profile=null)
    {
        parent::__construct($out);

        $this->profile = $profile;
    }

    /**
     * ID of the form
     *
     * @return int ID of the form
     */
    function id()
    {
        return 'subscribe-' . $this->profile->id;
    }

    /**
     * class of the form
     *
     * @return string of the form class
     */
    function formClass()
    {
        return 'form_user_subscribe ajax';
    }

    /**
     * Action of the form
     *
     * @return string URL of the action
     */
    function action()
    {
        return common_local_url('subscribe');
    }

    /**
     * Legend of the Form
     *
     * @return void
     */
    function formLegend()
    {
        // TRANS: Form of form to subscribe to a user.
        $this->out->element('legend', null, _('Subscribe to this user'));
    }

    /**
     * Data elements of the form
     *
     * @return void
     */
    function formData()
    {
        $this->out->hidden('subscribeto-' . $this->profile->id,
                           $this->profile->id,
                           'subscribeto');
    }

    /**
     * Action elements
     *
     * @return void
     */
    function formActions()
    {
        // TRANS: Button text to subscribe to a user.
        $this->out->submit('submit', _m('BUTTON','Subscribe'), 'submit', null,
                           // TRANS: Button title to subscribe to a user.
                           _('Subscribe to this user.'));
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Form for subscribing to a peopletag
 *
 * 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  Form
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Shashi Gowda <connect2shashi@gmail.com>
 * @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') && !defined('LACONICA')) {
    exit(1);
}

require_once INSTALLDIR.'/lib/form.php';

/**
 * Form for subscribing to a peopletag
 *
 * @category Form
 * @package  StatusNet
 * @author   Shashi Gowda <connect2shashi@gmail.com>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 *
 * @see      UnsubscribeForm
 */
class SubscribePeopletagForm extends Form
{
    /**
     * peopletag for the user to join
     */
    var $peopletag = null;

    /**
     * Constructor
     *
     * @param HTMLOutputter $out   output channel
     * @param peopletag     $peopletag peopletag to subscribe to
     */
    function __construct($out=null, $peopletag=null)
    {
        parent::__construct($out);

        $this->peopletag = $peopletag;
    }

    /**
     * ID of the form
     *
     * @return string ID of the form
     */
    function id()
    {
        return 'peopletag-subscribe-' . $this->peopletag->id;
    }

    /**
     * class of the form
     *
     * @return string of the form class
     */
    function formClass()
    {
        return 'form_peopletag_subscribe';
    }

    /**
     * Action of the form
     *
     * @return string URL of the action
     */
    function action()
    {
        return common_local_url('subscribepeopletag',
                                array('id' => $this->peopletag->id));
    }

    /**
     * Action elements
     *
     * @return void
     */
    function formActions()
    {
        // TRANS: Button text for subscribing to a list.
        $this->out->submit('submit', _m('BUTTON', 'Subscribe'));

    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Personal tag cloud section
 *
 * 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  Widget
 * @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') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Personal tag cloud section
 *
 * @category Widget
 * @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/
 */
class SubscribersPeopleSelfTagCloudSection extends SubPeopleTagCloudSection
{
    function title()
    {
        // TRANS: Title of personal tag cloud section.
        return _('People Tagcloud as self-tagged');
    }

    function query() {
//        return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscriber where subscribed=%d and subscribed != subscriber and tagger = tagged group by tag order by weight desc';

        return 'select profile_tag.tag, count(profile_tag.tag) as weight from subscription left join (profile_tag, profile_list) on  profile_list.tag =  profile_tag.tag and profile_list.tagger =  profile_tag.tagger and profile_tag.tagger = subscriber where subscribed=%d and subscribed != subscriber and profile_tag.tagger = tagged and profile_list.private = false and profile_tag.tag is not null group by profile_tag.tag order by weight desc';

//        return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscribed where subscriber=%d and subscribed != subscriber and tagger = tagged and tag is not null group by tag order by weight desc';
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Personal tag cloud section
 *
 * 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  Widget
 * @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') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Personal tag cloud section
 *
 * @category Widget
 * @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/
 */
class SubscribersPeopleTagCloudSection extends SubPeopleTagCloudSection
{
    function title()
    {
        // TRANS: Title of personal tag cloud section.
        return _('People Tagcloud as tagged');
    }

    function tagUrl($tag) {
        $nickname = $this->out->profile->nickname;
        return common_local_url('subscribers', array('nickname' => $nickname, 'tag' => $tag));
    }

    function query() {
//        return 'select tag, count(tag) as weight from subscription left join profile_tag on subscriber=tagged and subscribed=tagger where subscribed=%d and subscriber != subscribed group by tag order by weight desc';
        return 'select profile_tag.tag, count(profile_tag.tag) as weight from subscription left join (profile_tag, profile_list) on subscriber=profile_tag.tagged and subscribed=profile_tag.tagger and profile_tag.tagger = profile_list.tagger and profile_tag.tag = profile_list.tag where subscribed=%d and subscriber != subscribed and profile_list.private = false and profile_tag.tag is not null group by profile_tag.tag order by weight desc';
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Widget to show a list of profiles
 *
 * 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  Public
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2008-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') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Widget to show a list of subscriptions
 *
 * @category Public
 * @package  StatusNet
 * @author   Zach Copley <zach@status.net>
 * @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/
 */
class SubscriptionList extends ProfileList
{
    /** Owner of this list */
    var $owner = null;

    function __construct($profile, $owner=null, $action=null)
    {
        parent::__construct($profile, $action);

        $this->owner = $owner;
    }

    function newListItem($profile)
    {
        return new SubscriptionListItem($profile, $this->owner, $this->action);
    }
}

class SubscriptionListItem extends ProfileListItem
{
    /** Owner of this list */
    var $owner = null;

    function __construct($profile, $owner, $action)
    {
        parent::__construct($profile, $action);

        $this->owner = $owner;
    }

    function showProfile()
    {
        $this->startProfile();
        $this->showAvatar($this->profile);
        $this->showNickname();
        $this->showFullName();
        $this->showLocation();
        $this->showHomepage();
        $this->showBio();
        // Relevant portion!
        $this->showTags();
        if ($this->isOwn()) {
            $this->showOwnerControls();
        }
        $this->endProfile();
    }

    function showOwnerControls()
    {
        // pass
    }

    function isOwn()
    {
        $user = common_current_user();
        return (!empty($user) && ($this->owner->id == $user->id));
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Personal tag cloud section
 *
 * 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  Widget
 * @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') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Personal tag cloud section
 *
 * @category Widget
 * @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/
 */
class SubscriptionsPeopleSelfTagCloudSection extends SubPeopleTagCloudSection
{
    function title()
    {
        // TRANS: Title of personal tag cloud section.
        return _('People Tagcloud as self-tagged');
    }

    function query() {
//        return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscriber where subscribed=%d and subscriber != subscribed and tagger = tagged group by tag order by weight desc';

        return 'select profile_tag.tag, count(profile_tag.tag) as weight from subscription left join (profile_tag, profile_list) on profile_tag.tagger = subscribed and profile_tag.tag = profile_list.tag and profile_tag.tagger = profile_tag.tagger where subscriber=%d and subscribed != subscriber and profile_tag.tagger = profile_tag.tagged and profile_list.private = false and profile_tag.tag is not null group by profile_tag.tag order by weight desc';

//        return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscriber where subscribed=%d and subscribed != subscriber and tagger = tagged and tag is not null group by tag order by weight desc';
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Personal tag cloud section
 *
 * 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  Widget
 * @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') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Personal tag cloud section
 *
 * @category Widget
 * @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/
 */
class SubscriptionsPeopleTagCloudSection extends SubPeopleTagCloudSection
{
    function title()
    {
        // TRANS: Title of personal tag cloud section.
        return _('People Tagcloud as tagged');
    }

    function tagUrl($tag) {
        $nickname = $this->out->profile->nickname;
        return common_local_url('subscriptions', array('nickname' => $nickname, 'tag' => $tag));
    }

    function query() {
//        return 'select tag, count(tag) as weight from subscription left join profile_tag on subscriber=tagger and subscribed=tagged where subscriber=%d and subscriber != subscribed group by tag order by weight desc';
        return 'select profile_tag.tag, count(profile_tag.tag) as weight from subscription left join (profile_tag, profile_list) on subscriber=profile_tag.tagger and subscribed=tagged and profile_tag.tag = profile_list.tag and profile_tag.tagger = profile_list.tagger where subscriber=%d and subscriber != subscribed and profile_list.private = false and profile_tag.tag is not null group by profile_tag.tag order by weight desc';
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Database schema utilities
 *
 * 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  Database
 * @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);
}

/**
 * A class encapsulating the structure of a table.
 *
 * @category Database
 * @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/
 */

class TableDef
{
    /** name of the table */
    public $name;
    /** array of ColumnDef objects for the columns. */
    public $columns;

    /**
     * Constructor.
     *
     * @param string  $name     name of the table
     * @param array   $columns  columns in the table
     */

    function __construct($name=null,$columns=null)
    {
        $this->name = $name;
        $this->columns = $columns;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Base class for sections showing tag clouds
 *
 * 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  Widget
 * @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') && !defined('LACONICA')) {
    exit(1);
}

define('TAGS_PER_SECTION', 10);

/**
 * Base class for sections
 *
 * These are the widgets that show interesting data about a person
 * group, or site.
 *
 * @category Widget
 * @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/
 */
class TagCloudSection extends Section
{
    function showContent()
    {
        $tags = $this->getTags();

        if (!$tags) {
            // TRANS: Content displayed in a tag cloud section if there are no tags.
            $this->out->element('p', null, _m('NOTAGS','None'));
            return false;
        }

        $cnt = 0;

        $tw = array();
        $sum = 0;

        while ($tags->fetch() && ++$cnt <= TAGS_PER_SECTION) {
            $tw[$tags->tag] = $tags->weight;
            $sum += $tags->weight;
        }

        if ($cnt == 0) {
            // TRANS: Content displayed in a tag cloud section if there are no tags.
            $this->out->element('p', null, _m('NOTAGS','None'));
            return false;
        }

        ksort($tw);

        $this->out->elementStart('ul', 'tags xoxo tag-cloud');
        foreach ($tw as $tag => $weight) {
            $this->showTag($tag, $weight, ($sum == 0) ? 0 : $weight/$sum);
        }
        $this->out->elementEnd('ul');

        return ($cnt > TAGS_PER_SECTION);
    }

    function getTags()
    {
        return null;
    }

    function showTag($tag, $weight, $relative)
    {
        if ($relative > 0.1) {
            $rel =  'tag-cloud-7';
        } else if ($relative > 0.05) {
            $rel = 'tag-cloud-6';
        } else if ($relative > 0.02) {
            $rel = 'tag-cloud-5';
        } else if ($relative > 0.01) {
            $rel = 'tag-cloud-4';
        } else if ($relative > 0.005) {
            $rel = 'tag-cloud-3';
        } else if ($relative > 0.002) {
            $rel = 'tag-cloud-2';
        } else {
            $rel = 'tag-cloud-1';
        }

        $this->out->elementStart('li', $rel);
        $this->out->element('a', array('href' => $this->tagUrl($tag)),
                       $tag);
        $this->out->elementEnd('li');
    }

    function tagUrl($tag)
    {
        if ('showstream' === $this->out->trimmed('action')) {
            return common_local_url('showstream', array('nickname' => $this->out->profile->nickname, 'tag' => $tag));
        } else {
            return common_local_url('tag', array('tag' => $tag));
        }
    }

    function divId()
    {
        return 'tagcloud';
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * Stream of notices by a profile with a given tag
 *
 * 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  Stream
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 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);
}

/**
 * Stream of notices with a given profile and tag
 *
 * @category  Stream
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

class TaggedProfileNoticeStream extends ScopingNoticeStream
{
    function __construct($profile, $tag, $userProfile=-1)
    {
        if (is_int($userProfile) && $userProfile == -1) {
            $userProfile = Profile::current();
        }
        parent::__construct(new CachingNoticeStream(new RawTaggedProfileNoticeStream($profile, $tag),
                                                    'profile:notice_ids_tagged:'.$profile->id.':'.Cache::keyize($tag)),
                            $userProfile);
    }
}

/**
 * Raw stream of notices with a given profile and tag
 *
 * @category  Stream
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

class RawTaggedProfileNoticeStream extends NoticeStream
{
    protected $profile;
    protected $tag;

    function __construct($profile, $tag)
    {
        $this->profile = $profile;
        $this->tag     = $tag;
    }

    function getNoticeIds($offset, $limit, $since_id, $max_id)
    {
        // XXX It would be nice to do this without a join
        // (necessary to do it efficiently on accounts with long history)

        $notice = new Notice();

        $query =
          "select id from notice join notice_tag on id=notice_id where tag='".
          $notice->escape($this->tag) .
          "' and profile_id=" . intval($this->profile->id);

        $since = Notice::whereSinceId($since_id, 'id', 'notice.created');
        if ($since) {
            $query .= " and ($since)";
        }

        $max = Notice::whereMaxId($max_id, 'id', 'notice.created');
        if ($max) {
            $query .= " and ($max)";
        }

        $query .= ' order by notice.created DESC, id DESC';

        if (!is_null($offset)) {
            $query .= " LIMIT " . intval($limit) . " OFFSET " . intval($offset);
        }

        $notice->query($query);

        $ids = array();

        while ($notice->fetch()) {
            $ids[] = $notice->id;
        }

        return $ids;
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * Stream of notices with a given tag
 *
 * 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  Stream
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 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);
}

/**
 * Stream of notices with a given tag
 *
 * @category  Stream
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

class TagNoticeStream extends ScopingNoticeStream
{
    function __construct($tag, $profile = -1)
    {
        if (is_int($profile) && $profile == -1) {
            $profile = Profile::current();
        }
        parent::__construct(new CachingNoticeStream(new RawTagNoticeStream($tag),
                                                    'notice_tag:notice_ids:' . Cache::keyize($tag)));
    }
}

/**
 * Raw stream of notices with a given tag
 *
 * @category  Stream
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

class RawTagNoticeStream extends NoticeStream
{
    protected $tag;

    function __construct($tag)
    {
        $this->tag = $tag;
    }

    function getNoticeIds($offset, $limit, $since_id, $max_id)
    {
        $nt = new Notice_tag();

        $nt->tag = $this->tag;

        $nt->selectAdd();
        $nt->selectAdd('notice_id');

        Notice::addWhereSinceId($nt, $since_id, 'notice_id');
        Notice::addWhereMaxId($nt, $max_id, 'notice_id');

        $nt->orderBy('created DESC, notice_id DESC');

        if (!is_null($offset)) {
            $nt->limit($offset, $limit);
        }

        $ids = array();

        if ($nt->find()) {
            while ($nt->fetch()) {
                $ids[] = $nt->notice_id;
            }
        }

        return $ids;
    }
}