git.gnu.io has moved to IP address 209.51.188.249 -- please double check where you are logging in.

Commit e9995b0f authored by Craig Andrews's avatar Craig Andrews

Create IM plugin, Pluginize XMPP, Create AIM plugin

parent 5224c7d6
......@@ -699,3 +699,21 @@ StartShowContentLicense: Showing the default license for content
EndShowContentLicense: Showing the default license for content
- $action: the current action
GetImTransports: Get IM transports that are available
- &$transports: append your transport to this array like so: $transports[transportName]=array('display'=>display)
NormalizeImScreenname: Normalize an IM screenname
- $transport: transport the screenname is on
- &$screenname: screenname to be normalized
ValidateImScreenname: Validate an IM screenname
- $transport: transport the screenname is on
- $screenname: screenname to be validated
- $valid: is the screenname valid?
SendImConfirmationCode: Send a confirmation code to confirm a user owns an IM screenname
- $transport: transport the screenname exists on
- $screenname: screenname being confirmed
- $code: confirmation code for confirmation URL
- $user: user requesting the confirmation
......@@ -119,10 +119,16 @@ class ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction
if (strtolower($this->device) == 'sms') {
$this->user->smsnotify = true;
} elseif (strtolower($this->device) == 'im') {
$this->user->jabbernotify = true;
//TODO IM is pluginized now, so what should we do?
//Enable notifications for all IM plugins?
//For now, don't do anything
//$this->user->jabbernotify = true;
} elseif (strtolower($this->device == 'none')) {
$this->user->smsnotify = false;
$this->user->jabbernotify = false;
//TODO IM is pluginized now, so what should we do?
//Disable notifications for all IM plugins?
//For now, don't do anything
//$this->user->jabbernotify = false;
}
$result = $this->user->update($original);
......
......@@ -49,7 +49,7 @@ class ConfirmaddressAction extends Action
{
/** type of confirmation. */
var $type = null;
var $address;
/**
* Accept a confirmation code
......@@ -86,37 +86,75 @@ class ConfirmaddressAction extends Action
return;
}
$type = $confirm->address_type;
if (!in_array($type, array('email', 'jabber', 'sms'))) {
$transports = array();
Event::handle('GetImTransports', array(&$transports));
if (!in_array($type, array('email', 'sms')) && !in_array($type, array_keys($transports))) {
$this->serverError(sprintf(_('Unrecognized address type %s'), $type));
return;
}
if ($cur->$type == $confirm->address) {
$this->clientError(_('That address has already been confirmed.'));
return;
}
$this->address = $confirm->address;
$cur->query('BEGIN');
if (in_array($type, array('email', 'sms')))
{
if ($cur->$type == $confirm->address) {
$this->clientError(_('That address has already been confirmed.'));
return;
}
$orig_user = clone($cur);
$cur->$type = $confirm->address;
if ($type == 'sms') {
$cur->carrier = ($confirm->address_extra)+0;
$carrier = Sms_carrier::staticGet($cur->carrier);
$cur->smsemail = $carrier->toEmailAddress($cur->sms);
}
$result = $cur->updateKeys($orig_user);
if (!$result) {
common_log_db_error($cur, 'UPDATE', __FILE__);
$this->serverError(_('Couldn\'t update user.'));
return;
}
if ($type == 'email') {
$cur->emailChanged();
}
} else {
$user_im_prefs = new User_im_prefs();
$user_im_prefs->transport = $confirm->address_type;
$user_im_prefs->user_id = $cur->id;
if ($user_im_prefs->find() && $user_im_prefs->fetch()) {
if($user_im_prefs->screenname == $confirm->address){
$this->clientError(_('That address has already been confirmed.'));
return;
}
$user_im_prefs->screenname = $confirm->address;
$result = $user_im_prefs->update();
if (!$result) {
common_log_db_error($user_im_prefs, 'UPDATE', __FILE__);
$this->serverError(_('Couldn\'t update user im preferences.'));
return;
}
}else{
$user_im_prefs = new User_im_prefs();
$user_im_prefs->screenname = $confirm->address;
$user_im_prefs->transport = $confirm->address_type;
$user_im_prefs->user_id = $cur->id;
$result = $user_im_prefs->insert();
if (!$result) {
common_log_db_error($user_im_prefs, 'INSERT', __FILE__);
$this->serverError(_('Couldn\'t insert user im preferences.'));
return;
}
}
$orig_user = clone($cur);
$cur->$type = $confirm->address;
if ($type == 'sms') {
$cur->carrier = ($confirm->address_extra)+0;
$carrier = Sms_carrier::staticGet($cur->carrier);
$cur->smsemail = $carrier->toEmailAddress($cur->sms);
}
$result = $cur->updateKeys($orig_user);
if (!$result) {
common_log_db_error($cur, 'UPDATE', __FILE__);
$this->serverError(_('Couldn\'t update user.'));
return;
}
if ($type == 'email') {
$cur->emailChanged();
}
$result = $confirm->delete();
......@@ -128,8 +166,6 @@ class ConfirmaddressAction extends Action
}
$cur->query('COMMIT');
$this->type = $type;
$this->showPage();
}
......@@ -153,11 +189,10 @@ class ConfirmaddressAction extends Action
function showContent()
{
$cur = common_current_user();
$type = $this->type;
$this->element('p', null,
sprintf(_('The address "%s" has been '.
'confirmed for your account.'),
$cur->$type));
$this->address));
}
}
This diff is collapsed.
......@@ -275,12 +275,6 @@ class ShownoticeAction extends OwnerDesignAction
'content' => $id->toString()));
}
if ($user->jabbermicroid && $user->jabber && $this->notice->uri) {
$id = new Microid('xmpp:', $user->jabber,
$this->notice->uri);
$this->element('meta', array('name' => 'microid',
'content' => $id->toString()));
}
$this->element('link',array('rel'=>'alternate',
'type'=>'application/json+oembed',
'href'=>common_local_url(
......
......@@ -166,12 +166,6 @@ class ShowstreamAction extends ProfileAction
$this->element('meta', array('name' => 'microid',
'content' => $id->toString()));
}
if ($this->user->jabbermicroid && $this->user->jabber && $this->profile->profileurl) {
$id = new Microid('xmpp:'.$this->user->jabber,
$this->selfUrl());
$this->element('meta', array('name' => 'microid',
'content' => $id->toString()));
}
// See https://wiki.mozilla.org/Microsummaries
......
......@@ -48,11 +48,6 @@ class User extends Memcached_DataObject
public $language; // varchar(50)
public $timezone; // varchar(50)
public $emailpost; // tinyint(1) default_1
public $jabber; // varchar(255) unique_key
public $jabbernotify; // tinyint(1)
public $jabberreplies; // tinyint(1)
public $jabbermicroid; // tinyint(1) default_1
public $updatefrompresence; // tinyint(1)
public $sms; // varchar(64) unique_key
public $carrier; // int(4)
public $smsnotify; // tinyint(1)
......@@ -92,7 +87,7 @@ class User extends Memcached_DataObject
function updateKeys(&$orig)
{
$parts = array();
foreach (array('nickname', 'email', 'jabber', 'incomingemail', 'sms', 'carrier', 'smsemail', 'language', 'timezone') as $k) {
foreach (array('nickname', 'email', 'incomingemail', 'sms', 'carrier', 'smsemail', 'language', 'timezone') as $k) {
if (strcmp($this->$k, $orig->$k) != 0) {
$parts[] = $k . ' = ' . $this->_quote($this->$k);
}
......
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Data class for user IM preferences
*
* 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 Data
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @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/
*/
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
class User_im_prefs extends Memcached_DataObject
{
###START_AUTOCODE
/* the code below is auto generated do not remove the above tag */
public $__table = 'user_im_prefs'; // table name
public $user_id; // int(4) primary_key not_null
public $screenname; // varchar(255) not_null
public $transport; // varchar(255) not_null
public $notify; // tinyint(1)
public $replies; // tinyint(1)
public $microid; // tinyint(1)
public $updatefrompresence; // tinyint(1)
public $created; // datetime not_null default_0000-00-00%2000%3A00%3A00
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
/* Static get */
function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('User_im_prefs',$k,$v); }
function pkeyGet($kv)
{
return Memcached_DataObject::pkeyGet('User_im_prefs', $kv);
}
/* the code above is auto generated do not remove the tag below */
###END_AUTOCODE
/*
DB_DataObject calculates the sequence key(s) by taking the first key returned by the keys() function.
In this case, the keys() function returns user_id as the first key. user_id is not a sequence, but
DB_DataObject's sequenceKey() will incorrectly think it is. Then, since the sequenceKey() is a numeric
type, but is not set to autoincrement in the database, DB_DataObject will create a _seq table and
manage the sequence itself. This is not the correct behavior for the user_id in this class.
So we override that incorrect behavior, and simply say there is no sequence key.
*/
function sequenceKey()
{
return array(false,false);
}
}
......@@ -540,11 +540,6 @@ emailmicroid = 17
language = 2
timezone = 2
emailpost = 17
jabber = 2
jabbernotify = 17
jabberreplies = 17
jabbermicroid = 17
updatefrompresence = 17
sms = 2
carrier = 1
smsnotify = 17
......@@ -564,7 +559,6 @@ id = K
nickname = U
email = U
incomingemail = U
jabber = U
sms = U
uri = U
......@@ -616,3 +610,19 @@ modified = 384
[user_location_prefs__keys]
user_id = K
[user_im_prefs]
user_id = 129
screenname = 130
transport = 130
notify = 17
replies = 17
microid = 17
updatefrompresence = 17
created = 142
modified = 384
[user_im_prefs__keys]
user_id = K
transport = K
transport = U
screenname = U
......@@ -62,11 +62,6 @@ create table user (
language varchar(50) comment 'preferred language',
timezone varchar(50) comment 'timezone',
emailpost tinyint default 1 comment 'Post by email',
jabber varchar(255) unique key comment 'jabber ID for notices',
jabbernotify tinyint default 0 comment 'whether to send notices to jabber',
jabberreplies tinyint default 0 comment 'whether to send notices to jabber on replies',
jabbermicroid tinyint default 1 comment 'whether to publish xmpp microid',
updatefrompresence tinyint default 0 comment 'whether to record updates from Jabber presence notices',
sms varchar(64) unique key comment 'sms phone number',
carrier integer comment 'foreign key to sms_carrier' references sms_carrier (id),
smsnotify tinyint default 0 comment 'whether to send notices to SMS',
......@@ -259,9 +254,9 @@ create table oid_nonces (
create table confirm_address (
code varchar(32) not null primary key comment 'good random code',
user_id integer not null comment 'user who requested confirmation' references user (id),
address varchar(255) not null comment 'address (email, Jabber, SMS, etc.)',
address varchar(255) not null comment 'address (email, xmpp, SMS, etc.)',
address_extra varchar(255) not null comment 'carrier ID, for SMS',
address_type varchar(8) not null comment 'address type ("email", "jabber", "sms")',
address_type varchar(8) not null comment 'address type ("email", "xmpp", "sms")',
claimed datetime comment 'date this was claimed for queueing',
sent datetime comment 'date this was sent for queueing',
modified timestamp comment 'date this record was modified'
......@@ -276,7 +271,7 @@ create table remember_me (
create table queue_item (
id integer auto_increment primary key comment 'unique identifier',
frame blob not null comment 'data: object reference or opaque string',
transport varchar(8) not null comment 'queue for what? "email", "jabber", "sms", "irc", ...',
transport varchar(8) not null comment 'queue for what? "email", "xmpp", "sms", "irc", ...',
created datetime not null comment 'date this record was created',
claimed datetime comment 'date this item was claimed',
......@@ -348,7 +343,7 @@ create table invitation (
code varchar(32) not null primary key comment 'random code for an invitation',
user_id int not null comment 'who sent the invitation' references user (id),
address varchar(255) not null comment 'invitation sent to',
address_type varchar(8) not null comment 'address type ("email", "jabber", "sms")',
address_type varchar(8) not null comment 'address type ("email", "xmpp", "sms")',
created datetime not null comment 'date this record was created',
index invitation_address_idx (address, address_type),
......@@ -633,3 +628,18 @@ create table inbox (
constraint primary key (user_id)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
create table user_im_prefs (
user_id integer not null comment 'user' references user (id),
screenname varchar(255) not null comment 'screenname on this service',
transport varchar(255) not null comment 'transport (ex xmpp, aim)',
notify tinyint(1) not null default 0 comment 'Notify when a new notice is sent',
replies tinyint(1) not null default 0 comment 'Send replies from people not subscribed to',
microid tinyint(1) not null default 1 comment 'Publish a MicroID',
updatefrompresence tinyint(1) not null default 0 comment 'Send replies from people not subscribed to.',
created timestamp not null DEFAULT CURRENT_TIMESTAMP comment 'date this record was created',
modified timestamp comment 'date this record was modified',
constraint primary key (user_id, transport),
constraint unique key `transport_screenname_key` ( `transport` , `screenname` )
);
......@@ -47,63 +47,6 @@ class Channel
}
}
class XMPPChannel extends Channel
{
var $conn = null;
function source()
{
return 'xmpp';
}
function __construct($conn)
{
$this->conn = $conn;
}
function on($user)
{
return $this->set_notify($user, 1);
}
function off($user)
{
return $this->set_notify($user, 0);
}
function output($user, $text)
{
$text = '['.common_config('site', 'name') . '] ' . $text;
jabber_send_message($user->jabber, $text);
}
function error($user, $text)
{
$text = '['.common_config('site', 'name') . '] ' . $text;
jabber_send_message($user->jabber, $text);
}
function set_notify(&$user, $notify)
{
$orig = clone($user);
$user->jabbernotify = $notify;
$result = $user->update($orig);
if (!$result) {
$last_error = &PEAR::getStaticProperty('DB_DataObject','lastError');
common_log(LOG_ERR,
'Could not set notify flag to ' . $notify .
' for user ' . common_log_objstring($user) .
': ' . $last_error->message);
return false;
} else {
common_log(LOG_INFO,
'User ' . $user->nickname . ' set notify flag to ' . $notify);
return true;
}
}
}
class WebChannel extends Channel
{
var $out = null;
......
......@@ -596,7 +596,7 @@ class OffCommand extends Command
}
function execute($channel)
{
if ($other) {
if ($this->other) {
$channel->error($this->user, _("Command not yet implemented."));
} else {
if ($channel->off($this->user)) {
......@@ -619,7 +619,7 @@ class OnCommand extends Command
function execute($channel)
{
if ($other) {
if ($this->other) {
$channel->error($this->user, _("Command not yet implemented."));
} else {
if ($channel->on($this->user)) {
......
<?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); }
class IMChannel extends Channel
{
var $imPlugin;
function source()
{
return $imPlugin->transport;
}
function __construct($imPlugin)
{
$this->imPlugin = $imPlugin;
}
function on($user)
{
return $this->set_notify($user, 1);
}
function off($user)
{
return $this->set_notify($user, 0);
}
function output($user, $text)
{
$text = '['.common_config('site', 'name') . '] ' . $text;
$this->imPlugin->send_message($this->imPlugin->get_screenname($user), $text);
}
function error($user, $text)
{
$text = '['.common_config('site', 'name') . '] ' . $text;
$screenname = $this->imPlugin->get_screenname($user);
if($screenname){
$this->imPlugin->send_message($screenname, $text);
return true;
}else{
common_log(LOG_ERR,
'Could not send error message to user ' . common_log_objstring($user) .
' on transport ' . $this->imPlugin->transport .' : user preference does not exist');
return false;
}
}
function set_notify($user, $notify)
{
$user_im_prefs = new User_im_prefs();
$user_im_prefs->transport = $this->imPlugin->transport;
$user_im_prefs->user_id = $user->id;
if($user_im_prefs->find() && $user_im_prefs->fetch()){
if($user_im_prefs->notify == $notify){
//notify is already set the way they want
return true;
}else{
$original = clone($user_im_prefs);
$user_im_prefs->notify = $notify;
$result = $user_im_prefs->update($original);
if (!$result) {
$last_error = &PEAR::getStaticProperty('DB_DataObject','lastError');
common_log(LOG_ERR,
'Could not set notify flag to ' . $notify .
' for user ' . common_log_objstring($user) .
' on transport ' . $this->imPlugin->transport .' : ' . $last_error->message);
return false;
} else {
common_log(LOG_INFO,
'User ' . $user->nickname . ' set notify flag to ' . $notify);
return true;
}
}
}else{
common_log(LOG_ERR,
'Could not set notify flag to ' . $notify .
' for user ' . common_log_objstring($user) .
' on transport ' . $this->imPlugin->transport .' : user preference does not exist');
return false;
}
}
}
<?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); }
/**
* IKM background connection manager for IM-using queue handlers,
* allowing them to send outgoing messages on the right connection.
*
* In a multi-site queuedaemon.php run, one connection will be instantiated
* for each site being handled by the current process that has IM enabled.
*
* Implementations that extend this class will likely want to:
* 1) override start() with their connection process.
* 2) override handleInput() with what to do when data is waiting on
* one of the sockets
* 3) override idle($timeout) to do keepalives (if necessary)
* 4) implement send_raw_message() to send raw data that ImPlugin::enqueue_outgoing_raw
* enqueued
*/
abstract class ImManager extends IoManager
{
abstract function send_raw_message($data);
function __construct($imPlugin)
{
$this->plugin = $imPlugin;
//TODO We only really want to register this event if this is the thread that runs the ImManager
Event::addHandler('EndInitializeQueueManager', array($this, 'onEndInitializeQueueManager'));
}
/**
* Fetch the singleton manager for the current site.
* @return mixed ImManager, or false if unneeded
*/
public static function get()
{
throw new Exception('ImManager should be created using it\'s constructor, not the static get method');
}
/**
* Register notice queue handler
*
* @param QueueManager $manager
*
* @return boolean hook return
*/
function onEndInitializeQueueManager($manager)
{
$manager->connect($this->plugin->transport . '-out', new ImSenderQueueHandler($this->plugin, $this), 'imdaemon');
return true;
}
}
This diff is collapsed.
......@@ -17,31 +17,32 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
/**
* Queue handler for pushing new notices to Jabber users.
* @fixme this exception handling doesn't look very good.
* Common superclass for all IM sending queue handlers.
*/
class JabberQueueHandler extends QueueHandler
{
var $conn = null;
function transport()
class ImQueueHandler extends QueueHandler
{
function __construct($plugin)
{
return 'jabber';
$this->plugin = $plugin;
}
/**
* Handle a notice
* @param Notice $notice
* @return boolean success
*/
function handle($notice)
{
require_once(INSTALLDIR.'/lib/jabber.php');
try {
return jabber_broadcast_notice($notice);
} catch (XMPPHP_Exception $e) {
$this->log(LOG_ERR, "Got an XMPPHP_Exception: " . $e->getMessage());
return false;
$this->plugin->broadcast_notice($notice);
if ($notice->is_local == Notice::LOCAL_PUBLIC ||
$notice->is_local == Notice::LOCAL_NONPUBLIC) {
$this->plugin->public_notice($notice);
}
return true;
}
}
......@@ -17,29 +17,26 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
/**
* Queue handler for pushing new notices to public XMPP subscribers.
* Common superclass for all IM receiving queue handlers.
*/
class PublicQueueHandler extends QueueHandler
{
function transport()
class ImReceiverQueueHandler extends QueueHandler
{
function __construct($plugin)
{
return 'public';