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

repo_name: ksuudilla/gnu

license: mit


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
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GNU social is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.

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

/**
 * Show notice attachments
 *
 * @category  Personal
 * @package   GNUsocial
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2008-2009 StatusNet, Inc.
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */
class AttachmentAction extends ManagedAction
{
    /**
     * Attachment File object to show
     */
    public $attachment = null;

    public $filehash = null;
    public $filepath = null;
    public $filesize = null;
    public $mimetype = null;
    public $filename = null;

    /**
     * Load attributes based on database arguments
     *
     * Loads all the DB stuff
     *
     * @param array $args $_REQUEST array
     *
     * @return bool flag
     * @throws ClientException
     * @throws FileNotFoundException
     * @throws FileNotStoredLocallyException
     * @throws InvalidFilenameException
     * @throws ServerException
     */
    protected function prepare(array $args = [])
    {
        parent::prepare($args);

        try {
            if (!empty($id = $this->trimmed('attachment'))) {
                $this->attachment = File::getByID((int) $id);
            } elseif (!empty($this->filehash = $this->trimmed('filehash'))) {
                $file = File::getByHash($this->filehash);
                $file->fetch();
                $this->attachment = $file;
            }
        } catch (Exception $e) {
            // Not found
        }
        if (!$this->attachment instanceof File) {
            // TRANS: Client error displayed trying to get a non-existing attachment.
            $this->clientError(_m('No such attachment.'), 404);
        }

        $this->filesize = $this->attachment->size;
        $this->mimetype = $this->attachment->mimetype;
        $this->filename = $this->attachment->filename;

        if ($this->attachment->isLocal()) {
            $this->filepath = $this->attachment->getFileOrThumbnailPath();
            if (empty($this->filepath)) {
                $this->clientError(
                    _m('Requested local URL for a file that is not stored locally.'),
                    404
                );
            }
            $this->filesize = $this->attachment->getFileOrThumbnailSize();
            $this->mimetype = $this->attachment->getFileOrThumbnailMimetype();
            $this->filename = MediaFile::getDisplayName($this->attachment);
        }

        return true;
    }

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

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

    public function showPage(): void
    {
        if (
            !$this->attachment->isLocal()
            || empty($this->filepath)
            || !file_exists($this->filepath)
        ) {
            // If it's not a locally stored file, get lost
            common_redirect($this->attachment->getUrl(), 303);
        }

        parent::showPage();
    }

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

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

    /**
     * Show aside: this attachments appears in what notices
     *
     * @return void
     */
    public function showSections(): void
    {
        $ns = new AttachmentNoticeSection($this);
        $ns->show();
    }

    /**
     * Last-modified date for file
     *
     * @return int last-modified date as unix timestamp
     * @throws ServerException
     */
    public function lastModified(): ?int
    {
        if (common_config('site', 'use_x_sendfile')) {
            return null;
        }
        $path = $this->filepath;
        if (!empty($path)) {
            return filemtime($path);
        } else {
            return null;
        }
    }

    /**
     * etag header for file
     *
     * This returns the same data (inode, size, mtime) as Apache would,
     * but in decimal instead of hex.
     *
     * @return string etag http header
     * @throws ServerException
     */
    public function etag(): ?string
    {
        if (common_config('site', 'use_x_sendfile')) {
            return null;
        }

        $path = $this->filepath;

        $cache = Cache::instance();
        if ($cache) {
            if (empty($path)) {
                return null;
            }
            $key = Cache::key('attachments:etag:' . $path);
            $etag = $cache->get($key);
            if ($etag === false) {
                $etag = crc32(file_get_contents($path));
                $cache->set($key, $etag);
            }
            return $etag;
        }

        if (!empty($path)) {
            $stat = stat($path);
            return '"' . $stat['ino'] . '-' . $stat['size'] . '-' . $stat['mtime'] . '"';
        } else {
            return null;
        }
    }
}


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

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

/**
 * Download notice attachment
 *
 * @category  Personal
 * @package   GNUsocial
 * @author    Mikael Nordfeldth <mmn@hethane.se>
 * @copyright 2016 Free Software Foundation, Inc http://www.fsf.org
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or late
 */
class Attachment_downloadAction extends AttachmentAction
{
    public function showPage(): void
    {
        // Disable errors, to not mess with the file contents (suppress errors in case access to this
        // function is blocked, like in some shared hosts). Automatically reset at the end of the
        // script execution, and we don't want to have any more errors until then, so don't reset it
        @ini_set('display_errors', 0);

        if ($this->attachment->isLocal()) {
            common_send_file(
                $this->filepath,
                $this->mimetype,
                $this->filename,
                'attachment'
            );
        } else {
            common_redirect($this->attachment->getUrl(), 303);
        }
    }
}


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

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

/**
 * Show notice attachments
 *
 * @category  Personal
 * @package   GNUsocial
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2008-2009 StatusNet, Inc.
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */
class Attachment_thumbnailAction extends Attachment_viewAction
{
    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');
    }

    /**
     * Show an inline representation of an attachment of the size
     * requested in the GET variables (read in the constructor). Tries
     * to send the most appropriate file with the correct size and
     * headers or displays an error if it's not possible.
     * @throws ClientException
     * @throws ReflectionException
     * @throws ServerException
     */
    public function showPage(): void
    {
        // Returns a File_thumbnail object or throws exception if not available
        $filename = $this->filename;
        $filepath = $this->filepath;
        try {
            $thumbnail = $this->attachment->getThumbnail($this->thumb_w, $this->thumb_h, $this->thumb_c);
            $filename = $thumbnail->getFilename();
            $filepath = $thumbnail->getPath();
        } catch (UseFileAsThumbnailException $e) {
            // With this exception, the file exists locally $e->file;
        } catch (FileNotFoundException $e) {
            $this->clientError(_m('No such attachment'), 404);
        } catch (Exception $e) {
            if (is_null($filepath)) {
                $this->clientError(_m('No such thumbnail'), 404);
            }
            // Remote file
        }

        // Disable errors, to not mess with the file contents (suppress errors in case access to this
        // function is blocked, like in some shared hosts). Automatically reset at the end of the
        // script execution, and we don't want to have any more errors until then, so don't reset it
        @ini_set('display_errors', 0);

        common_send_file($filepath, $this->mimetype, $filename, 'inline');
    }
}


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

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

/**
 * View notice attachment
 *
 * @package   GNUsocial
 * @author    Miguel Dantas <biodantasgs@gmail.com>
 * @copyright 2019 Free Software Foundation, Inc http://www.fsf.org
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */
class Attachment_viewAction extends AttachmentAction
{
    public function showPage(): void
    {
        // Disable errors, to not mess with the file contents (suppress errors in case access to this
        // function is blocked, like in some shared hosts). Automatically reset at the end of the
        // script execution, and we don't want to have any more errors until then, so don't reset it
        @ini_set('display_errors', 0);

        if ($this->attachment->isLocal()) {
            $disposition = 'attachment';
            if (in_array(common_get_mime_media($this->mimetype), ['image', 'video'])) {
                $disposition = 'inline';
            }
            common_send_file($this->filepath, $this->mimetype,
$this->filename, $disposition);
        } else {
            common_redirect($this->attachment->getUrl(), 303);
        }
    }
}


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

/**
 * Retrieve user avatar by filename action class.
 *
 * @category Action
 * @package  GNUsocial
 *
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 */
defined('GNUSOCIAL') || die;

/**
 * Retrieve user avatar by filename action class.
 *
 * @category Action
 * @package  GNUsocial
 *
 * @author   Evan Prodromou <evan@status.net>
 * @author   Robin Millette <millette@status.net>
 * @author   Mikael Nordfeldth <mmn@hethane.se>
 * @author   Hugo Sales <hugo@fc.up.pt>
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 *
 * @see     http://www.gnu.org/software/social/
 */
class AvatarAction extends Action
{
    public $filename = null;
    public $filepath = null;
    public $mimetype = null;

    protected function prepare(array $args = [])
    {
        parent::prepare($args);
        $this->filename = File::tryFilename($this->trimmed('file'));
        $this->filepath = File::path($this->filename, common_config('avatar', 'dir'), false);
        if (!file_exists($this->filepath)) {
            // TRANS: Client error displayed trying to get a non-existing avatar.
            $this->clientError(_m('No such avatar.'), 404);
        }
        $this->mimetype = (new ImageFile(-1, $this->filepath))->mimetype;

        return true;
    }

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

        common_send_file($this->filepath, $this->mimetype, $this->filename, 'inline');
    }
}


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
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GNU social is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Upload an avatar
 *
 * @category  Settings
 * @package   GNUsocial
 *
 * @author    Evan Prodromou <evan@status.net>
 * @author    Zach Copley <zach@status.net>
 * @author    Diogo Cordeiro <diogo@fc.up.pt>
 * @copyright 2008-2009, 2020 Free Software Foundation http://fsf.org
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 */
defined('GNUSOCIAL') || die;

/**
 * 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
 *
 * @see     http://status.net/
 */
class AvatarsettingsAction extends SettingsAction
{
    public $mode;
    public $imagefile;
    public $filename;

    public function prepare(array $args = [])
    {
        $avatarpath = Avatar::path('');

        if (!is_writable($avatarpath)) {
            throw new Exception(_m("The administrator of your site needs to
                add write permissions on the avatar upload folder before
                you're able to set one."));
        }

        parent::prepare($args);
        return true;
    }

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

    /**
     * Instructions for use
     *
     * @return string instructions for use
     * @throws Exception
     *
     */
    public function getInstructions()
    {
        // TRANS: Instruction for avatar upload page.
        // TRANS: %s is the maximum file size, for example "500b", "10kB" or "2MB".
        return sprintf(
            _m('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. Currently overrides FormAction's showContent
     * since we haven't made classes out of AvatarCropForm and AvatarUploadForm.
     *
     * @return void
     */
    public function showContent()
    {
        if ($this->mode == 'crop') {
            $this->showCropForm();
        } else {
            $this->showUploadForm();
        }
    }

    public function showUploadForm()
    {
        // If we detect that the user didn't finish setting a new avatar, remove the temporary file.
        if (isset($_SESSION['FILEDATA'])) {
            @unlink($_SESSION['FILEDATA']['filepath']);
            unset($_SESSION['FILEDATA']);
        }
        $this->elementStart('form', ['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, _m('Avatar settings'));
        $this->hidden('token', common_session_token());

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

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

            try {
                $avatar = $this->scoped->getAvatar(AVATAR_PROFILE_SIZE);
                $this->elementStart('li', ['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, _m('Preview'));
                $this->elementStart('div', ['id' => 'avatar_preview_view']);
                $this->element('img', ['src' => $avatar->displayUrl(),
                    'width' => AVATAR_PROFILE_SIZE,
                    'height' => AVATAR_PROFILE_SIZE,
                    'alt' => $this->scoped->getNickname(),]);
                $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', ['id' => 'settings_attach']);
            $this->element('input', ['name' => 'MAX_FILE_SIZE',
                'type' => 'hidden',
                'id' => 'MAX_FILE_SIZE',
                'value' => ImageFile::maxFileSizeInt(),]);
            $this->element('input', ['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', [$this]);

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

    public function showCropForm()
    {
        $this->elementStart('form', ['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, _m('Avatar settings'));
        $this->hidden('token', common_session_token());

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

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

        $this->elementStart(
            'li',
            ['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, _m('Preview'));
        $this->elementStart('div', ['id' => 'avatar_preview_view']);
        $this->element('img', ['src' => Avatar::url($this->filedata['filename']),
            'width' => AVATAR_PROFILE_SIZE,
            'height' => AVATAR_PROFILE_SIZE,
            'alt' => $this->scoped->getNickname(),]);
        $this->elementEnd('div');

        foreach (['avatar_crop_x', 'avatar_crop_y',
                     'avatar_crop_w', 'avatar_crop_h',] as $crop_info) {
            $this->element('input', ['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');
    }

    /**
     * @return string
     * @throws NoResultException
     * @throws NoUploadedMediaException
     * @throws ServerException
     * @throws UnsupportedMediaException
     * @throws UseFileAsThumbnailException
     * @throws Exception
     *
     * @throws ClientException
     */
    protected function doPost()
    {
        if (Event::handle('StartAvatarSaveForm', [$this])) {
            if ($this->trimmed('upload')) {
                return $this->uploadAvatar();
            } elseif ($this->trimmed('crop')) {
                return $this->cropAvatar();
            } elseif ($this->trimmed('delete')) {
                return $this->deleteAvatar();
            } else {
                // TRANS: Unexpected validation error on avatar upload form.
                throw new ClientException(_m('Unexpected form submission.'));
            }
            Event::handle('EndAvatarSaveForm', [$this]);
        }
    }

    /**
     * Handle an image upload
     *
     * Does all the magic for handling an image upload, and crops the
     * image by default.
     *
     * @return string
     * @throws NoResultException
     * @throws NoUploadedMediaException
     * @throws ServerException
     * @throws UnsupportedMediaException
     * @throws UseFileAsThumbnailException
     *
     * @throws ClientException
     */
    public function uploadAvatar(): string
    {
        // ImageFile throws exception if something goes wrong, which we'll
        // pick up and show as an error message above the form.
        $imagefile = ImageFile::fromUpload('avatarfile');

        $type = $imagefile->preferredType();
        $filename = Avatar::filename(
            $this->scoped->getID(),
            image_type_to_extension($type),
            null,
            'tmp' . common_timestamp()
        );

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

        $filedata = [
            '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.
        return _m('Pick a square area of the image to be your avatar.');
    }

    /**
     * Handle the results of jcrop.
     *
     * @return string
     * @throws NoResultException
     * @throws ServerException
     * @throws UnsupportedMediaException
     *
     * @throws ClientException
     */
    public function cropAvatar()
    {
        $filedata = $_SESSION['FILEDATA'];

        if (empty($filedata)) {
            // TRANS: Server error displayed if an avatar upload went wrong somehow server side.
            throw new ServerException(_m('Lost our file data.'));
        }

        $file_d = min($filedata['width'], $filedata['height']);

        $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 = (int)(min($dest_w, $dest_h, common_config('avatar', 'maxsize')));

        $box = ['width' => $size, 'height' => $size,
            'x' => $dest_x, 'y' => $dest_y,
            'w' => $dest_w, 'h' => $dest_h,];

        $imagefile = new ImageFile(-1, $filedata['filepath']);
        $filename = Avatar::filename(
            $this->scoped->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 ($this->scoped->setOriginal($filename)) {
            @unlink($filedata['filepath']);
            unset($_SESSION['FILEDATA']);
            $this->mode = 'upload';
            // TRANS: Success message for having updated a user avatar.
            return _m('Avatar updated.');
        }

        // TRANS: Error displayed on the avatar upload page if the avatar could not be updated for an unknown reason.
        throw new ServerException(_m('Failed updating avatar.'));
    }

    /**
     * Get rid of the current avatar.
     *
     * @return string
     * @throws Exception
     *
     */
    public function deleteAvatar()
    {
        Avatar::deleteFromProfile($this->scoped);

        // TRANS: Success message for deleting a user avatar.
        return _m('Avatar deleted.');
    }

    /**
     * Add the jCrop stylesheet
     *
     * @return void
     */
    public function showStylesheets()
    {
        parent::showStylesheets();
        $this->cssLink('js/extlib/jquery-jcrop/css/jcrop.css', 'base', 'screen, projection, tv');
    }

    /**
     * Add the jCrop scripts
     *
     * @return void
     */
    public 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('GNUSOCIAL')) { 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 FormAction
{
    protected $form = 'BackupAccount';

    function title()
    {
        // TRANS: Title for backup account page.
        return _('Backup account');
    }

    protected function doPreparation()
    {
        if (!$this->scoped->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;
    }

    protected function doPost()
    {
        $stream = new UserActivityStream($this->scoped->getUser(), true, UserActivityStream::OUTPUT_RAW);

        header('Content-Disposition: attachment; filename='.urlencode($this->scoped->getNickname()).'.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());

        // Don't print the page HTML
        exit(0);
    }

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

    function lastModified()
    {
        // For comparison with If-Last-Modified
        // If not applicable, return null
        return null;
    }

    function etag()
    {
        return null;
    }
}


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

/**
 * Block a user action class.
 *
 * @category  Action
 * @package   GNUsocial
 * @author    Evan Prodromou <evan@status.net>
 * @author    Robin Millette <millette@status.net>
 * @copyright 2008, 2009 StatusNet, Inc.
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */

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

/**
 * Block a user action class.
 *
 * @category  Action
 * @package   GNUsocial
 * @author    Evan Prodromou <evan@status.net>
 * @author    Robin Millette <millette@status.net>
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */
class BlockAction extends ProfileFormAction
{
    public $profile = null;

    /**
     * Take arguments for running
     *
     * @param array $args $_REQUEST args
     *
     * @return boolean success flag
     */
    public function prepare(array $args = []): bool
    {
        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
     */
    public function handle(): void
    {
        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();
        }
    }

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

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

    public function showNoticeForm(): void
    {
        // nop
    }

    /**
     * Confirm with user.
     *
     * Shows a confirmation form.
     *
     * @return void
     */
    public 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', [
            '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
     */

    public function handlePost(): void
    {
        $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.'));
        }
    }

    public function showScripts(): void
    {
        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.
     */
    public function checkSessionToken(): void
    {
        if (
            $_SERVER['REQUEST_METHOD'] === 'POST'
            || $this->arg('yes')
            || $this->arg('no')
        ) {
            parent::checkSessionToken();
        }
    }

    /**
     * If we reached this form without returnto arguments, return to the
     * current user's subscription list.
     *
     * @return string URL
     */
    public function defaultReturnTo()
    {
        $user = common_current_user();
        if ($user) {
            return common_local_url(
                'subscribers',
                ['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 $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(array $args = array())
    {
        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()
    {
        parent::handle();

        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
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GNU social is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Confirm an address
 *
 * @category  Confirm
 * @package   GNUsocial
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2008-2009 StatusNet, Inc.
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */

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

/**
 * 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   GNUsocial
 * @author    Evan Prodromou <evan@status.net>
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */
class ConfirmaddressAction extends ManagedAction
{
    /** type of confirmation. */

    protected $address;

    protected function doPreparation()
    {
        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.
            throw new ClientException(_('No confirmation code.'));
        }
        $confirm = Confirm_address::getKV('code', $code);
        if (!$confirm instanceof Confirm_address) {
            // TRANS: Client error displayed when providing a non-existing confirmation code in the contact address confirmation action.
            throw new ClientException(_('Confirmation code not found.'), 404);
        }

        try {
            $profile = Profile::getByID($confirm->user_id);
        } catch (NoResultException $e) {
            common_log(LOG_INFO, 'Tried to confirm the email for a deleted profile: '._ve(['id'=>$confirm->user_id, 'email'=>$confirm->address]));
            $confirm->delete();
            throw $e;
        }
        if (!$profile->sameAs($this->scoped)) {
            // TRANS: Client error displayed when not providing a confirmation code for another user in the contact address confirmation action.
            throw new AuthorizationException(_('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')
            throw new ServerException(sprintf(_('Unrecognized address type %s'), $type));
        }
        $this->address = $confirm->address;

        $cur = $this->scoped->getUser();

        $cur->query('START TRANSACTION');
        if (in_array($type, array('email', 'sms'))) {
            common_debug("Confirming {$type} address for user {$this->scoped->getID()}");
            if ($cur->$type == $confirm->address) {
                // Already verified, so delete the confirm_address entry
                $confirm->delete();
                // TRANS: Client error for an already confirmed email/jabber/sms address.
                throw new AlreadyFulfilledException(_('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) {
                    // Already verified, so delete the confirm_address entry
                    $confirm->delete();
                    // TRANS: Client error for an already confirmed IM address.
                    throw new AlreadyFulfilledException(_('That address has already been confirmed.'));
                }
                $user_im_prefs->screenname = $confirm->address;
                $result = $user_im_prefs->update();

                if ($result === false) {
                    common_log_db_error($user_im_prefs, 'UPDATE', __FILE__);
                    // TRANS: Server error displayed when updating IM preferences fails.
                    throw new ServerException(_('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;
                $user_im_prefs->created = common_sql_now();
                $result = $user_im_prefs->insert();

                if ($result === false) {
                    common_log_db_error($user_im_prefs, 'INSERT', __FILE__);
                    // TRANS: Server error displayed when adding IM preferences fails.
                    throw new ServerException(_('Could not insert user IM preferences.'));
                }
            }
        }

        $confirm->delete();

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

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

    /**
     * Show a confirmation message.
     *
     * @return void
     */
    public function showContent()
    {
        $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
            )
        );
    }
}


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

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

/**
 * Conversation tree in the browser
 *
 * Will always try to show the entire conversation, since that's how our
 * ConversationNoticeStream works.
 *
 * @category Action
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @author   Mikael Nordfeldth <mmn@hethane.se>
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 * @link     http://status.net/
 */
class ConversationAction extends ManagedAction
{
    protected $redirectAfterLogin = true;

    public $conv        = null;
    public $page        = null;
    public $notices     = null;

    protected function doPreparation()
    {
        $this->conv = Conversation::getByID($this->int('id'));
    }

    /**
     * Returns the page title
     *
     * @return string page title
     */
    public function title()
    {
        // TRANS: Title for page with a conversion (multiple notices in context).
        return _('Conversation');
    }

    /**
     * Show content.
     *
     * NoticeList extended classes do most heavy lifting. Plugins can override.
     *
     * @return void
     */
    public function showContent()
    {
        if (Event::handle('StartShowConversation', [$this, $this->conv, $this->scoped])) {
            $notices = $this->conv->getNotices($this->scoped);
            $nl = new FullThreadedNoticeList($notices, $this, $this->scoped);
            $cnt = $nl->show();
        }
        Event::handle('EndShowConversation', [$this, $this->conv, $this->scoped]);
    }

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

    public function getFeeds()
    {
        return [
            new Feed(Feed::JSON,
                     common_local_url('apiconversation',
                                      ['id' => $this->conv->getID(),
                                       'format' => 'as']),
                     // TRANS: Title for link to notice feed.
                     // TRANS: %s is a user nickname.
                     _('Conversation feed (Activity Streams JSON)')
            ),
            new Feed(Feed::RSS2,
                     common_local_url('apiconversation',
                                      ['id' => $this->conv->getID(),
                                       'format' => 'rss']),
                     // TRANS: Title for link to notice feed.
                     // TRANS: %s is a user nickname.
                     _('Conversation feed (RSS 2.0)')
            ),
            new Feed(Feed::ATOM,
                     common_local_url('apiconversation',
                                      ['id' => $this->conv->getID(),
                                       'format' => 'atom']),
                     // TRANS: Title for link to notice feed.
                     // TRANS: %s is a user nickname.
                     _('Conversation feed (Atom)')
            )
        ];
    }
}