code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Destroy a notice through the 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
 * @author    Craig Andrews <candrews@integralblue.com>
 * @author    Evan Prodromou <evan@status.net>
 * @author    Jeffery To <jeffery.to@gmail.com>
 * @author    Tom Blankenship <mac65@mac65.com>
 * @author    Mike Cochrane <mikec@mikenz.geek.nz>
 * @author    Robin Millette <robin@millette.info>
 * @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);
}

/**
 * Deletes one of the authenticating user's statuses (notices).
 *
 * @category API
 * @package  StatusNet
 * @author   Craig Andrews <candrews@integralblue.com>
 * @author   Evan Prodromou <evan@status.net>
 * @author   Jeffery To <jeffery.to@gmail.com>
 * @author   Tom Blankenship <mac65@mac65.com>
 * @author   Mike Cochrane <mikec@mikenz.geek.nz>
 * @author   Robin Millette <robin@millette.info>
 * @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 ApiStatusesDestroyAction extends ApiAuthAction
{
    var $status = null;

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

        $this->user = $this->auth_user;
        $this->notice_id = (int)$this->trimmed('id');

        if (empty($notice_id)) {
            $this->notice_id = (int)$this->arg('id');
        }

        $this->notice = Notice::getKV((int)$this->notice_id);

        return true;
     }

    /**
     * Handle the request
     *
     * Delete the notice and all related replies
     *
     * @param array $args $_REQUEST data (unused)
     *
     * @return void
     */
    function handle($args)
    {
        parent::handle($args);

        if (!in_array($this->format, array('xml', 'json'))) {
            $this->clientError(
                // TRANS: Client error displayed when coming across a non-supported API method.
                _('API method not found.'),
                404
            );
            return;
        }

        if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) {
            $this->clientError(
                // TRANS: Client error displayed trying to delete a status not using POST or DELETE.
                // TRANS: POST and DELETE should not be translated.
                _('This method requires a POST or DELETE.'),
                400,
                $this->format
            );
            return;
        }

        if (empty($this->notice)) {
            $this->clientError(
                // TRANS: Client error displayed trying to delete a status with an invalid ID.
                _('No status found with that ID.'),
                404, $this->format
            );
            return;
        }

        if ($this->user->id == $this->notice->profile_id) {
            if (Event::handle('StartDeleteOwnNotice', array($this->user, $this->notice))) {
                $this->notice->delete();
                Event::handle('EndDeleteOwnNotice', array($this->user, $this->notice));
            }
	        $this->showNotice();
        } else {
            $this->clientError(
                // TRANS: Client error displayed trying to delete a status of another user.
                _('You may not delete another user\'s status.'),
                403,
                $this->format
            );
        }
    }

    /**
     * Show the deleted notice
     *
     * @return void
     */
    function showNotice()
    {
        if (!empty($this->notice)) {
            if ($this->format == 'xml') {
                $this->showSingleXmlStatus($this->notice);
            } elseif ($this->format == 'json') {
                $this->show_single_json_status($this->notice);
            }
        }
    }
}


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

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

/**
 * Repeat a notice through the API
 *
 * @category API
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class ApiStatusesRetweetAction extends ApiAuthAction
{
    protected $needPost = true;

    var $original = null;

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

        $id = $this->trimmed('id');

        $this->original = Notice::getKV('id', $id);

        if (!$this->original instanceof Notice) {
            // TRANS: Client error displayed trying to repeat a non-existing notice through the API.
            $this->clientError(_('No such notice.'), 400, $this->format);
        }

        return true;
    }

    /**
     * Handle the request
     *
     * Make a new notice for the update, save it, and show it
     *
     * @param array $args $_REQUEST data (unused)
     *
     * @return void
     */
    protected function handle()
    {
        parent::handle();

        $repeat = $this->original->repeat($this->scoped, $this->source);

        $this->showNotice($repeat);
    }

    /**
     * Show the resulting notice
     *
     * @return void
     */
    function showNotice($notice)
    {
        if (!empty($notice)) {
            if ($this->format == 'xml') {
                $this->showSingleXmlStatus($notice);
            } elseif ($this->format == 'json') {
                $this->show_single_json_status($notice);
            }
        }
    }
}

license: mit


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Show up to 100 repeats of a notice
 *
 * 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    Evan Prodromou <evan@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

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

/**
 * Show up to 100 repeats of a notice
 *
 * @category API
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class ApiStatusesRetweetsAction extends ApiAuthAction
{
    const MAXCOUNT = 100;

    var $original = null;
    var $cnt      = self::MAXCOUNT;

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

        $id = $this->trimmed('id');

        $this->original = Notice::getKV('id', $id);

        if (empty($this->original)) {
            // TRANS: Client error displayed trying to display redents of a non-exiting notice.
            $this->clientError(_('No such notice.'),
                               400, $this->format);
            return false;
        }

        $cnt = $this->trimmed('count');

        if (empty($cnt) || !is_integer($cnt)) {
            $cnt = 100;
        } else {
            $this->cnt = min((int)$cnt, self::MAXCOUNT);
        }

        return true;
    }

    /**
     * Handle the request
     *
     * Make a new notice for the update, save it, and show it
     *
     * @param array $args $_REQUEST data (unused)
     *
     * @return void
     */
    function handle($args)
    {
        parent::handle($args);

        $strm = $this->original->repeatStream($this->cnt);

        switch ($this->format) {
        case 'xml':
            $this->showXmlTimeline($strm);
            break;
        case 'json':
            $this->showJsonTimeline($strm);
            break;
        default:
            // TRANS: Client error displayed when coming across a non-supported API method.
            $this->clientError(_('API method not found.'), $code = 404);
            break;
        }
    }

    /**
     * Return true if read only.
     *
     * MAY override
     *
     * @param array $args other arguments
     *
     * @return boolean is read only action?
     */

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


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Show a notice (as a Twitter-style status)
 *
 * 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    Craig Andrews <candrews@integralblue.com>
 * @author    Evan Prodromou <evan@status.net>
 * @author    Jeffery To <jeffery.to@gmail.com>
 * @author    Tom Blankenship <mac65@mac65.com>
 * @author    Mike Cochrane <mikec@mikenz.geek.nz>
 * @author    Robin Millette <robin@millette.info>
 * @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('GNUSOCIAL')) { exit(1); }

/**
 * Returns the notice specified by id as a Twitter-style status and inline user
 *
 * @category API
 * @package  StatusNet
 * @author   Craig Andrews <candrews@integralblue.com>
 * @author   Evan Prodromou <evan@status.net>
 * @author   Jeffery To <jeffery.to@gmail.com>
 * @author   Tom Blankenship <mac65@mac65.com>
 * @author   Mike Cochrane <mikec@mikenz.geek.nz>
 * @author   Robin Millette <robin@millette.info>
 * @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 ApiStatusesShowAction extends ApiPrivateAuthAction
{
    var $notice_id = null;
    var $notice    = null;

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

        // 'id' is an undocumented parameter in Twitter's API. Several
        // clients make use of it, so we support it too.

        // show.json?id=12345 takes precedence over /show/12345.json

        $this->notice_id = (int)$this->trimmed('id');

        $this->notice = Notice::getKV('id', $this->notice_id);
        if (!$this->notice instanceof Notice) {
            $deleted = Deleted_notice::getKV('id', $this->notice_id);
            if ($deleted instanceof Deleted_notice) {
                // TRANS: Client error displayed trying to show a deleted notice.
                $this->clientError(_('Notice deleted.'), 410);
            }
            // TRANS: Client error displayed trying to show a non-existing notice.
            $this->clientError(_('No such notice.'), 404);
        }
        if (!$this->notice->inScope($this->scoped)) {
            // TRANS: Client exception thrown when trying a view a notice the user has no access to.
            throw new ClientException(_('Access restricted.'), 403);
        }

        return true;
    }

    /**
     * Handle the request
     *
     * Check the format and show the notice
     *
     * @return void
     */
    protected function handle()
    {
        parent::handle();

        if (!in_array($this->format, array('xml', 'json', 'atom'))) {
            // TRANS: Client error displayed when coming across a non-supported API method.
            $this->clientError(_('API method not found.'), 404);
        }

        switch ($_SERVER['REQUEST_METHOD']) {
        case 'GET':
            $this->showNotice();
            break;
        case 'DELETE':
            $this->deleteNotice();
            break;
        default:
            // TRANS: Client error displayed calling an unsupported HTTP error in API status show.
            $this->clientError(_('HTTP method not supported.'), 405);
        }
    }

    /**
     * Show the notice
     *
     * @return void
     */
    function showNotice()
    {
        if (!empty($this->notice)) {
            switch ($this->format) {
            case 'xml':
                $this->showSingleXmlStatus($this->notice);
                break;
            case 'json':
                $this->show_single_json_status($this->notice);
                break;
            case 'atom':
                $this->showSingleAtomStatus($this->notice);
                break;
            default:
                // TRANS: Exception thrown requesting an unsupported notice output format.
                // TRANS: %s is the requested output format.
                throw new Exception(sprintf(_("Unsupported format: %s."), $this->format));
            }
        } else {
            // XXX: Twitter just sets a 404 header and doens't bother
            // to return an err msg

            $deleted = Deleted_notice::getKV($this->notice_id);

            if (!empty($deleted)) {
                $this->clientError(
                    // TRANS: Client error displayed requesting a deleted status.
                    _('Status deleted.'),
                    410,
                    $this->format
                );
            } else {
                $this->clientError(
                    // TRANS: Client error displayed requesting a status with an invalid ID.
                    _('No status with that ID found.'),
                    404,
                    $this->format
                );
            }
        }
    }

    /**
     * We expose AtomPub here, so non-GET/HEAD reqs must be read/write.
     *
     * @param array $args other arguments
     *
     * @return boolean true
     */

    function isReadOnly($args)
    {
        return ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD');
    }

    /**
     * When was this notice last modified?
     *
     * @return string datestamp of the latest notice in the stream
     */
    function lastModified()
    {
        if (!empty($this->notice)) {
            return strtotime($this->notice->created);
        }

        return null;
    }

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

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

        return null;
    }

    function deleteNotice()
    {
        if ($this->format != 'atom') {
            // TRANS: Client error displayed when trying to delete a notice not using the Atom format.
            $this->clientError(_('Can only delete using the Atom format.'));
        }

        if (empty($this->auth_user) ||
            ($this->notice->profile_id != $this->auth_user->id &&
             !$this->auth_user->hasRight(Right::DELETEOTHERSNOTICE))) {
            // TRANS: Client error displayed when a user has no rights to delete notices of other users.
            $this->clientError(_('Cannot delete this notice.'), 403);
        }

        if (Event::handle('StartDeleteOwnNotice', array($this->auth_user, $this->notice))) {
            $this->notice->delete();
            Event::handle('EndDeleteOwnNotice', array($this->auth_user, $this->notice));
        }

        // @fixme is there better output we could do here?

        header('HTTP/1.1 200 OK');
        header('Content-Type: text/plain');
        // TRANS: Confirmation of notice deletion in API. %d is the ID (number) of the deleted notice.
        print(sprintf(_('Deleted notice %d'), $this->notice->id));
        print("\n");
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Post a notice (update your status) through the 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
 * @author    Craig Andrews <candrews@integralblue.com>
 * @author    Evan Prodromou <evan@status.net>
 * @author    Jeffery To <jeffery.to@gmail.com>
 * @author    Tom Blankenship <mac65@mac65.com>
 * @author    Mike Cochrane <mikec@mikenz.geek.nz>
 * @author    Robin Millette <robin@millette.info>
 * @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 statusesupdate statuses/update

    @section Description
    Updates the authenticating user's status. Requires the status parameter specified below.
    Request must be a POST.

    @par URL pattern
    /api/statuses/update.:format

    @par Formats (:format)
    xml, json

    @par HTTP Method(s)
    POST

    @par Requires Authentication
    Yes

    @param status (Required) The URL-encoded text of the status update.
    @param source (Optional) The source application name, if using HTTP authentication or an anonymous OAuth consumer.
    @param in_reply_to_status_id (Optional) The ID of an existing status that the update is in reply to.
    @param lat (Optional) The latitude the status refers to.
    @param long (Optional) The longitude the status refers to.
    @param media (Optional) a media upload, such as an image or movie file.

    @sa @ref authentication
    @sa @ref apiroot

    @subsection usagenotes Usage notes

    @li The URL pattern is relative to the @ref apiroot.
    @li If the @e source parameter is not supplied the source of the status will default to 'api'. When authenticated via a registered OAuth application, the application's registered name and URL will always override the source parameter.
    @li The XML response uses GeoRSS
    to encode the latitude and longitude (see example response below <georss:point>).
    @li Data uploaded via the @e media parameter should be multipart/form-data encoded.

    @subsection exampleusage Example usage

    @verbatim
    curl -u username:password http://example.com/api/statuses/update.xml -d status='Howdy!' -d lat='30.468' -d long='-94.743'
    @endverbatim

    @subsection exampleresponse Example response

    @verbatim
    <?xml version="1.0" encoding="UTF-8"?>
    <status>
      <text>Howdy!</text>
      <truncated>false</truncated>
      <created_at>Tue Mar 30 23:28:05 +0000 2010</created_at>
      <in_reply_to_status_id/>
      <source>api</source>
      <id>26668724</id>
      <in_reply_to_user_id/>
      <in_reply_to_screen_name/>
      <geo xmlns:georss="http://www.georss.org/georss">
        <georss:point>30.468 -94.743</georss:point>
      </geo>
      <favorited>false</favorited>
      <user>
        <id>25803</id>
        <name>Jed Sanders</name>
        <screen_name>jedsanders</screen_name>
        <location>Hoop and Holler, Texas</location>
        <description>I like to think of myself as America's Favorite.</description>
        <profile_image_url>http://avatar.example.com/25803-48-20080924200604.png</profile_image_url>
        <url>http://jedsanders.net</url>
        <protected>false</protected>
        <followers_count>5</followers_count>
        <profile_background_color/>
        <profile_text_color/>
        <profile_link_color/>
        <profile_sidebar_fill_color/>
        <profile_sidebar_border_color/>
        <friends_count>2</friends_count>
        <created_at>Wed Sep 24 20:04:00 +0000 2008</created_at>
        <favourites_count>0</favourites_count>
        <utc_offset>0</utc_offset>
        <time_zone>UTC</time_zone>
        <profile_background_image_url/>
        <profile_background_tile>false</profile_background_tile>
        <statuses_count>70</statuses_count>
        <following>true</following>
        <notifications>true</notifications>
      </user>
    </status>
    @endverbatim
*/

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

/**
 * Updates the authenticating user's status (posts a notice).
 *
 * @category API
 * @package  StatusNet
 * @author   Craig Andrews <candrews@integralblue.com>
 * @author   Evan Prodromou <evan@status.net>
 * @author   Jeffery To <jeffery.to@gmail.com>
 * @author   Tom Blankenship <mac65@mac65.com>
 * @author   Mike Cochrane <mikec@mikenz.geek.nz>
 * @author   Robin Millette <robin@millette.info>
 * @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 ApiStatusesUpdateAction extends ApiAuthAction
{
    protected $needPost = true;

    var $status                = null;
    var $in_reply_to_status_id = null;
    var $lat                   = null;
    var $lon                   = null;

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

        $this->status = $this->trimmed('status');
        $this->lat    = $this->trimmed('lat');
        $this->lon    = $this->trimmed('long');

        $this->in_reply_to_status_id
            = intval($this->trimmed('in_reply_to_status_id'));

        return true;
    }

    /**
     * Handle the request
     *
     * Make a new notice for the update, save it, and show it
     *
     * @return void
     */
    protected function handle()
    {
        parent::handle();

        // Workaround for PHP returning empty $_POST and $_FILES when POST
        // length > post_max_size in php.ini

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

            $this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
        }

        if (empty($this->status)) {
            // TRANS: Client error displayed when the parameter "status" is missing.
            $this->clientError(_('Client must provide a \'status\' parameter with a value.'));
        }

        if (is_null($this->scoped)) {
            // TRANS: Client error displayed when updating a status for a non-existing user.
            $this->clientError(_('No such user.'), 404);
        }

        /* Do not call shortenlinks until the whole notice has been build */

        // Check for commands

        $inter = new CommandInterpreter();
        $cmd = $inter->handle_command($this->auth_user, $this->status);

        if ($cmd) {
            if ($this->supported($cmd)) {
                $cmd->execute(new Channel());
            }

            // Cmd not supported?  Twitter just returns your latest status.
            // And, it returns your last status whether the cmd was successful
            // or not!

            $this->notice = $this->auth_user->getCurrentNotice();
        } else {
            $reply_to = null;

            if (!empty($this->in_reply_to_status_id)) {
                // Check whether notice actually exists

                $reply = Notice::getKV($this->in_reply_to_status_id);

                if ($reply) {
                    $reply_to = $this->in_reply_to_status_id;
                } else {
                    // TRANS: Client error displayed when replying to a non-existing notice.
                    $this->clientError(_('Parent notice not found.'), 404);
                }
            }

            $upload = null;
            try {
                $upload = MediaFile::fromUpload('media', $this->scoped);
                $this->status .= ' ' . $upload->shortUrl();
                /* Do not call shortenlinks until the whole notice has been build */
            } catch (NoUploadedMediaException $e) {
                // There was no uploaded media for us today.
            }

            /* Do call shortenlinks here & check notice length since notice is about to be saved & sent */
            $status_shortened = $this->auth_user->shortenlinks($this->status);

            if (Notice::contentTooLong($status_shortened)) {
                if ($upload instanceof MediaFile) {
                    $upload->delete();
                }
                // TRANS: Client error displayed exceeding the maximum notice length.
                // TRANS: %d is the maximum lenth for a notice.
                $msg = _m('Maximum notice size is %d character, including attachment URL.',
                          'Maximum notice size is %d characters, including attachment URL.',
                          Notice::maxContent());
                /* Use HTTP 413 error code (Request Entity Too Large)
                 * instead of basic 400 for better understanding
                 */
                $this->clientError(sprintf($msg, Notice::maxContent()), 413);
            }

            $content = html_entity_decode($status_shortened, ENT_NOQUOTES, 'UTF-8');

            $options = array('reply_to' => $reply_to);

            if ($this->scoped->shareLocation()) {

                $locOptions = Notice::locationOptions($this->lat,
                                                      $this->lon,
                                                      null,
                                                      null,
                                                      $this->scoped);

                $options = array_merge($options, $locOptions);
            }

            try {
                $this->notice = Notice::saveNew(
                    $this->scoped->id,
                    $content,
                    $this->source,
                    $options
                );
            } catch (Exception $e) {
                $this->clientError($e->getMessage(), $e->getCode());
            }

            if (isset($upload)) {
                $upload->attachToNotice($this->notice);
            }
        }

        $this->showNotice();
    }

    /**
     * Show the resulting notice
     *
     * @return void
     */
    function showNotice()
    {
        if (!empty($this->notice)) {
            if ($this->format == 'xml') {
                $this->showSingleXmlStatus($this->notice);
            } elseif ($this->format == 'json') {
                $this->show_single_json_status($this->notice);
            }
        }
    }

    /**
     * Is this command supported when doing an update from the API?
     *
     * @param string $cmd the command to check for
     *
     * @return boolean true or false
     */
    function supported($cmd)
    {
        static $cmdlist = array('SubCommand', 'UnsubCommand',
            'OnCommand', 'OffCommand', 'JoinCommand', 'LeaveCommand');

        $supported = null;

        if (Event::handle('CommandSupportedAPI', array($cmd, &$supported))) {
            $supported = $supported || in_array(get_class($cmd), $cmdlist);
        }

        return $supported;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Base class for showing subscription information in the 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
 * @author    Dan Moore <dan@moore.cx>
 * @author    Evan Prodromou <evan@status.net>
 * @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')) {
    exit(1);
}

/**
 * This class outputs a list of profiles as Twitter-style user and status objects.
 * It is used by the API methods /api/statuses/(friends|followers). To support the
 * social graph methods it also can output a simple list of IDs.
 *
 * @category API
 * @package  StatusNet
 * @author   Dan Moore <dan@moore.cx>
 * @author   Evan Prodromou <evan@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/
 */
abstract class ApiSubscriptionsAction extends ApiBareAuthAction
{
    var $profiles = null;
    var $tag      = null;
    var $lite     = null;
    var $ids_only = null;

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

        $this->tag      = $this->arg('tag');

        // Note: Twitter no longer supports 'lite'
        $this->lite     = $this->arg('lite');

        $this->ids_only = $this->arg('ids_only');

        // If called as a social graph method, show 5000 per page, otherwise 100

        $this->count    = isset($this->ids_only) ?
            5000 : (int)$this->arg('count', 100);

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

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

        $this->profiles = $this->getProfiles();

        return true;
    }

    /**
     * Handle the request
     *
     * Show the profiles
     *
     * @return void
     */
    protected function handle()
    {
        parent::handle();

        if (!in_array($this->format, array('xml', 'json'))) {
            // TRANS: Client error displayed when coming across a non-supported API method.
            $this->clientError(_('API method not found.'), 404);
        }

        $this->initDocument($this->format);

        if (isset($this->ids_only)) {
            $this->showIds();
        } else {
            $this->showProfiles(isset($this->lite) ? false : true);
        }

        $this->endDocument($this->format);
    }

    /**
     * Get profiles related to the type of subscriber/subscription action
     *
     * @return array Profiles
     */
    abstract protected function getProfiles();

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

    /**
     * When was this feed last modified?
     *
     * @return string datestamp of the latest profile in the stream
     */
    function lastModified()
    {
        if (!empty($this->profiles) && (count($this->profiles) > 0)) {
            return strtotime($this->profiles[0]->created);
        }

        return null;
    }

    /**
     * An entity tag for this action
     *
     * Returns an Etag based on the action name, language, user ID, and
     * timestamps of the first and last profiles in the subscriptions list
     * There's also an indicator to show whether this action is being called
     * as /api/statuses/(friends|followers) or /api/(friends|followers)/ids
     *
     * @return string etag
     */
    function etag()
    {
        if (!empty($this->profiles) && (count($this->profiles) > 0)) {

            $last = count($this->profiles) - 1;

            return '"' . implode(
                ':',
                array($this->arg('action'),
                      common_user_cache_hash($this->auth_user),
                      common_language(),
                      $this->target->id,
                      // Caching tags.
                      isset($this->ids_only) ? 'IDs' : 'Profiles',
                      strtotime($this->profiles[0]->created),
                      strtotime($this->profiles[$last]->created))
            )
            . '"';
        }

        return null;
    }

    /**
     * Show the profiles as Twitter-style useres and statuses
     *
     * @param boolean $include_statuses Whether to include the latest status
     *                                  with each user. Default true.
     *
     * @return void
     */
    function showProfiles($include_statuses = true)
    {
        switch ($this->format) {
        case 'xml':
            $this->elementStart('users', array('type' => 'array',
                                               'xmlns:statusnet' => 'http://status.net/schema/api/1/'));
            foreach ($this->profiles as $profile) {
                $this->showProfile(
                    $profile,
                    $this->format,
                    null,
                    $include_statuses
                );
            }
            $this->elementEnd('users');
            break;
        case 'json':
            $arrays = array();
            foreach ($this->profiles as $profile) {
                $arrays[] = $this->twitterUserArray(
                    $profile,
                    $include_statuses
                );
            }
            print json_encode($arrays);
            break;
        default:
            // TRANS: Client error displayed when requesting profiles of followers in an unsupported format.
            $this->clientError(_('Unsupported format.'));
            break;
        }
    }

    /**
     * Show the IDs of the profiles only. 5000 per page. To support
     * the 'social graph' methods: /api/(friends|followers)/ids
     *
     * @return void
     */
    function showIds()
    {
        switch ($this->format) {
        case 'xml':
            $this->elementStart('ids');
            foreach ($this->profiles as $profile) {
                $this->element('id', null, $profile->id);
            }
            $this->elementEnd('ids');
            break;
        case 'json':
            $ids = array();
            foreach ($this->profiles as $profile) {
                $ids[] = (int)$profile->id;
            }
            print json_encode($ids);
            break;
        default:
            // TRANS: Client error displayed when requesting IDs of followers in an unsupported format.
            $this->clientError(_('Unsupported format.'));
            break;
        }
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Show the friends 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  API
 * @package   StatusNet
 * @author    Craig Andrews <candrews@integralblue.com>
 * @author    Evan Prodromou <evan@status.net>
 * @author    Jeffery To <jeffery.to@gmail.com>
 * @author    mac65 <mac65@mac65.com>
 * @author    Mike Cochrane <mikec@mikenz.geek.nz>
 * @author    Robin Millette <robin@millette.info>
 * @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 friendstimeline statuses/friends_timeline

    @section Description
    Returns the 20 most recent statuses posted by the authenticating
    user and that user's friends. This is the equivalent of "You and
    friends" page in the web interface.

    @par URL patterns
    @li /api/statuses/friends_timeline.:format
    @li /api/statuses/friends_timeline/:id.:format

    @par Formats (:format)
    xml, json, rss, atom

    @par ID (:id)
    username, user id

    @par HTTP Method(s)
    GET

    @par Requires Authentication
    Sometimes (see: @ref authentication)

    @param user_id (Optional) Specifies a user by ID
    @param screen_name (Optional) Specifies a user by screename (nickname)
    @param since_id (Optional) Returns only statuses with an ID greater
    than (that is, more recent than) the specified ID.
    @param max_id (Optional) Returns only statuses with an ID less than
    (that is, older than) or equal to the specified ID.
    @param count (Optional) Specifies the number of statuses to retrieve.
    @param page (Optional) Specifies the page of results to retrieve.

    @sa @ref authentication
    @sa @ref apiroot

    @subsection usagenotes Usage notes
    @li The URL pattern is relative to the @ref apiroot.
    @li The XML response uses GeoRSS
    to encode the latitude and longitude (see example response below <georss:point>).

    @subsection exampleusage Example usage

    @verbatim
    curl http://identi.ca/api/statuses/friends_timeline/evan.xml?count=1&page=2
    @endverbatim

    @subsection exampleresponse Example response

    @verbatim
    <?xml version="1.0"?>
    <statuses type="array">
      <status>
        <text>back from the !yul !drupal meet with Evolving Web folk, @anarcat, @webchick and others, and an interesting refresher on SQL indexing</text>
        <truncated>false</truncated>
        <created_at>Wed Mar 31 01:33:02 +0000 2010</created_at>
        <in_reply_to_status_id/>
        <source><a href="http://code.google.com/p/microblog-purple/">mbpidgin</a></source>
        <id>26674201</id>
        <in_reply_to_user_id/>
        <in_reply_to_screen_name/>
        <geo/>
        <favorited>false</favorited>
        <user>
          <id>246</id>
          <name>Mark</name>
          <screen_name>lambic</screen_name>
          <location>Montreal, Canada</location>
          <description>Geek</description>
          <profile_image_url>http://avatar.identi.ca/246-48-20080702141545.png</profile_image_url>
          <url>http://lambic.co.uk</url>
          <protected>false</protected>
          <followers_count>73</followers_count>
          <profile_background_color>#F0F2F5</profile_background_color>
          <profile_text_color/>
          <profile_link_color>#002E6E</profile_link_color>
          <profile_sidebar_fill_color>#CEE1E9</profile_sidebar_fill_color>
          <profile_sidebar_border_color/>
          <friends_count>58</friends_count>
          <created_at>Wed Jul 02 14:12:15 +0000 2008</created_at>
          <favourites_count>2</favourites_count>
          <utc_offset>-14400</utc_offset>
          <time_zone>US/Eastern</time_zone>
          <profile_background_image_url/>
          <profile_background_tile>false</profile_background_tile>
          <statuses_count>933</statuses_count>
          <following>false</following>
          <notifications>false</notifications>
        </user>
      </status>
    </statuses>
    @endverbatim
*/

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

/**
 * Returns the most recent notices (default 20) posted by the target user.
 * This is the equivalent of 'You and friends' page accessed via Web.
 *
 * @category API
 * @package  StatusNet
 * @author   Craig Andrews <candrews@integralblue.com>
 * @author   Evan Prodromou <evan@status.net>
 * @author   Jeffery To <jeffery.to@gmail.com>
 * @author   mac65 <mac65@mac65.com>
 * @author   Mike Cochrane <mikec@mikenz.geek.nz>
 * @author   Robin Millette <robin@millette.info>
 * @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 ApiTimelineFriendsAction extends ApiBareAuthAction
{
    var $notices  = null;

    /**
     * Take arguments for running
     *
     * @param array $args $_REQUEST args
     *
     * @return boolean success flag
     *
     */
    protected function prepare(array $args=array())
    {
        parent::prepare($args);
        $this->target = $this->getTargetProfile($this->arg('id'));

        if (!($this->target instanceof Profile)) {
            // TRANS: Client error displayed when requesting dents of a user and friends for a user that does not exist.
            $this->clientError(_('No such user.'), 404);
        }

        $this->notices = $this->getNotices();

        return true;
    }

    /**
     * Handle the request
     *
     * Just show the notices
     *
     * @return void
     */
    protected function handle()
    {
        parent::handle();
        $this->showTimeline();
    }

    /**
     * Show the timeline of notices
     *
     * @return void
     */
    function showTimeline()
    {
        $sitename   = common_config('site', 'name');
        // TRANS: Title of API timeline for a user and friends.
        // TRANS: %s is a username.
        $title      = sprintf(_("%s and friends"), $this->target->nickname);
        $taguribase = TagURI::base();
        $id         = "tag:$taguribase:FriendsTimeline:" . $this->target->id;

        $subtitle = sprintf(
            // TRANS: Message is used as a subtitle. %1$s is a user nickname, %2$s is a site name.
            _('Updates from %1$s and friends on %2$s!'),
            $this->target->nickname,
            $sitename
        );

        $logo = $this->target->avatarUrl(AVATAR_PROFILE_SIZE);
        $link = common_local_url('all',
                    array('nickname' => $this->target->nickname));
        $self = $this->getSelfUri();

        switch($this->format) {
        case 'xml':
            $this->showXmlTimeline($this->notices);
            break;
        case 'rss':

            $this->showRssTimeline(
                $this->notices,
                $title,
                $link,
                $subtitle,
                null,
                $logo,
                $self
            );
            break;
        case 'atom':
            header('Content-Type: application/atom+xml; charset=utf-8');

            $atom = new AtomNoticeFeed($this->auth_user);

            $atom->setId($id);
            $atom->setTitle($title);
            $atom->setSubtitle($subtitle);
            $atom->setLogo($logo);
            $atom->setUpdated('now');
            $atom->addLink($link);
            $atom->setSelfLink($self);

            $atom->addEntryFromNotices($this->notices);

            $this->raw($atom->getString());

            break;
        case 'json':
            $this->showJsonTimeline($this->notices);
            break;
        case 'as':
            header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
            $doc = new ActivityStreamJSONDocument($this->auth_user, $title);
            $doc->addLink($link, 'alternate', 'text/html');
            $doc->addItemsFromNotices($this->notices);
            $this->raw($doc->asString());
            break;
        default:
            // TRANS: Client error displayed when coming across a non-supported API method.
            $this->clientError(_('API method not found.'), 404);
        }
    }

    /**
     * Get notices
     *
     * @return array notices
     */
    function getNotices()
    {
        $notices = array();

        $stream = new InboxNoticeStream($this->target, $this->scoped);

        $notice = $stream->getNotices(($this->page-1) * $this->count,
                                      $this->count,
                                      $this->since_id,
                                      $this->max_id);

        while ($notice->fetch()) {
            $notices[] = clone($notice);
        }

        return $notices;
    }

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

    /**
     * When was this feed last modified?
     *
     * @return string datestamp of the latest notice in the stream
     */
    function lastModified()
    {
        if (!empty($this->notices) && (count($this->notices) > 0)) {
            return strtotime($this->notices[0]->created);
        }

        return null;
    }

    /**
     * An entity tag for this stream
     *
     * Returns an Etag based on the action name, language, user ID, and
     * timestamps of the first and last notice in the timeline
     *
     * @return string etag
     */
    function etag()
    {
        if (!empty($this->notices) && (count($this->notices) > 0)) {
            $last = count($this->notices) - 1;

            return '"' . implode(
                                 ':',
                                 array($this->arg('action'),
                                       common_user_cache_hash($this->auth_user),
                                       common_language(),
                                       $this->target->id,
                                       strtotime($this->notices[0]->created),
                                       strtotime($this->notices[$last]->created))
                                 )
              . '"';
        }

        return null;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Show a group's 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  API
 * @package   StatusNet
 * @author    Craig Andrews <candrews@integralblue.com>
 * @author    Evan Prodromou <evan@status.net>
 * @author    Jeffery To <jeffery.to@gmail.com>
 * @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/
 */

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

/**
 * Returns the most recent notices (default 20) posted to the group specified by ID
 *
 * @category API
 * @package  StatusNet
 * @author   Craig Andrews <candrews@integralblue.com>
 * @author   Evan Prodromou <evan@status.net>
 * @author   Jeffery To <jeffery.to@gmail.com>
 * @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 ApiTimelineGroupAction extends ApiPrivateAuthAction
{
    var $group   = null;
    var $notices = null;

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

        $this->group   = $this->getTargetGroup($this->arg('id'));

        return true;
    }

    /**
     * Handle the request
     *
     * Just show the notices
     *
     * @return void
     */
    protected function handle()
    {
        parent::handle();

        if (empty($this->group)) {
            // TRANS: Client error displayed requesting most recent notices to a group for a non-existing group.
            $this->clientError(_('Group not found.'), 404);
        }

        $this->notices = $this->getNotices();
        $this->showTimeline();
    }

    /**
     * Show the timeline of notices
     *
     * @return void
     */
    function showTimeline()
    {
        // We'll pull common formatting out of this for other formats
        $atom = new AtomGroupNoticeFeed($this->group, $this->auth_user);

        $self = $this->getSelfUri();

        $link = common_local_url('showgroup',
                                 array('nickname' => $this->group->nickname));

        switch($this->format) {
        case 'xml':
            $this->showXmlTimeline($this->notices);
            break;
        case 'rss':
            $this->showRssTimeline(
                $this->notices,
                $atom->title,
                $this->group->homeUrl(),
                $atom->subtitle,
                null,
                $atom->logo,
                $self
            );
            break;
        case 'atom':
            header('Content-Type: application/atom+xml; charset=utf-8');
                $atom->addEntryFromNotices($this->notices);
                $this->raw($atom->getString());
            break;
        case 'json':
            $this->showJsonTimeline($this->notices);
            break;
        case 'as':
            header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
            $doc = new ActivityStreamJSONDocument($this->auth_user);
            $doc->setTitle($atom->title);
            $doc->addLink($link, 'alternate', 'text/html');
            $doc->addItemsFromNotices($this->notices);
            $this->raw($doc->asString());
            break;
        default:
            // TRANS: Client error displayed when trying to handle an unknown API method.
            $this->clientError(_('API method not found.'), 404);
        }
    }

    /**
     * Get notices
     *
     * @return array notices
     */
    function getNotices()
    {
        $notices = array();

        $notice = $this->group->getNotices(
            ($this->page-1) * $this->count,
            $this->count,
            $this->since_id,
            $this->max_id
        );

        while ($notice->fetch()) {
            $notices[] = clone($notice);
        }

        return $notices;
    }

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

    /**
     * When was this feed last modified?
     *
     * @return string datestamp of the latest notice in the stream
     */
    function lastModified()
    {
        if (!empty($this->notices) && (count($this->notices) > 0)) {
            return strtotime($this->notices[0]->created);
        }

        return null;
    }

    /**
     * An entity tag for this stream
     *
     * Returns an Etag based on the action name, language, group ID and
     * timestamps of the first and last notice in the timeline
     *
     * @return string etag
     */
    function etag()
    {
        if (!empty($this->notices) && (count($this->notices) > 0)) {

            $last = count($this->notices) - 1;

            return '"' . implode(
                ':',
                array($this->arg('action'),
                      common_user_cache_hash($this->auth_user),
                      common_language(),
                      $this->group->id,
                      strtotime($this->notices[0]->created),
                      strtotime($this->notices[$last]->created))
            )
            . '"';
        }

        return null;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Show the home 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  API
 * @package   StatusNet
 * @author    Craig Andrews <candrews@integralblue.com>
 * @author    Evan Prodromou <evan@status.net>
 * @author    Jeffery To <jeffery.to@gmail.com>
 * @author    mac65 <mac65@mac65.com>
 * @author    Mike Cochrane <mikec@mikenz.geek.nz>
 * @author    Robin Millette <robin@millette.info>
 * @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);
}

/**
 * Returns the most recent notices (default 20) posted by the target user.
 * This is the equivalent of 'You and friends' page accessed via Web.
 *
 * @category API
 * @package  StatusNet
 * @author   Craig Andrews <candrews@integralblue.com>
 * @author   Evan Prodromou <evan@status.net>
 * @author   Jeffery To <jeffery.to@gmail.com>
 * @author   mac65 <mac65@mac65.com>
 * @author   Mike Cochrane <mikec@mikenz.geek.nz>
 * @author   Robin Millette <robin@millette.info>
 * @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 ApiTimelineHomeAction extends ApiBareAuthAction
{
    var $notices  = null;

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

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

        if (!($this->target instanceof Profile)) {
            // TRANS: Client error displayed when requesting most recent dents by user and friends for a non-existing user.
            $this->clientError(_('No such user.'), 404);
        }

        $this->notices = $this->getNotices();

        return true;
    }

    /**
     * Handle the request
     *
     * Just show the notices
     *
     * @return void
     */
    protected function handle()
    {
        parent::handle();
        $this->showTimeline();
    }

    /**
     * Show the timeline of notices
     *
     * @return void
     */
    function showTimeline()
    {
        $sitename   = common_config('site', 'name');
        // TRANS: Timeline title for user and friends. %s is a user nickname.
        $title      = sprintf(_("%s and friends"), $this->target->nickname);
        $taguribase = TagURI::base();
        $id         = "tag:$taguribase:HomeTimeline:" . $this->target->id;

        $subtitle   = sprintf(
            // TRANS: Message is used as a subtitle. %1$s is a user nickname, %2$s is a site name.
            _('Updates from %1$s and friends on %2$s!'),
            $this->target->nickname, $sitename
        );

        $logo = $this->target->avatarUrl(AVATAR_PROFILE_SIZE);
        $link = common_local_url('all',
                    array('nickname' => $this->target->nickname));
        $self = $this->getSelfUri();

        switch($this->format) {
        case 'xml':
            $this->showXmlTimeline($this->notices);
            break;
        case 'rss':
            $this->showRssTimeline(
                $this->notices,
                $title,
                $link,
                $subtitle,
                null,
                $logo,
                $self
            );
            break;
        case 'atom':

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

            $atom = new AtomNoticeFeed($this->auth_user);

            $atom->setId($id);
            $atom->setTitle($title);
            $atom->setSubtitle($subtitle);
            $atom->setLogo($logo);
            $atom->setUpdated('now');

            $atom->addLink($link);
            $atom->setSelfLink($self);

            $atom->addEntryFromNotices($this->notices);
            $this->raw($atom->getString());

            break;
        case 'json':
            $this->showJsonTimeline($this->notices);
            break;
        case 'as':
            header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
            $doc = new ActivityStreamJSONDocument($this->auth_user);
            $doc->setTitle($title);
            $doc->addLink($link, 'alternate', 'text/html');
            $doc->addItemsFromNotices($this->notices);
            $this->raw($doc->asString());
            break;
        default:
            // TRANS: Client error displayed when coming across a non-supported API method.
            $this->clientError(_('API method not found.'), 404);
        }
    }

    /**
     * Get notices
     *
     * @return array notices
     */
    function getNotices()
    {
        $notices = array();

        $stream = new InboxNoticeStream($this->target, $this->scoped);

        $notice = $stream->getNotices(($this->page-1) * $this->count,
                                      $this->count,
                                      $this->since_id,
                                      $this->max_id);

        while ($notice->fetch()) {
            $notices[] = clone($notice);
        }

        return $notices;
    }

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

    /**
     * When was this feed last modified?
     *
     * @return string datestamp of the latest notice in the stream
     */
    function lastModified()
    {
        if (!empty($this->notices) && (count($this->notices) > 0)) {
            return strtotime($this->notices[0]->created);
        }

        return null;
    }

    /**
     * An entity tag for this stream
     *
     * Returns an Etag based on the action name, language, user ID, and
     * timestamps of the first and last notice in the timeline
     *
     * @return string etag
     */
    function etag()
    {
        if (!empty($this->notices) && (count($this->notices) > 0)) {

            $last = count($this->notices) - 1;

            return '"' . implode(
                ':',
                array($this->arg('action'),
                      common_user_cache_hash($this->auth_user),
                      common_language(),
                      $this->target->id,
                      strtotime($this->notices[0]->created),
                      strtotime($this->notices[$last]->created))
            )
            . '"';
        }

        return null;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Show a list's 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  API
 * @package   StatusNet
 * @author    Craig Andrews <candrews@integralblue.com>
 * @author    Evan Prodromou <evan@status.net>
 * @author    Jeffery To <jeffery.to@gmail.com>
 * @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);
}

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

/**
 * Returns the most recent notices (default 20) posted to the list specified by ID
 *
 * @category API
 * @package  StatusNet
 * @author   Craig Andrews <candrews@integralblue.com>
 * @author   Evan Prodromou <evan@status.net>
 * @author   Jeffery To <jeffery.to@gmail.com>
 * @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 ApiTimelineListAction extends ApiPrivateAuthAction
{

    var $list   = null;
    var $notices = array();
    var $next_cursor = 0;
    var $prev_cursor = 0;
    var $cursor = -1;

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

        $this->cursor = (int) $this->arg('cursor', -1);
        $this->list = $this->getTargetList($this->arg('user'), $this->arg('id'));

        return true;
    }

    /**
     * Handle the request
     *
     * Just show the notices
     *
     * @return void
     */
    protected function handle()
    {
        parent::handle();

        if (empty($this->list)) {
            // TRANS: Client error displayed trying to perform an action related to a non-existing list.
            $this->clientError(_('List not found.'), 404);
        }

        $this->getNotices();
        $this->showTimeline();
    }

    /**
     * Show the timeline of notices
     *
     * @return void
     */
    function showTimeline()
    {
        // We'll pull common formatting out of this for other formats
        $atom = new AtomListNoticeFeed($this->list, $this->auth_user);

        $self = $this->getSelfUri();

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

            foreach ($this->notices as $n) {
                $twitter_status = $this->twitterStatusArray($n);
                $this->showTwitterXmlStatus($twitter_status);
            }

            $this->elementEnd('statuses');
            $this->element('next_cursor', null, $this->next_cursor);
            $this->element('previous_cursor', null, $this->prev_cursor);
            $this->elementEnd('statuses_list');
            $this->endDocument('xml');
            break;
        case 'rss':
            $this->showRssTimeline(
                $this->notices,
                $atom->title,
                $this->list->getUri(),
                $atom->subtitle,
                null,
                $atom->logo,
                $self
            );
            break;
        case 'atom':
            header('Content-Type: application/atom+xml; charset=utf-8');

            try {
                $atom->setId($self);
                $atom->setSelfLink($self);
                $atom->addEntryFromNotices($this->notices);
                $this->raw($atom->getString());
            } catch (Atom10FeedException $e) {
                // TRANS: Server error displayed whe trying to get a timeline fails.
                // TRANS: %s is the error message.
                $this->serverError(sprintf(_('Could not generate feed for list - %s'), $e->getMessage()));
            }

            break;
        case 'json':
            $this->initDocument('json');

            $statuses = array();
            foreach ($this->notices as $n) {
                $twitter_status = $this->twitterStatusArray($n);
                array_push($statuses, $twitter_status);
            }

            $statuses_list = array('statuses' => $statuses,
                                   'next_cursor' => $this->next_cusror,
                                   'next_cursor_str' => strval($this->next_cusror),
                                   'previous_cursor' => $this->prev_cusror,
                                   'previous_cursor_str' => strval($this->prev_cusror)
                                   );
            $this->showJsonObjects($statuses_list);

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

    /**
     * Get notices
     *
     * @return array notices
     */
    function getNotices()
    {
        $fn = array($this->list, 'getNotices');
        list($this->notices, $this->next_cursor, $this->prev_cursor) =
                Profile_list::getAtCursor($fn, array(), $this->cursor, 20);
        if (!$this->notices) {
            $this->notices = array();
        }
    }

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

    /**
     * When was this feed last modified?
     *
     * @return string datestamp of the latest notice in the stream
     */
    function lastModified()
    {
        if (!empty($this->notices) && (count($this->notices) > 0)) {
            return strtotime($this->notices[0]->created);
        }

        return null;
    }

    /**
     * An entity tag for this stream
     *
     * Returns an Etag based on the action name, language, list ID and
     * timestamps of the first and last notice in the timeline
     *
     * @return string etag
     */
    function etag()
    {
        if (!empty($this->notices) && (count($this->notices) > 0)) {

            $last = count($this->notices) - 1;

            return '"' . implode(
                ':',
                array($this->arg('action'),
                      common_language(),
                      $this->list->id,
                      strtotime($this->notices[0]->created),
                      strtotime($this->notices[$last]->created))
            )
            . '"';
        }

        return null;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Show notices mentioning a user (@nickname)
 *
 * 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    Craig Andrews <candrews@integralblue.com>
 * @author    Evan Prodromou <evan@status.net>
 * @author    Jeffery To <jeffery.to@gmail.com>
 * @author    mac65 <mac65@mac65.com>
 * @author    Mike Cochrane <mikec@mikenz.geek.nz>
 * @author    Robin Millette <robin@millette.info>
 * @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);
}

/**
 * Returns the most recent (default 20) mentions (status containing @nickname)
 *
 * @category API
 * @package  StatusNet
 * @author   Craig Andrews <candrews@integralblue.com>
 * @author   Evan Prodromou <evan@status.net>
 * @author   Jeffery To <jeffery.to@gmail.com>
 * @author   mac65 <mac65@mac65.com>
 * @author   Mike Cochrane <mikec@mikenz.geek.nz>
 * @author   Robin Millette <robin@millette.info>
 * @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 ApiTimelineMentionsAction extends ApiBareAuthAction
{
    var $notices = null;

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

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

        if (!($this->target instanceof Profile)) {
            // TRANS: Client error displayed when requesting most recent mentions for a non-existing user.
            $this->clientError(_('No such user.'), 404);
        }

        $this->notices = $this->getNotices();

        return true;
    }

    /**
     * Handle the request
     *
     * Just show the notices
     *
     * @return void
     */
    protected function handle()
    {
        parent::handle();
        $this->showTimeline();
    }

    /**
     * Show the timeline of notices
     *
     * @return void
     */
    function showTimeline()
    {
        $sitename   = common_config('site', 'name');
        $title      = sprintf(
            // TRANS: Title for timeline of most recent mentions of a user.
            // TRANS: %1$s is the StatusNet sitename, %2$s is a user nickname.
            _('%1$s / Updates mentioning %2$s'),
            $sitename, $this->target->nickname
        );
        $taguribase = TagURI::base();
        $id         = "tag:$taguribase:Mentions:" . $this->target->id;

        $logo = $this->target->avatarUrl(AVATAR_PROFILE_SIZE);
        $link = common_local_url('replies',
                    array('nickname' => $this->target->nickname));
        $self = $this->getSelfUri();

        $subtitle   = sprintf(
            // TRANS: Subtitle for timeline of most recent mentions of a user.
            // TRANS: %1$s is the StatusNet sitename, %2$s is a user nickname,
            // TRANS: %3$s is a user's full name.
            _('%1$s updates that reply to updates from %3$s / %2$s.'),
            $sitename, $this->target->nickname, $this->target->getBestName()
        );

        switch($this->format) {
        case 'xml':
            $this->showXmlTimeline($this->notices);
            break;
        case 'rss':
            $this->showRssTimeline(
                $this->notices,
                $title,
                $link,
                $subtitle,
                null,
                $logo,
                $self
            );
            break;
        case 'atom':
            header('Content-Type: application/atom+xml; charset=utf-8');

            $atom = new AtomNoticeFeed($this->auth_user);

            $atom->setId($id);
            $atom->setTitle($title);
            $atom->setSubtitle($subtitle);
            $atom->setLogo($logo);
            $atom->setUpdated('now');

            $atom->addLink($link);
            $atom->setSelfLink($self);

            $atom->addEntryFromNotices($this->notices);
            $this->raw($atom->getString());

            break;
        case 'json':
            $this->showJsonTimeline($this->notices);
            break;
        case 'as':
            header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
            $doc = new ActivityStreamJSONDocument($this->auth_user);
            $doc->setTitle($title);
            $doc->addLink($link, 'alternate', 'text/html');
            $doc->addItemsFromNotices($this->notices);
            $this->raw($doc->asString());
            break;
        default:
            // TRANS: Client error displayed when coming across a non-supported API method.
            $this->clientError(_('API method not found.'), $code = 404);
            break;
        }
    }

    /**
     * Get notices
     *
     * @return array notices
     */
    function getNotices()
    {
        $notices = array();

        $stream = new ReplyNoticeStream($this->target->id, $this->scoped);

        $notice = $stream->getNotices(($this->page - 1) * $this->count,
                                      $this->count,
                                      $this->since_id,
                                      $this->max_id);

        while ($notice->fetch()) {
            $notices[] = clone($notice);
        }

        return $notices;
    }

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

    /**
     * When was this feed last modified?
     *
     * @return string datestamp of the latest notice in the stream
     */
    function lastModified()
    {
        if (!empty($this->notices) && (count($this->notices) > 0)) {
            return strtotime($this->notices[0]->created);
        }

        return null;
    }

    /**
     * An entity tag for this stream
     *
     * Returns an Etag based on the action name, language, user ID, and
     * timestamps of the first and last notice in the timeline
     *
     * @return string etag
     */
    function etag()
    {
        if (!empty($this->notices) && (count($this->notices) > 0)) {

            $last = count($this->notices) - 1;

            return '"' . implode(
                ':',
                array($this->arg('action'),
                      common_user_cache_hash($this->auth_user),
                      common_language(),
                      $this->target->id,
                      strtotime($this->notices[0]->created),
                      strtotime($this->notices[$last]->created))
            )
            . '"';
        }

        return null;
    }
}


code:
<?php

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

class ApiTimelineNetworkPublicAction extends ApiTimelinePublicAction
{
    function title()
    {
        return sprintf(_("%s network public timeline"), common_config('site', 'name'));
    }

    protected function getStream()
    {
        if (!$this->scoped instanceof Profile && common_config('public', 'localonly')) {
            $this->clientError(_('Network wide public feed is not permitted without authorization'), 403);
        }
        return new NetworkPublicNoticeStream($this->scoped);
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Show the public 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  API
 * @package   StatusNet
 * @author    Craig Andrews <candrews@integralblue.com>
 * @author    Evan Prodromou <evan@status.net>
 * @author    Jeffery To <jeffery.to@gmail.com>
 * @author    mac65 <mac65@mac65.com>
 * @author    Mike Cochrane <mikec@mikenz.geek.nz>
 * @author    Robin Millette <robin@millette.info>
 * @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);
}

/**
 * Returns the most recent notices (default 20) posted by everybody
 *
 * @category API
 * @package  StatusNet
 * @author   Craig Andrews <candrews@integralblue.com>
 * @author   Evan Prodromou <evan@status.net>
 * @author   Jeffery To <jeffery.to@gmail.com>
 * @author   mac65 <mac65@mac65.com>
 * @author   Mike Cochrane <mikec@mikenz.geek.nz>
 * @author   Robin Millette <robin@millette.info>
 * @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/
 */

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

/*! @page publictimeline statuses/public_timeline

    @section Description
    Returns the 20 most recent notices from users throughout the system who have
    uploaded their own avatars. Depending on configuration, it may or may not
    not include notices from automatic posting services.

    @par URL patterns
    @li /api/statuses/public_timeline.:format

    @par Formats (:format)
    xml, json, rss, atom

    @par HTTP Method(s)
    GET

    @par Requires Authentication
    No

    @param since_id (Optional) Returns only statuses with an ID greater
    than (that is, more recent than) the specified ID.
    @param max_id (Optional) Returns only statuses with an ID less than
    (that is, older than) or equal to the specified ID.
    @param count (Optional) Specifies the number of statuses to retrieve.
    @param page (Optional) Specifies the page of results to retrieve.

    @sa @ref apiroot

    @subsection usagenotes Usage notes
    @li The URL pattern is relative to the @ref apiroot.
    @li The XML response uses GeoRSS
    to encode the latitude and longitude (see example response below <georss:point>).

    @subsection exampleusage Example usage

    @verbatim
    curl http://identi.ca/api/statuses/friends_timeline/evan.xml?count=1&page=2
    @endverbatim

    @subsection exampleresponse Example response

    @verbatim
    <?xml version="1.0" encoding="UTF-8"?>
    <statuses type="array">
     <status>
      <text>@skwashd oh, commbank reenabled me super quick both times. but disconcerting when you don't expect it though</text>
      <truncated>false</truncated>
      <created_at>Sat Apr 17 00:49:12 +0000 2010</created_at>
      <in_reply_to_status_id>28838393</in_reply_to_status_id>
      <source>xmpp</source>
      <id>28838456</id>
      <in_reply_to_user_id>39303</in_reply_to_user_id>
      <in_reply_to_screen_name>skwashd</in_reply_to_screen_name>
      <geo></geo>
      <favorited>false</favorited>
      <user>
       <id>44517</id>
       <name>joshua may</name>
       <screen_name>notjosh</screen_name>
       <location></location>
       <description></description>
       <profile_image_url>http://avatar.identi.ca/44517-48-20090321004106.jpeg</profile_image_url>
       <url></url>
       <protected>false</protected>
       <followers_count>17</followers_count>
       <profile_background_color></profile_background_color>
       <profile_text_color></profile_text_color>
       <profile_link_color></profile_link_color>
       <profile_sidebar_fill_color></profile_sidebar_fill_color>
       <profile_sidebar_border_color></profile_sidebar_border_color>
       <friends_count>20</friends_count>
       <created_at>Sat Mar 21 00:40:25 +0000 2009</created_at>
       <favourites_count>0</favourites_count>
       <utc_offset>0</utc_offset>
       <time_zone>UTC</time_zone>
       <profile_background_image_url></profile_background_image_url>
       <profile_background_tile>false</profile_background_tile>
       <statuses_count>100</statuses_count>
       <following>false</following>
       <notifications>false</notifications>
    </user>
    </status>
    [....]
    </statuses>
@endverbatim
*/
class ApiTimelinePublicAction extends ApiPrivateAuthAction
{
    var $notices = null;

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

        $this->notices = $this->getNotices();

        return true;
    }

    /**
     * Handle the request
     *
     * Just show the notices
     *
     * @return void
     */
    protected function handle()
    {
        parent::handle();
        $this->showTimeline();
    }

    function title()
    {
        // TRANS: Title for site timeline. %s is the GNU social sitename.
        return sprintf(_("%s public timeline"), common_config('site', 'name'));
    }

    /**
     * Show the timeline of notices
     *
     * @return void
     */
    function showTimeline()
    {
        $nonapi_action = substr($this->action, strlen('apitimeline'));  // Just so we don't need to set this explicitly

        $sitelogo   = (common_config('site', 'logo')) ? common_config('site', 'logo') : Theme::path('logo.png');
        $title      = $this->title();
        $taguribase = TagURI::base();
        $id         = "tag:$taguribase:" . ucfirst($nonapi_action) . 'Timeline';    // Public or Networkpublic probably
        $link       = common_local_url($nonapi_action);
        $self       = $this->getSelfUri();
        // TRANS: Subtitle for site timeline. %s is the GNU social sitename.
        $subtitle   = sprintf(_("%s updates from everyone!"), common_config('site', 'name'));

        switch($this->format) {
        case 'xml':
            $this->showXmlTimeline($this->notices);
            break;
        case 'rss':
            $this->showRssTimeline(
                $this->notices,
                $title,
                $link,
                $subtitle,
                null,
                $sitelogo,
                $self
            );
            break;
        case 'atom':

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

            $atom = new AtomNoticeFeed($this->auth_user);

            $atom->setId($id);
            $atom->setTitle($title);
            $atom->setSubtitle($subtitle);
            $atom->setLogo($sitelogo);
            $atom->setUpdated('now');
            $atom->addLink(common_local_url($nonapi_action));
            $atom->setSelfLink($self);
            $atom->addEntryFromNotices($this->notices);

            $this->raw($atom->getString());

            break;
        case 'json':
            $this->showJsonTimeline($this->notices);
            break;
        case 'as':
            header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
            $doc = new ActivityStreamJSONDocument($this->auth_user);
            $doc->setTitle($title);
            $doc->addLink($link, 'alternate', 'text/html');
            $doc->addItemsFromNotices($this->notices);
            $this->raw($doc->asString());
            break;
        default:
            // TRANS: Client error displayed when coming across a non-supported API method.
            $this->clientError(_('API method not found.'), $code = 404);
            break;
        }
    }

    /**
     * Get notices
     *
     * @return array notices
     */
    function getNotices()
    {
        $notices = array();

        $stream = $this->getStream();

        $notice = $stream->getNotices(($this->page - 1) * $this->count,
                                      $this->count,
                                      $this->since_id,
                                      $this->max_id);

        $notices = $notice->fetchAll();

        NoticeList::prefill($notices);

        return $notices;
    }

    protected function getStream()
    {
        return new PublicNoticeStream($this->scoped);
    }

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

    /**
     * When was this feed last modified?
     *
     * @return string datestamp of the latest notice in the stream
     */
    function lastModified()
    {
        if (!empty($this->notices) && (count($this->notices) > 0)) {
            return strtotime($this->notices[0]->created);
        }

        return null;
    }

    /**
     * An entity tag for this stream
     *
     * Returns an Etag based on the action name, language, and
     * timestamps of the first and last notice in the timeline
     *
     * @return string etag
     */
    function etag()
    {
        if (!empty($this->notices) && (count($this->notices) > 0)) {

            $last = count($this->notices) - 1;

            return '"' . implode(
                ':',
                array($this->arg('action'),
                      common_user_cache_hash($this->auth_user),
                      common_language(),
                      strtotime($this->notices[0]->created),
                      strtotime($this->notices[$last]->created))
            )
            . '"';
        }

        return null;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Show authenticating user's most recent repeats
 *
 * 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    Evan Prodromou <evan@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

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

/**
 * Show authenticating user's most recent repeats
 *
 * @category API
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class ApiTimelineRetweetedByMeAction extends ApiAuthAction
{
    const DEFAULTCOUNT = 20;
    const MAXCOUNT     = 200;
    const MAXNOTICES   = 3200;

    var $repeats  = null;
    var $cnt      = self::DEFAULTCOUNT;
    var $page     = 1;
    var $since_id = null;
    var $max_id   = null;

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

        // TRANS: Server error displayed calling unimplemented API method for 'retweeted by me'.
        $this->serverError(_('Unimplemented.'), 503);

        return false;
    }

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


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Show most recent notices that are repeats in user's inbox
 *
 * 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    Evan Prodromou <evan@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

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

/**
 * Show most recent notices that are repeats in user's inbox
 *
 * @category API
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class ApiTimelineRetweetedToMeAction extends ApiAuthAction
{
    const DEFAULTCOUNT = 20;
    const MAXCOUNT     = 200;
    const MAXNOTICES   = 3200;

    var $repeats  = null;
    var $cnt      = self::DEFAULTCOUNT;
    var $page     = 1;
    var $since_id = null;
    var $max_id   = null;

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

        $cnt = $this->int('count', self::DEFAULTCOUNT, self::MAXCOUNT, 1);

        $page = $this->int('page', 1, (self::MAXNOTICES/$this->cnt));

        $since_id = $this->int('since_id');

        $max_id = $this->int('max_id');

        return true;
    }

    /**
     * Handle the request
     *
     * show a timeline of the user's repeated notices
     *
     * @param array $args $_REQUEST data (unused)
     *
     * @return void
     */
    function handle($args)
    {
        parent::handle($args);

        $offset = ($this->page-1) * $this->cnt;
        $limit  = $this->cnt;

        // TRANS: Title for Atom feed "repeated to me". %s is the user nickname.
        $title      = sprintf(_("Repeated to %s"), $this->auth_user->nickname);
        $subtitle   = sprintf(
            // @todo FIXME: $profile is not defined.
            // TRANS: Subtitle for API action that shows most recent notices that are repeats in user's inbox.
            // TRANS: %1$s is the sitename, %2$s is a user nickname, %3$s is a user profile name.
            _('%1$s notices that were to repeated to %2$s / %3$s.'),
            $sitename, $this->user->nickname, $profile->getBestName()
        );
        $taguribase = TagURI::base();
        $id         = "tag:$taguribase:RepeatedToMe:" . $this->auth_user->id;

        $link = common_local_url(
            'all',
             array('nickname' => $this->auth_user->nickname)
        );

        $strm = $this->auth_user->repeatedToMe($offset, $limit, $this->since_id, $this->max_id);

        switch ($this->format) {
        case 'xml':
            $this->showXmlTimeline($strm);
            break;
        case 'json':
            $this->showJsonTimeline($strm);
            break;
        case 'atom':
            header('Content-Type: application/atom+xml; charset=utf-8');

            $atom = new AtomNoticeFeed($this->auth_user);

            $atom->setId($id);
            $atom->setTitle($title);
            $atom->setSubtitle($subtitle);
            $atom->setUpdated('now');
            $atom->addLink($link);

            $id = $this->arg('id');

            $atom->setSelfLink($self);
            $atom->addEntryFromNotices($strm);

            $this->raw($atom->getString());

            break;
        case 'as':
            header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
            $doc = new ActivityStreamJSONDocument($this->auth_user);
            $doc->setTitle($title);
            $doc->addLink($link, 'alternate', 'text/html');
            $doc->addItemsFromNotices($strm);
            $this->raw($doc->asString());
            break;
        default:
            // TRANS: Client error displayed when coming across a non-supported API method.
            $this->clientError(_('API method not found.'), $code = 404);
            break;
        }
    }

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