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

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

/**
 * Settings for email
 *
 * @category Settings
 * @package  StatusNet
 * @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/
 *
 * @see      Widget
 */

class EmailsettingsAction extends SettingsAction
{
    /**
     * Title of the page
     *
     * @return string Title of the page
     */
    function title()
    {
        // TRANS: Title for e-mail settings.
        return _('Email settings');
    }

    /**
     * Instructions for use
     *
     * @return instructions for use
     */
    function getInstructions()
    {
        // XXX: For consistency of parameters in messages, this should be a
        //      regular parameters, replaced with sprintf().
        // TRANS: E-mail settings page instructions.
        // TRANS: %%site.name%% is the name of the site.
        return _('Manage how you get email from %%site.name%%.');
    }

    function showScripts()
    {
        parent::showScripts();
        $this->script('emailsettings.js');
        $this->autofocus('email');
    }

    /**
     * Content area of the page
     *
     * Shows a form for adding and removing email addresses and setting
     * email preferences.
     *
     * @return void
     */
    function showContent()
    {
        $user = $this->scoped->getUser();

        $this->elementStart('form', array('method' => 'post',
                                          'id' => 'form_settings_email',
                                          'class' => 'form_settings',
                                          'action' =>
                                          common_local_url('emailsettings')));
        $this->elementStart('fieldset');
        $this->elementStart('fieldset', array('id' => 'settings_email_address'));
        // TRANS: Form legend for e-mail settings form.
        $this->element('legend', null, _('Email address'));
        $this->hidden('token', common_session_token());

        if ($user->email) {
            $this->element('p', array('id' => 'form_confirmed'), $user->email);
            // TRANS: Form note in e-mail settings form.
            $this->element('p', array('class' => 'form_note'), _('Current confirmed email address.'));
            $this->hidden('email', $user->email);
            // TRANS: Button label to remove a confirmed e-mail address.
            $this->submit('remove', _m('BUTTON','Remove'));
        } else {
            $confirm = $this->getConfirmation();
            if ($confirm) {
                $this->element('p', array('id' => 'form_unconfirmed'), $confirm->address);
                $this->element('p', array('class' => 'form_note'),
                                        // TRANS: Form note in e-mail settings form.
                                        _('Awaiting confirmation on this address. '.
                                        'Check your inbox (and spam box!) for a message '.
                                        'with further instructions.'));
                $this->hidden('email', $confirm->address);
                // TRANS: Button label to cancel an e-mail address confirmation procedure.
                $this->submit('cancel', _m('BUTTON','Cancel'));
            } else {
                $this->elementStart('ul', 'form_data');
                $this->elementStart('li');
                // TRANS: Field label for e-mail address input in e-mail settings form.
                $this->input('email', _('Email address'),
                             ($this->arg('email')) ? $this->arg('email') : null,
                             // TRANS: Instructions for e-mail address input form. Do not translate
                             // TRANS: "example.org". It is one of the domain names reserved for
                             // TRANS: use in examples by http://www.rfc-editor.org/rfc/rfc2606.txt.
                             // TRANS: Any other domain may be owned by a legitimate person or
                             // TRANS: organization.
                             _('Email address, like "UserName@example.org"'));
                $this->elementEnd('li');
                $this->elementEnd('ul');
                // TRANS: Button label for adding an e-mail address in e-mail settings form.
                $this->submit('add', _m('BUTTON','Add'));
            }
        }
        $this->elementEnd('fieldset');

       if (common_config('emailpost', 'enabled') && $user->email) {
            $this->elementStart('fieldset', array('id' => 'settings_email_incoming'));
            // TRANS: Form legend for incoming e-mail settings form.
            $this->element('legend', null, _('Incoming email'));

            $this->elementStart('ul', 'form_data');
            $this->elementStart('li');
            $this->checkbox('emailpost',
                    // TRANS: Checkbox label in e-mail preferences form.
                    _('I want to post notices by email.'),
                    $user->emailpost);
            $this->elementEnd('li');
            $this->elementEnd('ul');

            // Our stylesheets make the form_data list items all floats, which
            // creates lots of problems with trying to wrap divs around things.
            // This should force a break before the next section, which needs
            // to be separate so we can disable the things in it when the
            // checkbox is off.
            $this->elementStart('div', array('style' => 'clear: both'));
            $this->elementEnd('div');

            $this->elementStart('div', array('id' => 'emailincoming'));

            if ($user->incomingemail) {
                $this->elementStart('p');
                $this->element('span', 'address', $user->incomingemail);
                // @todo XXX: Looks a little awkward in the UI.
                //      Something like "xxxx@identi.ca  Send email ..". Needs improvement.
                $this->element('span', 'input_instructions',
                               // TRANS: Form instructions for incoming e-mail form in e-mail settings.
                               _('Send email to this address to post new notices.'));
                $this->elementEnd('p');
                // TRANS: Button label for removing a set sender e-mail address to post notices from.
                $this->submit('removeincoming', _m('BUTTON','Remove'));
            }

            $this->elementStart('p');
            if ($user->incomingemail) {
                // TRANS: Instructions for incoming e-mail address input form, when an address has already been assigned.
                $msg = _('Make a new email address for posting to; '.
                         'cancels the old one.');
            } else {
                // TRANS: Instructions for incoming e-mail address input form.
                $msg = _('To send notices via email, we need to create a unique email address for you on this server:');
            }
            $this->element('span', 'input_instructions', $msg);
            $this->elementEnd('p');

            // TRANS: Button label for adding an e-mail address to send notices from.
            $this->submit('newincoming', _m('BUTTON','New'));

            $this->elementEnd('div'); // div#emailincoming

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

        $this->elementStart('fieldset', array('id' => 'settings_email_preferences'));
        // TRANS: Form legend for e-mail preferences form.
        $this->element('legend', null, _('Email preferences'));

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

        if (Event::handle('StartEmailFormData', array($this, $this->scoped))) {
            $this->elementStart('li');
            $this->checkbox('emailnotifysub',
                            // TRANS: Checkbox label in e-mail preferences form.
                            _('Send me notices of new subscriptions through email.'),
                            $user->emailnotifysub);
            $this->elementEnd('li');
            $this->elementStart('li');
            $this->checkbox('emailnotifymsg',
                            // TRANS: Checkbox label in e-mail preferences form.
                            _('Send me email when someone sends me a private message.'),
                            $user->emailnotifymsg);
            $this->elementEnd('li');
            $this->elementStart('li');
            $this->checkbox('emailnotifyattn',
                            // TRANS: Checkbox label in e-mail preferences form.
                            _('Send me email when someone sends me an "@-reply".'),
                            $user->emailnotifyattn);
            $this->elementEnd('li');
            $this->elementStart('li');
            $this->checkbox('emailnotifynudge',
                            // TRANS: Checkbox label in e-mail preferences form.
                            _('Allow friends to nudge me and send me an email.'),
                            $user->emailnotifynudge);
            $this->elementEnd('li');
            $this->elementStart('li');
            $this->checkbox('emailmicroid',
                            // TRANS: Checkbox label in e-mail preferences form.
                            _('Publish a MicroID for my email address.'),
                            $user->emailmicroid);
            $this->elementEnd('li');
            Event::handle('EndEmailFormData', array($this, $this->scoped));
        }
        $this->elementEnd('ul');
        // TRANS: Button label to save e-mail preferences.
        $this->submit('save', _m('BUTTON','Save'));
        $this->elementEnd('fieldset');
        $this->elementEnd('fieldset');
        $this->elementEnd('form');
    }

    /**
     * Gets any existing email address confirmations we're waiting for
     *
     * @return Confirm_address Email address confirmation for user, or null
     */
    function getConfirmation()
    {
        $user = common_current_user();

        $confirm = new Confirm_address();

        $confirm->user_id      = $user->id;
        $confirm->address_type = 'email';

        if ($confirm->find(true)) {
            return $confirm;
        } else {
            return null;
        }
    }

    /**
     * Handle posts
     *
     * Since there are a lot of different options on the page, we
     * figure out what we're supposed to do based on which button was
     * pushed
     *
     * @return void
     */
    function handlePost()
    {
        // CSRF protection
        $token = $this->trimmed('token');
        if (!$token || $token != common_session_token()) {
            // TRANS: Client error displayed when the session token does not match or is not given.
            $this->show_form(_('There was a problem with your session token. '.
                               'Try again, please.'));
            return;
        }

        if ($this->arg('save')) {
            $this->savePreferences();
        } else if ($this->arg('add')) {
            $this->addAddress();
        } else if ($this->arg('cancel')) {
            $this->cancelConfirmation();
        } else if ($this->arg('remove')) {
            $this->removeAddress();
        } else if ($this->arg('removeincoming')) {
            $this->removeIncoming();
        } else if ($this->arg('newincoming')) {
            $this->newIncoming();
        } else {
            // TRANS: Message given submitting a form with an unknown action in e-mail settings.
            $this->showForm(_('Unexpected form submission.'));
        }
    }

    /**
     * Save email preferences
     *
     * @return void
     */
    function savePreferences()
    {
        $user = $this->scoped->getUser();

        if (Event::handle('StartEmailSaveForm', array($this, $this->scoped))) {
            $emailnotifysub   = $this->booleanintstring('emailnotifysub');
            $emailnotifymsg   = $this->booleanintstring('emailnotifymsg');
            $emailnotifynudge = $this->booleanintstring('emailnotifynudge');
            $emailnotifyattn  = $this->booleanintstring('emailnotifyattn');
            $emailmicroid     = $this->booleanintstring('emailmicroid');
            $emailpost        = $this->booleanintstring('emailpost');

            $user->query('BEGIN');

            $original = clone($user);

            $user->emailnotifysub   = $emailnotifysub;
            $user->emailnotifymsg   = $emailnotifymsg;
            $user->emailnotifynudge = $emailnotifynudge;
            $user->emailnotifyattn  = $emailnotifyattn;
            $user->emailmicroid     = $emailmicroid;
            $user->emailpost        = $emailpost;

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

            if ($result === false) {
                common_log_db_error($user, 'UPDATE', __FILE__);
                $user->query('ROLLBACK');
                // TRANS: Server error thrown on database error updating e-mail preferences.
                $this->serverError(_('Could not update user.'));
            }

            $user->query('COMMIT');

            Event::handle('EndEmailSaveForm', array($this, $this->scoped));

            // TRANS: Confirmation message for successful e-mail preferences save.
            $this->showForm(_('Email preferences saved.'), true);
        }
    }

    /**
     * Add the address passed in by the user
     *
     * @return void
     */
    function addAddress()
    {
        $user = common_current_user();

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

        // Some validation

        if (!$email) {
            // TRANS: Message given saving e-mail address without having provided one.
            $this->showForm(_('No email address.'));
            return;
        }

        $email = common_canonical_email($email);

        if (!$email) {
            // TRANS: Message given saving e-mail address that cannot be normalised.
            $this->showForm(_('Cannot normalize that email address.'));
            return;
        }
        if (!Validate::email($email, common_config('email', 'check_domain'))) {
            // TRANS: Message given saving e-mail address that not valid.
            $this->showForm(_('Not a valid email address.'));
            return;
        } else if ($user->email == $email) {
            // TRANS: Message given saving e-mail address that is already set.
            $this->showForm(_('That is already your email address.'));
            return;
        } else if ($this->emailExists($email)) {
            // TRANS: Message given saving e-mail address that is already set for another user.
            $this->showForm(_('That email address already belongs '.
                              'to another user.'));
            return;
        }

        if (Event::handle('StartAddEmailAddress', array($user, $email))) {

            $confirm = new Confirm_address();

            $confirm->address      = $email;
            $confirm->address_type = 'email';
            $confirm->user_id      = $user->id;
            $confirm->code         = common_confirmation_code(64);

            $result = $confirm->insert();

            if ($result === false) {
                common_log_db_error($confirm, 'INSERT', __FILE__);
                // TRANS: Server error thrown on database error adding e-mail confirmation code.
                $this->serverError(_('Could not insert confirmation code.'));
            }

            mail_confirm_address($user, $confirm->code, $user->nickname, $email);

            Event::handle('EndAddEmailAddress', array($user, $email));
        }

        // TRANS: Message given saving valid e-mail address that is to be confirmed.
        $msg = _('A confirmation code was sent to the email address you added. '.
                 'Check your inbox (and spam box!) for the code and instructions '.
                 'on how to use it.');

        $this->showForm($msg, true);
    }

    /**
     * Handle a request to cancel email confirmation
     *
     * @return void
     */
    function cancelConfirmation()
    {
        $email = $this->arg('email');

        $confirm = $this->getConfirmation();

        if (!$confirm) {
            // TRANS: Message given canceling e-mail address confirmation that is not pending.
            $this->showForm(_('No pending confirmation to cancel.'));
            return;
        }
        if ($confirm->address != $email) {
            // TRANS: Message given canceling e-mail address confirmation for the wrong e-mail address.
            $this->showForm(_('That is the wrong email address.'));
            return;
        }

        $result = $confirm->delete();

        if (!$result) {
            common_log_db_error($confirm, 'DELETE', __FILE__);
            // TRANS: Server error thrown on database error canceling e-mail address confirmation.
            $this->serverError(_('Could not delete email confirmation.'));
        }

        // TRANS: Message given after successfully canceling e-mail address confirmation.
        $this->showForm(_('Email confirmation cancelled.'), true);
    }

    /**
     * Handle a request to remove an address from the user's account
     *
     * @return void
     */
    function removeAddress()
    {
        $user = common_current_user();

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

        // Maybe an old tab open...?

        if ($user->email != $email) {
            // TRANS: Message given trying to remove an e-mail address that is not
            // TRANS: registered for the active user.
            $this->showForm(_('That is not your email address.'));
            return;
        }

        $original = clone($user);

        $user->email = null;

        // Throws exception on failure. Also performs it within a transaction.
        $user->updateWithKeys($original);

        // TRANS: Message given after successfully removing a registered e-mail address.
        $this->showForm(_('The email address was removed.'), true);
    }

    /**
     * Handle a request to remove an incoming email address
     *
     * @return void
     */
    function removeIncoming()
    {
        $user = common_current_user();

        if (!$user->incomingemail) {
            // TRANS: Form validation error displayed when trying to remove an incoming e-mail address while no address has been set.
            $this->showForm(_('No incoming email address.'));
            return;
        }

        $orig = clone($user);

        $user->incomingemail = null;
        $user->emailpost = 0;

        // Throws exception on failure. Also performs it within a transaction.
        $user->updateWithKeys($orig);

        // TRANS: Message given after successfully removing an incoming e-mail address.
        $this->showForm(_('Incoming email address removed.'), true);
    }

    /**
     * Generate a new incoming email address
     *
     * @return void
     */
    function newIncoming()
    {
        $user = common_current_user();

        $orig = clone($user);

        $user->incomingemail = mail_new_incoming_address();
        $user->emailpost = 1;

        // Throws exception on failure. Also performs it within a transaction.
        $user->updateWithKeys($orig);

        // TRANS: Message given after successfully adding an incoming e-mail address.
        $this->showForm(_('New incoming email address added.'), true);
    }

    /**
     * Does another user already have this email address?
     *
     * Email addresses are unique for users.
     *
     * @param string $email Address to check
     *
     * @return boolean Whether the email already exists.
     */

    function emailExists($email)
    {
        $user = common_current_user();

        $other = User::getKV('email', $email);

        if (!$other) {
            return false;
        } else {
            return $other->id != $user->id;
        }
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * List of featured users
 *
 * 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  Public
 * @package   StatusNet
 * @author    Zach Copley <zach@status.net>
 * @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);
}

require_once INSTALLDIR.'/lib/profilelist.php';
require_once INSTALLDIR.'/lib/publicgroupnav.php';

/**
 * List of featured users
 *
 * @category Public
 * @package  StatusNet
 * @author   Zach Copley <zach@status.net>
 * @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 FeaturedAction extends Action
{
    var $page = null;

    function isReadOnly($args)
    {
        return true;
    }

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

        return true;
    }

    function title()
    {
        if ($this->page == 1) {
            // TRANS: Page title for first page of featured users.
            return _('Featured users');
        } else {
            // TRANS: Page title for all but first page of featured users.
            // TRANS: %d is the page number being displayed.
            return sprintf(_('Featured users, page %d'), $this->page);
        }
    }

    function handle($args)
    {
        parent::handle($args);

        $this->showPage();
    }

    function showPageNotice()
    {
        $instr = $this->getInstructions();
        $output = common_markup_to_html($instr);
        $this->elementStart('div', 'instructions');
        $this->raw($output);
        $this->elementEnd('div');
    }

    function getInstructions()
    {
        // TRANS: Description on page displaying featured users.
        return sprintf(_('A selection of some great users on %s.'),
                       common_config('site', 'name'));
    }

    function showContent()
    {
        // XXX: Note I'm doing it this two-stage way because a raw query
        // with a JOIN was *not* working. --Zach

        $featured_nicks = common_config('nickname', 'featured');

        if (count($featured_nicks) > 0) {

            $quoted = array();

            foreach ($featured_nicks as $nick) {
                $quoted[] = "'$nick'";
            }

            $user = new User;
            $user->whereAdd(sprintf('nickname IN (%s)', implode(',', $quoted)));
            $user->limit(($this->page - 1) * PROFILES_PER_PAGE, PROFILES_PER_PAGE + 1);
            $user->orderBy(common_database_tablename('user') .'.nickname ASC');

            $user->find();

            $profile_ids = array();

            while ($user->fetch()) {
                $profile_ids[] = $user->id;
            }

            $profile = new Profile;
            $profile->whereAdd(sprintf('profile.id IN (%s)', implode(',', $profile_ids)));
            $profile->orderBy('nickname ASC');

            $cnt = $profile->find();

            if ($cnt > 0) {
                $featured = new ProfileList($profile, $this);
                $featured->show();
            }

            $profile->free();

            $this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE,
                              $this->page, 'featured');
        }
    }
}

repo_name: piratas/tortuga

license: mit


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

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

define('LISTENER', 1);
define('LISTENEE', -1);
define('BOTH', 0);

// @todo XXX: Documentation missing.
class FoafAction extends Action
{
    function isReadOnly($args)
    {
        return true;
    }

    function prepare($args)
    {
        parent::prepare($args);

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

        if (empty($nickname_arg)) {
            // TRANS: Client error displayed when requesting Friends of a Friend feed without providing a user nickname.
            $this->clientError(_('No such user.'), 404);
        }

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

        // Permanent redirect on non-canonical nickname

        if ($nickname_arg != $this->nickname) {
            common_redirect(common_local_url('foaf',
                                             array('nickname' => $this->nickname)),
                            301);
        }

        $this->user = User::getKV('nickname', $this->nickname);

        if (!$this->user) {
            // TRANS: Client error displayed when requesting Friends of a Friend feed for an object that is not a user.
            $this->clientError(_('No such user.'), 404);
        }

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

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

        return true;
    }

    function handle($args)
    {
        parent::handle($args);

        header('Content-Type: application/rdf+xml');

        $this->startXML();
        $this->elementStart('rdf:RDF', array('xmlns:rdf' =>
                                              'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
                                              'xmlns:rdfs' =>
                                              'http://www.w3.org/2000/01/rdf-schema#',
                                              'xmlns:geo' =>
                                              'http://www.w3.org/2003/01/geo/wgs84_pos#',
                                              'xmlns:bio' =>
                                              'http://purl.org/vocab/bio/0.1/',
                                              'xmlns:sioc' =>
                                              'http://rdfs.org/sioc/ns#',
                                              'xmlns' => 'http://xmlns.com/foaf/0.1/'));

        // This is the document about the user

        $this->showPpd('', $this->user->getUri());

        // Would be nice to tell if they were a Person or not (e.g. a #person usertag?)
        $this->elementStart('Agent', array('rdf:about' => $this->user->getUri()));
        if ($this->user->email) {
            $this->element('mbox_sha1sum', null, sha1('mailto:' . $this->user->email));
        }
        if ($this->profile->fullname) {
            $this->element('name', null, $this->profile->fullname);
        }
        if ($this->profile->homepage) {
            $this->element('homepage', array('rdf:resource' => $this->profile->homepage));
        }
        if ($this->profile->profileurl) {
            $this->element('weblog', array('rdf:resource' => $this->profile->profileurl));
        }
        if ($this->profile->bio) {
            $this->element('bio:olb', null, $this->profile->bio);
        }

        $location = $this->profile->getLocation();
        if ($location) {
            $attr = array();
            if ($location->getRdfURL()) {
                $attr['rdf:about'] = $location->getRdfURL();
            }
            $location_name = $location->getName();

            $this->elementStart('based_near');
            $this->elementStart('geo:SpatialThing', $attr);
            if ($location_name) {
                $this->element('name', null, $location_name);
            }
            if ($location->lat) {
                $this->element('geo:lat', null, $location->lat);
            }
            if ($location->lon) {
                $this->element('geo:long', null, $location->lon);
            }
            if ($location->getURL()) {
                $this->element('page', array('rdf:resource'=>$location->getURL()));
            }
            $this->elementEnd('geo:SpatialThing');
            $this->elementEnd('based_near');
        }

        try {
            $avatar = Avatar::getUploaded($this->profile);
            $this->elementStart('img');
            $this->elementStart('Image', array('rdf:about' => $avatar->displayUrl()));
            foreach (array(AVATAR_PROFILE_SIZE, AVATAR_STREAM_SIZE, AVATAR_MINI_SIZE) as $size) {
                try {
                    $scaled = $this->profile->getAvatar($size);
                    $this->elementStart('thumbnail');
                    $this->element('Image', array('rdf:about' => $scaled->displayUrl()));
                    $this->elementEnd('thumbnail');
                } catch (Exception $e) {
                    // This avatar did not exist
                }
            }
            $this->elementEnd('Image');
            $this->elementEnd('img');
        } catch (NoAvatarException $e) {
            // No avatar for this user!
        }

        $person = $this->showMicrobloggingAccount($this->profile,
                                     common_root_url(), $this->user->getUri(),
                                     /*$fetchSubscriptions*/true,
                                     /*$isSubscriber*/false);

        // Get people who subscribe to user

        $sub = new Subscription();
        $sub->subscribed = $this->profile->id;
        $sub->whereAdd('subscriber != subscribed');

        if ($sub->find()) {
            while ($sub->fetch()) {
                $profile = Profile::getKV('id', $sub->subscriber);
                if (!$profile instanceof Profile) {
                    common_debug('Got a bad subscription: '.print_r($sub,true));
                    continue;
                }
                $other_uri = $profile->getUri();
                if (array_key_exists($other_uri, $person)) {
                    $person[$other_uri][0] = BOTH;
                } else {
                    $person[$other_uri] = array(LISTENER,
                                                $profile->id,
                                                $profile->nickname,
                                                $profile->isLocal() ? 'local' : 'remote');
                }
                unset($profile);
            }
        }

        unset($sub);

        foreach ($person as $uri => $p) {
            list($type, $id, $nickname, $local) = $p;
            if ($type == BOTH) {
                $this->element('knows', array('rdf:resource' => $uri));
            }
        }

        $this->elementEnd('Agent');

        foreach ($person as $uri => $p) {
            $foaf_url = null;
            list($type, $id, $nickname, $local) = $p;
            if ($local == 'local') {
                $foaf_url = common_local_url('foaf', array('nickname' => $nickname));
            }
            $profile = Profile::getKV($id);
            $this->elementStart('Agent', array('rdf:about' => $uri));
            if ($type == BOTH) {
                $this->element('knows', array('rdf:resource' => $this->user->getUri()));
            }
            $this->showMicrobloggingAccount($profile,
                                   ($local == 'local') ? common_root_url() : null,
                                   $uri,
                                   /*$fetchSubscriptions*/false,
                                   /*$isSubscriber*/($type == LISTENER || $type == BOTH));
            if ($foaf_url) {
                $this->element('rdfs:seeAlso', array('rdf:resource' => $foaf_url));
            }
            $this->elementEnd('Agent');
            if ($foaf_url) {
                $this->showPpd($foaf_url, $uri);
            }
            $profile->free();
            $profile = null;
            unset($profile);
        }

        $this->elementEnd('rdf:RDF');
        $this->endXML();
    }

    function showPpd($foaf_url, $person_uri)
    {
        $this->elementStart('PersonalProfileDocument', array('rdf:about' => $foaf_url));
        $this->element('maker', array('rdf:resource' => $person_uri));
        $this->element('primaryTopic', array('rdf:resource' => $person_uri));
        $this->elementEnd('PersonalProfileDocument');
    }

    /**
     * Output FOAF <account> bit for the given profile.
     *
     * @param Profile $profile
     * @param mixed $service Root URL of this StatusNet instance for a local
     *                       user, otherwise null.
     * @param mixed $useruri URI string for the referenced profile..
     * @param boolean $fetchSubscriptions Should we load and list all their subscriptions?
     * @param boolean $isSubscriber if not fetching subs, we can still mark the user as following the current page.
     *
     * @return array if $fetchSubscribers is set, return a list of info on those
     *               subscriptions.
     */
    function showMicrobloggingAccount($profile, $service=null, $useruri=null, $fetchSubscriptions=false, $isSubscriber=false)
    {
        $attr = array();
        if ($useruri) {
            $attr['rdf:about'] = $useruri . '#acct';
        }

        // Their account
        $this->elementStart('account');
        $this->elementStart('OnlineAccount', $attr);
        if ($service) {
            $this->element('accountServiceHomepage', array('rdf:resource' =>
                                                           $service));
        }
        $this->element('accountName', null, $profile->nickname);
        $this->element('accountProfilePage', array('rdf:resource' => $profile->profileurl));
        if ($useruri) {
            $this->element('sioc:account_of', array('rdf:resource'=>$useruri));
        }

        $person = array();

        if ($fetchSubscriptions) {
            // Get people user is subscribed to
            $sub = new Subscription();
            $sub->subscriber = $profile->id;
            $sub->whereAdd('subscriber != subscribed');

            if ($sub->find()) {
                while ($sub->fetch()) {
                    $profile = Profile::getKV('id', $sub->subscribed);
                    if (empty($profile)) {
                        common_debug('Got a bad subscription: '.print_r($sub,true));
                        continue;
                    }
                    $other_uri = $profile->getUri();
                    $this->element('sioc:follows', array('rdf:resource' => $other_uri.'#acct'));
                    $person[$other_uri] = array(LISTENEE,
                                                $profile->id,
                                                $profile->nickname,
                                                $profile->isLocal() ? 'local' : 'remote');
                    unset($profile);
                }
            }

            unset($sub);
        } else if ($isSubscriber) {
            // Just declare that they follow the user whose FOAF we're showing.
            $this->element('sioc:follows', array('rdf:resource' => $this->user->getUri() . '#acct'));
        }

        $this->elementEnd('OnlineAccount');
        $this->elementEnd('account');

        return $person;
    }
}


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

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

// @todo XXX: Documentation missing.
class FoafGroupAction extends Action
{
    function isReadOnly($args)
    {
        return true;
    }

    function prepare($args)
    {
        parent::prepare($args);

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

        if (empty($nickname_arg)) {
            // TRANS: Client error displayed when requesting Friends of a Friend feed without providing a group nickname.
            $this->clientError(_('No such group.'), 404);
        }

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

        // Permanent redirect on non-canonical nickname

        if ($nickname_arg != $this->nickname) {
            common_redirect(common_local_url('foafgroup',
                                             array('nickname' => $this->nickname)),
                            301);
            return false;
        }

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

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

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

        if (!$this->group) {
            // TRANS: Client error displayed when requesting Friends of a Friend feed for a nickname that is not a group.
            $this->clientError(_('No such group.'), 404);
        }

        common_set_returnto($this->selfUrl());

        return true;
    }

    function handle($args)
    {
        parent::handle($args);

        header('Content-Type: application/rdf+xml');

        $this->startXML();
        $this->elementStart('rdf:RDF', array('xmlns:rdf' =>
                                              'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
                                              'xmlns:dcterms' =>
                                              'http://purl.org/dc/terms/',
                                              'xmlns:sioc' =>
                                              'http://rdfs.org/sioc/ns#',
                                              'xmlns:foaf' =>
                                              'http://xmlns.com/foaf/0.1/',
                                              'xmlns:statusnet' =>
                                              'http://status.net/ont/',
                                              'xmlns' => 'http://xmlns.com/foaf/0.1/'));

        $this->showPpd(common_local_url('foafgroup', array('nickname' => $this->nickname)), $this->group->permalink());

        $this->elementStart('Group', array('rdf:about' =>
                                             $this->group->permalink()));
        if ($this->group->fullname) {
            $this->element('name', null, $this->group->fullname);
        }
        if ($this->group->description) {
            $this->element('dcterms:description', null, $this->group->description);
        }
        if ($this->group->nickname) {
            $this->element('dcterms:identifier', null, $this->group->nickname);
            $this->element('nick', null, $this->group->nickname);
        }
        foreach ($this->group->getAliases() as $alias) {
            $this->element('nick', null, $alias);
        }
        if ($this->group->homeUrl()) {
            $this->element('weblog', array('rdf:resource' => $this->group->homeUrl()));
        }
        if ($this->group->homepage) {
            $this->element('page', array('rdf:resource' => $this->group->homepage));
        }
        if ($this->group->homepage_logo) {
            $this->element('depiction', array('rdf:resource' => $this->group->homepage_logo));
        }

        $members = $this->group->getMembers();
        $member_details = array();
        while ($members->fetch()) {
            $member_uri = common_local_url('userbyid', array('id'=>$members->id));
            $member_details[$member_uri] = array(
                                        'nickname' => $members->nickname,
                                        'is_admin' => false,
                                        );
            $this->element('member', array('rdf:resource' => $member_uri));
        }

        $admins = $this->group->getAdmins();
        while ($admins->fetch()) {
            $admin_uri = common_local_url('userbyid', array('id'=>$admins->id));
            $member_details[$admin_uri]['is_admin'] = true;
            $this->element('statusnet:groupAdmin', array('rdf:resource' => $admin_uri));
        }

        $this->elementEnd('Group');

        ksort($member_details);
        foreach ($member_details as $uri => $details) {
            if ($details['is_admin'])
            {
                $this->elementStart('Agent', array('rdf:about' => $uri));
                $this->element('nick', null, $details['nickname']);
                $this->elementStart('account');
                $this->elementStart('sioc:User', array('rdf:about'=>$uri.'#acct'));
                $this->elementStart('sioc:has_function');
                $this->elementStart('statusnet:GroupAdminRole');
                $this->element('sioc:scope', array('rdf:resource' => $this->group->permalink()));
                $this->elementEnd('statusnet:GroupAdminRole');
                $this->elementEnd('sioc:has_function');
                $this->elementEnd('sioc:User');
                $this->elementEnd('account');
                $this->elementEnd('Agent');
            }
            else
            {
                $this->element('Agent', array(
                                        'foaf:nick' => $details['nickname'],
                                        'rdf:about' => $uri,
                                        ));
            }
        }

        $this->elementEnd('rdf:RDF');
        $this->endXML();
    }

    function showPpd($foaf_url, $person_uri)
    {
        $this->elementStart('Document', array('rdf:about' => $foaf_url));
        $this->element('primaryTopic', array('rdf:resource' => $person_uri));
        $this->elementEnd('Document');
    }

}


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

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

/**
 * Geocode action class
 *
 * @category Action
 * @package  StatusNet
 * @author   Craig Andrews <candrews@integralblue.com>
 * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 * @link     http://status.net/
 */
class GeocodeAction extends Action
{
    var $lat = null;
    var $lon = null;
    var $location = null;

    function prepare($args)
    {
        parent::prepare($args);
        $token = $this->trimmed('token');
        if (!$token || $token != common_session_token()) {
            // TRANS: Client error displayed when the session token does not match or is not given.
            $this->clientError(_('There was a problem with your session token. '.
                                 'Try again, please.'));
        }
        $this->lat = $this->trimmed('lat');
        $this->lon = $this->trimmed('lon');
        $this->location = Location::fromLatLon($this->lat, $this->lon);
        return true;
    }

    /**
     * Class handler
     *
     * @param array $args query arguments
     *
     * @return nothing
     *
     */
    function handle($args)
    {
        header('Content-Type: application/json; charset=utf-8');
        $location_object = array();
        $location_object['lat']=$this->lat;
        $location_object['lon']=$this->lon;
        if($this->location) {
            $location_object['location_id']=$this->location->location_id;
            $location_object['location_ns']=$this->location->location_ns;
            $location_object['name']=$this->location->getName();
            $location_object['url']=$this->location->getUrl();
        }
        print(json_encode($location_object));
    }

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


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

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

/**
 * An action for returning a requested file
 *
 * The StatusNet system will do an implicit user check if the site is
 * private before allowing this to continue
 *
 * @category  PrivateAttachments
 * @package   StatusNet
 * @author    Jeffery To <jeffery.to@gmail.com>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */
class GetfileAction extends Action
{
    /**
     * Path of file to return
     */
    var $path = null;

    /**
     * Get file name
     *
     * @param array $args $_REQUEST array
     *
     * @return success flag
     */
    protected function prepare(array $args=array())
    {
        parent::prepare($args);

        $filename = $this->trimmed('filename');
        $path = null;

        if ($filename && File::validFilename($filename)) {
            $path = File::path($filename);
        }

        if (empty($path) or !file_exists($path)) {
            // TRANS: Client error displayed when requesting a non-existent file.
            $this->clientError(_('No such file.'), 404);
        }
        if (!is_readable($path)) {
            // TRANS: Client error displayed when requesting a file without having read access to it.
            $this->clientError(_('Cannot read file.'), 403);
        }

        $this->path = $path;
        return true;
    }

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

    /**
     * Last-modified date for file
     *
     * @return int last-modified date as unix timestamp
     */
    function lastModified()
    {
        if (common_config('site', 'use_x_sendfile')) {
            return null;
        }

        return filemtime($this->path);
    }

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

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

        $stat = stat($this->path);
        return '"' . $stat['ino'] . '-' . $stat['size'] . '-' . $stat['mtime'] . '"';
    }

    /**
     * Handle input, produce output
     *
     * @return void
     */
    protected function handle()
    {
        // undo headers set by PHP sessions
        $sec = session_cache_expire() * 60;
        header('Expires: ' . date(DATE_RFC1123, time() + $sec));
        header('Cache-Control: max-age=' . $sec);

        parent::handle();

        $path = $this->path;

        $finfo = new finfo(FILEINFO_MIME_TYPE);

        header('Content-Type: ' . $finfo->file($path));

        if (common_config('site', 'use_x_sendfile')) {
            header('X-Sendfile: ' . $path);
        } else {
            header('Content-Length: ' . filesize($path));
            readfile($path);
        }
    }
}


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

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

/**
 * Assign role to user.
 *
 * @category Action
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 * @link     http://status.net/
 */
class GrantRoleAction extends ProfileFormAction
{
    /**
     * Check parameters
     *
     * @param array $args action arguments (URL, GET, POST)
     *
     * @return boolean success flag
     */
    function prepare($args)
    {
        if (!parent::prepare($args)) {
            return false;
        }

        $this->role = $this->arg('role');
        if (!Profile_role::isValid($this->role)) {
            // TRANS: Client error displayed when trying to assign an invalid role to a user.
            $this->clientError(_('Invalid role.'));
        }
        if (!Profile_role::isSettable($this->role)) {
            // TRANS: Client error displayed when trying to assign an reserved role to a user.
            $this->clientError(_('This role is reserved and cannot be set.'));
        }

        $cur = common_current_user();

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

        if (!$cur->hasRight(Right::GRANTROLE)) {
            // TRANS: Client error displayed when trying to assign a role to a user while not being allowed to set roles.
            $this->clientError(_('You cannot grant user roles on this site.'));
        }

        assert(!empty($this->profile)); // checked by parent

        if ($this->profile->hasRole($this->role)) {
            // TRANS: Client error displayed when trying to assign a role to a user that already has that role.
            $this->clientError(_('User already has this role.'));
        }

        return true;
    }

    /**
     * Sandbox a user.
     *
     * @return void
     */
    function handlePost()
    {
        $this->profile->grantRole($this->role);
    }
}


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

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

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

    /**
     * Take arguments for running
     *
     * @param array $args $_REQUEST args
     *
     * @return boolean success flag
     */
    function prepare($args)
    {
        parent::prepare($args);
        if (!common_logged_in()) {
            // TRANS: Error message displayed when trying to perform an action that requires a logged in user.
            $this->clientError(_('Not logged in.'));
        }
        $token = $this->trimmed('token');
        if (empty($token) || $token != common_session_token()) {
            // TRANS: Client error displayed when the session token does not match or is not given.
            $this->clientError(_('There was a problem with your session token. Try again, please.'));
        }
        $id = $this->trimmed('blockto');
        if (empty($id)) {
            // TRANS: Client error displayed trying to block a user from a group while not specifying a to be blocked user profile.
            $this->clientError(_('No profile specified.'));
        }
        $this->profile = Profile::getKV('id', $id);
        if (empty($this->profile)) {
            // TRANS: Client error displayed trying to block a user from a group while specifying a non-existing profile.
            $this->clientError(_('No profile with that ID.'));
        }
        $group_id = $this->trimmed('blockgroup');
        if (empty($group_id)) {
            // TRANS: Client error displayed trying to block a user from a group while not specifying a group to block a profile from.
            $this->clientError(_('No group specified.'));
        }
        $this->group = User_group::getKV('id', $group_id);
        if (empty($this->group)) {
            // TRANS: Client error displayed trying to block a user from a group while specifying a non-existing group.
            $this->clientError(_('No such group.'));
        }
        $user = common_current_user();
        if (!$user->isAdmin($this->group)) {
            // TRANS: Client error displayed trying to block a user from a group while not being an admin user.
            $this->clientError(_('Only an admin can block group members.'), 401);
        }
        if (Group_block::isBlocked($this->group, $this->profile)) {
            // TRANS: Client error displayed trying to block a user from a group while user is already blocked from the given group.
            $this->clientError(_('User is already blocked from group.'));
        }
        // XXX: could have proactive blocks, but we don't have UI for it.
        if (!$this->profile->isMember($this->group)) {
            // TRANS: Client error displayed trying to block a user from a group while user is not a member of given group.
            $this->clientError(_('User is not a member of group.'));
        }
        return true;
    }

    /**
     * Handle request
     *
     * Shows a page with list of favorite notices
     *
     * @param array $args $_REQUEST args; handled in prepare()
     *
     * @return void
     */
    function handle($args)
    {
        parent::handle($args);
        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
            if ($this->arg('no')) {
                $this->returnToPrevious();
            } elseif ($this->arg('yes')) {
                $this->blockProfile();
            } elseif ($this->arg('blockto')) {
                $this->showPage();
            }
        }
    }

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

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

    function showNoticeForm() {
        // nop
    }

    /**
     * Confirm with user.
     *
     * Shows a confirmation form.
     *
     * @return void
     */
    function areYouSureForm()
    {
        $id = $this->profile->id;
        $this->elementStart('form', array('id' => 'block-' . $id,
                                           'method' => 'post',
                                           'class' => 'form_settings form_entity_block',
                                           'action' => common_local_url('groupblock')));
        $this->elementStart('fieldset');
        $this->hidden('token', common_session_token());
        // TRANS: Fieldset legend for block user from group form.
        $this->element('legend', _('Block user'));
        $this->element('p', null,
                       // TRANS: Explanatory text for block user from group form before setting the block.
                       // TRANS: %1$s is that to be blocked user, %2$s is the group the user will be blocked from.
                       sprintf(_('Are you sure you want to block user "%1$s" from the group "%2$s"? '.
                                 'They will be removed from the group, unable to post, and '.
                                 'unable to subscribe to the group in the future.'),
                               $this->profile->getBestName(),
                               $this->group->getBestName()));
        $this->hidden('blockto-' . $this->profile->id,
                      $this->profile->id,
                      'blockto');
        $this->hidden('blockgroup-' . $this->group->id,
                      $this->group->id,
                      'blockgroup');
        foreach ($this->args as $k => $v) {
            if (substr($k, 0, 9) == 'returnto-') {
                $this->hidden($k, $v);
            }
        }
        $this->submit('form_action-no',
                      // TRANS: Button label on the form to block a user from a group.
                      _m('BUTTON','No'),
                      'submit form_action-primary',
                      'no',
                      // TRANS: Submit button title for 'No' when blocking a user from a group.
                      _('Do not block this user from this group.'));
        $this->submit('form_action-yes',
                      // TRANS: Button label on the form to block a user from a group.
                      _m('BUTTON','Yes'),
                      'submit form_action-secondary',
                      'yes',
                      // TRANS: Submit button title for 'Yes' when blocking a user from a group.
                      _('Block this user from this group.'));
        $this->elementEnd('fieldset');
        $this->elementEnd('form');
    }

    /**
     * Actually block a user.
     *
     * @return void
     */
    function blockProfile()
    {
        $block = Group_block::blockProfile($this->group, $this->profile,
                                           common_current_user());

        if (empty($block)) {
            // TRANS: Server error displayed when trying to block a user from a group fails because of an application error.
            $this->serverError(_("Database error blocking user from group."));
        }

        $this->returnToPrevious();
    }

    /**
     * If we reached this form without returnto arguments, default to
     * the top of the group's member list.
     *
     * @return string URL
     */
    function defaultReturnTo()
    {
        return common_local_url('groupmembers',
                                array('nickname' => $this->group->nickname));
    }

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


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Permalink for 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>
 * @author    Sarven Capadisli <csarven@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);
}

require_once INSTALLDIR.'/lib/noticelist.php';
require_once INSTALLDIR.'/lib/feedlist.php';

/**
 * Permalink for a group
 *
 * The group nickname can change, but not the group ID. So we use
 * an URL with the ID in it as the permanent identifier.
 *
 * @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 GroupbyidAction extends Action
{
    /** group we're viewing. */
    var $group = null;

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

    function prepare($args)
    {
        parent::prepare($args);

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

        if (!$id) {
            // TRANS: Client error displayed referring to a group's permalink without providing a group ID.
            $this->clientError(_('No ID.'));
        }

        common_debug("Got ID $id");

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

        if (!$this->group) {
            // TRANS: Client error displayed referring to a group's permalink for a non-existing group ID.
            $this->clientError(_('No such group.'), 404);
        }

        return true;
    }

    /**
     * Handle the request
     *
     * Shows a profile for the group, some controls, and a list of
     * group notices.
     *
     * @return void
     */
    function handle($args)
    {
        common_redirect($this->group->homeUrl(), 303);
    }
}


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

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

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

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

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

        $nickname_arg = $this->trimmed('nickname');
        $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('grouplogo', $args), 301);
        }

        if (!$nickname) {
            // TRANS: Client error displayed when trying to change group logo settings without providing a nickname.
            $this->clientError(_('No nickname.'), 404);
        }

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

        if ($groupid) {
            $this->group = User_group::getKV('id', $groupid);
        } else {
            $local = Local_group::getKV('nickname', $nickname);
            if ($local) {
                $this->group = User_group::getKV('id', $local->group_id);
            }
        }

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

        $cur = common_current_user();

        if (!$cur->isAdmin($this->group)) {
            // TRANS: Client error displayed when trying to change group logo settings while not being a group admin.
            $this->clientError(_('You must be an admin to edit the group.'), 403);
        }

        return true;
    }

    protected function handle()
    {
        parent::handle();
        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
            $this->handlePost();
        } else {
            $this->showForm();
        }
    }

    function showForm($msg = null, $success = false)
    {
        $this->msg     = $msg;
        $this->success = $success;

        $this->showPage();
    }

    /**
     * Title of the page
     *
     * @return string Title of the page
     */
    function title()
    {
        // TRANS: Title for group logo settings page.
        return _('Group logo');
    }

    /**
     * Instructions for use
     *
     * @return instructions for use
     */
    function getInstructions()
    {
        // TRANS: Instructions for group logo page.
        // TRANS: %s is the maximum file size for that site.
        return sprintf(_('You can upload a logo image for your group. The maximum file size is %s.'), ImageFile::maxFileSize());
    }

    /**
     * Content area of the page
     *
     * Shows a form for uploading an avatar.
     *
     * @return void
     */
    function showContent()
    {
        if ($this->mode == 'crop') {
            $this->showCropForm();
        } else {
            $this->showUploadForm();
        }
    }

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

        $profile = $user->getProfile();

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

        $original = $this->group->original_logo;

        $this->elementStart('form', array('enctype' => 'multipart/form-data',
                                          'method' => 'post',
                                          'id' => 'form_settings_avatar',
                                          'class' => 'form_settings',
                                          'action' =>
                                          common_local_url('grouplogo',
                                                           array('nickname' => $this->group->nickname))));
        $this->elementStart('fieldset');
        // TRANS: Group logo form legend.
        $this->element('legend', null, _('Group logo'));
        $this->hidden('token', common_session_token());

        $this->elementStart('ul', 'form_data');
        if ($original) {
            $this->elementStart('li', array('id' => 'avatar_original',
                                            'class' => 'avatar_view'));
            // TRANS: Uploaded original file in group logo form.
            $this->element('h2', null, _('Original'));
            $this->elementStart('div', array('id'=>'avatar_original_view'));
            $this->element('img', array('src' => $this->group->original_logo,
                                        'alt' => $this->group->nickname));
            $this->elementEnd('div');
            $this->elementEnd('li');
        }

        if ($this->group->homepage_logo) {
            $this->elementStart('li', array('id' => 'avatar_preview',
                                            'class' => 'avatar_view'));
            // TRANS: Header for preview of to be displayed group logo.
            $this->element('h2', null, _('Preview'));
            $this->elementStart('div', array('id'=>'avatar_preview_view'));
            $this->element('img', array('src' => $this->group->homepage_logo,
                                        'width' => AVATAR_PROFILE_SIZE,
                                        'height' => AVATAR_PROFILE_SIZE,
                                        'alt' => $this->group->nickname));
            $this->elementEnd('div');
            $this->elementEnd('li');
        }

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

        $this->elementStart('ul', 'form_actions');
        $this->elementStart('li');
        // TRANS: Submit button for uploading a group logo.
        $this->submit('upload', _('Upload'));
        $this->elementEnd('li');
        $this->elementEnd('ul');

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

    function showCropForm()
    {
        $this->elementStart('form', array('method' => 'post',
                                          'id' => 'form_settings_avatar',
                                          'class' => 'form_settings',
                                          'action' =>
                                          common_local_url('grouplogo',
                                                           array('nickname' => $this->group->nickname))));
        $this->elementStart('fieldset');
        // TRANS: Legend for group logo settings fieldset.
        $this->element('legend', null, _('Avatar settings'));
        $this->hidden('token', common_session_token());

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

        $this->elementStart('li',
                            array('id' => 'avatar_original',
                                  'class' => 'avatar_view'));
        // TRANS: Header for originally uploaded file before a crop on the group logo page.
        $this->element('h2', null, _('Original'));
        $this->elementStart('div', array('id'=>'avatar_original_view'));
        $this->element('img', array('src' => Avatar::url($this->filedata['filename']),
                                    'width' => $this->filedata['width'],
                                    'height' => $this->filedata['height'],
                                    'alt' => $this->group->nickname));
        $this->elementEnd('div');
        $this->elementEnd('li');

        $this->elementStart('li',
                            array('id' => 'avatar_preview',
                                  'class' => 'avatar_view'));
        // TRANS: Header for the cropped group logo on the group logo page.
        $this->element('h2', null, _('Preview'));
        $this->elementStart('div', array('id'=>'avatar_preview_view'));
        $this->element('img', array('src' => Avatar::url($this->filedata['filename']),
                                    'width' => AVATAR_PROFILE_SIZE,
                                    'height' => AVATAR_PROFILE_SIZE,
                                    'alt' => $this->group->nickname));
        $this->elementEnd('div');

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

        // TRANS: Button text for cropping an uploaded group logo.
        $this->submit('crop', _('Crop'));

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

    /**
     * Handle a post
     *
     * We mux on the button name to figure out what the user actually wanted.
     *
     * @return void
     */
    function handlePost()
    {
        // CSRF protection

        $token = $this->trimmed('token');
        if (!$token || $token != common_session_token()) {
            // TRANS: Form validation error message.
            $this->show_form(_('There was a problem with your session token. '.
                               'Try again, please.'));
            return;
        }

        if ($this->arg('upload')) {
            $this->uploadLogo();
        } else if ($this->arg('crop')) {
            $this->cropLogo();
        } else {
            // TRANS: Form validation error message when an unsupported argument is used.
            $this->showForm(_('Unexpected form submission.'));
        }
    }

    /**
     * Handle an image upload
     *
     * Does all the magic for handling an image upload, and crops the
     * image by default.
     *
     * @return void
     */
    function uploadLogo()
    {
        try {
            $imagefile = ImageFile::fromUpload('avatarfile');
        } catch (Exception $e) {
            $this->showForm($e->getMessage());
            return;
        }

        $type = $imagefile->preferredType();
        $filename = Avatar::filename($this->group->id,
                                     image_type_to_extension($type),
                                     null,
                                     'group-temp-'.common_timestamp());

        $filepath = Avatar::path($filename);

        $imagefile->copyTo($filepath);

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

        $_SESSION['FILEDATA'] = $filedata;

        $this->filedata = $filedata;

        $this->mode = 'crop';

        // TRANS: Form instructions on the group logo page.
        $this->showForm(_('Pick a square area of the image to be the logo.'),
                        true);
    }

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

        if (!$filedata) {
            // TRANS: Server error displayed trying to crop an uploaded group logo that is no longer present.
            $this->serverError(_('Lost our file data.'));
        }

        // If image is not being cropped assume pos & dimentions of original
        $dest_x = $this->arg('avatar_crop_x') ? $this->arg('avatar_crop_x'):0;
        $dest_y = $this->arg('avatar_crop_y') ? $this->arg('avatar_crop_y'):0;
        $dest_w = $this->arg('avatar_crop_w') ? $this->arg('avatar_crop_w'):$filedata['width'];
        $dest_h = $this->arg('avatar_crop_h') ? $this->arg('avatar_crop_h'):$filedata['height'];
        $size = min($dest_w, $dest_h, common_config('avatar', 'maxsize'));
        $box = array('width' => $size, 'height' => $size,
                     'x' => $dest_x,   'y' => $dest_y,
                     'w' => $dest_w,   'h' => $dest_h);

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

        $imagefile = new ImageFile(null, $filedata['filepath']);
        $filename = Avatar::filename($profile->getID(), image_type_to_extension($imagefile->preferredType()),
                                     $size, common_timestamp());

        $imagefile->resizeTo(Avatar::path($filename), $box);

        if ($profile->setOriginal($filename)) {
            @unlink($filedata['filepath']);
            unset($_SESSION['FILEDATA']);
            $this->mode = 'upload';
            // TRANS: Form success message after updating a group logo.
            $this->showForm(_('Logo updated.'), true);
        } else {
            // TRANS: Form failure message after failing to update a group logo.
            $this->showForm(_('Failed updating logo.'));
        }
    }

    function showPageNotice()
    {
        if ($this->msg) {
            $this->element('div', ($this->success) ? 'success' : 'error',
                           $this->msg);
        } else {
            $inst   = $this->getInstructions();
            $output = common_markup_to_html($inst);

            $this->elementStart('div', 'instructions');
            $this->raw($output);
            $this->elementEnd('div');
        }
    }

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

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

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

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


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

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

require_once(INSTALLDIR.'/lib/profilelist.php');
require_once INSTALLDIR.'/lib/publicgroupnav.php';

/**
 * List of group members
 *
 * @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 GroupmembersAction extends GroupAction
{
    var $page = null;

    function isReadOnly($args)
    {
        return true;
    }

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

        $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;

        return true;
    }

    function title()
    {
        if ($this->page == 1) {
            // TRANS: Title of the page showing group members.
            // TRANS: %s is the name of the group.
            return sprintf(_('%s group members'),
                           $this->group->nickname);
        } else {
            // TRANS: Title of the page showing group members.
            // TRANS: %1$s is the name of the group, %2$d is the page number of the members list.
            return sprintf(_('%1$s group members, page %2$d'),
                           $this->group->nickname,
                           $this->page);
        }
    }

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

    function showPageNotice()
    {
        $this->element('p', 'instructions',
                       // TRANS: Page notice for group members page.
                       _('A list of the users in this group.'));
    }

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

        $cnt = 0;

        $members = $this->group->getMembers($offset, $limit);

        if ($members) {
            $member_list = new GroupMemberList($members, $this->group, $this);
            $cnt = $member_list->show();
        }

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


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

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

require_once(INSTALLDIR.'/lib/profilelist.php');
require_once INSTALLDIR.'/lib/publicgroupnav.php';

/**
 * List of group members
 *
 * @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 GroupqueueAction extends GroupAction
{
    var $page = null;

    function isReadOnly($args)
    {
        return true;
    }

    // @todo FIXME: most of this belongs in a base class, sounds common to most group actions?
    protected function prepare(array $args=array())
    {
        parent::prepare($args);
        $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;

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

        // Permanent redirect on non-canonical nickname

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

        if (!$nickname) {
            // TRANS: Client error displayed when trying to view group members without providing a group nickname.
            $this->clientError(_('No nickname.'), 404);
        }

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

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

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

        if (!$this->group) {
            // TRANS: Client error displayed when trying to view group members for an object that is not a group.
            $this->clientError(_('No such group.'), 404);
        }

        $cur = common_current_user();
        if (!$cur || !$cur->isAdmin($this->group)) {
            // TRANS: Client error displayed when trying to approve group applicants without being a group administrator.
            $this->clientError(_('Only the group admin may approve users.'));
        }
        return true;
    }

    function title()
    {
        if ($this->page == 1) {
            // TRANS: Title of the first page showing pending group members still awaiting approval to join the group.
            // TRANS: %s is the name of the group.
            return sprintf(_('%s group members awaiting approval'),
                           $this->group->nickname);
        } else {
            // TRANS: Title of all but the first page showing pending group members still awaiting approval to join the group.
            // TRANS: %1$s is the name of the group, %2$d is the page number of the members list.
            return sprintf(_('%1$s group members awaiting approval, page %2$d'),
                           $this->group->nickname,
                           $this->page);
        }
    }

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

    function showPageNotice()
    {
        $this->element('p', 'instructions',
                       // TRANS: Page notice for group members page.
                       _('A list of users awaiting approval to join this group.'));
    }

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

        $cnt = 0;

        $members = $this->group->getRequests($offset, $limit);

        if ($members) {
            // @fixme change!
            $member_list = new GroupQueueList($members, $this->group, $this);
            $cnt = $member_list->show();
        }

        $members->free();

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

// @todo FIXME: documentation missing.
class GroupQueueList extends GroupMemberList
{
    function newListItem($profile)
    {
        return new GroupQueueListItem($profile, $this->group, $this->action);
    }
}

// @todo FIXME: documentation missing.
class GroupQueueListItem extends GroupMemberListItem
{
    function showActions()
    {
        $this->startActions();
        if (Event::handle('StartProfileListItemActionElements', array($this))) {
            $this->showApproveButtons();
            Event::handle('EndProfileListItemActionElements', array($this));
        }
        $this->endActions();
    }

    function showApproveButtons()
    {
        $this->out->elementStart('li', 'entity_approval');
        $form = new ApproveGroupForm($this->out, $this->group, $this->profile);
        $form->show();
        $this->out->elementEnd('li');
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Group main page
 *
 * 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>
 * @author    Sarven Capadisli <csarven@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);
}

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

define('MEMBERS_PER_SECTION', 27);

/**
 * Group RSS feed
 *
 * @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 groupRssAction extends Rss10Action
{
    /** group we're viewing. */
    var $group = null;

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

    /**
     * Prepare the action
     *
     * Reads and validates arguments and instantiates the attributes.
     *
     * @param array $args $_REQUEST args
     *
     * @return boolean success flag
     */
    function prepare($args)
    {
        parent::prepare($args);

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

        // Permanent redirect on non-canonical nickname

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

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

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

        if (!$local) {
            // TRANS: Client error displayed when requesting a group RSS feed for group that does not exist.
            $this->clientError(_('No such group.'), 404);
        }

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

        if (!$this->group) {
            // TRANS: Client error displayed when requesting a group RSS feed for an object that is not a group.
            $this->clientError(_('No such group.'), 404);
        }

        $this->notices = $this->getNotices($this->limit);
        return true;
    }

    function getNotices($limit=0)
    {
        $group = $this->group;

        if (is_null($group)) {
            return null;
        }

        $notices = array();
        $notice = $group->getNotices(0, ($limit == 0) ? NOTICES_PER_PAGE : $limit);

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

        return $notices;
    }

    function getChannel()
    {
        $group = $this->group;
        $c = array('url' => common_local_url('grouprss',
                                             array('nickname' =>
                                                   $group->nickname)),
                   // TRANS: Message is used as link title. %s is a user nickname.
                   'title' => sprintf(_('%s timeline'), $group->nickname),
                   'link' => common_local_url('showgroup', array('nickname' => $group->nickname)),
                   // TRANS: Message is used as link description. %1$s is a group name, %2$s is a site name.
                   'description' => sprintf(_('Updates from members of %1$s on %2$s!'),
                                            $group->nickname, common_config('site', 'name')));
        return $c;
    }

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