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

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

/**
 * Leave a group
 *
 * This is the action for leaving a group. It works more or less like the subscribe action
 * for users.
 *
 * @category Group
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class ApprovesubAction extends Action
{
    var $profile = null;

    /**
     * Prepare to run
     */
    function prepare($args)
    {
        parent::prepare($args);

        $cur = common_current_user();
        if (empty($cur)) {
            // TRANS: Client error displayed trying to approve group membership while not logged in.
            $this->clientError(_('Must be logged in.'), 403);
        }
        if ($this->arg('profile_id')) {
            $this->profile = Profile::getKV('id', $this->arg('profile_id'));
        } else {
            // TRANS: Client error displayed trying to approve subscriptionswithout specifying a profile to approve.
            $this->clientError(_('Must specify a profile.'));
        }

        $this->request = Subscription_queue::pkeyGet(array('subscriber' => $this->profile->id,
                                                           'subscribed' => $cur->id));

        if (empty($this->request)) {
            // TRANS: Client error displayed trying to approve subscription for a non-existing request.
            // TRANS: %s is a user nickname.
            $this->clientError(sprintf(_('%s is not in the moderation queue for your subscriptions.'), $this->profile->nickname), 403);
        }

        $this->approve = (bool)$this->arg('approve');
        $this->cancel = (bool)$this->arg('cancel');
        if (!$this->approve && !$this->cancel) {
            // TRANS: Client error displayed trying to approve/deny subscription.
            $this->clientError(_('Internal error: received neither cancel nor abort.'));
        }
        if ($this->approve && $this->cancel) {
            // TRANS: Client error displayed trying to approve/deny  subscription
            $this->clientError(_('Internal error: received both cancel and abort.'));
        }
        return true;
    }

    /**
     * Handle the request
     *
     * On POST, add the current user to the group
     *
     * @param array $args unused
     *
     * @return void
     */
    function handle($args)
    {
        parent::handle($args);
        $cur = common_current_user();

        try {
            if ($this->approve) {
                $this->request->complete();
            } elseif ($this->cancel) {
                $this->request->abort();
            }
        } catch (Exception $e) {
            common_log(LOG_ERR, "Exception canceling sub: " . $e->getMessage());
            // TRANS: Server error displayed when cancelling a queued subscription request fails.
            // TRANS: %1$s is the leaving user's nickname, $2$s is the nickname for which the leave failed.
            $this->serverError(sprintf(_('Could not cancel or approve request for user %1$s to join group %2$s.'),
                                       $this->profile->nickname, $cur->nickname));
            return;
        }

        if ($this->boolean('ajax')) {
            $this->startHTML('text/xml;charset=utf-8');
            $this->elementStart('head');
            // TRANS: Title for subscription approval ajax return
            // TRANS: %1$s is the approved user's nickname
            $this->element('title', null, sprintf(_m('TITLE','%1$s\'s request'),
                                                  $this->profile->nickname));
            $this->elementEnd('head');
            $this->elementStart('body');
            if ($this->approve) {
                // TRANS: Message on page for user after approving a subscription request.
                $this->element('p', 'success', _('Subscription approved.'));
            } elseif ($this->cancel) {
                // TRANS: Message on page for user after rejecting a subscription request.
                $this->element('p', 'success', _('Subscription canceled.'));
            }
            $this->elementEnd('body');
            $this->endHTML();
        } else {
            common_redirect(common_local_url('subqueue', array('nickname' =>
                                                               $cur->nickname)),
                            303);
        }
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2010, StatusNet, Inc.
 *
 * Feed of group memberships for a user, in ActivityStreams format
 *
 * 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  AtomPub
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

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

/**
 * Feed of group memberships for a user, in ActivityStreams format
 *
 * @category  Action
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */
class AtompubmembershipfeedAction extends AtompubAction
{
    private $_profile     = null;
    private $_memberships = null;

    protected function atompubPrepare()
    {
        $this->_profile = Profile::getKV('id', $this->trimmed('profile'));

        if (!$this->_profile instanceof Profile) {
            // TRANS: Client exception.
            throw new ClientException(_('No such profile.'), 404);
        }

        $this->_memberships = Group_member::byMember($this->_profile->id,
                                                     $this->offset,
                                                     $this->limit);
        return true;
    }

    protected function handleGet()
    {
        return $this->showFeed();
    }

    protected function handlePost()
    {
        return $this->addMembership();
    }

    /**
     * Show a feed of favorite activity streams objects
     *
     * @return void
     */
    function showFeed()
    {
        header('Content-Type: application/atom+xml; charset=utf-8');

        $url = common_local_url('AtomPubMembershipFeed',
                                array('profile' => $this->_profile->id));

        $feed = new Atom10Feed(true);

        $feed->addNamespace('activity',
                            'http://activitystrea.ms/spec/1.0/');

        $feed->addNamespace('poco',
                            'http://portablecontacts.net/spec/1.0');

        $feed->addNamespace('media',
                            'http://purl.org/syndication/atommedia');

        $feed->id = $url;

        $feed->setUpdated('now');

        $feed->addAuthor($this->_profile->getBestName(),
                         $this->_profile->getURI());

        // TRANS: Title for group membership feed.
        // TRANS: %s is a username.
        $feed->setTitle(sprintf(_('Group memberships of %s'),
                                $this->_profile->getBestName()));

        // TRANS: Subtitle for group membership feed.
        // TRANS: %1$s is a username, %2$s is the StatusNet sitename.
        $feed->setSubtitle(sprintf(_('Groups %1$s is a member of on %2$s'),
                                   $this->_profile->getBestName(),
                                   common_config('site', 'name')));

        $feed->addLink(common_local_url('usergroups',
                                        array('nickname' =>
                                              $this->_profile->nickname)));

        $feed->addLink($url,
                       array('rel' => 'self',
                             'type' => 'application/atom+xml'));

        // If there's more...

        if ($this->page > 1) {
            $feed->addLink($url,
                           array('rel' => 'first',
                                 'type' => 'application/atom+xml'));

            $feed->addLink(common_local_url('AtomPubMembershipFeed',
                                            array('profile' =>
                                                  $this->_profile->id),
                                            array('page' =>
                                                  $this->page - 1)),
                           array('rel' => 'prev',
                                 'type' => 'application/atom+xml'));
        }

        if ($this->_memberships->N > $this->count) {

            $feed->addLink(common_local_url('AtomPubMembershipFeed',
                                            array('profile' =>
                                                  $this->_profile->id),
                                            array('page' =>
                                                  $this->page + 1)),
                           array('rel' => 'next',
                                 'type' => 'application/atom+xml'));
        }

        $i = 0;

        while ($this->_memberships->fetch()) {

            // We get one more than needed; skip that one

            $i++;

            if ($i > $this->count) {
                break;
            }

            $act = $this->_memberships->asActivity();
            $feed->addEntryRaw($act->asString(false, false, false));
        }

        $this->raw($feed->getString());
    }

    /**
     * add a new favorite
     *
     * @return void
     */
    function addMembership()
    {
        // XXX: Refactor this; all the same for atompub

        if (empty($this->auth_user) ||
            $this->auth_user->id != $this->_profile->id) {
            // TRANS: Client exception thrown when trying subscribe someone else to a group.
            throw new ClientException(_("Cannot add someone else's".
                                        " membership."), 403);
        }

        $xml = file_get_contents('php://input');

        $dom = DOMDocument::loadXML($xml);

        if ($dom->documentElement->namespaceURI != Activity::ATOM ||
            $dom->documentElement->localName != 'entry') {
            // TRANS: Client error displayed when not using an Atom entry.
            throw new ClientException(_('Atom post must be an Atom entry.'));
            return;
        }

        $activity = new Activity($dom->documentElement);

        $membership = null;

        if (Event::handle('StartAtomPubNewActivity', array(&$activity))) {
            if ($activity->verb != ActivityVerb::JOIN) {
                // TRANS: Client error displayed when not using the join verb.
                throw new ClientException(_('Can only handle join activities.'));
            }

            $groupObj = $activity->objects[0];

            if ($groupObj->type != ActivityObject::GROUP) {
                // TRANS: Client exception thrown when trying to join something which is not a group
                throw new ClientException(_('Can only join groups.'));
            }

            $group = User_group::getKV('uri', $groupObj->id);

            if (empty($group)) {
                // XXX: import from listed URL or something
                // TRANS: Client exception thrown when trying to subscribe to a non-existing group.
                throw new ClientException(_('Unknown group.'));
            }

            $old = Group_member::pkeyGet(array('profile_id' => $this->auth_user->id,
                                               'group_id' => $group->id));

            if (!empty($old)) {
                // TRANS: Client exception thrown when trying to subscribe to an already subscribed group.
                throw new ClientException(_('Already a member.'));
            }

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

            if (Group_block::isBlocked($group, $profile)) {
                // XXX: import from listed URL or something
                // TRANS: Client exception thrown when trying to subscribe to group while blocked from that group.
                throw new ClientException(_('Blocked by admin.'));
            }

            $this->auth_user->joinGroup($group);

            Event::handle('EndAtomPubNewActivity', array($activity, $membership));
        }

        if (!empty($membership)) {
            $act = $membership->asActivity();

            header('Content-Type: application/atom+xml; charset=utf-8');
            header('Content-Location: ' . $act->selfLink);

            $this->startXML();
            $this->raw($act->asString(true, true, true));
            $this->endXML();
        }
    }

    /**
     * Return last modified, if applicable.
     *
     * MAY override
     *
     * @return string last modified http header
     */
    function lastModified()
    {
        // For comparison with If-Last-Modified
        // If not applicable, return null
        return null;
    }

    /**
     * Return etag, if applicable.
     *
     * MAY override
     *
     * @return string etag http header
     */
    function etag()
    {
        return null;
    }
}

repo_name: piratas/tortuga

license: mit


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2010, StatusNet, Inc.
 *
 * Show a single membership as an Activity Streams entry
 *
 * 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  AtomPub
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

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

/**
 * Show (or delete) a single membership event as an ActivityStreams entry
 *
 * @category  AtomPub
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */
class AtompubshowmembershipAction extends AtompubAction
{
    private $_private    = null;
    private $_group      = null;
    private $_membership = null;

    protected function atompubPrepare()
    {
        $this->_profile = Profile::getKV('id', $this->trimmed('profile'));

        if (!$this->_profile instanceof Profile) {
            // TRANS: Client exception.
            throw new ClientException(_('No such profile.'), 404);
        }

        $this->_group = User_group::getKV('id', $this->trimmed('group'));

        if (!$this->_group instanceof User_group) {
            // TRANS: Client exception thrown when referencing a non-existing group.
            throw new ClientException(_('No such group.'), 404);
        }

        $kv = array('group_id' => $groupId,
                    'profile_id' => $this->_profile->id);

        $this->_membership = Group_member::pkeyGet($kv);

        if (!$this->_membership instanceof Group_member) {
            // TRANS: Client exception thrown when trying to show membership of a non-subscribed group
            throw new ClientException(_('Not a member.'), 404);
        }

        return true;
    }

    protected function handleGet() {
        return $this->showMembership();
    }

    protected function handleDelete() {
        return $this->deleteMembership();
    }

    /**
     * show a single membership
     *
     * @return void
     */
    function showMembership()
    {
        $activity = $this->_membership->asActivity();

        header('Content-Type: application/atom+xml; charset=utf-8');

        $this->startXML();
        $this->raw($activity->asString(true, true, true));
        $this->endXML();

        return;
    }

    /**
     * Delete the membership (leave the group)
     *
     * @return void
     */
    function deleteMembership()
    {
        if (empty($this->auth_user) ||
            $this->auth_user->id != $this->_profile->id) {
            // TRANS: Client exception thrown when deleting someone else's membership.
            throw new ClientException(_("Cannot delete someone else's".
                                        " membership."), 403);
        }

        $this->auth_user->leaveGroup($this->_group);

        return;
    }

    /**
     * Return last modified, if applicable.
     *
     * Because the representation depends on the profile and group,
     * our last modified value is the maximum of their mod time
     * with the actual membership's mod time.
     *
     * @return string last modified http header
     */
    function lastModified()
    {
        return max(strtotime($this->_profile->modified),
                   strtotime($this->_group->modified),
                   strtotime($this->_membership->modified));
    }

    /**
     * Return etag, if applicable.
     *
     * A "weak" Etag including the profile and group id as well as
     * the admin flag and ctime of the membership.
     *
     * @return string etag http header
     */
    function etag()
    {
        $ctime = strtotime($this->_membership->created);

        $adminflag = ($this->_membership->is_admin) ? 't' : 'f';

        return 'W/"' . implode(':', array('AtomPubShowMembership',
                                          $this->_profile->id,
                                          $this->_group->id,
                                          $adminflag,
                                          $ctime)) . '"';
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2010, StatusNet, Inc.
 *
 * Single subscription
 *
 * 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  AtomPub
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

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

/**
 * Show a single subscription
 *
 * @category  AtomPub
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */
class AtompubshowsubscriptionAction extends AtompubAction
{
    private $_subscriber   = null;
    private $_subscribed   = null;
    private $_subscription = null;

    protected function atompubPrepare()
    {
        $subscriberId = $this->trimmed('subscriber');

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

        if (!$this->_subscriber instanceof Profile) {
            // TRANS: Client exception thrown when trying to display a subscription for a non-existing profile ID.
            // TRANS: %d is the non-existing profile ID number.
            throw new ClientException(sprintf(_('No such profile id: %d.'),
                                              $subscriberId), 404);
        }

        $subscribedId = $this->trimmed('subscribed');

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

        if (!$this->_subscribed instanceof Profile) {
            // TRANS: Client exception thrown when trying to display a subscription for a non-existing profile ID.
            // TRANS: %d is the non-existing profile ID number.
            throw new ClientException(sprintf(_('No such profile id: %d.'),
                                              $subscribedId), 404);
        }

        $this->_subscription = Subscription::pkeyGet(array('subscriber' => $subscriberId,
                                                           'subscribed' => $subscribedId));
        if (!$this->_subscription instanceof Subscription) {
            // TRANS: Client exception thrown when trying to display a subscription for a non-subscribed profile ID.
            // TRANS: %1$d is the non-existing subscriber ID number, $2$d is the ID of the profile that was not subscribed to.
            $msg = sprintf(_('Profile %1$d not subscribed to profile %2$d.'),
                           $subscriberId, $subscribedId);
            throw new ClientException($msg, 404);
        }

        return true;
    }

    protected function handleGet()
    {
        $this->showSubscription();
    }

    protected function handleDelete()
    {
        $this->deleteSubscription();
    }

    /**
     * Show the subscription in ActivityStreams Atom format.
     *
     * @return void
     */
    function showSubscription()
    {
        $activity = $this->_subscription->asActivity();

        header('Content-Type: application/atom+xml; charset=utf-8');

        $this->startXML();
        $this->raw($activity->asString(true, true, true));
        $this->endXML();
    }

    /**
     * Delete the subscription
     *
     * @return void
     */
    function deleteSubscription()
    {
        if (!$this->scoped instanceof Profile ||
                $this->scoped->id != $this->_subscriber->id) {
            // TRANS: Client exception thrown when trying to delete a subscription of another user.
            throw new ClientException(_("Cannot delete someone else's subscription."), 403);
        }

        Subscription::cancel($this->_subscriber, $this->_subscribed);
    }

    /**
     * Is this action read only?
     *
     * @param array $args other arguments
     *
     * @return boolean true
     */
    function isReadOnly($args)
    {
        if ($_SERVER['REQUEST_METHOD'] == 'DELETE') {
            return false;
        }

        return true;
    }

    /**
     * Return last modified, if applicable.
     *
     * @return string last modified http header
     */
    function lastModified()
    {
        return max(strtotime($this->_subscriber->modified),
                   strtotime($this->_subscribed->modified),
                   strtotime($this->_subscription->modified));
    }

    /**
     * Etag for this object
     *
     * @return string etag http header
     */
    function etag()
    {
        $mtime = strtotime($this->_subscription->modified);

        return 'W/"' . implode(':', array('AtomPubShowSubscription',
                                          $this->_subscriber->id,
                                          $this->_subscribed->id,
                                          $mtime)) . '"';
    }

    /**
     * Does this require authentication?
     *
     * @return boolean true if delete, else false
     */
    function requiresAuth()
    {
        if ($_SERVER['REQUEST_METHOD'] == 'DELETE') {
            return true;
        } else {
            return false;
        }
    }
}


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

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

/**
 * Subscription feed class for AtomPub
 *
 * Generates a list of the user's subscriptions
 *
 * @category  AtomPub
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */
class AtompubsubscriptionfeedAction extends AtompubAction
{
    private $_profile       = null;
    private $_subscriptions = null;

    protected function atompubPrepare()
    {
        $subscriber = $this->trimmed('subscriber');

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

        if (!$this->_profile instanceof Profile) {
            // TRANS: Client exception thrown when trying to display a subscription for a non-existing profile ID.
            // TRANS: %d is the non-existing profile ID number.
            throw new ClientException(sprintf(_('No such profile id: %d.'),
                                              $subscriber), 404);
        }

        $this->_subscriptions = Subscription::bySubscriber($this->_profile->id,
                                                           $this->offset,
                                                           $this->limit);

        return true;
    }

    protected function handleGet()
    {
        $this->showFeed();
    }

    protected function handlePost()
    {
        $this->addSubscription();
    }

    /**
     * Show the feed of subscriptions
     *
     * @return void
     */
    function showFeed()
    {
        header('Content-Type: application/atom+xml; charset=utf-8');

        $url = common_local_url('AtomPubSubscriptionFeed',
                                array('subscriber' => $this->_profile->id));

        $feed = new Atom10Feed(true);

        $feed->addNamespace('activity',
                            'http://activitystrea.ms/spec/1.0/');

        $feed->addNamespace('poco',
                            'http://portablecontacts.net/spec/1.0');

        $feed->addNamespace('media',
                            'http://purl.org/syndication/atommedia');

        $feed->addNamespace('georss',
                            'http://www.georss.org/georss');

        $feed->id = $url;

        $feed->setUpdated('now');

        $feed->addAuthor($this->_profile->getBestName(),
                         $this->_profile->getURI());

        // TRANS: Title for Atom subscription feed.
        // TRANS: %s is a user nickname.
        $feed->setTitle(sprintf(_("%s subscriptions"),
                                $this->_profile->getBestName()));

        // TRANS: Subtitle for Atom subscription feed.
        // TRANS: %1$s is a user nickname, %s$s is the StatusNet sitename.
        $feed->setSubtitle(sprintf(_("People %1\$s has subscribed to on %2\$s"),
                                   $this->_profile->getBestName(),
                                   common_config('site', 'name')));

        $feed->addLink(common_local_url('subscriptions',
                                        array('nickname' =>
                                              $this->_profile->nickname)));

        $feed->addLink($url,
                       array('rel' => 'self',
                             'type' => 'application/atom+xml'));

        // If there's more...

        if ($this->page > 1) {
            $feed->addLink($url,
                           array('rel' => 'first',
                                 'type' => 'application/atom+xml'));

            $feed->addLink(common_local_url('AtomPubSubscriptionFeed',
                                            array('subscriber' =>
                                                  $this->_profile->id),
                                            array('page' =>
                                                  $this->page - 1)),
                           array('rel' => 'prev',
                                 'type' => 'application/atom+xml'));
        }

        if ($this->_subscriptions->N > $this->count) {

            $feed->addLink(common_local_url('AtomPubSubscriptionFeed',
                                            array('subscriber' =>
                                                  $this->_profile->id),
                                            array('page' =>
                                                  $this->page + 1)),
                           array('rel' => 'next',
                                 'type' => 'application/atom+xml'));
        }

        $i = 0;

        // XXX: This is kind of inefficient

        while ($this->_subscriptions->fetch()) {

            // We get one more than needed; skip that one

            $i++;

            if ($i > $this->count) {
                break;
            }

            $act = $this->_subscriptions->asActivity();
            $feed->addEntryRaw($act->asString(false, false, false));
        }

        $this->raw($feed->getString());
    }

    /**
     * Add a new subscription
     *
     * Handling the POST method for AtomPub
     *
     * @return void
     */
    function addSubscription()
    {
        if (empty($this->auth_user) ||
            $this->auth_user->id != $this->_profile->id) {
            // TRANS: Client exception thrown when trying to subscribe another user.
            throw new ClientException(_("Cannot add someone else's".
                                        " subscription."), 403);
        }

        $xml = file_get_contents('php://input');

        $dom = DOMDocument::loadXML($xml);

        if ($dom->documentElement->namespaceURI != Activity::ATOM ||
            $dom->documentElement->localName != 'entry') {
            // TRANS: Client error displayed when not using an Atom entry.
            $this->clientError(_('Atom post must be an Atom entry.'));
        }

        $activity = new Activity($dom->documentElement);

        $sub = null;

        if (Event::handle('StartAtomPubNewActivity', array(&$activity))) {

            if ($activity->verb != ActivityVerb::FOLLOW) {
                // TRANS: Client error displayed when not using the follow verb.
                $this->clientError(_('Can only handle Follow activities.'));
            }

            $person = $activity->objects[0];

            if ($person->type != ActivityObject::PERSON) {
                // TRANS: Client exception thrown when subscribing to an object that is not a person.
                $this->clientError(_('Can only follow people.'));
            }

            // XXX: OStatus discovery (maybe)
            try {
                $profile = Profile::fromUri($person->id);
            } catch (UnknownUriException $e) {
                // TRANS: Client exception thrown when subscribing to a non-existing profile.
                // TRANS: %s is the unknown profile ID.
                $this->clientError(sprintf(_('Unknown profile %s.'), $person->id));
            }

            try {
                $sub = Subscription::start($this->_profile, $profile);
            } catch (AlreadyFulfilledException $e) {
                // 409 Conflict
                $this->clientError($e->getMessage(), 409);
            }

            Event::handle('EndAtomPubNewActivity', array($activity, $sub));
        }

        if (!empty($sub)) {
            $act = $sub->asActivity();

            header('Content-Type: application/atom+xml; charset=utf-8');
            header('Content-Location: ' . $act->selfLink);

            $this->startXML();
            $this->raw($act->asString(true, true, true));
            $this->endXML();
        }
    }
}


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

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

/**
 * Show notice attachments
 *
 * @category Personal
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class AttachmentAction extends ManagedAction
{
    /**
     * Attachment object to show
     */

    var $attachment = null;

    /**
     * Load attributes based on database arguments
     *
     * Loads all the DB stuff
     *
     * @param array $args $_REQUEST array
     *
     * @return success flag
     */

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

        if ($id = $this->trimmed('attachment')) {
            $this->attachment = File::getKV($id);
        }

        if (!$this->attachment instanceof File) {
            // TRANS: Client error displayed trying to get a non-existing attachment.
            $this->clientError(_('No such attachment.'), 404);
        }
        return true;
    }

    /**
     * Is this action read-only?
     *
     * @return boolean true
     */
    function isReadOnly($args)
    {
        return true;
    }

    /**
     * Title of the page
     *
     * @return string title of the page
     */
    function title()
    {
        $a = new Attachment($this->attachment);
        return $a->title();
    }

    public function showPage()
    {
        if (empty($this->attachment->filename)) {
            // if it's not a local file, gtfo
            common_redirect($this->attachment->url, 303);
        }

        parent::showPage();
    }

    /**
     * Fill the content area of the page
     *
     * Shows a single notice list item.
     *
     * @return void
     */
    function showContent()
    {
        $ali = new Attachment($this->attachment, $this);
        $cnt = $ali->show();
    }

    /**
     * Don't show page notice
     *
     * @return void
     */
    function showPageNoticeBlock()
    {
    }

    /**
     * Show aside: this attachments appears in what notices
     *
     * @return void
     */
    function showSections() {
        $ns = new AttachmentNoticeSection($this);
        $ns->show();
        if (!common_config('performance', 'high')) {
            $atcs = new AttachmentTagCloudSection($this);
            $atcs->show();
        }
    }
}


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

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

/**
 * Show notice attachments
 *
 * @category Personal
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class Attachment_thumbnailAction extends AttachmentAction
{
    protected $thumb_w = null;  // max width
    protected $thumb_h = null;  // max height
    protected $thumb_c = null;  // crop?

    protected function doPreparation()
    {
        parent::doPreparation();

        $this->thumb_w = $this->int('w');
        $this->thumb_h = $this->int('h');
        $this->thumb_c = $this->boolean('c');
    }

    public function showPage()
    {
        // Returns a File_thumbnail object or throws exception if not available
        try {
            $thumbnail = $this->attachment->getThumbnail($this->thumb_w, $this->thumb_h, $this->thumb_c);
        } catch (UseFileAsThumbnailException $e) {
            common_redirect($e->file->getUrl());
        }

        common_redirect(File_thumbnail::url($thumbnail->filename));
    }
}


code:
<?php
/**
 * Retrieve user avatar by nickname action class.
 *
 * PHP version 5
 *
 * @category Action
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @author   Robin Millette <millette@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('GNUSOCIAL')) { exit(1); }

/**
 * Retrieve user avatar by nickname action class.
 *
 * @category Action
 * @package  GNUsocial
 * @author   Evan Prodromou <evan@status.net>
 * @author   Robin Millette <millette@status.net>
 * @author   Mikael Nordfeldth <mmn@hethane.se>
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 * @link     http://www.gnu.org/software/social/
 */
class AvatarbynicknameAction extends Action
{
    /**
     * Class handler.
     *
     * @param array $args query arguments
     *
     * @return boolean false if nickname or user isn't found
     */
    protected function handle()
    {
        parent::handle();
        $nickname = $this->trimmed('nickname');
        if (!$nickname) {
            // TRANS: Client error displayed trying to get an avatar without providing a nickname.
            $this->clientError(_('No nickname.'));
        }
        $size = $this->trimmed('size') ?: 'original';

        $user = User::getKV('nickname', $nickname);
        if (!$user) {
            // TRANS: Client error displayed trying to get an avatar for a non-existing user.
            $this->clientError(_('No such user.'));
        }
        $profile = $user->getProfile();
        if (!$profile) {
            // TRANS: Error message displayed when referring to a user without a profile.
            $this->clientError(_('User has no profile.'));
        }

        if ($size === 'original') {
            try {
                $avatar = Avatar::getUploaded($profile);
                $url = $avatar->displayUrl();
            } catch (NoAvatarException $e) {
                $url = Avatar::defaultImage(AVATAR_PROFILE_SIZE);
            }
        } else {
            $url = $profile->avatarUrl($size);
        }

        common_redirect($url, 302);
    }

    function isReadOnly($args)
    {
        return true;
    }
}


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

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

/**
 * Upload an avatar
 *
 * We use jCrop plugin for jQuery to crop the image after upload.
 *
 * @category Settings
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @author   Zach Copley <zach@status.net>
 * @author   Sarven Capadisli <csarven@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class AvatarsettingsAction extends SettingsAction
{
    var $mode = null;
    var $imagefile = null;
    var $filename = null;

    /**
     * Title of the page
     *
     * @return string Title of the page
     */
    function title()
    {
        // TRANS: Title for avatar upload page.
        return _('Avatar');
    }

    /**
     * Instructions for use
     *
     * @return instructions for use
     */
    function getInstructions()
    {
        // TRANS: Instruction for avatar upload page.
        // TRANS: %s is the maximum file size, for example "500b", "10kB" or "2MB".
        return sprintf(_('You can upload your personal avatar. The maximum file size is %s.'),
                       ImageFile::maxFileSize());
    }

    /**
     * Content area of the page
     *
     * Shows a form for uploading an avatar.
     *
     * @return void
     */

    function showContent()
    {
        if ($this->mode == 'crop') {
            $this->showCropForm();
        } else {
            $this->showUploadForm();
        }
    }

    function showUploadForm()
    {
        $user = common_current_user();

        $profile = $user->getProfile();

        if (!$profile) {
            common_log_db_error($user, 'SELECT', __FILE__);
            // TRANS: Error message displayed when referring to a user without a profile.
            $this->serverError(_('User has no profile.'));
        }

        $this->elementStart('form', array('enctype' => 'multipart/form-data',
                                          'method' => 'post',
                                          'id' => 'form_settings_avatar',
                                          'class' => 'form_settings',
                                          'action' =>
                                          common_local_url('avatarsettings')));
        $this->elementStart('fieldset');
        // TRANS: Avatar upload page form legend.
        $this->element('legend', null, _('Avatar settings'));
        $this->hidden('token', common_session_token());

        if (Event::handle('StartAvatarFormData', array($this))) {
            $this->elementStart('ul', 'form_data');
            try {
                $original = Avatar::getUploaded($profile);

                $this->elementStart('li', array('id' => 'avatar_original',
                                                'class' => 'avatar_view'));
                // TRANS: Header on avatar upload page for thumbnail of originally uploaded avatar (h2).
                $this->element('h2', null, _("Original"));
                $this->elementStart('div', array('id'=>'avatar_original_view'));
                $this->element('img', array('src' => $original->displayUrl(),
                                            'width' => $original->width,
                                            'height' => $original->height,
                                            'alt' => $user->nickname));
                $this->elementEnd('div');
                $this->elementEnd('li');
            } catch (NoAvatarException $e) {
                // No original avatar found!
            }

            try {
                $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
                $this->elementStart('li', array('id' => 'avatar_preview',
                                                'class' => 'avatar_view'));
                // TRANS: Header on avatar upload page for thumbnail of to be used rendition of uploaded avatar (h2).
                $this->element('h2', null, _("Preview"));
                $this->elementStart('div', array('id'=>'avatar_preview_view'));
                $this->element('img', array('src' => $avatar->displayUrl(),
                                            'width' => AVATAR_PROFILE_SIZE,
                                            'height' => AVATAR_PROFILE_SIZE,
                                            'alt' => $user->nickname));
                $this->elementEnd('div');
                if (!empty($avatar->filename)) {
                    // TRANS: Button on avatar upload page to delete current avatar.
                    $this->submit('delete', _m('BUTTON','Delete'));
                }
                $this->elementEnd('li');
            } catch (NoAvatarException $e) {
                // No previously uploaded avatar to preview.
            }

            $this->elementStart('li', array ('id' => 'settings_attach'));
            $this->element('input', array('name' => 'MAX_FILE_SIZE',
                                          'type' => 'hidden',
                                          'id' => 'MAX_FILE_SIZE',
                                          'value' => ImageFile::maxFileSizeInt()));
            $this->element('input', array('name' => 'avatarfile',
                                          'type' => 'file',
                                          'id' => 'avatarfile'));
            $this->elementEnd('li');
            $this->elementEnd('ul');

            $this->elementStart('ul', 'form_actions');
            $this->elementStart('li');
                // TRANS: Button on avatar upload page to upload an avatar.
            $this->submit('upload', _m('BUTTON','Upload'));
            $this->elementEnd('li');
            $this->elementEnd('ul');
        }
        Event::handle('EndAvatarFormData', array($this));

        $this->elementEnd('fieldset');
        $this->elementEnd('form');
    }

    function showCropForm()
    {
        $user = common_current_user();

        $profile = $user->getProfile();

        if (!$profile) {
            common_log_db_error($user, 'SELECT', __FILE__);
            // TRANS: Error message displayed when referring to a user without a profile.
            $this->serverError(_('User has no profile.'));
        }

        $this->elementStart('form', array('method' => 'post',
                                          'id' => 'form_settings_avatar',
                                          'class' => 'form_settings',
                                          'action' =>
                                          common_local_url('avatarsettings')));
        $this->elementStart('fieldset');
        // TRANS: Avatar upload page crop form legend.
        $this->element('legend', null, _('Avatar settings'));
        $this->hidden('token', common_session_token());

        $this->elementStart('ul', 'form_data');

        $this->elementStart('li',
                            array('id' => 'avatar_original',
                                  'class' => 'avatar_view'));
        // TRANS: Header on avatar upload crop form for thumbnail of originally uploaded avatar (h2).
        $this->element('h2', null, _('Original'));
        $this->elementStart('div', array('id'=>'avatar_original_view'));
        $this->element('img', array('src' => Avatar::url($this->filedata['filename']),
                                    'width' => $this->filedata['width'],
                                    'height' => $this->filedata['height'],
                                    'alt' => $user->nickname));
        $this->elementEnd('div');
        $this->elementEnd('li');

        $this->elementStart('li',
                            array('id' => 'avatar_preview',
                                  'class' => 'avatar_view'));
        // TRANS: Header on avatar upload crop form for thumbnail of to be used rendition of uploaded avatar (h2).
        $this->element('h2', null, _('Preview'));
        $this->elementStart('div', array('id'=>'avatar_preview_view'));
        $this->element('img', array('src' => Avatar::url($this->filedata['filename']),
                                    'width' => AVATAR_PROFILE_SIZE,
                                    'height' => AVATAR_PROFILE_SIZE,
                                    'alt' => $user->nickname));
        $this->elementEnd('div');

        foreach (array('avatar_crop_x', 'avatar_crop_y',
                       'avatar_crop_w', 'avatar_crop_h') as $crop_info) {
            $this->element('input', array('name' => $crop_info,
                                          'type' => 'hidden',
                                          'id' => $crop_info));
        }

        // TRANS: Button on avatar upload crop form to confirm a selected crop as avatar.
        $this->submit('crop', _m('BUTTON','Crop'));

        $this->elementEnd('li');
        $this->elementEnd('ul');
        $this->elementEnd('fieldset');
        $this->elementEnd('form');
    }

    /**
     * Handle a post
     *
     * We mux on the button name to figure out what the user actually wanted.
     *
     * @return void
     */
    function handlePost()
    {
        // Workaround for PHP returning empty $_POST and $_FILES when POST
        // length > post_max_size in php.ini

        if (empty($_FILES)
            && empty($_POST)
            && ($_SERVER['CONTENT_LENGTH'] > 0)
        ) {
            // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
            // TRANS: %s is the number of bytes of the CONTENT_LENGTH.
            $msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
                      'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
                      intval($_SERVER['CONTENT_LENGTH']));
            $this->showForm(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
            return;
        }

        // CSRF protection

        $token = $this->trimmed('token');
        if (!$token || $token != common_session_token()) {
            // TRANS: Client error displayed when the session token does not match or is not given.
            $this->showForm(_('There was a problem with your session token. '.
                               'Try again, please.'));
            return;
        }

        if (Event::handle('StartAvatarSaveForm', array($this))) {
            if ($this->arg('upload')) {
                $this->uploadAvatar();
                } else if ($this->arg('crop')) {
                    $this->cropAvatar();
                } else if ($this->arg('delete')) {
                    $this->deleteAvatar();
                } else {
                    // TRANS: Unexpected validation error on avatar upload form.
                    $this->showForm(_('Unexpected form submission.'));
                }
            Event::handle('EndAvatarSaveForm', array($this));
        }
    }

    /**
     * Handle an image upload
     *
     * Does all the magic for handling an image upload, and crops the
     * image by default.
     *
     * @return void
     */
    function uploadAvatar()
    {
        try {
            $imagefile = ImageFile::fromUpload('avatarfile');
        } catch (Exception $e) {
            $this->showForm($e->getMessage());
            return;
        }
        if ($imagefile === null) {
            // TRANS: Validation error on avatar upload form when no file was uploaded.
            $this->showForm(_('No file uploaded.'));
            return;
        }

        $cur = common_current_user();
        $type = $imagefile->preferredType();
        $filename = Avatar::filename($cur->id,
                                     image_type_to_extension($type),
                                     null,
                                     'tmp'.common_timestamp());

        $filepath = Avatar::path($filename);
        $imagefile = $imagefile->copyTo($filepath);

        $filedata = array('filename' => $filename,
                          'filepath' => $filepath,
                          'width' => $imagefile->width,
                          'height' => $imagefile->height,
                          'type' => $type);

        $_SESSION['FILEDATA'] = $filedata;

        $this->filedata = $filedata;

        $this->mode = 'crop';

        // TRANS: Avatar upload form instruction after uploading a file.
        $this->showForm(_('Pick a square area of the image to be your avatar.'),
                        true);
    }

    /**
     * Handle the results of jcrop.
     *
     * @return void
     */
    public function cropAvatar()
    {
        $filedata = $_SESSION['FILEDATA'];

        if (!$filedata) {
            // TRANS: Server error displayed if an avatar upload went wrong somehow server side.
            $this->serverError(_('Lost our file data.'));
        }

        $file_d = ($filedata['width'] > $filedata['height'])
                     ? $filedata['height'] : $filedata['width'];

        $dest_x = $this->arg('avatar_crop_x') ? $this->arg('avatar_crop_x'):0;
        $dest_y = $this->arg('avatar_crop_y') ? $this->arg('avatar_crop_y'):0;
        $dest_w = $this->arg('avatar_crop_w') ? $this->arg('avatar_crop_w'):$file_d;
        $dest_h = $this->arg('avatar_crop_h') ? $this->arg('avatar_crop_h'):$file_d;
        $size = intval(min($dest_w, $dest_h, common_config('avatar', 'maxsize')));

        $box = array('width' => $size, 'height' => $size,
                     'x' => $dest_x,   'y' => $dest_y,
                     'w' => $dest_w,   'h' => $dest_h);

        $user = common_current_user();
        $profile = $user->getProfile();

        $imagefile = new ImageFile(null, $filedata['filepath']);
        $filename = Avatar::filename($profile->getID(), image_type_to_extension($imagefile->preferredType()),
                                     $size, common_timestamp());
        try {
            $imagefile->resizeTo(Avatar::path($filename), $box);
        } catch (UseFileAsThumbnailException $e) {
            common_debug('Using uploaded avatar directly without resizing, copying it to: '.$filename);
            if (!copy($filedata['filepath'], Avatar::path($filename))) {
                common_debug('Tried to copy image file '.$filedata['filepath'].' to destination '.Avatar::path($filename));
                throw new ServerException('Could not copy file to destination.');
            }
        }

        if ($profile->setOriginal($filename)) {
            @unlink($filedata['filepath']);
            unset($_SESSION['FILEDATA']);
            $this->mode = 'upload';
            // TRANS: Success message for having updated a user avatar.
            $this->showForm(_('Avatar updated.'), true);
        } else {
            // TRANS: Error displayed on the avatar upload page if the avatar could not be updated for an unknown reason.
            $this->showForm(_('Failed updating avatar.'));
        }
    }

    /**
     * Get rid of the current avatar.
     *
     * @return void
     */
    function deleteAvatar()
    {
        $user = common_current_user();
        $profile = $user->getProfile();

        Avatar::deleteFromProfile($profile);

        // TRANS: Success message for deleting a user avatar.
        $this->showForm(_('Avatar deleted.'), true);
    }

    /**
     * Add the jCrop stylesheet
     *
     * @return void
     */

    function showStylesheets()
    {
        parent::showStylesheets();
        $this->cssLink('js/extlib/jquery-jcrop/css/jcrop.css','base','screen, projection, tv');
    }

    /**
     * Add the jCrop scripts
     *
     * @return void
     */
    function showScripts()
    {
        parent::showScripts();

        if ($this->mode == 'crop') {
            $this->script('extlib/jquery-jcrop/jcrop.js');
            $this->script('jcrop.go.js');
        }

        $this->autofocus('avatarfile');
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2010, StatusNet, Inc.
 *
 * Download a backup of your own account to the browser
 *
 * 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  Account
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET')) {
    // This check helps protect against security problems;
    // your code file can't be executed directly from the web.
    exit(1);
}

/**
 * Download a backup of your own account to the browser
 *
 * We go through some hoops to make this only respond to POST, since
 * it's kind of expensive and there's probably some downside to having
 * your account in all kinds of search engines.
 *
 * @category  Account
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */
class BackupaccountAction extends Action
{
    /**
     * Returns the title of the page
     *
     * @return string page title
     */
    function title()
    {
        // TRANS: Title for backup account page.
        return _('Backup account');
    }

    /**
     * For initializing members of the class.
     *
     * @param array $argarray misc. arguments
     *
     * @return boolean true
     */
    function prepare($argarray)
    {
        parent::prepare($argarray);

        $cur = common_current_user();

        if (empty($cur)) {
            // TRANS: Client exception thrown when trying to backup an account while not logged in.
            throw new ClientException(_('Only logged-in users can backup their account.'), 403);
        }

        if (!$cur->hasRight(Right::BACKUPACCOUNT)) {
            // TRANS: Client exception thrown when trying to backup an account without having backup rights.
            throw new ClientException(_('You may not backup your account.'), 403);
        }

        return true;
    }

    /**
     * Handler method
     *
     * @param array $argarray is ignored since it's now passed in in prepare()
     *
     * @return void
     */
    function handle($argarray=null)
    {
        parent::handle($argarray);

        if ($this->isPost()) {
            $this->sendFeed();
        } else {
            $this->showPage();
        }
        return;
    }

    /**
     * Send a feed of the user's activities to the browser
     *
     * Uses the UserActivityStream class; may take a long time!
     *
     * @return void
     */

    function sendFeed()
    {
        $cur = common_current_user();

        $stream = new UserActivityStream($cur, true, UserActivityStream::OUTPUT_RAW);

        header('Content-Disposition: attachment; filename='.$cur->nickname.'.atom');
        header('Content-Type: application/atom+xml; charset=utf-8');

        // @fixme atom feed logic is in getString...
        // but we just want it to output to the outputter.
        $this->raw($stream->getString());
    }

    /**
     * Show a little form so that the person can request a backup.
     *
     * @return void
     */

    function showContent()
    {
        $form = new BackupAccountForm($this);
        $form->show();
    }

    /**
     * Return true if read only.
     *
     * MAY override
     *
     * @param array $args other arguments
     *
     * @return boolean is read only action?
     */
    function isReadOnly($args)
    {
        return true;
    }

    /**
     * Return last modified, if applicable.
     *
     * MAY override
     *
     * @return string last modified http header
     */
    function lastModified()
    {
        // For comparison with If-Last-Modified
        // If not applicable, return null
        return null;
    }

    /**
     * Return etag, if applicable.
     *
     * MAY override
     *
     * @return string etag http header
     */
    function etag()
    {
        return null;
    }
}

/**
 * A form for backing up the account.
 *
 * @category  Account
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */
class BackupAccountForm extends Form
{
    /**
     * Class of the form.
     *
     * @return string the form's class
     */
    function formClass()
    {
        return 'form_profile_backup';
    }

    /**
     * URL the form posts to
     *
     * @return string the form's action URL
     */
    function action()
    {
        return common_local_url('backupaccount');
    }

    /**
     * Output form data
     *
     * Really, just instructions for doing a backup.
     *
     * @return void
     */
    function formData()
    {
        $msg =
            // TRANS: Information displayed on the backup account page.
            _('You can backup your account data in '.
              'Activity Streams '.
              'format. This is an experimental feature and provides an '.
              'incomplete backup; private account '.
              'information like email and IM addresses is not backed up. '.
              'Additionally, uploaded files and direct messages are not '.
              'backed up.');
        $this->out->elementStart('p');
        $this->out->raw($msg);
        $this->out->elementEnd('p');
    }

    /**
     * Buttons for the form
     *
     * In this case, a single submit button
     *
     * @return void
     */
    function formActions()
    {
        $this->out->submit('submit',
                           // TRANS: Submit button to backup an account on the backup account page.
                           _m('BUTTON', 'Backup'),
                           'submit',
                           null,
                           // TRANS: Title for submit button to backup an account on the backup account page.
                           _('Backup your account.'));
    }
}


code:
<?php
/**
 * Block a user action class.
 *
 * PHP version 5
 *
 * @category Action
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @author   Robin Millette <millette@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);
}

/**
 * Block a user action class.
 *
 * @category Action
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @author   Robin Millette <millette@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 * @link     http://status.net/
 */
class BlockAction extends ProfileFormAction
{
    var $profile = null;

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

        $cur = common_current_user();

        assert(!empty($cur)); // checked by parent

        if ($cur->hasBlocked($this->profile)) {
            // TRANS: Client error displayed when blocking a user that has already been blocked.
            $this->clientError(_('You already blocked that user.'));
        }

        return true;
    }

    /**
     * Handle request
     *
     * @param array $args $_REQUEST args; handled in prepare()
     *
     * @return void
     */
    function handle($args)
    {
        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
            if ($this->arg('no')) {
                $this->returnToPrevious();
            } elseif ($this->arg('yes')) {
                $this->handlePost();
                $this->returnToPrevious();
            } else {
                $this->showPage();
            }
        } else {
            $this->showPage();
        }
    }

    function showContent() {
        $this->areYouSureForm();
    }

    function title() {
        // TRANS: Title for block user page.
        return _('Block user');
    }

    function showNoticeForm() {
        // nop
    }

    /**
     * Confirm with user.
     *
     * Shows a confirmation form.
     *
     * @return void
     */
    function areYouSureForm()
    {
        // @fixme if we ajaxify the confirmation form, skip the preview on ajax hits
        $profile = new ArrayWrapper(array($this->profile));
        $preview = new ProfileList($profile, $this);
        $preview->show();

        $id = $this->profile->id;
        $this->elementStart('form', array('id' => 'block-' . $id,
                                           'method' => 'post',
                                           'class' => 'form_settings form_entity_block',
                                           'action' => common_local_url('block')));
        $this->elementStart('fieldset');
        $this->hidden('token', common_session_token());
        // TRANS: Legend for block user form.
        $this->element('legend', _('Block user'));
        $this->element('p', null,
                       // TRANS: Explanation of consequences when blocking a user on the block user page.
                       _('Are you sure you want to block this user? '.
                         'Afterwards, they will be unsubscribed from you, '.
                         'unable to subscribe to you in the future, and '.
                         'you will not be notified of any @-replies from them.'));
        $this->element('input', array('id' => 'blockto-' . $id,
                                      'name' => 'profileid',
                                      'type' => 'hidden',
                                      'value' => $id));
        foreach ($this->args as $k => $v) {
            if (substr($k, 0, 9) == 'returnto-') {
                $this->hidden($k, $v);
            }
        }
        $this->submit('form_action-no',
                      // TRANS: Button label on the user block form.
                      _m('BUTTON','No'),
                      'submit form_action-primary',
                      'no',
                      // TRANS: Submit button title for 'No' when blocking a user.
                      _('Do not block this user.'));
        $this->submit('form_action-yes',
                      // TRANS: Button label on the user block form.
                      _m('BUTTON','Yes'),
                      'submit form_action-secondary',
                      'yes',
                      // TRANS: Submit button title for 'Yes' when blocking a user.
                      _('Block this user.'));
        $this->elementEnd('fieldset');
        $this->elementEnd('form');
    }

    /**
     * Actually block a user.
     *
     * @return void
     */

    function handlePost()
    {
        $cur = common_current_user();

        if (Event::handle('StartBlockProfile', array($cur, $this->profile))) {
            $result = $cur->block($this->profile);
            if ($result) {
                Event::handle('EndBlockProfile', array($cur, $this->profile));
            }
        }

        if (!$result) {
            // TRANS: Server error displayed when blocking a user fails.
            $this->serverError(_('Failed to save block information.'));
        }
    }

    function showScripts()
    {
        parent::showScripts();
        $this->autofocus('form_action-yes');
    }

    /**
     * Override for form session token checks; on our first hit we're just
     * requesting confirmation, which doesn't need a token. We need to be
     * able to take regular GET requests from email!
     *
     * @throws ClientException if token is bad on POST request or if we have
     *         confirmation parameters which could trigger something.
     */
    function checkSessionToken()
    {
        if ($_SERVER['REQUEST_METHOD'] == 'POST' ||
            $this->arg('yes') ||
            $this->arg('no')) {

            return parent::checkSessionToken();
        }
    }

    /**
     * If we reached this form without returnto arguments, return to the
     * current user's subscription list.
     *
     * @return string URL
     */
    function defaultReturnTo()
    {
        $user = common_current_user();
        if ($user) {
            return common_local_url('subscribers',
                                    array('nickname' => $user->nickname));
        } else {
            return common_local_url('public');
        }
    }
}


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

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

/**
 * List of profiles blocked from this group
 *
 * @category Group
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class BlockedfromgroupAction extends GroupAction
{
    var $page = null;

    function isReadOnly($args)
    {
        return true;
    }

    protected function prepare(array $args=array())
    {
        parent::prepare($args);
        $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;

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

        // Permanent redirect on non-canonical nickname

        if ($nickname_arg != $nickname) {
            $args = array('nickname' => $nickname);
            if ($this->page != 1) {
                $args['page'] = $this->page;
            }
            common_redirect(common_local_url('blockedfromgroup', $args), 301);
        }

        if (!$nickname) {
            // TRANS: Client error displayed when requesting a list of blocked users for a group without providing a group nickname.
            $this->clientError(_('No nickname.'), 404);
        }

        $local = Local_group::getKV('nickname', $nickname);

        if (!$local) {
            // TRANS: Client error displayed when requesting a list of blocked users for a non-local group.
            $this->clientError(_('No such group.'), 404);
        }

        $this->group = User_group::getKV('id', $local->group_id);

        if (!$this->group) {
            // TRANS: Client error displayed when requesting a list of blocked users for a non-existing group.
            $this->clientError(_('No such group.'), 404);
        }

        return true;
    }

    function title()
    {
        if ($this->page == 1) {
            // TRANS: Title for first page with list of users blocked from a group.
            // TRANS: %s is a group nickname.
            return sprintf(_('%s blocked profiles'),
                           $this->group->nickname);
        } else {
            // TRANS: Title for any but the first page with list of users blocked from a group.
            // TRANS: %1$s is a group nickname, %2$d is a page number.
            return sprintf(_('%1$s blocked profiles, page %2$d'),
                           $this->group->nickname,
                           $this->page);
        }
    }

    protected function handle()
    {
        parent::handle();
        $this->showPage();
    }

    function showPageNotice()
    {
        $this->element('p', 'instructions',
                       // TRANS: Instructions for list of users blocked from a group.
                       _('A list of the users blocked from joining this group.'));
    }

    function showContent()
    {
        $offset = ($this->page-1) * PROFILES_PER_PAGE;
        $limit =  PROFILES_PER_PAGE + 1;

        $cnt = 0;

        $blocked = $this->group->getBlocked($offset, $limit);

        if ($blocked) {
            $blocked_list = new GroupBlockList($blocked, $this->group, $this);
            $cnt = $blocked_list->show();
        }

        $blocked->free();

        $this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE,
                          $this->page, 'blockedfromgroup',
                          array('nickname' => $this->group->nickname));
    }
}

class GroupBlockList extends ProfileList
{
    var $group = null;

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

        $this->group = $group;
    }

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

class GroupBlockListItem extends ProfileListItem
{
    var $group = null;

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

        $this->group = $group;
    }

    function showActions()
    {
        $this->startActions();
        $this->showGroupUnblockForm();
        $this->endActions();
    }

    function showGroupUnblockForm()
    {
        $user = common_current_user();

        if (!empty($user) && $user->id != $this->profile->id && $user->isAdmin($this->group)) {
            $this->out->elementStart('li', 'entity_block');
            $bf = new GroupUnblockForm($this->out, $this->profile, $this->group,
                                       array('action' => 'blockedfromgroup',
                                             'nickname' => $this->group->nickname));
            $bf->show();
            $this->out->elementEnd('li');
        }
    }
}

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

    var $profile = null;

    /**
     * Group to block the user from
     */

    var $group = null;

    /**
     * Return-to args
     */

    var $args = null;

    /**
     * Constructor
     *
     * @param HTMLOutputter $out     output channel
     * @param Profile       $profile profile of user to block
     * @param User_group    $group   group to block user from
     * @param array         $args    return-to args
     */
    function __construct($out=null, $profile=null, $group=null, $args=null)
    {
        parent::__construct($out);

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

    /**
     * ID of the form
     *
     * @return int ID of the form
     */
    function id()
    {
        // This should be unique for the page.
        return 'unblock-' . $this->profile->id;
    }

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

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

    /**
     * Legend of the Form
     *
     * @return void
     */
    function formLegend()
    {
        // TRANS: Form legend for unblocking a user from a group.
        $this->out->element('legend', null, _('Unblock user from group'));
    }

    /**
     * Data elements of the form
     *
     * @return void
     */
    function formData()
    {
        $this->out->hidden('unblockto-' . $this->profile->id,
                           $this->profile->id,
                           'unblockto');
        $this->out->hidden('unblockgroup-' . $this->group->id,
                           $this->group->id,
                           'unblockgroup');
        if ($this->args) {
            foreach ($this->args as $k => $v) {
                $this->out->hidden('returnto-' . $k, $v);
            }
        }
    }

    /**
     * Action elements
     *
     * @return void
     */
    function formActions()
    {
        $this->out->submit('submit',
                           // TRANS: Button text for unblocking a user from a group.
                           _m('BUTTON','Unblock'),
                           'submit',
                           null,
                           // TRANS: Tooltip for button for unblocking a user from a group.
                           _('Unblock this user'));
    }
}


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

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

/**
 * Leave a group
 *
 * This is the action for leaving a group. It works more or less like the subscribe action
 * for users.
 *
 * @category Group
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class CancelgroupAction extends Action
{
    var $group = null;

    /**
     * Prepare to run
     */
    function prepare($args)
    {
        parent::prepare($args);

        if (!common_logged_in()) {
            // TRANS: Client error displayed when trying to leave a group while not logged in.
            $this->clientError(_('You must be logged in to leave a group.'));
        }

        $nickname_arg = $this->trimmed('nickname');
        $id = intval($this->arg('id'));
        if ($id) {
            $this->group = User_group::getKV('id', $id);
        } else if ($nickname_arg) {
            $nickname = common_canonical_nickname($nickname_arg);

            // Permanent redirect on non-canonical nickname
            if ($nickname_arg != $nickname) {
                $args = array('nickname' => $nickname);
                common_redirect(common_local_url('leavegroup', $args), 301);
            }

            $local = Local_group::getKV('nickname', $nickname);

            if (!$local) {
                // TRANS: Client error displayed when trying to leave a non-local group.
                $this->clientError(_('No such group.'), 404);
            }

            $this->group = User_group::getKV('id', $local->group_id);
        } else {
            // TRANS: Client error displayed when trying to leave a group without providing a group name or group ID.
            $this->clientError(_('No nickname or ID.'), 404);
        }

        if (!$this->group) {
            // TRANS: Client error displayed when trying to leave a non-existing group.
            $this->clientError(_('No such group.'), 404);
        }

        $cur = common_current_user();
        if (empty($cur)) {
            // TRANS: Client error displayed when trying to leave a group while not logged in.
            $this->clientError(_('Must be logged in.'), 403);
        }
        if ($this->arg('profile_id')) {
            if ($cur->isAdmin($this->group)) {
                $this->profile = Profile::getKV('id', $this->arg('profile_id'));
            } else {
                // TRANS: Client error displayed when trying to approve or cancel a group join request without
                // TRANS: being a group administrator.
                $this->clientError(_('Only group admin can approve or cancel join requests.'), 403);
            }
        } else {
            $this->profile = $cur->getProfile();
        }

        $this->request = Group_join_queue::pkeyGet(array('profile_id' => $this->profile->id,
                                                         'group_id' => $this->group->id));

        if (empty($this->request)) {
            // TRANS: Client error displayed when trying to approve a non-existing group join request.
            // TRANS: %s is a user nickname.
            $this->clientError(sprintf(_('%s is not in the moderation queue for this group.'), $this->profile->nickname), 403);
        }
        return true;
    }

    /**
     * Handle the request
     *
     * On POST, add the current user to the group
     *
     * @param array $args unused
     *
     * @return void
     */
    function handle($args)
    {
        parent::handle($args);

        try {
            $this->request->abort();
        } catch (Exception $e) {
            common_log(LOG_ERR, "Exception canceling group sub: " . $e->getMessage());
            // TRANS: Server error displayed when cancelling a queued group join request fails.
            // TRANS: %1$s is the leaving user's nickname, $2$s is the group nickname for which the leave failed.
            $this->serverError(sprintf(_('Could not cancel request for user %1$s to join group %2$s.'),
                                       $this->profile->nickname, $this->group->nickname));
            return;
        }

        if ($this->boolean('ajax')) {
            $this->startHTML('text/xml;charset=utf-8');
            $this->elementStart('head');
            // TRANS: Title for leave group page after leaving.
            // TRANS: %s$s is the leaving user's name, %2$s is the group name.
            $this->element('title', null, sprintf(_m('TITLE','%1$s left group %2$s'),
                                                  $this->profile->nickname,
                                                  $this->group->nickname));
            $this->elementEnd('head');
            $this->elementStart('body');
            $jf = new JoinForm($this, $this->group);
            $jf->show();
            $this->elementEnd('body');
            $this->endHTML();
        } else {
            common_redirect(common_local_url('groupmembers', array('nickname' => $this->group->nickname)), 303);
        }
    }
}


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

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

/**
 * Cancel the subscription of a profile
 *
 * @category Subscription
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @author   Mikael Nordfeldth <mmn@hethane.se>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class CancelsubscriptionAction extends FormAction
{
    protected $needPost = true;

    protected function doPreparation()
    {
        $profile_id = $this->int('unsubscribeto');
        $this->target = Profile::getKV('id', $profile_id);
        if (!$this->target instanceof Profile) {
            throw new NoProfileException($profile_id);
        }
    }

    protected function doPost()
    {
        try {
            $request = Subscription_queue::pkeyGet(array('subscriber' => $this->scoped->id,
                                                         'subscribed' => $this->target->id));
            if ($request instanceof Subscription_queue) {
                $request->abort();
            }
        } catch (AlreadyFulfilledException $e) {
            common_debug('Tried to cancel a non-existing pending subscription');
        }

        if (GNUsocial::isAjax()) {
            $this->startHTML('text/xml;charset=utf-8');
            $this->elementStart('head');
            // TRANS: Title after unsubscribing from a group.
            $this->element('title', null, _m('TITLE','Unsubscribed'));
            $this->elementEnd('head');
            $this->elementStart('body');
            $subscribe = new SubscribeForm($this, $this->target);
            $subscribe->show();
            $this->elementEnd('body');
            $this->endHTML();
            exit();
        }
        common_redirect(common_local_url('subscriptions', array('nickname' => $this->scoped->getNickname())), 303);
    }
}


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

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

/**
 * Confirm an address
 *
 * When users change their SMS, email, Jabber, or other addresses, we send out
 * a confirmation code to make sure the owner of that address approves. This class
 * accepts those codes.
 *
 * @category Confirm
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class ConfirmaddressAction extends Action
{
    /** type of confirmation. */

    var $address;

    /**
     * Accept a confirmation code
     *
     * Checks the code and confirms the address in the
     * user record
     *
     * @param args $args $_REQUEST array
     *
     * @return void
     */
    function handle($args)
    {
        parent::handle($args);
        if (!common_logged_in()) {
            common_set_returnto($this->selfUrl());
            common_redirect(common_local_url('login'));
        }
        $code = $this->trimmed('code');
        if (!$code) {
            // TRANS: Client error displayed when not providing a confirmation code in the contact address confirmation action.
            $this->clientError(_('No confirmation code.'));
        }
        $confirm = Confirm_address::getKV('code', $code);
        if (!$confirm) {
            // TRANS: Client error displayed when providing a non-existing confirmation code in the contact address confirmation action.
            $this->clientError(_('Confirmation code not found.'));
        }
        $cur = common_current_user();
        if ($cur->id != $confirm->user_id) {
            // TRANS: Client error displayed when not providing a confirmation code for another user in the contact address confirmation action.
            $this->clientError(_('That confirmation code is not for you!'));
        }
        $type = $confirm->address_type;
        $transports = array();
        Event::handle('GetImTransports', array(&$transports));
        if (!in_array($type, array('email', 'sms')) && !in_array($type, array_keys($transports))) {
            // TRANS: Server error for an unknown address type, which can be 'email', 'sms', or the name of an IM network (such as 'xmpp' or 'aim')
            $this->serverError(sprintf(_('Unrecognized address type %s'), $type));
        }
        $this->address = $confirm->address;
        $cur->query('BEGIN');
        if (in_array($type, array('email', 'sms')))
        {
            if ($cur->$type == $confirm->address) {
                // TRANS: Client error for an already confirmed email/jabber/sms address.
                $this->clientError(_('That address has already been confirmed.'));
            }

            $orig_user = clone($cur);

            $cur->$type = $confirm->address;

            if ($type == 'sms') {
                $cur->carrier  = ($confirm->address_extra)+0;
                $carrier       = Sms_carrier::getKV($cur->carrier);
                $cur->smsemail = $carrier->toEmailAddress($cur->sms);
            }

            // Throws exception on failure.
            $cur->updateWithKeys($orig_user);

            if ($type == 'email') {
                $cur->emailChanged();
            }

        } else {

            $user_im_prefs = new User_im_prefs();
            $user_im_prefs->transport = $confirm->address_type;
            $user_im_prefs->user_id = $cur->id;
            if ($user_im_prefs->find() && $user_im_prefs->fetch()) {
                if($user_im_prefs->screenname == $confirm->address){
                    // TRANS: Client error for an already confirmed IM address.
                    $this->clientError(_('That address has already been confirmed.'));
                }
                $user_im_prefs->screenname = $confirm->address;
                $result = $user_im_prefs->update();

                if (!$result) {
                    common_log_db_error($user_im_prefs, 'UPDATE', __FILE__);
                    // TRANS: Server error displayed when updating IM preferences fails.
                    $this->serverError(_('Could not update user IM preferences.'));
                }
            }else{
                $user_im_prefs = new User_im_prefs();
                $user_im_prefs->screenname = $confirm->address;
                $user_im_prefs->transport = $confirm->address_type;
                $user_im_prefs->user_id = $cur->id;
                $result = $user_im_prefs->insert();

                if (!$result) {
                    common_log_db_error($user_im_prefs, 'INSERT', __FILE__);
                    // TRANS: Server error displayed when adding IM preferences fails.
                    $this->serverError(_('Could not insert user IM preferences.'));
                }
            }

        }

        $result = $confirm->delete();

        if (!$result) {
            common_log_db_error($confirm, 'DELETE', __FILE__);
            // TRANS: Server error displayed when an address confirmation code deletion from the
            // TRANS: database fails in the contact address confirmation action.
            $this->serverError(_('Could not delete address confirmation.'));
        }

        $cur->query('COMMIT');
        $this->showPage();
    }

    /**
     * Title of the page
     *
     * @return string title
     */
    function title()
    {
        // TRANS: Title for the contact address confirmation action.
        return _('Confirm address');
    }

    /**
     * Show a confirmation message.
     *
     * @return void
     */
    function showContent()
    {
        $cur  = common_current_user();

        $this->element('p', null,
                       // TRANS: Success message for the contact address confirmation action.
                       // TRANS: %s can be 'email', 'jabber', or 'sms'.
                       sprintf(_('The address "%s" has been '.
                                 'confirmed for your account.'),
                               $this->address));
    }
}