code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Utility class for plugins
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Plugin
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2008 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

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

/**
 * Base class for plugins
 *
 * A base class for StatusNet plugins. Mostly a light wrapper around
 * the Event framework.
 *
 * Subclasses of Plugin will automatically handle an event if they define
 * a method called "onEventName". (Well, OK -- only if they call parent::__construct()
 * in their constructors.)
 *
 * They will also automatically handle the InitializePlugin and CleanupPlugin with the
 * initialize() and cleanup() methods, respectively.
 *
 * @category Plugin
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 *
 * @see      Event
 */

class Plugin
{
    function __construct()
    {
        Event::addHandler('InitializePlugin', array($this, 'initialize'));
        Event::addHandler('CleanupPlugin', array($this, 'cleanup'));

        foreach (get_class_methods($this) as $method) {
            if (mb_substr($method, 0, 2) == 'on') {
                Event::addHandler(mb_substr($method, 2), array($this, $method));
            }
        }

        $this->setupGettext();
    }

    function initialize()
    {
        return true;
    }

    function cleanup()
    {
        return true;
    }

    /**
     * Load related modules when needed
     *
     * Most non-trivial plugins will require extra modules to do their work. Typically
     * these include data classes, action classes, widget classes, or external libraries.
     *
     * This method receives a class name and loads the PHP file related to that class. By
     * tradition, action classes typically have files named for the action, all lower-case.
     * Data classes are in files with the data class name, initial letter capitalized.
     *
     * Note that this method will be called for *all* overloaded classes, not just ones
     * in this plugin! So, make sure to return true by default to let other plugins, and
     * the core code, get a chance.
     *
     * @param string $cls Name of the class to be loaded
     *
     * @return boolean hook value; true means continue processing, false means stop.
     */
    public function onAutoload($cls) {
        $cls = basename($cls);
        $basedir = INSTALLDIR . '/local/plugins/' . mb_substr(get_called_class(), 0, -6);
        if (!file_exists($basedir)) {
            $basedir = INSTALLDIR . '/plugins/' . mb_substr(get_called_class(), 0, -6);
        }

        $file = null;

        if (preg_match('/^(\w+)(Action|Form)$/', $cls, $type)) {
            $type = array_map('strtolower', $type);
            $file = "$basedir/{$type[2]}s/{$type[1]}.php";
        }
        if (!file_exists($file)) {
            $file = "$basedir/classes/{$cls}.php";

            // library files can be put into subdirs ('_'->'/' conversion)
            // such as LRDDMethod_WebFinger -> lib/lrddmethod/webfinger.php
            if (!file_exists($file)) {
                $type = strtolower($cls);
                $type = str_replace('_', '/', $type);
                $file = "$basedir/lib/{$type}.php";
            }
        }

        if (!is_null($file) && file_exists($file)) {
            require_once($file);
            return false;
        }

        return true;
    }

    /**
     * Checks if this plugin has localization that needs to be set up.
     * Gettext localizations can be called via the _m() helper function.
     */
    protected function setupGettext()
    {
        $class = get_class($this);
        if (substr($class, -6) == 'Plugin') {
            $name = substr($class, 0, -6);
            $path = common_config('plugins', 'locale_path');
            if (!$path) {
                // @fixme this will fail for things installed in local/plugins
                // ... but then so will web links so far.
                $path = INSTALLDIR . "/plugins/$name/locale";
            }
            if (file_exists($path) && is_dir($path)) {
                bindtextdomain($name, $path);
                bind_textdomain_codeset($name, 'UTF-8');
            }
        }
    }

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

    protected function debug($msg)
    {
        $this->log(LOG_DEBUG, $msg);
    }

    public function name()
    {
        $cls = get_class($this);
        return mb_substr($cls, 0, -6);
    }

    public function version()
    {
        return GNUSOCIAL_VERSION;
    }

    protected function userAgent() {
        return HTTPClient::userAgent()
                . ' (' . get_class($this) . ' v' . $this->version() . ')';
    }

    function onPluginVersion(&$versions)
    {
        $name = $this->name();

        $versions[] = array('name' => $name,
                            // TRANS: Displayed as version information for a plugin if no version information was found.
                            'version' => _('Unknown'));

        return true;
    }

    function path($relative)
    {
        return self::staticPath($this->name(), $relative);
    }

    static function staticPath($plugin, $relative)
    {
        $isHTTPS = StatusNet::isHTTPS();

        if ($isHTTPS) {
            $server = common_config('plugins', 'sslserver');
        } else {
            $server = common_config('plugins', 'server');
        }

        if (empty($server)) {
            if ($isHTTPS) {
                $server = common_config('site', 'sslserver');
            }
            if (empty($server)) {
                $server = common_config('site', 'server');
            }
        }

        if ($isHTTPS) {
            $path = common_config('plugins', 'sslpath');
        } else {
            $path = common_config('plugins', 'path');
        }

        if (empty($path)) {
            // XXX: extra stat().
            if (@file_exists(INSTALLDIR.'/local/plugins/'.$plugin.'/'.$relative)) {
                $path = common_config('site', 'path') . '/local/plugins/';
            } else {
                $path = common_config('site', 'path') . '/plugins/';
            }
        }

        if ($path[strlen($path)-1] != '/') {
            $path .= '/';
        }

        if ($path[0] != '/') {
            $path = '/'.$path;
        }

        $protocol = ($isHTTPS) ? 'https' : 'http';

        return $protocol.'://'.$server.$path.$plugin.'/'.$relative;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Form for enabling/disabling plugins
 *
 * 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
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

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

/**
 * Form for joining a group
 *
 * @category Form
 * @package  StatusNet
 * @author   Brion Vibber <brion@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      PluginEnableForm
 */

class PluginDisableForm extends PluginEnableForm
{
    /**
     * ID of the form
     *
     * @return string ID of the form
     */

    function id()
    {
        return 'plugin-disable-' . $this->plugin;
    }

    /**
     * class of the form
     *
     * @return string of the form class
     */

    function formClass()
    {
        return 'form_plugin_disable';
    }

    /**
     * Action of the form
     *
     * @return string URL of the action
     */

    function action()
    {
        return common_local_url('plugindisable',
                                array('plugin' => $this->plugin));
    }

    /**
     * Action elements
     *
     * @return void
     */

    function formActions()
    {
        // TRANS: Plugin admin panel controls
        $this->out->submit('submit', _m('plugin', 'Disable'));
    }

}

license: mit


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Form for enabling/disabling plugins
 *
 * 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
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

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

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

/**
 * Form for joining a group
 *
 * @category Form
 * @package  StatusNet
 * @author   Brion Vibber <brion@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      PluginDisableForm
 */

class PluginEnableForm extends Form
{
    /**
     * Plugin to enable/disable
     */

    var $plugin = null;

    /**
     * Constructor
     *
     * @param HTMLOutputter $out    output channel
     * @param string        $plugin plugin to enable/disable
     */

    function __construct($out=null, $plugin=null)
    {
        parent::__construct($out);

        $this->plugin = $plugin;
    }

    /**
     * ID of the form
     *
     * @return string ID of the form
     */

    function id()
    {
        return 'plugin-enable-' . $this->plugin;
    }

    /**
     * class of the form
     *
     * @return string of the form class
     */

    function formClass()
    {
        return 'form_plugin_enable';
    }

    /**
     * Action of the form
     *
     * @return string URL of the action
     */

    function action()
    {
        return common_local_url('pluginenable',
                                array('plugin' => $this->plugin));
    }

    /**
     * Action elements
     *
     * @return void
     */

    function formActions()
    {
        // TRANS: Plugin admin panel controls
        $this->out->submit('submit', _m('plugin', 'Enable'));
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Plugins administration panel
 *
 * 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  Settings
 * @package   StatusNet
 * @author    Brion Vibber <brion@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

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

require INSTALLDIR . "/lib/pluginenableform.php";
require INSTALLDIR . "/lib/plugindisableform.php";

/**
 * Plugin list
 *
 * @category Admin
 * @package  StatusNet
 * @author   Brion Vibber <brion@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 PluginList extends Widget
{
    var $plugins = array();

    function __construct($plugins, $out)
    {
        parent::__construct($out);
        $this->plugins = $plugins;
    }

    function show()
    {
        $this->startList();
        $this->showPlugins();
        $this->endList();
    }

    function startList()
    {
        $this->out->elementStart('table', 'plugin_list');
    }

    function endList()
    {
        $this->out->elementEnd('table');
    }

    function showPlugins()
    {
        foreach ($this->plugins as $plugin) {
            $pli = $this->newListItem($plugin);
            $pli->show();
        }
    }

    function newListItem($plugin)
    {
        return new PluginListItem($plugin, $this->out);
    }
}

class PluginListItem extends Widget
{
    /** Current plugin. */
    var $plugin = null;

    /** Local cache for plugin version info */
    protected static $versions = false;

    function __construct($plugin, $out)
    {
        parent::__construct($out);
        $this->plugin = $plugin;
    }

    function show()
    {
        $meta = $this->metaInfo();

        $this->out->elementStart('tr', array('id' => 'plugin-' . $this->plugin));

        // Name and controls
        $this->out->elementStart('td');
        $this->out->elementStart('div');
        if (!empty($meta['homepage'])) {
            $this->out->elementStart('a', array('href' => $meta['homepage']));
        }
        $this->out->text($this->plugin);
        if (!empty($meta['homepage'])) {
            $this->out->elementEnd('a');
        }
        $this->out->elementEnd('div');

        $form = $this->getControlForm();
        $form->show();

        $this->out->elementEnd('td');

        // Version and authors
        $this->out->elementStart('td');
        if (!empty($meta['version'])) {
            $this->out->elementStart('div');
            $this->out->text($meta['version']);
            $this->out->elementEnd('div');
        }
        if (!empty($meta['author'])) {
            $this->out->elementStart('div');
            $this->out->text($meta['author']);
            $this->out->elementEnd('div');
        }
        $this->out->elementEnd('td');

        // Description
        $this->out->elementStart('td');
        if (!empty($meta['rawdescription'])) {
            $this->out->raw($meta['rawdescription']);
        }
        $this->out->elementEnd('td');

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

    /**
     * Pull up the appropriate control form for this plugin, depending
     * on its current state.
     *
     * @return Form
     */
    protected function getControlForm()
    {
        $key = 'disable-' . $this->plugin;
        if (common_config('plugins', $key)) {
            return new PluginEnableForm($this->out, $this->plugin);
        } else {
            return new PluginDisableForm($this->out, $this->plugin);
        }
    }

    /**
     * Grab metadata about this plugin...
     * Warning: horribly inefficient and may explode!
     * Doesn't work for disabled plugins either.
     *
     * @fixme pull structured data from plugin source
     */
    function metaInfo()
    {
        $versions = self::getPluginVersions();
        $found = false;

        foreach ($versions as $info) {
            // hack for URL shorteners... "LilUrl (ur1.ca)" etc
            list($name, ) = explode(' ', $info['name']);

            if ($name == $this->plugin) {
                if ($found) {
                    // hack for URL shorteners...
                    $found['rawdescription'] .= "<br />\n" . $info['rawdescription'];
                } else {
                    $found = $info;
                }
            }
        }

        if ($found) {
            return $found;
        } else {
            return array('name' => $this->plugin,
                         // TRANS: Plugin description for a disabled plugin.
                         'rawdescription' => _m('plugin-description','(The plugin description is unavailable when a plugin has been disabled.)'));
        }
    }

    /**
     * Lazy-load the set of active plugin version info
     * @return array
     */
    protected static function getPluginVersions()
    {
        if (!is_array(self::$versions)) {
            $versions = array();
            Event::handle('PluginVersion', array(&$versions));
            self::$versions = $versions;
        }
        return self::$versions;
    }
}


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('GNUSOCIAL')) { exit(1); }

/**
 * Queue handler for letting plugins handle stuff.
 *
 * The plugin queue handler accepts notices over the "plugin" queue
 * and simply passes them through the "HandleQueuedNotice" event.
 *
 * This gives plugins a chance to do background processing without
 * actually registering their own queue and ensuring that things
 * are queued into it.
 *
 * Fancier plugins may wish to instead hook the 'GetQueueHandlerClass'
 * event with their own class, in which case they must ensure that
 * their notices get enqueued when they need them.
 */
class PluginQueueHandler extends QueueHandler
{
    function transport()
    {
        return 'plugin';
    }

    function handle($notice)
    {
        try {
            Event::handle('HandleQueuedNotice', array(&$notice));
        } catch (NoProfileException $unp) {
            // We can't do anything about this, so just skip
            return true;
        }
        return true;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * An activity
 *
 * 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  Feed
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Zach Copley <zach@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      http://status.net/
 */

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

class PoCo
{
    const NS = 'http://portablecontacts.net/spec/1.0';

    const USERNAME     = 'preferredUsername';
    const DISPLAYNAME  = 'displayName';
    const NOTE         = 'note';

    public $preferredUsername;
    public $displayName;
    public $note;
    public $address;
    public $urls = array();

    function __construct($element = null)
    {
        if (empty($element)) {
            return;
        }

        $this->preferredUsername = ActivityUtils::childContent(
            $element,
            self::USERNAME,
            self::NS
        );

        $this->displayName = ActivityUtils::childContent(
            $element,
            self::DISPLAYNAME,
            self::NS
        );

        $this->note = ActivityUtils::childContent(
            $element,
            self::NOTE,
            self::NS
        );

        $this->address = $this->_getAddress($element);
        $this->urls = $this->_getURLs($element);
    }

    private function _getURLs($element)
    {
        $urlEls = $element->getElementsByTagnameNS(self::NS, PoCoURL::URLS);
        $urls = array();

        foreach ($urlEls as $urlEl) {

            $type = ActivityUtils::childContent(
                $urlEl,
                PoCoURL::TYPE,
                PoCo::NS
            );

            $value = ActivityUtils::childContent(
                $urlEl,
                PoCoURL::VALUE,
                PoCo::NS
            );

            $primary = ActivityUtils::childContent(
                $urlEl,
                PoCoURL::PRIMARY,
                PoCo::NS
            );

            $isPrimary = false;

            if (isset($primary) && $primary == 'true') {
                $isPrimary = true;
            }

            // @todo check to make sure a primary hasn't already been added

            array_push($urls, new PoCoURL($type, $value, $isPrimary));
        }
        return $urls;
    }

    private function _getAddress($element)
    {
        $addressEl = ActivityUtils::child(
            $element,
            PoCoAddress::ADDRESS,
            PoCo::NS
        );

        if (!empty($addressEl)) {
            $formatted = ActivityUtils::childContent(
                $addressEl,
                PoCoAddress::FORMATTED,
                self::NS
            );

            if (!empty($formatted)) {
                $address = new PoCoAddress();
                $address->formatted = $formatted;
                return $address;
            }
        }

        return null;
    }

    static function fromProfile(Profile $profile)
    {
        $poco = new PoCo();

        $poco->preferredUsername = $profile->nickname;
        $poco->displayName       = $profile->getBestName();

        $poco->note = $profile->bio;

        $paddy = new PoCoAddress();
        $paddy->formatted = $profile->location;
        $poco->address = $paddy;

        if (!empty($profile->homepage)) {
            array_push(
                $poco->urls,
                new PoCoURL(
                    'homepage',
                    $profile->homepage,
                    true
                )
            );
        }

        return $poco;
    }

    static function fromGroup(User_group $group)
    {
        $poco = new PoCo();

        $poco->preferredUsername = $group->nickname;
        $poco->displayName       = $group->getBestName();

        $poco->note = $group->description;

        $paddy = new PoCoAddress();
        $paddy->formatted = $group->location;
        $poco->address = $paddy;

        if (!empty($group->homepage)) {
            array_push(
                $poco->urls,
                new PoCoURL(
                    'homepage',
                    $group->homepage,
                    true
                )
            );
        }

        return $poco;
    }

    function getPrimaryURL()
    {
        foreach ($this->urls as $url) {
            if ($url->primary) {
                return $url;
            }
        }
    }

    function asString()
    {
        $xs = new XMLStringer(true);
        $this->outputTo($xs);
        return $xs->getString();
    }

    function outputTo($xo)
    {
        $xo->element(
            'poco:preferredUsername',
            null,
            $this->preferredUsername
        );

        $xo->element(
            'poco:displayName',
            null,
            $this->displayName
        );

        if (!empty($this->note)) {
            $xo->element('poco:note', null, common_xml_safe_str($this->note));
        }

        if (!empty($this->address)) {
            $this->address->outputTo($xo);
        }

        foreach ($this->urls as $url) {
            $url->outputTo($xo);
        }
    }

    /**
     * Output a Portable Contact as an array suitable for serializing
     * as JSON
     *
     * @return $array the PoCo array
     */

    function asArray()
    {
        $poco = array();

        $poco['preferredUsername'] = $this->preferredUsername;
        $poco['displayName']       = $this->displayName;

        if (!empty($this->note)) {
            $poco['note'] = $this->note;
        }

        if (!empty($this->address)) {
            $poco['addresses'] = $this->address->asArray();
        }

        if (!empty($this->urls)) {

            $urls = array();

            foreach ($this->urls as $url) {
                $urls[] = $url->asArray();
            }

            $poco['urls'] = $urls;
        }

        return $poco;
    }

}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * An activity
 *
 * 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  Feed
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Zach Copley <zach@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      http://status.net/
 */

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

class PoCoAddress
{
    const ADDRESS   = 'address';
    const FORMATTED = 'formatted';

    public $formatted;

    // @todo Other address fields

    function asString()
    {
        $xs = new XMLStringer(true);
        $this->outputTo($xs);
        return $xs->getString();
    }

    function outputTo($xo)
    {
        if (!empty($this->formatted)) {
            $xo->elementStart('poco:address');
            $xo->element('poco:formatted', null, common_xml_safe_str($this->formatted));
            $xo->elementEnd('poco:address');
        }
    }

    /**
     * Return this PoCo address as an array suitable for serializing in JSON
     *
     * @return array the address
     */

    function asArray()
    {
        if (!empty($this->formatted)) {
            return array('formatted' => $this->formatted);
        }
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * An activity
 *
 * 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  Feed
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Zach Copley <zach@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      http://status.net/
 */

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

class PoCoURL
{
    const URLS      = 'urls';
    const TYPE      = 'type';
    const VALUE     = 'value';
    const PRIMARY   = 'primary';

    public $type;
    public $value;
    public $primary;

    function __construct($type, $value, $primary = false)
    {
        $this->type    = $type;
        $this->value   = $value;
        $this->primary = $primary;
    }

    function asString()
    {
        $xs = new XMLStringer(true);
        $this->outputTo($xs);
        return $xs->getString();
    }

    function outputTo($xo)
    {
        $xo->elementStart('poco:urls');
        $xo->element('poco:type', null, $this->type);
        $xo->element('poco:value', null, $this->value);
        if (!empty($this->primary)) {
            $xo->element('poco:primary', null, 'true');
        }
        $xo->elementEnd('poco:urls');
    }

    /**
     * Return this PoCo URL as an array suitable for serializing in JSON
     *
     * @array $url the url
     */

    function asArray()
    {
        $url = array();

        $url['type']  = $this->type;
        $url['value'] = $this->value;

        if (!empty($this->primary)) {
            $url['primary'] = 'true';
        }

        return $url;
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * Primary nav, show on all pages
 *
 * 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  Menu
 * @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);
}

/**
 * Primary, top-level menu
 *
 * @category  General
 * @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 PrimaryNav extends Menu
{
    function show()
    {
        $user = common_current_user();
        $this->action->elementStart('ul', array('class' => 'nav'));
        if (Event::handle('StartPrimaryNav', array($this->action))) {
            if (!empty($user)) {
                $this->action->menuItem(common_local_url('profilesettings'),
                                // TRANS: Menu item in primary navigation panel.
                                _m('MENU','Settings'),
                                // TRANS: Menu item title in primary navigation panel.
                                _('Change your personal settings.'),
                                false,
                                'nav_account');
                if ($user->hasRight(Right::CONFIGURESITE)) {
                    $this->action->menuItem(common_local_url('siteadminpanel'),
                                    // TRANS: Menu item in primary navigation panel.
                                    _m('MENU','Admin'),
                                    // TRANS: Menu item title in primary navigation panel.
                                    _('Site configuration.'),
                                    false,
                                    'nav_admin');
                }
                $this->action->menuItem(common_local_url('logout'),
                                // TRANS: Menu item in primary navigation panel.
                                _m('MENU','Logout'),
                                // TRANS: Menu item title in primary navigation panel.
                                _('Logout from the site.'),
                                false,
                                'nav_logout');
            } else {
                $this->action->menuItem(common_local_url('login'),
                                // TRANS: Menu item in primary navigation panel.
                                _m('MENU','Login'),
                                // TRANS: Menu item title in primary navigation panel.
                                _('Login to the site.'),
                                false,
                                'nav_login');
            }

            Event::handle('EndPrimaryNav', array($this->action));
        }

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


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * widget for displaying a list of notices
 *
 * 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  UI
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Sarven Capadisli <csarven@status.net>
 * @copyright 2008 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

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

/**
 * widget for displaying a list of notices in the primary content area
 *
 * @category UI
 * @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      Notice
 * @see      NoticeListItem
 * @see      ProfileNoticeList
 */
class PrimaryNoticeList extends NoticeList
{
    public function show()
    {
        $this->out->elementStart('div', array('id' =>'notices_primary'));
        $total = parent::show();
        $this->out->elementEnd('div');
        return $total;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * i/o manager to watch for a dead parent process
 *
 * 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    Brion Vibber <brion@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

class ProcessManager extends IoManager
{
    protected $socket;

    public static function get()
    {
        throw new Exception("Must pass ProcessManager per-instance");
    }

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

    /**
     * Tell the i/o queue master if and how we can handle multi-site
     * processes.
     *
     * Return one of:
     *   IoManager::SINGLE_ONLY
     *   IoManager::INSTANCE_PER_SITE
     *   IoManager::INSTANCE_PER_PROCESS
     */
    public static function multiSite()
    {
        return IoManager::INSTANCE_PER_PROCESS;
    }

    /**
     * We won't get any input on it, but if it's broken we'll
     * know something's gone horribly awry.
     *
     * @return array of resources
     */
    function getSockets()
    {
        return array($this->socket);
    }

    /**
     * See if the parent died and request a shutdown...
     *
     * @param resource $socket
     * @return boolean success
     */
    function handleInput($socket)
    {
        if (feof($socket)) {
            common_log(LOG_INFO, "Parent process exited; shutting down child.");
            $this->master->requestShutdown();
        }
        return true;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Common parent of Personal and Profile actions
 *
 * 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  Personal
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Sarven Capadisli <csarven@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/profileminilist.php';
require_once INSTALLDIR.'/lib/groupminilist.php';

/**
 * Profile action common superclass
 *
 * Abstracts out common code from profile and personal tabs
 *
 * @category Personal
 * @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 ProfileAction extends ManagedAction
{
    var $page    = null;
    var $tag     = null;

    protected $target  = null;    // Profile that we're showing

    protected function prepare(array $args=array())
    {
        parent::prepare($args);

        try {
            $nickname_arg = $this->arg('nickname');
            $nickname     = common_canonical_nickname($nickname_arg);

            // Permanent redirect on non-canonical nickname

            if ($nickname_arg != $nickname) {
                $args = array('nickname' => $nickname);
                if ($this->arg('page') && $this->arg('page') != 1) {
                    $args['page'] = $this->arg['page'];
                }
                common_redirect(common_local_url($this->getActionName(), $args), 301);
            }
            $this->user = User::getKV('nickname', $nickname);

            if (!$this->user) {
                // TRANS: Client error displayed when calling a profile action without specifying a user.
                $this->clientError(_('No such user.'), 404);
            }

            $this->target = $this->user->getProfile();
        } catch (NicknameException $e) {
            $id = (int)$this->arg('id');
            $this->target = Profile::getKV('id', $id);

            if (!$this->target instanceof Profile) {
                // TRANS: Error message displayed when referring to a user without a profile.
                $this->serverError(_m('Profile ID does not exist.'));
            }

            if ($this->target->isLocal()) {
                // For local users when accessed by id number, redirect to
                // the same action but using the nickname as argument.
                common_redirect(common_local_url($this->getActionName(),
                                                array('nickname'=>$user->getNickname())));
            }
        }

        if ($this->target->hasRole(Profile_role::SILENCED) &&
            (empty($this->scoped) || !$this->scoped->hasRight(Right::SILENCEUSER))) {
            throw new ClientException(_('This profile has been silenced by site moderators'), 403);
        }

        // backwards compatibility until all actions are fixed to use $this->target
        $this->profile = $this->target;

        $this->tag = $this->trimmed('tag');
        $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
        common_set_returnto($this->selfUrl());
        return true;
    }

    function isReadOnly($args)
    {
        return true;
    }

    function showSections()
    {
        $this->showSubscriptions();
        $this->showSubscribers();
        $this->showGroups();
        $this->showLists();
        $this->showStatistics();
    }

    /**
     * Convenience function for common pattern of links to subscription/groups sections.
     *
     * @param string $actionClass
     * @param string $title
     * @param string $cssClass
     */
    private function statsSectionLink($actionClass, $title, $cssClass='')
    {
        $this->element('a', array('href' => common_local_url($actionClass,
                                                             array('nickname' => $this->target->getNickname())),
                                  'class' => $cssClass),
                       $title);
    }

    function showSubscriptions()
    {
        $this->elementStart('div', array('id' => 'entity_subscriptions',
                                         'class' => 'section'));
        if (Event::handle('StartShowSubscriptionsMiniList', array($this))) {
            $this->elementStart('h2');
            // TRANS: H2 text for user subscription statistics.
            $this->statsSectionLink('subscriptions', _('Following'));
            $this->text(' ');
            $this->text($this->target->subscriptionCount());
            $this->elementEnd('h2');

            try {
                $profile = $this->target->getSubscribed(0, PROFILES_PER_MINILIST + 1);
                $pml = new ProfileMiniList($profile, $this);
                $pml->show();
            } catch (NoResultException $e) {
                // TRANS: Text for user subscription statistics if the user has no subscription
                $this->element('p', null, _('(None)'));
            }

            Event::handle('EndShowSubscriptionsMiniList', array($this));
        }
        $this->elementEnd('div');
    }

    function showSubscribers()
    {
        $this->elementStart('div', array('id' => 'entity_subscribers',
                                         'class' => 'section'));

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

            $this->elementStart('h2');
            // TRANS: H2 text for user subscriber statistics.
            $this->statsSectionLink('subscribers', _('Followers'));
            $this->text(' ');
            $this->text($this->target->subscriberCount());
            $this->elementEnd('h2');

            try {
                $profile = $this->target->getSubscribers(0, PROFILES_PER_MINILIST + 1);
                $sml = new SubscribersMiniList($profile, $this);
                $sml->show();
            } catch (NoResultException $e) {
                // TRANS: Text for user subscriber statistics if user has no subscribers.
                $this->element('p', null, _('(None)'));
            }

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

        $this->elementEnd('div');
    }

    function showStatistics()
    {
        $notice_count = $this->target->noticeCount();
        $age_days     = (time() - strtotime($this->target->created)) / 86400;
        if ($age_days < 1) {
            // Rather than extrapolating out to a bajillion...
            $age_days = 1;
        }
        $daily_count = round($notice_count / $age_days);

        $this->elementStart('div', array('id' => 'entity_statistics',
                                         'class' => 'section'));

        // TRANS: H2 text for user statistics.
        $this->element('h2', null, _('Statistics'));

        $profile = $this->target;
        $actionParams = array('nickname' => $profile->nickname);
        $stats = array(
            array(
                'id' => 'user-id',
                // TRANS: Label for user statistics.
                'label' => _('User ID'),
                'value' => $profile->id,
            ),
            array(
                'id' => 'member-since',
                // TRANS: Label for user statistics.
                'label' => _('Member since'),
                'value' => date('j M Y', strtotime($profile->created))
            ),
            array(
                'id' => 'notices',
                // TRANS: Label for user statistics.
                'label' => _('Notices'),
                'value' => $notice_count,
            ),
            array(
                'id' => 'daily_notices',
                // TRANS: Label for user statistics.
                // TRANS: Average count of posts made per day since account registration.
                'label' => _('Daily average'),
                'value' => $daily_count
            )
        );

        // Give plugins a chance to add stats entries
        Event::handle('ProfileStats', array($profile, &$stats));

        foreach ($stats as $row) {
            $this->showStatsRow($row);
        }
        $this->elementEnd('div');
    }

    private function showStatsRow($row)
    {
        $this->elementStart('dl', 'entity_' . $row['id']);
        $this->elementStart('dt');
        if (!empty($row['link'])) {
            $this->element('a', array('href' => $row['link']), $row['label']);
        } else {
            $this->text($row['label']);
        }
        $this->elementEnd('dt');
        $this->element('dd', null, $row['value']);
        $this->elementEnd('dl');
    }

    function showGroups()
    {
        $groups = $this->target->getGroups(0, GROUPS_PER_MINILIST + 1);

        $this->elementStart('div', array('id' => 'entity_groups',
                                         'class' => 'section'));
        if (Event::handle('StartShowGroupsMiniList', array($this))) {
            $this->elementStart('h2');
            // TRANS: H2 text for user group membership statistics.
            $this->statsSectionLink('usergroups', _('Groups'));
            $this->text(' ');
            $this->text($this->target->getGroupCount());
            $this->elementEnd('h2');

            if ($groups instanceof User_group) {
                $gml = new GroupMiniList($groups, $this->target, $this);
                $cnt = $gml->show();
            } else {
                // TRANS: Text for user user group membership statistics if user is not a member of any group.
                $this->element('p', null, _('(None)'));
            }

            Event::handle('EndShowGroupsMiniList', array($this));
        }
            $this->elementEnd('div');
    }

    function showLists()
    {
        $lists = $this->target->getLists($this->scoped);

        if ($lists->N > 0) {
            $this->elementStart('div', array('id' => 'entity_lists',
                                             'class' => 'section'));

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

                $url = common_local_url('peopletagsbyuser',
                                        array('nickname' => $this->target->getNickname()));

                $this->elementStart('h2');
                $this->element('a',
                               array('href' => $url),
                               // TRANS: H2 text for user list membership statistics.
                               _('Lists'));
                $this->text(' ');
                $this->text($lists->N);
                $this->elementEnd('h2');

                $this->elementStart('ul');

                $first = true;

                while ($lists->fetch()) {
                    if (!empty($lists->mainpage)) {
                        $url = $lists->mainpage;
                    } else {
                        $url = common_local_url('showprofiletag',
                                                array('tagger' => $this->target->getNickname(),
                                                      'tag'    => $lists->tag));
                    }
                    if (!$first) {
                        $this->text(', ');
                    } else {
                        $first = false;
                    }

                    $this->element('a', array('href' => $url),
                                   $lists->tag);
                }

                $this->elementEnd('ul');

                Event::handle('EndShowListsMiniList', array($this));
            }
            $this->elementEnd('div');
        }
    }
}

class SubscribersMiniList extends ProfileMiniList
{
    function newListItem($profile)
    {
        return new SubscribersMiniListItem($profile, $this->action);
    }
}

class SubscribersMiniListItem extends ProfileMiniListItem
{
    function linkAttributes()
    {
        $aAttrs = parent::linkAttributes();
        if (common_config('nofollow', 'subscribers')) {
            $aAttrs['rel'] .= ' nofollow';
        }
        return $aAttrs;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Superclass for forms that operate on a profile
 *
 * 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);
}

/**
 * Superclass for forms that operate on a profile
 *
 * Certain forms (block, silence, userflag, sandbox, delete) work on
 * a single profile and work almost the same. So, this form extracts
 * a lot of the common code to simplify those forms.
 *
 * @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/
 */

class ProfileActionForm extends Form
{
    /**
     * Profile of user to act on
     */

    var $profile = null;

    /**
     * Return-to args
     */

    var $args = null;

    /**
     * Constructor
     *
     * @param HTMLOutputter $out     output channel
     * @param Profile       $profile profile of user to act on
     * @param array         $args    return-to args
     */

    function __construct($out=null, $profile=null, $args=null)
    {
        parent::__construct($out);

        $this->profile = $profile;
        $this->args    = $args;
    }

    /**
     * ID of the form
     *
     * @return int ID of the form
     */

    function id()
    {
        return $this->target() . '-' . $this->profile->id;
    }

    /**
     * class of the form
     *
     * @return string class of the form
     */

    function formClass()
    {
        return 'form_user_'.$this->target();
    }

    /**
     * Action of the form
     *
     * @return string URL of the action
     */

    function action()
    {
        return common_local_url($this->target());
    }

    /**
     * Legend of the Form
     *
     * @return void
     */

    function formLegend()
    {
        $this->out->element('legend', null, $this->description());
    }

    /**
     * Data elements of the form
     *
     * @return void
     */

    function formData()
    {
        $action = $this->target();

        $this->out->hidden($action.'to-' . $this->profile->id,
                           $this->profile->id,
                           'profileid');

        if ($this->args) {
            foreach ($this->args as $k => $v) {
                $this->out->hidden('returnto-' . $k, $v);
            }
        }
    }

    /**
     * Action elements
     *
     * @return void
     */

    function formActions()
    {
        $this->out->submit('submit', $this->title(), 'submit',
                           null, $this->description());
    }

    /**
     * Action this form targets
     *
     * @return string Name of the action, lowercased.
     */

    function target()
    {
        return null;
    }

    /**
     * Title of the form
     *
     * @return string Title of the form, internationalized
     */

    function title()
    {
        return null;
    }

    /**
     * Description of the form
     *
     * @return string description of the form, internationalized
     */

    function description()
    {
        return null;
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * Superclass for profile blocks
 *
 * 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  Widget
 * @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);
}

/**
 * Class comment
 *
 * @category  General
 * @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/
 */

abstract class ProfileBlock extends Widget
{
    protected $avatarSize = AVATAR_PROFILE_SIZE;

    abstract function name();
    abstract function url();
    abstract function location();
    abstract function homepage();
    abstract function description();

    function show()
    {
        $this->showActions();
        $this->showAvatar($this->profile);
        $this->showName();
        $this->showLocation();
        $this->showHomepage();
        $this->showOtherProfiles();
        $this->showDescription();
        $this->showTags();
    }

    function showName()
    {
        $name = $this->name();

        if (!empty($name)) {
            $this->out->elementStart('p', 'profile_block_name');
            $url = $this->url();
            if (!empty($url)) {
                $this->out->element('a', array('href' => $url),
                                    $name);
            } else {
                $this->out->text($name);
            }
            $this->out->elementEnd('p');
        }
    }

    function showDescription()
    {
        $description = $this->description();

        if (!empty($description)) {
            $this->out->element(
                'p',
                'profile_block_description',
                $description
            );
        }
    }

    function showLocation()
    {
        $location = $this->location();

        if (!empty($location)) {
            $this->out->element('p', 'profile_block_location', $location);
        }
    }

    function showHomepage()
    {
        $homepage = $this->homepage();

        if (!empty($homepage)) {
            $this->out->element('a',
                                array('href' => $homepage,
                                      'rel' => 'me',
                                      'class' => 'profile_block_homepage'),
                                $homepage);
        }
    }

    function showOtherProfiles()
    {
        $otherProfiles = $this->otherProfiles();

        if (!empty($otherProfiles)) {

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

            foreach ($otherProfiles as $otherProfile) {
                $this->out->elementStart('li');
                $this->out->elementStart('a',
                                         array('href' => $otherProfile['href'],
                                               'rel' => 'me',
                                               'class' => 'profile_block_otherprofile',
                                               'title' => $otherProfile['text']));
                $this->out->element('img',
                                    array('src' => $otherProfile['image'],
                                          'class' => 'profile_block_otherprofile_icon'));
                $this->out->elementEnd('a');
                $this->out->elementEnd('li');
            }

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

    function showTags()
    {
    }

    function showActions()
    {
    }
}


code:
<?php
/**
 * Superclass for actions that operate on a user
 *
 * PHP version 5
 *
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 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/>.
 *
 * @category Action
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 * @link     http://status.net/
 */

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

/**
 * Superclass for actions that operate on a user
 *
 * @category Action
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 * @link     http://status.net/
 */
class ProfileFormAction extends RedirectingAction
{
    var $profile = null;

    /**
     * Take arguments for running
     *
     * @param array $args $_REQUEST args
     *
     * @return boolean success flag
     */
    function prepare($args)
    {
        parent::prepare($args);

        $this->checkSessionToken();

        if (!common_logged_in()) {
            if ($_SERVER['REQUEST_METHOD'] == 'POST') {
            // TRANS: Error message displayed when trying to perform an action that requires a logged in user.
                $this->clientError(_('Not logged in.'));
            } else {
                // Redirect to login.
                common_set_returnto($this->selfUrl());
                $user = common_current_user();
                if (Event::handle('RedirectToLogin', array($this, $user))) {
                    common_redirect(common_local_url('login'), 303);
                }
            }
            return false;
        }

        $id = $this->trimmed('profileid');

        if (!$id) {
            // TRANS: Client error displayed when trying to change user options without specifying a user to work on.
            $this->clientError(_('No profile specified.'));
        }

        $this->profile = Profile::getKV('id', $id);

        if (!$this->profile) {
            // TRANS: Client error displayed when trying to change user options without specifying an existing user to work on.
            $this->clientError(_('No profile with that ID.'));
        }

        return true;
    }

    /**
     * Handle request
     *
     * @param array $args $_REQUEST args; handled in prepare()
     *
     * @return void
     */
    function handle($args)
    {
        parent::handle($args);

        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
            $this->handlePost();
            $this->returnToPrevious();
        }
    }

    /**
     * handle a POST request
     *
     * sub-classes should overload this request
     *
     * @return void
     */
    function handlePost()
    {
        // TRANS: Server error displayed when using an unimplemented method.
        $this->serverError(_("Unimplemented method."));
    }
}


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);
}

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

/**
 * Widget to show a list of profiles
 *
 * @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 ProfileList extends Widget
{
    /** Current profile, profile query. */
    var $profile = null;
    /** Action object using us. */
    var $action = null;

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

        $this->profile = $profile;
        $this->action = $action;
    }

    function show()
    {
        $cnt = 0;

        if (Event::handle('StartProfileList', array($this))) {
            $this->startList();
            $cnt = $this->showProfiles();
            $this->endList();
            Event::handle('EndProfileList', array($this));
        }

        return $cnt;
    }

    function startList()
    {
        $this->out->elementStart('ul', 'profile_list xoxo');
    }

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

    function showProfiles()
    {
        $cnt = $this->profile->N;
        $profiles = $this->profile->fetchAll();

        $max = min($cnt, $this->maxProfiles());

        for ($i = 0; $i < $max; $i++) {
            $pli = $this->newListItem($profiles[$i]);
            $pli->show();
        }

        return $cnt;
    }

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

    function maxProfiles()
    {
        return PROFILES_PER_PAGE;
    }
}

class ProfileListItem extends Widget
{
    /** Current profile. */
    var $profile = null;
    /** Action object using us. */
    var $action = null;

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

        $this->profile = $profile;
        $this->action  = $action;
    }

    function show()
    {
        if (Event::handle('StartProfileListItem', array($this))) {
            $this->startItem();
            if (Event::handle('StartProfileListItemProfile', array($this))) {
                $this->showProfile();
                Event::handle('EndProfileListItemProfile', array($this));
            }
            if (Event::handle('StartProfileListItemActions', array($this))) {
                $this->showActions();
                Event::handle('EndProfileListItemActions', array($this));
            }
            $this->endItem();
            Event::handle('EndProfileListItem', array($this));
        }
    }

    function startItem()
    {
        $this->out->elementStart('li', array('class' => 'profile',
                                             'id' => 'profile-' . $this->profile->id));
    }

    function showProfile()
    {
        $this->startProfile();
        if (Event::handle('StartProfileListItemProfileElements', array($this))) {
            if (Event::handle('StartProfileListItemAvatar', array($this))) {
                $aAttrs = $this->linkAttributes();
                $this->out->elementStart('a', $aAttrs);
                $this->showAvatar($this->profile);
                $this->out->elementEnd('a');
                Event::handle('EndProfileListItemAvatar', array($this));
            }
            if (Event::handle('StartProfileListItemNickname', array($this))) {
                $this->showNickname();
                Event::handle('EndProfileListItemNickname', array($this));
            }
            if (Event::handle('StartProfileListItemFullName', array($this))) {
                $this->showFullName();
                Event::handle('EndProfileListItemFullName', array($this));
            }
            if (Event::handle('StartProfileListItemLocation', array($this))) {
                $this->showLocation();
                Event::handle('EndProfileListItemLocation', array($this));
            }
            if (Event::handle('StartProfileListItemHomepage', array($this))) {
                $this->showHomepage();
                Event::handle('EndProfileListItemHomepage', array($this));
            }
            if (Event::handle('StartProfileListItemBio', array($this))) {
                $this->showBio();
                Event::handle('EndProfileListItemBio', array($this));
            }
            if (Event::handle('StartProfileListItemTags', array($this))) {
                $this->showTags();
                Event::handle('EndProfileListItemTags', array($this));
            }
            Event::handle('EndProfileListItemProfileElements', array($this));
        }
        $this->endProfile();
    }

    function startProfile()
    {
        $this->out->elementStart('div', 'entity_profile h-card');
    }

    function showNickname()
    {
        $this->out->element('a', array('href'=>$this->profile->getUrl(),
                                       'class'=>'p-nickname'),
                            $this->profile->getNickname());
    }

    function showFullName()
    {
        if (!empty($this->profile->fullname)) {
            $this->out->element('span', 'p-name', $this->profile->fullname);
        }
    }

    function showLocation()
    {
        if (!empty($this->profile->location)) {
            $this->out->element('span', 'label p-locality', $this->profile->location);
        }
    }

    function showHomepage()
    {
        if (!empty($this->profile->homepage)) {
            $this->out->text(' ');
            $aAttrs = $this->homepageAttributes();
            $this->out->elementStart('a', $aAttrs);
            $this->out->raw($this->highlight($this->profile->homepage));
            $this->out->elementEnd('a');
        }
    }

    function showBio()
    {
        if (!empty($this->profile->bio)) {
            $this->out->elementStart('p', 'note');
            $this->out->raw($this->highlight($this->profile->bio));
            $this->out->elementEnd('p');
        }
    }

    function showTags()
    {
        $user = common_current_user();
        if (!empty($user)) {
            if ($user->id == $this->profile->id) {
                $tags = new SelftagsWidget($this->out, $user, $this->profile);
                $tags->show();
            } else if ($user->getProfile()->canTag($this->profile)) {
                $tags = new PeopletagsWidget($this->out, $user, $this->profile);
                $tags->show();
            }
        }
    }

    function endProfile()
    {
        $this->out->elementEnd('div');
    }

    function showActions()
    {
        $this->startActions();
        if (Event::handle('StartProfileListItemActionElements', array($this))) {
            $this->showSubscribeButton();
            Event::handle('EndProfileListItemActionElements', array($this));
        }
        $this->endActions();
    }

    function startActions()
    {
        $this->out->elementStart('div', 'entity_actions');
        $this->out->elementStart('ul');
    }

    function showSubscribeButton()
    {
        // Is this a logged-in user, looking at someone else's
        // profile?

        $user = common_current_user();

        if (!empty($user) && $this->profile->id != $user->id) {
            $this->out->elementStart('li', 'entity_subscribe');
            if ($user->isSubscribed($this->profile)) {
                $usf = new UnsubscribeForm($this->out, $this->profile);
                $usf->show();
            } else {
                if (Event::handle('StartShowProfileListSubscribeButton', array($this))) {
                    $sf = new SubscribeForm($this->out, $this->profile);
                    $sf->show();
                    Event::handle('EndShowProfileListSubscribeButton', array($this));
                }
            }
            $this->out->elementEnd('li');
        }
    }

    function endActions()
    {
        $this->out->elementEnd('ul');
        $this->out->elementEnd('div');
    }

    function endItem()
    {
        $this->out->elementEnd('li');
    }

    function highlight($text)
    {
        return htmlspecialchars($text);
    }

    function linkAttributes()
    {
        return array('href' => $this->profile->profileurl,
                     'class' => 'u-url',
                     'rel' => 'contact');
    }

    function homepageAttributes()
    {
        return array('href' => $this->profile->homepage,
                     'class' => 'u-url');
    }
}


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);
}

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

define('PROFILES_PER_MINILIST', 8);

/**
 * Widget to show a list of profiles, good for sidebar
 *
 * @category Public
 * @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 ProfileMiniList extends ProfileList
{
    const MAX_PROFILES = PROFILES_PER_MINILIST; // put it in the class

    function startList()
    {
        $this->out->elementStart('ul', 'entities users xoxo');
    }

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

    function maxProfiles()
    {
        return PROFILES_PER_MINILIST;
    }

    function avatarSize()
    {
        return AVATAR_MINI_SIZE;
    }
}

class ProfileMiniListItem extends ProfileListItem
{
    function show()
    {
        $this->out->elementStart('li', 'h-card');
        if (Event::handle('StartProfileListItemProfileElements', array($this))) {
            if (Event::handle('StartProfileListItemAvatar', array($this))) {
                $aAttrs = $this->linkAttributes();
                $this->out->elementStart('a', $aAttrs);
                $avatarUrl = $this->profile->avatarUrl(AVATAR_MINI_SIZE);
                $this->out->element('img', array('src' => $avatarUrl,
                                                 'width' => AVATAR_MINI_SIZE,
                                                 'height' => AVATAR_MINI_SIZE,
                                                 'class' => 'avatar u-photo',
                                                 'alt' =>  $this->profile->getBestName()));
                $this->out->elementEnd('a');
                Event::handle('EndProfileListItemAvatar', array($this));
            }
            $this->out->elementEnd('li');
        }
    }

    // default; overridden for nofollow lists

    function linkAttributes()
    {
        $aAttrs = parent::linkAttributes();

        $aAttrs['title'] = $this->profile->getBestName();
        $aAttrs['rel']   = 'contact member'; // @todo: member? always?
        $aAttrs['class'] = 'u-url p-name';

        return $aAttrs;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Class for an exception when a Profile has no discernable acct: URI
 *
 * 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  Exception
 * @package   StatusNet
 * @author    Mikael Nordfeldth <mmn@hethane.se>
 * @copyright 2013 Free Software Foundation, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      http://www.gnu.org/software/social/
 */

if (!defined('GNUSOCIAL')) { exit(1); }

/**
 * Parent class for an exception when a profile is missing
 *
 * @category Exception
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link     http://status.net/
 */

class ProfileNoAcctUriException extends ServerException
{
    public $profile = null;

    public function __construct(Profile $profile, $msg=null)
    {
        $this->profile = $profile;

        if ($msg === null) {
            // TRANS: Exception text shown when no profile can be found for a user.
            // TRANS: %1$s is a user nickname, $2$d is a user ID (number).
            $msg = sprintf(_('Could not get an acct: URI for profile with id==%u'), $this->profile->id);
        }

        parent::__construct($msg);
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * Stream of notices by a profile
 *
 * 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 by a profile
 *
 * @category  General
 * @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 ProfileNoticeStream extends ScopingNoticeStream
{
    var $streamProfile;
    var $userProfile;

    function __construct($profile, $userProfile = -1)
    {
        if (is_int($userProfile) && $userProfile == -1) {
            $userProfile = Profile::current();
        }
        $this->streamProfile = $profile;
        $this->userProfile   = $userProfile;
        parent::__construct(new CachingNoticeStream(new RawProfileNoticeStream($profile),
                                                    'profile:notice_ids:' . $profile->id),
                            $userProfile);
    }

    function getNoticeIds($offset, $limit, $since_id=null, $max_id=null)
    {
        if ($this->impossibleStream()) {
            return array();
        } else {
            return parent::getNoticeIds($offset, $limit, $since_id, $max_id);
        }
    }

    function getNotices($offset, $limit, $since_id=null, $max_id=null)
    {
        if ($this->impossibleStream()) {
            return new ArrayWrapper(array());
        } else {
            return parent::getNotices($offset, $limit, $since_id, $max_id);
        }
    }

    function impossibleStream()
    {
        $user = User::getKV('id', $this->streamProfile->id);

        // If it's a private stream, and no user or not a subscriber

        if (!empty($user) && $user->private_stream &&
            (empty($this->userProfile) || !$this->userProfile->isSubscribed($this->streamProfile))) {
            return true;
        }

        // If it's a spammy stream, and no user or not a moderator

        if (common_config('notice', 'hidespam')) {
            if ($this->streamProfile->hasRole(Profile_role::SILENCED) &&
                (empty($this->userProfile) || (($this->userProfile->id !== $this->streamProfile->id) && !$this->userProfile->hasRight(Right::REVIEWSPAM)))) {
                return true;
            }
        }

        return false;
    }
}

/**
 * Raw stream of notices by a profile
 *
 * @category  General
 * @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 RawProfileNoticeStream extends NoticeStream
{
    protected $profile;

    function __construct($profile)
    {
        parent::__construct();
        $this->profile = $profile;
    }

    function getNoticeIds($offset, $limit, $since_id, $max_id)
    {
        $notice = new Notice();

        $notice->profile_id = $this->profile->id;

        $notice->selectAdd();
        $notice->selectAdd('id');

        Notice::addWhereSinceId($notice, $since_id);
        Notice::addWhereMaxId($notice, $max_id);

        $notice->orderBy('created DESC, id DESC');

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

        $notice->find();

        $ids = array();

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

        return $ids;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Base class for sections showing lists of people
 *
 * 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('PROFILES_PER_SECTION', 6);

/**
 * 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/
 */

abstract class ProfileSection extends Section
{
    function showContent()
    {
        $profiles = $this->getProfiles();

        if (!$profiles->N) {
            return false;
        }

        $cnt = 0;

        $this->out->elementStart('table');
        $this->out->elementStart('tbody');
        while ($profiles->fetch() && ++$cnt <= PROFILES_PER_SECTION) {
            $this->showProfile($profiles);
        }
        $this->out->elementEnd('tbody');
        $this->out->elementEnd('table');

        return ($cnt > PROFILES_PER_SECTION);
    }

    function getProfiles()
    {
        return null;
    }

    function showProfile($profile)
    {
        $this->out->elementStart('tr');
        $this->out->elementStart('td');
        $this->out->elementStart('a', array('title' => $profile->getBestName(),
                                       'href' => $profile->profileurl,
                                       'rel' => 'contact member',
                                       'class' => 'h-card u-url'));
        $avatarUrl = $profile->avatarUrl(AVATAR_MINI_SIZE);
        $this->out->element('img', array('src' => $avatarUrl,
                                    'width' => AVATAR_MINI_SIZE,
                                    'height' => AVATAR_MINI_SIZE,
                                    'class' => 'avatar u-photo',
                                    'alt' => $profile->getBestName()));
        $this->out->elementEnd('a');
        $this->out->elementEnd('td');
        if (isset($profile->value)) {
            $this->out->element('td', 'value', $profile->value);
        }

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


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Menu for public group of actions
 *
 * 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  Menu
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2008 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('GNUSOCIAL')) { exit(1); }

/**
 * Menu for public group of actions
 *
 * @category Output
 * @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      Widget
 */
class PublicGroupNav extends Menu
{

    var $actionName = null;

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

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

        if (Event::handle('StartPublicGroupNav', array($this))) {
            if (!common_config('singleuser', 'enabled')) {
                // TRANS: Menu item in search group navigation panel.
                $this->out->menuItem(common_local_url('public'), _m('MENU','Public'),
                                     // TRANS: Menu item title in search group navigation panel.
                                     _('Public timeline'), $this->actionName == 'public', 'nav_timeline_public');
            }

            // TRANS: Menu item in search group navigation panel.
            $this->out->menuItem(common_local_url('groups'), _m('MENU','Groups'),
                // TRANS: Menu item title in search group navigation panel.
                _('User groups'), $this->actionName == 'groups', 'nav_groups');

            if (!common_config('performance', 'high')) {
                // TRANS: Menu item in search group navigation panel.
                $this->out->menuItem(common_local_url('publictagcloud'), _m('MENU','Recent tags'),
                                     // TRANS: Menu item title in search group navigation panel.
                                     _('Recent tags'), $this->actionName == 'publictagcloud', 'nav_recent-tags');
            }

            if (count(common_config('nickname', 'featured')) > 0) {
                // TRANS: Menu item in search group navigation panel.
                $this->out->menuItem(common_local_url('featured'), _m('MENU','Featured'),
                    // TRANS: Menu item title in search group navigation panel.
                    _('Featured users'), $this->actionName == 'featured', 'nav_featured');
            }

            Event::handle('EndPublicGroupNav', array($this));
        }
        $this->action->elementEnd('ul');
    }
}


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

/**
 * Public stream
 *
 * @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 PublicNoticeStream extends ScopingNoticeStream
{
    function __construct($profile=null)
    {
        parent::__construct(new CachingNoticeStream(new RawPublicNoticeStream(),
                                                    'public'),
                            $profile);
    }
}

/**
 * Raw public stream
 *
 * @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 RawPublicNoticeStream extends NoticeStream
{
    function getNoticeIds($offset, $limit, $since_id, $max_id)
    {
        $notice = new Notice();

        $notice->selectAdd(); // clears it
        $notice->selectAdd('id');

        $notice->orderBy('created DESC, id DESC');

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

        // This feed always gives only local activities.
        $notice->whereAdd('is_local = ' . Notice::LOCAL_PUBLIC);

        Notice::addWhereSinceId($notice, $since_id);
        Notice::addWhereMaxId($notice, $max_id);

        if (!empty($this->selectVerbs)) {
            $notice->whereAddIn('verb', $this->selectVerbs, $notice->columnType('verb'));
        }

        $ids = array();

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

        $notice->free();
        $notice = NULL;

        return $ids;
    }
}


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

/**
 * Public 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 PublicTagCloudSection extends TagCloudSection
{
    function __construct($out=null)
    {
        parent::__construct($out);
    }

    function title()
    {
        // TRANS: Title for inbox tag cloud section.
        return _m('TITLE', 'Trending topics');
    }

    function getTags()
    {
        $profile = Profile::current();

        if (empty($profile)) {
            $keypart = sprintf('Notice:public_tag_cloud:null');
        } else {
            $keypart = sprintf('Notice:public_tag_cloud:%d', $profile->id);
        }

        $tag = Memcached_DataObject::cacheGet($keypart);

        if ($tag === false) {

            $stream = new PublicNoticeStream($profile);

            $ids = $stream->getNoticeIds(0, 500, null, null);

            if (empty($ids)) {
                $tag = array();
            } else {
                $weightexpr = common_sql_weight('notice_tag.created', common_config('tag', 'dropoff'));
                // @fixme should we use the cutoff too? Doesn't help with indexing per-user.

                $qry = 'SELECT notice_tag.tag, '.
                    $weightexpr . ' as weight ' .
                    'FROM notice_tag JOIN notice ' .
                    'ON notice_tag.notice_id = notice.id ' .
                    'WHERE notice.id in (' . implode(',', $ids) . ') '.
                    'GROUP BY notice_tag.tag ' .
                    'ORDER BY weight DESC ';

                $limit = TAGS_PER_SECTION;
                $offset = 0;

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

                $t = new Notice_tag();

                $t->query($qry);

                $tag = array();

                while ($t->fetch()) {
                    $tag[] = clone($t);
                }
            }

            Memcached_DataObject::cacheSet($keypart, $tag, 60 * 60 * 24);
        }

        return new ArrayWrapper($tag);
    }

    function showMore()
    {
    }
}


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); }

/**
 * Base class for queue handlers.
 *
 * As of 0.9, queue handlers are short-lived for items as they are
 * dequeued by a QueueManager running in an IoMaster in a daemon
 * such as queuedaemon.php.
 *
 * Extensions requiring long-running maintenance or polling should
 * register an IoManager.
 *
 * Subclasses must override at least the following methods:
 * - transport
 * - handle
 */
class QueueHandler
{

    /**
     * Here's the meat of your queue handler -- you're handed a Notice
     * or other object, which you may do as you will with.
     *
     * If this function indicates failure, a warning will be logged
     * and the item is placed back in the queue to be re-run.
     *
     * @param mixed $object
     * @return boolean true on success, false on failure
     */
    function handle($object)
    {
        return true;
    }
}