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

/**
 * Invite button
 *
 * @category  Section
 * @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 InviteButtonSection extends Section
{
    protected $buttonText;

    function __construct($out = null, $buttonText = null)
    {
        $this->out = $out;
        if (empty($buttonText)) {
            // TRANS: Default button text for inviting more users to the StatusNet instance.
            $this->buttonText = _m('BUTTON', 'Invite more people');
        } else {
            $this->buttonText = $buttonText;
        }
    }

    function showTitle()
    {
        return false;
    }

    function divId()
    {
        return 'invite_button';
    }

    function showContent()
    {
        $this->out->element(
            'a',
            array(
                'href' => common_local_url('invite'),
                'class' => 'invite_button'
            ),
            $this->buttonText
        );
        return false;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Form for inviting collegues and friends
 *
 * 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    Zach Copley <zach@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

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

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

/**
 * Form for inviting collegues and friends
 *
 * @category Form
 * @package  StatusNet
 * @author   Zach Copley <zach@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class InviteForm extends Form
{
    /**
     * Constructor
     *
     * @param Action $out output channel
     */
    function __construct($out=null)
    {
        parent::__construct($out);
    }

    /**
     * ID of the form
     *
     * @return string ID of the form
     */
    function id()
    {
       return 'form_invite';
    }

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

    /**
     * Name of the form
     *
     * @return void
     */
    function formLegend()
    {
        // TRANS: Form legend.
        $this->out->element('legend', null, _('Invite collegues'));
    }

    /**
     * Data elements of the form
     *
     * @return void
     */
    function formData()
    {
        $this->out->elementStart('ul', 'form_data');
        $this->out->elementStart('li');
        $this->out->textarea(
            'addresses',
            // TRANS: Field label for a list of e-mail addresses.
            _('Email addresses'),
            $this->out->trimmed('addresses'),
            // TRANS: Field title for a list of e-mail addresses.
            _('Addresses of friends to invite (one per line).')
        );
        $this->out->elementEnd('li');
        $this->out->elementStart('li');
        $this->out->textarea(
            // TRANS: Field label for a personal message to send to invitees.
            'personal', _('Personal message'),
            $this->out->trimmed('personal'),
            // TRANS: Field title for a personal message to send to invitees.
            _('Optionally add a personal message to the invitation.')
        );
        $this->out->elementEnd('li');
        $this->out->elementEnd('ul');
    }

    /**
     * Action elements
     *
     * @return void
     */
    function formActions()
    {
        $this->out->submit(
            'send',
            // TRANS: Send button for inviting friends
            _m('BUTTON','Send'), 'submit form_action-primary',
            'send',
            // TRANS: Submit button title.
            _('Send invitations.')
        );
    }
}

license: mit


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Abstract class for i/o managers
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  QueueManager
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Sarven Capadisli <csarven@status.net>
 * @author    Brion Vibber <brion@status.net>
 * @copyright 2009-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/
 */

abstract class IoManager
{
    const SINGLE_ONLY = 0;
    const INSTANCE_PER_SITE = 1;
    const INSTANCE_PER_PROCESS = 2;

    /**
     * Factory function to get an appropriate subclass.
     */
    public static function get() {
        throw new MethodNotImplementedException(__METHOD__);
    }

    /**
     * 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::SINGLE_ONLY;
    }

    /**
     * If in a multisite configuration, the i/o master will tell
     * your manager about each site you'll have to handle so you
     * can do any necessary per-site setup.
     *
     * The new site will be the currently live configuration during
     * this call.
     */
    public function addSite()
    {
        /* no-op */
    }

    /**
     * This method is called when data is available on one of your
     * i/o manager's sockets. The socket with data is passed in,
     * in case you have multiple sockets.
     *
     * If your i/o manager is based on polling during idle processing,
     * you don't need to implement this.
     *
     * @param resource $socket
     * @return boolean true on success, false on failure
     */
    public function handleInput($socket)
    {
        return true;
    }

    /**
     * Return any open sockets that the run loop should listen
     * for input on. If input comes in on a listed socket,
     * the matching manager's handleInput method will be called.
     *
     * @return array of resources
     */
    function getSockets()
    {
        return array();
    }

    /**
     * Maximum planned time between poll() calls when input isn't waiting.
     * Actual time may vary!
     *
     * When we get a polling hit, the timeout will be cut down to 0 while
     * input is coming in, then will back off to this amount if no further
     * input shows up.
     *
     * By default polling is disabled; you must override this to enable
     * polling for this manager.
     *
     * @return int max poll interval in seconds, or 0 to disable polling
     */
    function pollInterval()
    {
        return 0;
    }

    /**
     * Request a maximum timeout for listeners before the next idle period.
     * Actual wait may be shorter, so don't go crazy in your idle()!
     * Wait could be longer if other handlers performed some slow activity.
     *
     * Return 0 to request that listeners return immediately if there's no
     * i/o and speed up the idle as much as possible; but don't do that all
     * the time as this will burn CPU.
     *
     * @return int seconds
     */
    function timeout()
    {
        return 60;
    }

    /**
     * Called by IoManager after each handled item or empty polling cycle.
     * This is a good time to e.g. service your XMPP connection.
     *
     * Doesn't need to be overridden if there's no maintenance to do.
     */
    function idle()
    {
        return true;
    }

    /**
     * The meat of a polling manager... check for something to do
     * and do it! Note that you should not take too long, as other
     * i/o managers may need to do some work too!
     *
     * On a successful hit, the next poll() call will come as soon
     * as possible followed by exponential backoff up to pollInterval()
     * if no more data is available.
     *
     * @return boolean true if events were hit
     */
    public function poll()
    {
        return false;
    }

    /**
     * Initialization, run when the queue manager starts.
     * If this function indicates failure, the handler run will be aborted.
     *
     * @param IoMaster $master process/event controller
     * @return boolean true on success, false on failure
     */
    public function start($master)
    {
        $this->master = $master;
        return true;
    }

    /**
     * Cleanup, run when the queue manager ends.
     * If this function indicates failure, a warning will be logged.
     *
     * @return boolean true on success, false on failure
     */
    public function finish()
    {
        return true;
    }

    /**
     * Ping iomaster's queue status monitor with a stats update.
     * Only valid during input loop!
     *
     * @param string $counter keyword for counter to increment
     */
    public function stats($counter, $owners=array())
    {
        $this->master->stats($counter, $owners);
    }
}


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

abstract class IoMaster
{
    public $id;

    protected $multiSite = false;
    protected $managers = array();
    protected $singletons = array();

    protected $pollTimeouts = array();
    protected $lastPoll = array();

    public $shutdown = false; // Did we do a graceful shutdown?
    public $respawn = true; // Should we respawn after shutdown?

    /**
     * @param string $id process ID to use in logging/monitoring
     */
    public function __construct($id)
    {
        $this->id = $id;
        $this->monitor = new QueueMonitor();
    }

    public function init($multiSite=null)
    {
        if ($multiSite !== null) {
            $this->multiSite = $multiSite;
        }

        $this->initManagers();
    }

    /**
     * Initialize IoManagers which are appropriate to this instance;
     * pass class names or instances into $this->instantiate().
     *
     * If setup and configuration may vary between sites in multi-site
     * mode, it's the subclass's responsibility to set them up here.
     *
     * Switching site configurations is an acceptable side effect.
     */
    abstract function initManagers();

    /**
     * Instantiate an i/o manager class for the current site.
     * If a multi-site capable handler is already present,
     * we don't need to build a new one.
     *
     * @param mixed $manager class name (to run $class::get()) or object
     */
    protected function instantiate($manager)
    {
        if (is_string($manager)) {
            $manager = call_user_func(array($class, 'get'));
        }

        $caps = $manager->multiSite();
        if ($caps == IoManager::SINGLE_ONLY) {
            if ($this->multiSite) {
                throw new Exception("$class can't run with --all; aborting.");
            }
        } else if ($caps == IoManager::INSTANCE_PER_PROCESS) {
            $manager->addSite();
        }

        if (!in_array($manager, $this->managers, true)) {
            // Only need to save singletons once
            $this->managers[] = $manager;
        }
    }

    /**
     * Basic run loop...
     *
     * Initialize all io managers, then sit around waiting for input.
     * Between events or timeouts, pass control back to idle() method
     * to allow for any additional background processing.
     */
    function service()
    {
        $this->logState('init');
        $this->start();
        $this->checkMemory(false);

        while (!$this->shutdown) {
            $timeouts = array_values($this->pollTimeouts);
            $timeouts[] = 60; // default max timeout

            // Wait for something on one of our sockets
            $sockets = array();
            $managers = array();
            foreach ($this->managers as $manager) {
                foreach ($manager->getSockets() as $socket) {
                    $sockets[] = $socket;
                    $managers[] = $manager;
                }
                $timeouts[] = intval($manager->timeout());
            }

            $timeout = min($timeouts);
            if ($sockets) {
                $read = $sockets;
                $write = array();
                $except = array();
                $this->logState('listening');
                //common_debug("Waiting up to $timeout seconds for socket data...");
                $ready = stream_select($read, $write, $except, $timeout, 0);

                if ($ready === false) {
                    common_log(LOG_ERR, "Error selecting on sockets");
                } else if ($ready > 0) {
                    foreach ($read as $socket) {
                        $index = array_search($socket, $sockets, true);
                        if ($index !== false) {
                            $this->logState('queue');
                            $managers[$index]->handleInput($socket);
                        } else {
                            common_log(LOG_ERR, "Saw input on a socket we didn't listen to");
                        }
                    }
                }
            }

            if ($timeout > 0 && empty($sockets)) {
                // If we had no listeners, sleep until the pollers' next requested wakeup.
                common_log(LOG_DEBUG, "Sleeping $timeout seconds until next poll cycle...");
                $this->logState('sleep');
                sleep($timeout);
            }

            $this->logState('poll');
            $this->poll();

            $this->logState('idle');
            $this->idle();

            $this->checkMemory();
        }

        $this->logState('shutdown');
        $this->finish();
    }

    /**
     * Check runtime memory usage, possibly triggering a graceful shutdown
     * and thread respawn if we've crossed the soft limit.
     *
     * @param boolean $respawn if false we'll shut down instead of respawning
     */
    protected function checkMemory($respawn=true)
    {
        $memoryLimit = $this->softMemoryLimit();
        if ($memoryLimit > 0) {
            $usage = memory_get_usage();
            if ($usage > $memoryLimit) {
                common_log(LOG_INFO, "Queue thread hit soft memory limit ($usage > $memoryLimit); gracefully restarting.");
                if ($respawn) {
                    $this->requestRestart();
                } else {
                    $this->requestShutdown();
                }
            } else if (common_config('queue', 'debug_memory')) {
                $fmt = number_format($usage);
                common_log(LOG_DEBUG, "Memory usage $fmt");
            }
        }
    }

    /**
     * Return fully-parsed soft memory limit in bytes.
     * @return intval 0 or -1 if not set
     */
    function softMemoryLimit()
    {
        $softLimit = trim(common_config('queue', 'softlimit'));
        if (substr($softLimit, -1) == '%') {
            $limit = $this->parseMemoryLimit(ini_get('memory_limit'));
            if ($limit > 0) {
                return intval(substr($softLimit, 0, -1) * $limit / 100);
            } else {
                return -1;
            }
        } else {
            return $this->parseMemoryLimit($softLimit);
        }
        return $softLimit;
    }

    /**
     * Interpret PHP shorthand for memory_limit and friends.
     * Why don't they just expose the actual numeric value? :P
     * @param string $mem
     * @return int
     */
    public function parseMemoryLimit($mem)
    {
        // http://www.php.net/manual/en/faq.using.php#faq.using.shorthandbytes
        $mem = strtolower(trim($mem));
        $size = array('k' => 1024,
                      'm' => 1024*1024,
                      'g' => 1024*1024*1024);
        if (empty($mem)) {
            return 0;
        } else if (is_numeric($mem)) {
            return intval($mem);
        } else {
            $mult = substr($mem, -1);
            if (isset($size[$mult])) {
                return substr($mem, 0, -1) * $size[$mult];
            } else {
                return intval($mem);
            }
        }
    }

    function start()
    {
        foreach ($this->managers as $index => $manager) {
            $manager->start($this);
            // @fixme error check
            if ($manager->pollInterval()) {
                // We'll want to check for input on the first pass
                $this->pollTimeouts[$index] = 0;
                $this->lastPoll[$index] = 0;
            }
        }
    }

    function finish()
    {
        foreach ($this->managers as $manager) {
            $manager->finish();
            // @fixme error check
        }
    }

    /**
     * Called during the idle portion of the runloop to see which handlers
     */
    function poll()
    {
        foreach ($this->managers as $index => $manager) {
            $interval = $manager->pollInterval();
            if ($interval <= 0) {
                // Not a polling manager.
                continue;
            }

            if (isset($this->pollTimeouts[$index])) {
                $timeout = $this->pollTimeouts[$index];
                if (time() - $this->lastPoll[$index] < $timeout) {
                    // Not time to poll yet.
                    continue;
                }
            } else {
                $timeout = 0;
            }
            $hit = $manager->poll();

            $this->lastPoll[$index] = time();
            if ($hit) {
                // Do the next poll quickly, there may be more input!
                $this->pollTimeouts[$index] = 0;
            } else {
                // Empty queue. Exponential backoff up to the maximum poll interval.
                if ($timeout > 0) {
                    $timeout = min($timeout * 2, $interval);
                } else {
                    $timeout = 1;
                }
                $this->pollTimeouts[$index] = $timeout;
            }
        }
    }

    /**
     * Called after each handled item or empty polling cycle.
     * This is a good time to e.g. service your XMPP connection.
     */
    function idle()
    {
        foreach ($this->managers as $manager) {
            $manager->idle();
        }
    }

    /**
     * Send thread state update to the monitoring server, if configured.
     *
     * @param string $state ('init', 'queue', 'shutdown' etc)
     * @param string $substate (optional, eg queue name 'omb' 'sms' etc)
     */
    protected function logState($state, $substate='')
    {
        $this->monitor->logState($this->id, $state, $substate);
    }

    /**
     * Send thread stats.
     * Thread ID will be implicit; other owners can be listed as well
     * for per-queue and per-site records.
     *
     * @param string $key counter name
     * @param array $owners list of owner keys like 'queue:xmpp' or 'site:stat01'
     */
    public function stats($key, $owners=array())
    {
        $owners[] = "thread:" . $this->id;
        $this->monitor->stats($key, $owners);
    }

    /**
     * For IoManagers to request a graceful shutdown at end of event loop.
     */
    public function requestShutdown()
    {
        $this->shutdown = true;
        $this->respawn = false;
    }

    /**
     * For IoManagers to request a graceful restart at end of event loop.
     */
    public function requestRestart()
    {
        $this->shutdown = true;
        $this->respawn = true;
    }

}


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

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

/**
 * Form for joining a group
 *
 * @category Form
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @author   Sarven Capadisli <csarven@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 *
 * @see      UnsubscribeForm
 */
class JoinForm extends Form
{
    /**
     * group for user to join
     */
    var $group = null;

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

        $this->group = $group;
    }

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

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

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

    /**
     * Action elements
     *
     * @return void
     */
    function formActions()
    {
        // TRANS: Button text for joining a group.
        $this->out->submit('submit', _m('BUTTON','Join'));
    }
}


code:
<?php
if (!defined('GNUSOCIAL')) { exit(1); }

/*
 * Collection primarily as the root of an Activity Streams doc but can be used as the value
 * of extension properties in a variety of situations.
 *
 * A valid Collection object serialization MUST contain at least the url or items properties.
 */
class JSONActivityCollection {

    /* Non-negative integer specifying the total number of activities within the stream */
    protected $totalItems;

    /* An array containing a listing of Objects of any object type */
    protected $items;

    /* IRI referencing a JSON document containing the full listing of objects in the collection */
    protected $url;

    /**
     * Constructor
     *
     * @param array  $items       array of activity items
     * @param string $url         url of a doc list all the objs in the collection
     * @param int    $totalItems  total number of items in the collection
     */
    function __construct(array $items=[], $url = null)
    {
        $this->items      = empty($items) ? array() : $items;
        $this->totalItems = count($items);
        $this->url        = $url;
    }

    /**
     * Get the total number of items in the collection
     *
     * @return int total the total
     */
    public function getTotalItems()
    {
        $this->totalItems = count($items);
        return $this->totalItems;
    }
}


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  Search
 * @package   StatusNet
 * @author    Zach Copley <zach@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);
}

/**
 * widget-like class for showing JSON search results
 *
 * @category Search
 * @package  StatusNet
 * @author   Zach Copley <zach@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 *
 */

class JSONSearchResultsList
{
    protected $notice;  // protected attrs invisible to json_encode()
    protected $rpp;

    // The below attributes are carefully named so the JSON output from
    // this obj matches the output from search.twitter.com

    var $results;
    var $since_id;
    var $max_id;
    var $refresh_url;
    var $results_per_page;
    var $completed_in;
    var $page;
    var $query;

    /**
     * constructor
     *
     * @param Notice $notice   stream of notices from DB_DataObject
     * @param string $query    the original search query
     * @param int    $rpp      the number of results to display per page
     * @param int    $page     a page offset
     * @param int    $since_id only display notices newer than this
     */

    function __construct($notice, $query, $rpp, $page, $since_id = 0)
    {
        $this->notice           = $notice;
        $this->query            = urlencode($query);
        $this->results_per_page = $rpp;
        $this->rpp              = $rpp;
        $this->page             = $page;
        $this->since_id         = $since_id;
        $this->results          = array();
    }

    /**
     * show the list of search results
     *
     * @return int $count of the search results listed.
     */

    function show()
    {
        $cnt = 0;
        $this->max_id = 0;

        $time_start = microtime(true);

        while ($this->notice->fetch() && $cnt <= $this->rpp) {
            $cnt++;

            // XXX: Hmmm. this depends on desc sort order
            if (!$this->max_id) {
                $this->max_id = (int)$this->notice->id;
            }

            if ($this->since_id && $this->notice->id <= $this->since_id) {
                break;
            }

            if ($cnt > $this->rpp) {
                break;
            }

            $profile = $this->notice->getProfile();

            // Don't show notices from deleted users

            if (!empty($profile)) {
                $item = new ResultItem($this->notice);
                array_push($this->results, $item);
            }
        }

        $time_end           = microtime(true);
        $this->completed_in = $time_end - $time_start;

        // Set other attrs

        $this->refresh_url = '?since_id=' . $this->max_id .
            '&q=' . $this->query;

        // pagination stuff

        if ($cnt > $this->rpp) {
            $this->next_page = '?page=' . ($this->page + 1) .
                '&max_id=' . $this->max_id;
            if ($this->rpp != 15) {
                $this->next_page .= '&rpp=' . $this->rpp;
            }
            $this->next_page .= '&q=' . $this->query;
        }

        if ($this->page > 1) {
            $this->previous_page = '?page=' . ($this->page - 1) .
                '&max_id=' . $this->max_id;
            if ($this->rpp != 15) {
                $this->previous_page .= '&rpp=' . $this->rpp;
            }
            $this->previous_page .= '&q=' . $this->query;
        }

        print json_encode($this);

        return $cnt;
    }
}

/**
 * widget for displaying a single JSON search result
 *
 * @category UI
 * @package  StatusNet
 * @author   Zach Copley <zach@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 * @see      JSONSearchResultsList
 */

class ResultItem
{
    /** The notice this item is based on. */

    protected $notice;  // protected attrs invisible to json_encode()

    /** The profile associated with the notice. */

    protected $profile;

    // The below attributes are carefully named so the JSON output from
    // this obj matches the output from search.twitter.com

    var $text;
    var $to_user_id;
    var $to_user;
    var $from_user;
    var $id;
    var $from_user_id;
    var $iso_language_code;
    var $source = null;
    var $source_link = null;
    var $profile_image_url;
    var $created_at;

    /**
     * constructor
     *
     * Also initializes the profile attribute.
     *
     * @param Notice $notice The notice we'll display
     */

    function __construct($notice)
    {
        $this->notice  = $notice;
        $this->profile = $notice->getProfile();
        $this->buildResult();
    }

    /**
     * Build a search result object
     *
     * This populates the the result in preparation for JSON encoding.
     *
     * @return void
     */

    function buildResult()
    {
        $this->text      = $this->notice->content;
        $replier_profile = null;

        if ($this->notice->reply_to) {
            $reply = Notice::getKV(intval($this->notice->reply_to));
            if ($reply) {
                $replier_profile = $reply->getProfile();
            }
        }

        $this->to_user_id = ($replier_profile) ?
            intval($replier_profile->id) : null;
        $this->to_user    = ($replier_profile) ?
            $replier_profile->nickname : null;

        $this->from_user    = $this->profile->nickname;
        $this->id           = $this->notice->id;
        $this->from_user_id = $this->profile->id;

        $this->iso_language_code = Profile_prefs::getConfigData($this->profile, 'site', 'language');

        // set source and source_link
        $this->setSourceData();

        $this->profile_image_url = $this->profile->avatarUrl(AVATAR_STREAM_SIZE);

        $this->created_at = common_date_rfc2822($this->notice->created);
    }

    /**
     * Set the notice's source data (api/app name and URL)
     *
     * Either the name (and link) of the API client that posted the notice,
     * or one of other other channels. Uses the local notice object.
     *
     * @return void
     */
    function setSourceData()
    {
        $source = null;
        $source_link = null;

        switch ($source) {
        case 'web':
        case 'xmpp':
        case 'mail':
        case 'omb':
        case 'api':
            // Gettext translations for the below source types are available.
            $source = _($this->notice->source);
            break;

        default:
            $ns = Notice_source::getKV($this->notice->source);
            if ($ns instanceof Notice_source) {
                $source = $ns->code;
                if (!empty($ns->url)) {
                    $source_link = $ns->url;
                    if (!empty($ns->name)) {
                        $source = $ns->name;
                    }
                }
            }
            break;
        }

        $this->source = $source;
        $this->source_link = $source_link;
    }
}


code:
<?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Utility functions for i18n
 *
 * @category  I18n
 * @package   GNU social
 * @author    Matthew Gregg <matthew.gregg@gmail.com>
 * @author    Ciaran Gultnieks <ciaran@ciarang.com>
 * @author    Evan Prodromou <evan@status.net>
 * @author    Diogo Cordeiro <diogo@fc.up.pt>
 * @copyright 2010-2019 Free Software Foundation, Inc http://www.fsf.org
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */

defined('GNUSOCIAL') || die();

// Locale category constants are usually predefined, but may not be
// on some systems such as Win32.
$LC_CATEGORIES = ['LC_CTYPE',
                  'LC_NUMERIC',
                  'LC_TIME',
                  'LC_COLLATE',
                  'LC_MONETARY',
                  'LC_MESSAGES',
                  'LC_ALL'];
foreach ($LC_CATEGORIES as $key => $name) {
    if (!defined($name)) {
        define($name, $key);
    }
}

if (!function_exists('dpgettext')) {
    /**
     * Context-aware dgettext wrapper; use when messages in different contexts
     * won't be distinguished from the English source but need different translations.
     * The context string will appear as msgctxt in the .po files.
     *
     * Not currently exposed in PHP's gettext module; implemented to be compat
     * with gettext.h's macros.
     *
     * @param string $domain domain identifier
     * @param string $context context identifier, should be some key like "menu|file"
     * @param string $msg English source text
     * @return string original or translated message
     */
    function dpgettext($domain, $context, $msg)
    {
        $msgid = $context . "\004" . $msg;
        $out = dcgettext($domain, $msgid, LC_MESSAGES);
        if ($out == $msgid) {
            return $msg;
        } else {
            return $out;
        }
    }
}

if (!function_exists('pgettext')) {
    /**
     * Context-aware gettext wrapper; use when messages in different contexts
     * won't be distinguished from the English source but need different translations.
     * The context string will appear as msgctxt in the .po files.
     *
     * Not currently exposed in PHP's gettext module; implemented to be compat
     * with gettext.h's macros.
     *
     * @param string $context context identifier, should be some key like "menu|file"
     * @param string $msgid English source text
     * @return string original or translated message
     */
    function pgettext($context, $msgid)
    {
        return dpgettext(textdomain(NULL), $context, $msgid);
    }
}

if (!function_exists('dnpgettext')) {
    /**
     * Context-aware dngettext wrapper; use when messages in different contexts
     * won't be distinguished from the English source but need different translations.
     * The context string will appear as msgctxt in the .po files.
     *
     * Not currently exposed in PHP's gettext module; implemented to be compat
     * with gettext.h's macros.
     *
     * @param string $domain domain identifier
     * @param string $context context identifier, should be some key like "menu|file"
     * @param string $msg singular English source text
     * @param string $plural plural English source text
     * @param int $n number of items to control plural selection
     * @return string original or translated message
     */
    function dnpgettext($domain, $context, $msg, $plural, $n)
    {
        $msgid = $context . "\004" . $msg;
        $out = dcngettext($domain, $msgid, $plural, $n, LC_MESSAGES);
        if ($out == $msgid) {
            return $msg;
        } else {
            return $out;
        }
    }
}

if (!function_exists('npgettext')) {
    /**
     * Context-aware ngettext wrapper; use when messages in different contexts
     * won't be distinguished from the English source but need different translations.
     * The context string will appear as msgctxt in the .po files.
     *
     * Not currently exposed in PHP's gettext module; implemented to be compat
     * with gettext.h's macros.
     *
     * @param string $context context identifier, should be some key like "menu|file"
     * @param string $msgid singular English source text
     * @param string $plural plural English source text
     * @param int $n number of items to control plural selection
     * @return string original or translated message
     */
    function npgettext($context, $msgid, $plural, $n)
    {
        return dnpgettext(textdomain(NULL), $msgid, $plural, $n, LC_MESSAGES);
    }
}

/**
 * Shortcut for *gettext functions with smart domain detection.
 *
 * If calling from a plugin, this function checks which plugin was
 * being called from and uses that as text domain, which will have
 * been set up during plugin initialization.
 *
 * Also handles plurals and contexts depending on what parameters
 * are passed to it:
 *
 *   gettext -> _m($msg)
 *  ngettext -> _m($msg1, $msg2, $n)
 *  pgettext -> _m($ctx, $msg)
 * npgettext -> _m($ctx, $msg1, $msg2, $n)
 *
 * @fixme may not work properly in eval'd code
 *
 * @param string $msg
 * @return string
 * @throws Exception
 */
function _m($msg/*, ...*/)
{
    $domain = _mdomain(debug_backtrace());
    $args = func_get_args();
    switch (count($args)) {
        case 1:
            return dgettext($domain, $msg);
        case 2:
            return dpgettext($domain, $args[0], $args[1]);
        case 3:
            return dngettext($domain, $args[0], $args[1], $args[2]);
        case 4:
            return dnpgettext($domain, $args[0], $args[1], $args[2], $args[3]);
        default:
            throw new Exception("Bad parameter count to _m()");
    }
}

/**
 * Looks for which plugin we've been called from to set the gettext domain;
 * if not in a plugin subdirectory, we'll use the default 'statusnet'.
 *
 * Note: we can't return null for default domain since most of the PHP gettext
 * wrapper functions turn null into "" before passing to the backend library.
 *
 * @param array $backtrace debug_backtrace() output
 * @return string
 * @private
 * @fixme could explode if SN is under a 'plugins' folder or share name.
 */
function _mdomain($backtrace)
{
    /*
      0 =>
        array
          'file' => string '/var/www/mublog/plugins/FeedSub/FeedSubPlugin.php' (length=49)
          'line' => int 77
          'function' => string '_m' (length=2)
          'args' =>
            array
              0 => &string 'Feeds' (length=5)
    */
    static $cached;
    $path = $backtrace[0]['file'];
    if (!isset($cached[$path])) {
        if (DIRECTORY_SEPARATOR !== '/') {
            $path = strtr($path, DIRECTORY_SEPARATOR, '/');
        }
        $plug = strpos($path, '/plugins/');
        if ($plug === false) {
            // We're not in a plugin; return default domain.
            $final = 'statusnet';
        } else {
            $cut = $plug + 9;
            $cut2 = strpos($path, '/', $cut);
            if ($cut2) {
                $final = substr($path, $cut, $cut2 - $cut);
            } else {
                // We might be running directly from the plugins dir?
                // If so, there's no place to store locale info.
                $final = 'statusnet';
            }
        }
        $cached[$path] = $final;
    }
    return $cached[$path];
}

/**
 * Content negotiation for language codes
 *
 * @param $http_accept_lang_header string HTTP Accept-Language header
 * @return string language code for best language match, false otherwise
 */

function client_preferred_language($http_accept_lang_header)
{
    $client_langs = [];

    $all_languages = common_config('site', 'languages');

    preg_match_all('"(((\S\S)-?(\S\S)?)(;q=([0-9.]+))?)\s*(,\s*|$)"',
        strtolower($http_accept_lang_header), $http_langs);

    for ($i = 0; $i < count($http_langs); ++$i) {
        if (!empty($http_langs[2][$i])) {
            // if no q default to 1.0
            $client_langs[$http_langs[2][$i]] =
                ($http_langs[6][$i] ? (float)$http_langs[6][$i] : 1.0 - ($i * 0.01));
        }
        if (!empty($http_langs[3][$i]) && empty($client_langs[$http_langs[3][$i]])) {
            // if a catchall default 0.01 lower
            $client_langs[$http_langs[3][$i]] =
                ($http_langs[6][$i] ? (float)$http_langs[6][$i] - 0.01 : 0.99);
        }
    }
    // sort in descending q
    arsort($client_langs);

    foreach ($client_langs as $lang => $q) {
        if (isset($all_languages[$lang])) {
            return ($all_languages[$lang]['lang']);
        }
    }
    return false;
}

/**
 * returns a simple code -> name mapping for languages
 *
 * @return array map of available languages by code to language name.
 */

function get_nice_language_list()
{
    $nice_lang = [];

    $all_languages = common_config('site', 'languages');

    foreach ($all_languages as $lang) {
        $nice_lang = $nice_lang + array($lang['lang'] => $lang['name']);
    }
    return $nice_lang;
}

/*
 * Check whether a language is right-to-left
 *
 * @param string $lang language code of the language to check
 *
 * @return boolean true if language is rtl
 */

function is_rtl($lang_value)
{
        foreach (common_config('site', 'languages') as $code => $info) {
                if ($lang_value == $info['lang']) {
                        return $info['direction'] == 'rtl';
                }
        }
}

/**
 * Get a list of all languages that are enabled in the default config
 *
 * This should ONLY be called when setting up the default config in common.php.
 * Any other attempt to get a list of languages should instead call
 * common_config('site','languages')
 *
 * @return array mapping of language codes to language info
 */
function get_all_languages()
{
    return [
        'af'        => ['q' => 0.8, 'lang' => 'af', 'name' => 'Afrikaans', 'direction' => 'ltr'],
        'ar'        => ['q' => 0.8, 'lang' => 'ar', 'name' => 'Arabic', 'direction' => 'rtl'],
        'ast'       => ['q' => 1, 'lang' => 'ast', 'name' => 'Asturian', 'direction' => 'ltr'],
        'eu'        => ['q' => 1, 'lang' => 'eu', 'name' => 'Basque', 'direction' => 'ltr'],
        'be-tarask' => ['q' => 0.5, 'lang' => 'be-tarask', 'name' => 'Belarusian (Taraškievica orthography)', 'direction' => 'ltr'],
        'br'        => ['q' => 0.8, 'lang' => 'br', 'name' => 'Breton', 'direction' => 'ltr'],
        'bg'        => ['q' => 0.8, 'lang' => 'bg', 'name' => 'Bulgarian', 'direction' => 'ltr'],
        'my'        => ['q' => 1, 'lang' => 'my', 'name' => 'Burmese', 'direction' => 'ltr'],
        'ca'        => ['q' => 0.5, 'lang' => 'ca', 'name' => 'Catalan', 'direction' => 'ltr'],
        'zh-cn'     => ['q' => 0.9, 'lang' => 'zh_CN', 'name' => 'Chinese (Simplified)', 'direction' => 'ltr'],
        'zh-hant'   => ['q' => 0.2, 'lang' => 'zh_TW', 'name' => 'Chinese (Taiwanese)', 'direction' => 'ltr'],
        'ksh'       => ['q' => 1, 'lang' => 'ksh', 'name' => 'Colognian', 'direction' => 'ltr'],
        'cs'        => ['q' => 0.5, 'lang' => 'cs', 'name' => 'Czech', 'direction' => 'ltr'],
        'da'        => ['q' => 0.8, 'lang' => 'da', 'name' => 'Danish', 'direction' => 'ltr'],
        'nl'        => ['q' => 0.5, 'lang' => 'nl', 'name' => 'Dutch', 'direction' => 'ltr'],
        'arz'       => ['q' => 0.8, 'lang' => 'arz', 'name' => 'Egyptian Spoken Arabic', 'direction' => 'rtl'],
        'en'        => ['q' => 1, 'lang' => 'en', 'name' => 'English', 'direction' => 'ltr'],
        'en-us'     => ['q' => 1, 'lang' => 'en', 'name' => 'English (US)', 'direction' => 'ltr'],
        'en-gb'     => ['q' => 1, 'lang' => 'en_GB', 'name' => 'English (UK)', 'direction' => 'ltr'],
        'eo'        => ['q' => 0.8, 'lang' => 'eo', 'name' => 'Esperanto', 'direction' => 'ltr'],
        'fi'        => ['q' => 1, 'lang' => 'fi', 'name' => 'Finnish', 'direction' => 'ltr'],
        'fr'        => ['q' => 1, 'lang' => 'fr', 'name' => 'French', 'direction' => 'ltr'],
        'fr-fr'     => ['q' => 1, 'lang' => 'fr', 'name' => 'French (France)', 'direction' => 'ltr'],
        'fur'       => ['q' => 0.8, 'lang' => 'fur', 'name' => 'Friulian', 'direction' => 'ltr'],
        'gl'        => ['q' => 0.8, 'lang' => 'gl', 'name' => 'Galician', 'direction' => 'ltr'],
        'ka'        => ['q' => 0.8, 'lang' => 'ka', 'name' => 'Georgian', 'direction' => 'ltr'],
        'de'        => ['q' => 0.8, 'lang' => 'de', 'name' => 'German', 'direction' => 'ltr'],
        'el'        => ['q' => 0.1, 'lang' => 'el', 'name' => 'Greek', 'direction' => 'ltr'],
        'he'        => ['q' => 0.5, 'lang' => 'he', 'name' => 'Hebrew', 'direction' => 'rtl'],
        'hu'        => ['q' => 0.8, 'lang' => 'hu', 'name' => 'Hungarian', 'direction' => 'ltr'],
        'is'        => ['q' => 0.1, 'lang' => 'is', 'name' => 'Icelandic', 'direction' => 'ltr'],
        'id'        => ['q' => 1, 'lang' => 'id', 'name' => 'Indonesian', 'direction' => 'ltr'],
        'ia'        => ['q' => 0.8, 'lang' => 'ia', 'name' => 'Interlingua', 'direction' => 'ltr'],
        'ga'        => ['q' => 0.5, 'lang' => 'ga', 'name' => 'Irish', 'direction' => 'ltr'],
        'it'        => ['q' => 1, 'lang' => 'it', 'name' => 'Italian', 'direction' => 'ltr'],
        'ja'        => ['q' => 0.5, 'lang' => 'ja', 'name' => 'Japanese', 'direction' => 'ltr'],
        'ko'        => ['q' => 0.9, 'lang' => 'ko', 'name' => 'Korean', 'direction' => 'ltr'],
        'lv'        => ['q' => 1, 'lang' => 'lv', 'name' => 'Latvian', 'direction' => 'ltr'],
        'lt'        => ['q' => 1, 'lang' => 'lt', 'name' => 'Lithuanian', 'direction' => 'ltr'],
        'lb'        => ['q' => 1, 'lang' => 'lb', 'name' => 'Luxembourgish', 'direction' => 'ltr'],
        'mk'        => ['q' => 0.5, 'lang' => 'mk', 'name' => 'Macedonian', 'direction' => 'ltr'],
        'mg'        => ['q' => 1, 'lang' => 'mg', 'name' => 'Malagasy', 'direction' => 'ltr'],
        'ms'        => ['q' => 1, 'lang' => 'ms', 'name' => 'Malay', 'direction' => 'ltr'],
        'ml'        => ['q' => 0.5, 'lang' => 'ml', 'name' => 'Malayalam', 'direction' => 'ltr'],
        'ne'        => ['q' => 1, 'lang' => 'ne', 'name' => 'Nepali', 'direction' => 'ltr'],
        'nb'        => ['q' => 0.1, 'lang' => 'nb', 'name' => 'Norwegian (Bokmål)', 'direction' => 'ltr'],
        'no'        => ['q' => 0.1, 'lang' => 'nb', 'name' => 'Norwegian (Bokmål)', 'direction' => 'ltr'],
        'nn'        => ['q' => 1, 'lang' => 'nn', 'name' => 'Norwegian (Nynorsk)', 'direction' => 'ltr'],
        'fa'        => ['q' => 1, 'lang' => 'fa', 'name' => 'Persian', 'direction' => 'rtl'],
        'pl'        => ['q' => 0.5, 'lang' => 'pl', 'name' => 'Polish', 'direction' => 'ltr'],
        'pt'        => ['q' => 1, 'lang' => 'pt', 'name' => 'Portuguese', 'direction' => 'ltr'],
        'pt-br'     => ['q' => 0.9, 'lang' => 'pt_BR', 'name' => 'Brazilian Portuguese', 'direction' => 'ltr'],
        'ru'        => ['q' => 0.9, 'lang' => 'ru', 'name' => 'Russian', 'direction' => 'ltr'],
        'sr-ec'     => ['q' => 1, 'lang' => 'sr-ec', 'name' => 'Serbian', 'direction' => 'ltr'],
        'es'        => ['q' => 1, 'lang' => 'es', 'name' => 'Spanish', 'direction' => 'ltr'],
        'sv'        => ['q' => 0.8, 'lang' => 'sv', 'name' => 'Swedish', 'direction' => 'ltr'],
        'tl'        => ['q' => 0.8, 'lang' => 'tl', 'name' => 'Tagalog', 'direction' => 'ltr'],
        'ta'        => ['q' => 1, 'lang' => 'ta', 'name' => 'Tamil', 'direction' => 'ltr'],
        'te'        => ['q' => 0.3, 'lang' => 'te', 'name' => 'Telugu', 'direction' => 'ltr'],
        'tr'        => ['q' => 0.5, 'lang' => 'tr', 'name' => 'Turkish', 'direction' => 'ltr'],
        'uk'        => ['q' => 1, 'lang' => 'uk', 'name' => 'Ukrainian', 'direction' => 'ltr'],
        'hsb'       => ['q' => 0.8, 'lang' => 'hsb', 'name' => 'Upper Sorbian', 'direction' => 'ltr'],
        'ur'        => ['q' => 1, 'lang' => 'ur_PK', 'name' => 'Urdu (Pakistan)', 'direction' => 'rtl'],
        'vi'        => ['q' => 0.8, 'lang' => 'vi', 'name' => 'Vietnamese', 'direction' => 'ltr'],
    ];
}


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

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

/**
 * Form for leaving a group
 *
 * @category Form
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @author   Sarven Capadisli <csarven@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 *
 * @see      UnsubscribeForm
 */
class LeaveForm extends Form
{
    /**
     * group for user to leave
     */

    var $group = null;

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

        $this->group = $group;
    }

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

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

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

    /**
     * Action elements
     *
     * @return void
     */
    function formActions()
    {
        // TRANS: Button text on form to leave a group.
        $this->out->submit('submit', _m('BUTTON','Leave'));
    }
}


code:
<?php

/**
 * Based on code from Stomp PHP library, working around bugs in the base class.
 *
 * Original code is copyright 2005-2006 The Apache Software Foundation
 * Modifications copyright 2009 StatusNet Inc by Brion Vibber <brion@status.net>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

class LiberalStomp extends Stomp
{
    /**
     * We need to be able to get the socket so advanced daemons can
     * do a select() waiting for input both from the queue and from
     * other sources such as an XMPP connection.
     *
     * @return resource
     */
    function getSocket()
    {
        return $this->_socket;
    }

    /**
     * Return the host we're currently connected to.
     *
     * @return string
     */
    function getServer()
    {
        $idx = $this->_currentHost;
        if ($idx >= 0) {
            $host = $this->_hosts[$idx];
            return "$host[0]:$host[1]";
        } else {
            return '[unconnected]';
        }
    }

    /**
     * Make socket connection to the server
     * We also set the stream to non-blocking mode, since we'll be
     * select'ing to wait for updates. In blocking mode it seems
     * to get confused sometimes.
     *
     * @throws StompException
     */
    protected function _makeConnection ()
    {
        parent::_makeConnection();
        stream_set_blocking($this->_socket, 0);
    }

    /**
     * Version 1.0.0 of the Stomp library gets confused if messages
     * come in too fast over the connection. This version will read
     * out as many frames as are ready to be read from the socket.
     *
     * Modified from Stomp::readFrame()
     *
     * @return StompFrame False when no frame to read
     */
    public function readFrames ()
    {
        if (!$this->hasFrameToRead()) {
            return false;
        }

        $rb = 1024;
        $data = '';
        $end = false;
        $frames = array();

        do {
            // @fixme this sometimes hangs in blocking mode...
            // shouldn't we have been idle until we found there's more data?
            $read = fread($this->_socket, $rb);
            if ($read === false || ($read === '' && feof($this->_socket))) {
                // @fixme possibly attempt an auto reconnect as old code?
                throw new StompException("Error reading");
                //$this->_reconnect();
                // @fixme this will lose prior items
                //return $this->readFrames();
            }
            $data .= $read;
            if (strpos($data, "\x00") !== false) {
                // Frames are null-delimited, but some servers
                // may append an extra \n according to old bug reports.
                $data = str_replace("\x00\n", "\x00", $data);
                $chunks = explode("\x00", $data);

                $data = array_pop($chunks);
                $frames = array_merge($frames, $chunks);
                if ($data == '') {
                    // We're at the end of a frame; stop reading.
                    break;
                } else {
                    // In the middle of a frame; keep going.
                }
            }
            // @fixme find out why this len < 2 check was there
            //$len = strlen($data);
        } while (true);//$len < 2 || $end == false);

        return array_map(array($this, 'parseFrame'), $frames);
    }

    /**
     * Parse a raw Stomp frame into an object.
     * Extracted from Stomp::readFrame()
     *
     * @param string $data
     * @return StompFrame
     */
    function parseFrame($data)
    {
        list ($header, $body) = explode("\n\n", $data, 2);
        $header = explode("\n", $header);
        $headers = array();
        $command = null;
        foreach ($header as $v) {
            if (isset($command)) {
                list ($name, $value) = explode(':', $v, 2);
                $headers[$name] = $value;
            } else {
                $command = $v;
            }
        }
        $frame = new StompFrame($command, $headers, trim($body));
        if (isset($frame->headers['transformation']) && $frame->headers['transformation'] == 'jms-map-json') {
            require_once 'Stomp/Message/Map.php';
            return new StompMessageMap($frame);
        } else {
            return $frame;
        }
        return $frame;
    }

    /**
     * Write frame to server
     *
     * @param StompFrame $stompFrame
     */
    protected function _writeFrame (StompFrame $stompFrame)
    {
        if (!is_resource($this->_socket)) {
            require_once 'Stomp/Exception.php';
            throw new StompException('Socket connection hasn\'t been established');
        }

        $data = $stompFrame->__toString();

        // Make sure the socket's in a writable state; if not, wait a bit.
        stream_set_blocking($this->_socket, 1);

        $r = fwrite($this->_socket, $data, strlen($data));
        stream_set_blocking($this->_socket, 0);
        if ($r === false || $r == 0) {
            $this->_reconnect();
            $this->_writeFrame($stompFrame);
        }
    }
 }


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Lists a user has created
 *
 * 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    Shashi Gowda <connect2shashi@gmail.com>
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

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

/**
 * Peopletags a user has subscribed to
 *
 * @category Widget
 * @package  StatusNet
 * @author   Shashi Gowda <connect2shashi@gmail.com>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class ListsNav extends MoreMenu
{
    var $profile=null;
    var $lists=null;

    function __construct($out, Profile $profile)
    {
        parent::__construct($out);
        $this->profile = $profile;

        $this->lists = $profile->getLists(Profile::current());
    }

    function tag()
    {
        return 'lists';
    }

    function getItems()
    {
        $items = array();

        while ($this->lists->fetch()) {
                $mode = $this->lists->private ? 'private' : 'public';
                $items[] = array('showprofiletag',
                                 array('nickname' => $this->profile->getNickname(),
                                       'tag'    => $this->lists->tag),
                                 $this->lists->tag,
                                 '');
         }

         return $items;
    }

    function hasLists()
    {
        return (!empty($this->lists) && $this->lists->N > 0);
    }

    function seeAllItem()
    {
        return array('peopletagsbyuser',
                     array('nickname' => $this->profile->nickname),
                     // TRANS: Link description for seeing all lists.
                     _('See all'),
                     // TRANS: Link title for seeing all lists.
                     _('See all lists you have created.'));
    }
}


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

/**
 * class for locations
 *
 * These are stored in the DB as part of notice and profile records,
 * but since they're about the same in both, we have a separate class
 * for them.
 *
 * @category Location
 * @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 Location
{
    public  $lat;
    public  $lon;
    public  $location_id;
    public  $location_ns;
    private $_url;
    private $_rdfurl;

    var $names = array();

    /**
     * Constructor that makes a Location from Notice::locationOptions(...)
     *
     * @param array $options    an array for example provided by Notice::locationOptions(...)
     *
     * @return Location Location with the given options (lat, lon, id, name)
     */
    static function fromOptions(array $options) {
        $location = new Location();
        foreach (['lat', 'lon', 'location_id', 'location_ns'] as $opt) {
            if (isset($options[$opt])) {
                $location->$opt = $options[$opt];
            }
        }
        return $location;
    }

    /**
     * Constructor that makes a Location from a string name
     *
     * @param string $name     Human-readable name (any kind)
     * @param string $language Language, default = common_language()
     *
     * @return Location Location with that name (or null if not found)
     */

    static function fromName($name, $language=null)
    {
        if (is_null($language)) {
            $language = common_language();
        }

        $location = null;

        // Let a third-party handle it

        Event::handle('LocationFromName', array($name, $language, &$location));

        return $location;
    }

    /**
     * Constructor that makes a Location from an ID
     *
     * @param integer $id       Identifier ID
     * @param integer $ns       Namespace of the identifier
     * @param string  $language Language to return name in (default is common)
     *
     * @return Location The location with this ID (or null if none)
     */

    static function fromId($id, $ns, $language=null)
    {
        if (is_null($language)) {
            $language = common_language();
        }

        $location = null;

        // Let a third-party handle it

        Event::handle('LocationFromId', array($id, $ns, $language, &$location));

        return $location;
    }

    /**
     * Constructor that finds the nearest location to a lat/lon pair
     *
     * @param float  $lat      Latitude
     * @param float  $lon      Longitude
     * @param string $language Language for results, default = current
     *
     * @return Location the location found, or null if none found
     */

    static function fromLatLon($lat, $lon, $language=null)
    {
        if (is_null($language)) {
            $language = common_language();
        }

        $location = null;

        // Let a third-party handle it

        if (Event::handle('LocationFromLatLon',
                          array($lat, $lon, $language, &$location))) {
            // Default is just the lat/lon pair

            $location = new Location();

            $location->lat = $lat;
            $location->lon = $lon;
        }

        return $location;
    }

    /**
     * Get the name for this location in the given language
     *
     * @param string $language language to use, default = current
     *
     * @return string location name or null if not found
     */

    function getName($language=null)
    {
        if (is_null($language)) {
            $language = common_language();
        }

        if (array_key_exists($language, $this->names)) {
            return $this->names[$language];
        } else {
            $name = null;
            Event::handle('LocationNameLanguage', array($this, $language, &$name));
            if (!empty($name)) {
                $this->names[$language] = $name;
                return $name;
            }
        }
    }

    /**
     * Get an URL suitable for this location
     *
     * @return string URL for this location or NULL
     */

    function getURL()
    {
        // Keep one cached

        if (is_string($this->_url)) {
            return $this->_url;
        }

        $url = null;

        Event::handle('LocationUrl', array($this, &$url));

        $this->_url = $url;

        return $url;
    }

    /**
     * Get an URL for this location, suitable for embedding in RDF
     *
     * @return string URL for this location or NULL
     */

    function getRdfURL()
    {
        // Keep one cached

        if (is_string($this->_rdfurl)) {
            return $this->_rdfurl;
        }

        $url = null;

        Event::handle('LocationRdfUrl', array($this, &$url));

        $this->_rdfurl = $url;

        return $url;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Menu for login 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('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

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

/**
 * Menu for login group of actions
 *
 * @category Output
 * @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      Widget
 */
class LoginGroupNav extends Menu
{
    /**
     * Show the menu
     *
     * @return void
     */
    function show()
    {
        $action_name = $this->action->trimmed('action');

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

        if (Event::handle('StartLoginGroupNav', array($this->action))) {

            $this->action->menuItem(common_local_url('login'),
                                    // TRANS: Menu item for logging in to the StatusNet site.
                                    _m('MENU','Login'),
                                    // TRANS: Title for menu item for logging in to the StatusNet site.
                                    _('Login with a username and password'),
                                    $action_name === 'login');

            if (!common_logged_in() &&
                !(common_config('site','closed') || common_config('site','inviteonly'))) {
                $this->action->menuItem(common_local_url('register'),
                                        // TRANS: Menu item for registering with the StatusNet site.
                                        _m('MENU','Register'),
                                        // TRANS: Title for menu item for registering with the StatusNet site.
                                        _('Sign up for a new account'),
                                        $action_name === 'register');
            }

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

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