code:
<?php
/*
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, 2010 StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

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

require_once(INSTALLDIR.'/lib/channel.php');

class Command
{
    protected $scoped = null;   // The Profile of the user performing the command
    var $user = null;

    function __construct($user=null)
    {
        $this->scoped = $user->getProfile();
        $this->user = $user;
    }

    /**
     * Execute the command and send success or error results
     * back via the given communications channel.
     *
     * @param Channel
     */
    public function execute($channel)
    {
        try {
            $this->handle($channel);
        } catch (CommandException $e) {
            $channel->error($this->user, $e->getMessage());
        } catch (Exception $e) {
            common_log(LOG_ERR, "Error handling " . get_class($this) . ": " . $e->getMessage());
            $channel->error($this->user, $e->getMessage());
        }
    }

    /**
     * Override this with the meat!
     *
     * An error to send back to the user may be sent by throwing
     * a CommandException with a formatted message.
     *
     * @param Channel
     * @throws CommandException
     */
    function handle($channel)
    {
        return false;
    }

    /**
     * Look up a notice from an argument, by poster's name to get last post
     * or notice_id prefixed with #.
     *
     * @return Notice
     * @throws CommandException
     */
    function getNotice($arg)
    {
        $notice = null;
        if (Event::handle('StartCommandGetNotice', array($this, $arg, &$notice))) {
            if(substr($this->other,0,1)=='#'){
                // A specific notice_id #123

                $notice = Notice::getKV(substr($arg,1));
                if (!$notice) {
                    // TRANS: Command exception text shown when a notice ID is requested that does not exist.
                    throw new CommandException(_('Notice with that id does not exist.'));
                }
            }

            if (Validate::uri($this->other)) {
                // A specific notice by URI lookup
                $notice = Notice::getKV('uri', $arg);
            }

            if (!$notice) {
                // Local or remote profile name to get their last notice.
                // May throw an exception and report 'no such user'
                $recipient = $this->getProfile($arg);

                $notice = $recipient->getCurrentNotice();
                if (!$notice) {
                    // TRANS: Command exception text shown when a last user notice is requested and it does not exist.
                    throw new CommandException(_('User has no last notice.'));
                }
            }
        }
        Event::handle('EndCommandGetNotice', array($this, $arg, &$notice));
        if (!$notice) {
            // TRANS: Command exception text shown when a notice ID is requested that does not exist.
            throw new CommandException(_('Notice with that id does not exist.'));
        }
        return $notice;
    }

    /**
     * Look up a local or remote profile by nickname.
     *
     * @return Profile
     * @throws CommandException
     */
    function getProfile($arg)
    {
        $profile = null;
        if (Event::handle('StartCommandGetProfile', array($this, $arg, &$profile))) {
            $profile =
              common_relative_profile($this->user, common_canonical_nickname($arg));
        }
        Event::handle('EndCommandGetProfile', array($this, $arg, &$profile));
        if (!$profile) {
            // TRANS: Message given requesting a profile for a non-existing user.
            // TRANS: %s is the nickname of the user for which the profile could not be found.
            throw new CommandException(sprintf(_('Could not find a user with nickname %s.'), $arg));
        }
        return $profile;
    }

    /**
     * Get a local user by name
     * @return User
     * @throws CommandException
     */
    function getUser($arg)
    {
        $user = null;
        if (Event::handle('StartCommandGetUser', array($this, $arg, &$user))) {
            $user = User::getKV('nickname', Nickname::normalize($arg));
        }
        Event::handle('EndCommandGetUser', array($this, $arg, &$user));
        if (!$user){
            // TRANS: Message given getting a non-existing user.
            // TRANS: %s is the nickname of the user that could not be found.
            throw new CommandException(sprintf(_('Could not find a local user with nickname %s.'),
                               $arg));
        }
        return $user;
    }

    /**
     * Get a local or remote group by name.
     * @return User_group
     * @throws CommandException
     */
    function getGroup($arg)
    {
        $group = null;
        if (Event::handle('StartCommandGetGroup', array($this, $arg, &$group))) {
            $group = User_group::getForNickname($arg, $this->user->getProfile());
        }
        Event::handle('EndCommandGetGroup', array($this, $arg, &$group));
        if (!$group) {
            // TRANS: Command exception text shown when a group is requested that does not exist.
            throw new CommandException(_('No such group.'));
        }
        return $group;
    }
}

class CommandException extends Exception
{
}

class UnimplementedCommand extends Command
{
    function handle($channel)
    {
        // TRANS: Error text shown when an unimplemented command is given.
        $channel->error($this->user, _('Sorry, this command is not yet implemented.'));
    }
}

class TrackingCommand extends UnimplementedCommand
{
}

class TrackOffCommand extends UnimplementedCommand
{
}

class TrackCommand extends UnimplementedCommand
{
    var $word = null;
    function __construct($user, $word)
    {
        parent::__construct($user);
        $this->word = $word;
    }
}

class UntrackCommand extends UnimplementedCommand
{
    var $word = null;
    function __construct($user, $word)
    {
        parent::__construct($user);
        $this->word = $word;
    }
}

class NudgeCommand extends Command
{
    var $other = null;
    function __construct($user, $other)
    {
        parent::__construct($user);
        $this->other = $other;
    }

    function handle($channel)
    {
        $recipient = $this->getUser($this->other);
        if ($recipient->id == $this->user->id) {
            // TRANS: Command exception text shown when a user tries to nudge themselves.
            throw new CommandException(_('It does not make a lot of sense to nudge yourself!'));
        } else {
            if ($recipient->email && $recipient->emailnotifynudge) {
                mail_notify_nudge($this->user, $recipient);
            }
            // XXX: notify by IM
            // XXX: notify by SMS
            // TRANS: Message given having nudged another user.
            // TRANS: %s is the nickname of the user that was nudged.
            $channel->output($this->user, sprintf(_('Nudge sent to %s.'),
                           $recipient->nickname));
        }
    }
}

class InviteCommand extends UnimplementedCommand
{
    var $other = null;
    function __construct($user, $other)
    {
        parent::__construct($user);
        $this->other = $other;
    }
}

class StatsCommand extends Command
{
    function handle($channel)
    {
        $profile = $this->user->getProfile();

        $subs_count   = $profile->subscriptionCount();
        $subbed_count = $profile->subscriberCount();
        $notice_count = $profile->noticeCount();

        // TRANS: User statistics text.
        // TRANS: %1$s is the number of other user the user is subscribed to.
        // TRANS: %2$s is the number of users that are subscribed to the user.
        // TRANS: %3$s is the number of notices the user has sent.
        $channel->output($this->user, sprintf(_("Subscriptions: %1\$s\n".
                                   "Subscribers: %2\$s\n".
                                   "Notices: %3\$s"),
                                 $subs_count,
                                 $subbed_count,
                                 $notice_count));
    }
}

class JoinCommand extends Command
{
    var $other = null;

    function __construct($user, $other)
    {
        parent::__construct($user);
        $this->other = $other;
    }

    function handle($channel)
    {
        $group = $this->getGroup($this->other);
        $cur   = $this->user;

        if ($cur->isMember($group)) {
            // TRANS: Error text shown a user tries to join a group they already are a member of.
            $channel->error($cur, _('You are already a member of that group.'));
            return;
        }
        if (Group_block::isBlocked($group, $cur->getProfile())) {
            // TRANS: Error text shown when a user tries to join a group they are blocked from joining.
          $channel->error($cur, _('You have been blocked from that group by the admin.'));
            return;
        }

        try {
            $cur->joinGroup($group);
        } catch (Exception $e) {
            // TRANS: Message given having failed to add a user to a group.
            // TRANS: %1$s is the nickname of the user, %2$s is the nickname of the group.
            $channel->error($cur, sprintf(_('Could not join user %1$s to group %2$s.'),
                                          $cur->nickname, $group->nickname));
            return;
        }

        // TRANS: Message given having added a user to a group.
        // TRANS: %1$s is the nickname of the user, %2$s is the nickname of the group.
        $channel->output($cur, sprintf(_('%1$s joined group %2$s.'),
                                              $cur->nickname,
                                              $group->nickname));
    }
}

class DropCommand extends Command
{
    var $other = null;

    function __construct($user, $other)
    {
        parent::__construct($user);
        $this->other = $other;
    }

    function handle($channel)
    {
        $group = $this->getGroup($this->other);
        $cur   = $this->user;

        if (!$group) {
            // TRANS: Error text shown when trying to leave a group that does not exist.
            $channel->error($cur, _('No such group.'));
            return;
        }

        if (!$cur->isMember($group)) {
            // TRANS: Error text shown when trying to leave an existing group the user is not a member of.
            $channel->error($cur, _('You are not a member of that group.'));
            return;
        }

        try {
            $cur->leaveGroup($group);
        } catch (Exception $e) {
            // TRANS: Message given having failed to remove a user from a group.
            // TRANS: %1$s is the nickname of the user, %2$s is the nickname of the group.
            $channel->error($cur, sprintf(_('Could not remove user %1$s from group %2$s.'),
                                          $cur->nickname, $group->nickname));
            return;
        }

        // TRANS: Message given having removed a user from a group.
        // TRANS: %1$s is the nickname of the user, %2$s is the nickname of the group.
        $channel->output($cur, sprintf(_('%1$s left group %2$s.'),
                                              $cur->nickname,
                                              $group->nickname));
    }
}

class TagCommand extends Command
{
    var $other = null;
    var $tags = null;
    function __construct($user, $other, $tags)
    {
        parent::__construct($user);
        $this->other = $other;
        $this->tags = $tags;
    }

    function handle($channel)
    {
        $profile = $this->getProfile($this->other);
        $cur     = $this->user->getProfile();

        if (!$profile) {
            // TRANS: Client error displayed trying to perform an action related to a non-existing profile.
            $channel->error($cur, _('No such profile.'));
            return;
        }
        if (!$cur->canTag($profile)) {
            // TRANS: Error displayed when trying to tag a user that cannot be tagged.
            $channel->error($cur, _('You cannot tag this user.'));
            return;
        }

        $privs = array();
        $tags = preg_split('/[\s,]+/', $this->tags);
        $clean_tags = array();

        foreach ($tags as $tag) {
            $private = @$tag[0] === '.';
            $tag = $clean_tags[] = common_canonical_tag($tag);

            if (!common_valid_profile_tag($tag)) {
                // TRANS: Error displayed if a given tag is invalid.
                // TRANS: %s is the invalid tag.
                $channel->error($cur, sprintf(_('Invalid tag: "%s".'), $tag));
                return;
            }
            $privs[$tag] = $private;
        }

        try {
            foreach ($clean_tags as $tag) {
                Profile_tag::setTag($cur->id, $profile->id, $tag, null, $privs[$tag]);
            }
        } catch (Exception $e) {
            // TRANS: Error displayed if tagging a user fails.
            // TRANS: %1$s is the tagged user, %2$s is the error message (no punctuation).
            $channel->error($cur, sprintf(_('Error tagging %1$s: %2$s'),
                                          $profile->nickname, $e->getMessage()));
            return;
        }

        // TRANS: Succes message displayed if tagging a user succeeds.
        // TRANS: %1$s is the tagged user's nickname, %2$s is a list of tags.
        // TRANS: Plural is decided based on the number of tags added (not part of message).
        $channel->output($cur, sprintf(_m('%1$s was tagged %2$s',
                                          '%1$s was tagged %2$s',
                                          count($clean_tags)),
                                       $profile->nickname,
                                       // TRANS: Separator for list of tags.
                                       implode(_(', '), $clean_tags)));
    }
}

class UntagCommand extends TagCommand
{
    function handle($channel)
    {
        $profile = $this->getProfile($this->other);
        $cur     = $this->user->getProfile();

        if (!$profile) {
            // TRANS: Client error displayed trying to perform an action related to a non-existing profile.
            $channel->error($cur, _('No such profile.'));
            return;
        }
        if (!$cur->canTag($profile)) {
            // TRANS: Error displayed when trying to tag a user that cannot be tagged.
            $channel->error($cur, _('You cannot tag this user.'));
            return;
        }

        $tags = array_map('common_canonical_tag', preg_split('/[\s,]+/', $this->tags));

        foreach ($tags as $tag) {
            if (!common_valid_profile_tag($tag)) {
                // TRANS: Error displayed if a given tag is invalid.
                // TRANS: %s is the invalid tag.
                $channel->error($cur, sprintf(_('Invalid tag: "%s"'), $tag));
                return;
            }
        }

        try {
            foreach ($tags as $tag) {
                Profile_tag::unTag($cur->id, $profile->id, $tag);
            }
        } catch (Exception $e) {
            // TRANS: Error displayed if untagging a user fails.
            // TRANS: %1$s is the untagged user, %2$s is the error message (no punctuation).
            $channel->error($cur, sprintf(_('Error untagging %1$s: %2$s'),
                                          $profile->nickname, $e->getMessage()));
            return;
        }

        // TRANS: Succes message displayed if untagging a user succeeds.
        // TRANS: %1$s is the untagged user's nickname, %2$s is a list of tags.
        // TRANS: Plural is decided based on the number of tags removed (not part of message).
        $channel->output($cur, sprintf(_m('The following tag was removed from user %1$s: %2$s.',
                                         'The following tags were removed from user %1$s: %2$s.',
                                         count($tags)),
                                       $profile->nickname,
                                       // TRANS: Separator for list of tags.
                                       implode(_(', '), $tags)));
    }
}

class WhoisCommand extends Command
{
    var $other = null;
    function __construct($user, $other)
    {
        parent::__construct($user);
        $this->other = $other;
    }

    function handle($channel)
    {
        $recipient = $this->getProfile($this->other);

        // TRANS: Whois output.
        // TRANS: %1$s nickname of the queried user, %2$s is their profile URL.
        $whois = sprintf(_m('WHOIS',"%1\$s (%2\$s)"), $recipient->nickname,
                         $recipient->profileurl);
        if ($recipient->fullname) {
            // TRANS: Whois output. %s is the full name of the queried user.
            $whois .= "\n" . sprintf(_('Fullname: %s'), $recipient->fullname);
        }
        if ($recipient->location) {
            // TRANS: Whois output. %s is the location of the queried user.
            $whois .= "\n" . sprintf(_('Location: %s'), $recipient->location);
        }
        if ($recipient->homepage) {
            // TRANS: Whois output. %s is the homepage of the queried user.
            $whois .= "\n" . sprintf(_('Homepage: %s'), $recipient->homepage);
        }
        if ($recipient->bio) {
            // TRANS: Whois output. %s is the bio information of the queried user.
            $whois .= "\n" . sprintf(_('About: %s'), $recipient->bio);
        }
        $channel->output($this->user, $whois);
    }
}

class ReplyCommand extends Command
{
    var $other = null;
    var $text = null;
    function __construct($user, $other, $text)
    {
        parent::__construct($user);
        $this->other = $other;
        $this->text = $text;
    }

    function handle($channel)
    {
        $notice = $this->getNotice($this->other);
        $recipient = $notice->getProfile();

        $len = mb_strlen($this->text);

        if ($len == 0) {
            // TRANS: Command exception text shown when trying to reply to a notice without providing content for the reply.
            $channel->error($this->user, _('No content!'));
            return;
        }

        $this->text = $this->user->shortenLinks($this->text);

        if (Notice::contentTooLong($this->text)) {
            // XXX: i18n. Needs plural support.
            // TRANS: Message given if content of a notice for a reply is too long. %1$d is used for plural.
            // TRANS: %1$d is the maximum number of characters, %2$d is the number of submitted characters.
            $channel->error($this->user, sprintf(_m('Notice too long - maximum is %1$d character, you sent %2$d.',
                                                    'Notice too long - maximum is %1$d characters, you sent %2$d.',
                                                    Notice::maxContent()),
                                                 Notice::maxContent(), mb_strlen($this->text)));
            return;
        }

        $notice = Notice::saveNew($this->user->id, $this->text, $channel->source(),
                                  array('reply_to' => $notice->id));

        if ($notice) {
            // TRANS: Text shown having sent a reply to a notice successfully.
            // TRANS: %s is the nickname of the user of the notice the reply was sent to.
            $channel->output($this->user, sprintf(_('Reply to %s sent.'), $recipient->nickname));
        } else {
            // TRANS: Error text shown when a reply to a notice fails with an unknown reason.
            $channel->error($this->user, _('Error saving notice.'));
        }

    }
}

class GetCommand extends Command
{
    var $other = null;

    function __construct($user, $other)
    {
        parent::__construct($user);
        $this->other = $other;
    }

    function handle($channel)
    {
        $target = $this->getProfile($this->other);

        $notice = $target->getCurrentNotice();
        if (!$notice) {
            // TRANS: Error text shown when a last user notice is requested and it does not exist.
            $channel->error($this->user, _('User has no last notice.'));
            return;
        }
        $notice_content = $notice->content;

        $channel->output($this->user, $target->nickname . ": " . $notice_content);
    }
}

class SubCommand extends Command
{
    var $other = null;

    function __construct($user, $other)
    {
        parent::__construct($user);
        $this->other = $other;
    }

    function handle($channel)
    {

        if (!$this->other) {
            // TRANS: Error text shown when no username was provided when issuing a subscribe command.
            $channel->error($this->user, _('Specify the name of the user to subscribe to.'));
            return;
        }

        $target = $this->getProfile($this->other);

        try {
            Subscription::start($this->user->getProfile(), $target);
            // TRANS: Text shown after having subscribed to another user successfully.
            // TRANS: %s is the name of the user the subscription was requested for.
            $channel->output($this->user, sprintf(_('Subscribed to %s.'), $this->other));
        } catch (Exception $e) {
            $channel->error($this->user, $e->getMessage());
        }
    }
}

class UnsubCommand extends Command
{
    var $other = null;

    function __construct($user, $other)
    {
        parent::__construct($user);
        $this->other = $other;
    }

    function handle($channel)
    {
        if(!$this->other) {
            // TRANS: Error text shown when no username was provided when issuing an unsubscribe command.
            $channel->error($this->user, _('Specify the name of the user to unsubscribe from.'));
            return;
        }

        $target = $this->getProfile($this->other);

        try {
            Subscription::cancel($this->user->getProfile(), $target);
            // TRANS: Text shown after having unsubscribed from another user successfully.
            // TRANS: %s is the name of the user the unsubscription was requested for.
            $channel->output($this->user, sprintf(_('Unsubscribed from %s.'), $this->other));
        } catch (Exception $e) {
            $channel->error($this->user, $e->getMessage());
        }
    }
}

class OffCommand extends Command
{
    var $other = null;

    function __construct($user, $other=null)
    {
        parent::__construct($user);
        $this->other = $other;
    }
    function handle($channel)
    {
        if ($this->other) {
            // TRANS: Error text shown when issuing the command "off" with a setting which has not yet been implemented.
            $channel->error($this->user, _("Command not yet implemented."));
        } else {
            if ($channel->off($this->user)) {
                // TRANS: Text shown when issuing the command "off" successfully.
                $channel->output($this->user, _('Notification off.'));
            } else {
                // TRANS: Error text shown when the command "off" fails for an unknown reason.
                $channel->error($this->user, _('Can\'t turn off notification.'));
            }
        }
    }
}

class OnCommand extends Command
{
    var $other = null;
    function __construct($user, $other=null)
    {
        parent::__construct($user);
        $this->other = $other;
    }

    function handle($channel)
    {
        if ($this->other) {
            // TRANS: Error text shown when issuing the command "on" with a setting which has not yet been implemented.
            $channel->error($this->user, _("Command not yet implemented."));
        } else {
            if ($channel->on($this->user)) {
                // TRANS: Text shown when issuing the command "on" successfully.
                $channel->output($this->user, _('Notification on.'));
            } else {
                // TRANS: Error text shown when the command "on" fails for an unknown reason.
                $channel->error($this->user, _('Can\'t turn on notification.'));
            }
        }
    }
}

class LoginCommand extends Command
{
    function handle($channel)
    {
        $disabled = common_config('logincommand','disabled');
        $disabled = isset($disabled) && $disabled;
        if($disabled) {
            // TRANS: Error text shown when issuing the login command while login is disabled.
            $channel->error($this->user, _('Login command is disabled.'));
            return;
        }

        try {
            $login_token = Login_token::makeNew($this->user);
        } catch (Exception $e) {
            $channel->error($this->user, $e->getMessage());
        }

        $channel->output($this->user,
            // TRANS: Text shown after issuing the login command successfully.
            // TRANS: %s is a logon link..
            sprintf(_('This link is useable only once and is valid for only 2 minutes: %s.'),
                    common_local_url('otp',
                        array('user_id' => $login_token->user_id, 'token' => $login_token->token))));
    }
}

class LoseCommand extends Command
{
    var $other = null;

    function __construct($user, $other)
    {
        parent::__construct($user);
        $this->other = $other;
    }

    function execute($channel)
    {
        if(!$this->other) {
            // TRANS: Error text shown when no username was provided when issuing the command.
            $channel->error($this->user, _('Specify the name of the user to unsubscribe from.'));
            return;
        }

        $result = Subscription::cancel($this->getProfile($this->other), $this->user->getProfile());

        if ($result) {
            // TRANS: Text shown after issuing the lose command successfully (stop another user from following the current user).
            // TRANS: %s is the name of the user the unsubscription was requested for.
            $channel->output($this->user, sprintf(_('Unsubscribed %s.'), $this->other));
        } else {
            $channel->error($this->user, $result);
        }
    }
}

class SubscriptionsCommand extends Command
{
    function handle($channel)
    {
        $profile = $this->user->getSubscribed(0);
        $nicknames=array();
        while ($profile->fetch()) {
            $nicknames[]=$profile->nickname;
        }
        if(count($nicknames)==0){
            // TRANS: Text shown after requesting other users a user is subscribed to without having any subscriptions.
            $out=_('You are not subscribed to anyone.');
        }else{
            // TRANS: Text shown after requesting other users a user is subscribed to.
            // TRANS: This message supports plural forms. This message is followed by a
            // TRANS: hard coded space and a comma separated list of subscribed users.
            $out = _m('You are subscribed to this person:',
                'You are subscribed to these people:',
                count($nicknames));
            $out .= ' ';
            $out .= implode(', ',$nicknames);
        }
        $channel->output($this->user,$out);
    }
}

class SubscribersCommand extends Command
{
    function handle($channel)
    {
        $profile = $this->user->getSubscribers();
        $nicknames=array();
        while ($profile->fetch()) {
            $nicknames[]=$profile->nickname;
        }
        if(count($nicknames)==0){
            // TRANS: Text shown after requesting other users that are subscribed to a user
            // TRANS: (followers) without having any subscribers.
            $out=_('No one is subscribed to you.');
        }else{
            // TRANS: Text shown after requesting other users that are subscribed to a user (followers).
            // TRANS: This message supports plural forms. This message is followed by a
            // TRANS: hard coded space and a comma separated list of subscribing users.
            $out = _m('This person is subscribed to you:',
                'These people are subscribed to you:',
                count($nicknames));
            $out .= ' ';
            $out .= implode(', ',$nicknames);
        }
        $channel->output($this->user,$out);
    }
}

class GroupsCommand extends Command
{
    function handle($channel)
    {
        $group = $this->user->getGroups();
        $groups=array();
        while ($group instanceof User_group && $group->fetch()) {
            $groups[]=$group->nickname;
        }
        if(count($groups)==0){
            // TRANS: Text shown after requesting groups a user is subscribed to without having
            // TRANS: any group subscriptions.
            $out=_('You are not a member of any groups.');
        }else{
            // TRANS: Text shown after requesting groups a user is subscribed to.
            // TRANS: This message supports plural forms. This message is followed by a
            // TRANS: hard coded space and a comma separated list of subscribed groups.
            $out = _m('You are a member of this group:',
                'You are a member of these groups:',
                count($nicknames));
            $out.=implode(', ',$groups);
        }
        $channel->output($this->user,$out);
    }
}

class HelpCommand extends Command
{
    function handle($channel)
    {
        // TRANS: Header line of help text for commands.
        $out = array(_m('COMMANDHELP', "Commands:"));
        $commands = array(// TRANS: Help message for IM/SMS command "on".
                          "on" => _m('COMMANDHELP', "turn on notifications"),
                          // TRANS: Help message for IM/SMS command "off".
                          "off" => _m('COMMANDHELP', "turn off notifications"),
                          // TRANS: Help message for IM/SMS command "help".
                          "help" => _m('COMMANDHELP', "show this help"),
                          // TRANS: Help message for IM/SMS command "follow <nickname>".
                          "follow <nickname>" => _m('COMMANDHELP', "subscribe to user"),
                          // TRANS: Help message for IM/SMS command "groups".
                          "groups" => _m('COMMANDHELP', "lists the groups you have joined"),
                          // TRANS: Help message for IM/SMS command "tag".
                          "tag <nickname> <tags>" => _m('COMMANDHELP',"tag a user"),
                          // TRANS: Help message for IM/SMS command "untag".
                          "untag <nickname> <tags>" => _m('COMMANDHELP',"untag a user"),
                          // TRANS: Help message for IM/SMS command "subscriptions".
                          "subscriptions" => _m('COMMANDHELP', "list the people you follow"),
                          // TRANS: Help message for IM/SMS command "subscribers".
                          "subscribers" => _m('COMMANDHELP', "list the people that follow you"),
                          // TRANS: Help message for IM/SMS command "leave <nickname>".
                          "leave <nickname>" => _m('COMMANDHELP', "unsubscribe from user"),
                          // TRANS: Help message for IM/SMS command "d <nickname> <text>".
                          "d <nickname> <text>" => _m('COMMANDHELP', "direct message to user"),
                          // TRANS: Help message for IM/SMS command "get <nickname>".
                          "get <nickname>" => _m('COMMANDHELP', "get last notice from user"),
                          // TRANS: Help message for IM/SMS command "whois <nickname>".
                          "whois <nickname>" => _m('COMMANDHELP', "get profile info on user"),
                          // TRANS: Help message for IM/SMS command "lose <nickname>".
                          "lose <nickname>" => _m('COMMANDHELP', "force user to stop following you"),
                          // TRANS: Help message for IM/SMS command "reply #<notice_id>".
                          "reply #<notice_id>" => _m('COMMANDHELP', "reply to notice with a given id"),
                          // TRANS: Help message for IM/SMS command "reply <nickname>".
                          "reply <nickname>" => _m('COMMANDHELP', "reply to the last notice from user"),
                          // TRANS: Help message for IM/SMS command "join <group>".
                          "join <group>" => _m('COMMANDHELP', "join group"),
                          // TRANS: Help message for IM/SMS command "login".
                          "login" => _m('COMMANDHELP', "Get a link to login to the web interface"),
                          // TRANS: Help message for IM/SMS command "drop <group>".
                          "drop <group>" => _m('COMMANDHELP', "leave group"),
                          // TRANS: Help message for IM/SMS command "stats".
                          "stats" => _m('COMMANDHELP', "get your stats"),
                          // TRANS: Help message for IM/SMS command "stop".
                          "stop" => _m('COMMANDHELP', "same as 'off'"),
                          // TRANS: Help message for IM/SMS command "quit".
                          "quit" => _m('COMMANDHELP', "same as 'off'"),
                          // TRANS: Help message for IM/SMS command "sub <nickname>".
                          "sub <nickname>" => _m('COMMANDHELP', "same as 'follow'"),
                          // TRANS: Help message for IM/SMS command "unsub <nickname>".
                          "unsub <nickname>" => _m('COMMANDHELP', "same as 'leave'"),
                          // TRANS: Help message for IM/SMS command "last <nickname>".
                          "last <nickname>" => _m('COMMANDHELP', "same as 'get'"),
                          // TRANS: Help message for IM/SMS command "on <nickname>".
                          "on <nickname>" => _m('COMMANDHELP', "not yet implemented."),
                          // TRANS: Help message for IM/SMS command "off <nickname>".
                          "off <nickname>" => _m('COMMANDHELP', "not yet implemented."),
                          // TRANS: Help message for IM/SMS command "nudge <nickname>".
                          "nudge <nickname>" => _m('COMMANDHELP', "remind a user to update."),
                          // TRANS: Help message for IM/SMS command "invite <phone number>".
                          "invite <phone number>" => _m('COMMANDHELP', "not yet implemented."),
                          // TRANS: Help message for IM/SMS command "track <word>".
                          "track <word>" => _m('COMMANDHELP', "not yet implemented."),
                          // TRANS: Help message for IM/SMS command "untrack <word>".
                          "untrack <word>" => _m('COMMANDHELP', "not yet implemented."),
                          // TRANS: Help message for IM/SMS command "track off".
                          "track off" => _m('COMMANDHELP', "not yet implemented."),
                          // TRANS: Help message for IM/SMS command "untrack all".
                          "untrack all" => _m('COMMANDHELP', "not yet implemented."),
                          // TRANS: Help message for IM/SMS command "tracks".
                          "tracks" => _m('COMMANDHELP', "not yet implemented."),
                          // TRANS: Help message for IM/SMS command "tracking".
                          "tracking" => _m('COMMANDHELP', "not yet implemented."));

        // Give plugins a chance to add or override...
        Event::handle('HelpCommandMessages', array($this, &$commands));

        ksort($commands);
        foreach ($commands as $command => $help) {
            $out[] = "$command - $help";
        }
        $channel->output($this->user, implode("\n", $out));
    }
}


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

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

class CommandInterpreter
{
    function handle_command($user, $text)
    {
        // XXX: localise

        $text = preg_replace('/\s+/', ' ', trim($text));
        list($cmd, $arg) = self::split_arg($text);

        // We try to support all the same commands as Twitter, see
        // http://getsatisfaction.com/twitter/topics/what_are_the_twitter_commands
        // There are a few compatibility commands from earlier versions of
        // StatusNet

        $cmd = strtolower($cmd);
        $result = false;

        if (Event::handle('StartInterpretCommand', array($cmd, $arg, $user, &$result))) {
            switch($cmd) {
            case 'help':
                if ($arg) {
                    $result = null;
                } else {
                    $result = new HelpCommand($user);
                }
                break;
            case 'login':
                if ($arg) {
                    $result = null;
                } else {
                    $result = new LoginCommand($user);
                }
                break;
            case 'lose':
                if ($arg) {
                    list($other, $extra) = self::split_arg($arg);
                    if ($extra) {
                        $result = null;
                    } else {
                        $result = new LoseCommand($user, $other);
                    }
                } else {
                    $result = null;
                }
                break;
            case 'subscribers':
                if ($arg) {
                    $result = null;
                } else {
                    $result = new SubscribersCommand($user);
                }
                break;
            case 'subscriptions':
                if ($arg) {
                    $result = null;
                } else {
                    $result = new SubscriptionsCommand($user);
                }
                break;
            case 'groups':
                if ($arg) {
                    $result = null;
                } else {
                    $result = new GroupsCommand($user);
                }
                break;
            case 'on':
                if ($arg) {
                    list($other, $extra) = self::split_arg($arg);
                    if ($extra) {
                        $result = null;
                    } else {
                        $result = new OnCommand($user, $other);
                    }
                } else {
                    $result = new OnCommand($user);
                }
                break;
            case 'off':
                if ($arg) {
                    list($other, $extra) = self::split_arg($arg);
                    if ($extra) {
                        $result = null;
                    } else {
                        $result = new OffCommand($user, $other);
                    }
                } else {
                    $result = new OffCommand($user);
                }
                break;
            case 'stop':
            case 'quit':
                if ($arg) {
                    $result = null;
                } else {
                    $result = new OffCommand($user);
                }
                break;
            case 'join':
                if (!$arg) {
                    $result = null;
                } else {
                    list($other, $extra) = self::split_arg($arg);
                    if ($extra) {
                        $result = null;
                    } else {
                        $result = new JoinCommand($user, $other);
                    }
                }
                break;
            case 'drop':
                if (!$arg) {
                    $result = null;
                } else {
                    list($other, $extra) = self::split_arg($arg);
                    if ($extra) {
                        $result = null;
                    } else {
                        $result = new DropCommand($user, $other);
                    }
                }
                break;
            case 'follow':
            case 'sub':
                if (!$arg) {
                    $result = null;
                } else {
                    list($other, $extra) = self::split_arg($arg);
                    if ($extra) {
                        $result = null;
                    } else {
                        $result = new SubCommand($user, $other);
                    }
                }
                break;
            case 'leave':
            case 'unsub':
                if (!$arg) {
                    $result = null;
                } else {
                    list($other, $extra) = self::split_arg($arg);
                    if ($extra) {
                        $result = null;
                    } else {
                        $result = new UnsubCommand($user, $other);
                    }
                }
                break;
            case 'get':
            case 'last':
                if (!$arg) {
                    $result = null;
                }
                list($other, $extra) = self::split_arg($arg);
                if ($extra) {
                    $result = null;
                } else {
                    $result = new GetCommand($user, $other);
                }
                break;
            case 'r':
            case 'reply':
                if (!$arg) {
                    $result = null;
                }
                list($other, $extra) = self::split_arg($arg);
                if (!$extra) {
                    $result = null;
                } else {
                    $result = new ReplyCommand($user, $other, $extra);
                }
                break;
            case 'whois':
                if (!$arg) {
                    $result = null;
                } else {
                    list($other, $extra) = self::split_arg($arg);
                    if ($extra) {
                        $result = null;
                    } else {
                        $result = new WhoisCommand($user, $other);
                    }
                }
                break;
            case 'nudge':
                if (!$arg) {
                    $result = null;
                } else {
                    list($other, $extra) = self::split_arg($arg);
                    if ($extra) {
                        $result = null;
                    } else {
                        $result = new NudgeCommand($user, $other);
                    }
                }
                break;
            case 'stats':
                if ($arg) {
                    $result = null;
                } else {
                    $result = new StatsCommand($user);
                }
                break;
            case 'invite':
                if (!$arg) {
                    $result = null;
                } else {
                    list($other, $extra) = self::split_arg($arg);
                    if ($extra) {
                        $result = null;
                    } else {
                        $result = new InviteCommand($user, $other);
                    }
                }
                break;
             case 'list':
             case 'tag':
                if (!$arg) {
                    $result = null;
                    break;
                }
                list($other, $tags) = self::split_arg($arg);
                if (!$tags) {
                    $result = null;
                } else {
                    $result = new TagCommand($user, $other, $tags);
                }
                break;
             case 'unlist':
             case 'untag':
                if (!$arg) {
                    $result = null;
                    break;
                }
                list($other, $tags) = self::split_arg($arg);
                if (!$tags) {
                    $result = null;
                } else {
                    $result = new UntagCommand($user, $other, $tags);
                }
                break;
            case 'track':
                if (!$arg) {
                    $result = null;
                } else {
                    list($word, $extra) = self::split_arg($arg);
                    if ($extra) {
                        $result = null;
                    } else if ($word == 'off') {
                        $result = new TrackOffCommand($user);
                    } else {
                        $result = new TrackCommand($user, $word);
                    }
                }
                break;
            case 'untrack':
                if (!$arg) {
                    $result = null;
                } else {
                    list($word, $extra) = self::split_arg($arg);
                    if ($extra) {
                        $result = null;
                    } else if ($word == 'all') {
                        $result = new TrackOffCommand($user);
                    } else {
                        $result = new UntrackCommand($user, $word);
                    }
                }
                break;
            case 'tracks':
            case 'tracking':
                if ($arg) {
                    $result = null;
                } else {
                    $result = new TrackingCommand($user);
                }
                break;
            }

            Event::handle('EndInterpretCommand', array($cmd, $arg, $user, &$result));
        }

        return $result;
    }

    /**
     * Split arguments without triggering a PHP notice warning
     */
    static function split_arg($text)
    {
        $pieces = explode(' ', $text, 2);
        if (count($pieces) == 1) {
            $pieces[] = null;
        }
        return $pieces;
    }
}

repo_name: dansup/gnu

license: mit


code:
<?php
/*
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2008-2010, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

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

// All the fun stuff to actually initialize StatusNet's framework code,
// without loading up a site configuration.
require_once INSTALLDIR . '/lib/framework.php';

try {
    GNUsocial::init(@$server, @$path, @$conffile);
} catch (NoConfigException $e) {
    // XXX: Throw a conniption if database not installed
    // XXX: Find a way to use htmlwriter for this instead of handcoded markup
    // TRANS: Error message displayed when no configuration file was found for a StatusNet installation.
    echo '
'. _('No configuration file found.') .'
';
    // TRANS: Error message displayed when no configuration file was found for a StatusNet installation.
    // TRANS: Is followed by a list of directories (separated by HTML breaks).
    echo '
'. _('I looked for configuration files in the following places:') .'
 ';
    echo implode($e->configFiles, '
');
    // TRANS: Error message displayed when no configuration file was found for a StatusNet installation.
    echo '
'. _('You may wish to run the installer to fix this.') .'
';
    // @todo FIXME Link should be in a para?
    // TRANS: Error message displayed when no configuration file was found for a StatusNet installation.
    // TRANS: The text is link text that leads to the installer page.
    echo ''. _('Go to the installer.') .'';
    exit;
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Widget to show a list of OAuth applications
 *
 * 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  Application
 * @package   StatusNet
 * @author    Zach Copley <zach@status.net>
 * @copyright 2008-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('GNUSOCIAL')) { exit(1); }

/**
 * Widget to show a list of connected OAuth clients
 *
 * @category Application
 * @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 ConnectedAppsList extends Widget
{
    /** Current connected application query */
    var $connection = null;

    /** Owner of this list */
    var $owner = null;

    function __construct($connection, Profile $owner, Action $out=null)
    {
        parent::__construct($out);

        common_debug("ConnectedAppsList constructor");

        $this->connection = $connection;
        $this->owner      = $owner;
    }

    /* Override this in subclasses. */
    function showOwnerControls()
    {
        return;
    }

    function show()
    {
        $this->out->elementStart('ul', 'applications');

        $cnt = 0;

        while ($this->connection->fetch()) {
            $cnt++;
            if($cnt > APPS_PER_PAGE) {
                break;
            }
            $this->showConnection();
        }

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

        return $cnt;
    }

    function showConnection()
    {
        $app = Oauth_application::getKV('id', $this->connection->application_id);

        $this->out->elementStart('li', array('class' => 'application h-entry',
                                             'id'    => 'oauthclient-' . $app->id));

        $this->out->elementStart('a', array('href' => $app->source_url,
                                            'class' => 'h-card p-name'));

        if (!empty($app->icon)) {
            $this->out->element('img', array('src' => $app->icon,
                                             'class' => 'avatar u-photo'));
        }
        if ($app->name != 'anonymous') {
            $this->out->text($app->name);
        } else {
            // TRANS: Name for an anonymous application in application list.
            $this->out->element('span', 'p-name', _('Unknown application'));
        }
        $this->out->elementEnd('a');

        if ($app->name != 'anonymous') {
            // @todo FIXME: i18n trouble.
            // TRANS: Message has a leading space and a trailing space. Used in application list.
            // TRANS: Before this message the application name is put, behind it the organisation that manages it.
            $this->out->raw(_(' by '));

            $this->out->element('a', array('href' => $app->homepage,
                                           'class' => 'h-card'),
                                $app->organization);
        }

        // TRANS: Application access type
        $readWriteText = _('read-write');
        // TRANS: Application access type
        $readOnlyText = _('read-only');

        $access = ($this->connection->access_type & Oauth_application::$writeAccess)
            ? $readWriteText : $readOnlyText;
        $modifiedDate = common_date_string($this->connection->modified);
        // TRANS: Used in application list. %1$s is a modified date, %2$s is access type ("read-write" or "read-only")
        $txt = sprintf(_('Approved %1$s - "%2$s" access.'), $modifiedDate, $access);

        // @todo FIXME: i18n trouble.
        $this->out->raw(" - $txt");
        if (!empty($app->description)) {
            $this->out->element(
                'p', array('class' => 'application_description'),
                $app->description
            );
        }
        $this->out->element(
            'p', array(
            'class' => 'access_token'),
            // TRANS: Access token in the application list.
            // TRANS: %s are the first 7 characters of the access token.
            sprintf(_('Access token starting with: %s'), substr($this->connection->token, 0, 7))
        );

        $this->out->elementStart(
            'form',
            array(
                'id' => 'form_revoke_app',
                'class' => 'form_revoke_app',
                'method' => 'POST',
                'action' => common_local_url('oauthconnectionssettings')
            )
        );
        $this->out->elementStart('fieldset');
        $this->out->hidden('oauth_token', $this->connection->token);
        $this->out->hidden('token', common_session_token());
        // TRANS: Button label in application list to revoke access to user data.
        $this->out->submit('revoke', _m('BUTTON','Revoke'));
        $this->out->elementEnd('fieldset');
        $this->out->elementEnd('form');

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


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * Notice stream for a conversation
 *
 * 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  NoticeStream
 * @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('GNUSOCIAL')) { exit(1); }

/**
 * Notice stream for a conversation
 *
 * @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 ConversationNoticeStream extends ScopingNoticeStream
{
    function __construct($id, $profile = -1)
    {
        if (is_int($profile) && $profile == -1) {
            $profile = Profile::current();
        }

        parent::__construct(new RawConversationNoticeStream($id),
                            $profile);
    }
}

/**
 * Notice stream for a conversation
 *
 * @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 RawConversationNoticeStream extends NoticeStream
{
    protected $id;

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

    function getNoticeIds($offset, $limit, $since_id=null, $max_id=null)
    {
        $notice = new Notice();
        // SELECT
        $notice->selectAdd();
        $notice->selectAdd('id');

        // WHERE
        $notice->conversation = $this->id;
        if (!empty($since_id)) {
            $notice->whereAdd(sprintf('notice.id > %d', $since_id));
        }
        if (!empty($max_id)) {
            $notice->whereAdd(sprintf('notice.id <= %d', $max_id));
        }
        if (!is_null($offset)) {
            $notice->limit($offset, $limit);
        }

        self::filterVerbs($notice, $this->selectVerbs);

        // ORDER BY
        // currently imitates the previously used "_reverseChron" sorting
        $notice->orderBy('notice.created DESC');
        $notice->find();
        return $notice->fetchAll('id');
    }
}


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

/**
 * PHP 5.3 implementation of function currying, using native closures.
 * On 5.2 and lower we use the fallback implementation in util.php
 *
 * @param callback $fn
 * @param ... any remaining arguments will be appended to call-time params
 * @return callback
 */
function curry($fn) {
    $extra_args = func_get_args();
    array_shift($extra_args);
    return function() use ($fn, $extra_args) {
        $args = func_get_args();
        return call_user_func_array($fn,
            array_merge($args, $extra_args));
    };
}


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

class Daemon
{
    var $daemonize = true;
    var $_id = 'generic';

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

    function name()
    {
        return null;
    }

    function get_id()
    {
        return $this->_id;
    }

    function set_id($id)
    {
        $this->_id = $id;
    }

    function background()
    {
        /*
         * This prefers to Starting PHP 5.4 (dotdeb), maybe earlier for some version/distrib
         * seems MySQL connection using mysqli driver get lost when fork.
         * Need to unset it so that child process recreate it.
         *
         * @todo FIXME cleaner way to do it ?
         */
        global $_DB_DATAOBJECT;
        unset($_DB_DATAOBJECT['CONNECTIONS']);

        $pid = pcntl_fork();
        if ($pid < 0) { // error
            common_log(LOG_ERR, "Could not fork.");
            return false;
        } else if ($pid > 0) { // parent
            common_log(LOG_INFO, "Successfully forked.");
            exit(0);
        } else { // child
            return true;
        }
    }

    function alreadyRunning()
    {
        $pidfilename = $this->pidFilename();

        if (!$pidfilename) {
            return false;
        }

        if (!file_exists($pidfilename)) {
            return false;
        }
        $contents = file_get_contents($pidfilename);
        if (posix_kill(trim($contents), 0)) {
            return true;
        } else {
            return false;
        }
    }

    function writePidFile()
    {
        $pidfilename = $this->pidFilename();

        if (!$pidfilename) {
            return false;
        }

        return file_put_contents($pidfilename, posix_getpid() . "\n");
    }

    function clearPidFile()
    {
        $pidfilename = $this->pidFilename();
        if (!$pidfilename) {
            return false;
        }
        return unlink($pidfilename);
    }

    function pidFilename()
    {
        $piddir = common_config('daemon', 'piddir');
        if (!$piddir) {
            return null;
        }
        $name = $this->name();
        if (!$name) {
            return null;
        }
        return $piddir . '/' . $name . '.pid';
    }

    function changeUser()
    {
        $groupname = common_config('daemon', 'group');

        if ($groupname) {
            $group_info = posix_getgrnam($groupname);
            if (!$group_info) {
                common_log(LOG_WARNING,
                           'Ignoring unknown group for daemon: ' . $groupname);
            } else {
                common_log(LOG_INFO, "Setting group to " . $groupname);
                posix_setgid($group_info['gid']);
            }
        }

        $username = common_config('daemon', 'user');

        if ($username) {
            $user_info = posix_getpwnam($username);
            if (!$user_info) {
                common_log(LOG_WARNING,
                           'Ignoring unknown user for daemon: ' . $username);
            } else {
                common_log(LOG_INFO, "Setting user to " . $username);
                posix_setuid($user_info['uid']);
            }
        }
    }

    function runOnce()
    {
        if ($this->alreadyRunning()) {
            common_log(LOG_INFO, $this->name() . ' already running. Exiting.');
            exit(0);
        }

        if ($this->daemonize) {
            common_log(LOG_INFO, 'Backgrounding daemon "'.$this->name().'"');
            $this->background();
        }

        $this->writePidFile();
        $this->changeUser();
        $this->run();
        $this->clearPidFile();
    }

    function run()
    {
        return true;
    }
}


code:
<?php
/**
 * DB error action.
 *
 * PHP version 5
 *
 * @category Action
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @author   Zach Copley <zach@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 * @link     http://status.net/
 *
 * 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);
}

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

/**
 * Class for displaying DB Errors
 *
 * This only occurs if there's been a DB_DataObject_Error that's
 * reported through PEAR, so we try to avoid doing anything that connects
 * to the DB, so we don't trigger it again.
 *
 * @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 DBErrorAction extends ServerErrorAction
{
    function __construct($message='Error', $code=500)
    {
        parent::__construct($message, $code);
    }

    function title()
    {
        // TRANS: Page title for when a database error occurs.
        return _('Database error');
    }

    function getLanguage()
    {
        // Don't try to figure out user's language; just show the page
        return common_config('site', 'language');
    }

    function showPrimaryNav()
    {
        // don't show primary nav
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Simple-minded queue manager for storing items in the database
 *
 * 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    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/
 */

class DBQueueManager extends QueueManager
{
    /**
     * Saves an object reference into the queue item table.
     * @return boolean true on success
     * @throws ServerException on failure
     */
    public function enqueue($object, $queue)
    {
        $qi = new Queue_item();

        $qi->frame     = $this->encode($object);
        $qi->transport = $queue;
        $qi->created   = common_sql_now();
        $result        = $qi->insert();

        if ($result === false) {
            common_log_db_error($qi, 'INSERT', __FILE__);
            throw new ServerException('DB error inserting queue item');
        }

        $this->stats('enqueued', $queue);

        return true;
    }

    /**
     * Poll every 10 seconds for new events during idle periods.
     * We'll look in more often when there's data available.
     *
     * @return int seconds
     */
    public function pollInterval()
    {
        return 10;
    }

    /**
     * Run a polling cycle during idle processing in the input loop.
     * @return boolean true if we should poll again for more data immediately
     */
    public function poll()
    {
        //$this->_log(LOG_DEBUG, 'Checking for notices...');
        $qi = Queue_item::top($this->activeQueues(), $this->getIgnoredTransports());
        if (!$qi instanceof Queue_item) {
            //$this->_log(LOG_DEBUG, 'No notices waiting; idling.');
            return false;
        }

        try {
            $item = $this->decode($qi->frame);
        } catch (Exception $e) {
            $this->_log(LOG_INFO, "[{$qi->transport}] Discarding: ".$e->getMessage());
            $this->_done($qi);
            return true;
        }

        $rep = $this->logrep($item);
        $this->_log(LOG_DEBUG, "Got {$rep} for transport {$qi->transport}");

        try {
            $handler = $this->getHandler($qi->transport);
            $result = $handler->handle($item);
        } catch (NoQueueHandlerException $e) {
            $this->noHandlerFound($qi, $rep);
            return true;
        } catch (AlreadyFulfilledException $e) {
            $this->_log(LOG_ERR, "[{$qi->transport}:$rep] AlreadyFulfilledException thrown: {$e->getMessage()}");
            $result = true;
        } catch (Exception $e) {
            $this->_log(LOG_ERR, "[{$qi->transport}:$rep] Exception thrown: {$e->getMessage()}");
            $result = false;
        }

        if ($result) {
            $this->_log(LOG_INFO, "[{$qi->transport}:$rep] Successfully handled item");
            $this->_done($qi);
        } else {
            $this->_log(LOG_INFO, "[{$qi->transport}:$rep] Failed to handle item");
            $this->_fail($qi);
        }
        return true;
    }

    // What to do if no handler was found. For example, the OpportunisticQM
    // should avoid deleting items just because it can't reach XMPP queues etc.
    protected function noHandlerFound(Queue_item $qi, $rep=null) {
        $this->_log(LOG_INFO, "[{$qi->transport}:{$rep}] No handler for queue {$qi->transport}; discarding.");
        $this->_done($qi);
    }

    /**
     * Delete our claimed item from the queue after successful processing.
     *
     * @param QueueItem $qi
     */
    protected function _done(Queue_item $qi)
    {
        if (empty($qi->claimed)) {
            $this->_log(LOG_WARNING, "Reluctantly releasing unclaimed queue item {$qi->id} from {$qi->transport}");
        }
        $qi->delete();

        $this->stats('handled', $qi->transport);
    }

    /**
     * Free our claimed queue item for later reprocessing in case of
     * temporary failure.
     *
     * @param QueueItem $qi
     */
    protected function _fail(Queue_item $qi, $releaseOnly=false)
    {
        if (empty($qi->claimed)) {
            $this->_log(LOG_WARNING, "[{$qi->transport}:item {$qi->id}] Ignoring failure for unclaimed queue item");
        } else {
            $qi->releaseClaim();
        }

        if (!$releaseOnly) {
            $this->stats('error', $qi->transport);
        }
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Default settings for core configuration
 *
 * 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  Config
 * @package   GNUsocial
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2008-9 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://www.gnu.org/software/social/
 */

$default =
    array('site' =>
        array('name' => 'Just another GNU social node',
              'nickname' => 'gnusocial',
              'wildcard' => null,
              'server' => $_server,
              'theme' => 'neo-gnu',
              'path' => $_path,
              'logfile' => null,
              'logo' => null,
              'ssllogo' => null,
              'logdebug' => false,
              'logperf' => false, // Enable to dump performance counters to syslog
              'logperf_detail' => false, // Enable to dump every counter hit
              'fancy' => false,
              'locale_path' => INSTALLDIR.'/locale',
              'language' => 'en',
              'langdetect' => true,
              'languages' => get_all_languages(),
              'email' =>
              array_key_exists('SERVER_ADMIN', $_SERVER) ? $_SERVER['SERVER_ADMIN'] : null,
              'fakeaddressrecovery' => true,
              'broughtby' => null,
              'timezone' => 'UTC',
              'broughtbyurl' => null,
              'closed' => false,
              'inviteonly' => true,
              'private' => false,
              'ssl' => 'never',
              'sslproxy' => false,   // set to true to force GNU social to think it is HTTPS (i.e. using reverse proxy to enable it)
              'sslserver' => null,
              'dupelimit' => 60, // default for same person saying the same thing
              'textlimit' => 1000, // in chars; 0 == no limit
              'indent' => true,
              'use_x_sendfile' => false,
              'notice' => null, // site wide notice text
              'build' => 1, // build number, for code-dependent cache
              ),
        'db' =>
          array('database' => null, // must be set
              'schema_location' => INSTALLDIR . '/classes',
              'class_location' => INSTALLDIR . '/classes',
              'require_prefix' => 'classes/',
              'class_prefix' => '',
              'mirror' => null,
              'utf8' => true,
              'db_driver' => 'DB', # XXX: JanRain libs only work with DB
              'quote_identifiers' => false,
              'type' => 'mysql',
              'schemacheck' => 'runtime', // 'runtime' or 'script'
              'annotate_queries' => false, // true to add caller comments to queries, eg /* POST Notice::saveNew */
              'log_queries' => false, // true to log all DB queries
              'log_slow_queries' => 0, // if set, log queries taking over N seconds
              'mysql_foreign_keys' => false), // if set, enables experimental foreign key support on MySQL
        'fix' =>
        array('fancyurls' => true,   // makes sure aliases in WebFinger etc. are not f'd by index.php/ URLs
              ),
        'syslog' =>
        array('appname' => 'statusnet', # for syslog
              'priority' => 'debug', # XXX: currently ignored
              'facility' => LOG_USER),
        'queue' =>
        array('enabled' => true,
              'daemon' => false, # Use queuedaemon. Default to false
              'subsystem' => 'db', # default to database, or 'stomp'
              'stomp_server' => null,
              'queue_basename' => '/queue/statusnet/',
              'control_channel' => '/topic/statusnet/control', // broadcasts to all queue daemons
              'stomp_username' => null,
              'stomp_password' => null,
              'stomp_persistent' => true, // keep items across queue server restart, if persistence is enabled
              'stomp_transactions' => true, // use STOMP transactions to aid in detecting failures (supported by ActiveMQ, but not by all)
              'stomp_acks' => true, // send acknowledgements after successful processing (supported by ActiveMQ, but not by all)
              'stomp_manual_failover' => true, // if multiple servers are listed, treat them as separate (enqueue on one randomly, listen on all)
              'monitor' => null, // URL to monitor ping endpoint (work in progress)
              'softlimit' => '90%', // total size or % of memory_limit at which to restart queue threads gracefully
              'spawndelay' => 1, // Wait at least N seconds between (re)spawns of child processes to avoid slamming the queue server with subscription startup
              'debug_memory' => false, // true to spit memory usage to log
              'breakout' => array(), // List queue specifiers to break out when using Stomp queue.
                                     // Default will share all queues for all sites within each group.
                                     // Specify as <group>/<queue> or <group>/<queue>/<site>,
                                     // using nickname identifier as site.
                                     //
                                     // 'main/distrib' separate "distrib" queue covering all sites
                                     // 'xmpp/xmppout/mysite' separate "xmppout" queue covering just 'mysite'
              'max_retries' => 10, // drop messages after N failed attempts to process (Stomp)
              'dead_letter_dir' => false, // set to directory to save dropped messages into (Stomp)
              ),
        'license' =>
        array('type' => 'cc', # can be 'cc', 'allrightsreserved', 'private'
              'owner' => null, # can be name of content owner e.g. for enterprise
              'url' => 'https://creativecommons.org/licenses/by/3.0/',
              'title' => 'Creative Commons Attribution 3.0',
              'image' => $_path . '/theme/licenses/cc_by_3.0_80x15.png'),
        'mail' =>
        array('backend' => 'mail',
              'params' => null,
              'domain_check' => true),
        'nickname' =>
        array('blacklist' => array(),
              'featured' => array()),
        'profile' =>
        array('banned' => array(),
              'biolimit' => null,
              'changenick' => false,
              'allowprivate' => false,  // whether to allow setting stream to private ("only followers can read")
              'backup' => false,    // can cause DoS, so should be done via CLI
              'restore' => false,
              'delete' => false,
              'move' => true),
        'image' =>
        array('jpegquality' => 85),
        'avatar' =>
        array('server' => null,
              'dir' => INSTALLDIR . '/avatar/',
              'path' => $_path . '/avatar/',
              'ssl' => null,
              'maxsize' => 300),
        'foaf' =>
        array(
              'mbox_sha1sum' => false,
            ),
        'public' =>
        array('localonly' => false,
              'blacklist' => array(),
              'autosource' => array()),
        'theme' =>
        array('server' => null,
              'dir' => null,
              'path'=> null,
              'ssl' => null),
        'usertheme' =>
        array('linkcolor' => 'black',
              'backgroundcolor' => 'black'),
        'theme_upload' =>
        array('enabled' => extension_loaded('zip')),
        'javascript' =>
        array('server' => null,
              'path'=> null,
              'ssl' => null,
              'bustframes' => true),
        'local' => // To override path/server for themes in 'local' dir (not currently applied to local plugins)
        array('server' => null,
              'dir' => null,
              'path' => null,
              'ssl' => null),
        'throttle' =>
        array('enabled' => false, // whether to throttle edits; false by default
              'count' => 20, // number of allowed messages in timespan
              'timespan' => 600), // timespan for throttling
        'invite' =>
        array('enabled' => true),
        'tag' =>
        array('dropoff' => 864000.0,   # controls weighting based on age
              'cutoff' => 86400 * 90), # only look at notices posted in last 90 days
        'popular' =>
        array('dropoff' => 864000.0,   # controls weighting based on age
              'cutoff' => 86400 * 90), # only look at notices favorited in last 90 days
        'daemon' =>
        array('piddir' => sys_get_temp_dir(),
              'user' => false,
              'group' => false),
        'emailpost' =>
        array('enabled' => false),
        'sms' =>
        array('enabled' => false),
        'twitterimport' =>
        array('enabled' => false),
        'integration' =>
        array('source' => 'StatusNet', # source attribute for Twitter
              'taguri' => null), # base for tag URIs
        'twitter' =>
        array('signin' => true,
              'consumer_key' => null,
              'consumer_secret' => null),
        'cache' =>
        array('base' => null),
        'ping' =>
        array('notify' => array(),
              'timeout' => 2),
        'inboxes' =>
        array('enabled' => true), # ignored after 0.9.x
        'newuser' =>
        array('default' => null,
              'welcome' => null),
        'linkify' => array(
            // "bare" below means "without schema", like domain.com vs. https://domain.com
            'bare_domains' => false,  // convert domain.com to domain.com ?
            'bare_ipv4' => false,   // convert IPv4 addresses to hyperlinks?
            'bare_ipv6' => false,   // convert IPv6 addresses to hyperlinks?
        ),
        'attachments' =>
        array('server' => null,
              'dir' => INSTALLDIR . '/file/',
              'path' => $_path . '/file/',
              'sslserver' => null,
              'sslpath' => null,
              'ssl' => null,
              'supported' => array(
                                'application/vnd.oasis.opendocument.chart'                  => 'odc',
                                'application/vnd.oasis.opendocument.formula'                => 'odf',
                                'application/vnd.oasis.opendocument.graphics'               => 'odg',
                                'application/vnd.oasis.opendocument.graphics-template'      => 'otg',
                                'application/vnd.oasis.opendocument.image'                  => 'odi',
                                'application/vnd.oasis.opendocument.presentation'           => 'odp',
                                'application/vnd.oasis.opendocument.presentation-template'  => 'otp',
                                'application/vnd.oasis.opendocument.spreadsheet'            => 'ods',
                                'application/vnd.oasis.opendocument.spreadsheet-template'   => 'ots',
                                'application/vnd.oasis.opendocument.text'                   => 'odt',
                                'application/vnd.oasis.opendocument.text-master'            => 'odm',
                                'application/vnd.oasis.opendocument.text-template'          => 'ott',
                                'application/vnd.oasis.opendocument.text-web'               => 'oth',
                                'application/pdf'   => 'pdf',
                                'application/zip'   => 'zip',
                                'application/xml'   => 'xml',
                                'image/png'         => 'png',
                                'image/jpeg'        => 'jpg',
                                'image/gif'         => 'gif',
                                'image/svg+xml'     => 'svg',
                                'image/vnd.microsoft.icon'  => 'ico',
                                'audio/ogg'         => 'ogg',
                                'audio/mpeg'        => 'mpg',
                                'audio/x-speex'     => 'spx',
                                'application/ogg'   => 'ogx',
                                'text/plain'        => 'txt',
                                'video/mpeg'        => 'mpeg',
                                'video/mp4'         => 'mp4',
                                'video/ogg'         => 'ogv',
                                'video/quicktime'   => 'mov',
                                'video/webm'        => 'webm',
                                ),
              'file_quota' => 5000000,
              'user_quota' => 50000000,
              'monthly_quota' => 15000000,
              'uploads' => true,
              'filename_base' => 'hash',   // for new files, choose one: 'upload', 'hash'
              'show_html' => false,  // show (filtered) text/html attachments (and oEmbed HTML etc.). Doesn't affect AJAX calls.
              'show_thumbs' => true, // show thumbnails in notice lists for uploaded images, and photos and videos linked remotely that provide oEmbed info
              'process_links' => true, // check linked resources for embeddable photos and videos; this will hit referenced external web sites when processing new messages.
              ),
        'thumbnail' =>
        array('crop' => false,      // overridden to true if thumb height === null
              'maxsize' => 1000,     // thumbs with an edge larger than this will not be generated
              'width' => 450,
              'height' => 600,
              'upscale' => false,
              'animated' => false), // null="UseFileAsThumbnail", false="can use still frame". true requires ImageMagickPlugin
        'application' =>
        array('desclimit' => null),
        'group' =>
        array('maxaliases' => 3,
              'desclimit' => null,
              'addtag' => false),
        'peopletag' =>
        array('maxtags' => 100, // maximum number of tags a user can create.
              'maxpeople' => 500, // maximum no. of people with the same tag by the same user
              'allow_tagging' => array('all' => true), // equivalent to array('local' => true, 'remote' => true)
              'desclimit' => null),
        'search' =>
        array('type' => 'like'),
        'sessions' =>
        array('handle' => false,   // whether to handle sessions ourselves
              'debug' => false,    // debugging output for sessions
              'gc_limit' => 1000), // max sessions to expire at a time
        'htmlfilter' => array(  // purify HTML through HTMLPurifier
            'img' => true,
            'video' => true,
            'audio' => true,
        ),
        'notice' =>
        array('contentlimit' => null,
              'allowprivate' => false,  // whether to allow users to "check the padlock" to publish notices available for their subscribers.
              'defaultscope' => null, // null means 1 if site/private, 0 otherwise
              'hidespam' => true), // Whether to hide silenced users from timelines
        'message' =>
        array('contentlimit' => null),
        'location' =>
        array('share' => 'user', // whether to share location; 'always', 'user', 'never'
              'sharedefault' => false),
        'logincommand' =>
        array('disabled' => true),
        'plugins' =>
        array('core' => array(
                            'ActivityVerb' => array(),
                            'ActivityVerbPost' => array(),
                            'ActivityModeration' => array(),
                            'AuthCrypt' => array(),
                            'Cronish' => array(),
                            'Favorite' => array(),
                            'HTMLPurifierSchemes' => array(),
                            'Share' => array(),
                            'LRDD' => array(),
                        ),
              'default' => array(
                            'Activity' => array(),
                            'AntiBrute' => array(),
                            'Bookmark' => array(),
                            'ClientSideShorten' => array(),
                            'DefaultLayout' => array(),
                            'Directory' => array(),
                            'DirectMessage' => array(),
                            'EmailAuthentication' => array(),
                            'Event' => array(),
                            'Oembed' => array(),
                            'OpenID' => array(),
                            'OpportunisticQM' => array(),
                            'OStatus' => array(),
                            'Poll' => array(),
                            'SearchSub' => array(),
                            'SimpleCaptcha' => array(),
                            'TagSub' => array(),
                            'WebFinger' => array(),
                        ),
              'locale_path' => false, // Set to a path to use *instead of* each plugin's own locale subdirectories
              'server' => null,
              'sslserver' => null,
              'path' => null,
              'sslpath' => null,
              ),
        'admin' =>
        array('panels' => array('site', 'user', 'paths', 'access', 'sessions', 'sitenotice', 'license', 'plugins')),
        'singleuser' =>
        array('enabled' => false,
              'nickname' => null),
        'robotstxt' =>
        array('crawldelay' => 0,
              'disallow' => array('main', 'settings', 'admin', 'search', 'message')
              ),
        'api' =>
        array('realm' => null),
        'nofollow' =>
        array('subscribers' => true,
              'members' => true,
              'peopletag' => true,
              'external' => 'sometimes'), // Options: 'sometimes', 'never', default = 'sometimes'
        'url' =>
        array('shortener' => 'internal',
              'maxurllength' => 100,
              'maxnoticelength' => -1),
        'http' => // HTTP client settings when contacting other sites
        array('ssl_cafile' => false, // To enable SSL cert validation, point to a CA bundle (eg '/usr/lib/ssl/certs/ca-certificates.crt') (this activates "ssl_verify_peer")
              'ssl_verify_host' => true,    // HTTPRequest2 makes sure this is set to CURLOPT_SSL_VERIFYHOST==2 if using curl
              'curl' => false, // Use CURL backend for HTTP fetches if available. (If not, PHP's socket streams will be used.)
              'connect_timeout' => 5,
              'proxy_host' => null,
              'proxy_port' => null,
              'proxy_user' => null,
              'proxy_password' => null,
              'proxy_auth_scheme' => null,
              ),
        'router' =>
        array('cache' => true), // whether to cache the router object. Defaults to true, turn off for devel
        'discovery' =>
          array('cors' => false), // Allow Cross-Origin Resource Sharing for service discovery (host-meta, XRD, etc.)
        'performance' => array('high' => false) // disable some features for higher performance; default false
    );


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

/**
 * Default menu
 *
 * @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/
 */
class DefaultLocalNav extends Menu
{
    function show()
    {
        $user = common_current_user();

        $this->action->elementStart('ul', array('id' => 'nav_local_default'));

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

            if (!empty($user)) {
                $pn = new PersonalGroupNav($this->action);
                // TRANS: Menu item in default local navigation panel.
                $this->submenu(_m('MENU','Home'), $pn);
            }

            $bn = new PublicGroupNav($this->action);
            // TRANS: Menu item in default local navigation panel.
            $this->submenu(_m('MENU','Public'), $bn);

            if (!empty($user)) {
                $sn = new GroupsNav($this->action, $user);
                if ($sn->haveGroups()) {
                    // TRANS: Menu item in default local navigation panel.
                    $this->submenu(_m('MENU', 'Groups'), $sn);
                }
            }

            if (!empty($user)) {
                $sn = new ListsNav($this->action, $user->getProfile());
                if ($sn->hasLists()) {
                    // TRANS: Menu item in default local navigation panel.
                    $this->submenu(_m('MENU', 'Lists'), $sn);
                }
            }

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

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


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * Default profile block to show current user's info
 *
 * 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);
}

/**
 * Default profile block
 *
 * @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/
 */

class DefaultProfileBlock extends AccountProfileBlock
{
    function __construct($out)
    {
        $user = common_current_user();
        if (empty($user)) {
            throw new Exception("DefaultProfileBlock with no user.");
        }
        parent::__construct($out, $user->getProfile());
    }

    function location()
    {
        return null;
    }

    function homepage()
    {
        return null;
    }

    function description()
    {
        return null;
    }

    function otherProfiles()
    {
        return array();
    }
}


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

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

/**
 * Form for deleting a group
 *
 * @category Form
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @author   Sarven Capadisli <csarven@status.net>
 * @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      UnsubscribeForm
 * @fixme    merge a bunch of this stuff with similar form types to reduce boilerplate
 */
class DeleteGroupForm extends Form
{
    /**
     * group for user to delete
     */
    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-delete-' . $this->group->getID();
    }

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

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

    function formData()
    {
        $this->out->hidden($this->id() . '-returnto-action', 'groupbyid', 'returnto-action');
        $this->out->hidden($this->id() . '-returnto-id', $this->group->getID(), 'returnto-id');
    }

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