Create IM plugin, Pluginize XMPP, Create AIM plugin
This commit is contained in:
parent
5224c7d6c2
commit
e9995b0f6a
18
EVENTS.txt
18
EVENTS.txt
@ -699,3 +699,21 @@ StartShowContentLicense: Showing the default license for content
|
|||||||
|
|
||||||
EndShowContentLicense: Showing the default license for content
|
EndShowContentLicense: Showing the default license for content
|
||||||
- $action: the current action
|
- $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') {
|
if (strtolower($this->device) == 'sms') {
|
||||||
$this->user->smsnotify = true;
|
$this->user->smsnotify = true;
|
||||||
} elseif (strtolower($this->device) == 'im') {
|
} 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')) {
|
} elseif (strtolower($this->device == 'none')) {
|
||||||
$this->user->smsnotify = false;
|
$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);
|
$result = $this->user->update($original);
|
||||||
|
@ -49,7 +49,7 @@ class ConfirmaddressAction extends Action
|
|||||||
{
|
{
|
||||||
/** type of confirmation. */
|
/** type of confirmation. */
|
||||||
|
|
||||||
var $type = null;
|
var $address;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accept a confirmation code
|
* Accept a confirmation code
|
||||||
@ -86,37 +86,75 @@ class ConfirmaddressAction extends Action
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$type = $confirm->address_type;
|
$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));
|
$this->serverError(sprintf(_('Unrecognized address type %s'), $type));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($cur->$type == $confirm->address) {
|
$this->address = $confirm->address;
|
||||||
$this->clientError(_('That address has already been confirmed.'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$cur->query('BEGIN');
|
$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);
|
$orig_user = clone($cur);
|
||||||
|
|
||||||
$cur->$type = $confirm->address;
|
$cur->$type = $confirm->address;
|
||||||
|
|
||||||
if ($type == 'sms') {
|
if ($type == 'sms') {
|
||||||
$cur->carrier = ($confirm->address_extra)+0;
|
$cur->carrier = ($confirm->address_extra)+0;
|
||||||
$carrier = Sms_carrier::staticGet($cur->carrier);
|
$carrier = Sms_carrier::staticGet($cur->carrier);
|
||||||
$cur->smsemail = $carrier->toEmailAddress($cur->sms);
|
$cur->smsemail = $carrier->toEmailAddress($cur->sms);
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $cur->updateKeys($orig_user);
|
$result = $cur->updateKeys($orig_user);
|
||||||
|
|
||||||
if (!$result) {
|
if (!$result) {
|
||||||
common_log_db_error($cur, 'UPDATE', __FILE__);
|
common_log_db_error($cur, 'UPDATE', __FILE__);
|
||||||
$this->serverError(_('Couldn\'t update user.'));
|
$this->serverError(_('Couldn\'t update user.'));
|
||||||
return;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($type == 'email') {
|
|
||||||
$cur->emailChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $confirm->delete();
|
$result = $confirm->delete();
|
||||||
@ -128,8 +166,6 @@ class ConfirmaddressAction extends Action
|
|||||||
}
|
}
|
||||||
|
|
||||||
$cur->query('COMMIT');
|
$cur->query('COMMIT');
|
||||||
|
|
||||||
$this->type = $type;
|
|
||||||
$this->showPage();
|
$this->showPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,11 +189,10 @@ class ConfirmaddressAction extends Action
|
|||||||
function showContent()
|
function showContent()
|
||||||
{
|
{
|
||||||
$cur = common_current_user();
|
$cur = common_current_user();
|
||||||
$type = $this->type;
|
|
||||||
|
|
||||||
$this->element('p', null,
|
$this->element('p', null,
|
||||||
sprintf(_('The address "%s" has been '.
|
sprintf(_('The address "%s" has been '.
|
||||||
'confirmed for your account.'),
|
'confirmed for your account.'),
|
||||||
$cur->$type));
|
$this->address));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,9 +31,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
require_once INSTALLDIR.'/lib/connectsettingsaction.php';
|
|
||||||
require_once INSTALLDIR.'/lib/jabber.php';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Settings for Jabber/XMPP integration
|
* Settings for Jabber/XMPP integration
|
||||||
*
|
*
|
||||||
@ -68,8 +65,8 @@ class ImsettingsAction extends ConnectSettingsAction
|
|||||||
function getInstructions()
|
function getInstructions()
|
||||||
{
|
{
|
||||||
return _('You can send and receive notices through '.
|
return _('You can send and receive notices through '.
|
||||||
'Jabber/GTalk [instant messages](%%doc.im%%). '.
|
'instant messaging [instant messages](%%doc.im%%). '.
|
||||||
'Configure your address and settings below.');
|
'Configure your addresses and settings below.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -84,85 +81,108 @@ class ImsettingsAction extends ConnectSettingsAction
|
|||||||
|
|
||||||
function showContent()
|
function showContent()
|
||||||
{
|
{
|
||||||
if (!common_config('xmpp', 'enabled')) {
|
$transports = array();
|
||||||
|
Event::handle('GetImTransports', array(&$transports));
|
||||||
|
if (! $transports) {
|
||||||
$this->element('div', array('class' => 'error'),
|
$this->element('div', array('class' => 'error'),
|
||||||
_('IM is not available.'));
|
_('IM is not available.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
$this->elementStart('form', array('method' => 'post',
|
|
||||||
'id' => 'form_settings_im',
|
|
||||||
'class' => 'form_settings',
|
|
||||||
'action' =>
|
|
||||||
common_local_url('imsettings')));
|
|
||||||
$this->elementStart('fieldset', array('id' => 'settings_im_address'));
|
|
||||||
$this->element('legend', null, _('Address'));
|
|
||||||
$this->hidden('token', common_session_token());
|
|
||||||
|
|
||||||
if ($user->jabber) {
|
$user_im_prefs_by_transport = array();
|
||||||
$this->element('p', 'form_confirmed', $user->jabber);
|
|
||||||
$this->element('p', 'form_note',
|
|
||||||
_('Current confirmed Jabber/GTalk address.'));
|
|
||||||
$this->hidden('jabber', $user->jabber);
|
|
||||||
$this->submit('remove', _('Remove'));
|
|
||||||
} else {
|
|
||||||
$confirm = $this->getConfirmation();
|
|
||||||
if ($confirm) {
|
|
||||||
$this->element('p', 'form_unconfirmed', $confirm->address);
|
|
||||||
$this->element('p', 'form_note',
|
|
||||||
sprintf(_('Awaiting confirmation on this address. '.
|
|
||||||
'Check your Jabber/GTalk account for a '.
|
|
||||||
'message with further instructions. '.
|
|
||||||
'(Did you add %s to your buddy list?)'),
|
|
||||||
jabber_daemon_address()));
|
|
||||||
$this->hidden('jabber', $confirm->address);
|
|
||||||
$this->submit('cancel', _('Cancel'));
|
|
||||||
} else {
|
|
||||||
$this->elementStart('ul', 'form_data');
|
|
||||||
$this->elementStart('li');
|
|
||||||
$this->input('jabber', _('IM address'),
|
|
||||||
($this->arg('jabber')) ? $this->arg('jabber') : null,
|
|
||||||
sprintf(_('Jabber or GTalk address, '.
|
|
||||||
'like "UserName@example.org". '.
|
|
||||||
'First, make sure to add %s to your '.
|
|
||||||
'buddy list in your IM client or on GTalk.'),
|
|
||||||
jabber_daemon_address()));
|
|
||||||
$this->elementEnd('li');
|
|
||||||
$this->elementEnd('ul');
|
|
||||||
$this->submit('add', _('Add'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->elementEnd('fieldset');
|
|
||||||
|
|
||||||
$this->elementStart('fieldset', array('id' => 'settings_im_preferences'));
|
foreach($transports as $transport=>$transport_info)
|
||||||
$this->element('legend', null, _('Preferences'));
|
{
|
||||||
$this->elementStart('ul', 'form_data');
|
$this->elementStart('form', array('method' => 'post',
|
||||||
$this->elementStart('li');
|
'id' => 'form_settings_im',
|
||||||
$this->checkbox('jabbernotify',
|
'class' => 'form_settings',
|
||||||
_('Send me notices through Jabber/GTalk.'),
|
'action' =>
|
||||||
$user->jabbernotify);
|
common_local_url('imsettings')));
|
||||||
$this->elementEnd('li');
|
$this->elementStart('fieldset', array('id' => 'settings_im_address'));
|
||||||
$this->elementStart('li');
|
$this->element('legend', null, $transport_info['display']);
|
||||||
$this->checkbox('updatefrompresence',
|
$this->hidden('token', common_session_token());
|
||||||
_('Post a notice when my Jabber/GTalk status changes.'),
|
$this->hidden('transport', $transport);
|
||||||
$user->updatefrompresence);
|
|
||||||
$this->elementEnd('li');
|
if ($user_im_prefs = User_im_prefs::pkeyGet( array('transport' => $transport, 'user_id' => $user->id) )) {
|
||||||
$this->elementStart('li');
|
$user_im_prefs_by_transport[$transport] = $user_im_prefs;
|
||||||
$this->checkbox('jabberreplies',
|
$this->element('p', 'form_confirmed', $user_im_prefs->screenname);
|
||||||
_('Send me replies through Jabber/GTalk '.
|
$this->element('p', 'form_note',
|
||||||
'from people I\'m not subscribed to.'),
|
sprintf(_('Current confirmed %s address.'),$transport_info['display']));
|
||||||
$user->jabberreplies);
|
$this->hidden('screenname', $user_im_prefs->screenname);
|
||||||
$this->elementEnd('li');
|
$this->submit('remove', _('Remove'));
|
||||||
$this->elementStart('li');
|
} else {
|
||||||
$this->checkbox('jabbermicroid',
|
$confirm = $this->getConfirmation($transport);
|
||||||
_('Publish a MicroID for my Jabber/GTalk address.'),
|
if ($confirm) {
|
||||||
$user->jabbermicroid);
|
$this->element('p', 'form_unconfirmed', $confirm->address);
|
||||||
$this->elementEnd('li');
|
$this->element('p', 'form_note',
|
||||||
$this->elementEnd('ul');
|
sprintf(_('Awaiting confirmation on this address. '.
|
||||||
$this->submit('save', _('Save'));
|
'Check your %s account for a '.
|
||||||
$this->elementEnd('fieldset');
|
'message with further instructions.'),
|
||||||
$this->elementEnd('form');
|
$transport_info['display']));
|
||||||
|
$this->hidden('screenname', $confirm->address);
|
||||||
|
$this->submit('cancel', _('Cancel'));
|
||||||
|
} else {
|
||||||
|
$this->elementStart('ul', 'form_data');
|
||||||
|
$this->elementStart('li');
|
||||||
|
$this->input('screenname', _('IM address'),
|
||||||
|
($this->arg('screenname')) ? $this->arg('screenname') : null,
|
||||||
|
sprintf(_('%s screenname.'),
|
||||||
|
$transport_info['display']));
|
||||||
|
$this->elementEnd('li');
|
||||||
|
$this->elementEnd('ul');
|
||||||
|
$this->submit('add', _('Add'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->elementEnd('fieldset');
|
||||||
|
$this->elementEnd('form');
|
||||||
|
}
|
||||||
|
|
||||||
|
if($user_im_prefs_by_transport)
|
||||||
|
{
|
||||||
|
$this->elementStart('form', array('method' => 'post',
|
||||||
|
'id' => 'form_settings_im',
|
||||||
|
'class' => 'form_settings',
|
||||||
|
'action' =>
|
||||||
|
common_local_url('imsettings')));
|
||||||
|
$this->elementStart('fieldset', array('id' => 'settings_im_preferences'));
|
||||||
|
$this->element('legend', null, _('Preferences'));
|
||||||
|
$this->hidden('token', common_session_token());
|
||||||
|
$this->elementStart('table');
|
||||||
|
$this->elementStart('tr');
|
||||||
|
$this->element('th', null, _('Preferences'));
|
||||||
|
foreach($user_im_prefs_by_transport as $transport=>$user_im_prefs)
|
||||||
|
{
|
||||||
|
$this->element('th', null, $transports[$transport]['display']);
|
||||||
|
}
|
||||||
|
$this->elementEnd('tr');
|
||||||
|
$preferences = array(
|
||||||
|
array('name'=>'notify', 'description'=>_('Send me notices')),
|
||||||
|
array('name'=>'updatefrompresence', 'description'=>_('Post a notice when my status changes.')),
|
||||||
|
array('name'=>'replies', 'description'=>_('Send me replies '.
|
||||||
|
'from people I\'m not subscribed to.')),
|
||||||
|
array('name'=>'microid', 'description'=>_('Publish a MicroID'))
|
||||||
|
);
|
||||||
|
foreach($preferences as $preference)
|
||||||
|
{
|
||||||
|
$this->elementStart('tr');
|
||||||
|
foreach($user_im_prefs_by_transport as $transport=>$user_im_prefs)
|
||||||
|
{
|
||||||
|
$preference_name = $preference['name'];
|
||||||
|
$this->elementStart('td');
|
||||||
|
$this->checkbox($transport . '_' . $preference['name'],
|
||||||
|
$preference['description'],
|
||||||
|
$user_im_prefs->$preference_name);
|
||||||
|
$this->elementEnd('td');
|
||||||
|
}
|
||||||
|
$this->elementEnd('tr');
|
||||||
|
}
|
||||||
|
$this->elementEnd('table');
|
||||||
|
$this->submit('save', _('Save'));
|
||||||
|
$this->elementEnd('fieldset');
|
||||||
|
$this->elementEnd('form');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -171,14 +191,14 @@ class ImsettingsAction extends ConnectSettingsAction
|
|||||||
* @return Confirm_address address object for this user
|
* @return Confirm_address address object for this user
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function getConfirmation()
|
function getConfirmation($transport)
|
||||||
{
|
{
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
|
|
||||||
$confirm = new Confirm_address();
|
$confirm = new Confirm_address();
|
||||||
|
|
||||||
$confirm->user_id = $user->id;
|
$confirm->user_id = $user->id;
|
||||||
$confirm->address_type = 'jabber';
|
$confirm->address_type = $transport;
|
||||||
|
|
||||||
if ($confirm->find(true)) {
|
if ($confirm->find(true)) {
|
||||||
return $confirm;
|
return $confirm;
|
||||||
@ -232,35 +252,31 @@ class ImsettingsAction extends ConnectSettingsAction
|
|||||||
|
|
||||||
function savePreferences()
|
function savePreferences()
|
||||||
{
|
{
|
||||||
|
|
||||||
$jabbernotify = $this->boolean('jabbernotify');
|
|
||||||
$updatefrompresence = $this->boolean('updatefrompresence');
|
|
||||||
$jabberreplies = $this->boolean('jabberreplies');
|
|
||||||
$jabbermicroid = $this->boolean('jabbermicroid');
|
|
||||||
|
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
|
|
||||||
assert(!is_null($user)); // should already be checked
|
$user_im_prefs = new User_im_prefs();
|
||||||
|
$user_im_prefs->user_id = $user->id;
|
||||||
|
if($user_im_prefs->find() && $user_im_prefs->fetch())
|
||||||
|
{
|
||||||
|
$preferences = array('notify', 'updatefrompresence', 'replies', 'microid');
|
||||||
|
$user_im_prefs->query('BEGIN');
|
||||||
|
do
|
||||||
|
{
|
||||||
|
$original = clone($user_im_prefs);
|
||||||
|
foreach($preferences as $preference)
|
||||||
|
{
|
||||||
|
$user_im_prefs->$preference = $this->boolean($user_im_prefs->transport . '_' . $preference);
|
||||||
|
}
|
||||||
|
$result = $user_im_prefs->update($original);
|
||||||
|
|
||||||
$user->query('BEGIN');
|
if ($result === false) {
|
||||||
|
common_log_db_error($user, 'UPDATE', __FILE__);
|
||||||
$original = clone($user);
|
$this->serverError(_('Couldn\'t update IM preferences.'));
|
||||||
|
return;
|
||||||
$user->jabbernotify = $jabbernotify;
|
}
|
||||||
$user->updatefrompresence = $updatefrompresence;
|
}while($user_im_prefs->fetch());
|
||||||
$user->jabberreplies = $jabberreplies;
|
$user_im_prefs->query('COMMIT');
|
||||||
$user->jabbermicroid = $jabbermicroid;
|
|
||||||
|
|
||||||
$result = $user->update($original);
|
|
||||||
|
|
||||||
if ($result === false) {
|
|
||||||
common_log_db_error($user, 'UPDATE', __FILE__);
|
|
||||||
$this->serverError(_('Couldn\'t update user.'));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$user->query('COMMIT');
|
|
||||||
|
|
||||||
$this->showForm(_('Preferences saved.'), true);
|
$this->showForm(_('Preferences saved.'), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +284,7 @@ class ImsettingsAction extends ConnectSettingsAction
|
|||||||
* Sends a confirmation to the address given
|
* Sends a confirmation to the address given
|
||||||
*
|
*
|
||||||
* Stores a confirmation record and sends out a
|
* Stores a confirmation record and sends out a
|
||||||
* Jabber message with the confirmation info.
|
* message with the confirmation info.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
@ -277,36 +293,41 @@ class ImsettingsAction extends ConnectSettingsAction
|
|||||||
{
|
{
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
|
|
||||||
$jabber = $this->trimmed('jabber');
|
$screenname = $this->trimmed('screenname');
|
||||||
|
$transport = $this->trimmed('transport');
|
||||||
|
|
||||||
// Some validation
|
// Some validation
|
||||||
|
|
||||||
if (!$jabber) {
|
if (!$screenname) {
|
||||||
$this->showForm(_('No Jabber ID.'));
|
$this->showForm(_('No screenname.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$jabber = jabber_normalize_jid($jabber);
|
if (!$transport) {
|
||||||
|
$this->showForm(_('No transport.'));
|
||||||
if (!$jabber) {
|
|
||||||
$this->showForm(_('Cannot normalize that Jabber ID'));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!jabber_valid_base_jid($jabber)) {
|
|
||||||
$this->showForm(_('Not a valid Jabber ID'));
|
Event::handle('NormalizeImScreenname', array($transport, &$screenname));
|
||||||
|
|
||||||
|
if (!$screenname) {
|
||||||
|
$this->showForm(_('Cannot normalize that screenname'));
|
||||||
return;
|
return;
|
||||||
} else if ($user->jabber == $jabber) {
|
}
|
||||||
$this->showForm(_('That is already your Jabber ID.'));
|
$valid = false;
|
||||||
|
Event::handle('ValidateImScreenname', array($transport, $screenname, &$valid));
|
||||||
|
if (!$valid) {
|
||||||
|
$this->showForm(_('Not a valid screenname'));
|
||||||
return;
|
return;
|
||||||
} else if ($this->jabberExists($jabber)) {
|
} else if ($this->screennameExists($transport, $screenname)) {
|
||||||
$this->showForm(_('Jabber ID already belongs to another user.'));
|
$this->showForm(_('Screenname already belongs to another user.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$confirm = new Confirm_address();
|
$confirm = new Confirm_address();
|
||||||
|
|
||||||
$confirm->address = $jabber;
|
$confirm->address = $screenname;
|
||||||
$confirm->address_type = 'jabber';
|
$confirm->address_type = $transport;
|
||||||
$confirm->user_id = $user->id;
|
$confirm->user_id = $user->id;
|
||||||
$confirm->code = common_confirmation_code(64);
|
$confirm->code = common_confirmation_code(64);
|
||||||
$confirm->sent = common_sql_now();
|
$confirm->sent = common_sql_now();
|
||||||
@ -320,15 +341,10 @@ class ImsettingsAction extends ConnectSettingsAction
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
jabber_confirm_address($confirm->code,
|
Event::handle('SendImConfirmationCode', array($transport, $screenname, $confirm->code, $user));
|
||||||
$user->nickname,
|
|
||||||
$jabber);
|
|
||||||
|
|
||||||
$msg = sprintf(_('A confirmation code was sent '.
|
$msg = _('A confirmation code was sent '.
|
||||||
'to the IM address you added. '.
|
'to the IM address you added.');
|
||||||
'You must approve %s for '.
|
|
||||||
'sending messages to you.'),
|
|
||||||
jabber_daemon_address());
|
|
||||||
|
|
||||||
$this->showForm($msg, true);
|
$this->showForm($msg, true);
|
||||||
}
|
}
|
||||||
@ -343,15 +359,16 @@ class ImsettingsAction extends ConnectSettingsAction
|
|||||||
|
|
||||||
function cancelConfirmation()
|
function cancelConfirmation()
|
||||||
{
|
{
|
||||||
$jabber = $this->arg('jabber');
|
$screenname = $this->trimmed('screenname');
|
||||||
|
$transport = $this->trimmed('transport');
|
||||||
|
|
||||||
$confirm = $this->getConfirmation();
|
$confirm = $this->getConfirmation($transport);
|
||||||
|
|
||||||
if (!$confirm) {
|
if (!$confirm) {
|
||||||
$this->showForm(_('No pending confirmation to cancel.'));
|
$this->showForm(_('No pending confirmation to cancel.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($confirm->address != $jabber) {
|
if ($confirm->address != $screenname) {
|
||||||
$this->showForm(_('That is the wrong IM address.'));
|
$this->showForm(_('That is the wrong IM address.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -360,7 +377,7 @@ class ImsettingsAction extends ConnectSettingsAction
|
|||||||
|
|
||||||
if (!$result) {
|
if (!$result) {
|
||||||
common_log_db_error($confirm, 'DELETE', __FILE__);
|
common_log_db_error($confirm, 'DELETE', __FILE__);
|
||||||
$this->serverError(_('Couldn\'t delete email confirmation.'));
|
$this->serverError(_('Couldn\'t delete confirmation.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,29 +396,25 @@ class ImsettingsAction extends ConnectSettingsAction
|
|||||||
{
|
{
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
|
|
||||||
$jabber = $this->arg('jabber');
|
$screenname = $this->trimmed('screenname');
|
||||||
|
$transport = $this->trimmed('transport');
|
||||||
|
|
||||||
// Maybe an old tab open...?
|
// Maybe an old tab open...?
|
||||||
|
|
||||||
if ($user->jabber != $jabber) {
|
$user_im_prefs = new User_im_prefs();
|
||||||
$this->showForm(_('That is not your Jabber ID.'));
|
$user_im_prefs->user_id = $user->id;
|
||||||
|
if(! ($user_im_prefs->find() && $user_im_prefs->fetch())) {
|
||||||
|
$this->showForm(_('That is not your screenname.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$user->query('BEGIN');
|
$result = $user_im_prefs->delete();
|
||||||
|
|
||||||
$original = clone($user);
|
|
||||||
|
|
||||||
$user->jabber = null;
|
|
||||||
|
|
||||||
$result = $user->updateKeys($original);
|
|
||||||
|
|
||||||
if (!$result) {
|
if (!$result) {
|
||||||
common_log_db_error($user, 'UPDATE', __FILE__);
|
common_log_db_error($user, 'UPDATE', __FILE__);
|
||||||
$this->serverError(_('Couldn\'t update user.'));
|
$this->serverError(_('Couldn\'t update user im prefs.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$user->query('COMMIT');
|
|
||||||
|
|
||||||
// XXX: unsubscribe to the old address
|
// XXX: unsubscribe to the old address
|
||||||
|
|
||||||
@ -409,25 +422,27 @@ class ImsettingsAction extends ConnectSettingsAction
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does this Jabber ID exist?
|
* Does this screenname exist?
|
||||||
*
|
*
|
||||||
* Checks if we already have another user with this address.
|
* Checks if we already have another user with this address.
|
||||||
*
|
*
|
||||||
* @param string $jabber Address to check
|
* @param string $transport Transport to check
|
||||||
|
* @param string $screenname Screenname to check
|
||||||
*
|
*
|
||||||
* @return boolean whether the Jabber ID exists
|
* @return boolean whether the screenname exists
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function jabberExists($jabber)
|
function screennameExists($transport, $screenname)
|
||||||
{
|
{
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
|
|
||||||
$other = User::staticGet('jabber', $jabber);
|
$user_im_prefs = new User_im_prefs();
|
||||||
|
$user_im_prefs->transport = $transport;
|
||||||
if (!$other) {
|
$user_im_prefs->screenname = $screenname;
|
||||||
|
if($user_im_prefs->find() && $user_im_prefs->fetch()){
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
return false;
|
return false;
|
||||||
} else {
|
|
||||||
return $other->id != $user->id;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -275,12 +275,6 @@ class ShownoticeAction extends OwnerDesignAction
|
|||||||
'content' => $id->toString()));
|
'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',
|
$this->element('link',array('rel'=>'alternate',
|
||||||
'type'=>'application/json+oembed',
|
'type'=>'application/json+oembed',
|
||||||
'href'=>common_local_url(
|
'href'=>common_local_url(
|
||||||
|
@ -166,12 +166,6 @@ class ShowstreamAction extends ProfileAction
|
|||||||
$this->element('meta', array('name' => 'microid',
|
$this->element('meta', array('name' => 'microid',
|
||||||
'content' => $id->toString()));
|
'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
|
// See https://wiki.mozilla.org/Microsummaries
|
||||||
|
|
||||||
|
@ -48,11 +48,6 @@ class User extends Memcached_DataObject
|
|||||||
public $language; // varchar(50)
|
public $language; // varchar(50)
|
||||||
public $timezone; // varchar(50)
|
public $timezone; // varchar(50)
|
||||||
public $emailpost; // tinyint(1) default_1
|
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 $sms; // varchar(64) unique_key
|
||||||
public $carrier; // int(4)
|
public $carrier; // int(4)
|
||||||
public $smsnotify; // tinyint(1)
|
public $smsnotify; // tinyint(1)
|
||||||
@ -92,7 +87,7 @@ class User extends Memcached_DataObject
|
|||||||
function updateKeys(&$orig)
|
function updateKeys(&$orig)
|
||||||
{
|
{
|
||||||
$parts = array();
|
$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) {
|
if (strcmp($this->$k, $orig->$k) != 0) {
|
||||||
$parts[] = $k . ' = ' . $this->_quote($this->$k);
|
$parts[] = $k . ' = ' . $this->_quote($this->$k);
|
||||||
}
|
}
|
||||||
|
71
classes/User_im_prefs.php
Normal file
71
classes/User_im_prefs.php
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<?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
|
language = 2
|
||||||
timezone = 2
|
timezone = 2
|
||||||
emailpost = 17
|
emailpost = 17
|
||||||
jabber = 2
|
|
||||||
jabbernotify = 17
|
|
||||||
jabberreplies = 17
|
|
||||||
jabbermicroid = 17
|
|
||||||
updatefrompresence = 17
|
|
||||||
sms = 2
|
sms = 2
|
||||||
carrier = 1
|
carrier = 1
|
||||||
smsnotify = 17
|
smsnotify = 17
|
||||||
@ -564,7 +559,6 @@ id = K
|
|||||||
nickname = U
|
nickname = U
|
||||||
email = U
|
email = U
|
||||||
incomingemail = U
|
incomingemail = U
|
||||||
jabber = U
|
|
||||||
sms = U
|
sms = U
|
||||||
uri = U
|
uri = U
|
||||||
|
|
||||||
@ -616,3 +610,19 @@ modified = 384
|
|||||||
[user_location_prefs__keys]
|
[user_location_prefs__keys]
|
||||||
user_id = K
|
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',
|
language varchar(50) comment 'preferred language',
|
||||||
timezone varchar(50) comment 'timezone',
|
timezone varchar(50) comment 'timezone',
|
||||||
emailpost tinyint default 1 comment 'Post by email',
|
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',
|
sms varchar(64) unique key comment 'sms phone number',
|
||||||
carrier integer comment 'foreign key to sms_carrier' references sms_carrier (id),
|
carrier integer comment 'foreign key to sms_carrier' references sms_carrier (id),
|
||||||
smsnotify tinyint default 0 comment 'whether to send notices to SMS',
|
smsnotify tinyint default 0 comment 'whether to send notices to SMS',
|
||||||
@ -259,9 +254,9 @@ create table oid_nonces (
|
|||||||
create table confirm_address (
|
create table confirm_address (
|
||||||
code varchar(32) not null primary key comment 'good random code',
|
code varchar(32) not null primary key comment 'good random code',
|
||||||
user_id integer not null comment 'user who requested confirmation' references user (id),
|
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_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',
|
claimed datetime comment 'date this was claimed for queueing',
|
||||||
sent datetime comment 'date this was sent for queueing',
|
sent datetime comment 'date this was sent for queueing',
|
||||||
modified timestamp comment 'date this record was modified'
|
modified timestamp comment 'date this record was modified'
|
||||||
@ -276,7 +271,7 @@ create table remember_me (
|
|||||||
create table queue_item (
|
create table queue_item (
|
||||||
id integer auto_increment primary key comment 'unique identifier',
|
id integer auto_increment primary key comment 'unique identifier',
|
||||||
frame blob not null comment 'data: object reference or opaque string',
|
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',
|
created datetime not null comment 'date this record was created',
|
||||||
claimed datetime comment 'date this item was claimed',
|
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',
|
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),
|
user_id int not null comment 'who sent the invitation' references user (id),
|
||||||
address varchar(255) not null comment 'invitation sent to',
|
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',
|
created datetime not null comment 'date this record was created',
|
||||||
|
|
||||||
index invitation_address_idx (address, address_type),
|
index invitation_address_idx (address, address_type),
|
||||||
@ -633,3 +628,18 @@ create table inbox (
|
|||||||
constraint primary key (user_id)
|
constraint primary key (user_id)
|
||||||
|
|
||||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
) 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
|
class WebChannel extends Channel
|
||||||
{
|
{
|
||||||
var $out = null;
|
var $out = null;
|
||||||
|
@ -596,7 +596,7 @@ class OffCommand extends Command
|
|||||||
}
|
}
|
||||||
function execute($channel)
|
function execute($channel)
|
||||||
{
|
{
|
||||||
if ($other) {
|
if ($this->other) {
|
||||||
$channel->error($this->user, _("Command not yet implemented."));
|
$channel->error($this->user, _("Command not yet implemented."));
|
||||||
} else {
|
} else {
|
||||||
if ($channel->off($this->user)) {
|
if ($channel->off($this->user)) {
|
||||||
@ -619,7 +619,7 @@ class OnCommand extends Command
|
|||||||
|
|
||||||
function execute($channel)
|
function execute($channel)
|
||||||
{
|
{
|
||||||
if ($other) {
|
if ($this->other) {
|
||||||
$channel->error($this->user, _("Command not yet implemented."));
|
$channel->error($this->user, _("Command not yet implemented."));
|
||||||
} else {
|
} else {
|
||||||
if ($channel->on($this->user)) {
|
if ($channel->on($this->user)) {
|
||||||
|
104
lib/imchannel.php
Normal file
104
lib/imchannel.php
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
70
lib/immanager.php
Normal file
70
lib/immanager.php
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
}
|
612
lib/implugin.php
Normal file
612
lib/implugin.php
Normal file
@ -0,0 +1,612 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Superclass for plugins that do instant messaging
|
||||||
|
*
|
||||||
|
* 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 Plugin
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Craig Andrews <candrews@integralblue.com>
|
||||||
|
* @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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Superclass for plugins that do authentication
|
||||||
|
*
|
||||||
|
* Implementations will likely want to override onStartIoManagerClasses() so that their
|
||||||
|
* IO manager is used
|
||||||
|
*
|
||||||
|
* @category Plugin
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Craig Andrews <candrews@integralblue.com>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
abstract class ImPlugin extends Plugin
|
||||||
|
{
|
||||||
|
//name of this IM transport
|
||||||
|
public $transport = null;
|
||||||
|
//list of screennames that should get all public notices
|
||||||
|
public $public = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* normalize a screenname for comparison
|
||||||
|
*
|
||||||
|
* @param string $screenname screenname to normalize
|
||||||
|
*
|
||||||
|
* @return string an equivalent screenname in normalized form
|
||||||
|
*/
|
||||||
|
abstract function normalize($screenname);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* validate (ensure the validity of) a screenname
|
||||||
|
*
|
||||||
|
* @param string $screenname screenname to validate
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
abstract function validate($screenname);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the internationalized/translated display name of this IM service
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
abstract function getDisplayName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send a single notice to a given screenname
|
||||||
|
* The implementation should put raw data, ready to send, into the outgoing
|
||||||
|
* queue using enqueue_outgoing_raw()
|
||||||
|
*
|
||||||
|
* @param string $screenname screenname to send to
|
||||||
|
* @param Notice $notice notice to send
|
||||||
|
*
|
||||||
|
* @return boolean success value
|
||||||
|
*/
|
||||||
|
function send_notice($screenname, $notice)
|
||||||
|
{
|
||||||
|
return $this->send_message($screenname, $this->format_notice($notice));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send a message (text) to a given screenname
|
||||||
|
* The implementation should put raw data, ready to send, into the outgoing
|
||||||
|
* queue using enqueue_outgoing_raw()
|
||||||
|
*
|
||||||
|
* @param string $screenname screenname to send to
|
||||||
|
* @param Notice $body text to send
|
||||||
|
*
|
||||||
|
* @return boolean success value
|
||||||
|
*/
|
||||||
|
abstract function send_message($screenname, $body);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* receive a raw message
|
||||||
|
* Raw IM data is taken from the incoming queue, and passed to this function.
|
||||||
|
* It should parse the raw message and call handle_incoming()
|
||||||
|
*
|
||||||
|
* @param object $data raw IM data
|
||||||
|
*
|
||||||
|
* @return boolean success value
|
||||||
|
*/
|
||||||
|
abstract function receive_raw_message($data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the screenname of the daemon that sends and receives message for this service
|
||||||
|
*
|
||||||
|
* @return string screenname of this plugin
|
||||||
|
*/
|
||||||
|
abstract function daemon_screenname();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the microid uri of a given screenname
|
||||||
|
*
|
||||||
|
* @param string $screenname screenname
|
||||||
|
*
|
||||||
|
* @return string microid uri
|
||||||
|
*/
|
||||||
|
function microiduri($screenname)
|
||||||
|
{
|
||||||
|
return $this->transport . ':' . $screenname;
|
||||||
|
}
|
||||||
|
//========================UTILITY FUNCTIONS USEFUL TO IMPLEMENTATIONS - MISC ========================\
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put raw message data (ready to send) into the outgoing queue
|
||||||
|
*
|
||||||
|
* @param object $data
|
||||||
|
*/
|
||||||
|
function enqueue_outgoing_raw($data)
|
||||||
|
{
|
||||||
|
$qm = QueueManager::get();
|
||||||
|
$qm->enqueue($data, $this->transport . '-out');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put raw message data (received, ready to be processed) into the incoming queue
|
||||||
|
*
|
||||||
|
* @param object $data
|
||||||
|
*/
|
||||||
|
function enqueue_incoming_raw($data)
|
||||||
|
{
|
||||||
|
$qm = QueueManager::get();
|
||||||
|
$qm->enqueue($data, $this->transport . '-in');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* given a screenname, get the corresponding user
|
||||||
|
*
|
||||||
|
* @param string $screenname
|
||||||
|
*
|
||||||
|
* @return User user
|
||||||
|
*/
|
||||||
|
function get_user($screenname)
|
||||||
|
{
|
||||||
|
$user_im_prefs = $this->get_user_im_prefs_from_screenname($screenname);
|
||||||
|
if($user_im_prefs){
|
||||||
|
$user = User::staticGet('id', $user_im_prefs->user_id);
|
||||||
|
$user_im_prefs->free();
|
||||||
|
return $user;
|
||||||
|
}else{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* given a screenname, get the User_im_prefs object for this transport
|
||||||
|
*
|
||||||
|
* @param string $screenname
|
||||||
|
*
|
||||||
|
* @return User_im_prefs user_im_prefs
|
||||||
|
*/
|
||||||
|
function get_user_im_prefs_from_screenname($screenname)
|
||||||
|
{
|
||||||
|
if($user_im_prefs = User_im_prefs::pkeyGet( array('transport' => $this->transport, 'screenname' => $screenname) )){
|
||||||
|
return $user_im_prefs;
|
||||||
|
}else{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* given a User, get their screenname
|
||||||
|
*
|
||||||
|
* @param User $user
|
||||||
|
*
|
||||||
|
* @return string screenname of that user
|
||||||
|
*/
|
||||||
|
function get_screenname($user)
|
||||||
|
{
|
||||||
|
$user_im_prefs = $this->get_user_im_prefs_from_user($user);
|
||||||
|
if($user_im_prefs){
|
||||||
|
return $user_im_prefs->screenname;
|
||||||
|
}else{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* given a User, get their User_im_prefs
|
||||||
|
*
|
||||||
|
* @param User $user
|
||||||
|
*
|
||||||
|
* @return User_im_prefs user_im_prefs of that user
|
||||||
|
*/
|
||||||
|
function get_user_im_prefs_from_user($user)
|
||||||
|
{
|
||||||
|
if($user_im_prefs = User_im_prefs::pkeyGet( array('transport' => $this->transport, 'user_id' => $user->id) )){
|
||||||
|
return $user_im_prefs;
|
||||||
|
}else{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//========================UTILITY FUNCTIONS USEFUL TO IMPLEMENTATIONS - SENDING ========================\
|
||||||
|
/**
|
||||||
|
* Send a message to a given screenname from the site
|
||||||
|
*
|
||||||
|
* @param string $screenname screenname to send the message to
|
||||||
|
* @param string $msg message contents to send
|
||||||
|
*
|
||||||
|
* @param boolean success
|
||||||
|
*/
|
||||||
|
protected function send_from_site($screenname, $msg)
|
||||||
|
{
|
||||||
|
$text = '['.common_config('site', 'name') . '] ' . $msg;
|
||||||
|
$this->send_message($screenname, $text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send a confirmation code to a user
|
||||||
|
*
|
||||||
|
* @param string $screenname screenname sending to
|
||||||
|
* @param string $code the confirmation code
|
||||||
|
* @param User $user user sending to
|
||||||
|
*
|
||||||
|
* @return boolean success value
|
||||||
|
*/
|
||||||
|
function send_confirmation_code($screenname, $code, $user)
|
||||||
|
{
|
||||||
|
$body = sprintf(_('User "%s" on %s has said that your %s screenname belongs to them. ' .
|
||||||
|
'If that\'s true, you can confirm by clicking on this URL: ' .
|
||||||
|
'%s' .
|
||||||
|
' . (If you cannot click it, copy-and-paste it into the ' .
|
||||||
|
'address bar of your browser). If that user isn\'t you, ' .
|
||||||
|
'or if you didn\'t request this confirmation, just ignore this message.'),
|
||||||
|
$user->nickname, common_config('site', 'name'), $this->getDisplayName(), common_local_url('confirmaddress', array('code' => $code)));
|
||||||
|
|
||||||
|
return $this->send_message($screenname, $body);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send a notice to all public listeners
|
||||||
|
*
|
||||||
|
* For notices that are generated on the local system (by users), we can optionally
|
||||||
|
* forward them to remote listeners by XMPP.
|
||||||
|
*
|
||||||
|
* @param Notice $notice notice to broadcast
|
||||||
|
*
|
||||||
|
* @return boolean success flag
|
||||||
|
*/
|
||||||
|
|
||||||
|
function public_notice($notice)
|
||||||
|
{
|
||||||
|
// Now, users who want everything
|
||||||
|
|
||||||
|
// FIXME PRIV don't send out private messages here
|
||||||
|
// XXX: should we send out non-local messages if public,localonly
|
||||||
|
// = false? I think not
|
||||||
|
|
||||||
|
foreach ($this->public as $screenname) {
|
||||||
|
common_log(LOG_INFO,
|
||||||
|
'Sending notice ' . $notice->id .
|
||||||
|
' to public listener ' . $screenname,
|
||||||
|
__FILE__);
|
||||||
|
$this->send_notice($screenname, $notice);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* broadcast a notice to all subscribers and reply recipients
|
||||||
|
*
|
||||||
|
* This function will send a notice to all subscribers on the local server
|
||||||
|
* who have IM addresses, and have IM notification enabled, and
|
||||||
|
* have this subscription enabled for IM. It also sends the notice to
|
||||||
|
* all recipients of @-replies who have IM addresses and IM notification
|
||||||
|
* enabled. This is really the heart of IM distribution in StatusNet.
|
||||||
|
*
|
||||||
|
* @param Notice $notice The notice to broadcast
|
||||||
|
*
|
||||||
|
* @return boolean success flag
|
||||||
|
*/
|
||||||
|
|
||||||
|
function broadcast_notice($notice)
|
||||||
|
{
|
||||||
|
|
||||||
|
$ni = $notice->whoGets();
|
||||||
|
|
||||||
|
foreach ($ni as $user_id => $reason) {
|
||||||
|
$user = User::staticGet($user_id);
|
||||||
|
if (empty($user)) {
|
||||||
|
// either not a local user, or just not found
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$user_im_prefs = $this->get_user_im_prefs_from_user($user);
|
||||||
|
if(!$user_im_prefs || !$user_im_prefs->notify){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($reason) {
|
||||||
|
case NOTICE_INBOX_SOURCE_REPLY:
|
||||||
|
if (!$user_im_prefs->replies) {
|
||||||
|
continue 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NOTICE_INBOX_SOURCE_SUB:
|
||||||
|
$sub = Subscription::pkeyGet(array('subscriber' => $user->id,
|
||||||
|
'subscribed' => $notice->profile_id));
|
||||||
|
if (empty($sub) || !$sub->jabber) {
|
||||||
|
continue 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NOTICE_INBOX_SOURCE_GROUP:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception(sprintf(_("Unknown inbox source %d."), $reason));
|
||||||
|
}
|
||||||
|
|
||||||
|
common_log(LOG_INFO,
|
||||||
|
'Sending notice ' . $notice->id . ' to ' . $user_im_prefs->screenname,
|
||||||
|
__FILE__);
|
||||||
|
$this->send_notice($user_im_prefs->screenname, $notice);
|
||||||
|
$user_im_prefs->free();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* makes a plain-text formatted version of a notice, suitable for IM distribution
|
||||||
|
*
|
||||||
|
* @param Notice $notice notice being sent
|
||||||
|
*
|
||||||
|
* @return string plain-text version of the notice, with user nickname prefixed
|
||||||
|
*/
|
||||||
|
|
||||||
|
function format_notice($notice)
|
||||||
|
{
|
||||||
|
$profile = $notice->getProfile();
|
||||||
|
return $profile->nickname . ': ' . $notice->content . ' [' . $notice->id . ']';
|
||||||
|
}
|
||||||
|
//========================UTILITY FUNCTIONS USEFUL TO IMPLEMENTATIONS - RECEIVING ========================\
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to handle a message as a command
|
||||||
|
* @param User $user user the message is from
|
||||||
|
* @param string $body message text
|
||||||
|
* @return boolean true if the message was a command and was executed, false if it was not a command
|
||||||
|
*/
|
||||||
|
protected function handle_command($user, $body)
|
||||||
|
{
|
||||||
|
$inter = new CommandInterpreter();
|
||||||
|
$cmd = $inter->handle_command($user, $body);
|
||||||
|
if ($cmd) {
|
||||||
|
$chan = new IMChannel($this);
|
||||||
|
$cmd->execute($chan);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is some text an autoreply message?
|
||||||
|
* @param string $txt message text
|
||||||
|
* @return boolean true if autoreply
|
||||||
|
*/
|
||||||
|
protected function is_autoreply($txt)
|
||||||
|
{
|
||||||
|
if (preg_match('/[\[\(]?[Aa]uto[-\s]?[Rr]e(ply|sponse)[\]\)]/', $txt)) {
|
||||||
|
return true;
|
||||||
|
} else if (preg_match('/^System: Message wasn\'t delivered. Offline storage size was exceeded.$/', $txt)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is some text an OTR message?
|
||||||
|
* @param string $txt message text
|
||||||
|
* @return boolean true if OTR
|
||||||
|
*/
|
||||||
|
protected function is_otr($txt)
|
||||||
|
{
|
||||||
|
if (preg_match('/^\?OTR/', $txt)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for handling incoming messages
|
||||||
|
* Your incoming message handler will probably want to call this function
|
||||||
|
*
|
||||||
|
* @param string $from screenname the message was sent from
|
||||||
|
* @param string $message message contents
|
||||||
|
*
|
||||||
|
* @param boolean success
|
||||||
|
*/
|
||||||
|
protected function handle_incoming($from, $notice_text)
|
||||||
|
{
|
||||||
|
$user = $this->get_user($from);
|
||||||
|
// For common_current_user to work
|
||||||
|
global $_cur;
|
||||||
|
$_cur = $user;
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
$this->send_from_site($from, 'Unknown user; go to ' .
|
||||||
|
common_local_url('imsettings') .
|
||||||
|
' to add your address to your account');
|
||||||
|
common_log(LOG_WARNING, 'Message from unknown user ' . $from);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($this->handle_command($user, $notice_text)) {
|
||||||
|
common_log(LOG_INFO, "Command message by $from handled.");
|
||||||
|
return;
|
||||||
|
} else if ($this->is_autoreply($notice_text)) {
|
||||||
|
common_log(LOG_INFO, 'Ignoring auto reply from ' . $from);
|
||||||
|
return;
|
||||||
|
} else if ($this->is_otr($notice_text)) {
|
||||||
|
common_log(LOG_INFO, 'Ignoring OTR from ' . $from);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
common_log(LOG_INFO, 'Posting a notice from ' . $user->nickname);
|
||||||
|
|
||||||
|
$this->add_notice($from, $user, $notice_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->free();
|
||||||
|
unset($user);
|
||||||
|
unset($_cur);
|
||||||
|
unset($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for handling incoming messages
|
||||||
|
* Your incoming message handler will probably want to call this function
|
||||||
|
*
|
||||||
|
* @param string $from screenname the message was sent from
|
||||||
|
* @param string $message message contents
|
||||||
|
*
|
||||||
|
* @param boolean success
|
||||||
|
*/
|
||||||
|
protected function add_notice($screenname, $user, $body)
|
||||||
|
{
|
||||||
|
$body = trim(strip_tags($body));
|
||||||
|
$content_shortened = common_shorten_links($body);
|
||||||
|
if (Notice::contentTooLong($content_shortened)) {
|
||||||
|
$this->send_from_site($screenname, sprintf(_('Message too long - maximum is %1$d characters, you sent %2$d.'),
|
||||||
|
Notice::maxContent(),
|
||||||
|
mb_strlen($content_shortened)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$notice = Notice::saveNew($user->id, $content_shortened, $this->transport);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
common_log(LOG_ERR, $e->getMessage());
|
||||||
|
$this->send_from_site($from, $e->getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
common_broadcast_notice($notice);
|
||||||
|
common_log(LOG_INFO,
|
||||||
|
'Added notice ' . $notice->id . ' from user ' . $user->nickname);
|
||||||
|
$notice->free();
|
||||||
|
unset($notice);
|
||||||
|
}
|
||||||
|
|
||||||
|
//========================EVENT HANDLERS========================\
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register notice queue handler
|
||||||
|
*
|
||||||
|
* @param QueueManager $manager
|
||||||
|
*
|
||||||
|
* @return boolean hook return
|
||||||
|
*/
|
||||||
|
function onEndInitializeQueueManager($manager)
|
||||||
|
{
|
||||||
|
$manager->connect($this->transport . '-in', new ImReceiverQueueHandler($this));
|
||||||
|
$manager->connect($this->transport, new ImQueueHandler($this));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onStartImDaemonIoManagers(&$classes)
|
||||||
|
{
|
||||||
|
//$classes[] = new ImManager($this); // handles sending/receiving/pings/reconnects
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onStartEnqueueNotice($notice, &$transports)
|
||||||
|
{
|
||||||
|
$profile = Profile::staticGet($notice->profile_id);
|
||||||
|
|
||||||
|
if (!$profile) {
|
||||||
|
common_log(LOG_WARNING, 'Refusing to broadcast notice with ' .
|
||||||
|
'unknown profile ' . common_log_objstring($notice),
|
||||||
|
__FILE__);
|
||||||
|
}else{
|
||||||
|
$transports[] = $this->transport;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEndShowHeadElements($action)
|
||||||
|
{
|
||||||
|
$aname = $action->trimmed('action');
|
||||||
|
|
||||||
|
if ($aname == 'shownotice') {
|
||||||
|
|
||||||
|
$user_im_prefs = new User_im_prefs();
|
||||||
|
$user_im_prefs->user_id = $action->profile->id;
|
||||||
|
$user_im_prefs->transport = $this->transport;
|
||||||
|
|
||||||
|
if ($user_im_prefs->find() && $user_im_prefs->fetch() && $user_im_prefs->microid && $action->notice->uri) {
|
||||||
|
$id = new Microid($this->microiduri($user_im_prefs->screenname),
|
||||||
|
$action->notice->uri);
|
||||||
|
$action->element('meta', array('name' => 'microid',
|
||||||
|
'content' => $id->toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if ($aname == 'showstream') {
|
||||||
|
|
||||||
|
$user_im_prefs = new User_im_prefs();
|
||||||
|
$user_im_prefs->user_id = $action->user->id;
|
||||||
|
$user_im_prefs->transport = $this->transport;
|
||||||
|
|
||||||
|
if ($user_im_prefs->find() && $user_im_prefs->fetch() && $user_im_prefs->microid && $action->profile->profileurl) {
|
||||||
|
$id = new Microid($this->microiduri($user_im_prefs->screenname),
|
||||||
|
$action->selfUrl());
|
||||||
|
$action->element('meta', array('name' => 'microid',
|
||||||
|
'content' => $id->toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onNormalizeImScreenname($transport, &$screenname)
|
||||||
|
{
|
||||||
|
if($transport == $this->transport)
|
||||||
|
{
|
||||||
|
$screenname = $this->normalize($screenname);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onValidateImScreenname($transport, $screenname, &$valid)
|
||||||
|
{
|
||||||
|
if($transport == $this->transport)
|
||||||
|
{
|
||||||
|
$valid = $this->validate($screenname);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onGetImTransports(&$transports)
|
||||||
|
{
|
||||||
|
$transports[$this->transport] = array('display' => $this->getDisplayName());
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSendImConfirmationCode($transport, $screenname, $code, $user)
|
||||||
|
{
|
||||||
|
if($transport == $this->transport)
|
||||||
|
{
|
||||||
|
$this->send_confirmation_code($screenname, $code, $user);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onUserDeleteRelated($user, &$tables)
|
||||||
|
{
|
||||||
|
$tables[] = 'User_im_prefs';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initialize()
|
||||||
|
{
|
||||||
|
if(is_null($this->transport)){
|
||||||
|
throw new Exception('transport cannot be null');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -17,31 +17,32 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queue handler for pushing new notices to Jabber users.
|
* Common superclass for all IM sending queue handlers.
|
||||||
* @fixme this exception handling doesn't look very good.
|
|
||||||
*/
|
*/
|
||||||
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)
|
function handle($notice)
|
||||||
{
|
{
|
||||||
require_once(INSTALLDIR.'/lib/jabber.php');
|
$this->plugin->broadcast_notice($notice);
|
||||||
try {
|
if ($notice->is_local == Notice::LOCAL_PUBLIC ||
|
||||||
return jabber_broadcast_notice($notice);
|
$notice->is_local == Notice::LOCAL_NONPUBLIC) {
|
||||||
} catch (XMPPHP_Exception $e) {
|
$this->plugin->public_notice($notice);
|
||||||
$this->log(LOG_ERR, "Got an XMPPHP_Exception: " . $e->getMessage());
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -17,29 +17,26 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
||||||
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';
|
$this->plugin = $plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle($notice)
|
/**
|
||||||
|
* Handle incoming IM data sent by a user to the IM bot
|
||||||
|
* @param object $data
|
||||||
|
* @return boolean success
|
||||||
|
*/
|
||||||
|
function handle($data)
|
||||||
{
|
{
|
||||||
require_once(INSTALLDIR.'/lib/jabber.php');
|
return $this->plugin->receive_raw_message($data);
|
||||||
try {
|
|
||||||
return jabber_public_notice($notice);
|
|
||||||
} catch (XMPPHP_Exception $e) {
|
|
||||||
$this->log(LOG_ERR, "Got an XMPPHP_Exception: " . $e->getMessage());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
44
lib/imsenderqueuehandler.php
Normal file
44
lib/imsenderqueuehandler.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?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); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common superclass for all IM sending queue handlers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ImSenderQueueHandler extends QueueHandler
|
||||||
|
{
|
||||||
|
function __construct($plugin, $immanager)
|
||||||
|
{
|
||||||
|
$this->plugin = $plugin;
|
||||||
|
$this->immanager = $immanager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle outgoing IM data to be sent from the bot to a user
|
||||||
|
* @param object $data
|
||||||
|
* @return boolean success
|
||||||
|
*/
|
||||||
|
function handle($data)
|
||||||
|
{
|
||||||
|
return $this->immanager->send_raw_message($data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
473
lib/jabber.php
473
lib/jabber.php
@ -1,473 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* StatusNet, the distributed open-source microblogging tool
|
|
||||||
*
|
|
||||||
* utility functions for Jabber/GTalk/XMPP messages
|
|
||||||
*
|
|
||||||
* 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 Network
|
|
||||||
* @package StatusNet
|
|
||||||
* @author Evan Prodromou <evan@status.net>
|
|
||||||
* @copyright 2008 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 'XMPPHP/XMPP.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* checks whether a string is a syntactically valid Jabber ID (JID)
|
|
||||||
*
|
|
||||||
* @param string $jid string to check
|
|
||||||
*
|
|
||||||
* @return boolean whether the string is a valid JID
|
|
||||||
*/
|
|
||||||
|
|
||||||
function jabber_valid_base_jid($jid)
|
|
||||||
{
|
|
||||||
// Cheap but effective
|
|
||||||
return Validate::email($jid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* normalizes a Jabber ID for comparison
|
|
||||||
*
|
|
||||||
* @param string $jid JID to check
|
|
||||||
*
|
|
||||||
* @return string an equivalent JID in normalized (lowercase) form
|
|
||||||
*/
|
|
||||||
|
|
||||||
function jabber_normalize_jid($jid)
|
|
||||||
{
|
|
||||||
if (preg_match("/(?:([^\@]+)\@)?([^\/]+)(?:\/(.*))?$/", $jid, $matches)) {
|
|
||||||
$node = $matches[1];
|
|
||||||
$server = $matches[2];
|
|
||||||
return strtolower($node.'@'.$server);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* the JID of the Jabber daemon for this StatusNet instance
|
|
||||||
*
|
|
||||||
* @return string JID of the Jabber daemon
|
|
||||||
*/
|
|
||||||
|
|
||||||
function jabber_daemon_address()
|
|
||||||
{
|
|
||||||
return common_config('xmpp', 'user') . '@' . common_config('xmpp', 'server');
|
|
||||||
}
|
|
||||||
|
|
||||||
class Sharing_XMPP extends XMPPHP_XMPP
|
|
||||||
{
|
|
||||||
function getSocket()
|
|
||||||
{
|
|
||||||
return $this->socket;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build an XMPP proxy connection that'll save outgoing messages
|
|
||||||
* to the 'xmppout' queue to be picked up by xmppdaemon later.
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lazy-connect the configured Jabber account to the configured server;
|
|
||||||
* if already opened, the same connection will be returned.
|
|
||||||
*
|
|
||||||
* In a multi-site background process, each site configuration
|
|
||||||
* will get its own connection.
|
|
||||||
*
|
|
||||||
* @param string $resource Resource to connect (defaults to configured resource)
|
|
||||||
*
|
|
||||||
* @return XMPPHP connection to the configured server
|
|
||||||
*/
|
|
||||||
|
|
||||||
function jabber_connect($resource=null)
|
|
||||||
{
|
|
||||||
static $connections = array();
|
|
||||||
$site = common_config('site', 'server');
|
|
||||||
if (empty($connections[$site])) {
|
|
||||||
if (empty($resource)) {
|
|
||||||
$resource = common_config('xmpp', 'resource');
|
|
||||||
}
|
|
||||||
$conn = new Sharing_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'),
|
|
||||||
$resource,
|
|
||||||
common_config('xmpp', 'server'),
|
|
||||||
common_config('xmpp', 'debug') ?
|
|
||||||
true : false,
|
|
||||||
common_config('xmpp', 'debug') ?
|
|
||||||
XMPPHP_Log::LEVEL_VERBOSE : null
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!$conn) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$connections[$site] = $conn;
|
|
||||||
|
|
||||||
$conn->autoSubscribe();
|
|
||||||
$conn->useEncryption(common_config('xmpp', 'encryption'));
|
|
||||||
|
|
||||||
try {
|
|
||||||
common_log(LOG_INFO, __METHOD__ . ": connecting " .
|
|
||||||
common_config('xmpp', 'user') . '/' . $resource);
|
|
||||||
//$conn->connect(true); // true = persistent connection
|
|
||||||
$conn->connect(); // persistent connections break multisite
|
|
||||||
} catch (XMPPHP_Exception $e) {
|
|
||||||
common_log(LOG_ERR, $e->getMessage());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$conn->processUntil('session_start');
|
|
||||||
}
|
|
||||||
return $connections[$site];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Queue send for a single notice to a given Jabber address
|
|
||||||
*
|
|
||||||
* @param string $to JID to send the notice to
|
|
||||||
* @param Notice $notice notice to send
|
|
||||||
*
|
|
||||||
* @return boolean success value
|
|
||||||
*/
|
|
||||||
|
|
||||||
function jabber_send_notice($to, $notice)
|
|
||||||
{
|
|
||||||
$conn = jabber_proxy();
|
|
||||||
$profile = Profile::staticGet($notice->profile_id);
|
|
||||||
if (!$profile) {
|
|
||||||
common_log(LOG_WARNING, 'Refusing to send notice with ' .
|
|
||||||
'unknown profile ' . common_log_objstring($notice),
|
|
||||||
__FILE__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$msg = jabber_format_notice($profile, $notice);
|
|
||||||
$entry = jabber_format_entry($profile, $notice);
|
|
||||||
$conn->message($to, $msg, 'chat', null, $entry);
|
|
||||||
$profile->free();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* extra information for XMPP messages, as defined by Twitter
|
|
||||||
*
|
|
||||||
* @param Profile $profile Profile of the sending user
|
|
||||||
* @param Notice $notice Notice being sent
|
|
||||||
*
|
|
||||||
* @return string Extra information (Atom, HTML, addresses) in string format
|
|
||||||
*/
|
|
||||||
|
|
||||||
function jabber_format_entry($profile, $notice)
|
|
||||||
{
|
|
||||||
$entry = $notice->asAtomEntry(true, true);
|
|
||||||
|
|
||||||
$xs = new XMLStringer();
|
|
||||||
$xs->elementStart('html', array('xmlns' => 'http://jabber.org/protocol/xhtml-im'));
|
|
||||||
$xs->elementStart('body', array('xmlns' => 'http://www.w3.org/1999/xhtml'));
|
|
||||||
$xs->element('a', array('href' => $profile->profileurl),
|
|
||||||
$profile->nickname);
|
|
||||||
$xs->text(": ");
|
|
||||||
if (!empty($notice->rendered)) {
|
|
||||||
$xs->raw($notice->rendered);
|
|
||||||
} else {
|
|
||||||
$xs->raw(common_render_content($notice->content, $notice));
|
|
||||||
}
|
|
||||||
$xs->text(" ");
|
|
||||||
$xs->element('a', array(
|
|
||||||
'href'=>common_local_url('conversation',
|
|
||||||
array('id' => $notice->conversation)).'#notice-'.$notice->id
|
|
||||||
),sprintf(_('[%s]'),$notice->id));
|
|
||||||
$xs->elementEnd('body');
|
|
||||||
$xs->elementEnd('html');
|
|
||||||
|
|
||||||
$html = $xs->getString();
|
|
||||||
|
|
||||||
return $html . ' ' . $entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* sends a single text message to a given JID
|
|
||||||
*
|
|
||||||
* @param string $to JID to send the message to
|
|
||||||
* @param string $body body of the message
|
|
||||||
* @param string $type type of the message
|
|
||||||
* @param string $subject subject of the message
|
|
||||||
*
|
|
||||||
* @return boolean success flag
|
|
||||||
*/
|
|
||||||
|
|
||||||
function jabber_send_message($to, $body, $type='chat', $subject=null)
|
|
||||||
{
|
|
||||||
$conn = jabber_proxy();
|
|
||||||
$conn->message($to, $body, $type, $subject);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* sends a presence stanza on the Jabber network
|
|
||||||
*
|
|
||||||
* @param string $status current status, free-form string
|
|
||||||
* @param string $show structured status value
|
|
||||||
* @param string $to recipient of presence, null for general
|
|
||||||
* @param string $type type of status message, related to $show
|
|
||||||
* @param int $priority priority of the presence
|
|
||||||
*
|
|
||||||
* @return boolean success value
|
|
||||||
*/
|
|
||||||
|
|
||||||
function jabber_send_presence($status, $show='available', $to=null,
|
|
||||||
$type = 'available', $priority=null)
|
|
||||||
{
|
|
||||||
$conn = jabber_connect();
|
|
||||||
if (!$conn) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$conn->presence($status, $show, $to, $type, $priority);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* sends a confirmation request to a JID
|
|
||||||
*
|
|
||||||
* @param string $code confirmation code for confirmation URL
|
|
||||||
* @param string $nickname nickname of confirming user
|
|
||||||
* @param string $address JID to send confirmation to
|
|
||||||
*
|
|
||||||
* @return boolean success flag
|
|
||||||
*/
|
|
||||||
|
|
||||||
function jabber_confirm_address($code, $nickname, $address)
|
|
||||||
{
|
|
||||||
$body = 'User "' . $nickname . '" on ' . common_config('site', 'name') . ' ' .
|
|
||||||
'has said that your Jabber ID belongs to them. ' .
|
|
||||||
'If that\'s true, you can confirm by clicking on this URL: ' .
|
|
||||||
common_local_url('confirmaddress', array('code' => $code)) .
|
|
||||||
' . (If you cannot click it, copy-and-paste it into the ' .
|
|
||||||
'address bar of your browser). If that user isn\'t you, ' .
|
|
||||||
'or if you didn\'t request this confirmation, just ignore this message.';
|
|
||||||
|
|
||||||
return jabber_send_message($address, $body);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* sends a "special" presence stanza on the Jabber network
|
|
||||||
*
|
|
||||||
* @param string $type Type of presence
|
|
||||||
* @param string $to JID to send presence to
|
|
||||||
* @param string $show show value for presence
|
|
||||||
* @param string $status status value for presence
|
|
||||||
*
|
|
||||||
* @return boolean success flag
|
|
||||||
*
|
|
||||||
* @see jabber_send_presence()
|
|
||||||
*/
|
|
||||||
|
|
||||||
function jabber_special_presence($type, $to=null, $show=null, $status=null)
|
|
||||||
{
|
|
||||||
// FIXME: why use this instead of jabber_send_presence()?
|
|
||||||
$conn = jabber_connect();
|
|
||||||
|
|
||||||
$to = htmlspecialchars($to);
|
|
||||||
$status = htmlspecialchars($status);
|
|
||||||
|
|
||||||
$out = "<presence";
|
|
||||||
if ($to) {
|
|
||||||
$out .= " to='$to'";
|
|
||||||
}
|
|
||||||
if ($type) {
|
|
||||||
$out .= " type='$type'";
|
|
||||||
}
|
|
||||||
if ($show == 'available' and !$status) {
|
|
||||||
$out .= "/>";
|
|
||||||
} else {
|
|
||||||
$out .= ">";
|
|
||||||
if ($show && ($show != 'available')) {
|
|
||||||
$out .= "<show>$show</show>";
|
|
||||||
}
|
|
||||||
if ($status) {
|
|
||||||
$out .= "<status>$status</status>";
|
|
||||||
}
|
|
||||||
$out .= "</presence>";
|
|
||||||
}
|
|
||||||
$conn->send($out);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Queue broadcast of a notice to all subscribers and reply recipients
|
|
||||||
*
|
|
||||||
* This function will send a notice to all subscribers on the local server
|
|
||||||
* who have Jabber addresses, and have Jabber notification enabled, and
|
|
||||||
* have this subscription enabled for Jabber. It also sends the notice to
|
|
||||||
* all recipients of @-replies who have Jabber addresses and Jabber notification
|
|
||||||
* enabled. This is really the heart of Jabber distribution in StatusNet.
|
|
||||||
*
|
|
||||||
* @param Notice $notice The notice to broadcast
|
|
||||||
*
|
|
||||||
* @return boolean success flag
|
|
||||||
*/
|
|
||||||
|
|
||||||
function jabber_broadcast_notice($notice)
|
|
||||||
{
|
|
||||||
if (!common_config('xmpp', 'enabled')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
$profile = Profile::staticGet($notice->profile_id);
|
|
||||||
|
|
||||||
if (!$profile) {
|
|
||||||
common_log(LOG_WARNING, 'Refusing to broadcast notice with ' .
|
|
||||||
'unknown profile ' . common_log_objstring($notice),
|
|
||||||
__FILE__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$msg = jabber_format_notice($profile, $notice);
|
|
||||||
$entry = jabber_format_entry($profile, $notice);
|
|
||||||
|
|
||||||
$profile->free();
|
|
||||||
unset($profile);
|
|
||||||
|
|
||||||
$sent_to = array();
|
|
||||||
|
|
||||||
$conn = jabber_proxy();
|
|
||||||
|
|
||||||
$ni = $notice->whoGets();
|
|
||||||
|
|
||||||
foreach ($ni as $user_id => $reason) {
|
|
||||||
$user = User::staticGet($user_id);
|
|
||||||
if (empty($user) ||
|
|
||||||
empty($user->jabber) ||
|
|
||||||
!$user->jabbernotify) {
|
|
||||||
// either not a local user, or just not found
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
switch ($reason) {
|
|
||||||
case NOTICE_INBOX_SOURCE_REPLY:
|
|
||||||
if (!$user->jabberreplies) {
|
|
||||||
continue 2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NOTICE_INBOX_SOURCE_SUB:
|
|
||||||
$sub = Subscription::pkeyGet(array('subscriber' => $user->id,
|
|
||||||
'subscribed' => $notice->profile_id));
|
|
||||||
if (empty($sub) || !$sub->jabber) {
|
|
||||||
continue 2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NOTICE_INBOX_SOURCE_GROUP:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Exception(sprintf(_("Unknown inbox source %d."), $reason));
|
|
||||||
}
|
|
||||||
|
|
||||||
common_log(LOG_INFO,
|
|
||||||
'Sending notice ' . $notice->id . ' to ' . $user->jabber,
|
|
||||||
__FILE__);
|
|
||||||
$conn->message($user->jabber, $msg, 'chat', null, $entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Queue send of a notice to all public listeners
|
|
||||||
*
|
|
||||||
* For notices that are generated on the local system (by users), we can optionally
|
|
||||||
* forward them to remote listeners by XMPP.
|
|
||||||
*
|
|
||||||
* @param Notice $notice notice to broadcast
|
|
||||||
*
|
|
||||||
* @return boolean success flag
|
|
||||||
*/
|
|
||||||
|
|
||||||
function jabber_public_notice($notice)
|
|
||||||
{
|
|
||||||
// Now, users who want everything
|
|
||||||
|
|
||||||
$public = common_config('xmpp', 'public');
|
|
||||||
|
|
||||||
// FIXME PRIV don't send out private messages here
|
|
||||||
// XXX: should we send out non-local messages if public,localonly
|
|
||||||
// = false? I think not
|
|
||||||
|
|
||||||
if ($public && $notice->is_local == Notice::LOCAL_PUBLIC) {
|
|
||||||
$profile = Profile::staticGet($notice->profile_id);
|
|
||||||
|
|
||||||
if (!$profile) {
|
|
||||||
common_log(LOG_WARNING, 'Refusing to broadcast notice with ' .
|
|
||||||
'unknown profile ' . common_log_objstring($notice),
|
|
||||||
__FILE__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$msg = jabber_format_notice($profile, $notice);
|
|
||||||
$entry = jabber_format_entry($profile, $notice);
|
|
||||||
|
|
||||||
$conn = jabber_proxy();
|
|
||||||
|
|
||||||
foreach ($public as $address) {
|
|
||||||
common_log(LOG_INFO,
|
|
||||||
'Sending notice ' . $notice->id .
|
|
||||||
' to public listener ' . $address,
|
|
||||||
__FILE__);
|
|
||||||
$conn->message($address, $msg, 'chat', null, $entry);
|
|
||||||
}
|
|
||||||
$profile->free();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* makes a plain-text formatted version of a notice, suitable for Jabber distribution
|
|
||||||
*
|
|
||||||
* @param Profile &$profile profile of the sending user
|
|
||||||
* @param Notice &$notice notice being sent
|
|
||||||
*
|
|
||||||
* @return string plain-text version of the notice, with user nickname prefixed
|
|
||||||
*/
|
|
||||||
|
|
||||||
function jabber_format_notice(&$profile, &$notice)
|
|
||||||
{
|
|
||||||
return $profile->nickname . ': ' . $notice->content . ' [' . $notice->id . ']';
|
|
||||||
}
|
|
@ -36,20 +36,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
|||||||
class QueueHandler
|
class QueueHandler
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
|
||||||
* Return transport keyword which identifies items this queue handler
|
|
||||||
* services; must be defined for all subclasses.
|
|
||||||
*
|
|
||||||
* Must be 8 characters or less to fit in the queue_item database.
|
|
||||||
* ex "email", "jabber", "sms", "irc", ...
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function transport()
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Here's the meat of your queue handler -- you're handed a Notice
|
* Here's the meat of your queue handler -- you're handed a Notice
|
||||||
* or other object, which you may do as you will with.
|
* or other object, which you may do as you will with.
|
||||||
|
@ -213,18 +213,8 @@ abstract class QueueManager extends IoManager
|
|||||||
$this->connect('sms', 'SmsQueueHandler');
|
$this->connect('sms', 'SmsQueueHandler');
|
||||||
}
|
}
|
||||||
|
|
||||||
// XMPP output handlers...
|
|
||||||
$this->connect('jabber', 'JabberQueueHandler');
|
|
||||||
$this->connect('public', 'PublicQueueHandler');
|
|
||||||
|
|
||||||
// @fixme this should get an actual queue
|
|
||||||
//$this->connect('confirm', 'XmppConfirmHandler');
|
|
||||||
|
|
||||||
// For compat with old plugins not registering their own handlers.
|
// For compat with old plugins not registering their own handlers.
|
||||||
$this->connect('plugin', 'PluginQueueHandler');
|
$this->connect('plugin', 'PluginQueueHandler');
|
||||||
|
|
||||||
$this->connect('xmppout', 'XmppOutQueueHandler', 'xmppdaemon');
|
|
||||||
|
|
||||||
}
|
}
|
||||||
Event::handle('EndInitializeQueueManager', array($this));
|
Event::handle('EndInitializeQueueManager', array($this));
|
||||||
}
|
}
|
||||||
@ -251,8 +241,8 @@ abstract class QueueManager extends IoManager
|
|||||||
$group = 'queuedaemon';
|
$group = 'queuedaemon';
|
||||||
if ($this->master) {
|
if ($this->master) {
|
||||||
// hack hack
|
// hack hack
|
||||||
if ($this->master instanceof XmppMaster) {
|
if ($this->master instanceof ImMaster) {
|
||||||
return 'xmppdaemon';
|
return 'imdaemon';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $group;
|
return $group;
|
||||||
|
@ -36,7 +36,7 @@ class QueueMonitor
|
|||||||
* Only explicitly listed thread/site/queue owners will be incremented.
|
* Only explicitly listed thread/site/queue owners will be incremented.
|
||||||
*
|
*
|
||||||
* @param string $key counter name
|
* @param string $key counter name
|
||||||
* @param array $owners list of owner keys like 'queue:jabber' or 'site:stat01'
|
* @param array $owners list of owner keys like 'queue:xmpp' or 'site:stat01'
|
||||||
*/
|
*/
|
||||||
public function stats($key, $owners=array())
|
public function stats($key, $owners=array())
|
||||||
{
|
{
|
||||||
|
@ -994,18 +994,9 @@ function common_enqueue_notice($notice)
|
|||||||
|
|
||||||
$transports = $allTransports;
|
$transports = $allTransports;
|
||||||
|
|
||||||
$xmpp = common_config('xmpp', 'enabled');
|
|
||||||
|
|
||||||
if ($xmpp) {
|
|
||||||
$transports[] = 'jabber';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($notice->is_local == Notice::LOCAL_PUBLIC ||
|
if ($notice->is_local == Notice::LOCAL_PUBLIC ||
|
||||||
$notice->is_local == Notice::LOCAL_NONPUBLIC) {
|
$notice->is_local == Notice::LOCAL_NONPUBLIC) {
|
||||||
$transports = array_merge($transports, $localTransports);
|
$transports = array_merge($transports, $localTransports);
|
||||||
if ($xmpp) {
|
|
||||||
$transports[] = 'public';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Event::handle('StartEnqueueNotice', array($notice, &$transports))) {
|
if (Event::handle('StartEnqueueNotice', array($notice, &$transports))) {
|
||||||
|
@ -1,485 +0,0 @@
|
|||||||
<?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); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* XMPP background connection manager for XMPP-using queue handlers,
|
|
||||||
* allowing them to send outgoing messages on the right connection.
|
|
||||||
*
|
|
||||||
* Input is handled during socket select loop, keepalive pings during idle.
|
|
||||||
* Any incoming messages will be forwarded to the main XmppDaemon process,
|
|
||||||
* which handles direct user interaction.
|
|
||||||
*
|
|
||||||
* In a multi-site queuedaemon.php run, one connection will be instantiated
|
|
||||||
* for each site being handled by the current process that has XMPP enabled.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class XmppManager extends IoManager
|
|
||||||
{
|
|
||||||
protected $site = null;
|
|
||||||
protected $pingid = 0;
|
|
||||||
protected $lastping = null;
|
|
||||||
|
|
||||||
static protected $singletons = array();
|
|
||||||
|
|
||||||
const PING_INTERVAL = 120;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch the singleton XmppManager for the current site.
|
|
||||||
* @return mixed XmppManager, or false if unneeded
|
|
||||||
*/
|
|
||||||
public static function get()
|
|
||||||
{
|
|
||||||
if (common_config('xmpp', 'enabled')) {
|
|
||||||
$site = common_config('site', 'server');
|
|
||||||
if (empty(self::$singletons[$site])) {
|
|
||||||
self::$singletons[$site] = new XmppManager();
|
|
||||||
}
|
|
||||||
return self::$singletons[$site];
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tell the i/o master we need one instance for each supporting site
|
|
||||||
* being handled in this process.
|
|
||||||
*/
|
|
||||||
public static function multiSite()
|
|
||||||
{
|
|
||||||
return IoManager::INSTANCE_PER_SITE;
|
|
||||||
}
|
|
||||||
|
|
||||||
function __construct()
|
|
||||||
{
|
|
||||||
$this->site = common_config('site', 'server');
|
|
||||||
$this->resource = common_config('xmpp', 'resource') . 'daemon';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize connection to server.
|
|
||||||
* @return boolean true on success
|
|
||||||
*/
|
|
||||||
public function start($master)
|
|
||||||
{
|
|
||||||
parent::start($master);
|
|
||||||
$this->switchSite();
|
|
||||||
|
|
||||||
require_once INSTALLDIR . "/lib/jabber.php";
|
|
||||||
|
|
||||||
# Low priority; we don't want to receive messages
|
|
||||||
|
|
||||||
common_log(LOG_INFO, "INITIALIZE");
|
|
||||||
$this->conn = jabber_connect($this->resource);
|
|
||||||
|
|
||||||
if (empty($this->conn)) {
|
|
||||||
common_log(LOG_ERR, "Couldn't connect to server.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->log(LOG_DEBUG, "Initializing stanza handlers.");
|
|
||||||
|
|
||||||
$this->conn->addEventHandler('message', 'handle_message', $this);
|
|
||||||
$this->conn->addEventHandler('presence', 'handle_presence', $this);
|
|
||||||
$this->conn->addEventHandler('reconnect', 'handle_reconnect', $this);
|
|
||||||
|
|
||||||
$this->conn->setReconnectTimeout(600);
|
|
||||||
jabber_send_presence("Send me a message to post a notice", 'available', null, 'available', 100);
|
|
||||||
|
|
||||||
return !is_null($this->conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Message pump is triggered on socket input, so we only need an idle()
|
|
||||||
* call often enough to trigger our outgoing pings.
|
|
||||||
*/
|
|
||||||
function timeout()
|
|
||||||
{
|
|
||||||
return self::PING_INTERVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lists the XMPP connection socket to allow i/o master to wake
|
|
||||||
* when input comes in here as well as from the queue source.
|
|
||||||
*
|
|
||||||
* @return array of resources
|
|
||||||
*/
|
|
||||||
public function getSockets()
|
|
||||||
{
|
|
||||||
if ($this->conn) {
|
|
||||||
return array($this->conn->getSocket());
|
|
||||||
} else {
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process XMPP events that have come in over the wire.
|
|
||||||
* Side effects: may switch site configuration
|
|
||||||
* @fixme may kill process on XMPP error
|
|
||||||
* @param resource $socket
|
|
||||||
*/
|
|
||||||
public function handleInput($socket)
|
|
||||||
{
|
|
||||||
$this->switchSite();
|
|
||||||
|
|
||||||
# Process the queue for as long as needed
|
|
||||||
try {
|
|
||||||
if ($this->conn) {
|
|
||||||
assert($socket === $this->conn->getSocket());
|
|
||||||
|
|
||||||
common_log(LOG_DEBUG, "Servicing the XMPP queue.");
|
|
||||||
$this->stats('xmpp_process');
|
|
||||||
$this->conn->processTime(0);
|
|
||||||
}
|
|
||||||
} catch (XMPPHP_Exception $e) {
|
|
||||||
common_log(LOG_ERR, "Got an XMPPHP_Exception: " . $e->getMessage());
|
|
||||||
die($e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Idle processing for io manager's execution loop.
|
|
||||||
* Send keepalive pings to server.
|
|
||||||
*
|
|
||||||
* Side effect: kills process on exception from XMPP library.
|
|
||||||
*
|
|
||||||
* @fixme non-dying error handling
|
|
||||||
*/
|
|
||||||
public function idle($timeout=0)
|
|
||||||
{
|
|
||||||
if ($this->conn) {
|
|
||||||
$now = time();
|
|
||||||
if (empty($this->lastping) || $now - $this->lastping > self::PING_INTERVAL) {
|
|
||||||
$this->switchSite();
|
|
||||||
try {
|
|
||||||
$this->sendPing();
|
|
||||||
$this->lastping = $now;
|
|
||||||
} catch (XMPPHP_Exception $e) {
|
|
||||||
common_log(LOG_ERR, "Got an XMPPHP_Exception: " . $e->getMessage());
|
|
||||||
die($e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For queue handlers to pass us a message to push out,
|
|
||||||
* if we're active.
|
|
||||||
*
|
|
||||||
* @fixme should this be blocking etc?
|
|
||||||
*
|
|
||||||
* @param string $msg XML stanza to send
|
|
||||||
* @return boolean success
|
|
||||||
*/
|
|
||||||
public function send($msg)
|
|
||||||
{
|
|
||||||
if ($this->conn && !$this->conn->isDisconnected()) {
|
|
||||||
$bytes = $this->conn->send($msg);
|
|
||||||
if ($bytes > 0) {
|
|
||||||
$this->conn->processTime(0);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Can't send right now...
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a keepalive ping to the XMPP server.
|
|
||||||
*/
|
|
||||||
protected function sendPing()
|
|
||||||
{
|
|
||||||
$jid = jabber_daemon_address().'/'.$this->resource;
|
|
||||||
$server = common_config('xmpp', 'server');
|
|
||||||
|
|
||||||
if (!isset($this->pingid)) {
|
|
||||||
$this->pingid = 0;
|
|
||||||
} else {
|
|
||||||
$this->pingid++;
|
|
||||||
}
|
|
||||||
|
|
||||||
common_log(LOG_DEBUG, "Sending ping #{$this->pingid}");
|
|
||||||
|
|
||||||
$this->conn->send("<iq from='{$jid}' to='{$server}' id='ping_{$this->pingid}' type='get'><ping xmlns='urn:xmpp:ping'/></iq>");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback for Jabber reconnect event
|
|
||||||
* @param $pl
|
|
||||||
*/
|
|
||||||
function handle_reconnect(&$pl)
|
|
||||||
{
|
|
||||||
common_log(LOG_NOTICE, 'XMPP reconnected');
|
|
||||||
|
|
||||||
$this->conn->processUntil('session_start');
|
|
||||||
$this->conn->presence(null, 'available', null, 'available', 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function get_user($from)
|
|
||||||
{
|
|
||||||
$user = User::staticGet('jabber', jabber_normalize_jid($from));
|
|
||||||
return $user;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* XMPP callback for handling message input...
|
|
||||||
* @param array $pl XMPP payload
|
|
||||||
*/
|
|
||||||
function handle_message(&$pl)
|
|
||||||
{
|
|
||||||
$from = jabber_normalize_jid($pl['from']);
|
|
||||||
|
|
||||||
if ($pl['type'] != 'chat') {
|
|
||||||
$this->log(LOG_WARNING, "Ignoring message of type ".$pl['type']." from $from.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mb_strlen($pl['body']) == 0) {
|
|
||||||
$this->log(LOG_WARNING, "Ignoring message with empty body from $from.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forwarded from another daemon for us to handle; this shouldn't
|
|
||||||
// happen any more but we might get some legacy items.
|
|
||||||
if ($this->is_self($from)) {
|
|
||||||
$this->log(LOG_INFO, "Got forwarded notice from self ($from).");
|
|
||||||
$from = $this->get_ofrom($pl);
|
|
||||||
$this->log(LOG_INFO, "Originally sent by $from.");
|
|
||||||
if (is_null($from) || $this->is_self($from)) {
|
|
||||||
$this->log(LOG_INFO, "Ignoring notice originally sent by $from.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$user = $this->get_user($from);
|
|
||||||
|
|
||||||
// For common_current_user to work
|
|
||||||
global $_cur;
|
|
||||||
$_cur = $user;
|
|
||||||
|
|
||||||
if (!$user) {
|
|
||||||
$this->from_site($from, 'Unknown user; go to ' .
|
|
||||||
common_local_url('imsettings') .
|
|
||||||
' to add your address to your account');
|
|
||||||
$this->log(LOG_WARNING, 'Message from unknown user ' . $from);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ($this->handle_command($user, $pl['body'])) {
|
|
||||||
$this->log(LOG_INFO, "Command message by $from handled.");
|
|
||||||
return;
|
|
||||||
} else if ($this->is_autoreply($pl['body'])) {
|
|
||||||
$this->log(LOG_INFO, 'Ignoring auto reply from ' . $from);
|
|
||||||
return;
|
|
||||||
} else if ($this->is_otr($pl['body'])) {
|
|
||||||
$this->log(LOG_INFO, 'Ignoring OTR from ' . $from);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
|
|
||||||
$this->log(LOG_INFO, 'Posting a notice from ' . $user->nickname);
|
|
||||||
|
|
||||||
$this->add_notice($user, $pl);
|
|
||||||
}
|
|
||||||
|
|
||||||
$user->free();
|
|
||||||
unset($user);
|
|
||||||
unset($_cur);
|
|
||||||
|
|
||||||
unset($pl['xml']);
|
|
||||||
$pl['xml'] = null;
|
|
||||||
|
|
||||||
$pl = null;
|
|
||||||
unset($pl);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function is_self($from)
|
|
||||||
{
|
|
||||||
return preg_match('/^'.strtolower(jabber_daemon_address()).'/', strtolower($from));
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_ofrom($pl)
|
|
||||||
{
|
|
||||||
$xml = $pl['xml'];
|
|
||||||
$addresses = $xml->sub('addresses');
|
|
||||||
if (!$addresses) {
|
|
||||||
$this->log(LOG_WARNING, 'Forwarded message without addresses');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$address = $addresses->sub('address');
|
|
||||||
if (!$address) {
|
|
||||||
$this->log(LOG_WARNING, 'Forwarded message without address');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (!array_key_exists('type', $address->attrs)) {
|
|
||||||
$this->log(LOG_WARNING, 'No type for forwarded message');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$type = $address->attrs['type'];
|
|
||||||
if ($type != 'ofrom') {
|
|
||||||
$this->log(LOG_WARNING, 'Type of forwarded message is not ofrom');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (!array_key_exists('jid', $address->attrs)) {
|
|
||||||
$this->log(LOG_WARNING, 'No jid for forwarded message');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$jid = $address->attrs['jid'];
|
|
||||||
if (!$jid) {
|
|
||||||
$this->log(LOG_WARNING, 'Could not get jid from address');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$this->log(LOG_DEBUG, 'Got message forwarded from jid ' . $jid);
|
|
||||||
return $jid;
|
|
||||||
}
|
|
||||||
|
|
||||||
function is_autoreply($txt)
|
|
||||||
{
|
|
||||||
if (preg_match('/[\[\(]?[Aa]uto[-\s]?[Rr]e(ply|sponse)[\]\)]/', $txt)) {
|
|
||||||
return true;
|
|
||||||
} else if (preg_match('/^System: Message wasn\'t delivered. Offline storage size was exceeded.$/', $txt)) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function is_otr($txt)
|
|
||||||
{
|
|
||||||
if (preg_match('/^\?OTR/', $txt)) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function from_site($address, $msg)
|
|
||||||
{
|
|
||||||
$text = '['.common_config('site', 'name') . '] ' . $msg;
|
|
||||||
jabber_send_message($address, $text);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handle_command($user, $body)
|
|
||||||
{
|
|
||||||
$inter = new CommandInterpreter();
|
|
||||||
$cmd = $inter->handle_command($user, $body);
|
|
||||||
if ($cmd) {
|
|
||||||
$chan = new XMPPChannel($this->conn);
|
|
||||||
$cmd->execute($chan);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function add_notice(&$user, &$pl)
|
|
||||||
{
|
|
||||||
$body = trim($pl['body']);
|
|
||||||
$content_shortened = common_shorten_links($body);
|
|
||||||
if (Notice::contentTooLong($content_shortened)) {
|
|
||||||
$from = jabber_normalize_jid($pl['from']);
|
|
||||||
$this->from_site($from, sprintf(_('Message too long - maximum is %1$d characters, you sent %2$d.'),
|
|
||||||
Notice::maxContent(),
|
|
||||||
mb_strlen($content_shortened)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$notice = Notice::saveNew($user->id, $content_shortened, 'xmpp');
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$this->log(LOG_ERR, $e->getMessage());
|
|
||||||
$this->from_site($user->jabber, $e->getMessage());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
common_broadcast_notice($notice);
|
|
||||||
$this->log(LOG_INFO,
|
|
||||||
'Added notice ' . $notice->id . ' from user ' . $user->nickname);
|
|
||||||
$notice->free();
|
|
||||||
unset($notice);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handle_presence(&$pl)
|
|
||||||
{
|
|
||||||
$from = jabber_normalize_jid($pl['from']);
|
|
||||||
switch ($pl['type']) {
|
|
||||||
case 'subscribe':
|
|
||||||
# We let anyone subscribe
|
|
||||||
$this->subscribed($from);
|
|
||||||
$this->log(LOG_INFO,
|
|
||||||
'Accepted subscription from ' . $from);
|
|
||||||
break;
|
|
||||||
case 'subscribed':
|
|
||||||
case 'unsubscribed':
|
|
||||||
case 'unsubscribe':
|
|
||||||
$this->log(LOG_INFO,
|
|
||||||
'Ignoring "' . $pl['type'] . '" from ' . $from);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (!$pl['type']) {
|
|
||||||
$user = User::staticGet('jabber', $from);
|
|
||||||
if (!$user) {
|
|
||||||
$this->log(LOG_WARNING, 'Presence from unknown user ' . $from);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ($user->updatefrompresence) {
|
|
||||||
$this->log(LOG_INFO, 'Updating ' . $user->nickname .
|
|
||||||
' status from presence.');
|
|
||||||
$this->add_notice($user, $pl);
|
|
||||||
}
|
|
||||||
$user->free();
|
|
||||||
unset($user);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
unset($pl['xml']);
|
|
||||||
$pl['xml'] = null;
|
|
||||||
|
|
||||||
$pl = null;
|
|
||||||
unset($pl);
|
|
||||||
}
|
|
||||||
|
|
||||||
function log($level, $msg)
|
|
||||||
{
|
|
||||||
$text = 'XMPPDaemon('.$this->resource.'): '.$msg;
|
|
||||||
common_log($level, $text);
|
|
||||||
}
|
|
||||||
|
|
||||||
function subscribed($to)
|
|
||||||
{
|
|
||||||
jabber_special_presence('subscribed', $to);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make sure we're on the right site configuration
|
|
||||||
*/
|
|
||||||
protected function switchSite()
|
|
||||||
{
|
|
||||||
if ($this->site != common_config('site', 'server')) {
|
|
||||||
common_log(LOG_DEBUG, __METHOD__ . ": switching to site $this->site");
|
|
||||||
$this->stats('switch');
|
|
||||||
StatusNet::init($this->site);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* StatusNet - the distributed open-source microblogging tool
|
|
||||||
* Copyright (C) 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Queue handler for pre-processed outgoing XMPP messages.
|
|
||||||
* Formatted XML stanzas will have been pushed into the queue
|
|
||||||
* via the Queued_XMPP connection proxy, probably from some
|
|
||||||
* other queue processor.
|
|
||||||
*
|
|
||||||
* Here, the XML stanzas are simply pulled out of the queue and
|
|
||||||
* pushed out over the wire; an XmppManager is needed to set up
|
|
||||||
* and maintain the actual server connection.
|
|
||||||
*
|
|
||||||
* This queue will be run via XmppDaemon rather than QueueDaemon.
|
|
||||||
*
|
|
||||||
* @author Brion Vibber <brion@status.net>
|
|
||||||
*/
|
|
||||||
class XmppOutQueueHandler extends QueueHandler
|
|
||||||
{
|
|
||||||
function transport() {
|
|
||||||
return 'xmppout';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Take a previously-queued XMPP stanza and send it out ot the server.
|
|
||||||
* @param string $msg
|
|
||||||
* @return boolean true on success
|
|
||||||
*/
|
|
||||||
function handle($msg)
|
|
||||||
{
|
|
||||||
assert(is_string($msg));
|
|
||||||
|
|
||||||
$xmpp = XmppManager::get();
|
|
||||||
$ok = $xmpp->send($msg);
|
|
||||||
|
|
||||||
return $ok;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
162
plugins/Aim/AimPlugin.php
Normal file
162
plugins/Aim/AimPlugin.php
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2009, StatusNet, Inc.
|
||||||
|
*
|
||||||
|
* Send and receive notices using the AIM network
|
||||||
|
*
|
||||||
|
* 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 IM
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Craig Andrews <candrews@integralblue.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('STATUSNET')) {
|
||||||
|
// This check helps protect against security problems;
|
||||||
|
// your code file can't be executed directly from the web.
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
// We bundle the phptoclib library...
|
||||||
|
set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/extlib/phptoclib');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plugin for AIM
|
||||||
|
*
|
||||||
|
* @category Plugin
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Craig Andrews <candrews@integralblue.com>
|
||||||
|
* @copyright 2009 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class AimPlugin extends ImPlugin
|
||||||
|
{
|
||||||
|
public $user = null;
|
||||||
|
public $password = null;
|
||||||
|
public $publicFeed = array();
|
||||||
|
|
||||||
|
public $transport = 'aim';
|
||||||
|
|
||||||
|
function getDisplayName()
|
||||||
|
{
|
||||||
|
return _m('AIM');
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalize($screenname)
|
||||||
|
{
|
||||||
|
$screenname = str_replace(" ","", $screenname);
|
||||||
|
return strtolower($screenname);
|
||||||
|
}
|
||||||
|
|
||||||
|
function daemon_screenname()
|
||||||
|
{
|
||||||
|
return $this->user;
|
||||||
|
}
|
||||||
|
|
||||||
|
function validate($screenname)
|
||||||
|
{
|
||||||
|
if(preg_match('/^[a-z]\w{2,15}$/i', $screenname)) {
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load related modules when needed
|
||||||
|
*
|
||||||
|
* @param string $cls Name of the class to be loaded
|
||||||
|
*
|
||||||
|
* @return boolean hook value; true means continue processing, false means stop.
|
||||||
|
*/
|
||||||
|
function onAutoload($cls)
|
||||||
|
{
|
||||||
|
$dir = dirname(__FILE__);
|
||||||
|
|
||||||
|
switch ($cls)
|
||||||
|
{
|
||||||
|
case 'Aim':
|
||||||
|
require_once(INSTALLDIR.'/plugins/Aim/extlib/phptoclib/aimclassw.php');
|
||||||
|
return false;
|
||||||
|
case 'AimManager':
|
||||||
|
include_once $dir . '/'.strtolower($cls).'.php';
|
||||||
|
return false;
|
||||||
|
case 'Fake_Aim':
|
||||||
|
include_once $dir . '/'. $cls .'.php';
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onStartImDaemonIoManagers(&$classes)
|
||||||
|
{
|
||||||
|
parent::onStartImDaemonIoManagers(&$classes);
|
||||||
|
$classes[] = new AimManager($this); // handles sending/receiving
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function microiduri($screenname)
|
||||||
|
{
|
||||||
|
return 'aim:' . $screenname;
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_message($screenname, $body)
|
||||||
|
{
|
||||||
|
$this->fake_aim->sendIm($screenname, $body);
|
||||||
|
$this->enqueue_outgoing_raw($this->fake_aim->would_be_sent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function receive_raw_message($message)
|
||||||
|
{
|
||||||
|
$info=Aim::getMessageInfo($message);
|
||||||
|
$from = $info['from'];
|
||||||
|
$user = $this->get_user($from);
|
||||||
|
$notice_text = $info['message'];
|
||||||
|
|
||||||
|
return $this->handle_incoming($from, $notice_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initialize(){
|
||||||
|
if(!isset($this->user)){
|
||||||
|
throw new Exception("must specify a user");
|
||||||
|
}
|
||||||
|
if(!isset($this->password)){
|
||||||
|
throw new Exception("must specify a password");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->fake_aim = new Fake_Aim($this->user,$this->password,4);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onPluginVersion(&$versions)
|
||||||
|
{
|
||||||
|
$versions[] = array('name' => 'AIM',
|
||||||
|
'version' => STATUSNET_VERSION,
|
||||||
|
'author' => 'Craig Andrews',
|
||||||
|
'homepage' => 'http://status.net/wiki/Plugin:AIM',
|
||||||
|
'rawdescription' =>
|
||||||
|
_m('The AIM plugin allows users to send and receive notices over the AIM network.'));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
43
plugins/Aim/Fake_Aim.php
Normal file
43
plugins/Aim/Fake_Aim.php
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Instead of sending AIM messages, retrieve the raw data that would be sent
|
||||||
|
*
|
||||||
|
* 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 Network
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Craig Andrews <candrews@integralblue.com>
|
||||||
|
* @copyright 2010 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Fake_Aim extends Aim
|
||||||
|
{
|
||||||
|
public $would_be_sent = null;
|
||||||
|
|
||||||
|
function sflapSend($sflap_type, $sflap_data, $no_null, $formatted)
|
||||||
|
{
|
||||||
|
$this->would_be_sent = array($sflap_type, $sflap_data, $no_null, $formatted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
27
plugins/Aim/README
Normal file
27
plugins/Aim/README
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
The AIM plugin allows users to send and receive notices over the AIM network.
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
add "addPlugin('aim',
|
||||||
|
array('setting'=>'value', 'setting2'=>'value2', ...);"
|
||||||
|
to the bottom of your config.php
|
||||||
|
|
||||||
|
The daemon included with this plugin must be running. It will be started by
|
||||||
|
the plugin along with their other daemons when you run scripts/startdaemons.sh.
|
||||||
|
See the StatusNet README for more about queuing and daemons.
|
||||||
|
|
||||||
|
Settings
|
||||||
|
========
|
||||||
|
user*: username (screenname) to use when logging into AIM
|
||||||
|
password*: password for that user
|
||||||
|
|
||||||
|
* required
|
||||||
|
default values are in (parenthesis)
|
||||||
|
|
||||||
|
Example
|
||||||
|
=======
|
||||||
|
addPlugin('aim', array(
|
||||||
|
'user=>'...',
|
||||||
|
'password'=>'...'
|
||||||
|
));
|
||||||
|
|
100
plugins/Aim/aimmanager.php
Normal file
100
plugins/Aim/aimmanager.php
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<?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); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AIM background connection manager for AIM-using queue handlers,
|
||||||
|
* allowing them to send outgoing messages on the right connection.
|
||||||
|
*
|
||||||
|
* Input is handled during socket select loop, keepalive pings during idle.
|
||||||
|
* Any incoming messages will be handled.
|
||||||
|
*
|
||||||
|
* In a multi-site queuedaemon.php run, one connection will be instantiated
|
||||||
|
* for each site being handled by the current process that has XMPP enabled.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class AimManager extends ImManager
|
||||||
|
{
|
||||||
|
|
||||||
|
public $conn = null;
|
||||||
|
/**
|
||||||
|
* Initialize connection to server.
|
||||||
|
* @return boolean true on success
|
||||||
|
*/
|
||||||
|
public function start($master)
|
||||||
|
{
|
||||||
|
if(parent::start($master))
|
||||||
|
{
|
||||||
|
$this->connect();
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSockets()
|
||||||
|
{
|
||||||
|
$this->connect();
|
||||||
|
if($this->conn){
|
||||||
|
return array($this->conn->myConnection);
|
||||||
|
}else{
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process AIM events that have come in over the wire.
|
||||||
|
* @param resource $socket
|
||||||
|
*/
|
||||||
|
public function handleInput($socket)
|
||||||
|
{
|
||||||
|
common_log(LOG_DEBUG, "Servicing the AIM queue.");
|
||||||
|
$this->stats('aim_process');
|
||||||
|
$this->conn->receive();
|
||||||
|
}
|
||||||
|
|
||||||
|
function connect()
|
||||||
|
{
|
||||||
|
if (!$this->conn) {
|
||||||
|
$this->conn=new Aim($this->plugin->user,$this->plugin->password,4);
|
||||||
|
$this->conn->registerHandler("IMIn",array($this,"handle_aim_message"));
|
||||||
|
$this->conn->myServer="toc.oscar.aol.com";
|
||||||
|
$this->conn->signon();
|
||||||
|
$this->conn->setProfile(_m('Send me a message to post a notice'),false);
|
||||||
|
}
|
||||||
|
return $this->conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handle_aim_message($data)
|
||||||
|
{
|
||||||
|
$this->plugin->enqueue_incoming_raw($data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_raw_message($data)
|
||||||
|
{
|
||||||
|
$this->connect();
|
||||||
|
if (!$this->conn) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$this->conn->sflapSend($data[0],$data[1],$data[2],$data[3]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
169
plugins/Aim/extlib/phptoclib/README.txt
Executable file
169
plugins/Aim/extlib/phptoclib/README.txt
Executable file
@ -0,0 +1,169 @@
|
|||||||
|
phpTOCLib version 1.0 RC1
|
||||||
|
|
||||||
|
This is released under the LGPL. AIM,TOC,OSCAR, and all other related protocols/terms are
|
||||||
|
copyright AOL/Time Warner. This project is in no way affiliated with them, nor is this
|
||||||
|
project supported by them.
|
||||||
|
|
||||||
|
Some of the code is loosely based off of a script by Jeffrey Grafton. Mainly the decoding of packets, and the
|
||||||
|
function for roasting passwords is entirly his.
|
||||||
|
|
||||||
|
TOC documentation used is available at http://simpleaim.sourceforge.net/docs/TOC.txt
|
||||||
|
|
||||||
|
|
||||||
|
About:
|
||||||
|
phpTOCLib aims to be a PHP equivalent to the PERL module NET::AIM. Due to some limitations,
|
||||||
|
this is difficult. Many features have been excluded in the name of simplicity, and leaves
|
||||||
|
you alot of room to code with externally, providing function access to the variables that
|
||||||
|
need them.
|
||||||
|
|
||||||
|
I have aimed to make this extensible, and easy to use, therefore taking away some built in
|
||||||
|
functionality that I had originally out in. This project comes after several months of
|
||||||
|
researching the TOC protocol.
|
||||||
|
|
||||||
|
example.php is included with the class. It needs to be executed from the command line
|
||||||
|
(ie:php -q testscript.php) and you need to call php.exe with the -q
|
||||||
|
example is provided as a demonstaration only. Though it creats a very simple, functional bot, it lacks any sort of commands, it merely resends the message it recieves in reverse.
|
||||||
|
|
||||||
|
|
||||||
|
Revisions:
|
||||||
|
|
||||||
|
-----------------------------------
|
||||||
|
by Rajiv Makhijani
|
||||||
|
(02/24/04)
|
||||||
|
- Fixed Bug in Setting Permit/Deny Mode
|
||||||
|
- Fixes so Uninitialized string offset notice doesn't appear
|
||||||
|
- Replaced New Lines Outputed for Each Flap Read with " . " so
|
||||||
|
that you can still tell it is active but it does not take so much space
|
||||||
|
- Removed "eh?" message
|
||||||
|
- Added MySQL Database Connection Message
|
||||||
|
- New Functions:
|
||||||
|
update_profile(profile data string, powered by boolean)
|
||||||
|
* The profile data string is the text that goes in the profile.
|
||||||
|
* The powered by boolean if set to true displays a link to the
|
||||||
|
sourceforge page of the script.
|
||||||
|
(02/28/04)
|
||||||
|
- Silent option added to set object not to output any information
|
||||||
|
- To follow silent rule use sEcho function instead of Echo
|
||||||
|
-----------------------------------
|
||||||
|
by Jeremy (pickleman78)
|
||||||
|
(05/26/04) beta 1 release
|
||||||
|
-Complete overhaul of class design and message handling
|
||||||
|
-Fixed bug involving sign off after long periods of idling
|
||||||
|
-Added new function $Aim->registerHandler
|
||||||
|
-Added the capability to handle all AIM messages
|
||||||
|
-Processing the messages is still the users responsibility
|
||||||
|
-Did a little bit of code cleanup
|
||||||
|
-Added a few internal functions to make the classes internal life easier
|
||||||
|
-Improved AIM server error message processing
|
||||||
|
-Updated this document (hopefully Rajiv will clean it up some, since I'm a terrible documenter)
|
||||||
|
-------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
Several methods are provided in the class that allow for simple access to some of the
|
||||||
|
common features of AIM. Below are details.
|
||||||
|
|
||||||
|
$Aim->Aim($sn,$password,$pdmode, $silent=false)
|
||||||
|
The constructor, it takes 4 arguments.
|
||||||
|
$sn is your screen name
|
||||||
|
$password is you password, in plain text
|
||||||
|
$pdmode is the permit deny mode. This can be as follows:
|
||||||
|
1 - Allow All
|
||||||
|
2 - Deny All
|
||||||
|
3 - Permit only those on your permit list
|
||||||
|
4 - Permit all those not on your deny list
|
||||||
|
$silent if set to true prints out nothing
|
||||||
|
|
||||||
|
So, if your screen-name is JohnDoe746 and your password is fertu, and you want to allow
|
||||||
|
all users of the AIM server to contact you, you would code as follows
|
||||||
|
$myaim=new Aim("JohnDoe746","fertu",1);
|
||||||
|
|
||||||
|
|
||||||
|
$Aim->add_permit($buddy)
|
||||||
|
This adds the buddy passed to the function to your permit list.
|
||||||
|
ie: $myaim->add_permit("My friend22");
|
||||||
|
|
||||||
|
$Aim->block_buddy($buddy)
|
||||||
|
Blocks a user. This will switch your pd mode to 4. After using this, for the user to remain
|
||||||
|
out of contact with you, it is required to provide the constructor with a pd mode of 4
|
||||||
|
ie:$myaim->block_buddy("Annoying guy 4");
|
||||||
|
|
||||||
|
$Aim->send_im($to,$message,$auto=false)
|
||||||
|
Sends $message to $user. If you set the 3rd argument to true, then the recipient will receive it in
|
||||||
|
the same format as an away message. (Auto Response from me:)
|
||||||
|
A message longer than 65535 will be truncated
|
||||||
|
ie:$myaim->send_im("myfriend","This is a happy message");
|
||||||
|
|
||||||
|
$Aim->set_my_info()
|
||||||
|
Sends an update buddy command to the server and allows some internal values about yourself
|
||||||
|
to be set.
|
||||||
|
ie:$myaim->set_my_info();
|
||||||
|
|
||||||
|
$Aim->signon()
|
||||||
|
Call this to connect to the server. This must be called before any other methods will work
|
||||||
|
properly
|
||||||
|
ie:$mybot->signon();
|
||||||
|
|
||||||
|
$Aim->getLastReceived()
|
||||||
|
Returns $this->myLastReceived['decoded']. This should be the only peice of the gotten data
|
||||||
|
you need to concern yourself with. This is a preferred method of accessing this variable to prevent
|
||||||
|
accidental modification of $this->myLastReceived. Accidently modifying this variable can
|
||||||
|
cause some internal failures.
|
||||||
|
|
||||||
|
$Aim->read_from_aim()
|
||||||
|
This is a wrapper for $Aim->sflap_read(), and only returns the $this->myLastReceived['data']
|
||||||
|
portion of the message. It is preferred that you do not call $Aim->sflap_read() and use this
|
||||||
|
function instead. This function has a return value. Calling this prevents the need to call
|
||||||
|
$Aim->getLastReceived()
|
||||||
|
|
||||||
|
$Aim->setWarning($wl)
|
||||||
|
This allows you to update the bots warning level when warned.
|
||||||
|
|
||||||
|
$Aim->getBuddies()
|
||||||
|
Returns the $this->myBuddyList array. Use this instead of modifying the internal variable
|
||||||
|
|
||||||
|
$Aim->getPermit()
|
||||||
|
Returns the $this->myPermitList array. Use this instead of modifying the internal variable
|
||||||
|
|
||||||
|
$Aim->getBlocked()
|
||||||
|
Returns the $this->myBlockedList array. Use this instead of modifying the internal variable
|
||||||
|
|
||||||
|
$Aim->warn_user($user,$anon=false)
|
||||||
|
Warn $user. If anon is set to true, then it warns the user anonomously
|
||||||
|
|
||||||
|
$Aim->update_profile($information, $poweredby=false)
|
||||||
|
Updates Profile to $information. If $poweredby is true a link to
|
||||||
|
sourceforge page for this script is appended to profile
|
||||||
|
|
||||||
|
$Aim->registerHandler($function_name,$command)
|
||||||
|
This is by far the best thing about the new release.
|
||||||
|
For more information please reas supplement.txt. It is not included here because of the sheer size of the document.
|
||||||
|
supplement.txt contains full details on using registerHandler and what to expect for each input.
|
||||||
|
|
||||||
|
|
||||||
|
For convenience, I have provided some functions to simplify message processing.
|
||||||
|
|
||||||
|
They can be read about in the file "supplement.txt". I chose not to include the text here because it
|
||||||
|
is a huge document
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
There are a few things you should note about AIM
|
||||||
|
1)An incoming message has HTML tags in it. You are responsible for stripping those tags
|
||||||
|
2)Outgoing messages can have HTML tags, but will work fine if they don't. To include things
|
||||||
|
in the time feild next to the users name, send it as a comment
|
||||||
|
|
||||||
|
Conclusion:
|
||||||
|
The class is released under the LGPL. If you have any bug reports, comments, questions
|
||||||
|
feature requests, or want to help/show me what you've created with this(I am very interested in this),
|
||||||
|
please drop me an email: pickleman78@users.sourceforge.net. This code was written by
|
||||||
|
Jeremy(a.k.a pickleman78) and Rajiv M (a.k.a compwiz562).
|
||||||
|
|
||||||
|
|
||||||
|
Special thanks:
|
||||||
|
I'd like to thank all of the people who have contributed ideas, testing, bug reports, and code additions to
|
||||||
|
this project. I'd like to especially thank Rajiv, who has done do much for the project, and has kept this documnet
|
||||||
|
looking nice. He also has done alot of testing of this script too. I'd also like to thank SpazLink for his help in
|
||||||
|
testing. And finally I'd like to thank Jeffery Grafton, whose script inspired me to start this project.
|
2370
plugins/Aim/extlib/phptoclib/aimclassw.php
Executable file
2370
plugins/Aim/extlib/phptoclib/aimclassw.php
Executable file
File diff suppressed because it is too large
Load Diff
229
plugins/Aim/extlib/phptoclib/dconnection.php
Executable file
229
plugins/Aim/extlib/phptoclib/dconnection.php
Executable file
@ -0,0 +1,229 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
//The following class was created June 30th 2004 by Jeremy(pickle)
|
||||||
|
//This class is designed to handle a direct connection
|
||||||
|
|
||||||
|
class Dconnect
|
||||||
|
{
|
||||||
|
var $sock;
|
||||||
|
var $lastReceived;
|
||||||
|
var $lastMessage;
|
||||||
|
var $connected;
|
||||||
|
var $cookie;
|
||||||
|
var $type=2;
|
||||||
|
var $connectedTo;
|
||||||
|
|
||||||
|
|
||||||
|
function Dconnect($ip,$port)
|
||||||
|
{
|
||||||
|
if(!$this->connect($ip,$port))
|
||||||
|
{
|
||||||
|
sEcho("Connection failed constructor");
|
||||||
|
$this->connected=false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
$this->connected=true;
|
||||||
|
|
||||||
|
$this->lastMessage="";
|
||||||
|
$this->lastReceived="";
|
||||||
|
}
|
||||||
|
|
||||||
|
function readDIM()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
if(!$this->stuffToRead())
|
||||||
|
{
|
||||||
|
sEcho("Nothing to read");
|
||||||
|
$this->lastMessage=$this->lastReceived="";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
$head=fread($this->sock,6);
|
||||||
|
if(strlen($head)<=0)
|
||||||
|
{
|
||||||
|
sEcho("The direct connection has been closed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$minihead=unpack("a4ver/nsize",$head);
|
||||||
|
if($minihead['size'] <=0)
|
||||||
|
return;
|
||||||
|
$headerinfo=unpack("nchan/nsix/nzero/a6cookie/Npt1/Npt2/npt3/Nlen/Npt/npt0/ntype/Nzerom/a*sn",fread($this->sock,($minihead['size']-6)));
|
||||||
|
$allheader=array_merge($minihead,$headerinfo);
|
||||||
|
sEcho($allheader);
|
||||||
|
if($allheader['len']>0 && $allheader['len'] <= MAX_DIM_SIZE)
|
||||||
|
{
|
||||||
|
$left=$allheader['len'];
|
||||||
|
$stuff="";
|
||||||
|
$nonin=0;
|
||||||
|
while(strlen($stuff) < $allheader['len'] && $nonin<3)
|
||||||
|
{
|
||||||
|
$stuffg=fread($this->sock,$left);
|
||||||
|
if(strlen($stuffg)<0)
|
||||||
|
{
|
||||||
|
$nonin++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$left=$left - strlen($stuffg);
|
||||||
|
$stuff.=$stuffg;
|
||||||
|
}
|
||||||
|
$data=unpack("a*decoded",$stuff);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if($allheader['len'] > MAX_DIM_SIZE)
|
||||||
|
{
|
||||||
|
$data['decoded']="too big";
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
$data['decoded']="";
|
||||||
|
$all=array_merge($allheader,$data);
|
||||||
|
|
||||||
|
$this->lastReceived=$all;
|
||||||
|
$this->lastMessage=$all['decoded'];
|
||||||
|
|
||||||
|
//$function=$this->DimInf . "(\$all);";
|
||||||
|
//eval($function);
|
||||||
|
|
||||||
|
return $all;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendMessage($message,$sn)
|
||||||
|
{
|
||||||
|
//Make the "mini header"
|
||||||
|
$minihead=pack("a4n","ODC2",76);
|
||||||
|
$header=pack("nnna6NNnNNnnNa*",1,6,0,$this->cookie,0,0,0,strlen($message),0,0,96,0,$sn);
|
||||||
|
$bighead=$minihead . $header;
|
||||||
|
while(strlen($bighead)<76)
|
||||||
|
$bighead.=pack("c",0);
|
||||||
|
|
||||||
|
$tosend=$bighead . pack("a*",$message);
|
||||||
|
$w=array($this->sock);
|
||||||
|
stream_select($r=NULL,$w,$e=NULL,NULL);
|
||||||
|
//Now send it all
|
||||||
|
fputs($this->sock,$tosend,strlen($tosend));
|
||||||
|
}
|
||||||
|
function stuffToRead()
|
||||||
|
{
|
||||||
|
//$info=stream_get_meta_data($this->sock);
|
||||||
|
//sEcho($info);
|
||||||
|
$s=array($this->sock);
|
||||||
|
$changed=stream_select($s,$fds=NULL,$m=NULL,0,20000);
|
||||||
|
return ($changed>0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function close()
|
||||||
|
{
|
||||||
|
$this->connected=false;
|
||||||
|
return fclose($this->sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
function connect($ip,$port)
|
||||||
|
{
|
||||||
|
$this->sock=fsockopen($ip,$port,$en,$es,3);
|
||||||
|
if(!$this->sock)
|
||||||
|
{ sEcho("Connection failed");
|
||||||
|
$this->sock=null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class FileSendConnect
|
||||||
|
{
|
||||||
|
var $sock;
|
||||||
|
var $lastReceived;
|
||||||
|
var $lastMessage;
|
||||||
|
var $connected;
|
||||||
|
var $cookie;
|
||||||
|
var $tpye=3;
|
||||||
|
|
||||||
|
|
||||||
|
function FileSendConnect($ip,$port)
|
||||||
|
{
|
||||||
|
if(!$this->connect($ip,$port))
|
||||||
|
{
|
||||||
|
sEcho("Connection failed constructor");
|
||||||
|
$this->connected=false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
$this->connected=true;
|
||||||
|
|
||||||
|
$this->lastMessage="";
|
||||||
|
$this->lastReceived="";
|
||||||
|
}
|
||||||
|
|
||||||
|
function readDIM()
|
||||||
|
{
|
||||||
|
|
||||||
|
if(!$this->stuffToRead())
|
||||||
|
{
|
||||||
|
sEcho("Nothing to read");
|
||||||
|
$this->lastMessage=$this->lastReceived="";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$minihead=unpack("a4ver/nsize",fread($this->sock,6));
|
||||||
|
if($minihead['size'] <=0)
|
||||||
|
return;
|
||||||
|
$headerinfo=unpack("nchan/nsix/nzero/a6cookie/Npt1/Npt2/npt3/Nlen/Npt/npt0/ntype/Nzerom/a*sn",fread($this->sock,($minihead['size']-6)));
|
||||||
|
$allheader=array_merge($minihead,$headerinfo);
|
||||||
|
sEcho($allheader);
|
||||||
|
if($allheader['len']>0)
|
||||||
|
$data=unpack("a*decoded",fread($this->sock,$allheader['len']));
|
||||||
|
else
|
||||||
|
$data['decoded']="";
|
||||||
|
$all=array_merge($allheader,$data);
|
||||||
|
|
||||||
|
$this->lastReceived=$all;
|
||||||
|
$this->lastMessage=$all['decoded'];
|
||||||
|
|
||||||
|
//$function=$this->DimInf . "(\$all);";
|
||||||
|
//eval($function);
|
||||||
|
|
||||||
|
return $all;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendMessage($message,$sn)
|
||||||
|
{
|
||||||
|
//Make the "mini header"
|
||||||
|
$minihead=pack("a4n","ODC2",76);
|
||||||
|
$header=pack("nnna6NNnNNnnNa*",1,6,0,$this->cookie,0,0,0,strlen($message),0,0,96,0,$sn);
|
||||||
|
$bighead=$minihead . $header;
|
||||||
|
while(strlen($bighead)<76)
|
||||||
|
$bighead.=pack("c",0);
|
||||||
|
|
||||||
|
$tosend=$bighead . pack("a*",$message);
|
||||||
|
|
||||||
|
//Now send it all
|
||||||
|
fwrite($this->sock,$tosend,strlen($tosend));
|
||||||
|
}
|
||||||
|
function stuffToRead()
|
||||||
|
{
|
||||||
|
//$info=stream_get_meta_data($this->sock);
|
||||||
|
//sEcho($info);
|
||||||
|
$s=array($this->sock);
|
||||||
|
$changed=stream_select($s,$fds=NULL,$m=NULL,1);
|
||||||
|
return ($changed>0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function close()
|
||||||
|
{
|
||||||
|
$this->connected=false;
|
||||||
|
fclose($this->sock);
|
||||||
|
unset($this->sock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function connect($ip,$port)
|
||||||
|
{
|
||||||
|
$this->sock=fsockopen($ip,$port,$en,$es,3);
|
||||||
|
if(!$this->sock)
|
||||||
|
{ sEcho("Connection failed to" . $ip . ":" . $port);
|
||||||
|
$this->sock=null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -57,12 +57,14 @@ class ImapManager extends IoManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tell the i/o master we need one instance for each supporting site
|
* Tell the i/o master we need one instance globally.
|
||||||
* being handled in this process.
|
* Since this is a plugin manager, the plugin class itself will
|
||||||
|
* create one instance per site. This prevents the IoMaster from
|
||||||
|
* making more instances.
|
||||||
*/
|
*/
|
||||||
public static function multiSite()
|
public static function multiSite()
|
||||||
{
|
{
|
||||||
return IoManager::INSTANCE_PER_SITE;
|
return IoManager::GLOBAL_SINGLE_ONLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
/**
|
/**
|
||||||
* StatusNet, the distributed open-source microblogging tool
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
*
|
*
|
||||||
* Queue-mediated proxy class for outgoing XMPP messages.
|
* Instead of sending XMPP messages, retrieve the raw XML that would be sent
|
||||||
*
|
*
|
||||||
* PHP version 5
|
* PHP version 5
|
||||||
*
|
*
|
||||||
@ -31,10 +31,10 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
require_once INSTALLDIR . '/lib/jabber.php';
|
class Fake_XMPP extends XMPPHP_XMPP
|
||||||
|
|
||||||
class Queued_XMPP extends XMPPHP_XMPP
|
|
||||||
{
|
{
|
||||||
|
public $would_be_sent = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
@ -63,54 +63,41 @@ class Queued_XMPP extends XMPPHP_XMPP
|
|||||||
*/
|
*/
|
||||||
public function send($msg, $timeout=NULL)
|
public function send($msg, $timeout=NULL)
|
||||||
{
|
{
|
||||||
$qm = QueueManager::get();
|
$this->would_be_sent = $msg;
|
||||||
$qm->enqueue(strval($msg), 'xmppout');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Since we'll be getting input through a queue system's run loop,
|
|
||||||
* we'll process one standalone message at a time rather than our
|
|
||||||
* own XMPP message pump.
|
|
||||||
*
|
|
||||||
* @param string $message
|
|
||||||
*/
|
|
||||||
public function processMessage($message) {
|
|
||||||
$frame = array_shift($this->frames);
|
|
||||||
xml_parse($this->parser, $frame->body, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@{
|
//@{
|
||||||
/**
|
/**
|
||||||
* Stream i/o functions disabled; push input through processMessage()
|
* Stream i/o functions disabled; only do output
|
||||||
*/
|
*/
|
||||||
public function connect($timeout = 30, $persistent = false, $sendinit = true)
|
public function connect($timeout = 30, $persistent = false, $sendinit = true)
|
||||||
{
|
{
|
||||||
throw new Exception("Can't connect to server from XMPP queue proxy.");
|
throw new Exception("Can't connect to server from fake XMPP.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function disconnect()
|
public function disconnect()
|
||||||
{
|
{
|
||||||
throw new Exception("Can't connect to server from XMPP queue proxy.");
|
throw new Exception("Can't connect to server from fake XMPP.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function process()
|
public function process()
|
||||||
{
|
{
|
||||||
throw new Exception("Can't read stream from XMPP queue proxy.");
|
throw new Exception("Can't read stream from fake XMPP.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processUntil($event, $timeout=-1)
|
public function processUntil($event, $timeout=-1)
|
||||||
{
|
{
|
||||||
throw new Exception("Can't read stream from XMPP queue proxy.");
|
throw new Exception("Can't read stream from fake XMPP.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function read()
|
public function read()
|
||||||
{
|
{
|
||||||
throw new Exception("Can't read stream from XMPP queue proxy.");
|
throw new Exception("Can't read stream from fake XMPP.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function readyToProcess()
|
public function readyToProcess()
|
||||||
{
|
{
|
||||||
throw new Exception("Can't read stream from XMPP queue proxy.");
|
throw new Exception("Can't read stream from fake XMPP.");
|
||||||
}
|
}
|
||||||
//@}
|
//@}
|
||||||
}
|
}
|
35
plugins/Xmpp/README
Normal file
35
plugins/Xmpp/README
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
The XMPP plugin allows users to send and receive notices over the XMPP/Jabber/GTalk network.
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
add "addPlugin('xmpp',
|
||||||
|
array('setting'=>'value', 'setting2'=>'value2', ...);"
|
||||||
|
to the bottom of your config.php
|
||||||
|
|
||||||
|
The daemon included with this plugin must be running. It will be started by
|
||||||
|
the plugin along with their other daemons when you run scripts/startdaemons.sh.
|
||||||
|
See the StatusNet README for more about queuing and daemons.
|
||||||
|
|
||||||
|
Settings
|
||||||
|
========
|
||||||
|
user*: user part of the jid
|
||||||
|
server*: server part of the jid
|
||||||
|
resource: resource part of the jid
|
||||||
|
port (5222): port on which to connect to the server
|
||||||
|
encryption (true): use encryption on the connection
|
||||||
|
host (same as server): host to connect to. Usually, you won't set this.
|
||||||
|
debug (false): log extra debug info
|
||||||
|
public: list of jid's that should get the public feed (firehose)
|
||||||
|
|
||||||
|
* required
|
||||||
|
default values are in (parenthesis)
|
||||||
|
|
||||||
|
Example
|
||||||
|
=======
|
||||||
|
addPlugin('xmpp', array(
|
||||||
|
'user=>'update',
|
||||||
|
'server=>'identi.ca',
|
||||||
|
'password'=>'...',
|
||||||
|
'public'=>array('bob@aol.com', 'sue@google.com')
|
||||||
|
));
|
||||||
|
|
43
plugins/Xmpp/Sharing_XMPP.php
Normal file
43
plugins/Xmpp/Sharing_XMPP.php
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2009, StatusNet, Inc.
|
||||||
|
*
|
||||||
|
* Send and receive notices using the Jabber network
|
||||||
|
*
|
||||||
|
* 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 Jabber
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2009 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET')) {
|
||||||
|
// This check helps protect against security problems;
|
||||||
|
// your code file can't be executed directly from the web.
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Sharing_XMPP extends XMPPHP_XMPP
|
||||||
|
{
|
||||||
|
function getSocket()
|
||||||
|
{
|
||||||
|
return $this->socket;
|
||||||
|
}
|
||||||
|
}
|
247
plugins/Xmpp/XmppPlugin.php
Normal file
247
plugins/Xmpp/XmppPlugin.php
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2009, StatusNet, Inc.
|
||||||
|
*
|
||||||
|
* Send and receive notices using the XMPP network
|
||||||
|
*
|
||||||
|
* 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 IM
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2009 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET')) {
|
||||||
|
// This check helps protect against security problems;
|
||||||
|
// your code file can't be executed directly from the web.
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plugin for XMPP
|
||||||
|
*
|
||||||
|
* @category Plugin
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2009 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class XmppPlugin extends ImPlugin
|
||||||
|
{
|
||||||
|
public $server = null;
|
||||||
|
public $port = 5222;
|
||||||
|
public $user = 'update';
|
||||||
|
public $resource = null;
|
||||||
|
public $encryption = true;
|
||||||
|
public $password = null;
|
||||||
|
public $host = null; // only set if != server
|
||||||
|
public $debug = false; // print extra debug info
|
||||||
|
|
||||||
|
public $transport = 'xmpp';
|
||||||
|
|
||||||
|
protected $fake_xmpp;
|
||||||
|
|
||||||
|
function getDisplayName(){
|
||||||
|
return _m('XMPP/Jabber/GTalk');
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalize($screenname)
|
||||||
|
{
|
||||||
|
if (preg_match("/(?:([^\@]+)\@)?([^\/]+)(?:\/(.*))?$/", $screenname, $matches)) {
|
||||||
|
$node = $matches[1];
|
||||||
|
$server = $matches[2];
|
||||||
|
return strtolower($node.'@'.$server);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function daemon_screenname()
|
||||||
|
{
|
||||||
|
$ret = $this->user . '@' . $this->server;
|
||||||
|
if($this->resource)
|
||||||
|
{
|
||||||
|
return $ret . '/' . $this->resource;
|
||||||
|
}else{
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function validate($screenname)
|
||||||
|
{
|
||||||
|
// Cheap but effective
|
||||||
|
return Validate::email($screenname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load related modules when needed
|
||||||
|
*
|
||||||
|
* @param string $cls Name of the class to be loaded
|
||||||
|
*
|
||||||
|
* @return boolean hook value; true means continue processing, false means stop.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function onAutoload($cls)
|
||||||
|
{
|
||||||
|
$dir = dirname(__FILE__);
|
||||||
|
|
||||||
|
switch ($cls)
|
||||||
|
{
|
||||||
|
case 'Sharing_XMPP':
|
||||||
|
case 'Fake_XMPP':
|
||||||
|
include_once $dir . '/'.$cls.'.php';
|
||||||
|
return false;
|
||||||
|
case 'XmppManager':
|
||||||
|
include_once $dir . '/'.strtolower($cls).'.php';
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onStartImDaemonIoManagers(&$classes)
|
||||||
|
{
|
||||||
|
parent::onStartImDaemonIoManagers(&$classes);
|
||||||
|
$classes[] = new XmppManager($this); // handles pings/reconnects
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function microiduri($screenname)
|
||||||
|
{
|
||||||
|
return 'xmpp:' . $screenname;
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_message($screenname, $body)
|
||||||
|
{
|
||||||
|
$this->fake_xmpp->message($screenname, $body, 'chat');
|
||||||
|
$this->enqueue_outgoing_raw($this->fake_xmpp->would_be_sent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_notice($screenname, $notice)
|
||||||
|
{
|
||||||
|
$msg = $this->format_notice($notice);
|
||||||
|
$entry = $this->format_entry($notice);
|
||||||
|
|
||||||
|
$this->fake_xmpp->message($screenname, $msg, 'chat', null, $entry);
|
||||||
|
$this->enqueue_outgoing_raw($this->fake_xmpp->would_be_sent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* extra information for XMPP messages, as defined by Twitter
|
||||||
|
*
|
||||||
|
* @param Profile $profile Profile of the sending user
|
||||||
|
* @param Notice $notice Notice being sent
|
||||||
|
*
|
||||||
|
* @return string Extra information (Atom, HTML, addresses) in string format
|
||||||
|
*/
|
||||||
|
|
||||||
|
function format_entry($notice)
|
||||||
|
{
|
||||||
|
$profile = $notice->getProfile();
|
||||||
|
|
||||||
|
$entry = $notice->asAtomEntry(true, true);
|
||||||
|
|
||||||
|
$xs = new XMLStringer();
|
||||||
|
$xs->elementStart('html', array('xmlns' => 'http://jabber.org/protocol/xhtml-im'));
|
||||||
|
$xs->elementStart('body', array('xmlns' => 'http://www.w3.org/1999/xhtml'));
|
||||||
|
$xs->element('a', array('href' => $profile->profileurl),
|
||||||
|
$profile->nickname);
|
||||||
|
$xs->text(": ");
|
||||||
|
if (!empty($notice->rendered)) {
|
||||||
|
$xs->raw($notice->rendered);
|
||||||
|
} else {
|
||||||
|
$xs->raw(common_render_content($notice->content, $notice));
|
||||||
|
}
|
||||||
|
$xs->text(" ");
|
||||||
|
$xs->element('a', array(
|
||||||
|
'href'=>common_local_url('conversation',
|
||||||
|
array('id' => $notice->conversation)).'#notice-'.$notice->id
|
||||||
|
),sprintf(_('[%s]'),$notice->id));
|
||||||
|
$xs->elementEnd('body');
|
||||||
|
$xs->elementEnd('html');
|
||||||
|
|
||||||
|
$html = $xs->getString();
|
||||||
|
|
||||||
|
return $html . ' ' . $entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
function receive_raw_message($pl)
|
||||||
|
{
|
||||||
|
$from = $this->normalize($pl['from']);
|
||||||
|
|
||||||
|
if ($pl['type'] != 'chat') {
|
||||||
|
common_log(LOG_WARNING, "Ignoring message of type ".$pl['type']." from $from.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mb_strlen($pl['body']) == 0) {
|
||||||
|
common_log(LOG_WARNING, "Ignoring message with empty body from $from.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->handle_incoming($from, $pl['body']);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initialize(){
|
||||||
|
if(!isset($this->server)){
|
||||||
|
throw new Exception("must specify a server");
|
||||||
|
}
|
||||||
|
if(!isset($this->port)){
|
||||||
|
throw new Exception("must specify a port");
|
||||||
|
}
|
||||||
|
if(!isset($this->user)){
|
||||||
|
throw new Exception("must specify a user");
|
||||||
|
}
|
||||||
|
if(!isset($this->password)){
|
||||||
|
throw new Exception("must specify a password");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->fake_xmpp = new Fake_XMPP($this->host ?
|
||||||
|
$this->host :
|
||||||
|
$this->server,
|
||||||
|
$this->port,
|
||||||
|
$this->user,
|
||||||
|
$this->password,
|
||||||
|
$this->resource,
|
||||||
|
$this->server,
|
||||||
|
$this->debug ?
|
||||||
|
true : false,
|
||||||
|
$this->debug ?
|
||||||
|
XMPPHP_Log::LEVEL_VERBOSE : null
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onPluginVersion(&$versions)
|
||||||
|
{
|
||||||
|
$versions[] = array('name' => 'XMPP',
|
||||||
|
'version' => STATUSNET_VERSION,
|
||||||
|
'author' => 'Craig Andrews, Evan Prodromou',
|
||||||
|
'homepage' => 'http://status.net/wiki/Plugin:XMPP',
|
||||||
|
'rawdescription' =>
|
||||||
|
_m('The XMPP plugin allows users to send and receive notices over the XMPP/Jabber network.'));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
279
plugins/Xmpp/xmppmanager.php
Normal file
279
plugins/Xmpp/xmppmanager.php
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
<?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); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XMPP background connection manager for XMPP-using queue handlers,
|
||||||
|
* allowing them to send outgoing messages on the right connection.
|
||||||
|
*
|
||||||
|
* Input is handled during socket select loop, keepalive pings during idle.
|
||||||
|
* Any incoming messages will be handled.
|
||||||
|
*
|
||||||
|
* In a multi-site queuedaemon.php run, one connection will be instantiated
|
||||||
|
* for each site being handled by the current process that has XMPP enabled.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class XmppManager extends ImManager
|
||||||
|
{
|
||||||
|
protected $lastping = null;
|
||||||
|
protected $pingid = null;
|
||||||
|
|
||||||
|
public $conn = null;
|
||||||
|
|
||||||
|
const PING_INTERVAL = 120;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize connection to server.
|
||||||
|
* @return boolean true on success
|
||||||
|
*/
|
||||||
|
public function start($master)
|
||||||
|
{
|
||||||
|
if(parent::start($master))
|
||||||
|
{
|
||||||
|
$this->connect();
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_raw_message($data)
|
||||||
|
{
|
||||||
|
$this->connect();
|
||||||
|
if (!$this->conn || $this->conn->isDisconnected()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$this->conn->send($data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message pump is triggered on socket input, so we only need an idle()
|
||||||
|
* call often enough to trigger our outgoing pings.
|
||||||
|
*/
|
||||||
|
function timeout()
|
||||||
|
{
|
||||||
|
return self::PING_INTERVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process XMPP events that have come in over the wire.
|
||||||
|
* @fixme may kill process on XMPP error
|
||||||
|
* @param resource $socket
|
||||||
|
*/
|
||||||
|
public function handleInput($socket)
|
||||||
|
{
|
||||||
|
# Process the queue for as long as needed
|
||||||
|
try {
|
||||||
|
common_log(LOG_DEBUG, "Servicing the XMPP queue.");
|
||||||
|
$this->stats('xmpp_process');
|
||||||
|
$this->conn->processTime(0);
|
||||||
|
} catch (XMPPHP_Exception $e) {
|
||||||
|
common_log(LOG_ERR, "Got an XMPPHP_Exception: " . $e->getMessage());
|
||||||
|
die($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists the IM connection socket to allow i/o master to wake
|
||||||
|
* when input comes in here as well as from the queue source.
|
||||||
|
*
|
||||||
|
* @return array of resources
|
||||||
|
*/
|
||||||
|
public function getSockets()
|
||||||
|
{
|
||||||
|
$this->connect();
|
||||||
|
if($this->conn){
|
||||||
|
return array($this->conn->getSocket());
|
||||||
|
}else{
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Idle processing for io manager's execution loop.
|
||||||
|
* Send keepalive pings to server.
|
||||||
|
*
|
||||||
|
* Side effect: kills process on exception from XMPP library.
|
||||||
|
*
|
||||||
|
* @fixme non-dying error handling
|
||||||
|
*/
|
||||||
|
public function idle($timeout=0)
|
||||||
|
{
|
||||||
|
$now = time();
|
||||||
|
if (empty($this->lastping) || $now - $this->lastping > self::PING_INTERVAL) {
|
||||||
|
try {
|
||||||
|
$this->send_ping();
|
||||||
|
} catch (XMPPHP_Exception $e) {
|
||||||
|
common_log(LOG_ERR, "Got an XMPPHP_Exception: " . $e->getMessage());
|
||||||
|
die($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function connect()
|
||||||
|
{
|
||||||
|
if (!$this->conn || $this->conn->isDisconnected()) {
|
||||||
|
$resource = 'queue' . posix_getpid();
|
||||||
|
$this->conn = new Sharing_XMPP($this->plugin->host ?
|
||||||
|
$this->plugin->host :
|
||||||
|
$this->plugin->server,
|
||||||
|
$this->plugin->port,
|
||||||
|
$this->plugin->user,
|
||||||
|
$this->plugin->password,
|
||||||
|
$this->plugin->resource,
|
||||||
|
$this->plugin->server,
|
||||||
|
$this->plugin->debug ?
|
||||||
|
true : false,
|
||||||
|
$this->plugin->debug ?
|
||||||
|
XMPPHP_Log::LEVEL_VERBOSE : null
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$this->conn) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$this->conn->addEventHandler('message', 'handle_xmpp_message', $this);
|
||||||
|
$this->conn->addEventHandler('reconnect', 'handle_xmpp_reconnect', $this);
|
||||||
|
$this->conn->setReconnectTimeout(600);
|
||||||
|
|
||||||
|
$this->conn->autoSubscribe();
|
||||||
|
$this->conn->useEncryption($this->plugin->encryption);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->conn->connect(true); // true = persistent connection
|
||||||
|
} catch (XMPPHP_Exception $e) {
|
||||||
|
common_log(LOG_ERR, $e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->conn->processUntil('session_start');
|
||||||
|
$this->send_presence(_m('Send me a message to post a notice'), 'available', null, 'available', 100);
|
||||||
|
}
|
||||||
|
return $this->conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_ping()
|
||||||
|
{
|
||||||
|
$this->connect();
|
||||||
|
if (!$this->conn || $this->conn->isDisconnected()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$now = time();
|
||||||
|
if (!isset($this->pingid)) {
|
||||||
|
$this->pingid = 0;
|
||||||
|
} else {
|
||||||
|
$this->pingid++;
|
||||||
|
}
|
||||||
|
|
||||||
|
common_log(LOG_DEBUG, "Sending ping #{$this->pingid}");
|
||||||
|
$this->conn->send("<iq from='{" . $this->plugin->daemon_screenname() . "}' to='{$this->plugin->server}' id='ping_{$this->pingid}' type='get'><ping xmlns='urn:xmpp:ping'/></iq>");
|
||||||
|
$this->lastping = $now;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handle_xmpp_message(&$pl)
|
||||||
|
{
|
||||||
|
$this->plugin->enqueue_incoming_raw($pl);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for Jabber reconnect event
|
||||||
|
* @param $pl
|
||||||
|
*/
|
||||||
|
function handle_xmpp_reconnect(&$pl)
|
||||||
|
{
|
||||||
|
common_log(LOG_NOTICE, 'XMPP reconnected');
|
||||||
|
|
||||||
|
$this->conn->processUntil('session_start');
|
||||||
|
$this->send_presence(_m('Send me a message to post a notice'), 'available', null, 'available', 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sends a presence stanza on the XMPP network
|
||||||
|
*
|
||||||
|
* @param string $status current status, free-form string
|
||||||
|
* @param string $show structured status value
|
||||||
|
* @param string $to recipient of presence, null for general
|
||||||
|
* @param string $type type of status message, related to $show
|
||||||
|
* @param int $priority priority of the presence
|
||||||
|
*
|
||||||
|
* @return boolean success value
|
||||||
|
*/
|
||||||
|
|
||||||
|
function send_presence($status, $show='available', $to=null,
|
||||||
|
$type = 'available', $priority=null)
|
||||||
|
{
|
||||||
|
$this->connect();
|
||||||
|
if (!$this->conn || $this->conn->isDisconnected()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$this->conn->presence($status, $show, $to, $type, $priority);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sends a "special" presence stanza on the XMPP network
|
||||||
|
*
|
||||||
|
* @param string $type Type of presence
|
||||||
|
* @param string $to JID to send presence to
|
||||||
|
* @param string $show show value for presence
|
||||||
|
* @param string $status status value for presence
|
||||||
|
*
|
||||||
|
* @return boolean success flag
|
||||||
|
*
|
||||||
|
* @see send_presence()
|
||||||
|
*/
|
||||||
|
|
||||||
|
function special_presence($type, $to=null, $show=null, $status=null)
|
||||||
|
{
|
||||||
|
// FIXME: why use this instead of send_presence()?
|
||||||
|
$this->connect();
|
||||||
|
if (!$this->conn || $this->conn->isDisconnected()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$to = htmlspecialchars($to);
|
||||||
|
$status = htmlspecialchars($status);
|
||||||
|
|
||||||
|
$out = "<presence";
|
||||||
|
if ($to) {
|
||||||
|
$out .= " to='$to'";
|
||||||
|
}
|
||||||
|
if ($type) {
|
||||||
|
$out .= " type='$type'";
|
||||||
|
}
|
||||||
|
if ($show == 'available' and !$status) {
|
||||||
|
$out .= "/>";
|
||||||
|
} else {
|
||||||
|
$out .= ">";
|
||||||
|
if ($show && ($show != 'available')) {
|
||||||
|
$out .= "<show>$show</show>";
|
||||||
|
}
|
||||||
|
if ($status) {
|
||||||
|
$out .= "<status>$status</status>";
|
||||||
|
}
|
||||||
|
$out .= "</presence>";
|
||||||
|
}
|
||||||
|
$this->conn->send($out);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -39,9 +39,7 @@ $daemons = array();
|
|||||||
|
|
||||||
$daemons[] = INSTALLDIR.'/scripts/queuedaemon.php';
|
$daemons[] = INSTALLDIR.'/scripts/queuedaemon.php';
|
||||||
|
|
||||||
if(common_config('xmpp','enabled')) {
|
$daemons[] = INSTALLDIR.'/scripts/imdaemon.php';
|
||||||
$daemons[] = INSTALLDIR.'/scripts/xmppdaemon.php';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Event::handle('GetValidDaemons', array(&$daemons))) {
|
if (Event::handle('GetValidDaemons', array(&$daemons))) {
|
||||||
foreach ($daemons as $daemon) {
|
foreach ($daemons as $daemon) {
|
||||||
|
@ -23,34 +23,32 @@ define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
|
|||||||
$shortoptions = 'fi::';
|
$shortoptions = 'fi::';
|
||||||
$longoptions = array('id::', 'foreground');
|
$longoptions = array('id::', 'foreground');
|
||||||
|
|
||||||
$helptext = <<<END_OF_XMPP_HELP
|
$helptext = <<<END_OF_IM_HELP
|
||||||
Daemon script for receiving new notices from Jabber users.
|
Daemon script for receiving new notices from IM users.
|
||||||
|
|
||||||
-i --id Identity (default none)
|
-i --id Identity (default none)
|
||||||
-f --foreground Stay in the foreground (default background)
|
-f --foreground Stay in the foreground (default background)
|
||||||
|
|
||||||
END_OF_XMPP_HELP;
|
END_OF_IM_HELP;
|
||||||
|
|
||||||
require_once INSTALLDIR.'/scripts/commandline.inc';
|
require_once INSTALLDIR.'/scripts/commandline.inc';
|
||||||
|
|
||||||
require_once INSTALLDIR . '/lib/jabber.php';
|
class ImDaemon extends SpawningDaemon
|
||||||
|
|
||||||
class XMPPDaemon extends SpawningDaemon
|
|
||||||
{
|
{
|
||||||
function __construct($id=null, $daemonize=true, $threads=1)
|
function __construct($id=null, $daemonize=true, $threads=1)
|
||||||
{
|
{
|
||||||
if ($threads != 1) {
|
if ($threads != 1) {
|
||||||
// This should never happen. :)
|
// This should never happen. :)
|
||||||
throw new Exception("XMPPDaemon can must run single-threaded");
|
throw new Exception("IMDaemon can must run single-threaded");
|
||||||
}
|
}
|
||||||
parent::__construct($id, $daemonize, $threads);
|
parent::__construct($id, $daemonize, $threads);
|
||||||
}
|
}
|
||||||
|
|
||||||
function runThread()
|
function runThread()
|
||||||
{
|
{
|
||||||
common_log(LOG_INFO, 'Waiting to listen to XMPP and queues');
|
common_log(LOG_INFO, 'Waiting to listen to IM connections and queues');
|
||||||
|
|
||||||
$master = new XmppMaster($this->get_id());
|
$master = new ImMaster($this->get_id());
|
||||||
$master->init();
|
$master->init();
|
||||||
$master->service();
|
$master->service();
|
||||||
|
|
||||||
@ -61,7 +59,7 @@ class XMPPDaemon extends SpawningDaemon
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class XmppMaster extends IoMaster
|
class ImMaster extends IoMaster
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Initialize IoManagers for the currently configured site
|
* Initialize IoManagers for the currently configured site
|
||||||
@ -69,20 +67,17 @@ class XmppMaster extends IoMaster
|
|||||||
*/
|
*/
|
||||||
function initManagers()
|
function initManagers()
|
||||||
{
|
{
|
||||||
// @fixme right now there's a hack in QueueManager to determine
|
$classes = array();
|
||||||
// which queues to subscribe to based on the master class.
|
if (Event::handle('StartImDaemonIoManagers', array(&$classes))) {
|
||||||
$this->instantiate('QueueManager');
|
$classes[] = 'QueueManager';
|
||||||
$this->instantiate('XmppManager');
|
}
|
||||||
|
Event::handle('EndImDaemonIoManagers', array(&$classes));
|
||||||
|
foreach ($classes as $class) {
|
||||||
|
$this->instantiate($class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Abort immediately if xmpp is not enabled, otherwise the daemon chews up
|
|
||||||
// lots of CPU trying to connect to unconfigured servers
|
|
||||||
if (common_config('xmpp','enabled')==false) {
|
|
||||||
print "Aborting daemon - xmpp is disabled\n";
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (have_option('i', 'id')) {
|
if (have_option('i', 'id')) {
|
||||||
$id = get_option_value('i', 'id');
|
$id = get_option_value('i', 'id');
|
||||||
} else if (count($args) > 0) {
|
} else if (count($args) > 0) {
|
||||||
@ -93,6 +88,6 @@ if (have_option('i', 'id')) {
|
|||||||
|
|
||||||
$foreground = have_option('f', 'foreground');
|
$foreground = have_option('f', 'foreground');
|
||||||
|
|
||||||
$daemon = new XMPPDaemon($id, !$foreground);
|
$daemon = new ImDaemon($id, !$foreground);
|
||||||
|
|
||||||
$daemon->runOnce();
|
$daemon->runOnce();
|
@ -21,7 +21,7 @@
|
|||||||
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
|
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
|
||||||
|
|
||||||
$shortoptions = 'fi:at:';
|
$shortoptions = 'fi:at:';
|
||||||
$longoptions = array('id=', 'foreground', 'all', 'threads=', 'skip-xmpp', 'xmpp-only');
|
$longoptions = array('id=', 'foreground', 'all', 'threads=');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to get a count of the processors available on the current system
|
* Attempts to get a count of the processors available on the current system
|
||||||
@ -163,13 +163,6 @@ if (!$threads) {
|
|||||||
$daemonize = !(have_option('f') || have_option('--foreground'));
|
$daemonize = !(have_option('f') || have_option('--foreground'));
|
||||||
$all = have_option('a') || have_option('--all');
|
$all = have_option('a') || have_option('--all');
|
||||||
|
|
||||||
if (have_option('--skip-xmpp')) {
|
|
||||||
define('XMPP_EMERGENCY_FLAG', true);
|
|
||||||
}
|
|
||||||
if (have_option('--xmpp-only')) {
|
|
||||||
define('XMPP_ONLY_FLAG', true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$daemon = new QueueDaemon($id, $daemonize, $threads, $all);
|
$daemon = new QueueDaemon($id, $daemonize, $threads, $all);
|
||||||
$daemon->runOnce();
|
$daemon->runOnce();
|
||||||
|
|
||||||
|
@ -23,8 +23,8 @@
|
|||||||
SDIR=`dirname $0`
|
SDIR=`dirname $0`
|
||||||
DIR=`php $SDIR/getpiddir.php`
|
DIR=`php $SDIR/getpiddir.php`
|
||||||
|
|
||||||
for f in jabberhandler ombhandler publichandler smshandler pinghandler \
|
for f in ombhandler smshandler pinghandler \
|
||||||
xmppconfirmhandler xmppdaemon twitterhandler facebookhandler \
|
twitterhandler facebookhandler \
|
||||||
twitterstatusfetcher synctwitterfriends pluginhandler rsscloudhandler; do
|
twitterstatusfetcher synctwitterfriends pluginhandler rsscloudhandler; do
|
||||||
|
|
||||||
FILES="$DIR/$f.*.pid"
|
FILES="$DIR/$f.*.pid"
|
||||||
|
Loading…
Reference in New Issue
Block a user