Merge branch 'testing' of git@gitorious.org:statusnet/mainline into testing

This commit is contained in:
Evan Prodromou 2010-03-10 14:13:02 -05:00
commit a2cc26ba8a
22 changed files with 595 additions and 196 deletions

View File

@ -52,7 +52,7 @@ class ApiStatusnetConfigAction extends ApiAction
var $keys = array(
'site' => array('name', 'server', 'theme', 'path', 'fancy', 'language',
'email', 'broughtby', 'broughtbyurl', 'closed',
'inviteonly', 'private'),
'inviteonly', 'private','textlimit'),
'license' => array('url', 'title', 'image'),
'nickname' => array('featured'),
'throttle' => array('enabled', 'count', 'timespan'),

View File

@ -126,6 +126,8 @@ class OtpAction extends Action
$this->lt->delete();
$this->lt = null;
common_real_login(true);
if ($this->rememberme) {
common_rememberme($this->user);
}

View File

@ -308,7 +308,7 @@ function checkPrereqs()
printf('<p class="error">PHP is linked to a version of the PCRE library ' .
'that does not support Unicode properties. ' .
'If you are running Red Hat Enterprise Linux / ' .
'CentOS 5.3 or earlier, see <a href="' .
'CentOS 5.4 or earlier, see <a href="' .
'http://status.net/wiki/Red_Hat_Enterprise_Linux#PCRE_library' .
'">our documentation page</a> on fixing this.</p>');
$pass = false;
@ -483,6 +483,7 @@ function showForm()
$dbRadios .= "<input type=\"radio\" name=\"dbtype\" id=\"dbtype-$type\" value=\"$type\" $checked/> $info[name]<br />\n";
}
}
echo<<<E_O_T
</ul>
</dd>
@ -559,6 +560,11 @@ function showForm()
<input id="admin_email" name="admin_email" value="{$post->value('admin_email')}" />
<p class="form_guide">Optional email address for the initial StatusNet user (administrator)</p>
</li>
<li>
<label for="admin_updates">Subscribe to announcements</label>
<input type="checkbox" id="admin_updates" name="admin_updates" value="true" checked="checked" />
<p class="form_guide">Release and security feed from <a href="http://update.status.net/">update@status.net</a> (recommended)</p>
</li>
</ul>
</fieldset>
<input type="submit" name="submit" class="submit" value="Submit" />
@ -583,10 +589,11 @@ function handlePost()
$sitename = $_POST['sitename'];
$fancy = !empty($_POST['fancy']);
$adminNick = $_POST['admin_nickname'];
$adminNick = strtolower($_POST['admin_nickname']);
$adminPass = $_POST['admin_password'];
$adminPass2 = $_POST['admin_password2'];
$adminEmail = $_POST['admin_email'];
$adminUpdates = $_POST['admin_updates'];
$server = $_SERVER['HTTP_HOST'];
$path = substr(dirname($_SERVER['PHP_SELF']), 1);
@ -623,6 +630,19 @@ STR;
updateStatus("No initial StatusNet user nickname specified.", true);
$fail = true;
}
if ($adminNick && !preg_match('/^[0-9a-z]{1,64}$/', $adminNick)) {
updateStatus('The user nickname "' . htmlspecialchars($adminNick) .
'" is invalid; should be plain letters and numbers no longer than 64 characters.', true);
$fail = true;
}
// @fixme hardcoded list; should use User::allowed_nickname()
// if/when it's safe to have loaded the infrastructure here
$blacklist = array('main', 'admin', 'twitter', 'settings', 'rsd.xml', 'favorited', 'featured', 'favoritedrss', 'featuredrss', 'rss', 'getfile', 'api', 'groups', 'group', 'peopletag', 'tag', 'user', 'message', 'conversation', 'bookmarklet', 'notice', 'attachment', 'search', 'index.php', 'doc', 'opensearch', 'robots.txt', 'xd_receiver.html', 'facebook');
if (in_array($adminNick, $blacklist)) {
updateStatus('The user nickname "' . htmlspecialchars($adminNick) .
'" is reserved.', true);
$fail = true;
}
if (empty($adminPass)) {
updateStatus("No initial StatusNet user password specified.", true);
@ -657,7 +677,7 @@ STR;
}
// Okay, cross fingers and try to register an initial user
if (registerInitialUser($adminNick, $adminPass, $adminEmail)) {
if (registerInitialUser($adminNick, $adminPass, $adminEmail, $adminUpdates)) {
updateStatus(
"An initial user with the administrator role has been created."
);
@ -854,7 +874,7 @@ function runDbScript($filename, $conn, $type = 'mysqli')
return true;
}
function registerInitialUser($nickname, $password, $email)
function registerInitialUser($nickname, $password, $email, $adminUpdates)
{
define('STATUSNET', true);
define('LACONICA', true); // compatibility
@ -882,7 +902,7 @@ function registerInitialUser($nickname, $password, $email)
// Attempt to do a remote subscribe to update@status.net
// Will fail if instance is on a private network.
if (class_exists('Ostatus_profile')) {
if (class_exists('Ostatus_profile') && $adminUpdates) {
try {
$oprofile = Ostatus_profile::ensureProfile('http://update.status.net/');
Subscription::start($user->getProfile(), $oprofile->localProfile());

View File

@ -767,11 +767,14 @@ class Action extends HTMLOutputter // lawsuit
{
$this->element('dt', array('id' => 'site_statusnet_license'), _('StatusNet software license'));
$this->elementStart('dd', null);
// @fixme drop the final spaces in the messages when at good spot
// to let translations get updated.
if (common_config('site', 'broughtby')) {
$instr = _('**%%site.name%%** is a microblogging service brought to you by [%%site.broughtby%%](%%site.broughtbyurl%%). ');
} else {
$instr = _('**%%site.name%%** is a microblogging service. ');
}
$instr .= ' ';
$instr .= sprintf(_('It runs the [StatusNet](http://status.net/) microblogging software, version %s, available under the [GNU Affero General Public License](http://www.fsf.org/licensing/licenses/agpl-3.0.html).'), STATUSNET_VERSION);
$output = common_markup_to_html($instr);
$this->raw($output);

View File

@ -235,9 +235,13 @@ class ApiAuthAction extends ApiAction
{
$this->basicAuthProcessHeader();
$realm = common_config('site', 'name') . ' API';
$realm = common_config('api', 'realm');
if (!isset($this->auth_user_nickname) && $required) {
if (empty($realm)) {
$realm = common_config('site', 'name') . ' API';
}
if (empty($this->auth_user_nickname) && $required) {
header('WWW-Authenticate: Basic realm="' . $realm . '"');
// show error if the user clicks 'cancel'

View File

@ -47,6 +47,25 @@ class Channel
}
}
class CLIChannel extends Channel
{
function source()
{
return 'cli';
}
function output($user, $text)
{
$site = common_config('site', 'name');
print "[{$user->nickname}@{$site}] $text\n";
}
function error($user, $text)
{
$this->output($user, $text);
}
}
class XMPPChannel extends Channel
{

View File

@ -1,7 +1,7 @@
<?php
/*
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2008, 2009, StatusNet, Inc.
* Copyright (C) 2008, 2009, 2010 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
@ -31,15 +31,147 @@ class Command
$this->user = $user;
}
function execute($channel)
/**
* Execute the command and send success or error results
* back via the given communications channel.
*
* @param Channel
*/
public function execute($channel)
{
try {
$this->handle($channel);
} catch (CommandException $e) {
$channel->error($this->user, $e->getMessage());
} catch (Exception $e) {
common_log(LOG_ERR, "Error handling " . get_class($this) . ": " . $e->getMessage());
$channel->error($this->user, $e->getMessage());
}
}
/**
* Override this with the meat!
*
* An error to send back to the user may be sent by throwing
* a CommandException with a formatted message.
*
* @param Channel
* @throws CommandException
*/
function handle($channel)
{
return false;
}
/**
* Look up a notice from an argument, by poster's name to get last post
* or notice_id prefixed with #.
*
* @return Notice
* @throws CommandException
*/
function getNotice($arg)
{
$notice = null;
if (Event::handle('StartCommandGetNotice', array($this, $arg, &$notice))) {
if(substr($this->other,0,1)=='#'){
// A specific notice_id #123
$notice = Notice::staticGet(substr($arg,1));
if (!$notice) {
throw new CommandException(_('Notice with that id does not exist'));
}
}
if (Validate::uri($this->other)) {
// A specific notice by URI lookup
$notice = Notice::staticGet('uri', $arg);
}
if (!$notice) {
// Local or remote profile name to get their last notice.
// May throw an exception and report 'no such user'
$recipient = $this->getProfile($arg);
$notice = $recipient->getCurrentNotice();
if (!$notice) {
throw new CommandException(_('User has no last notice'));
}
}
}
Event::handle('EndCommandGetNotice', array($this, $arg, &$notice));
if (!$notice) {
throw new CommandException(_('Notice with that id does not exist'));
}
return $notice;
}
/**
* Look up a local or remote profile by nickname.
*
* @return Profile
* @throws CommandException
*/
function getProfile($arg)
{
$profile = null;
if (Event::handle('StartCommandGetProfile', array($this, $arg, &$profile))) {
$profile =
common_relative_profile($this->user, common_canonical_nickname($arg));
}
Event::handle('EndCommandGetProfile', array($this, $arg, &$profile));
if (!$profile) {
throw new CommandException(sprintf(_('Could not find a user with nickname %s'), $arg));
}
return $profile;
}
/**
* Get a local user by name
* @return User
* @throws CommandException
*/
function getUser($arg)
{
$user = null;
if (Event::handle('StartCommandGetUser', array($this, $arg, &$user))) {
$user = User::staticGet('nickname', $arg);
}
Event::handle('EndCommandGetUser', array($this, $arg, &$user));
if (!$user){
throw new CommandException(sprintf(_('Could not find a local user with nickname %s'),
$arg));
}
return $user;
}
/**
* Get a local or remote group by name.
* @return User_group
* @throws CommandException
*/
function getGroup($arg)
{
$group = null;
if (Event::handle('StartCommandGetGroup', array($this, $arg, &$group))) {
$group = User_group::getForNickname($arg, $this->user->getProfile());
}
Event::handle('EndCommandGetGroup', array($this, $arg, &$group));
if (!$group) {
throw new CommandException(_('No such group.'));
}
return $group;
}
}
class CommandException extends Exception
{
}
class UnimplementedCommand extends Command
{
function execute($channel)
function handle($channel)
{
$channel->error($this->user, _("Sorry, this command is not yet implemented."));
}
@ -81,24 +213,20 @@ class NudgeCommand extends Command
parent::__construct($user);
$this->other = $other;
}
function execute($channel)
function handle($channel)
{
$recipient = User::staticGet('nickname', $this->other);
if(! $recipient){
$channel->error($this->user, sprintf(_('Could not find a user with nickname %s'),
$this->other));
}else{
if ($recipient->id == $this->user->id) {
$channel->error($this->user, _('It does not make a lot of sense to nudge yourself!'));
}else{
if ($recipient->email && $recipient->emailnotifynudge) {
mail_notify_nudge($this->user, $recipient);
}
// XXX: notify by IM
// XXX: notify by SMS
$channel->output($this->user, sprintf(_('Nudge sent to %s'),
$recipient->nickname));
$recipient = $this->getUser($this->other);
if ($recipient->id == $this->user->id) {
throw new CommandException(_('It does not make a lot of sense to nudge yourself!'));
} else {
if ($recipient->email && $recipient->emailnotifynudge) {
mail_notify_nudge($this->user, $recipient);
}
// XXX: notify by IM
// XXX: notify by SMS
$channel->output($this->user, sprintf(_('Nudge sent to %s'),
$recipient->nickname));
}
}
}
@ -115,7 +243,7 @@ class InviteCommand extends UnimplementedCommand
class StatsCommand extends Command
{
function execute($channel)
function handle($channel)
{
$profile = $this->user->getProfile();
@ -142,34 +270,9 @@ class FavCommand extends Command
$this->other = $other;
}
function execute($channel)
function handle($channel)
{
if(substr($this->other,0,1)=='#'){
//favoriting a specific notice_id
$notice = Notice::staticGet(substr($this->other,1));
if (!$notice) {
$channel->error($this->user, _('Notice with that id does not exist'));
return;
}
$recipient = $notice->getProfile();
}else{
//favoriting a given user's last notice
$recipient =
common_relative_profile($this->user, common_canonical_nickname($this->other));
if (!$recipient) {
$channel->error($this->user, _('No such user.'));
return;
}
$notice = $recipient->getCurrentNotice();
if (!$notice) {
$channel->error($this->user, _('User has no last notice'));
return;
}
}
$notice = $this->getNotice($this->other);
$fave = Fave::addNew($this->user, $notice);
if (!$fave) {
@ -177,7 +280,10 @@ class FavCommand extends Command
return;
}
$other = User::staticGet('id', $recipient->id);
// @fixme favorite notification should be triggered
// at a lower level
$other = User::staticGet('id', $notice->profile_id);
if ($other && $other->id != $user->id) {
if ($other->email && $other->emailnotifyfav) {
@ -191,6 +297,7 @@ class FavCommand extends Command
}
}
class JoinCommand extends Command
{
var $other = null;
@ -201,17 +308,10 @@ class JoinCommand extends Command
$this->other = $other;
}
function execute($channel)
function handle($channel)
{
$nickname = common_canonical_nickname($this->other);
$group = User_group::staticGet('nickname', $nickname);
$cur = $this->user;
if (!$group) {
$channel->error($cur, _('No such group.'));
return;
}
$group = $this->getGroup($this->other);
$cur = $this->user;
if ($cur->isMember($group)) {
$channel->error($cur, _('You are already a member of that group'));
@ -249,12 +349,10 @@ class DropCommand extends Command
$this->other = $other;
}
function execute($channel)
function handle($channel)
{
$nickname = common_canonical_nickname($this->other);
$group = User_group::staticGet('nickname', $nickname);
$cur = $this->user;
$group = $this->getGroup($this->other);
$cur = $this->user;
if (!$group) {
$channel->error($cur, _('No such group.'));
@ -293,15 +391,9 @@ class WhoisCommand extends Command
$this->other = $other;
}
function execute($channel)
function handle($channel)
{
$recipient =
common_relative_profile($this->user, common_canonical_nickname($this->other));
if (!$recipient) {
$channel->error($this->user, _('No such user.'));
return;
}
$recipient = $this->getProfile($this->other);
$whois = sprintf(_("%1\$s (%2\$s)"), $recipient->nickname,
$recipient->profileurl);
@ -332,9 +424,18 @@ class MessageCommand extends Command
$this->text = $text;
}
function execute($channel)
function handle($channel)
{
$other = User::staticGet('nickname', common_canonical_nickname($this->other));
try {
$other = $this->getUser($this->other);
} catch (CommandException $e) {
try {
$profile = $this->getProfile($this->other);
} catch (CommandException $f) {
throw $e;
}
throw new CommandException(sprintf(_('%s is a remote profile; you can only send direct messages to users on the same server.'), $this->other));
}
$len = mb_strlen($this->text);
@ -380,33 +481,9 @@ class RepeatCommand extends Command
$this->other = $other;
}
function execute($channel)
function handle($channel)
{
if(substr($this->other,0,1)=='#'){
//repeating a specific notice_id
$notice = Notice::staticGet(substr($this->other,1));
if (!$notice) {
$channel->error($this->user, _('Notice with that id does not exist'));
return;
}
$recipient = $notice->getProfile();
}else{
//repeating a given user's last notice
$recipient =
common_relative_profile($this->user, common_canonical_nickname($this->other));
if (!$recipient) {
$channel->error($this->user, _('No such user.'));
return;
}
$notice = $recipient->getCurrentNotice();
if (!$notice) {
$channel->error($this->user, _('User has no last notice'));
return;
}
}
$notice = $this->getNotice($this->other);
if($this->user->id == $notice->profile_id)
{
@ -414,7 +491,7 @@ class RepeatCommand extends Command
return;
}
if ($recipient->hasRepeated($notice->id)) {
if ($this->user->getProfile()->hasRepeated($notice->id)) {
$channel->error($this->user, _('Already repeated that notice'));
return;
}
@ -441,33 +518,10 @@ class ReplyCommand extends Command
$this->text = $text;
}
function execute($channel)
function handle($channel)
{
if(substr($this->other,0,1)=='#'){
//replying to a specific notice_id
$notice = Notice::staticGet(substr($this->other,1));
if (!$notice) {
$channel->error($this->user, _('Notice with that id does not exist'));
return;
}
$recipient = $notice->getProfile();
}else{
//replying to a given user's last notice
$recipient =
common_relative_profile($this->user, common_canonical_nickname($this->other));
if (!$recipient) {
$channel->error($this->user, _('No such user.'));
return;
}
$notice = $recipient->getCurrentNotice();
if (!$notice) {
$channel->error($this->user, _('User has no last notice'));
return;
}
}
$notice = $this->getNotice($this->other);
$recipient = $notice->getProfile();
$len = mb_strlen($this->text);
@ -507,17 +561,10 @@ class GetCommand extends Command
$this->other = $other;
}
function execute($channel)
function handle($channel)
{
$target_nickname = common_canonical_nickname($this->other);
$target = $this->getProfile($this->other);
$target =
common_relative_profile($this->user, $target_nickname);
if (!$target) {
$channel->error($this->user, _('No such user.'));
return;
}
$notice = $target->getCurrentNotice();
if (!$notice) {
$channel->error($this->user, _('User has no last notice'));
@ -525,7 +572,7 @@ class GetCommand extends Command
}
$notice_content = $notice->content;
$channel->output($this->user, $target_nickname . ": " . $notice_content);
$channel->output($this->user, $target->nickname . ": " . $notice_content);
}
}
@ -540,7 +587,7 @@ class SubCommand extends Command
$this->other = $other;
}
function execute($channel)
function handle($channel)
{
if (!$this->other) {
@ -548,16 +595,16 @@ class SubCommand extends Command
return;
}
$otherUser = User::staticGet('nickname', $this->other);
$target = $this->getProfile($this->other);
if (empty($otherUser)) {
$channel->error($this->user, _('No such user'));
return;
$remote = Remote_profile::staticGet('id', $target->id);
if ($remote) {
throw new CommandException(_("Can't subscribe to OMB profiles by command."));
}
try {
Subscription::start($this->user->getProfile(),
$otherUser->getProfile());
$target);
$channel->output($this->user, sprintf(_('Subscribed to %s'), $this->other));
} catch (Exception $e) {
$channel->error($this->user, $e->getMessage());
@ -576,22 +623,18 @@ class UnsubCommand extends Command
$this->other = $other;
}
function execute($channel)
function handle($channel)
{
if(!$this->other) {
$channel->error($this->user, _('Specify the name of the user to unsubscribe from'));
return;
}
$otherUser = User::staticGet('nickname', $this->other);
if (empty($otherUser)) {
$channel->error($this->user, _('No such user'));
}
$target = $this->getProfile($this->other);
try {
Subscription::cancel($this->user->getProfile(),
$otherUser->getProfile());
$target);
$channel->output($this->user, sprintf(_('Unsubscribed from %s'), $this->other));
} catch (Exception $e) {
$channel->error($this->user, $e->getMessage());
@ -607,7 +650,7 @@ class OffCommand extends Command
parent::__construct($user);
$this->other = $other;
}
function execute($channel)
function handle($channel)
{
if ($other) {
$channel->error($this->user, _("Command not yet implemented."));
@ -630,7 +673,7 @@ class OnCommand extends Command
$this->other = $other;
}
function execute($channel)
function handle($channel)
{
if ($other) {
$channel->error($this->user, _("Command not yet implemented."));
@ -646,7 +689,7 @@ class OnCommand extends Command
class LoginCommand extends Command
{
function execute($channel)
function handle($channel)
{
$disabled = common_config('logincommand','disabled');
$disabled = isset($disabled) && $disabled;
@ -670,7 +713,7 @@ class LoginCommand extends Command
class SubscriptionsCommand extends Command
{
function execute($channel)
function handle($channel)
{
$profile = $this->user->getSubscriptions(0);
$nicknames=array();
@ -692,7 +735,7 @@ class SubscriptionsCommand extends Command
class SubscribersCommand extends Command
{
function execute($channel)
function handle($channel)
{
$profile = $this->user->getSubscribers();
$nicknames=array();
@ -714,7 +757,7 @@ class SubscribersCommand extends Command
class GroupsCommand extends Command
{
function execute($channel)
function handle($channel)
{
$group = $this->user->getGroups();
$groups=array();
@ -735,7 +778,7 @@ class GroupsCommand extends Command
class HelpCommand extends Command
{
function execute($channel)
function handle($channel)
{
$channel->output($this->user,
_("Commands:\n".

View File

@ -293,4 +293,6 @@ $default =
array('crawldelay' => 0,
'disallow' => array('main', 'settings', 'admin', 'search', 'message')
),
'api' =>
array('realm' => null),
);

View File

@ -88,22 +88,30 @@ class Sharing_XMPP extends XMPPHP_XMPP
/**
* Build an XMPP proxy connection that'll save outgoing messages
* to the 'xmppout' queue to be picked up by xmppdaemon later.
*
* If queueing is disabled, we'll grab a live connection.
*
* @return XMPPHP
*/
function jabber_proxy()
{
$proxy = new Queued_XMPP(common_config('xmpp', 'host') ?
common_config('xmpp', 'host') :
common_config('xmpp', 'server'),
common_config('xmpp', 'port'),
common_config('xmpp', 'user'),
common_config('xmpp', 'password'),
common_config('xmpp', 'resource') . 'daemon',
common_config('xmpp', 'server'),
common_config('xmpp', 'debug') ?
true : false,
common_config('xmpp', 'debug') ?
XMPPHP_Log::LEVEL_VERBOSE : null);
return $proxy;
if (common_config('queue', 'enabled')) {
$proxy = new Queued_XMPP(common_config('xmpp', 'host') ?
common_config('xmpp', 'host') :
common_config('xmpp', 'server'),
common_config('xmpp', 'port'),
common_config('xmpp', 'user'),
common_config('xmpp', 'password'),
common_config('xmpp', 'resource') . 'daemon',
common_config('xmpp', 'server'),
common_config('xmpp', 'debug') ?
true : false,
common_config('xmpp', 'debug') ?
XMPPHP_Log::LEVEL_VERBOSE : null);
return $proxy;
} else {
return jabber_connect();
}
}
/**

View File

@ -49,10 +49,20 @@ class Queued_XMPP extends XMPPHP_XMPP
*/
public function __construct($host, $port, $user, $password, $resource, $server = null, $printlog = false, $loglevel = null)
{
parent::__construct($host, $port, $user, $password, $resource, $server, $printlog, $loglevel);
// Normally the fulljid isn't filled out until resource binding time;
// we need to save it here since we're not talking to a real server.
$this->fulljid = "{$this->basejid}/{$this->resource}";
parent::__construct($host, $port, $user, $password, $resource, $server, $printlog, $loglevel);
// We use $host to connect, but $server to build JIDs if specified.
// This seems to fix an upstream bug where $host was used to build
// $this->basejid, never seen since it isn't actually used in the base
// classes.
if (!$server) {
$server = $this->host;
}
$this->basejid = $this->user . '@' . $server;
// Normally the fulljid is filled out by the server at resource binding
// time, but we need to do it since we're not talking to a real server.
$this->fulljid = "{$this->basejid}/{$this->resource}";
}
/**

View File

@ -52,17 +52,43 @@ function common_init_language()
{
mb_internal_encoding('UTF-8');
// gettext seems very picky... We first need to setlocale()
// to a locale which _does_ exist on the system, and _then_
// we can set in another locale that may not be set up
// (say, ga_ES for Galego/Galician) it seems to take it.
common_init_locale("en_US");
// Note that this setlocale() call may "fail" but this is harmless;
// gettext will still select the right language.
$language = common_language();
$locale_set = common_init_locale($language);
if (!$locale_set) {
// The requested locale doesn't exist on the system.
//
// gettext seems very picky... We first need to setlocale()
// to a locale which _does_ exist on the system, and _then_
// we can set in another locale that may not be set up
// (say, ga_ES for Galego/Galician) it seems to take it.
//
// For some reason C and POSIX which are guaranteed to work
// don't do the job. en_US.UTF-8 should be there most of the
// time, but not guaranteed.
$ok = common_init_locale("en_US");
if (!$ok) {
// Try to find a complete, working locale...
// @fixme shelling out feels awfully inefficient
// but I don't think there's a more standard way.
$all = `locale -a`;
foreach (explode("\n", $all) as $locale) {
if (preg_match('/\.utf[-_]?8$/i', $locale)) {
$ok = setlocale(LC_ALL, $locale);
if ($ok) {
break;
}
}
}
if (!$ok) {
common_log(LOG_ERR, "Unable to find a UTF-8 locale on this system; UI translations may not work.");
}
}
$locale_set = common_init_locale($language);
}
setlocale(LC_CTYPE, 'C');
// So we do not have to make people install the gettext locales
$path = common_config('site','locale_path');
@ -133,6 +159,11 @@ function common_munge_password($password, $id)
function common_check_user($nickname, $password)
{
// empty nickname always unacceptable
if (empty($nickname)) {
return false;
}
$authenticatedUser = false;
if (Event::handle('StartCheckPassword', array($nickname, $password, &$authenticatedUser))) {

View File

@ -36,6 +36,7 @@ class XmppManager extends IoManager
protected $site = null;
protected $pingid = 0;
protected $lastping = null;
protected $conn = null;
static protected $singletons = array();

View File

@ -321,6 +321,86 @@ class OStatusPlugin extends Plugin
return true;
}
/**
* Allow remote profile references to be used in commands:
* sub update@status.net
* whois evan@identi.ca
* reply http://identi.ca/evan hey what's up
*
* @param Command $command
* @param string $arg
* @param Profile &$profile
* @return hook return code
*/
function onStartCommandGetProfile($command, $arg, &$profile)
{
$oprofile = $this->pullRemoteProfile($arg);
if ($oprofile && !$oprofile->isGroup()) {
$profile = $oprofile->localProfile();
return false;
} else {
return true;
}
}
/**
* Allow remote group references to be used in commands:
* join group+statusnet@identi.ca
* join http://identi.ca/group/statusnet
* drop identi.ca/group/statusnet
*
* @param Command $command
* @param string $arg
* @param User_group &$group
* @return hook return code
*/
function onStartCommandGetGroup($command, $arg, &$group)
{
$oprofile = $this->pullRemoteProfile($arg);
if ($oprofile && $oprofile->isGroup()) {
$group = $oprofile->localGroup();
return false;
} else {
return true;
}
}
protected function pullRemoteProfile($arg)
{
$oprofile = null;
if (preg_match('!^((?:\w+\.)*\w+@(?:\w+\.)*\w+(?:\w+\-\w+)*\.\w+)$!', $arg)) {
// webfinger lookup
try {
return Ostatus_profile::ensureWebfinger($arg);
} catch (Exception $e) {
common_log(LOG_ERR, 'Webfinger lookup failed for ' .
$arg . ': ' . $e->getMessage());
}
}
// Look for profile URLs, with or without scheme:
$urls = array();
if (preg_match('!^https?://((?:\w+\.)*\w+(?:\w+\-\w+)*\.\w+(?:/\w+)+)$!', $arg)) {
$urls[] = $arg;
}
if (preg_match('!^((?:\w+\.)*\w+(?:\w+\-\w+)*\.\w+(?:/\w+)+)$!', $arg)) {
$schemes = array('http', 'https');
foreach ($schemes as $scheme) {
$urls[] = "$scheme://$arg";
}
}
foreach ($urls as $url) {
try {
return Ostatus_profile::ensureProfile($url);
} catch (Exception $e) {
common_log(LOG_ERR, 'Profile lookup failed for ' .
$arg . ': ' . $e->getMessage());
}
}
return null;
}
/**
* Make sure necessary tables are filled out.
*/

View File

@ -192,7 +192,7 @@ class HubSub extends Memcached_DataObject
// Any existing query string parameters must be preserved
$url = $this->callback;
if (strpos('?', $url) !== false) {
if (strpos($url, '?') !== false) {
$url .= '&';
} else {
$url .= '?';

View File

@ -129,7 +129,7 @@ class FeedDiscovery
function initFromResponse($response)
{
if (!$response->isOk()) {
throw new FeedSubBadResponseException($response->getCode());
throw new FeedSubBadResponseException($response->getStatus());
}
$sourceurl = $response->getUrl();

View File

@ -152,7 +152,7 @@ class RSSCloudNotifier
function notify($profile)
{
$feed = common_path('api/statuses/user_timeline/') .
$profile->nickname . '.rss';
$profile->id . '.rss';
$cloudSub = new RSSCloudSubscription();

View File

@ -270,13 +270,14 @@ class RSSCloudRequestNotifyAction extends Action
function userFromFeed($feed)
{
// We only do profile feeds
// We only do canonical RSS2 profile feeds (specified by ID), e.g.:
// http://www.example.com/api/statuses/user_timeline/2.rss
$path = common_path('api/statuses/user_timeline/');
$valid = '%^' . $path . '(?<nickname>.*)\.rss$%';
$valid = '%^' . $path . '(?<id>.*)\.rss$%';
if (preg_match($valid, $feed, $matches)) {
$user = User::staticGet('nickname', $matches['nickname']);
$user = User::staticGet('id', $matches['id']);
if (!empty($user)) {
return $user;
}

View File

@ -14,8 +14,6 @@ registered prior to that timestamp.
Todo:
* make email field required on registration form
* add a more visible indicator that validation is still outstanding
* localization for UI strings
* test with XMPP, API posting

View File

@ -54,12 +54,33 @@ class RequireValidatedEmailPlugin extends Plugin
$user = User::staticGet('id', $notice->profile_id);
if (!empty($user)) { // it's a remote notice
if (!$this->validated($user)) {
throw new ClientException(_("You must validate your email address before posting."));
throw new ClientException(_m("You must validate your email address before posting."));
}
}
return true;
}
/**
* Event handler for registration attempts; rejects the registration
* if email field is missing.
*
* @param RegisterAction $action
* @return bool hook result code
*/
function onStartRegistrationTry($action)
{
$email = $action->trimmed('email');
if (empty($email)) {
$action->showForm(_m('You must provide an email address to register.'));
return false;
}
// Default form will run address format validation and reject if bad.
return true;
}
/**
* Check if a user has a validated email address or has been
* otherwise grandfathered in.

View File

@ -0,0 +1,31 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-03-10 10:05-0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: RequireValidatedEmailPlugin.php:57
msgid "You must validate your email address before posting."
msgstr ""
#: RequireValidatedEmailPlugin.php:75
msgid "You must provide an email address to register."
msgstr ""
#: RequireValidatedEmailPlugin.php:128
msgid ""
"The Require Validated Email plugin disables posting for accounts that do not "
"have a validated email address."
msgstr ""

80
scripts/command.php Executable file
View File

@ -0,0 +1,80 @@
#!/usr/bin/env php
<?php
/*
* StatusNet - a distributed open-source microblogging tool
* Copyright (C) 2008, 2009, 2010 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/>.
*/
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
$shortoptions = 'i:n:';
$longoptions = array('id=', 'nickname=');
$helptext = <<<END_OF_USERROLE_HELP
command.php [options] [command line]
Perform commands on behalf of a user, such as sub, unsub, join, drop
-i --id ID of the user
-n --nickname nickname of the user
END_OF_USERROLE_HELP;
require_once INSTALLDIR.'/scripts/commandline.inc';
function interpretCommand($user, $body)
{
$inter = new CommandInterpreter();
$chan = new CLIChannel();
$cmd = $inter->handle_command($user, $body);
if ($cmd) {
$cmd->execute($chan);
return true;
} else {
$chan->error($user, "Not a valid command. Try 'help'?");
return false;
}
}
if (have_option('i', 'id')) {
$id = get_option_value('i', 'id');
$user = User::staticGet('id', $id);
if (empty($user)) {
print "Can't find user with ID $id\n";
exit(1);
}
} else if (have_option('n', 'nickname')) {
$nickname = get_option_value('n', 'nickname');
$user = User::staticGet('nickname', $nickname);
if (empty($user)) {
print "Can't find user with nickname '$nickname'\n";
exit(1);
}
} else {
print "You must provide either an ID or a nickname.\n\n";
print $helptext;
exit(1);
}
// @todo refactor the interactive console in console.php and use
// that to optionally make an interactive test console here too.
// Would be good to help people test commands when XMPP or email
// isn't available locally.
interpretCommand($user, implode(' ', $args));

45
scripts/flushsite.php Normal file
View File

@ -0,0 +1,45 @@
#!/usr/bin/env php
<?php
/*
* StatusNet - a 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/>.
*/
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
$shortoptions = 'd';
$longoptions = array('delete');
$helptext = <<<END_OF_FLUSHSITE_HELP
flushsite.php -s<sitename>
Flush the site with the given name from memcached.
END_OF_FLUSHSITE_HELP;
require_once INSTALLDIR.'/scripts/commandline.inc';
$nickname = common_config('site', 'nickname');
$sn = Status_network::memGet('nickname', $nickname);
if (empty($sn)) {
print "No such site.\n";
exit(-1);
}
print "Flushing cache for {$nickname}...";
$sn->decache();
print "OK.\n";