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

repo_name: piratas/tortuga

license: mit


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 the latest notices for a given tag
 *
 * 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 20 most recent notices tagged by a given tag
 *
 * @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 ApiTimelineTagAction extends ApiPrivateAuthAction
{
    var $notices = null;

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

        common_debug("apitimelinetag prepare()");

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

        return true;
    }

    /**
     * Handle the request
     *
     * Just show the notices
     *
     * @param array $args $_REQUEST data (unused)
     *
     * @return void
     */
    function handle($args)
    {
        parent::handle($args);
        $this->showTimeline();
    }

    /**
     * Show the timeline of notices
     *
     * @return void
     */
    function showTimeline()
    {
        $sitename   = common_config('site', 'name');
        $sitelogo   = (common_config('site', 'logo')) ? common_config('site', 'logo') : Theme::path('logo.png');
        // TRANS: Title for timeline with lastest notices with a given tag.
        // TRANS: %s is the tag.
        $title      = sprintf(_("Notices tagged with %s"), $this->tag);
        $subtitle   = sprintf(
            // TRANS: Subtitle for timeline with lastest notices with a given tag.
            // TRANS: %1$s is the tag, $2$s is the StatusNet sitename.
            _('Updates tagged with %1$s on %2$s!'),
            $this->tag,
            $sitename
        );
        $taguribase = TagURI::base();
        $id         = "tag:$taguribase:TagTimeline:".$this->tag;

        $link = common_local_url(
            'tag',
            array('tag' => $this->tag)
        );

        $self = $this->getSelfUri();

        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($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();

        $notice = Notice_tag::getStream(
            $this->tag,
            ($this->page - 1) * $this->count,
            $this->count + 1,
            $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, 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->tag,
                      strtotime($this->notices[0]->created),
                      strtotime($this->notices[$last]->created))
            )
            . '"';
        }

        return null;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Show a user's timeline
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  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 authenticating
 * user. Another user's timeline can be requested via the id parameter. This
 * is the API equivalent of the user profile web page.
 *
 * @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 ApiTimelineUserAction extends ApiBareAuthAction
{
    var $notices = null;

    var $next_id = 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 requesting most recent notices for a non-existing user.
            $this->clientError(_('No such user.'), 404);
        }

        if (!$this->target->isLocal()) {
            $this->serverError(_('Remote user timelines are not available here yet.'), 501);
        }

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

        return true;
    }

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

        if ($this->isPost()) {
            $this->handlePost();
        } else {
            $this->showTimeline();
        }
    }

    /**
     * Show the timeline of notices
     *
     * @return void
     */
    function showTimeline()
    {
        // We'll use the shared params from the Atom stub
        // for other feed types.
        $atom = new AtomUserNoticeFeed($this->target->getUser(), $this->auth_user);

        $link = common_local_url(
                                 'showstream',
                                 array('nickname' => $this->target->nickname)
                                 );

        $self = $this->getSelfUri();

        // FriendFeed's SUP protocol
        // Also added RSS and Atom feeds

        $suplink = common_local_url('sup', null, null, $this->target->id);
        header('X-SUP-ID: ' . $suplink);

        // paging links
        $nextUrl = !empty($this->next_id)
                    ? common_local_url('ApiTimelineUser',
                                    array('format' => $this->format,
                                          'id' => $this->target->id),
                                    array('max_id' => $this->next_id))
                    : null;

        $prevExtra = array();
        if (!empty($this->notices)) {
            assert($this->notices[0] instanceof Notice);
            $prevExtra['since_id'] = $this->notices[0]->id;
        }

        $prevUrl = common_local_url('ApiTimelineUser',
                                    array('format' => $this->format,
                                          'id' => $this->target->id),
                                    $prevExtra);
        $firstUrl = common_local_url('ApiTimelineUser',
                                    array('format' => $this->format,
                                          'id' => $this->target->id));

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

            $atom->setId($self);
            $atom->setSelfLink($self);

            // Add navigation links: next, prev, first
            // Note: we use IDs rather than pages for navigation; page boundaries
            // change too quickly!

            if (!empty($this->next_id)) {
                $atom->addLink($nextUrl,
                               array('rel' => 'next',
                                     'type' => 'application/atom+xml'));
            }

            if (($this->page > 1 || !empty($this->max_id)) && !empty($this->notices)) {
                $atom->addLink($prevUrl,
                               array('rel' => 'prev',
                                     'type' => 'application/atom+xml'));
            }

            if ($this->page > 1 || !empty($this->since_id) || !empty($this->max_id)) {
                $atom->addLink($firstUrl,
                               array('rel' => 'first',
                                     'type' => 'application/atom+xml'));

            }

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

            if (!empty($this->next_id)) {
                $doc->addLink($nextUrl,
                               array('rel' => 'next',
                                     'type' => ActivityStreamJSONDocument::CONTENT_TYPE));
            }

            if (($this->page > 1 || !empty($this->max_id)) && !empty($this->notices)) {
                $doc->addLink($prevUrl,
                               array('rel' => 'prev',
                                     'type' => ActivityStreamJSONDocument::CONTENT_TYPE));
            }

            if ($this->page > 1 || !empty($this->since_id) || !empty($this->max_id)) {
                $doc->addLink($firstUrl,
                               array('rel' => 'first',
                                     'type' => ActivityStreamJSONDocument::CONTENT_TYPE));
            }

            $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();

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

        while ($notice->fetch()) {
            if (count($notices) < $this->count) {
                $notices[] = clone($notice);
            } else {
                $this->next_id = $notice->id;
                break;
            }
        }

        return $notices;
    }

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

    function handlePost()
    {
        if (empty($this->auth_user) ||
            $this->auth_user->id != $this->target->id) {
            // TRANS: Client error displayed trying to add a notice to another user's timeline.
            $this->clientError(_('Only the user can add to their own timeline.'));
        }

        // Only handle posts for Atom
        if ($this->format != 'atom') {
            // TRANS: Client error displayed when using another format than AtomPub.
            $this->clientError(_('Only accept AtomPub for Atom feeds.'));
        }

        $xml = trim(file_get_contents('php://input'));
        if (empty($xml)) {
            // TRANS: Client error displayed attempting to post an empty API notice.
            $this->clientError(_('Atom post must not be empty.'));
        }

        $old = error_reporting(error_reporting() & ~(E_WARNING | E_NOTICE));
        $dom = new DOMDocument();
        $ok = $dom->loadXML($xml);
        error_reporting($old);
        if (!$ok) {
            // TRANS: Client error displayed attempting to post an API that is not well-formed XML.
            $this->clientError(_('Atom post must be well-formed XML.'));
        }

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

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

        $saved = null;

        if (Event::handle('StartAtomPubNewActivity', array(&$activity, $this->target->getUser(), &$saved))) {
            if ($activity->verb != ActivityVerb::POST) {
                // TRANS: Client error displayed when not using the POST verb. Do not translate POST.
                $this->clientError(_('Can only handle POST activities.'));
            }

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

            if (!in_array($note->type, array(ActivityObject::NOTE,
                                             ActivityObject::BLOGENTRY,
                                             ActivityObject::STATUS))) {
                // TRANS: Client error displayed when using an unsupported activity object type.
                // TRANS: %s is the unsupported activity object type.
                $this->clientError(sprintf(_('Cannot handle activity object type "%s".'),
                                             $note->type));
            }

            $saved = $this->postNote($activity);

            Event::handle('EndAtomPubNewActivity', array($activity, $this->target->getUser(), $saved));
        }

        if (!empty($saved)) {
            header('HTTP/1.1 201 Created');
            header("Location: " . common_local_url('ApiStatusesShow', array('id' => $saved->id,
                                                                            'format' => 'atom')));
            $this->showSingleAtomStatus($saved);
        }
    }

    function postNote($activity)
    {
        $note = $activity->objects[0];

        // Use summary as fallback for content

        if (!empty($note->content)) {
            $sourceContent = $note->content;
        } else if (!empty($note->summary)) {
            $sourceContent = $note->summary;
        } else if (!empty($note->title)) {
            $sourceContent = $note->title;
        } else {
            // @fixme fetch from $sourceUrl?
            // TRANS: Client error displayed when posting a notice without content through the API.
            // TRANS: %d is the notice ID (number).
            $this->clientError(sprintf(_('No content for notice %d.'), $note->id));
        }

        // Get (safe!) HTML and text versions of the content

        $rendered = common_purify($sourceContent);
        $content = common_strip_html($rendered);

        $shortened = $this->auth_user->shortenLinks($content);

        $options = array('is_local' => Notice::LOCAL_PUBLIC,
                         'rendered' => $rendered,
                         'replies' => array(),
                         'groups' => array(),
                         'tags' => array(),
                         'urls' => array());

        // accept remote URI (not necessarily a good idea)

        common_debug("Note ID is {$note->id}");

        if (!empty($note->id)) {
            $notice = Notice::getKV('uri', trim($note->id));

            if (!empty($notice)) {
                // TRANS: Client error displayed when using another format than AtomPub.
                // TRANS: %s is the notice URI.
                $this->clientError(sprintf(_('Notice with URI "%s" already exists.'), $note->id));
            }
            common_log(LOG_NOTICE, "Saving client-supplied notice URI '$note->id'");
            $options['uri'] = $note->id;
        }

        // accept remote create time (also maybe not such a good idea)

        if (!empty($activity->time)) {
            common_log(LOG_NOTICE, "Saving client-supplied create time {$activity->time}");
            $options['created'] = common_sql_date($activity->time);
        }

        // Check for optional attributes...

        if ($activity->context instanceof ActivityContext) {

            foreach ($activity->context->attention as $uri=>$type) {
                try {
                    $profile = Profile::fromUri($uri);
                    if ($profile->isGroup()) {
                        $options['groups'][] = $profile->id;
                    } else {
                        $options['replies'][] = $uri;
                    }
                } catch (UnknownUriException $e) {
                    common_log(LOG_WARNING, sprintf('AtomPub post with unknown attention URI %s', $uri));
                }
            }

            // Maintain direct reply associations
            // @fixme what about conversation ID?

            if (!empty($activity->context->replyToID)) {
                $orig = Notice::getKV('uri',
                                          $activity->context->replyToID);
                if (!empty($orig)) {
                    $options['reply_to'] = $orig->id;
                }
            }

            $location = $activity->context->location;

            if ($location) {
                $options['lat'] = $location->lat;
                $options['lon'] = $location->lon;
                if ($location->location_id) {
                    $options['location_ns'] = $location->location_ns;
                    $options['location_id'] = $location->location_id;
                }
            }
        }

        // Atom categories <-> hashtags

        foreach ($activity->categories as $cat) {
            if ($cat->term) {
                $term = common_canonical_tag($cat->term);
                if ($term) {
                    $options['tags'][] = $term;
                }
            }
        }

        // Atom enclosures -> attachment URLs
        foreach ($activity->enclosures as $href) {
            // @fixme save these locally or....?
            $options['urls'][] = $href;
        }

        $saved = Notice::saveNew($this->target->id,
                                 $content,
                                 'atompub', // TODO: deal with this
                                 $options);

        return $saved;
    }
}


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

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

/**
 *  Returns the top ten queries that are currently trending
 *
 * @category Search
 * @package  StatusNet
 * @author   Zach Copley <zach@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 *
 * @see      ApiAction
 */
class ApiTrendsAction extends ApiPrivateAuthAction
{
    var $callback;

    /**
     * Initialization.
     *
     * @param array $args Web and URL arguments
     *
     * @return boolean false if user doesn't exist
     */
    function prepare($args)
    {
        parent::prepare($args);
        return true;
    }

    /**
     * Handle a request
     *
     * @param array $args Arguments from $_REQUEST
     *
     * @return void
     */
    function handle($args)
    {
        parent::handle($args);
        $this->showTrends();
    }

    /**
     * Output the trends
     *
     * @return void
     */
    function showTrends()
    {
        // TRANS: Server error for unfinished API method showTrends.
        $this->serverError(_('API method under construction.'), 501);
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Show a user's followers (subscribers)
 *
 * 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('GNUSOCIAL')) { exit(1); }

/**
 * Ouputs the authenticating user's followers (subscribers), each with
 * current Twitter-style status inline.  They are ordered by the order
 * in which they subscribed to the user, 100 at a time.
 *
 * @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/
 */
class ApiUserFollowersAction extends ApiSubscriptionsAction
{
    /**
     * Get the user's subscribers (followers) as an array of profiles
     *
     * @return array Profiles
     */
    protected function getProfiles()
    {
        $offset = ($this->page - 1) * $this->count;
        $limit =  $this->count + 1;

        $subs = null;

        if (isset($this->tag)) {
            $subs = $this->target->getTaggedSubscribers(
                $this->tag, $offset, $limit
            );
        } else {
            $subs = $this->target->getSubscribers(
                $offset,
                $limit
            );
        }

        $profiles = array();

        while ($subs->fetch()) {
            $profiles[] = clone($subs);
        }

        return $profiles;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Show a user's friends (subscriptions)
 *
 * 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('GNUSOCIAL')) { exit(1); }

/**
 * Ouputs the authenticating user's friends (subscriptions), each with
 * current Twitter-style status inline.  They are ordered by the date
 * in which the user subscribed to them, 100 at a time.
 *
 * @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/
 */
class ApiUserFriendsAction extends ApiSubscriptionsAction
{
    /**
     * Get the user's subscriptions (friends) as an array of profiles
     *
     * @return array Profiles
     */
    protected function getProfiles()
    {
        $offset = ($this->page - 1) * $this->count;
        $limit =  $this->count + 1;

        $subs = null;

        if (isset($this->tag)) {
            $subs = $this->target->getTaggedSubscriptions(
                $this->tag, $offset, $limit
            );
        } else {
            $subs = $this->target->getSubscribed(
                $offset,
                $limit
            );
        }

        $profiles = array();

        while ($subs->fetch()) {
            $profiles[] = clone($subs);
        }

        return $profiles;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Return a user's avatar image
 *
 * 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    Brion Vibber <brion@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

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

/**
 * Ouputs avatar URL for a user, specified by screen name.
 * Unlike most API endpoints, this returns an HTTP redirect rather than direct data.
 *
 * @category API
 * @package  StatusNet
 * @author   Brion Vibber <brion@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class ApiUserProfileImageAction extends ApiPrivateAuthAction
{
    /**
     * Take arguments for running
     *
     * @param array $args $_REQUEST args
     *
     * @return boolean success flag
     *
     */
    protected function prepare(array $args=array())
    {
        parent::prepare($args);
        $user = User::getKV('nickname', $this->arg('screen_name'));
        if (!($user instanceof User)) {
            // TRANS: Client error displayed when requesting user information for a non-existing user.
            $this->clientError(_('User not found.'), 404);
        }
        $this->target = $user->getProfile();
        $this->size = $this->arg('size');

        return true;
    }

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

        $size = $this->avatarSize();
        $url  = $this->target->avatarUrl($size);

        // We don't actually output JSON or XML data -- redirect!
        common_redirect($url, 302);
    }

    /**
     * Get the appropriate pixel size for an avatar based on the request...
     *
     * @return int
     */
    private function avatarSize()
    {
        switch ($this->size) {
            case 'mini':
                return AVATAR_MINI_SIZE; // 24x24
            case 'bigger':
                return AVATAR_PROFILE_SIZE; // Twitter does 73x73, but we do 96x96
            case 'normal': // fall through
            default:
                return AVATAR_STREAM_SIZE; // 48x48
        }
    }

    /**
     * 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 user's profile information
 *
 * 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    mac65 <mac65@mac65.com>
 * @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);
}

/**
 * Ouputs information for a user, specified by ID or screen name.
 * The user's most recent status will be returned inline.
 *
 * @category API
 * @package  StatusNet
 * @author   Dan Moore <dan@moore.cx>
 * @author   Evan Prodromou <evan@status.net>
 * @author   mac65 <mac65@mac65.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 ApiUserShowAction extends ApiPrivateAuthAction
{
    /**
     * Take arguments for running
     *
     * @param array $args $_REQUEST args
     *
     * @return boolean success flag
     *
     */
    protected function prepare(array $args=array())
    {
        parent::prepare($args);

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

        // XXX: email field deprecated in Twitter's API

        if (!empty($email)) {
            $user = User::getKV('email', $email);
        } else {
            $user = $this->getTargetUser($this->arg('id'));
        }

        if (!($user instanceof User)) {
            // TRANS: Client error displayed when requesting user information for a non-existing user.
            $this->clientError(_('User not found.'), 404);
        }
        $this->target = $user->getProfile();

        return true;
    }

    /**
     * Handle the request
     *
     * Check the format and show the user info
     *
     * @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);
        }

        $twitter_user = $this->twitterUserArray($this->target, true);

        if ($this->format == 'xml') {
            $this->initDocument('xml');
            $this->showTwitterXmlUser($twitter_user, 'user', true);
            $this->endDocument('xml');
        } elseif ($this->format == 'json') {
            $this->initDocument('json');
            $this->showJsonObjects($twitter_user);
            $this->endDocument('json');
        }
    }

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

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

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

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

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

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

            // Permanent redirect on non-canonical nickname

            if ($nickname_arg != $nickname) {
                $args = array('nickname' => $nickname);
                common_redirect(common_local_url('leavegroup', $args), 301);
            }

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

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

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

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

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

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

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

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

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

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

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