We are no longer offering accounts on this server. Consider https://gitlab.freedesktop.org/ as a place to host projects.

Commit 80a17387 authored by Brion Vibber's avatar Brion Vibber

Command input processing now has centralized places for looking up notice,...

Command input processing now has centralized places for looking up notice, user/profile, and group arguments.
OStatus plugin overrides these to allow using webfinger (user@example.com), profile URL (http://example.com/user) and bare profile URL (example.com/user) as arguments.
parent 927a368d
<?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 =
common_relative_profile($this->user, $target_nickname);
$target = $this->getProfile($this->other);
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".
......
......@@ -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.
*/
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment