code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Base class for API actions that require authentication
 *
 * 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  API
 * @package   StatusNet
 * @author    Adrian Lang <mail@adrianlang.de>
 * @author    Brenda Wallace <shiny@cpan.org>
 * @author    Craig Andrews <candrews@integralblue.com>
 * @author    Dan Moore <dan@moore.cx>
 * @author    Evan Prodromou <evan@status.net>
 * @author    mEDI <medi@milaro.net>
 * @author    Sarven Capadisli <csarven@status.net>
 * @author    Zach Copley <zach@status.net>
 * @copyright 2009-2010 StatusNet, Inc.
 * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

/* External API usage documentation. Please update when you change how this method works. */

/*! @page authentication Authentication

    GNU social supports HTTP Basic Authentication and OAuth for API calls.

    @warning Currently, users who have created accounts without setting a
    password via OpenID, Facebook Connect, etc., cannot use the API until
    they set a password with their account settings panel.

    @section HTTP Basic Auth

    @section OAuth

*/

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

/**
 * Actions extending this class will require auth
 *
 * @category API
 * @package  StatusNet
 * @author   Zach Copley <zach@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class ApiAuthAction extends ApiAction
{
    var $auth_user_nickname = null;
    var $auth_user_password = null;

    /**
     * Take arguments for running, looks for an OAuth request,
     * and outputs basic auth header if needed
     *
     * @param array $args $_REQUEST args
     *
     * @return boolean success flag
     *
     */
    protected function prepare(array $args=array())
    {
        parent::prepare($args);

        // NOTE: $this->scoped and $this->auth_user has to get set in
        // prepare(), not handle(), as subclasses use them in prepares.

        // Allow regular login session, but we have to double-check the
        // HTTP_REFERER value to avoid cross domain POSTing since the API
        // doesn't use the "token" form field.
        if (common_logged_in() && common_local_referer()) {
            $this->scoped = Profile::current();
            $this->auth_user = $this->scoped->getUser();
            if (!$this->auth_user->hasRight(Right::API)) {
                // TRANS: Authorization exception thrown when a user without API access tries to access the API.
                throw new AuthorizationException(_('Not allowed to use API.'));
            }
            // Let's run this in the same way as if we've just authenticated the user (basic/oauth auth)
            Event::handle('EndSetApiUser', array($this->auth_user));
            $this->access = self::READ_WRITE;
        } else {
            $oauthReq = $this->getOAuthRequest();

            if ($oauthReq instanceof OAuthRequest) {
                $this->checkOAuthRequest($oauthReq);
            } else {
                // If not using OAuth, check if there is a basic auth
                // and require it if the current action requires it.
                $this->checkBasicAuthUser($this->requiresAuth());
            }

            // NOTE: Make sure we're scoped properly based on the auths!
            if (isset($this->auth_user) && $this->auth_user instanceof User) {
                $this->scoped = $this->auth_user->getProfile();
            } else {
                $this->scoped = null;
            }
        }

        // legacy user transferral
        // TODO: remove when sure no extended classes need it
        $this->user = $this->auth_user;

        // Reject API calls with the wrong access level

        if ($this->isReadOnly($args) == false) {
            if ($this->access != self::READ_WRITE) {
                // TRANS: Client error 401.
                $msg = _('API resource requires read-write access, ' .
                         'but you only have read access.');
                $this->clientError($msg, 401);
            }
        }

        return true;
    }

    /**
     * Determine whether the request is an OAuth request.
     * This is to avoid doign any unnecessary DB lookups.
     *
     * @return mixed the OAuthRequest or false
     */
    function getOAuthRequest()
    {
        ApiOAuthAction::cleanRequest();

        $req  = OAuthRequest::from_request();

        $consumer    = $req->get_parameter('oauth_consumer_key');
        $accessToken = $req->get_parameter('oauth_token');

        // XXX: Is it good enough to assume it's not meant to be an
        // OAuth request if there is no consumer or token? --Z

        if (empty($consumer) || empty($accessToken)) {
            return false;
        }

        return $req;
    }

    /**
     * Verifies the OAuth request signature, sets the auth user
     * and access type (read-only or read-write)
     *
     * @param OAuthRequest $request the OAuth Request
     *
     * @return nothing
     */
    function checkOAuthRequest($request)
    {
        $datastore   = new ApiGNUsocialOAuthDataStore();
        $server      = new OAuthServer($datastore);
        $hmac_method = new OAuthSignatureMethod_HMAC_SHA1();

        $server->add_signature_method($hmac_method);

        try {
            $server->verify_request($request);

            $consumer     = $request->get_parameter('oauth_consumer_key');
            $access_token = $request->get_parameter('oauth_token');

            $app = Oauth_application::getByConsumerKey($consumer);

            if (empty($app)) {
                common_log(
                    LOG_WARNING,
                    'API OAuth - Couldn\'t find the OAuth app for consumer key: ' .
                    $consumer
                );
                // TRANS: OAuth exception thrown when no application is found for a given consumer key.
                throw new OAuthException(_('No application for that consumer key.'));
            }

            // set the source attr
            if ($app->name != 'anonymous') {
                $this->source = $app->name;
            }

            $appUser = Oauth_application_user::getKV('token', $access_token);

            if (!empty($appUser)) {
                // If access_type == 0 we have either a request token
                // or a bad / revoked access token

                if ($appUser->access_type != 0) {
                    // Set the access level for the api call
                    $this->access = ($appUser->access_type & Oauth_application::$writeAccess)
                      ? self::READ_WRITE : self::READ_ONLY;

                    // Set the auth user
                    if (Event::handle('StartSetApiUser', array(&$user))) {
                        $user = User::getKV('id', $appUser->profile_id);
                    }
                    if ($user instanceof User) {
                        if (!$user->hasRight(Right::API)) {
                            // TRANS: Authorization exception thrown when a user without API access tries to access the API.
                            throw new AuthorizationException(_('Not allowed to use API.'));
                        }
                        $this->auth_user = $user;
                        Event::handle('EndSetApiUser', array($this->auth_user));
                    } else {
                        // If $user is not a real User, let's force it to null.
                        $this->auth_user = null;
                    }

                    // FIXME: setting the value returned by common_current_user()
                    // There should probably be a better method for this. common_set_user()
                    // does lots of session stuff.
                    global $_cur;
                    $_cur = $this->auth_user;

                    $msg = "API OAuth authentication for user '%s' (id: %d) on behalf of " .
                        "application '%s' (id: %d) with %s access.";

                    common_log(
                        LOG_INFO,
                        sprintf(
                            $msg,
                            $this->auth_user->nickname,
                            $this->auth_user->id,
                            $app->name,
                            $app->id,
                            ($this->access = self::READ_WRITE) ? 'read-write' : 'read-only'
                        )
                    );
                } else {
                    // TRANS: OAuth exception given when an incorrect access token was given for a user.
                    throw new OAuthException(_('Bad access token.'));
                }
            } else {
                // Also should not happen.
                // TRANS: OAuth exception given when no user was found for a given token (no token was found).
                throw new OAuthException(_('No user for that token.'));
            }

        } catch (OAuthException $e) {
            $this->logAuthFailure($e->getMessage());
            common_log(LOG_WARNING, 'API OAuthException - ' . $e->getMessage());
            $this->clientError($e->getMessage(), 401);
        }
    }

    /**
     * Does this API resource require authentication?
     *
     * @return boolean true
     */
    public function requiresAuth()
    {
        return true;
    }

    /**
     * Check for a user specified via HTTP basic auth. If there isn't
     * one, try to get one by outputting the basic auth header.
     *
     * @return boolean true or false
     */
    function checkBasicAuthUser($required = true)
    {
        $this->basicAuthProcessHeader();

        $realm = common_config('api', 'realm');

        if (empty($realm)) {
            $realm = common_config('site', 'name') . ' API';
        }

        if (empty($this->auth_user_nickname) && $required) {
            header('WWW-Authenticate: Basic realm="' . $realm . '"');

            // show error if the user clicks 'cancel'
            // TRANS: Client error thrown when authentication fails because a user clicked "Cancel".
            $this->clientError(_('Could not authenticate you.'), 401);

        } else {
            // $this->auth_user_nickname - i.e. PHP_AUTH_USER - will have a value since it was not empty

            $user = common_check_user($this->auth_user_nickname,
                                      $this->auth_user_password);

            Event::handle('StartSetApiUser', array(&$user));
            if ($user instanceof User) {
                if (!$user->hasRight(Right::API)) {
                    // TRANS: Authorization exception thrown when a user without API access tries to access the API.
                    throw new AuthorizationException(_('Not allowed to use API.'));
                }
                $this->auth_user = $user;

                Event::handle('EndSetApiUser', array($this->auth_user));
            } else {
                $this->auth_user = null;
            }

            if ($required && $this->auth_user instanceof User) {
                // By default, basic auth users have rw access
                $this->access = self::READ_WRITE;
            } elseif ($required) {
                $msg = sprintf(
                    "basic auth nickname = %s",
                    $this->auth_user_nickname
                );
                $this->logAuthFailure($msg);

                // We must present WWW-Authenticate in accordance to HTTP status code 401
                header('WWW-Authenticate: Basic realm="' . $realm . '"');
                // TRANS: Client error thrown when authentication fails.
                $this->clientError(_('Could not authenticate you.'), 401);
            } else {
                // all get rw access for actions that don't require auth
                $this->access = self::READ_WRITE;
            }
        }
    }

    /**
     * Read the HTTP headers and set the auth user.  Decodes HTTP_AUTHORIZATION
     * param to support basic auth when PHP is running in CGI mode.
     *
     * @return void
     */
    function basicAuthProcessHeader()
    {
        $authHeaders = array('AUTHORIZATION',
                             'HTTP_AUTHORIZATION',
                             'REDIRECT_HTTP_AUTHORIZATION'); // rewrite for CGI
        $authorization_header = null;
        foreach ($authHeaders as $header) {
            if (isset($_SERVER[$header])) {
                $authorization_header = $_SERVER[$header];
                break;
            }
        }

        if (isset($_SERVER['PHP_AUTH_USER'])) {
            $this->auth_user_nickname = $_SERVER['PHP_AUTH_USER'];
            $this->auth_user_password = $_SERVER['PHP_AUTH_PW'];
        } elseif (isset($authorization_header)
            && strstr(substr($authorization_header, 0, 5), 'Basic')) {

            // Decode the HTTP_AUTHORIZATION header on php-cgi server self
            // on fcgid server the header name is AUTHORIZATION
            $auth_hash = base64_decode(substr($authorization_header, 6));
            list($this->auth_user_nickname,
                 $this->auth_user_password) = explode(':', $auth_hash);

            // Set all to null on a empty basic auth request

            if (empty($this->auth_user_nickname)) {
                $this->auth_user_nickname = null;
                $this->auth_password = null;
            }
        }
    }

    /**
     * Log an API authentication failure. Collect the proxy and IP
     * and log them
     *
     * @param string $logMsg additional log message
     */
     function logAuthFailure($logMsg)
     {
        list($proxy, $ip) = common_client_ip();

        $msg = sprintf(
            'API auth failure (proxy = %1$s, ip = %2$s) - ',
            $proxy,
            $ip
        );

        common_log(LOG_WARNING, $msg . $logMsg);
     }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Base class for API actions that require "bare auth". Bare auth means
 * authentication is required only if the action is called without an argument
 * or query param specifying user id.
 *
 * 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  API
 * @package   StatusNet
 * @author    Adrian Lang <mail@adrianlang.de>
 * @author    Brenda Wallace <shiny@cpan.org>
 * @author    Craig Andrews <candrews@integralblue.com>
 * @author    Dan Moore <dan@moore.cx>
 * @author    Evan Prodromou <evan@status.net>
 * @author    mEDI <medi@milaro.net>
 * @author    Sarven Capadisli <csarven@status.net>
 * @author    Zach Copley <zach@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

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

/**
 * Actions extending this class will require auth unless a target
 * user ID has been specified
 *
 * @category API
 * @package  StatusNet
 * @author   Adrian Lang <mail@adrianlang.de>
 * @author   Brenda Wallace <shiny@cpan.org>
 * @author   Craig Andrews <candrews@integralblue.com>
 * @author   Dan Moore <dan@moore.cx>
 * @author   Evan Prodromou <evan@status.net>
 * @author   mEDI <medi@milaro.net>
 * @author   Sarven Capadisli <csarven@status.net>
 * @author   Zach Copley <zach@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class ApiBareAuthAction extends ApiAuthAction
{
    /**
     * Does this API resource require authentication?
     *
     * @return boolean true or false
     */
    function requiresAuth()
    {
        // If the site is "private", all API methods except statusnet/config
        // need authentication
        if (common_config('site', 'private')) {
            return true;
        }

        // check whether a user has been specified somehow
        if (!$this->arg('id') && !$this->arg('user_id')
                && mb_strlen($this->arg('screen_name'))===0) {
            return true;
        }

        return false;
    }
}

repo_name: andremichelle/gnu

license: mit


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

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

require_once 'OAuth.php';

/**
 * @fixme class doc
 */
class ApiGNUsocialOAuthDataStore extends OAuthDataStore
{
    function lookup_consumer($consumer_key)
    {
        $con = Consumer::getKV('consumer_key', $consumer_key);

        if (!$con instanceof Consumer) {

            // Create an anon consumer and anon application if one
            // doesn't exist already
            if ($consumer_key == 'anonymous') {

                common_debug("API OAuth - creating anonymous consumer");
                $con = new Consumer();
                $con->consumer_key    = $consumer_key;
                $con->consumer_secret = $consumer_key;
                $con->created         = common_sql_now();

                $result = $con->insert();
                if (!$result) {
                    // TRANS: Server error displayed when trying to create an anynymous OAuth consumer.
                    $this->serverError(_('Could not create anonymous consumer.'));
                }

                $app = Oauth_application::getByConsumerKey('anonymous');

                if (!$app) {
                    common_debug("API OAuth - creating anonymous application");
                    $app               = new OAuth_application();
                    $app->owner        = 1; // XXX: What to do here?
                    $app->consumer_key = $con->consumer_key;
                    $app->name         = 'anonymous';
                    $app->icon         = 'default-avatar-stream.png'; // XXX: Fix this!
                    $app->description  = "An anonymous application";
                    // XXX: allow the user to set the access type when
                    // authorizing? Currently we default to r+w for anonymous
                    // OAuth client applications
                    $app->access_type  = 3; // read + write
                    $app->type         = 2; // desktop
                    $app->created      = common_sql_now();

                    $id = $app->insert();

                    if (!$id) {
                        // TRANS: Server error displayed when trying to create an anynymous OAuth application.
                        $this->serverError(_("Could not create anonymous OAuth application."));
                    }
                }
            } else {
                return null;
            }
        }

        return new OAuthConsumer(
            $con->consumer_key,
            $con->consumer_secret
        );
    }

    function getAppByRequestToken($token_key)
    {
        // Look up the full req token
        $req_token = $this->lookup_token(
            null,
            'request',
            $token_key
        );

        if (empty($req_token)) {
            common_debug("Couldn't get request token from oauth datastore");
            return null;
        }

        // Look up the full Token
        $token = new Token();
        $token->tok = $req_token->key;
        $result = $token->find(true);

        if (empty($result)) {
            common_debug('Couldn\'t find req token in the token table.');
            return null;
        }

        // Look up the app
        $app = new Oauth_application();
        $app->consumer_key = $token->consumer_key;
        $result = $app->find(true);

        if (!empty($result)) {
            return $app;
        } else {
            common_debug("Couldn't find the app!");
            return null;
        }
    }

    function new_access_token($token, $consumer, $verifier = null)
    {
        common_debug(
            sprintf(
                "New access token from request token %s, consumer %s and verifier %s ",
                $token,
                $consumer,
                $verifier
            ),
            __FILE__
        );

        $rt = new Token();

        $rt->consumer_key = $consumer->key;
        $rt->tok          = $token->key;
        $rt->type         = 0; // request

        $app = Oauth_application::getByConsumerKey($consumer->key);
        assert(!empty($app));

        if ($rt->find(true) && $rt->state == 1 && $rt->verifier == $verifier) { // authorized

            common_debug('Request token found.', __FILE__);

            // find the app and profile associated with this token
            $tokenAssoc = Oauth_token_association::getKV('token', $rt->tok);

            if (!$tokenAssoc) {
                throw new Exception(
                    // TRANS: Exception thrown when no token association could be found.
                    _('Could not find a profile and application associated with the request token.')
                );
            }

            // Check to see if we have previously issued an access token for
            // this application and profile; if so we can just return the
            // existing access token. That seems to be the best practice. It
            // makes it so users only have to authorize the app once per
            // machine.

            $appUser = new Oauth_application_user();

            $appUser->application_id = $app->id;
            $appUser->profile_id     = $tokenAssoc->profile_id;

            $result = $appUser->find(true);

            if (!empty($result)) {

                common_log(LOG_INFO,
                     sprintf(
                        "Existing access token found for application %s, profile %s.",
                        $app->id,
                        $tokenAssoc->profile_id
                     )
                );

                $at = null;

                // Special case: we used to store request tokens in the
                // Oauth_application_user record, and the access_type would
                // always be 0 (no access) as a failsafe until an access
                // token was issued and replaced the request token. There could
                // be a few old Oauth_application_user records storing request
                // tokens still around, and we don't want to accidentally
                // return a useless request token instead of a new access
                // token. So if we find one, we generate a new access token
                // and update the existing Oauth_application_user record before
                // returning the new access token. This should be rare.

                if ($appUser->access_type == 0) {

                    $at = $this->generateNewAccessToken($consumer, $rt, $verifier);
                    $this->updateAppUser($appUser, $app, $at);

                } else {

                    $at = new Token();

                    // fetch the full access token
                    $at->consumer_key = $consumer->key;
                    $at->tok          = $appUser->token;

                    $result = $at->find(true);

                    if (!$result) {
                        throw new Exception(
                            // TRANS: Exception thrown when no access token can be issued.
                            _('Could not issue access token.')
                        );
                    }
                }

                // Yay, we can re-issue the access token
                return new OAuthToken($at->tok, $at->secret);

            } else {

               common_log(LOG_INFO,
                    sprintf(
                        "Creating new access token for application %s, profile %s.",
                        $app->id,
                        $tokenAssoc->profile_id
                     )
                );

                $at = $this->generateNewAccessToken($consumer, $rt, $verifier);
                $this->newAppUser($tokenAssoc, $app, $at);

                // Okay, good
                return new OAuthToken($at->tok, $at->secret);
            }

        } else {

            // the token was not authorized or not verfied
            common_log(
                LOG_INFO,
                sprintf(
                    "API OAuth - Attempt to exchange unauthorized or unverified request token %s for an access token.",
                     $rt->tok
                )
            );
            return null;
        }
    }

    /*
     * Generate a new access token and save it to the database
     *
     * @param Consumer $consumer the OAuth consumer
     * @param Token    $rt       the authorized request token
     * @param string   $verifier the OAuth 1.0a verifier
     *
     * @access private
     *
     * @return Token   $at       the new access token
     */
    private function generateNewAccessToken($consumer, $rt, $verifier)
    {
        $at = new Token();

        $at->consumer_key      = $consumer->key;
        $at->tok               = common_random_hexstr(16);
        $at->secret            = common_random_hexstr(16);
        $at->type              = 1; // access
        $at->verifier          = $verifier;
        $at->verified_callback = $rt->verified_callback; // 1.0a
        $at->created           = common_sql_now();

        if (!$at->insert()) {
            $e = $at->_lastError;
            common_debug('access token "' . $at->tok . '" not inserted: "' . $e->message . '"', __FILE__);
            return null;
        } else {
            common_debug('access token "' . $at->tok . '" inserted', __FILE__);
            // burn the old one
            $orig_rt   = clone($rt);
            $rt->state = 2; // used
            if (!$rt->update($orig_rt)) {
                return null;
            }
            common_debug('request token "' . $rt->tok . '" updated', __FILE__);
        }

        return $at;
    }

   /*
    * Add a new app user (Oauth_application_user) record
    *
    * @param Oauth_token_association $tokenAssoc token-to-app association
    * @param Oauth_application       $app        the OAuth client app
    * @param Token                   $at         the access token
    *
    * @access private
    *
    * @return void
    */
    private function newAppUser($tokenAssoc, $app, $at)
    {
        $appUser = new Oauth_application_user();

        $appUser->profile_id     = $tokenAssoc->profile_id;
        $appUser->application_id = $app->id;
        $appUser->access_type    = $app->access_type;
        $appUser->token          = $at->tok;
        $appUser->created        = common_sql_now();

        $result = $appUser->insert();

        if (!$result) {
            common_log_db_error($appUser, 'INSERT', __FILE__);

            throw new Exception(
                // TRANS: Exception thrown when a database error occurs.
                _('Database error inserting OAuth application user.')
            );
        }
    }

   /*
    * Update an existing app user (Oauth_application_user) record
    *
    * @param Oauth_application_user $appUser existing app user rec
    * @param Oauth_application      $app     the OAuth client app
    * @param Token                  $at      the access token
    *
    * @access private
    *
    * @return void
    */
    private function updateAppUser($appUser, $app, $at)
    {
        $original = clone($appUser);
        $appUser->access_type = $app->access_type;
        $appUser->token       = $at->tok;

        $result = $appUser->update($original);

        if (!$result) {
            common_log_db_error($appUser, 'UPDATE', __FILE__);
            throw new Exception(
                // TRANS: Exception thrown when a database error occurs.
                _('Database error updating OAuth application user.')
            );
        }
    }

    /**
     * Revoke specified access token
     *
     * Revokes the token specified by $token_key.
     * Throws exceptions in case of error.
     *
     * @param string $token_key the token to be revoked
     * @param int    $type      type of token (0 = req, 1 = access)
     *
     * @access public
     *
     * @return void
     */
    public function revoke_token($token_key, $type = 0) {
        $rt        = new Token();
        $rt->tok   = $token_key;
        $rt->type  = $type;
        $rt->state = 0;

        if (!$rt->find(true)) {
            // TRANS: Exception thrown when an attempt is made to revoke an unknown token.
            throw new Exception(_('Tried to revoke unknown token.'));
        }

        if (!$rt->delete()) {
            // TRANS: Exception thrown when an attempt is made to remove a revoked token.
            throw new Exception(_('Failed to delete revoked token.'));
        }
    }

    /*
     * Create a new request token. Overrided to support OAuth 1.0a callback
     *
     * @param OAuthConsumer $consumer the OAuth Consumer for this token
     * @param string        $callback the verified OAuth callback URL
     *
     * @return OAuthToken   $token a new unauthorized OAuth request token
     */
    function new_request_token($consumer, $callback = null)
    {
        $t = new Token();
        $t->consumer_key = $consumer->key;
        $t->tok = common_random_hexstr(16);
        $t->secret = common_random_hexstr(16);
        $t->type = 0; // request
        $t->state = 0; // unauthorized
        $t->verified_callback = $callback;

        if ($callback === 'oob') {
            // six digit pin
            $t->verifier = mt_rand(0, 9999999);
        } else {
            $t->verifier = common_random_hexstr(8);
        }

        $t->created = common_sql_now();
        if (!$t->insert()) {
            return null;
        } else {
            return new OAuthToken($t->tok, $t->secret);
        }
    }

    /**
     * Authorize specified OAuth token
     *
     * Authorizes the authorization token specified by $token_key.
     * Throws exceptions in case of error.
     *
     * @param string $token_key The token to be authorized
     *
     * @access public
     **/
    public function authorize_token($token_key) {
        $rt = new Token();
        $rt->tok = $token_key;
        $rt->type = 0;
        $rt->state = 0;
        if (!$rt->find(true)) {
            throw new Exception('Tried to authorize unknown token');
        }
        $orig_rt = clone($rt);
        $rt->state = 1; # Authorized but not used
        if (!$rt->update($orig_rt)) {
            throw new Exception('Failed to authorize token');
        }
    }

    /**
     *
     * http://oauth.net/core/1.0/#nonce
     * "The Consumer SHALL then generate a Nonce value that is unique for
     * all requests with that timestamp."
     * XXX: It's not clear why the token is here
     *
     * @param type $consumer
     * @param type $token
     * @param type $nonce
     * @param type $timestamp
     * @return type
     */
    function lookup_nonce($consumer, $token, $nonce, $timestamp)
    {
        $n = new Nonce();
        $n->consumer_key = $consumer->key;
        $n->ts = common_sql_date($timestamp);
        $n->nonce = $nonce;
        if ($n->find(true)) {
            return true;
        } else {
            $n->created = common_sql_now();
            $n->insert();
            return false;
        }
    }

    /**
     *
     * @param type $consumer
     * @param type $token_type
     * @param type $token_key
     * @return OAuthToken
     */
    function lookup_token($consumer, $token_type, $token)
    {
        $t = new Token();
        if (!is_null($consumer)) {
            $t->consumer_key = $consumer->key;
        }
        $t->tok = $token;
        $t->type = ($token_type == 'access') ? 1 : 0;
        if ($t->find(true)) {
            return new OAuthToken($t->tok, $t->secret);
        } else {
            return null;
        }
    }

    /**
     *
     * @param type $token_key
     * @return Token
     */
    function getTokenByKey($token_key)
    {
        $t = new Token();
        $t->tok = $token_key;
        if ($t->find(true)) {
            return $t;
        } else {
            return null;
        }
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Base class for list members and list subscribers api.
 *
 * 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  API
 * @package   StatusNet
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

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

class ApiListUsersAction extends ApiBareAuthAction
{
    var $list   = null;
    var $user   = false;
    var $create = false;
    var $delete = false;
    var $cursor = -1;
    var $next_cursor = 0;
    var $prev_cursor = 0;
    var $users = null;

    protected function prepare(array $args=array())
    {
        // delete list member if method is DELETE or if method is POST and an argument
        // _method is set to DELETE
        $this->delete = ($_SERVER['REQUEST_METHOD'] == 'DELETE' ||
                            ($this->trimmed('_method') == 'DELETE' &&
                             $_SERVER['REQUEST_METHOD'] == 'POST'));

        // add member if method is POST
        $this->create = (!$this->delete &&
                         $_SERVER['REQUEST_METHOD'] == 'POST');

        if ($this->arg('id')) {
            $this->target = $this->getTargetProfile($this->arg('id'));
        }

        parent::prepare($args);

        $this->list = $this->getTargetList($this->arg('user'), $this->arg('list_id'));

        if (empty($this->list)) {
            // TRANS: Client error displayed when referring to a non-existing list.
            $this->clientError(_('List not found.'), 404, $this->format);
        }

        if(!$this->create && !$this->delete) {
            $this->getUsers();
        }
        return true;
    }

    function requiresAuth()
    {
        return parent::requiresAuth() ||
            $this->create || $this->delete;
    }

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

        if($this->delete) {
            return $this->handleDelete();
        }

        if($this->create) {
            return $this->handlePost();
        }

        switch($this->format) {
        case 'xml':
            $this->initDocument('xml');
            $this->elementStart('users_list', array('xmlns:statusnet' =>
                                         'http://status.net/schema/api/1/'));
            $this->elementStart('users', array('type' => 'array'));

            if (is_array($this->users)) {
                foreach ($this->users as $u) {
                    $twitter_user = $this->twitterUserArray($u, true);
                    $this->showTwitterXmlUser($twitter_user);
                }
            } else {
                while ($this->users->fetch()) {
                    $twitter_user = $this->twitterUserArray($this->users, true);
                    $this->showTwitterXmlUser($twitter_user);
                }
            }

            $this->elementEnd('users');
            $this->element('next_cursor', null, $this->next_cursor);
            $this->element('previous_cursor', null, $this->prev_cursor);
            $this->elementEnd('users_list');
            break;
        case 'json':
            $this->initDocument('json');

            $users = array();

            if (is_array($this->users)) {
                foreach ($this->users as $u) {
                    $twitter_user = $this->twitterUserArray($u, true);
                    array_push($users, $twitter_user);
                }
            } else {
                while ($this->users->fetch()) {
                    $twitter_user = $this->twitterUserArray($this->users, true);
                    array_push($users, $twitter_user);
                }
            }

            $users_list = array('users' => $users,
                                'next_cursor' => $this->next_cursor,
                                'next_cursor_str' => strval($this->next_cursor),
                                'previous_cursor' => $this->prev_cursor,
                                'previous_cursor_str' => strval($this->prev_cursor));

            $this->showJsonObjects($users_list);

            $this->endDocument('json');
            break;
        default:
            $this->clientError(
                // TRANS: Client error displayed when coming across a non-supported API method.
                _('API method not found.'),
                404,
                $this->format
            );
            break;
        }
    }

    function handlePost()
    {
    }

    function handleDelete()
    {
    }

    function getUsers()
    {
    }

    function isReadOnly($args)
    {
        return false;
    }

    function lastModified()
    {
        if(!empty($this->list)) {
            return strtotime($this->list->modified);
        }
        return null;
    }

    /**
     * An entity tag for this list
     *
     * Returns an Etag based on the action name, language, user ID and
     * timestamps of the first and last list the user has joined
     *
     * @return string etag
     */
    function etag()
    {
        if (!empty($this->list)) {

            return '"' . implode(
                ':',
                array($this->arg('action'),
                      common_language(),
                      $this->list->id,
                      strtotime($this->list->created),
                      strtotime($this->list->modified))
            )
            . '"';
        }

        return null;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Base action for OAuth API endpoints
 *
 * 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  API
 * @package   StatusNet
 * @author    Zach Copley <zach@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET')) {
    exit(1);
}
require_once INSTALLDIR . '/lib/apiaction.php';

/**
 * Base action for API OAuth enpoints. Clean up the
 * request. Some other common functions.
 *
 * @category API
 * @package  StatusNet
 * @author   Zach Copley <zach@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class ApiOAuthAction extends ApiAction
{
    /**
     * Is this a read-only action?
     *
     * @return boolean false
     */
    function isReadOnly($args)
    {
        return false;
    }

    protected function prepare(array $args=array())
    {
        self::cleanRequest();
        return parent::prepare($args);
    }

    /*
     * Clean up the request so the OAuth library doesn't find
     * any extra parameters or anything else it's not expecting.
     * I'm looking at you, p parameter.
     */

    static function cleanRequest()
    {
        // kill evil effects of magical slashing
        if (get_magic_quotes_gpc() == 1) {
            $_POST = array_map('stripslashes', $_POST);
            $_GET = array_map('stripslashes', $_GET);
        }

        // strip out the p param added in index.php
        unset($_GET['p']);
        unset($_POST['p']);
        unset($_REQUEST['p']);

        $queryArray = explode('&', $_SERVER['QUERY_STRING']);

        for ($i = 0; $i < sizeof($queryArray); $i++) {
            if (substr($queryArray[$i], 0, 2) == 'p=') {
                unset($queryArray[$i]);
            }
        }

        $_SERVER['QUERY_STRING'] = implode('&', $queryArray);
    }

}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Base class for API actions that only require auth when a site
 * is configured to be private
 *
 * 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  API
 * @package   StatusNet
 * @author    Adrian Lang <mail@adrianlang.de>
 * @author    Brenda Wallace <shiny@cpan.org>
 * @author    Craig Andrews <candrews@integralblue.com>
 * @author    Dan Moore <dan@moore.cx>
 * @author    Evan Prodromou <evan@status.net>
 * @author    mEDI <medi@milaro.net>
 * @author    Sarven Capadisli <csarven@status.net>
 * @author    Zach Copley <zach@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

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

/**
 * Actions extending this class will require auth only if a site is private
 *
 * @category API
 * @package  StatusNet
 * @author   Adrian Lang <mail@adrianlang.de>
 * @author   Brenda Wallace <shiny@cpan.org>
 * @author   Craig Andrews <candrews@integralblue.com>
 * @author   Dan Moore <dan@moore.cx>
 * @author   Evan Prodromou <evan@status.net>
 * @author   mEDI <medi@milaro.net>
 * @author   Sarven Capadisli <csarven@status.net>
 * @author   Zach Copley <zach@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class ApiPrivateAuthAction extends ApiAuthAction
{
   /**
     * Does this API resource require authentication?
     *
     * @return boolean true or false
     */
    function requiresAuth()
    {
        // If the site is "private", all API methods except statusnet/config
        // need authentication
        if (common_config('site', 'private')) {
            return true;
        }

        return false;
    }
}


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

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

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

/**
 * Form for editing an application
 *
 * @category Form
 * @package  StatusNet
 * @author   Zach Copley <zach@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 *
 */
class ApplicationEditForm extends Form
{
    /**
     * group for user to join
     */
    var $application = null;

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

        $this->application = $application;
    }

    /**
     * ID of the form
     *
     * @return string ID of the form
     */
    function id()
    {
        if ($this->application) {
            return 'form_application_edit-' . $this->application->id;
        } else {
            return 'form_application_add';
        }
    }

    /**
     * HTTP method used to submit the form
     *
     * For image data we need to send multipart/form-data
     * so we set that here too
     *
     * @return string the method to use for submitting
     */
    function method()
    {
        $this->enctype = 'multipart/form-data';
        return 'post';
    }

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

    /**
     * Action of the form
     *
     * @return string URL of the action
     */
    function action()
    {
        $cur = common_current_user();

        if (!empty($this->application)) {
            return common_local_url('editapplication',
                                    array('id' => $this->application->id));
        } else {
            return common_local_url('newapplication');
        }
    }

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

    /**
     * Data elements of the form
     *
     * @return void
     */
    function formData()
    {
        if ($this->application) {
            $id                = $this->application->id;
            $icon              = $this->application->icon;
            $name              = $this->application->name;
            $description       = $this->application->description;
            $source_url        = $this->application->source_url;
            $organization      = $this->application->organization;
            $homepage          = $this->application->homepage;
            $callback_url      = $this->application->callback_url;
            $this->type        = $this->application->type;
            $this->access_type = $this->application->access_type;
        } else {
            $id                = '';
            $icon              = '';
            $name              = '';
            $description       = '';
            $source_url        = '';
            $organization      = '';
            $homepage          = '';
            $callback_url      = '';
            $this->type        = '';
            $this->access_type = '';
        }

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

        $this->out->elementStart('li', array('id' => 'application_icon'));

        if (!empty($icon)) {
            $this->out->element('img', array('src' => $icon));
        }

        $this->out->element('input', array('name' => 'MAX_FILE_SIZE',
                                           'type' => 'hidden',
                                           'id' => 'MAX_FILE_SIZE',
                                           'value' => ImageFile::maxFileSizeInt()));
        $this->out->element('label', array('for' => 'app_icon'),
                            // TRANS: Form input field label for application icon.
                            _('Icon'));
        $this->out->element('input', array('name' => 'app_icon',
                                           'type' => 'file',
                                           'id' => 'app_icon'));
        // TRANS: Form guide.
        $this->out->element('p', 'form_guide', _('Icon for this application'));
        $this->out->elementEnd('li');

        $this->out->elementStart('li');

        $this->out->hidden('application_id', $id);

        // TRANS: Form input field label for application name.
        $this->out->input('name', _('Name'),
                          ($this->out->arg('name')) ? $this->out->arg('name') : $name);

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

        $this->out->elementStart('li');

        $maxDesc = Oauth_application::maxDesc();
        if ($maxDesc > 0) {
            // TRANS: Form input field instructions.
            // TRANS: %d is the number of available characters for the description.
            $descInstr = sprintf(_m('Describe your application in %d character','Describe your application in %d characters',$maxDesc),
                                 $maxDesc);
        } else {
            // TRANS: Form input field instructions.
            $descInstr = _('Describe your application');
        }
        // TRANS: Form input field label.
        $this->out->textarea('description', _('Description'),
                        ($this->out->arg('description')) ? $this->out->arg('description') : $description,
                             $descInstr);

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

        $this->out->elementStart('li');
        // TRANS: Form input field instructions.
        $instruction = _('URL of the homepage of this application');
        // TRANS: Form input field label.
        $this->out->input('source_url', _('Source URL'),
                          ($this->out->arg('source_url')) ? $this->out->arg('source_url') : $source_url,
                          $instruction);
        $this->out->elementEnd('li');

        $this->out->elementStart('li');
        // TRANS: Form input field instructions.
        $instruction = _('Organization responsible for this application');
        // TRANS: Form input field label.
        $this->out->input('organization', _('Organization'),
                          ($this->out->arg('organization')) ? $this->out->arg('organization') : $organization,
                          $instruction);
        $this->out->elementEnd('li');

        $this->out->elementStart('li');
        // TRANS: Form input field instructions.
        $instruction = _('URL for the homepage of the organization');
        // TRANS: Form input field label.
        $this->out->input('homepage', _('Homepage'),
                          ($this->out->arg('homepage')) ? $this->out->arg('homepage') : $homepage,
                          $instruction);
        $this->out->elementEnd('li');

        $this->out->elementStart('li');
        // TRANS: Form input field instructions.
        $instruction = _('URL to redirect to after authentication');
        // TRANS: Form input field label.
        $this->out->input('callback_url', ('Callback URL'),
                          ($this->out->arg('callback_url')) ? $this->out->arg('callback_url') : $callback_url,
                          $instruction);
        $this->out->elementEnd('li');

        $this->out->elementStart('li', array('id' => 'application_types'));

        $attrs = array('name' => 'app_type',
                       'type' => 'radio',
                       'id' => 'app_type-browser',
                       'class' => 'radio',
                       'value' => Oauth_application::$browser);

        // Default to Browser

        if (empty($this->application)
            || empty($this->application->type)
            || $this->application->type == Oauth_application::$browser) {
            $attrs['checked'] = 'checked';
        }

        $this->out->element('input', $attrs);

        $this->out->element('label', array('for' => 'app_type-browser',
                                           'class' => 'radio'),
                            // TRANS: Radio button label for application type
                            _('Browser'));

        $attrs = array('name' => 'app_type',
                       'type' => 'radio',
                       'id' => 'app_type-dekstop',
                       'class' => 'radio',
                       'value' => Oauth_application::$desktop);

        if (!empty($this->application) && $this->application->type == Oauth_application::$desktop) {
            $attrs['checked'] = 'checked';
        }

        $this->out->element('input', $attrs);

        $this->out->element('label', array('for' => 'app_type-desktop',
                                           'class' => 'radio'),
                            // TRANS: Radio button label for application type
                            _('Desktop'));
        // TRANS: Form guide.
        $this->out->element('p', 'form_guide', _('Type of application, browser or desktop'));
        $this->out->elementEnd('li');

        $this->out->elementStart('li', array('id' => 'default_access_types'));

        $attrs = array('name' => 'default_access_type',
                       'type' => 'radio',
                       'id' => 'default_access_type-r',
                       'class' => 'radio',
                       'value' => 'r');

        // default to read-only access

        if (empty($this->application)
            || empty($this->application->access_type)
            || $this->application->access_type & Oauth_application::$readAccess) {
            $attrs['checked'] = 'checked';
        }

        $this->out->element('input', $attrs);

        $this->out->element('label', array('for' => 'default_access_type-ro',
                                           'class' => 'radio'),
                            // TRANS: Radio button label for access type.
                            _('Read-only'));

        $attrs = array('name' => 'default_access_type',
                       'type' => 'radio',
                       'id' => 'default_access_type-rw',
                       'class' => 'radio',
                       'value' => 'rw');

        if (!empty($this->application)
            && $this->application->access_type & Oauth_application::$readAccess
            && $this->application->access_type & Oauth_application::$writeAccess
            ) {
            $attrs['checked'] = 'checked';
        }

        $this->out->element('input', $attrs);

        $this->out->element('label', array('for' => 'default_access_type-rw',
                                           'class' => 'radio'),
                            // TRANS: Radio button label for access type.
                            _('Read-write'));
        // TRANS: Form guide.
        $this->out->element('p', 'form_guide', _('Default access for this application: read-only, or read-write'));

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

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

    /**
     * Action elements
     *
     * @return void
     */
    function formActions()
    {
        // TRANS: Button label in the "Edit application" form.
        $this->out->submit('cancel', _m('BUTTON','Cancel'), 'submit form_action-primary',
                           // TRANS: Submit button title.
                           'cancel', _('Cancel application changes.'));
        // TRANS: Button label in the "Edit application" form.
        $this->out->submit('save', _m('BUTTON','Save'), 'submit form_action-secondary',
                           // TRANS: Submit button title.
                           'save', _('Save application changes.'));
    }
}


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

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

/**
 * Widget to show a list of OAuth applications
 *
 * @category Application
 * @package  StatusNet
 * @author   Zach Copley <zach@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class ApplicationList extends Widget
{
    /** Current application, application query */
    var $application = null;

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

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

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

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

        $cnt = 0;

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

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

        return $cnt;
    }

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

        $this->out->elementStart('a', array('href' => common_local_url('showapplication',
                                                                       array('id' => $this->application->id)),
                                            'class' => 'h-card'));

        if (!empty($this->application->icon)) {
            $this->out->element('img', array('src' => $this->application->icon,
                                             'class' => 'avatar u-photo'));
        }

        $this->out->text($this->application->name);
        $this->out->elementEnd('a');

        $this->out->raw(' by ');

        $this->out->element('a', array('href' => $this->application->homepage,
                                       'class' => 'u-url'),
                            $this->application->organization);

        $this->out->element('p', 'note', $this->application->description);
        $this->out->elementEnd('li');

    }

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


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

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

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

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

    var $group = null;
    var $profile = null;

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

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

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

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

    /**
     * Action of the form
     *
     * @return string URL of the action
     */
    function action()
    {
        $params = array();
        if ($this->profile) {
            $params['profile_id'] = $this->profile->id;
        }
        return common_local_url('approvegroup',
                                array('id' => $this->group->id), $params);
    }

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

    function formActions()
    {
        // TRANS: Submit button text to accept a group membership request on approve group form.
        $this->out->submit('approve', _m('BUTTON','Accept'));
        // TRANS: Submit button text to reject a group membership request on approve group form.
        $this->out->submit('cancel', _m('BUTTON','Reject'));
    }
}


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

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

/**
 * Form for approving or reject a pending subscription request
 *
 * @category Form
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @author   Sarven Capadisli <csarven@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 *
 * @see      UnsubscribeForm
 */
class ApproveSubForm extends Form
{
    var $profile = null;

    /**
     * Constructor
     *
     * @param HTMLOutputter $out   output channel
     * @param Profile       $profile user whose request to accept or drop
     */
    function __construct($out=null, $profile=null)
    {
        parent::__construct($out);

        $this->profile = $profile;
    }

    /**
     * ID of the form
     *
     * @return string ID of the form
     */
    function id()
    {
        return 'sub-queue-' . $this->profile->id;
    }

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

    /**
     * Action of the form
     *
     * @return string URL of the action
     */
    function action()
    {
        $params = array();
        if ($this->profile) {
            $params['profile_id'] = $this->profile->id;
        }
        return common_local_url('approvesub',
                                array(), $params);
    }

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

    function formActions()
    {
        // TRANS: Submit button text to accept a subscription request on approve sub form.
        $this->out->submit($this->id().'-approve', _m('BUTTON','Accept'), 'submit approve', 'approve');
        // TRANS: Submit button text to reject a subscription request on approve sub form.
        $this->out->submit($this->id().'-cancel', _m('BUTTON','Reject'), 'submit cancel', 'cancel');
    }
}


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

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

class ArrayWrapper
{
    var $_items = null;
    var $_count = 0;
    var $N = 0;
    var $_i = -1;

    function __construct($items)
    {
        $this->_items = $items;
        $this->_count = count($this->_items);
        $this->N = $this->_count;
    }

    function fetch()
    {
        if (!$this->_items) {
            return false;
        }
        $this->_i++;
        if ($this->_i < $this->_count) {
            return true;
        } else {
            return false;
        }
    }

	function fetchAll($k= false, $v = false, $method = false)
	{
		if ($k !== false || $v !== false || $method !== false)
		{
			$item =& $this->_items[$this->_i];
			return $item->fetchAll($k, $v, $method);
		}
		return $this->_items;
	}

    function __set($name, $value)
    {
        $item =& $this->_items[$this->_i];
        $item->$name = $value;
        return $item->$name;
    }

    function __get($name)
    {
        $item =& $this->_items[$this->_i];
        return $item->$name;
    }

    function __isset($name)
    {
        $item =& $this->_items[$this->_i];
        return isset($item->$name);
    }

    function __unset($name)
    {
        $item =& $this->_items[$this->_i];
        unset($item->$name);
    }

    function __call($name, $args)
    {
        $item =& $this->_items[$this->_i];
        if (!is_object($item)) {
            common_log(LOG_ERR, "Invalid entry " . var_export($item, true) . " at index $this->_i of $this->N; calling $name()");
            throw new ServerException("Internal error: bad entry in array wrapper list.");
        }
        return call_user_func_array(array($item, $name), $args);
    }
}


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

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

class Atom10FeedException extends Exception
{
}

/**
 * Class for building an Atom feed in memory.  Get the finished doc
 * as a string with Atom10Feed::getString().
 *
 * @category Feed
 * @package  StatusNet
 * @author   Zach Copley <zach@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class Atom10Feed extends XMLStringer
{
    public  $xw;

    // @fixme most of these should probably be read-only properties
    private $namespaces;
    private $authors;
    private $subject;
    private $categories;
    private $contributors;
    private $generator;
    private $icon;
    private $links;
    private $selfLink;
    private $selfLinkType;
    public $logo;
    private $rights;
    public $subtitle;
    public $title;
    private $published;
    private $updated;
    private $entries;

    /**
     * Constructor
     *
     * @param boolean $indent  flag to turn indenting on or off
     *
     * @return void
     */
    function __construct($indent = true) {
        parent::__construct($indent);
        $this->namespaces = array();
        $this->authors    = array();
        $this->links      = array();
        $this->entries    = array();
        $this->addNamespace('', 'http://www.w3.org/2005/Atom');
    }

    /**
     * Add another namespace to the feed
     *
     * @param string $namespace the namespace
     * @param string $uri       namspace uri
     *
     * @return void
     */
    function addNamespace($namespace, $uri)
    {
        $ns = array($namespace => $uri);
        $this->namespaces = array_merge($this->namespaces, $ns);
    }

    function addAuthor($name, $uri = null, $email = null)
    {
        $xs = new XMLStringer(true);

        $xs->elementStart('author');

        if (!empty($name)) {
            $xs->element('name', null, $name);
        } else {
            throw new Atom10FeedException(
                // TRANS: Atom feed exception thrown when an author element does not contain a name element.
                _('Author element must contain a name element.')
            );
        }

        if (isset($uri)) {
            $xs->element('uri', null, $uri);
        }

        if (isset($email)) {
            $xs->element('email', null, $email);
        }

        $xs->elementEnd('author');

        array_push($this->authors, $xs->getString());
    }

    /**
     * Add an Author to the feed via raw XML string
     *
     * @param string $xmlAuthor An XML string representation author
     *
     * @return void
     */
    function addAuthorRaw($xmlAuthor)
    {
        array_push($this->authors, $xmlAuthor);
    }

    function renderAuthors()
    {
        foreach ($this->authors as $author) {
            $this->raw($author);
        }
    }

    function getNamespaces()
    {
        return $this->namespaces;
    }

    function initFeed()
    {
        $this->startXML();
        $commonAttrs = array('xml:lang' => 'en-US');
        foreach ($this->namespaces as $prefix => $uri) {
            if ($prefix == '') {
                $attr = 'xmlns';
            } else {
                $attr = 'xmlns:' . $prefix;
            }
            $commonAttrs[$attr] = $uri;
        }
        $this->elementStart('feed', $commonAttrs);

        $this->element(
            'generator', array(
                'uri'     => 'https://gnu.io/social',
                'version' => GNUSOCIAL_VERSION
            ),
            'GNU social'
        );

        $this->element('id', null, $this->id);
        $this->element('title', null, $this->title);
        $this->element('subtitle', null, $this->subtitle);

        if (!empty($this->logo)) {
            $this->element('logo', null, $this->logo);
        }

        $this->element('updated', null, $this->updated);

        $this->renderAuthors();

        if ($this->selfLink) {
            $this->addLink($this->selfLink, array('rel' => 'self',
                                                  'type' => $this->selfLinkType));
        }
        $this->renderLinks();
    }

    /**
     * Check that all required elements have been set, etc.
     * Throws an Atom10FeedException if something's missing.
     *
     * @return void
     */
    function validate()
    {
    }

    function renderLinks()
    {
        foreach ($this->links as $attrs)
        {
            $this->element('link', $attrs);
        }
    }

    function addEntryRaw($xmlEntry)
    {
        array_push($this->entries, $xmlEntry);
    }

    function addEntry($entry)
    {
        array_push($this->entries, $entry->getString());
    }

    function renderEntries()
    {
        foreach ($this->entries as $entry) {
            $this->raw($entry);
        }
    }

    function endFeed()
    {
        $this->elementEnd('feed');
        $this->xw->endDocument();
    }

    function getString()
    {
        if (Event::handle('StartApiAtom', array($this))) {

            $this->validate();
            $this->initFeed();

            if (!empty($this->subject)) {
                $this->raw($this->subject);
            }

            $this->renderEntries();
            $this->endFeed();

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

        return $this->xw->outputMemory();
    }

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

    function setSelfLink($url, $type='application/atom+xml')
    {
        $this->selfLink = $url;
        $this->selfLinkType = $type;
    }

    function setTitle($title)
    {
        $this->title = $title;
    }

    function setSubtitle($subtitle)
    {
        $this->subtitle = $subtitle;
    }

    function setLogo($logo)
    {
        $this->logo = $logo;
    }

    function setUpdated($dt)
    {
        $this->updated = common_date_iso8601($dt);
    }

    function setPublished($dt)
    {
        $this->published = common_date_iso8601($dt);
    }

    /**
     * Adds a link element into the Atom document
     *
     * Assumes you want rel="alternate" and type="text/html" unless
     * you send in $otherAttrs.
     *
     * @param string $uri            the uri the href needs to point to
     * @param array  $otherAttrs     other attributes to stick in
     *
     * @return void
     */
    function addLink($uri, $otherAttrs = null) {
        $attrs = array('href' => $uri);

        if (is_null($otherAttrs)) {
            $attrs['rel']  = 'alternate';
            $attrs['type'] = 'text/html';
        } else {
            $attrs = array_merge($attrs, $otherAttrs);
        }

        array_push($this->links, $attrs);
    }
}


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

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

class AtomCategory
{
    public $term;
    public $scheme;
    public $label;

    function __construct($element=null)
    {
        if ($element && $element->attributes) {
            $this->term = $this->extract($element, 'term');
            $this->scheme = $this->extract($element, 'scheme');
            $this->label = $this->extract($element, 'label');
        }
    }

    protected function extract($element, $attrib)
    {
        $node = $element->attributes->getNamedItemNS(Activity::ATOM, $attrib);
        if ($node) {
            return trim($node->textContent);
        }
        $node = $element->attributes->getNamedItem($attrib);
        if ($node) {
            return trim($node->textContent);
        }
        return null;
    }

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

    function outputTo($xo)
    {
        $attribs = array();
        if ($this->term !== null) {
            $attribs['term'] = $this->term;
        }
        if ($this->scheme !== null) {
            $attribs['scheme'] = $this->scheme;
        }
        if ($this->label !== null) {
            $attribs['label'] = $this->label;
        }
        $xo->element('category', $attribs);
    }
}


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

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

/**
 * Class for group notice feeds.  May contains a reference to the group.
 *
 * @category Feed
 * @package  StatusNet
 * @author   Zach Copley <zach@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class AtomGroupNoticeFeed extends AtomNoticeFeed
{
    private $group;

    /**
     * Constructor
     *
     * @param Group   $group   the group for the feed
     * @param User    $cur     the current authenticated user, if any
     * @param boolean $indent  flag to turn indenting on or off
     *
     * @return void
     */
    function __construct($group, $cur = null, $indent = true) {
        parent::__construct($cur, $indent);
        $this->group = $group;

        // TRANS: Title in atom group notice feed. %s is a group name.
        $title      = sprintf(_("%s timeline"), $group->nickname);
        $this->setTitle($title);

        $sitename   = common_config('site', 'name');
        $subtitle   = sprintf(
            // TRANS: Message is used as a subtitle in atom group notice feed.
            // TRANS: %1$s is a group name, %2$s is a site name.
            _('Updates from %1$s on %2$s!'),
            $group->nickname,
            $sitename
        );
        $this->setSubtitle($subtitle);

        $avatar = $group->homepage_logo;
        $logo = ($avatar) ? $avatar : User_group::defaultLogo(AVATAR_PROFILE_SIZE);
        $this->setLogo($logo);

        $this->setUpdated('now');

        $self = common_local_url('ApiTimelineGroup',
                                 array('id' => $group->id,
                                       'format' => 'atom'));
        $this->setId($self);
        $this->setSelfLink($self);

        $ao = ActivityObject::fromGroup($group);

        $this->addAuthorRaw($ao->asString('author'));

        $this->addLink($group->homeUrl());
    }

    function getGroup()
    {
        return $this->group;
    }

    function initFeed()
    {
        parent::initFeed();

        $attrs = array();

        if (!empty($this->cur)) {
            $attrs['member'] = $this->cur->isMember($this->group)
                ? 'true' : 'false';
            $attrs['blocked'] = Group_block::isBlocked(
                $this->group,
                $this->cur->getProfile()
            ) ? 'true' : 'false';
        }

        $attrs['member_count'] = $this->group->getMemberCount();

        $this->element('statusnet:group_info', $attrs);
    }
}


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

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

/**
 * Class for list notice feeds.  May contain a reference to the list.
 *
 * @category Feed
 * @package  StatusNet
 * @author   Zach Copley <zach@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class AtomListNoticeFeed extends AtomNoticeFeed
{
    private $list;
    private $tagger;

    /**
     * Constructor
     *
     * @param List    $list    the list for the feed
     * @param User    $cur     the current authenticated user, if any
     * @param boolean $indent  flag to turn indenting on or off
     *
     * @return void
     */
    function __construct($list, $cur = null, $indent = true) {
        parent::__construct($cur, $indent);
        $this->list = $list;
        $this->tagger = Profile::getKV('id', $list->tagger);

        // TRANS: Title in atom list notice feed. %1$s is a list name, %2$s is a tagger's nickname.
        $title = sprintf(_('Timeline for people in list %1$s by %2$s'), $list->tag, $this->tagger->nickname);
        $this->setTitle($title);

        $sitename   = common_config('site', 'name');
        $subtitle   = sprintf(
            // TRANS: Message is used as a subtitle in atom list notice feed.
            // TRANS: %1$s is a tagger's nickname, %2$s is a list name, %3$s is a site name.
            _('Updates from %1$s\'s list %2$s on %3$s!'),
            $this->tagger->nickname,
            $list->tag,
            $sitename
        );
        $this->setSubtitle($subtitle);

        $avatar = $this->tagger->avatarUrl(AVATAR_PROFILE_SIZE);
        $this->setLogo($avatar);

        $this->setUpdated('now');

        $self = common_local_url('ApiTimelineList',
                                 array('user' => $this->tagger->nickname,
                                       'id' => $list->tag,
                                       'format' => 'atom'));
        $this->setId($self);
        $this->setSelfLink($self);

        $ao = ActivityObject::fromPeopletag($this->list);

        $this->addAuthorRaw($ao->asString('author'));

        $this->addLink($this->list->getUri());
    }

    function getList()
    {
        return $this->list;
    }
}


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

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

/**
 * Class for creating a feed that represents a collection of notices. Builds the
 * feed in memory. Get the feed as a string with AtomNoticeFeed::getString().
 *
 * @category Feed
 * @package  StatusNet
 * @author   Zach Copley <zach@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class AtomNoticeFeed extends Atom10Feed
{
    var $cur;
    protected $scoped=null;

    /**
     * Constructor - adds a bunch of XML namespaces we need in our
     * notice-specific Atom feeds, and allows setting the current
     * authenticated user (useful for API methods).
     *
     * @param User    $cur     the current authenticated user (optional)
     * @param boolean $indent  Whether to indent XML output
     *
     */
    function __construct($cur = null, $indent = true) {
        parent::__construct($indent);

        $this->cur = $cur ?: common_current_user();
        $this->scoped = !is_null($this->cur) ? $this->cur->getProfile() : null;

        // Feeds containing notice info use these namespaces

        $this->addNamespace(
            'thr',
            'http://purl.org/syndication/thread/1.0'
        );

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

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

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

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

        // XXX: What should the uri be?
        $this->addNamespace(
            'ostatus',
            'http://ostatus.org/schema/1.0'
        );

        $this->addNamespace(
            'statusnet',
            'http://status.net/schema/api/1/'
        );
    }

    /**
     * Add more than one Notice to the feed
     *
     * @param mixed $notices an array of Notice objects or handle
     *
     */
    function addEntryFromNotices($notices)
    {
        if (is_array($notices)) {
            foreach ($notices as $notice) {
                $this->addEntryFromNotice($notice);
            }
        } elseif ($notices instanceof Notice) {
            while ($notices->fetch()) {
                $this->addEntryFromNotice($notices);
            }
        } else {
            throw new ServerException('addEntryFromNotices got neither an array nor a Notice object');
        }
    }

    /**
     * Add a single Notice to the feed
     *
     * @param Notice $notice a Notice to add
     */
    function addEntryFromNotice(Notice $notice)
    {
        try {
            $source = $this->showSource();
            $author = $this->showAuthor();

            $this->addEntryRaw($notice->asAtomEntry(false, $source, $author, $this->scoped));
        } catch (Exception $e) {
            common_log(LOG_ERR, $e->getMessage());
            // we continue on exceptions
        }
    }

    function showSource()
    {
        return true;
    }

    function showAuthor()
    {
        return true;
    }
}


code:
<?php
/*
 * GNU social - a federating social network
 * Copyright (C) 2015, Free Software Foundation, Inc.
 * Copyright (C) before that, 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') && !defined('STATUSNET')) { exit(1); }

abstract class AtompubAction extends ApiAuthAction
{
    protected function prepare(array $args=array())
    {
        parent::prepare($args);

        return $this->atompubPrepare();
    }

    protected function atompubPrepare() {
        return true;
    }

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

        switch ($_SERVER['REQUEST_METHOD']) {
        case 'HEAD':
            $this->handleHead();
            break;
        case 'GET':
            $this->handleGet();
            break;
        case 'POST':
            $this->handlePost();
            break;
        case 'DELETE':
            $this->handleDelete();
            break;
        default:
            // TRANS: Client exception thrown when using an unsupported HTTP method.
            throw new ClientException(_('HTTP method not supported.'), 405);
        }

        return true;
    }

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

    protected function handleGet()
    {
        throw new ClientException(_('HTTP method not supported.'), 405);
    }

    protected function handlePost()
    {
        throw new ClientException(_('HTTP method not supported.'), 405);
    }

    protected function handleDelete()
    {
        throw new ClientException(_('HTTP method not supported.'), 405);
    }

    function isReadOnly($args)
    {
        // GET/HEAD is readonly, POST and DELETE (etc?) are readwrite.
        return in_array($_SERVER['REQUEST_METHOD'], array('GET', 'HEAD'));
    }

    function requiresAuth()
    {
        // GET/HEAD don't require auth, POST and DELETE (etc?) require it.
        return !in_array($_SERVER['REQUEST_METHOD'], array('GET', 'HEAD'));
    }
}