summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/accountsettingsaction.php64
-rw-r--r--lib/action.php19
-rw-r--r--lib/command.php16
-rw-r--r--lib/common.php36
-rw-r--r--lib/facebookaction.php11
-rw-r--r--lib/groupeditform.php24
-rw-r--r--lib/logingroupnav.php38
-rw-r--r--lib/messageform.php17
-rw-r--r--lib/noticeform.php23
-rw-r--r--lib/oauthstore.php357
-rw-r--r--lib/omb.php335
-rw-r--r--lib/settingsaction.php10
-rw-r--r--lib/unqueuemanager.php2
-rw-r--r--lib/util.php26
14 files changed, 648 insertions, 330 deletions
diff --git a/lib/accountsettingsaction.php b/lib/accountsettingsaction.php
index 1a21d871e..9814c48ab 100644
--- a/lib/accountsettingsaction.php
+++ b/lib/accountsettingsaction.php
@@ -98,42 +98,42 @@ class AccountSettingsNav extends Widget
function show()
{
- # action => array('prompt', 'title')
- $menu =
- array('profilesettings' =>
- array(_('Profile'),
- _('Change your profile settings')),
- 'avatarsettings' =>
- array(_('Avatar'),
- _('Upload an avatar')),
- 'passwordsettings' =>
- array(_('Password'),
- _('Change your password')),
- 'emailsettings' =>
- array(_('Email'),
- _('Change email handling')),
- 'openidsettings' =>
- array(_('OpenID'),
- _('Add or remove OpenIDs')),
- 'userdesignsettings' =>
- array(_('Design'),
- _('Design your profile')),
- 'othersettings' =>
- array(_('Other'),
- _('Other options')));
-
$action_name = $this->action->trimmed('action');
$this->action->elementStart('ul', array('class' => 'nav'));
- foreach ($menu as $menuaction => $menudesc) {
- if ($menuaction == 'openidsettings' &&
- !common_config('openid', 'enabled')) {
- continue;
+ if (Event::handle('StartAccountSettingsNav', array(&$this->action))) {
+
+ $menu =
+ array('profilesettings' =>
+ array(_('Profile'),
+ _('Change your profile settings')),
+ 'avatarsettings' =>
+ array(_('Avatar'),
+ _('Upload an avatar')),
+ 'passwordsettings' =>
+ array(_('Password'),
+ _('Change your password')),
+ 'emailsettings' =>
+ array(_('Email'),
+ _('Change email handling')),
+ 'openidsettings' =>
+ array(_('OpenID'),
+ _('Add or remove OpenIDs')),
+ 'userdesignsettings' =>
+ array(_('Design'),
+ _('Design your profile')),
+ 'othersettings' =>
+ array(_('Other'),
+ _('Other options')));
+
+ foreach ($menu as $menuaction => $menudesc) {
+ $this->action->menuItem(common_local_url($menuaction),
+ $menudesc[0],
+ $menudesc[1],
+ $action_name === $menuaction);
}
- $this->action->menuItem(common_local_url($menuaction),
- $menudesc[0],
- $menudesc[1],
- $action_name === $menuaction);
+
+ Event::handle('EndAccountSettingsNav', array(&$this->action));
}
$this->action->elementEnd('ul');
diff --git a/lib/action.php b/lib/action.php
index 1bdc4daea..4d724fba5 100644
--- a/lib/action.php
+++ b/lib/action.php
@@ -120,14 +120,17 @@ class Action extends HTMLOutputter // lawsuit
{
// XXX: attributes (profile?)
$this->elementStart('head');
- $this->showTitle();
- $this->showShortcutIcon();
- $this->showStylesheets();
- $this->showScripts();
- $this->showOpenSearch();
- $this->showFeeds();
- $this->showDescription();
- $this->extraHead();
+ if (Event::handle('StartHeadChildren', array($this))) {
+ $this->showTitle();
+ $this->showShortcutIcon();
+ $this->showStylesheets();
+ $this->showScripts();
+ $this->showOpenSearch();
+ $this->showFeeds();
+ $this->showDescription();
+ $this->extraHead();
+ Event::handle('EndHeadChildren', array($this));
+ }
$this->elementEnd('head');
}
diff --git a/lib/command.php b/lib/command.php
index 4e2280bc8..371386dc5 100644
--- a/lib/command.php
+++ b/lib/command.php
@@ -211,16 +211,20 @@ class MessageCommand extends Command
function execute($channel)
{
$other = User::staticGet('nickname', common_canonical_nickname($this->other));
+
$len = mb_strlen($this->text);
+
if ($len == 0) {
$channel->error($this->user, _('No content!'));
return;
- } else if ($len > 140) {
- $content = common_shorten_links($content);
- if (mb_strlen($content) > 140) {
- $channel->error($this->user, sprintf(_('Message too long - maximum is 140 characters, you sent %d'), $len));
- return;
- }
+ }
+
+ $this->text = common_shorten_links($this->text);
+
+ if (Message::contentTooLong($this->text)) {
+ $channel->error($this->user, sprintf(_('Message too long - maximum is %d characters, you sent %d'),
+ Message::maxContent(), mb_strlen($this->text)));
+ return;
}
if (!$other) {
diff --git a/lib/common.php b/lib/common.php
index 6c4b856e0..84ee5be15 100644
--- a/lib/common.php
+++ b/lib/common.php
@@ -19,7 +19,7 @@
if (!defined('LACONICA')) { exit(1); }
-define('LACONICA_VERSION', '0.8.1dev');
+define('LACONICA_VERSION', '0.9.0dev');
define('AVATAR_PROFILE_SIZE', 96);
define('AVATAR_STREAM_SIZE', 48);
@@ -114,7 +114,9 @@ $config =
'ssl' => 'never',
'sslserver' => null,
'shorturllength' => 30,
- 'dupelimit' => 60), # default for same person saying the same thing
+ 'dupelimit' => 60, # default for same person saying the same thing
+ 'textlimit' => 140,
+ ),
'syslog' =>
array('appname' => 'laconica', # for syslog
'priority' => 'debug', # XXX: currently ignored
@@ -138,7 +140,8 @@ $config =
array('blacklist' => array(),
'featured' => array()),
'profile' =>
- array('banned' => array()),
+ array('banned' => array(),
+ 'biolimit' => null),
'avatar' =>
array('server' => null,
'dir' => INSTALLDIR . '/avatar/',
@@ -258,7 +261,8 @@ $config =
'filecommand' => '/usr/bin/file',
),
'group' =>
- array('maxaliases' => 3),
+ array('maxaliases' => 3,
+ 'desclimit' => null),
'oohembed' => array('endpoint' => 'http://oohembed.com/oohembed/'),
'search' =>
array('type' => 'fulltext'),
@@ -273,6 +277,10 @@ $config =
'linkcolor' => null,
'backgroundimage' => null,
'disposition' => null),
+ 'notice' =>
+ array('contentlimit' => null),
+ 'message' =>
+ array('contentlimit' => null),
);
$config['db'] = &PEAR::getStaticProperty('DB_DataObject','options');
@@ -399,17 +407,19 @@ require_once INSTALLDIR.'/lib/serverexception.php';
define('NICKNAME_FMT', VALIDATE_NUM.VALIDATE_ALPHA_LOWER);
-function __autoload($class)
+function __autoload($cls)
{
- if ($class == 'OAuthRequest') {
+ if (file_exists(INSTALLDIR.'/classes/' . $cls . '.php')) {
+ require_once(INSTALLDIR.'/classes/' . $cls . '.php');
+ } else if (file_exists(INSTALLDIR.'/lib/' . strtolower($cls) . '.php')) {
+ require_once(INSTALLDIR.'/lib/' . strtolower($cls) . '.php');
+ } else if (mb_substr($cls, -6) == 'Action' &&
+ file_exists(INSTALLDIR.'/actions/' . strtolower(mb_substr($cls, 0, -6)) . '.php')) {
+ require_once(INSTALLDIR.'/actions/' . strtolower(mb_substr($cls, 0, -6)) . '.php');
+ } else if ($cls == 'OAuthRequest') {
require_once('OAuth.php');
- } else if (file_exists(INSTALLDIR.'/classes/' . $class . '.php')) {
- require_once(INSTALLDIR.'/classes/' . $class . '.php');
- } else if (file_exists(INSTALLDIR.'/lib/' . strtolower($class) . '.php')) {
- require_once(INSTALLDIR.'/lib/' . strtolower($class) . '.php');
- } else if (mb_substr($class, -6) == 'Action' &&
- file_exists(INSTALLDIR.'/actions/' . strtolower(mb_substr($class, 0, -6)) . '.php')) {
- require_once(INSTALLDIR.'/actions/' . strtolower(mb_substr($class, 0, -6)) . '.php');
+ } else {
+ Event::handle('Autoload', array(&$cls));
}
}
diff --git a/lib/facebookaction.php b/lib/facebookaction.php
index 289e702c6..4edd3a077 100644
--- a/lib/facebookaction.php
+++ b/lib/facebookaction.php
@@ -35,7 +35,6 @@ if (!defined('LACONICA'))
require_once INSTALLDIR.'/lib/facebookutil.php';
require_once INSTALLDIR.'/lib/noticeform.php';
-
class FacebookAction extends Action
{
@@ -180,7 +179,6 @@ class FacebookAction extends Action
}
-
// Make this into a widget later
function showLocalNav()
{
@@ -240,7 +238,6 @@ class FacebookAction extends Action
$this->endHTML();
}
-
function showInstructions()
{
@@ -271,7 +268,6 @@ class FacebookAction extends Action
$this->elementEnd('div');
}
-
function showLoginForm($msg = null)
{
@@ -316,7 +312,6 @@ class FacebookAction extends Action
}
-
function updateProfileBox($notice)
{
@@ -398,7 +393,6 @@ class FacebookAction extends Action
$this->xw->openURI('php://output');
}
-
/**
* Generate pagination links
*
@@ -457,8 +451,9 @@ class FacebookAction extends Action
} else {
$content_shortened = common_shorten_links($content);
- if (mb_strlen($content_shortened) > 140) {
- $this->showPage(_('That\'s too long. Max notice size is 140 chars.'));
+ if (Notice::contentTooLong($content_shortened)) {
+ $this->showPage(sprintf(_('That\'s too long. Max notice size is %d chars.'),
+ Notice::maxContent()));
return;
}
}
diff --git a/lib/groupeditform.php b/lib/groupeditform.php
index fbb39129b..47e62d469 100644
--- a/lib/groupeditform.php
+++ b/lib/groupeditform.php
@@ -150,27 +150,33 @@ class GroupEditForm extends Form
$this->out->elementStart('li');
$this->out->hidden('groupid', $id);
$this->out->input('nickname', _('Nickname'),
- ($this->out->arg('nickname')) ? $this->out->arg('nickname') : $nickname,
- _('1-64 lowercase letters or numbers, no punctuation or spaces'));
+ ($this->out->arg('nickname')) ? $this->out->arg('nickname') : $nickname,
+ _('1-64 lowercase letters or numbers, no punctuation or spaces'));
$this->out->elementEnd('li');
$this->out->elementStart('li');
$this->out->input('fullname', _('Full name'),
- ($this->out->arg('fullname')) ? $this->out->arg('fullname') : $fullname);
+ ($this->out->arg('fullname')) ? $this->out->arg('fullname') : $fullname);
$this->out->elementEnd('li');
$this->out->elementStart('li');
$this->out->input('homepage', _('Homepage'),
- ($this->out->arg('homepage')) ? $this->out->arg('homepage') : $homepage,
- _('URL of the homepage or blog of the group or topic'));
+ ($this->out->arg('homepage')) ? $this->out->arg('homepage') : $homepage,
+ _('URL of the homepage or blog of the group or topic'));
$this->out->elementEnd('li');
$this->out->elementStart('li');
+ $desclimit = User_group::maxDescription();
+ if ($desclimit == 0) {
+ $descinstr = _('Describe the group or topic');
+ } else {
+ $descinstr = sprintf(_('Describe the group or topic in %d characters'), $desclimit);
+ }
$this->out->textarea('description', _('Description'),
- ($this->out->arg('description')) ? $this->out->arg('description') : $description,
- _('Describe the group or topic in 140 chars'));
+ ($this->out->arg('description')) ? $this->out->arg('description') : $description,
+ $descinstr);
$this->out->elementEnd('li');
$this->out->elementStart('li');
$this->out->input('location', _('Location'),
- ($this->out->arg('location')) ? $this->out->arg('location') : $location,
- _('Location for the group, if any, like "City, State (or Region), Country"'));
+ ($this->out->arg('location')) ? $this->out->arg('location') : $location,
+ _('Location for the group, if any, like "City, State (or Region), Country"'));
$this->out->elementEnd('li');
if (common_config('group', 'maxaliases') > 0) {
$aliases = (empty($this->group)) ? array() : $this->group->getAliases();
diff --git a/lib/logingroupnav.php b/lib/logingroupnav.php
index 2fb1828d6..bae45b077 100644
--- a/lib/logingroupnav.php
+++ b/lib/logingroupnav.php
@@ -69,30 +69,30 @@ class LoginGroupNav extends Widget
function show()
{
- // action => array('prompt', 'title')
- $menu = array();
+ $action_name = $this->action->trimmed('action');
+
+ $this->action->elementStart('ul', array('class' => 'nav'));
+
+ if (Event::handle('StartLoginGroupNav', array(&$this->action))) {
+
+ $this->action->menuItem(common_local_url('login'),
+ _('Login'),
+ _('Login with a username and password'),
+ $action_name === 'login');
- if (!common_config('site','openidonly')) {
- $menu['login'] = array(_('Login'),
- _('Login with a username and password'));
if (!(common_config('site','closed') || common_config('site','inviteonly'))) {
- $menu['register'] = array(_('Register'),
- _('Sign up for a new account'));
+ $this->action->menuItem(common_local_url('register'),
+ _('Register'),
+ _('Sign up for a new account'),
+ $action_name === 'register');
}
- }
- if (common_config('openid', 'enabled')) {
- $menu['openidlogin'] = array(_('OpenID'),
- _('Login or register with OpenID'));
- }
- $action_name = $this->action->trimmed('action');
- $this->action->elementStart('ul', array('class' => 'nav'));
+ $this->action->menuItem(common_local_url('openidlogin'),
+ _('OpenID'),
+ _('Login or register with OpenID'),
+ $action_name === 'openidlogin');
- foreach ($menu as $menuaction => $menudesc) {
- $this->action->menuItem(common_local_url($menuaction),
- $menudesc[0],
- $menudesc[1],
- $action_name === $menuaction);
+ Event::handle('EndLoginGroupNav', array(&$this->action));
}
$this->action->elementEnd('ul');
diff --git a/lib/messageform.php b/lib/messageform.php
index 8ea2b36c2..044fdc719 100644
--- a/lib/messageform.php
+++ b/lib/messageform.php
@@ -140,12 +140,19 @@ class MessageForm extends Form
'rows' => 4,
'name' => 'content'),
($this->content) ? $this->content : '');
- $this->out->elementStart('dl', 'form_note');
- $this->out->element('dt', null, _('Available characters'));
- $this->out->element('dd', array('id' => 'notice_text-count'),
- '140');
- $this->out->elementEnd('dl');
+ $contentLimit = Message::maxContent();
+
+ $this->out->element('script', array('type' => 'text/javascript'),
+ 'maxLength = ' . $contentLimit . ';');
+
+ if ($contentLimit > 0) {
+ $this->out->elementStart('dl', 'form_note');
+ $this->out->element('dt', null, _('Available characters'));
+ $this->out->element('dd', array('id' => 'notice_text-count'),
+ $contentLimit);
+ $this->out->elementEnd('dl');
+ }
}
/**
diff --git a/lib/noticeform.php b/lib/noticeform.php
index 4e2a2edd6..35a21c6bd 100644
--- a/lib/noticeform.php
+++ b/lib/noticeform.php
@@ -83,7 +83,7 @@ class NoticeForm extends Form
$this->action = $action;
$this->content = $content;
-
+
if ($user) {
$this->user = $user;
} else {
@@ -117,7 +117,6 @@ class NoticeForm extends Form
return common_local_url('newnotice');
}
-
/**
* Legend of the Form
*
@@ -128,7 +127,6 @@ class NoticeForm extends Form
$this->out->element('legend', null, _('Send a notice'));
}
-
/**
* Data elements
*
@@ -145,11 +143,20 @@ class NoticeForm extends Form
'rows' => 4,
'name' => 'status_textarea'),
($this->content) ? $this->content : '');
- $this->out->elementStart('dl', 'form_note');
- $this->out->element('dt', null, _('Available characters'));
- $this->out->element('dd', array('id' => 'notice_text-count'),
- '140');
- $this->out->elementEnd('dl');
+
+ $contentLimit = Notice::maxContent();
+
+ $this->out->element('script', array('type' => 'text/javascript'),
+ 'maxLength = ' . $contentLimit . ';');
+
+ if ($contentLimit > 0) {
+ $this->out->elementStart('dl', 'form_note');
+ $this->out->element('dt', null, _('Available characters'));
+ $this->out->element('dd', array('id' => 'notice_text-count'),
+ $contentLimit);
+ $this->out->elementEnd('dl');
+ }
+
if (common_config('attachments', 'uploads')) {
$this->out->element('label', array('for' => 'notice_data-attach'),_('Attach'));
$this->out->element('input', array('id' => 'notice_data-attach',
diff --git a/lib/oauthstore.php b/lib/oauthstore.php
index f224c6c22..87d8cf213 100644
--- a/lib/oauthstore.php
+++ b/lib/oauthstore.php
@@ -17,15 +17,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('LACONICA')) {
+ exit(1);
+}
-require_once(INSTALLDIR.'/lib/omb.php');
+require_once 'libomb/datastore.php';
-class LaconicaOAuthDataStore extends OAuthDataStore
+class LaconicaDataStore extends OMB_Datastore
{
// We keep a record of who's contacted us
-
function lookup_consumer($consumer_key)
{
$con = Consumer::staticGet('consumer_key', $consumer_key);
@@ -44,7 +45,9 @@ class LaconicaOAuthDataStore extends OAuthDataStore
function lookup_token($consumer, $token_type, $token_key)
{
$t = new Token();
- $t->consumer_key = $consumer->key;
+ if (!is_null($consumer)) {
+ $t->consumer_key = $consumer->key;
+ }
$t->tok = $token_key;
$t->type = ($token_type == 'access') ? 1 : 0;
if ($t->find(true)) {
@@ -154,4 +157,348 @@ class LaconicaOAuthDataStore extends OAuthDataStore
{
return $this->new_access_token($consumer);
}
+
+
+ /**
+ * Revoke specified OAuth token
+ *
+ * Revokes the authorization token specified by $token_key.
+ * Throws exceptions in case of error.
+ *
+ * @param string $token_key The token to be revoked
+ *
+ * @access public
+ **/
+ public function revoke_token($token_key) {
+ $rt = new Token();
+ $rt->tok = $token_key;
+ $rt->type = 0;
+ $rt->state = 0;
+ if (!$rt->find(true)) {
+ throw new Exception('Tried to revoke unknown token');
+ }
+ if (!$rt->delete()) {
+ throw new Exception('Failed to delete revoked token');
+ }
+ }
+
+ /**
+ * Authorize specified OAuth token
+ *
+ * Authorizes the authorization token specified by $token_key.
+ * Throws exceptions in case of error.
+ *
+ * @param string $token_key The token to be authorized
+ *
+ * @access public
+ **/
+ public function authorize_token($token_key) {
+ $rt = new Token();
+ $rt->tok = $token_key;
+ $rt->type = 0;
+ $rt->state = 0;
+ if (!$rt->find(true)) {
+ throw new Exception('Tried to authorize unknown token');
+ }
+ $orig_rt = clone($rt);
+ $rt->state = 1; # Authorized but not used
+ if (!$rt->update($orig_rt)) {
+ throw new Exception('Failed to authorize token');
+ }
+ }
+
+ /**
+ * Get profile by identifying URI
+ *
+ * Returns an OMB_Profile object representing the OMB profile identified by
+ * $identifier_uri.
+ * Returns null if there is no such OMB profile.
+ * Throws exceptions in case of other error.
+ *
+ * @param string $identifier_uri The OMB identifier URI specifying the
+ * requested profile
+ *
+ * @access public
+ *
+ * @return OMB_Profile The corresponding profile
+ **/
+ public function getProfile($identifier_uri) {
+ /* getProfile is only used for remote profiles by libomb.
+ TODO: Make it work with local ones anyway. */
+ $remote = Remote_profile::staticGet('uri', $identifier_uri);
+ if (!$remote) throw new Exception('No such remote profile');
+ $profile = Profile::staticGet('id', $remote->id);
+ if (!$profile) throw new Exception('No profile for remote user');
+
+ require_once INSTALLDIR.'/lib/omb.php';
+ return profile_to_omb_profile($identifier_uri, $profile);
+ }
+
+ /**
+ * Save passed profile
+ *
+ * Stores the OMB profile $profile. Overwrites an existing entry.
+ * Throws exceptions in case of error.
+ *
+ * @param OMB_Profile $profile The OMB profile which should be saved
+ *
+ * @access public
+ **/
+ public function saveProfile($omb_profile) {
+ if (common_profile_url($omb_profile->getNickname()) ==
+ $omb_profile->getProfileURL()) {
+ throw new Exception('Not implemented');
+ } else {
+ $remote = Remote_profile::staticGet('uri', $omb_profile->getIdentifierURI());
+
+ if ($remote) {
+ $exists = true;
+ $profile = Profile::staticGet($remote->id);
+ $orig_remote = clone($remote);
+ $orig_profile = clone($profile);
+ # XXX: compare current postNotice and updateProfile URLs to the ones
+ # stored in the DB to avoid (possibly...) above attack
+ } else {
+ $exists = false;
+ $remote = new Remote_profile();
+ $remote->uri = $omb_profile->getIdentifierURI();
+ $profile = new Profile();
+ }
+
+ $profile->nickname = $omb_profile->getNickname();
+ $profile->profileurl = $omb_profile->getProfileURL();
+
+ $fullname = $omb_profile->getFullname();
+ $profile->fullname = is_null($fullname) ? '' : $fullname;
+ $homepage = $omb_profile->getHomepage();
+ $profile->homepage = is_null($homepage) ? '' : $homepage;
+ $bio = $omb_profile->getBio();
+ $profile->bio = is_null($bio) ? '' : $bio;
+ $location = $omb_profile->getLocation();
+ $profile->location = is_null($location) ? '' : $location;
+
+ if ($exists) {
+ $profile->update($orig_profile);
+ } else {
+ $profile->created = DB_DataObject_Cast::dateTime(); # current time
+ $id = $profile->insert();
+ if (!$id) {
+ throw new Exception(_('Error inserting new profile'));
+ }
+ $remote->id = $id;
+ }
+
+ $avatar_url = $omb_profile->getAvatarURL();
+ if ($avatar_url) {
+ if (!$this->add_avatar($profile, $avatar_url)) {
+ throw new Exception(_('Error inserting avatar'));
+ }
+ } else {
+ $avatar = $profile->getOriginalAvatar();
+ if($avatar) $avatar->delete();
+ $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
+ if($avatar) $avatar->delete();
+ $avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
+ if($avatar) $avatar->delete();
+ $avatar = $profile->getAvatar(AVATAR_MINI_SIZE);
+ if($avatar) $avatar->delete();
+ }
+
+ if ($exists) {
+ if (!$remote->update($orig_remote)) {
+ throw new Exception(_('Error updating remote profile'));
+ }
+ } else {
+ $remote->created = DB_DataObject_Cast::dateTime(); # current time
+ if (!$remote->insert()) {
+ throw new Exception(_('Error inserting remote profile'));
+ }
+ }
+ }
+ }
+
+ function add_avatar($profile, $url)
+ {
+ $temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar');
+ copy($url, $temp_filename);
+ $imagefile = new ImageFile($profile->id, $temp_filename);
+ $filename = Avatar::filename($profile->id,
+ image_type_to_extension($imagefile->type),
+ null,
+ common_timestamp());
+ rename($temp_filename, Avatar::path($filename));
+ return $profile->setOriginal($filename);
+ }
+
+ /**
+ * Save passed notice
+ *
+ * Stores the OMB notice $notice. The datastore may change the passed notice.
+ * This might by neccessary for URIs depending on a database key. Note that
+ * it is the user’s duty to present a mechanism for his OMB_Datastore to
+ * appropriately change his OMB_Notice.
+ * Throws exceptions in case of error.
+ *
+ * @param OMB_Notice $notice The OMB notice which should be saved
+ *
+ * @access public
+ **/
+ public function saveNotice(&$omb_notice) {
+ if (Notice::staticGet('uri', $omb_notice->getIdentifierURI())) {
+ throw new Exception(_('Duplicate notice'));
+ }
+ $author_uri = $omb_notice->getAuthor()->getIdentifierURI();
+ common_log(LOG_DEBUG, $author_uri, __FILE__);
+ $author = Remote_profile::staticGet('uri', $author_uri);
+ if (!$author) {
+ $author = User::staticGet('uri', $author_uri);
+ }
+ if (!$author) {
+ throw new Exception('No such user');
+ }
+
+ common_log(LOG_DEBUG, print_r($author, true), __FILE__);
+
+ $notice = Notice::saveNew($author->id,
+ $omb_notice->getContent(),
+ 'omb',
+ false,
+ null,
+ $omb_notice->getIdentifierURI());
+ if (is_string($notice)) {
+ throw new Exception($notice);
+ }
+ common_broadcast_notice($notice, true);
+ }
+
+ /**
+ * Get subscriptions of a given profile
+ *
+ * Returns an array containing subscription informations for the specified
+ * profile. Every array entry should in turn be an array with keys
+ * 'uri´: The identifier URI of the subscriber
+ * 'token´: The subscribe token
+ * 'secret´: The secret token
+ * Throws exceptions in case of error.
+ *
+ * @param string $subscribed_user_uri The OMB identifier URI specifying the
+ * subscribed profile
+ *
+ * @access public
+ *
+ * @return mixed An array containing the subscriptions or 0 if no
+ * subscription has been found.
+ **/
+ public function getSubscriptions($subscribed_user_uri) {
+ $sub = new Subscription();
+
+ $user = $this->_getAnyProfile($subscribed_user_uri);
+
+ $sub->subscribed = $user->id;
+
+ if (!$sub->find(true)) {
+ return 0;
+ }
+
+ /* Since we do not use OMB_Service_Provider’s action methods, there
+ is no need to actually return the subscriptions. */
+ return 1;
+ }
+
+ private function _getAnyProfile($uri)
+ {
+ $user = Remote_profile::staticGet('uri', $uri);
+ if (!$user) {
+ $user = User::staticGet('uri', $uri);
+ }
+ if (!$user) {
+ throw new Exception('No such user');
+ }
+ return $user;
+ }
+
+ /**
+ * Delete a subscription
+ *
+ * Deletes the subscription from $subscriber_uri to $subscribed_user_uri.
+ * Throws exceptions in case of error.
+ *
+ * @param string $subscriber_uri The OMB identifier URI specifying the
+ * subscribing profile
+ *
+ * @param string $subscribed_user_uri The OMB identifier URI specifying the
+ * subscribed profile
+ *
+ * @access public
+ **/
+ public function deleteSubscription($subscriber_uri, $subscribed_user_uri)
+ {
+ $sub = new Subscription();
+
+ $subscribed = $this->_getAnyProfile($subscribed_user_uri);
+ $subscriber = $this->_getAnyProfile($subscriber_uri);
+
+ $sub->subscribed = $subscribed->id;
+ $sub->subscriber = $subscriber->id;
+
+ $sub->delete();
+ }
+
+ /**
+ * Save a subscription
+ *
+ * Saves the subscription from $subscriber_uri to $subscribed_user_uri.
+ * Throws exceptions in case of error.
+ *
+ * @param string $subscriber_uri The OMB identifier URI specifying
+ * the subscribing profile
+ *
+ * @param string $subscribed_user_uri The OMB identifier URI specifying
+ * the subscribed profile
+ * @param OAuthToken $token The access token
+ *
+ * @access public
+ **/
+ public function saveSubscription($subscriber_uri, $subscribed_user_uri,
+ $token)
+ {
+ $sub = new Subscription();
+
+ $subscribed = $this->_getAnyProfile($subscribed_user_uri);
+ $subscriber = $this->_getAnyProfile($subscriber_uri);
+
+ $sub->subscribed = $subscribed->id;
+ $sub->subscriber = $subscriber->id;
+
+ $sub_exists = $sub->find(true);
+
+ if ($sub_exists) {
+ $orig_sub = clone($sub);
+ } else {
+ $sub->created = DB_DataObject_Cast::dateTime();
+ }
+
+ $sub->token = $token->key;
+ $sub->secret = $token->secret;
+
+ if ($sub_exists) {
+ $result = $sub->update($orig_sub);
+ } else {
+ $result = $sub->insert();
+ }
+
+ if (!$result) {
+ common_log_db_error($sub, ($sub_exists) ? 'UPDATE' : 'INSERT', __FILE__);
+ throw new Exception(_('Couldn\'t insert new subscription.'));
+ return;
+ }
+
+ /* Notify user, if necessary. */
+
+ if ($subscribed instanceof User) {
+ mail_subscribe_notify_profile($subscribed,
+ Profile::staticGet($subscriber->id));
+ }
+ }
}
+?>
diff --git a/lib/omb.php b/lib/omb.php
index 4f6a96095..b9d0eef64 100644
--- a/lib/omb.php
+++ b/lib/omb.php
@@ -17,36 +17,22 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
-
-require_once('OAuth.php');
-require_once(INSTALLDIR.'/lib/oauthstore.php');
-
-require_once(INSTALLDIR.'/classes/Consumer.php');
-require_once(INSTALLDIR.'/classes/Nonce.php');
-require_once(INSTALLDIR.'/classes/Token.php');
-
-require_once('Auth/Yadis/Yadis.php');
-
-define('OAUTH_NAMESPACE', 'http://oauth.net/core/1.0/');
-define('OMB_NAMESPACE', 'http://openmicroblogging.org/protocol/0.1');
-define('OMB_VERSION_01', 'http://openmicroblogging.org/protocol/0.1');
-define('OAUTH_DISCOVERY', 'http://oauth.net/discovery/1.0');
+if (!defined('LACONICA')) {
+ exit(1);
+}
-define('OMB_ENDPOINT_UPDATEPROFILE', OMB_NAMESPACE.'/updateProfile');
-define('OMB_ENDPOINT_POSTNOTICE', OMB_NAMESPACE.'/postNotice');
-define('OAUTH_ENDPOINT_REQUEST', OAUTH_NAMESPACE.'endpoint/request');
-define('OAUTH_ENDPOINT_AUTHORIZE', OAUTH_NAMESPACE.'endpoint/authorize');
-define('OAUTH_ENDPOINT_ACCESS', OAUTH_NAMESPACE.'endpoint/access');
-define('OAUTH_ENDPOINT_RESOURCE', OAUTH_NAMESPACE.'endpoint/resource');
-define('OAUTH_AUTH_HEADER', OAUTH_NAMESPACE.'parameters/auth-header');
-define('OAUTH_POST_BODY', OAUTH_NAMESPACE.'parameters/post-body');
-define('OAUTH_HMAC_SHA1', OAUTH_NAMESPACE.'signature/HMAC-SHA1');
+require_once INSTALLDIR.'/lib/oauthstore.php';
+require_once 'OAuth.php';
+require_once 'libomb/constants.php';
+require_once 'libomb/service_consumer.php';
+require_once 'libomb/notice.php';
+require_once 'libomb/profile.php';
+require_once 'Auth/Yadis/Yadis.php';
function omb_oauth_consumer()
{
static $con = null;
- if (!$con) {
+ if (is_null($con)) {
$con = new OAuthConsumer(common_root_url(), '');
}
return $con;
@@ -55,7 +41,7 @@ function omb_oauth_consumer()
function omb_oauth_server()
{
static $server = null;
- if (!$server) {
+ if (is_null($server)) {
$server = new OAuthServer(omb_oauth_datastore());
$server->add_signature_method(omb_hmac_sha1());
}
@@ -65,8 +51,8 @@ function omb_oauth_server()
function omb_oauth_datastore()
{
static $store = null;
- if (!$store) {
- $store = new LaconicaOAuthDataStore();
+ if (is_null($store)) {
+ $store = new LaconicaDataStore();
}
return $store;
}
@@ -74,57 +60,18 @@ function omb_oauth_datastore()
function omb_hmac_sha1()
{
static $hmac_method = null;
- if (!$hmac_method) {
+ if (is_null($hmac_method)) {
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
}
return $hmac_method;
}
-function omb_get_services($xrd, $type)
+function omb_broadcast_notice($notice)
{
- return $xrd->services(array(omb_service_filter($type)));
-}
-function omb_service_filter($type)
-{
- return create_function('$s',
- 'return omb_match_service($s, \''.$type.'\');');
-}
+ $omb_notice = notice_to_omb_notice($notice);
-function omb_match_service($service, $type)
-{
- return in_array($type, $service->getTypes());
-}
-
-function omb_service_uri($service)
-{
- if (!$service) {
- return null;
- }
- $uris = $service->getURIs();
- if (!$uris) {
- return null;
- }
- return $uris[0];
-}
-
-function omb_local_id($service)
-{
- if (!$service) {
- return null;
- }
- $els = $service->getElements('xrd:LocalID');
- if (!$els) {
- return null;
- }
- $el = $els[0];
- return $service->parser->content($el);
-}
-
-function omb_broadcast_remote_subscribers($notice)
-{
-
- # First, get remote users subscribed to this profile
+ /* Get remote users subscribed to this profile. */
$rp = new Remote_profile();
$rp->query('SELECT postnoticeurl, token, secret ' .
@@ -135,170 +82,148 @@ function omb_broadcast_remote_subscribers($notice)
$posted = array();
while ($rp->fetch()) {
- if (!$posted[$rp->postnoticeurl]) {
- common_log(LOG_DEBUG, 'Posting to ' . $rp->postnoticeurl);
- if (omb_post_notice_keys($notice, $rp->postnoticeurl, $rp->token, $rp->secret)) {
- common_log(LOG_DEBUG, 'Finished to ' . $rp->postnoticeurl);
- $posted[$rp->postnoticeurl] = true;
- } else {
- common_log(LOG_DEBUG, 'Failed posting to ' . $rp->postnoticeurl);
- }
+ if (isset($posted[$rp->postnoticeurl])) {
+ /* We already posted to this url. */
+ continue;
}
- }
-
- $rp->free();
- unset($rp);
+ common_debug('Posting to ' . $rp->postnoticeurl, __FILE__);
+
+ /* Post notice. */
+ $service = new Laconica_OMB_Service_Consumer(
+ array(OMB_ENDPOINT_POSTNOTICE => $rp->postnoticeurl));
+ try {
+ $service->setToken($rp->token, $rp->secret);
+ $service->postNotice($omb_notice);
+ } catch (Exception $e) {
+ common_log(LOG_ERR, 'Failed posting to ' . $rp->postnoticeurl);
+ common_log(LOG_ERR, 'Error status '.$e);
+ continue;
+ }
+ $posted[$rp->postnoticeurl] = true;
- return true;
-}
+ common_debug('Finished to ' . $rp->postnoticeurl, __FILE__);
+ }
-function omb_post_notice($notice, $remote_profile, $subscription)
-{
- return omb_post_notice_keys($notice, $remote_profile->postnoticeurl, $subscription->token, $subscription->secret);
+ return;
}
-function omb_post_notice_keys($notice, $postnoticeurl, $tk, $secret)
+function omb_broadcast_profile($profile)
{
- $user = User::staticGet('id', $notice->profile_id);
+ $user = User::staticGet('id', $profile->id);
if (!$user) {
return false;
}
- $con = omb_oauth_consumer();
-
- $token = new OAuthToken($tk, $secret);
-
- $url = $postnoticeurl;
- $parsed = parse_url($url);
- $params = array();
- parse_str($parsed['query'], $params);
+ $profile = $user->getProfile();
- $req = OAuthRequest::from_consumer_and_token($con, $token,
- 'POST', $url, $params);
+ $omb_profile = profile_to_omb_profile($user->uri, $profile, true);
- $req->set_parameter('omb_version', OMB_VERSION_01);
- $req->set_parameter('omb_listenee', $user->uri);
- $req->set_parameter('omb_notice', $notice->uri);
- $req->set_parameter('omb_notice_content', $notice->content);
- $req->set_parameter('omb_notice_url', common_local_url('shownotice',
- array('notice' =>
- $notice->id)));
- $req->set_parameter('omb_notice_license', common_config('license', 'url'));
-
- $user->free();
- unset($user);
+ /* Get remote users subscribed to this profile. */
+ $rp = new Remote_profile();
- $req->sign_request(omb_hmac_sha1(), $con, $token);
+ $rp->query('SELECT updateprofileurl, token, secret ' .
+ 'FROM subscription JOIN remote_profile ' .
+ 'ON subscription.subscriber = remote_profile.id ' .
+ 'WHERE subscription.subscribed = ' . $profile->id . ' ');
- # We re-use this tool's fetcher, since it's pretty good
+ $posted = array();
- $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
+ while ($rp->fetch()) {
+ if (isset($posted[$rp->updateprofileurl])) {
+ /* We already posted to this url. */
+ continue;
+ }
+ common_debug('Posting to ' . $rp->updateprofileurl, __FILE__);
+
+ /* Update profile. */
+ $service = new Laconica_OMB_Service_Consumer(
+ array(OMB_ENDPOINT_UPDATEPROFILE => $rp->updateprofileurl));
+ try {
+ $service->setToken($rp->token, $rp->secret);
+ $service->updateProfile($omb_profile);
+ } catch (Exception $e) {
+ common_log(LOG_ERR, 'Failed posting to ' . $rp->updateprofileurl);
+ common_log(LOG_ERR, 'Error status '.$e);
+ continue;
+ }
+ $posted[$rp->updateprofileurl] = true;
- if (!$fetcher) {
- common_log(LOG_WARNING, 'Failed to initialize Yadis fetcher.', __FILE__);
- return false;
+ common_debug('Finished to ' . $rp->updateprofileurl, __FILE__);
}
- $result = $fetcher->post($req->get_normalized_http_url(),
- $req->to_postdata(),
- array('User-Agent: Laconica/' . LACONICA_VERSION));
-
- if ($result->status == 403) { # not authorized, don't send again
- common_debug('403 result, deleting subscription', __FILE__);
- # FIXME: figure out how to delete this
- # $subscription->delete();
- return false;
- } else if ($result->status != 200) {
- common_debug('Error status '.$result->status, __FILE__);
- return false;
- } else { # success!
- parse_str($result->body, $return);
- if ($return['omb_version'] == OMB_VERSION_01) {
- return true;
- } else {
- return false;
- }
- }
+ return;
}
-function omb_broadcast_profile($profile)
-{
- # First, get remote users subscribed to this profile
- # XXX: use a join here rather than looping through results
- $sub = new Subscription();
- $sub->subscribed = $profile->id;
- if ($sub->find()) {
- $updated = array();
- while ($sub->fetch()) {
- $rp = Remote_profile::staticGet('id', $sub->subscriber);
- if ($rp) {
- if (!array_key_exists($rp->updateprofileurl, $updated)) {
- if (omb_update_profile($profile, $rp, $sub)) {
- $updated[$rp->updateprofileurl] = true;
- }
- }
- }
- }
+class Laconica_OMB_Service_Consumer extends OMB_Service_Consumer {
+ public function __construct($urls)
+ {
+ $this->services = $urls;
+ $this->datastore = omb_oauth_datastore();
+ $this->oauth_consumer = omb_oauth_consumer();
+ $this->fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
}
+
}
-function omb_update_profile($profile, $remote_profile, $subscription)
+function profile_to_omb_profile($uri, $profile, $force = false)
{
- $user = User::staticGet($profile->id);
- $con = omb_oauth_consumer();
- $token = new OAuthToken($subscription->token, $subscription->secret);
- $url = $remote_profile->updateprofileurl;
- $parsed = parse_url($url);
- $params = array();
- parse_str($parsed['query'], $params);
- $req = OAuthRequest::from_consumer_and_token($con, $token,
- "POST", $url, $params);
- $req->set_parameter('omb_version', OMB_VERSION_01);
- $req->set_parameter('omb_listenee', $user->uri);
- $req->set_parameter('omb_listenee_profile', common_profile_url($profile->nickname));
- $req->set_parameter('omb_listenee_nickname', $profile->nickname);
-
- # We use blanks to force emptying any existing values in these optional fields
-
- $req->set_parameter('omb_listenee_fullname',
- ($profile->fullname) ? $profile->fullname : '');
- $req->set_parameter('omb_listenee_homepage',
- ($profile->homepage) ? $profile->homepage : '');
- $req->set_parameter('omb_listenee_bio',
- ($profile->bio) ? $profile->bio : '');
- $req->set_parameter('omb_listenee_location',
- ($profile->location) ? $profile->location : '');
+ $omb_profile = new OMB_Profile($uri);
+ $omb_profile->setNickname($profile->nickname);
+ $omb_profile->setLicenseURL(common_config('license', 'url'));
+ if (!is_null($profile->fullname)) {
+ $omb_profile->setFullname($profile->fullname);
+ } elseif ($force) {
+ $omb_profile->setFullname('');
+ }
+ if (!is_null($profile->homepage)) {
+ $omb_profile->setHomepage($profile->homepage);
+ } elseif ($force) {
+ $omb_profile->setHomepage('');
+ }
+ if (!is_null($profile->bio)) {
+ $omb_profile->setBio($profile->bio);
+ } elseif ($force) {
+ $omb_profile->setBio('');
+ }
+ if (!is_null($profile->location)) {
+ $omb_profile->setLocation($profile->location);
+ } elseif ($force) {
+ $omb_profile->setLocation('');
+ }
+ if (!is_null($profile->profileurl)) {
+ $omb_profile->setProfileURL($profile->profileurl);
+ } elseif ($force) {
+ $omb_profile->setProfileURL('');
+ }
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
- $req->set_parameter('omb_listenee_avatar',
- ($avatar) ? $avatar->url : '');
+ if ($avatar) {
+ $omb_profile->setAvatarURL($avatar->url);
+ } elseif ($force) {
+ $omb_profile->setAvatarURL('');
+ }
+ return $omb_profile;
+}
- $req->sign_request(omb_hmac_sha1(), $con, $token);
+function notice_to_omb_notice($notice)
+{
+ /* Create an OMB_Notice for $notice. */
+ $user = User::staticGet('id', $notice->profile_id);
- # We re-use this tool's fetcher, since it's pretty good
+ if (!$user) {
+ return null;
+ }
- $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
+ $profile = $user->getProfile();
- $result = $fetcher->post($req->get_normalized_http_url(),
- $req->to_postdata(),
- array('User-Agent: Laconica/' . LACONICA_VERSION));
+ $omb_notice = new OMB_Notice(profile_to_omb_profile($user->uri, $profile),
+ $notice->uri,
+ $notice->content);
+ $omb_notice->setURL(common_local_url('shownotice', array('notice' =>
+ $notice->id)));
+ $omb_notice->setLicenseURL(common_config('license', 'url'));
- if (empty($result) || !$result) {
- common_debug("Unable to contact " . $req->get_normalized_http_url());
- } else if ($result->status == 403) { # not authorized, don't send again
- common_debug('403 result, deleting subscription', __FILE__);
- $subscription->delete();
- return false;
- } else if ($result->status != 200) {
- common_debug('Error status '.$result->status, __FILE__);
- return false;
- } else { # success!
- parse_str($result->body, $return);
- if (isset($return['omb_version']) && $return['omb_version'] === OMB_VERSION_01) {
- return true;
- } else {
- return false;
- }
- }
+ return $omb_notice;
}
+?>
diff --git a/lib/settingsaction.php b/lib/settingsaction.php
index 17d3a2f64..4cf9b80c4 100644
--- a/lib/settingsaction.php
+++ b/lib/settingsaction.php
@@ -77,10 +77,12 @@ class SettingsAction extends CurrentUserDesignAction
// _all_ our settings are important
common_set_returnto($this->selfUrl());
$user = common_current_user();
- if ($user->hasOpenID()) {
- common_redirect(common_local_url('openidlogin'), 303);
- } else {
- common_redirect(common_local_url('login'), 303);
+ if (Event::handle('RedirectToLogin', array($this, $user))) {
+ if ($user->hasOpenID()) {
+ common_redirect(common_local_url('openidlogin'), 303);
+ } else {
+ common_redirect(common_local_url('login'), 303);
+ }
}
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$this->handlePost();
diff --git a/lib/unqueuemanager.php b/lib/unqueuemanager.php
index a10ca339a..920313c0c 100644
--- a/lib/unqueuemanager.php
+++ b/lib/unqueuemanager.php
@@ -39,7 +39,7 @@ class UnQueueManager
case 'omb':
if ($this->_isLocal($notice)) {
require_once(INSTALLDIR.'/lib/omb.php');
- omb_broadcast_remote_subscribers($notice);
+ omb_broadcast_notice($notice);
}
break;
case 'public':
diff --git a/lib/util.php b/lib/util.php
index 748c8332f..3fa90d31a 100644
--- a/lib/util.php
+++ b/lib/util.php
@@ -540,7 +540,8 @@ function common_linkify($url) {
function common_shorten_links($text)
{
- if (mb_strlen($text) <= 140) return $text;
+ $maxLength = Notice::maxContent();
+ if ($maxLength == 0 || mb_strlen($text) <= $maxLength) return $text;
return common_replace_urls_callback($text, array('File_redirection', 'makeShort'));
}
@@ -685,14 +686,10 @@ function common_relative_profile($sender, $nickname, $dt=null)
function common_local_url($action, $args=null, $params=null, $fragment=null)
{
- static $sensitive = array('login', 'register', 'passwordsettings',
- 'twittersettings', 'finishopenidlogin',
- 'finishaddopenid', 'api');
-
$r = Router::get();
$path = $r->build($action, $args, $params, $fragment);
- $ssl = in_array($action, $sensitive);
+ $ssl = common_is_sensitive($action);
if (common_config('site','fancy')) {
$url = common_path(mb_substr($path, 1), $ssl);
@@ -706,6 +703,20 @@ function common_local_url($action, $args=null, $params=null, $fragment=null)
return $url;
}
+function common_is_sensitive($action)
+{
+ static $sensitive = array('login', 'register', 'passwordsettings',
+ 'twittersettings', 'finishopenidlogin',
+ 'finishaddopenid', 'api');
+ $ssl = null;
+
+ if (Event::handle('SensitiveAction', array($action, &$ssl))) {
+ $ssl = in_array($action, $sensitive);
+ }
+
+ return $ssl;
+}
+
function common_path($relative, $ssl=false)
{
$pathpart = (common_config('site', 'path')) ? common_config('site', 'path')."/" : '';
@@ -1112,7 +1123,8 @@ function common_negotiate_type($cprefs, $sprefs)
function common_config($main, $sub)
{
global $config;
- return isset($config[$main][$sub]) ? $config[$main][$sub] : false;
+ return (array_key_exists($main, $config) &&
+ array_key_exists($sub, $config[$main])) ? $config[$main][$sub] : false;
}
function common_copy_args($from)