Merge branch '0.9.x' into openidplugin
Conflicts: actions/login.php actions/register.php
This commit is contained in:
commit
9f356b55c6
118
README
118
README
|
@ -553,25 +553,53 @@ our kind of hacky home-grown DB-based queue solution. See the "queues"
|
|||
config section below for how to configure to use STOMP. As of this
|
||||
writing, the software has been tested with ActiveMQ (
|
||||
|
||||
Twitter Friends Syncing
|
||||
-----------------------
|
||||
Twitter Bridge
|
||||
--------------
|
||||
|
||||
As of Laconica 0.6.3, users may set a flag in their settings ("Subscribe
|
||||
to my Twitter friends here" under the Twitter tab) to have Laconica
|
||||
attempt to locate and subscribe to "friends" (people they "follow") on
|
||||
Twitter who also have accounts on your Laconica system, and who have
|
||||
previously set up a link for automatically posting notices to Twitter.
|
||||
* OAuth
|
||||
|
||||
Optionally, there is a script (./scripts/synctwitterfriends.php), meant
|
||||
to be run periodically from a job scheduler (e.g.: cron under Unix), to
|
||||
look for new additions to users' friends lists. Note that the friends
|
||||
syncing only subscribes users to each other, it does not unsubscribe
|
||||
users when they stop following each other on Twitter.
|
||||
As of 0.8.1, OAuth is used to to access protected resources on Twitter
|
||||
instead of HTTP Basic Auth. To use Twitter bridging you will need
|
||||
to register your instance of Laconica as an application on Twitter
|
||||
(http://twitter.com/apps), and update the following variables in your
|
||||
config.php with the consumer key and secret Twitter generates for you:
|
||||
|
||||
Sample cron job:
|
||||
$config['twitter']['consumer_key'] = 'YOURKEY';
|
||||
$config['twitter']['consumer_secret'] = 'YOURSECRET';
|
||||
|
||||
# Update Twitter friends subscriptions every half hour
|
||||
0,30 * * * * /path/to/php /path/to/laconica/scripts/synctwitterfriends.php>&/dev/null
|
||||
When registering your application with Twitter set the type to "Browser"
|
||||
and your Callback URL to:
|
||||
|
||||
http://example.org/mublog/twitter/authorization
|
||||
|
||||
The default access type should be, "Read & Write".
|
||||
|
||||
* Importing statuses from Twitter
|
||||
|
||||
To allow your users to import their friends' Twitter statuses, you will
|
||||
need to enable the bidirectional Twitter bridge in config.php:
|
||||
|
||||
$config['twitterbridge']['enabled'] = true;
|
||||
|
||||
and run the TwitterStatusFetcher daemon (scripts/twitterstatusfetcher.php).
|
||||
Additionally, you will want to set the integration source variable,
|
||||
which will keep notices posted to Twitter via Laconica from looping
|
||||
back. The integration source should be set to the name of your
|
||||
application, exactly as you specified it on the settings page for your
|
||||
Laconica application on Twitter, e.g.:
|
||||
|
||||
$config['integration']['source'] = 'YourApp';
|
||||
|
||||
* Twitter Friends Syncing
|
||||
|
||||
Users may set a flag in their settings ("Subscribe to my Twitter friends
|
||||
here" under the Twitter tab) to have Laconica attempt to locate and
|
||||
subscribe to "friends" (people they "follow") on Twitter who also have
|
||||
accounts on your Laconica system, and who have previously set up a link
|
||||
for automatically posting notices to Twitter.
|
||||
|
||||
As of 0.8.0, this is no longer accomplished via a cron job. Instead you
|
||||
must run the SyncTwitterFriends daemon (scripts/synctwitterfreinds.php).
|
||||
|
||||
Built-in Facebook Application
|
||||
-----------------------------
|
||||
|
@ -940,6 +968,8 @@ closed: If set to 'true', will disallow registration on your site.
|
|||
the service, *then* set this variable to 'true'.
|
||||
inviteonly: If set to 'true', will only allow registration if the user
|
||||
was invited by an existing user.
|
||||
openidonly: If set to 'true', will only allow registrations and logins
|
||||
through OpenID.
|
||||
private: If set to 'true', anonymous users will be redirected to the
|
||||
'login' page. Also, API methods that normally require no
|
||||
authentication will require it. Note that this does not turn
|
||||
|
@ -967,6 +997,9 @@ shorturllength: Length of URL at which URLs in a message exceeding 140
|
|||
dupelimit: minimum time allowed for one person to say the same thing
|
||||
twice. Default 60s. Anything lower is considered a user
|
||||
or UI error.
|
||||
textlimit: default max size for texts in the site. Defaults to 140.
|
||||
0 means no limit. Can be fine-tuned for notices, messages,
|
||||
profile bios and group descriptions.
|
||||
|
||||
db
|
||||
--
|
||||
|
@ -1167,6 +1200,14 @@ For configuring invites.
|
|||
|
||||
enabled: Whether to allow users to send invites. Default true.
|
||||
|
||||
openid
|
||||
------
|
||||
|
||||
For configuring OpenID.
|
||||
|
||||
enabled: Whether to allow users to register and login using OpenID. Default
|
||||
true.
|
||||
|
||||
tag
|
||||
---
|
||||
|
||||
|
@ -1228,6 +1269,30 @@ enabled: Set to true to enable. Default false.
|
|||
server: a string with the hostname of the sphinx server.
|
||||
port: an integer with the port number of the sphinx server.
|
||||
|
||||
emailpost
|
||||
---------
|
||||
|
||||
For post-by-email.
|
||||
|
||||
enabled: Whether to enable post-by-email. Defaults to true. You will
|
||||
also need to set up maildaemon.php.
|
||||
|
||||
sms
|
||||
---
|
||||
|
||||
For SMS integration.
|
||||
|
||||
enabled: Whether to enable SMS integration. Defaults to true. Queues
|
||||
should also be enabled.
|
||||
|
||||
twitter
|
||||
-------
|
||||
|
||||
For Twitter integration
|
||||
|
||||
enabled: Whether to enable Twitter integration. Defaults to true.
|
||||
Queues should also be enabled.
|
||||
|
||||
integration
|
||||
-----------
|
||||
|
||||
|
@ -1269,6 +1334,8 @@ banned: an array of usernames and/or profile IDs of 'banned' profiles.
|
|||
The site will reject any notices by these users -- they will
|
||||
not be accepted at all. (Compare with blacklisted users above,
|
||||
whose posts just won't show up in the public stream.)
|
||||
biolimit: max character length of bio; 0 means no limit; null means to use
|
||||
the site text limit default.
|
||||
|
||||
newuser
|
||||
-------
|
||||
|
@ -1365,6 +1432,9 @@ Options for group functionality.
|
|||
|
||||
maxaliases: maximum number of aliases a group can have. Default 3. Set
|
||||
to 0 or less to prevent aliases in a group.
|
||||
desclimit: maximum number of characters to allow in group descriptions.
|
||||
null (default) means to use the site-wide text limits. 0
|
||||
means no limit.
|
||||
|
||||
oohembed
|
||||
--------
|
||||
|
@ -1443,6 +1513,24 @@ linkcolor: Hex color of all links.
|
|||
backgroundimage: Image to use for the background.
|
||||
disposition: Flags for whether or not to tile the background image.
|
||||
|
||||
notice
|
||||
------
|
||||
|
||||
Configuration options specific to notices.
|
||||
|
||||
contentlimit: max length of the plain-text content of a notice.
|
||||
Default is null, meaning to use the site-wide text limit.
|
||||
0 means no limit.
|
||||
|
||||
message
|
||||
-------
|
||||
|
||||
Configuration options specific to messages.
|
||||
|
||||
contentlimit: max length of the plain-text content of a message.
|
||||
Default is null, meaning to use the site-wide text limit.
|
||||
0 means no limit.
|
||||
|
||||
Plugins
|
||||
=======
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Access token class.
|
||||
* Access token class
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
|
@ -32,10 +32,11 @@ if (!defined('LACONICA')) {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
|
||||
require_once INSTALLDIR.'/lib/omb.php';
|
||||
|
||||
/**
|
||||
* Access token class.
|
||||
* Access token class
|
||||
*
|
||||
* @category Action
|
||||
* @package Laconica
|
||||
|
@ -47,28 +48,23 @@ require_once INSTALLDIR.'/lib/omb.php';
|
|||
class AccesstokenAction extends Action
|
||||
{
|
||||
/**
|
||||
* Class handler.
|
||||
* Class handler
|
||||
*
|
||||
* @param array $args query arguments
|
||||
*
|
||||
* @return boolean false if user doesn't exist
|
||||
*/
|
||||
* @return nothing
|
||||
*
|
||||
**/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
try {
|
||||
common_debug('getting request from env variables', __FILE__);
|
||||
common_remove_magic_from_request();
|
||||
$req = OAuthRequest::from_request('POST', common_local_url('accesstoken'));
|
||||
common_debug('getting a server', __FILE__);
|
||||
$server = omb_oauth_server();
|
||||
common_debug('fetching the access token', __FILE__);
|
||||
$token = $server->fetch_access_token($req);
|
||||
common_debug('got this token: "'.print_r($token, true).'"', __FILE__);
|
||||
common_debug('printing the access token', __FILE__);
|
||||
print $token;
|
||||
} catch (OAuthException $e) {
|
||||
$srv = new OMB_Service_Provider(null, omb_oauth_datastore(),
|
||||
omb_oauth_server());
|
||||
$srv->writeAccessToken();
|
||||
} catch (Exception $e) {
|
||||
$this->serverError($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -25,11 +25,31 @@ require_once INSTALLDIR.'/lib/feedlist.php';
|
|||
|
||||
class AllAction extends ProfileAction
|
||||
{
|
||||
var $notice;
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
$cur = common_current_user();
|
||||
|
||||
if (!empty($cur) && $cur->id == $this->user->id) {
|
||||
$this->notice = $this->user->noticeInbox(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
|
||||
} else {
|
||||
$this->notice = $this->user->noticesWithFriends(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
|
||||
}
|
||||
|
||||
if($this->page > 1 && $this->notice->N == 0){
|
||||
$this->serverError(_('No such page'),$code=404);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
@ -88,7 +108,9 @@ class AllAction extends ProfileAction
|
|||
}
|
||||
}
|
||||
else {
|
||||
$message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname);
|
||||
$message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and then nudge %s or post a notice to his or her attention.'),
|
||||
(!common_config('site','openidonly')) ? 'register' : 'openidlogin',
|
||||
$this->user->nickname);
|
||||
}
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
|
@ -98,15 +120,7 @@ class AllAction extends ProfileAction
|
|||
|
||||
function showContent()
|
||||
{
|
||||
$cur = common_current_user();
|
||||
|
||||
if (!empty($cur) && $cur->id == $this->user->id) {
|
||||
$notice = $this->user->noticeInbox(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
|
||||
} else {
|
||||
$notice = $this->user->noticesWithFriends(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
|
||||
}
|
||||
|
||||
$nl = new NoticeList($notice, $this);
|
||||
$nl = new NoticeList($this->notice, $this);
|
||||
|
||||
$cnt = $nl->show();
|
||||
|
||||
|
|
|
@ -115,8 +115,8 @@ class AllrssAction extends Rss10Action
|
|||
'link' => common_local_url('all',
|
||||
array('nickname' =>
|
||||
$user->nickname)),
|
||||
'description' => sprintf(_('Feed for friends of %s'),
|
||||
$user->nickname));
|
||||
'description' => sprintf(_('Updates from %1$s and friends on %2$s!'),
|
||||
$user->nickname, common_config('site', 'name')));
|
||||
return $c;
|
||||
}
|
||||
|
||||
|
|
|
@ -131,6 +131,8 @@ class ApiAction extends Action
|
|||
'tags/timeline',
|
||||
'oembed/oembed',
|
||||
'groups/show',
|
||||
'groups/timeline',
|
||||
'groups/list_all',
|
||||
'groups/timeline');
|
||||
|
||||
static $bareauth = array('statuses/user_timeline',
|
||||
|
@ -140,7 +142,8 @@ class ApiAction extends Action
|
|||
'statuses/mentions',
|
||||
'statuses/followers',
|
||||
'favorites/favorites',
|
||||
'friendships/show');
|
||||
'friendships/show',
|
||||
'groups/list_groups');
|
||||
|
||||
$fullname = "$this->api_action/$this->api_method";
|
||||
|
||||
|
|
|
@ -103,18 +103,18 @@ class AttachmentAction extends Action
|
|||
$this->element('link',array('rel'=>'alternate',
|
||||
'type'=>'application/json+oembed',
|
||||
'href'=>common_local_url(
|
||||
'api',
|
||||
array('apiaction'=>'oembed','method'=>'oembed.json'),
|
||||
array('url'=>
|
||||
'oembed',
|
||||
array(),
|
||||
array('format'=>'json', 'url'=>
|
||||
common_local_url('attachment',
|
||||
array('attachment' => $this->attachment->id)))),
|
||||
'title'=>'oEmbed'),null);
|
||||
$this->element('link',array('rel'=>'alternate',
|
||||
'type'=>'text/xml+oembed',
|
||||
'href'=>common_local_url(
|
||||
'api',
|
||||
array('apiaction'=>'oembed','method'=>'oembed.xml'),
|
||||
array('url'=>
|
||||
'oembed',
|
||||
array(),
|
||||
array('format'=>'xml','url'=>
|
||||
common_local_url('attachment',
|
||||
array('attachment' => $this->attachment->id)))),
|
||||
'title'=>'oEmbed'),null);
|
||||
|
|
|
@ -382,13 +382,7 @@ class AvatarsettingsAction extends AccountSettingsAction
|
|||
function showStylesheets()
|
||||
{
|
||||
parent::showStylesheets();
|
||||
$jcropStyle =
|
||||
common_path('theme/base/css/jquery.Jcrop.css?version='.LACONICA_VERSION);
|
||||
|
||||
$this->element('link', array('rel' => 'stylesheet',
|
||||
'type' => 'text/css',
|
||||
'href' => $jcropStyle,
|
||||
'media' => 'screen, projection, tv'));
|
||||
$this->cssLink('css/jquery.Jcrop.css','base','screen, projection, tv');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -402,13 +396,8 @@ class AvatarsettingsAction extends AccountSettingsAction
|
|||
parent::showScripts();
|
||||
|
||||
if ($this->mode == 'crop') {
|
||||
$jcropPack = common_path('js/jcrop/jquery.Jcrop.pack.js');
|
||||
$jcropGo = common_path('js/jcrop/jquery.Jcrop.go.js');
|
||||
|
||||
$this->element('script', array('type' => 'text/javascript',
|
||||
'src' => $jcropPack));
|
||||
$this->element('script', array('type' => 'text/javascript',
|
||||
'src' => $jcropGo));
|
||||
$this->script('js/jcrop/jquery.Jcrop.min.js');
|
||||
$this->script('js/jcrop/jquery.Jcrop.go.js');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,7 +67,11 @@ class ConfirmaddressAction extends Action
|
|||
parent::handle($args);
|
||||
if (!common_logged_in()) {
|
||||
common_set_returnto($this->selfUrl());
|
||||
common_redirect(common_local_url('login'));
|
||||
if (!common_config('site', 'openidonly')) {
|
||||
common_redirect(common_local_url('login'));
|
||||
} else {
|
||||
common_redirect(common_local_url('openidlogin'));
|
||||
}
|
||||
return;
|
||||
}
|
||||
$code = $this->trimmed('code');
|
||||
|
|
|
@ -196,8 +196,8 @@ class EditgroupAction extends GroupDesignAction
|
|||
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
|
||||
$this->showForm(_('Full name is too long (max 255 chars).'));
|
||||
return;
|
||||
} else if (!is_null($description) && mb_strlen($description) > 140) {
|
||||
$this->showForm(_('description is too long (max 140 chars).'));
|
||||
} else if (User_group::descriptionTooLong($description)) {
|
||||
$this->showForm(sprintf(_('description is too long (max %d chars).'), User_group::maxDescription()));
|
||||
return;
|
||||
} else if (!is_null($location) && mb_strlen($location) > 255) {
|
||||
$this->showForm(_('Location is too long (max 255 chars).'));
|
||||
|
|
|
@ -122,7 +122,7 @@ class EmailsettingsAction extends AccountSettingsAction
|
|||
}
|
||||
$this->elementEnd('fieldset');
|
||||
|
||||
if ($user->email) {
|
||||
if (common_config('emailpost', 'enabled') && $user->email) {
|
||||
$this->elementStart('fieldset', array('id' => 'settings_email_incoming'));
|
||||
$this->element('legend',_('Incoming email'));
|
||||
if ($user->incomingemail) {
|
||||
|
@ -173,11 +173,13 @@ class EmailsettingsAction extends AccountSettingsAction
|
|||
_('Allow friends to nudge me and send me an email.'),
|
||||
$user->emailnotifynudge);
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->checkbox('emailpost',
|
||||
_('I want to post notices by email.'),
|
||||
$user->emailpost);
|
||||
$this->elementEnd('li');
|
||||
if (common_config('emailpost', 'enabled')) {
|
||||
$this->elementStart('li');
|
||||
$this->checkbox('emailpost',
|
||||
_('I want to post notices by email.'),
|
||||
$user->emailpost);
|
||||
$this->elementEnd('li');
|
||||
}
|
||||
$this->elementStart('li');
|
||||
$this->checkbox('emailmicroid',
|
||||
_('Publish a MicroID for my email address.'),
|
||||
|
|
|
@ -153,7 +153,8 @@ class FavoritedAction extends Action
|
|||
$message .= _('Be the first to add a notice to your favorites by clicking the fave button next to any notice you like.');
|
||||
}
|
||||
else {
|
||||
$message .= _('Why not [register an account](%%action.register%%) and be the first to add a notice to your favorites!');
|
||||
$message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and be the first to add a notice to your favorites!'),
|
||||
(!common_config('site','openidonly')) ? 'register' : 'openidlogin');
|
||||
}
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
|
|
|
@ -111,8 +111,8 @@ class FavoritesrssAction extends Rss10Action
|
|||
'link' => common_local_url('showfavorites',
|
||||
array('nickname' =>
|
||||
$user->nickname)),
|
||||
'description' => sprintf(_('Feed of favorite notices of %s'),
|
||||
$user->nickname));
|
||||
'description' => sprintf(_('Updates favored by %1$s on %2$s!'),
|
||||
$user->nickname, common_config('site', 'name')));
|
||||
return $c;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
<?php
|
||||
/*
|
||||
/**
|
||||
* Handler for remote subscription finish callback
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Action
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @author Robin Millette <millette@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://laconi.ca/
|
||||
*
|
||||
* Laconica - a distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, 2009, Control Yourself, Inc.
|
||||
*
|
||||
|
@ -15,285 +26,123 @@
|
|||
*
|
||||
* 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('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/extlib/libomb/service_consumer.php';
|
||||
require_once INSTALLDIR.'/lib/omb.php';
|
||||
|
||||
/**
|
||||
* Handler for remote subscription finish callback
|
||||
*
|
||||
* When a remote user subscribes a local user, a redirect to this action is
|
||||
* issued after the remote user authorized his service to subscribe.
|
||||
*
|
||||
* @category Action
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @author Robin Millette <millette@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
if (!defined('LACONICA')) { exit(1); }
|
||||
|
||||
require_once(INSTALLDIR.'/lib/omb.php');
|
||||
|
||||
class FinishremotesubscribeAction extends Action
|
||||
{
|
||||
|
||||
/**
|
||||
* Class handler.
|
||||
*
|
||||
* @param array $args query arguments
|
||||
*
|
||||
* @return nothing
|
||||
*
|
||||
**/
|
||||
function handle($args)
|
||||
{
|
||||
|
||||
parent::handle($args);
|
||||
|
||||
if (common_logged_in()) {
|
||||
$this->clientError(_('You can use the local subscription!'));
|
||||
return;
|
||||
}
|
||||
/* Restore session data. RemotesubscribeAction should have stored
|
||||
this entry. */
|
||||
$service = unserialize($_SESSION['oauth_authorization_request']);
|
||||
|
||||
$omb = $_SESSION['oauth_authorization_request'];
|
||||
|
||||
if (!$omb) {
|
||||
if (!$service) {
|
||||
$this->clientError(_('Not expecting this response!'));
|
||||
return;
|
||||
}
|
||||
|
||||
common_debug('stored request: '.print_r($omb,true), __FILE__);
|
||||
common_debug('stored request: '. print_r($service, true), __FILE__);
|
||||
|
||||
common_remove_magic_from_request();
|
||||
$req = OAuthRequest::from_request('POST', common_local_url('finishuserauthorization'));
|
||||
|
||||
$token = $req->get_parameter('oauth_token');
|
||||
|
||||
# I think this is the success metric
|
||||
|
||||
if ($token != $omb['token']) {
|
||||
$this->clientError(_('Not authorized.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$version = $req->get_parameter('omb_version');
|
||||
|
||||
if ($version != OMB_VERSION_01) {
|
||||
$this->clientError(_('Unknown version of OMB protocol.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$nickname = $req->get_parameter('omb_listener_nickname');
|
||||
|
||||
if (!$nickname) {
|
||||
$this->clientError(_('No nickname provided by remote server.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$profile_url = $req->get_parameter('omb_listener_profile');
|
||||
|
||||
if (!$profile_url) {
|
||||
$this->clientError(_('No profile URL returned by server.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Validate::uri($profile_url, array('allowed_schemes' => array('http', 'https')))) {
|
||||
$this->clientError(_('Invalid profile URL returned by server.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($profile_url == common_local_url('showstream', array('nickname' => $nickname))) {
|
||||
$this->clientError(_('You can use the local subscription!'));
|
||||
return;
|
||||
}
|
||||
|
||||
common_debug('listenee: "'.$omb['listenee'].'"', __FILE__);
|
||||
|
||||
$user = User::staticGet('nickname', $omb['listenee']);
|
||||
/* Create user objects for both users. Do it early for request
|
||||
validation. */
|
||||
$user = User::staticGet('uri', $service->getListeneeURI());
|
||||
|
||||
if (!$user) {
|
||||
$this->clientError(_('User being listened to doesn\'t exist.'));
|
||||
$this->clientError(_('User being listened to does not exist.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$other = User::staticGet('uri', $omb['listener']);
|
||||
$other = User::staticGet('uri', $service->getListenerURI());
|
||||
|
||||
if ($other) {
|
||||
$this->clientError(_('You can use the local subscription!'));
|
||||
return;
|
||||
}
|
||||
|
||||
$fullname = $req->get_parameter('omb_listener_fullname');
|
||||
$homepage = $req->get_parameter('omb_listener_homepage');
|
||||
$bio = $req->get_parameter('omb_listener_bio');
|
||||
$location = $req->get_parameter('omb_listener_location');
|
||||
$avatar_url = $req->get_parameter('omb_listener_avatar');
|
||||
$remote = Remote_profile::staticGet('uri', $service->getListenerURI());
|
||||
|
||||
list($newtok, $newsecret) = $this->access_token($omb);
|
||||
|
||||
if (!$newtok || !$newsecret) {
|
||||
$this->clientError(_('Couldn\'t convert request tokens to access tokens.'));
|
||||
return;
|
||||
}
|
||||
|
||||
# XXX: possible attack point; subscribe and return someone else's profile URI
|
||||
|
||||
$remote = Remote_profile::staticGet('uri', $omb['listener']);
|
||||
|
||||
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['listener'];
|
||||
$profile = new Profile();
|
||||
}
|
||||
|
||||
$profile->nickname = $nickname;
|
||||
$profile->profileurl = $profile_url;
|
||||
|
||||
if (!is_null($fullname)) {
|
||||
$profile->fullname = $fullname;
|
||||
}
|
||||
if (!is_null($homepage)) {
|
||||
$profile->homepage = $homepage;
|
||||
}
|
||||
if (!is_null($bio)) {
|
||||
$profile->bio = $bio;
|
||||
}
|
||||
if (!is_null($location)) {
|
||||
$profile->location = $location;
|
||||
}
|
||||
|
||||
if ($exists) {
|
||||
$profile->update($orig_profile);
|
||||
} else {
|
||||
$profile->created = DB_DataObject_Cast::dateTime(); # current time
|
||||
$id = $profile->insert();
|
||||
if (!$id) {
|
||||
$this->serverError(_('Error inserting new profile'));
|
||||
return;
|
||||
}
|
||||
$remote->id = $id;
|
||||
}
|
||||
|
||||
if ($avatar_url) {
|
||||
if (!$this->add_avatar($profile, $avatar_url)) {
|
||||
$this->serverError(_('Error inserting avatar'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$remote->postnoticeurl = $omb['post_notice_url'];
|
||||
$remote->updateprofileurl = $omb['update_profile_url'];
|
||||
|
||||
if ($exists) {
|
||||
if (!$remote->update($orig_remote)) {
|
||||
$this->serverError(_('Error updating remote profile'));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
$remote->created = DB_DataObject_Cast::dateTime(); # current time
|
||||
if (!$remote->insert()) {
|
||||
$this->serverError(_('Error inserting remote profile'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
$profile = Profile::staticGet($remote->id);
|
||||
|
||||
if ($user->hasBlocked($profile)) {
|
||||
$this->clientError(_('That user has blocked you from subscribing.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$sub = new Subscription();
|
||||
|
||||
$sub->subscriber = $remote->id;
|
||||
$sub->subscribed = $user->id;
|
||||
|
||||
$sub_exists = false;
|
||||
|
||||
if ($sub->find(true)) {
|
||||
$sub_exists = true;
|
||||
$orig_sub = clone($sub);
|
||||
} else {
|
||||
$sub_exists = false;
|
||||
$sub->created = DB_DataObject_Cast::dateTime(); # current time
|
||||
}
|
||||
|
||||
$sub->token = $newtok;
|
||||
$sub->secret = $newsecret;
|
||||
|
||||
if ($sub_exists) {
|
||||
$result = $sub->update($orig_sub);
|
||||
} else {
|
||||
$result = $sub->insert();
|
||||
}
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($sub, ($sub_exists) ? 'UPDATE' : 'INSERT', __FILE__);
|
||||
$this->clientError(_('Couldn\'t insert new subscription.'));
|
||||
/* Perform the handling itself via libomb. */
|
||||
try {
|
||||
$service->finishAuthorization();
|
||||
} catch (OAuthException $e) {
|
||||
if ($e->getMessage() == 'The authorized token does not equal the ' .
|
||||
'submitted token.') {
|
||||
$this->clientError(_('You are not authorized.'));
|
||||
return;
|
||||
} else {
|
||||
$this->clientError(_('Could not convert request token to ' .
|
||||
'access token.'));
|
||||
return;
|
||||
}
|
||||
} catch (OMB_RemoteServiceException $e) {
|
||||
$this->clientError(_('Remote service uses unknown version of ' .
|
||||
'OMB protocol.'));
|
||||
return;
|
||||
} catch (Exception $e) {
|
||||
common_debug('Got exception ' . print_r($e, true), __FILE__);
|
||||
$this->clientError($e->getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
# Notify user, if necessary
|
||||
/* The service URLs are not accessible from datastore, so setting them
|
||||
after insertion of the profile. */
|
||||
$orig_remote = clone($remote);
|
||||
|
||||
mail_subscribe_notify_profile($user, $profile);
|
||||
$remote->postnoticeurl =
|
||||
$service->getServiceURI(OMB_ENDPOINT_POSTNOTICE);
|
||||
$remote->updateprofileurl =
|
||||
$service->getServiceURI(OMB_ENDPOINT_UPDATEPROFILE);
|
||||
|
||||
# Clear the data
|
||||
if (!$remote->update($orig_remote)) {
|
||||
$this->serverError(_('Error updating remote profile'));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Clear the session data. */
|
||||
unset($_SESSION['oauth_authorization_request']);
|
||||
|
||||
# If we show subscriptions in reverse chron order, this should
|
||||
# show up close to the top of the page
|
||||
|
||||
/* If we show subscriptions in reverse chronological order, the new one
|
||||
should show up close to the top of the page. */
|
||||
common_redirect(common_local_url('subscribers', array('nickname' =>
|
||||
$user->nickname)),
|
||||
303);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
function access_token($omb)
|
||||
{
|
||||
|
||||
common_debug('starting request for access token', __FILE__);
|
||||
|
||||
$con = omb_oauth_consumer();
|
||||
$tok = new OAuthToken($omb['token'], $omb['secret']);
|
||||
|
||||
common_debug('using request token "'.$tok.'"', __FILE__);
|
||||
|
||||
$url = $omb['access_token_url'];
|
||||
|
||||
common_debug('using access token url "'.$url.'"', __FILE__);
|
||||
|
||||
# XXX: Is this the right thing to do? Strip off GET params and make them
|
||||
# POST params? Seems wrong to me.
|
||||
|
||||
$parsed = parse_url($url);
|
||||
$params = array();
|
||||
parse_str($parsed['query'], $params);
|
||||
|
||||
$req = OAuthRequest::from_consumer_and_token($con, $tok, "POST", $url, $params);
|
||||
|
||||
$req->set_parameter('omb_version', OMB_VERSION_01);
|
||||
|
||||
# XXX: test to see if endpoint accepts this signature method
|
||||
|
||||
$req->sign_request(omb_hmac_sha1(), $con, $tok);
|
||||
|
||||
# We re-use this tool's fetcher, since it's pretty good
|
||||
|
||||
common_debug('posting to access token url "'.$req->get_normalized_http_url().'"', __FILE__);
|
||||
common_debug('posting request data "'.$req->to_postdata().'"', __FILE__);
|
||||
|
||||
$fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
|
||||
$result = $fetcher->post($req->get_normalized_http_url(),
|
||||
$req->to_postdata(),
|
||||
array('User-Agent: Laconica/' . LACONICA_VERSION));
|
||||
|
||||
common_debug('got result: "'.print_r($result,true).'"', __FILE__);
|
||||
|
||||
if ($result->status != 200) {
|
||||
return null;
|
||||
}
|
||||
|
||||
parse_str($result->body, $return);
|
||||
|
||||
return array($return['oauth_token'], $return['oauth_token_secret']);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -428,13 +428,7 @@ class GrouplogoAction extends GroupDesignAction
|
|||
function showStylesheets()
|
||||
{
|
||||
parent::showStylesheets();
|
||||
$jcropStyle =
|
||||
common_path('theme/base/css/jquery.Jcrop.css?version='.LACONICA_VERSION);
|
||||
|
||||
$this->element('link', array('rel' => 'stylesheet',
|
||||
'type' => 'text/css',
|
||||
'href' => $jcropStyle,
|
||||
'media' => 'screen, projection, tv'));
|
||||
$this->cssLink('css/jquery.Jcrop.css','base','screen, projection, tv');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -448,13 +442,8 @@ class GrouplogoAction extends GroupDesignAction
|
|||
parent::showScripts();
|
||||
|
||||
if ($this->mode == 'crop') {
|
||||
$jcropPack = common_path('js/jcrop/jquery.Jcrop.pack.js');
|
||||
$jcropGo = common_path('js/jcrop/jquery.Jcrop.go.js');
|
||||
|
||||
$this->element('script', array('type' => 'text/javascript',
|
||||
'src' => $jcropPack));
|
||||
$this->element('script', array('type' => 'text/javascript',
|
||||
'src' => $jcropGo));
|
||||
$this->script('js/jcrop/jquery.Jcrop.min.js');
|
||||
$this->script('js/jcrop/jquery.Jcrop.go.js');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -132,9 +132,10 @@ class groupRssAction extends Rss10Action
|
|||
$c = array('url' => common_local_url('grouprss',
|
||||
array('nickname' =>
|
||||
$group->nickname)),
|
||||
'title' => $group->nickname,
|
||||
'title' => sprintf(_('%s timeline'), $group->nickname),
|
||||
'link' => common_local_url('showgroup', array('nickname' => $group->nickname)),
|
||||
'description' => sprintf(_('Microblog by %s group'), $group->nickname));
|
||||
'description' => sprintf(_('Updates from members of %1$s on %2$s!'),
|
||||
$group->nickname, common_config('site', 'name')));
|
||||
return $c;
|
||||
}
|
||||
|
||||
|
|
|
@ -82,7 +82,8 @@ class GroupsearchAction extends SearchAction
|
|||
$message = _('If you can\'t find the group you\'re looking for, you can [create it](%%action.newgroup%%) yourself.');
|
||||
}
|
||||
else {
|
||||
$message = _('Why not [register an account](%%action.register%%) and [create the group](%%action.newgroup%%) yourself!');
|
||||
$message = sprintf(_('Why not [register an account](%%%%action.%s%%%%) and [create the group](%%%%action.newgroup%%%%) yourself!'),
|
||||
(!common_config('site','openidonly')) ? 'register' : 'openidlogin');
|
||||
}
|
||||
$this->elementStart('div', 'guide');
|
||||
$this->raw(common_markup_to_html($message));
|
||||
|
|
|
@ -84,6 +84,12 @@ class ImsettingsAction extends ConnectSettingsAction
|
|||
|
||||
function showContent()
|
||||
{
|
||||
if (!common_config('xmpp', 'enabled')) {
|
||||
$this->element('div', array('class' => 'error'),
|
||||
_('IM is not available.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$user = common_current_user();
|
||||
$this->elementStart('form', array('method' => 'post',
|
||||
'id' => 'form_settings_im',
|
||||
|
|
|
@ -235,7 +235,7 @@ class InviteAction extends CurrentUserDesignAction
|
|||
common_root_url(),
|
||||
$personal,
|
||||
common_local_url('showstream', array('nickname' => $user->nickname)),
|
||||
common_local_url('register', array('code' => $invite->code)));
|
||||
common_local_url((!common_config('site', 'openidonly')) ? 'register' : 'openidlogin', array('code' => $invite->code)));
|
||||
|
||||
mail_send($recipients, $headers, $body);
|
||||
}
|
||||
|
|
|
@ -247,7 +247,7 @@ class LoginAction extends Action
|
|||
return _('For security reasons, please re-enter your ' .
|
||||
'user name and password ' .
|
||||
'before changing your settings.');
|
||||
} else {
|
||||
} else if (common_config('openid', 'enabled')) {
|
||||
return _('Login with your username and password. ' .
|
||||
'Don\'t have a username yet? ' .
|
||||
'[Register](%%action.register%%) a new account.');
|
||||
|
|
|
@ -146,8 +146,8 @@ class NewgroupAction extends Action
|
|||
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
|
||||
$this->showForm(_('Full name is too long (max 255 chars).'));
|
||||
return;
|
||||
} else if (!is_null($description) && mb_strlen($description) > 140) {
|
||||
$this->showForm(_('description is too long (max 140 chars).'));
|
||||
} else if (User_group::descriptionTooLong($description)) {
|
||||
$this->showForm(sprintf(_('description is too long (max %d chars).'), User_group::maxDescription()));
|
||||
return;
|
||||
} else if (!is_null($location) && mb_strlen($location) > 255) {
|
||||
$this->showForm(_('Location is too long (max 255 chars).'));
|
||||
|
|
|
@ -144,9 +144,10 @@ class NewmessageAction extends Action
|
|||
} else {
|
||||
$content_shortened = common_shorten_links($this->content);
|
||||
|
||||
if (mb_strlen($content_shortened) > 140) {
|
||||
$this->showForm(_('That\'s too long. ' .
|
||||
'Max message size is 140 chars.'));
|
||||
if (Message::contentTooLong($content_shortened)) {
|
||||
$this->showForm(sprintf(_('That\'s too long. ' .
|
||||
'Max message size is %d chars.'),
|
||||
Message::maxContent()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,8 +91,8 @@ class NewnoticeAction extends Action
|
|||
// is losts when size is exceeded
|
||||
if (empty($_POST) && $_SERVER['CONTENT_LENGTH']) {
|
||||
$this->clientError(sprintf(_('The server was unable to handle ' .
|
||||
'that much POST data (%s bytes) due to its current configuration.'),
|
||||
$_SERVER['CONTENT_LENGTH']));
|
||||
'that much POST data (%s bytes) due to its current configuration.'),
|
||||
$_SERVER['CONTENT_LENGTH']));
|
||||
}
|
||||
parent::handle($args);
|
||||
|
||||
|
@ -130,7 +130,7 @@ class NewnoticeAction extends Action
|
|||
$hint = '';
|
||||
}
|
||||
$this->clientError(sprintf(
|
||||
_('%s is not a supported filetype on this server.'), $filetype) . $hint);
|
||||
_('%s is not a supported filetype on this server.'), $filetype) . $hint);
|
||||
}
|
||||
|
||||
function isRespectsQuota($user) {
|
||||
|
@ -162,9 +162,10 @@ class NewnoticeAction extends Action
|
|||
$this->clientError(_('No content!'));
|
||||
} else {
|
||||
$content_shortened = common_shorten_links($content);
|
||||
if (mb_strlen($content_shortened) > 140) {
|
||||
$this->clientError(_('That\'s too long. '.
|
||||
'Max notice size is 140 chars.'));
|
||||
if (Notice::contentTooLong($content_shortened)) {
|
||||
$this->clientError(sprintf(_('That\'s too long. '.
|
||||
'Max notice size is %d chars.'),
|
||||
Notice::maxContent()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,37 +191,37 @@ class NewnoticeAction extends Action
|
|||
|
||||
if (isset($_FILES['attach']['error'])) {
|
||||
switch ($_FILES['attach']['error']) {
|
||||
case UPLOAD_ERR_NO_FILE:
|
||||
// no file uploaded, nothing to do
|
||||
break;
|
||||
case UPLOAD_ERR_NO_FILE:
|
||||
// no file uploaded, nothing to do
|
||||
break;
|
||||
|
||||
case UPLOAD_ERR_OK:
|
||||
$mimetype = $this->getUploadedFileType();
|
||||
if (!$this->isRespectsQuota($user)) {
|
||||
die('clientError() should trigger an exception before reaching here.');
|
||||
}
|
||||
break;
|
||||
case UPLOAD_ERR_OK:
|
||||
$mimetype = $this->getUploadedFileType();
|
||||
if (!$this->isRespectsQuota($user)) {
|
||||
die('clientError() should trigger an exception before reaching here.');
|
||||
}
|
||||
break;
|
||||
|
||||
case UPLOAD_ERR_INI_SIZE:
|
||||
$this->clientError(_('The uploaded file exceeds the upload_max_filesize directive in php.ini.'));
|
||||
case UPLOAD_ERR_INI_SIZE:
|
||||
$this->clientError(_('The uploaded file exceeds the upload_max_filesize directive in php.ini.'));
|
||||
|
||||
case UPLOAD_ERR_FORM_SIZE:
|
||||
$this->clientError(_('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.'));
|
||||
case UPLOAD_ERR_FORM_SIZE:
|
||||
$this->clientError(_('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.'));
|
||||
|
||||
case UPLOAD_ERR_PARTIAL:
|
||||
$this->clientError(_('The uploaded file was only partially uploaded.'));
|
||||
case UPLOAD_ERR_PARTIAL:
|
||||
$this->clientError(_('The uploaded file was only partially uploaded.'));
|
||||
|
||||
case UPLOAD_ERR_NO_TMP_DIR:
|
||||
$this->clientError(_('Missing a temporary folder.'));
|
||||
case UPLOAD_ERR_NO_TMP_DIR:
|
||||
$this->clientError(_('Missing a temporary folder.'));
|
||||
|
||||
case UPLOAD_ERR_CANT_WRITE:
|
||||
$this->clientError(_('Failed to write file to disk.'));
|
||||
case UPLOAD_ERR_CANT_WRITE:
|
||||
$this->clientError(_('Failed to write file to disk.'));
|
||||
|
||||
case UPLOAD_ERR_EXTENSION:
|
||||
$this->clientError(_('File upload stopped by extension.'));
|
||||
case UPLOAD_ERR_EXTENSION:
|
||||
$this->clientError(_('File upload stopped by extension.'));
|
||||
|
||||
default:
|
||||
die('Should never reach here.');
|
||||
default:
|
||||
die('Should never reach here.');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -233,7 +234,7 @@ class NewnoticeAction extends Action
|
|||
$fileRecord = $this->storeFile($filename, $mimetype);
|
||||
|
||||
$fileurl = common_local_url('attachment',
|
||||
array('attachment' => $fileRecord->id));
|
||||
array('attachment' => $fileRecord->id));
|
||||
|
||||
// not sure this is necessary -- Zach
|
||||
$this->maybeAddRedir($fileRecord->id, $fileurl);
|
||||
|
@ -241,9 +242,10 @@ class NewnoticeAction extends Action
|
|||
$short_fileurl = common_shorten_url($fileurl);
|
||||
$content_shortened .= ' ' . $short_fileurl;
|
||||
|
||||
if (mb_strlen($content_shortened) > 140) {
|
||||
if (Notice::contentTooLong($content_shortened)) {
|
||||
$this->deleteFile($filename);
|
||||
$this->clientError(_('Max notice size is 140 chars, including attachment URL.'));
|
||||
$this->clientError(sprintf(_('Max notice size is %d chars, including attachment URL.'),
|
||||
Notice::maxContent()));
|
||||
}
|
||||
|
||||
// Also, not sure this is necessary -- Zach
|
||||
|
@ -367,7 +369,7 @@ class NewnoticeAction extends Action
|
|||
File_to_post::processNew($filerec->id, $notice->id);
|
||||
|
||||
$this->maybeAddRedir($filerec->id,
|
||||
common_local_url('file', array('notice' => $notice->id)));
|
||||
common_local_url('file', array('notice' => $notice->id)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -121,7 +121,9 @@ class NoticesearchAction extends SearchAction
|
|||
$message = sprintf(_('Be the first to [post on this topic](%%%%action.newnotice%%%%?status_textarea=%s)!'), urlencode($q));
|
||||
}
|
||||
else {
|
||||
$message = sprintf(_('Why not [register an account](%%%%action.register%%%%) and be the first to [post on this topic](%%%%action.newnotice%%%%?status_textarea=%s)!'), urlencode($q));
|
||||
$message = sprintf(_('Why not [register an account](%%%%action.%s%%%%) and be the first to [post on this topic](%%%%action.newnotice%%%%?status_textarea=%s)!'),
|
||||
(!common_config('site','openidonly')) ? 'register' : 'openidlogin',
|
||||
urlencode($q));
|
||||
}
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
|
|
|
@ -86,9 +86,10 @@ class NoticesearchrssAction extends Rss10Action
|
|||
{
|
||||
$q = $this->trimmed('q');
|
||||
$c = array('url' => common_local_url('noticesearchrss', array('q' => $q)),
|
||||
'title' => common_config('site', 'name') . sprintf(_(' Search Stream for "%s"'), $q),
|
||||
'title' => sprintf(_('Updates with "%s"'), $q),
|
||||
'link' => common_local_url('noticesearch', array('q' => $q)),
|
||||
'description' => sprintf(_('All updates matching search term "%s"'), $q));
|
||||
'description' => sprintf(_('Updates matching search term "%1$s" on %2$s!'),
|
||||
$q, common_config('site', 'name')));
|
||||
return $c;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,8 +31,6 @@ if (!defined('LACONICA')) {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/twitterapi.php';
|
||||
|
||||
/**
|
||||
* Oembed provider implementation
|
||||
*
|
||||
|
@ -46,17 +44,13 @@ require_once INSTALLDIR.'/lib/twitterapi.php';
|
|||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
class TwitapioembedAction extends TwitterapiAction
|
||||
class OembedAction extends Action
|
||||
{
|
||||
|
||||
function oembed($args, $apidata)
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
common_debug("in oembed api action");
|
||||
|
||||
$this->auth_user = $apidata['user'];
|
||||
|
||||
$url = $args['url'];
|
||||
if( substr(strtolower($url),0,strlen(common_root_url())) == strtolower(common_root_url()) ){
|
||||
$path = substr($url,strlen(common_root_url()));
|
||||
|
@ -131,8 +125,7 @@ class TwitapioembedAction extends TwitterapiAction
|
|||
default:
|
||||
$this->serverError(_("$path not supported for oembed requests"), 501);
|
||||
}
|
||||
|
||||
switch($apidata['content-type']){
|
||||
switch($args['format']){
|
||||
case 'xml':
|
||||
$this->init_document('xml');
|
||||
$this->elementStart('oembed');
|
||||
|
@ -151,12 +144,11 @@ class TwitapioembedAction extends TwitterapiAction
|
|||
if($oembed['thumbnail_url']) $this->element('thumbnail_url',null,$oembed['thumbnail_url']);
|
||||
if($oembed['thumbnail_width']) $this->element('thumbnail_width',null,$oembed['thumbnail_width']);
|
||||
if($oembed['thumbnail_height']) $this->element('thumbnail_height',null,$oembed['thumbnail_height']);
|
||||
|
||||
|
||||
$this->elementEnd('oembed');
|
||||
$this->end_document('xml');
|
||||
break;
|
||||
case 'json':
|
||||
case 'json': case '':
|
||||
$this->init_document('json');
|
||||
print(json_encode($oembed));
|
||||
$this->end_document('json');
|
||||
|
@ -164,10 +156,51 @@ class TwitapioembedAction extends TwitterapiAction
|
|||
default:
|
||||
$this->serverError(_('content type ' . $apidata['content-type'] . ' not supported'), 501);
|
||||
}
|
||||
|
||||
}else{
|
||||
$this->serverError(_('Only ' . common_root_url() . ' urls over plain http please'), 404);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function init_document($type)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'xml':
|
||||
header('Content-Type: application/xml; charset=utf-8');
|
||||
$this->startXML();
|
||||
break;
|
||||
case 'json':
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
// Check for JSONP callback
|
||||
$callback = $this->arg('callback');
|
||||
if ($callback) {
|
||||
print $callback . '(';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$this->serverError(_('Not a supported data format.'), 501);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function end_document($type='xml')
|
||||
{
|
||||
switch ($type) {
|
||||
case 'xml':
|
||||
$this->endXML();
|
||||
break;
|
||||
case 'json':
|
||||
// Check for JSONP callback
|
||||
$callback = $this->arg('callback');
|
||||
if ($callback) {
|
||||
print ')';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$this->serverError(_('Not a supported data format.'), 501);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
|
@ -66,7 +66,7 @@ class OpensearchAction extends Action
|
|||
$type = 'noticesearch';
|
||||
$short_name = _('Notice Search');
|
||||
}
|
||||
header('Content-Type: text/html');
|
||||
header('Content-Type: application/opensearchdescription+xml');
|
||||
$this->startXML();
|
||||
$this->elementStart('OpenSearchDescription', array('xmlns' => 'http://a9.com/-/spec/opensearch/1.1/'));
|
||||
$short_name = common_config('site', 'name').' '.$short_name;
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
<?php
|
||||
/*
|
||||
/**
|
||||
* Handle postnotice action
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Action
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @author Robin Millette <millette@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://laconi.ca/
|
||||
*
|
||||
* Laconica - a distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, 2009, Control Yourself, Inc.
|
||||
*
|
||||
|
@ -17,75 +28,71 @@
|
|||
* 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 INSTALLDIR.'/lib/omb.php';
|
||||
require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
|
||||
|
||||
/**
|
||||
* Handler for postnotice action
|
||||
*
|
||||
* @category Action
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @author Robin Millette <millette@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
class PostnoticeAction extends Action
|
||||
{
|
||||
/**
|
||||
* For initializing members of the class.
|
||||
*
|
||||
* @param array $argarray misc. arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function prepare($argarray)
|
||||
{
|
||||
parent::prepare($argarray);
|
||||
try {
|
||||
$this->checkNotice();
|
||||
} catch (Exception $e) {
|
||||
$this->clientError($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
try {
|
||||
common_remove_magic_from_request();
|
||||
$req = OAuthRequest::from_request('POST', common_local_url('postnotice'));
|
||||
# Note: server-to-server function!
|
||||
$server = omb_oauth_server();
|
||||
list($consumer, $token) = $server->verify_request($req);
|
||||
if ($this->save_notice($req, $consumer, $token)) {
|
||||
print "omb_version=".OMB_VERSION_01;
|
||||
}
|
||||
} catch (OAuthException $e) {
|
||||
$srv = new OMB_Service_Provider(null, omb_oauth_datastore(),
|
||||
omb_oauth_server());
|
||||
$srv->handlePostNotice();
|
||||
} catch (Exception $e) {
|
||||
$this->serverError($e->getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function save_notice(&$req, &$consumer, &$token)
|
||||
function checkNotice()
|
||||
{
|
||||
$version = $req->get_parameter('omb_version');
|
||||
if ($version != OMB_VERSION_01) {
|
||||
$this->clientError(_('Unsupported OMB version'), 400);
|
||||
return false;
|
||||
}
|
||||
# First, check to see
|
||||
$listenee = $req->get_parameter('omb_listenee');
|
||||
$remote_profile = Remote_profile::staticGet('uri', $listenee);
|
||||
if (!$remote_profile) {
|
||||
$this->clientError(_('Profile unknown'), 403);
|
||||
return false;
|
||||
}
|
||||
$sub = Subscription::staticGet('token', $token->key);
|
||||
if (!$sub) {
|
||||
$this->clientError(_('No such subscription'), 403);
|
||||
return false;
|
||||
}
|
||||
$content = $req->get_parameter('omb_notice_content');
|
||||
$content_shortened = common_shorten_links($content);
|
||||
if (mb_strlen($content_shortened) > 140) {
|
||||
$content = common_shorten_links($_POST['omb_notice_content']);
|
||||
if (Notice::contentTooLong($content)) {
|
||||
$this->clientError(_('Invalid notice content'), 400);
|
||||
return false;
|
||||
}
|
||||
$notice_uri = $req->get_parameter('omb_notice');
|
||||
if (!Validate::uri($notice_uri) &&
|
||||
!common_valid_tag($notice_uri)) {
|
||||
$this->clientError(_('Invalid notice uri'), 400);
|
||||
return false;
|
||||
$license = $_POST['omb_notice_license'];
|
||||
$site_license = common_config('license', 'url');
|
||||
if ($license && !common_compatible_license($license, $site_license)) {
|
||||
throw new Exception(sprintf(_('Notice license ‘%s’ is not ' .
|
||||
'compatible with site license ‘%s’.'),
|
||||
$license, $site_license));
|
||||
}
|
||||
$notice_url = $req->get_parameter('omb_notice_url');
|
||||
if ($notice_url && !common_valid_http_url($notice_url)) {
|
||||
$this->clientError(_('Invalid notice url'), 400);
|
||||
return false;
|
||||
}
|
||||
$notice = Notice::staticGet('uri', $notice_uri);
|
||||
if (!$notice) {
|
||||
$notice = Notice::saveNew($remote_profile->id, $content, 'omb', false, null, $notice_uri);
|
||||
if (is_string($notice)) {
|
||||
common_server_serror($notice, 500);
|
||||
return false;
|
||||
}
|
||||
common_broadcast_notice($notice, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -109,9 +109,16 @@ class ProfilesettingsAction extends AccountSettingsAction
|
|||
_('URL of your homepage, blog, or profile on another site'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$maxBio = Profile::maxBio();
|
||||
if ($maxBio > 0) {
|
||||
$bioInstr = sprintf(_('Describe yourself and your interests in %d chars'),
|
||||
$maxBio);
|
||||
} else {
|
||||
$bioInstr = _('Describe yourself and your interests');
|
||||
}
|
||||
$this->textarea('bio', _('Bio'),
|
||||
($this->arg('bio')) ? $this->arg('bio') : $profile->bio,
|
||||
_('Describe yourself and your interests in 140 chars'));
|
||||
$bioInstr);
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->input('location', _('Location'),
|
||||
|
@ -189,7 +196,7 @@ class ProfilesettingsAction extends AccountSettingsAction
|
|||
// Some validation
|
||||
if (!Validate::string($nickname, array('min_length' => 1,
|
||||
'max_length' => 64,
|
||||
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
|
||||
'format' => NICKNAME_FMT))) {
|
||||
$this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.'));
|
||||
return;
|
||||
} else if (!User::allowed_nickname($nickname)) {
|
||||
|
@ -202,8 +209,9 @@ class ProfilesettingsAction extends AccountSettingsAction
|
|||
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
|
||||
$this->showForm(_('Full name is too long (max 255 chars).'));
|
||||
return;
|
||||
} else if (!is_null($bio) && mb_strlen($bio) > 140) {
|
||||
$this->showForm(_('Bio is too long (max 140 chars).'));
|
||||
} else if (Profile::bioTooLong($bio)) {
|
||||
$this->showForm(sprintf(_('Bio is too long (max %d chars).'),
|
||||
Profile::maxBio()));
|
||||
return;
|
||||
} else if (!is_null($location) && mb_strlen($location) > 255) {
|
||||
$this->showForm(_('Location is too long (max 255 chars).'));
|
||||
|
|
|
@ -59,6 +59,7 @@ class PublicAction extends Action
|
|||
*/
|
||||
|
||||
var $page = null;
|
||||
var $notice;
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
|
@ -84,6 +85,18 @@ class PublicAction extends Action
|
|||
|
||||
common_set_returnto($this->selfUrl());
|
||||
|
||||
$this->notice = Notice::publicStream(($this->page-1)*NOTICES_PER_PAGE,
|
||||
NOTICES_PER_PAGE + 1);
|
||||
|
||||
if (!$this->notice) {
|
||||
$this->serverError(_('Could not retrieve public stream.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if($this->page > 1 && $this->notice->N == 0){
|
||||
$this->serverError(_('No such page'),$code=404);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -165,7 +178,8 @@ class PublicAction extends Action
|
|||
}
|
||||
else {
|
||||
if (! (common_config('site','closed') || common_config('site','inviteonly'))) {
|
||||
$message .= _('Why not [register an account](%%action.register%%) and be the first to post!');
|
||||
$message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and be the first to post!'),
|
||||
(!common_config('site','openidonly')) ? 'register' : 'openidlogin');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,15 +199,7 @@ class PublicAction extends Action
|
|||
|
||||
function showContent()
|
||||
{
|
||||
$notice = Notice::publicStream(($this->page-1)*NOTICES_PER_PAGE,
|
||||
NOTICES_PER_PAGE + 1);
|
||||
|
||||
if (!$notice) {
|
||||
$this->serverError(_('Could not retrieve public stream.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$nl = new NoticeList($notice, $this);
|
||||
$nl = new NoticeList($this->notice, $this);
|
||||
|
||||
$cnt = $nl->show();
|
||||
|
||||
|
@ -220,9 +226,11 @@ class PublicAction extends Action
|
|||
function showAnonymousMessage()
|
||||
{
|
||||
if (! (common_config('site','closed') || common_config('site','inviteonly'))) {
|
||||
$m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
|
||||
'based on the Free Software [Laconica](http://laconi.ca/) tool. ' .
|
||||
'[Join now](%%action.register%%) to share notices about yourself with friends, family, and colleagues! ([Read more](%%doc.help%%))');
|
||||
$m = sprintf(_('This is %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
|
||||
'based on the Free Software [Laconica](http://laconi.ca/) tool. ' .
|
||||
'[Join now](%%%%action.%s%%%%) to share notices about yourself with friends, family, and colleagues! ' .
|
||||
'([Read more](%%%%doc.help%%%%))'),
|
||||
(!common_config('site','openidonly')) ? 'register' : 'openidlogin');
|
||||
} else {
|
||||
$m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
|
||||
'based on the Free Software [Laconica](http://laconi.ca/) tool.');
|
||||
|
|
|
@ -86,9 +86,9 @@ class PublicrssAction extends Rss10Action
|
|||
{
|
||||
$c = array(
|
||||
'url' => common_local_url('publicrss')
|
||||
, 'title' => sprintf(_('%s Public Stream'), common_config('site', 'name'))
|
||||
, 'title' => sprintf(_('%s public timeline'), common_config('site', 'name'))
|
||||
, 'link' => common_local_url('public')
|
||||
, 'description' => sprintf(_('All updates for %s'), common_config('site', 'name')));
|
||||
, 'description' => sprintf(_('%s updates from everyone!'), common_config('site', 'name')));
|
||||
return $c;
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,8 @@ class PublictagcloudAction extends Action
|
|||
$message .= _('Be the first to post one!');
|
||||
}
|
||||
else {
|
||||
$message .= _('Why not [register an account](%%action.register%%) and be the first to post one!');
|
||||
$message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and be the first to post one!'),
|
||||
(!common_config('site','openidonly')) ? 'register' : 'openidlogin');
|
||||
}
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
|
|
|
@ -207,8 +207,9 @@ class RegisterAction extends Action
|
|||
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
|
||||
$this->showForm(_('Full name is too long (max 255 chars).'));
|
||||
return;
|
||||
} else if (!is_null($bio) && mb_strlen($bio) > 140) {
|
||||
$this->showForm(_('Bio is too long (max 140 chars).'));
|
||||
} else if (Profile::bioTooLong($bio)) {
|
||||
$this->showForm(sprintf(_('Bio is too long (max %d chars).'),
|
||||
Profile::maxBio()));
|
||||
return;
|
||||
} else if (!is_null($location) && mb_strlen($location) > 255) {
|
||||
$this->showForm(_('Location is too long (max 255 chars).'));
|
||||
|
@ -442,10 +443,16 @@ class RegisterAction extends Action
|
|||
'or profile on another site'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$maxBio = Profile::maxBio();
|
||||
if ($maxBio > 0) {
|
||||
$bioInstr = sprintf(_('Describe yourself and your interests in %d chars'),
|
||||
$maxBio);
|
||||
} else {
|
||||
$bioInstr = _('Describe yourself and your interests');
|
||||
}
|
||||
$this->textarea('bio', _('Bio'),
|
||||
$this->trimmed('bio'),
|
||||
_('Describe yourself and your '.
|
||||
'interests in 140 chars'));
|
||||
$bioInstr);
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->input('location', _('Location'),
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
<?php
|
||||
/*
|
||||
/**
|
||||
* Handler for remote subscription
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Action
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @author Robin Millette <millette@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://laconi.ca/
|
||||
*
|
||||
* Laconica - a distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, 2009, Control Yourself, Inc.
|
||||
*
|
||||
|
@ -15,12 +26,27 @@
|
|||
*
|
||||
* 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('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/omb.php';
|
||||
require_once INSTALLDIR.'/extlib/libomb/service_consumer.php';
|
||||
require_once INSTALLDIR.'/extlib/libomb/profile.php';
|
||||
|
||||
/**
|
||||
* Handler for remote subscription
|
||||
*
|
||||
* @category Action
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @author Robin Millette <millette@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
if (!defined('LACONICA')) { exit(1); }
|
||||
|
||||
require_once(INSTALLDIR.'/lib/omb.php');
|
||||
|
||||
class RemotesubscribeAction extends Action
|
||||
{
|
||||
var $nickname;
|
||||
|
@ -36,7 +62,7 @@ class RemotesubscribeAction extends Action
|
|||
return false;
|
||||
}
|
||||
|
||||
$this->nickname = $this->trimmed('nickname');
|
||||
$this->nickname = $this->trimmed('nickname');
|
||||
$this->profile_url = $this->trimmed('profile_url');
|
||||
|
||||
return true;
|
||||
|
@ -47,7 +73,7 @@ class RemotesubscribeAction extends Action
|
|||
parent::handle($args);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
# CSRF protection
|
||||
/* Use a session token for CSRF protection. */
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->showForm(_('There was a problem with your session token. '.
|
||||
|
@ -71,11 +97,13 @@ class RemotesubscribeAction extends Action
|
|||
if ($this->err) {
|
||||
$this->element('div', 'error', $this->err);
|
||||
} else {
|
||||
$inst = _('To subscribe, you can [login](%%action.login%%),' .
|
||||
' or [register](%%action.register%%) a new ' .
|
||||
' account. If you already have an account ' .
|
||||
' on a [compatible microblogging site](%%doc.openmublog%%), ' .
|
||||
' enter your profile URL below.');
|
||||
$inst = sprintf(_('To subscribe, you can [login](%%%%action.%s%%%%),' .
|
||||
' or [register](%%%%action.%s%%%%) a new ' .
|
||||
' account. If you already have an account ' .
|
||||
' on a [compatible microblogging site](%%doc.openmublog%%), ' .
|
||||
' enter your profile URL below.'),
|
||||
(!common_config('site','openidonly')) ? 'login' : 'openidlogin',
|
||||
(!common_config('site','openidonly')) ? 'register' : 'openidlogin');
|
||||
$output = common_markup_to_html($inst);
|
||||
$this->elementStart('div', 'instructions');
|
||||
$this->raw($output);
|
||||
|
@ -90,8 +118,8 @@ class RemotesubscribeAction extends Action
|
|||
|
||||
function showContent()
|
||||
{
|
||||
# id = remotesubscribe conflicts with the
|
||||
# button on profile page
|
||||
/* The id 'remotesubscribe' conflicts with the
|
||||
button on profile page. */
|
||||
$this->elementStart('form', array('id' => 'form_remote_subscribe',
|
||||
'method' => 'post',
|
||||
'class' => 'form_settings',
|
||||
|
@ -117,247 +145,50 @@ class RemotesubscribeAction extends Action
|
|||
|
||||
function remoteSubscription()
|
||||
{
|
||||
$user = $this->getUser();
|
||||
|
||||
if (!$user) {
|
||||
if (!$this->nickname) {
|
||||
$this->showForm(_('No such user.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$user = User::staticGet('nickname', $this->nickname);
|
||||
|
||||
$this->profile_url = $this->trimmed('profile_url');
|
||||
|
||||
if (!$this->profile_url) {
|
||||
$this->showForm(_('No such user.'));
|
||||
$this->showForm(_('No such user'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Validate::uri($this->profile_url, array('allowed_schemes' => array('http', 'https')))) {
|
||||
if (!common_valid_http_url($this->profile_url)) {
|
||||
$this->showForm(_('Invalid profile URL (bad format)'));
|
||||
return;
|
||||
}
|
||||
|
||||
$fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
|
||||
$yadis = Auth_Yadis_Yadis::discover($this->profile_url, $fetcher);
|
||||
|
||||
if (!$yadis || $yadis->failed) {
|
||||
$this->showForm(_('Not a valid profile URL (no YADIS document).'));
|
||||
try {
|
||||
$service = new OMB_Service_Consumer($this->profile_url,
|
||||
common_root_url(),
|
||||
omb_oauth_datastore());
|
||||
} catch (OMB_InvalidYadisException $e) {
|
||||
$this->showForm(_('Not a valid profile URL (no YADIS document or ' .
|
||||
'no or invalid XRDS defined).'));
|
||||
return;
|
||||
}
|
||||
|
||||
# XXX: a little liberal for sites that accidentally put whitespace before the xml declaration
|
||||
|
||||
$xrds =& Auth_Yadis_XRDS::parseXRDS(trim($yadis->response_text));
|
||||
|
||||
if (!$xrds) {
|
||||
$this->showForm(_('Not a valid profile URL (no XRDS defined).'));
|
||||
if ($service->getServiceURI(OAUTH_ENDPOINT_REQUEST) ==
|
||||
common_local_url('requesttoken') ||
|
||||
User::staticGet('uri', $service->getRemoteUserURI())) {
|
||||
$this->showForm(_('That’s a local profile! Login to subscribe.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$omb = $this->getOmb($xrds);
|
||||
|
||||
if (!$omb) {
|
||||
$this->showForm(_('Not a valid profile URL (incorrect services).'));
|
||||
try {
|
||||
$service->requestToken();
|
||||
} catch (OMB_RemoteServiceException $e) {
|
||||
$this->showForm(_('Couldn’t get a request token.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (omb_service_uri($omb[OAUTH_ENDPOINT_REQUEST]) ==
|
||||
common_local_url('requesttoken'))
|
||||
{
|
||||
$this->showForm(_('That\'s a local profile! Login to subscribe.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (User::staticGet('uri', omb_local_id($omb[OAUTH_ENDPOINT_REQUEST]))) {
|
||||
$this->showForm(_('That\'s a local profile! Login to subscribe.'));
|
||||
return;
|
||||
}
|
||||
|
||||
list($token, $secret) = $this->requestToken($omb);
|
||||
|
||||
if (!$token || !$secret) {
|
||||
$this->showForm(_('Couldn\'t get a request token.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$this->requestAuthorization($user, $omb, $token, $secret);
|
||||
}
|
||||
|
||||
function getUser()
|
||||
{
|
||||
$user = null;
|
||||
if ($this->nickname) {
|
||||
$user = User::staticGet('nickname', $this->nickname);
|
||||
}
|
||||
return $user;
|
||||
}
|
||||
|
||||
function getOmb($xrds)
|
||||
{
|
||||
static $omb_endpoints = array(OMB_ENDPOINT_UPDATEPROFILE, OMB_ENDPOINT_POSTNOTICE);
|
||||
static $oauth_endpoints = array(OAUTH_ENDPOINT_REQUEST, OAUTH_ENDPOINT_AUTHORIZE,
|
||||
OAUTH_ENDPOINT_ACCESS);
|
||||
$omb = array();
|
||||
|
||||
# XXX: the following code could probably be refactored to eliminate dupes
|
||||
|
||||
$oauth_services = omb_get_services($xrds, OAUTH_DISCOVERY);
|
||||
|
||||
if (!$oauth_services) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$oauth_service = $oauth_services[0];
|
||||
|
||||
$oauth_xrd = $this->getXRD($oauth_service, $xrds);
|
||||
|
||||
if (!$oauth_xrd) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$this->addServices($oauth_xrd, $oauth_endpoints, $omb)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$omb_services = omb_get_services($xrds, OMB_NAMESPACE);
|
||||
|
||||
if (!$omb_services) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$omb_service = $omb_services[0];
|
||||
|
||||
$omb_xrd = $this->getXRD($omb_service, $xrds);
|
||||
|
||||
if (!$omb_xrd) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$this->addServices($omb_xrd, $omb_endpoints, $omb)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
# XXX: check that we got all the services we needed
|
||||
|
||||
foreach (array_merge($omb_endpoints, $oauth_endpoints) as $type) {
|
||||
if (!array_key_exists($type, $omb) || !$omb[$type]) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!omb_local_id($omb[OAUTH_ENDPOINT_REQUEST])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $omb;
|
||||
}
|
||||
|
||||
function getXRD($main_service, $main_xrds)
|
||||
{
|
||||
$uri = omb_service_uri($main_service);
|
||||
if (strpos($uri, "#") !== 0) {
|
||||
# FIXME: more rigorous handling of external service definitions
|
||||
return null;
|
||||
}
|
||||
$id = substr($uri, 1);
|
||||
$nodes = $main_xrds->allXrdNodes;
|
||||
$parser = $main_xrds->parser;
|
||||
foreach ($nodes as $node) {
|
||||
$attrs = $parser->attributes($node);
|
||||
if (array_key_exists('xml:id', $attrs) &&
|
||||
$attrs['xml:id'] == $id) {
|
||||
# XXX: trick the constructor into thinking this is the only node
|
||||
$bogus_nodes = array($node);
|
||||
return new Auth_Yadis_XRDS($parser, $bogus_nodes);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function addServices($xrd, $types, &$omb)
|
||||
{
|
||||
foreach ($types as $type) {
|
||||
$matches = omb_get_services($xrd, $type);
|
||||
if ($matches) {
|
||||
$omb[$type] = $matches[0];
|
||||
} else {
|
||||
# no match for type
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function requestToken($omb)
|
||||
{
|
||||
$con = omb_oauth_consumer();
|
||||
|
||||
$url = omb_service_uri($omb[OAUTH_ENDPOINT_REQUEST]);
|
||||
|
||||
# XXX: Is this the right thing to do? Strip off GET params and make them
|
||||
# POST params? Seems wrong to me.
|
||||
|
||||
$parsed = parse_url($url);
|
||||
$params = array();
|
||||
parse_str($parsed['query'], $params);
|
||||
|
||||
$req = OAuthRequest::from_consumer_and_token($con, null, "POST", $url, $params);
|
||||
|
||||
$listener = omb_local_id($omb[OAUTH_ENDPOINT_REQUEST]);
|
||||
|
||||
if (!$listener) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$req->set_parameter('omb_listener', $listener);
|
||||
$req->set_parameter('omb_version', OMB_VERSION_01);
|
||||
|
||||
# XXX: test to see if endpoint accepts this signature method
|
||||
|
||||
$req->sign_request(omb_hmac_sha1(), $con, null);
|
||||
|
||||
# We re-use this tool's fetcher, since it's pretty good
|
||||
|
||||
$fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
|
||||
|
||||
$result = $fetcher->post($req->get_normalized_http_url(),
|
||||
$req->to_postdata(),
|
||||
array('User-Agent: Laconica/' . LACONICA_VERSION));
|
||||
if ($result->status != 200) {
|
||||
return null;
|
||||
}
|
||||
|
||||
parse_str($result->body, $return);
|
||||
|
||||
return array($return['oauth_token'], $return['oauth_token_secret']);
|
||||
}
|
||||
|
||||
function requestAuthorization($user, $omb, $token, $secret)
|
||||
{
|
||||
$con = omb_oauth_consumer();
|
||||
$tok = new OAuthToken($token, $secret);
|
||||
|
||||
$url = omb_service_uri($omb[OAUTH_ENDPOINT_AUTHORIZE]);
|
||||
|
||||
# XXX: Is this the right thing to do? Strip off GET params and make them
|
||||
# POST params? Seems wrong to me.
|
||||
|
||||
$parsed = parse_url($url);
|
||||
$params = array();
|
||||
parse_str($parsed['query'], $params);
|
||||
|
||||
$req = OAuthRequest::from_consumer_and_token($con, $tok, 'GET', $url, $params);
|
||||
|
||||
# We send over a ton of information. This lets the other
|
||||
# server store info about our user, and it lets the current
|
||||
# user decide if they really want to authorize the subscription.
|
||||
|
||||
$req->set_parameter('omb_version', OMB_VERSION_01);
|
||||
$req->set_parameter('omb_listener', omb_local_id($omb[OAUTH_ENDPOINT_REQUEST]));
|
||||
$req->set_parameter('omb_listenee', $user->uri);
|
||||
$req->set_parameter('omb_listenee_profile', common_profile_url($user->nickname));
|
||||
$req->set_parameter('omb_listenee_nickname', $user->nickname);
|
||||
$req->set_parameter('omb_listenee_license', common_config('license', 'url'));
|
||||
|
||||
/* Create an OMB_Profile from $user. */
|
||||
$profile = $user->getProfile();
|
||||
if (!$profile) {
|
||||
common_log_db_error($user, 'SELECT', __FILE__);
|
||||
|
@ -365,49 +196,16 @@ class RemotesubscribeAction extends Action
|
|||
return;
|
||||
}
|
||||
|
||||
if (!is_null($profile->fullname)) {
|
||||
$req->set_parameter('omb_listenee_fullname', $profile->fullname);
|
||||
}
|
||||
if (!is_null($profile->homepage)) {
|
||||
$req->set_parameter('omb_listenee_homepage', $profile->homepage);
|
||||
}
|
||||
if (!is_null($profile->bio)) {
|
||||
$req->set_parameter('omb_listenee_bio', $profile->bio);
|
||||
}
|
||||
if (!is_null($profile->location)) {
|
||||
$req->set_parameter('omb_listenee_location', $profile->location);
|
||||
}
|
||||
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
|
||||
if ($avatar) {
|
||||
$req->set_parameter('omb_listenee_avatar', $avatar->url);
|
||||
}
|
||||
|
||||
# XXX: add a nonce to prevent replay attacks
|
||||
|
||||
$req->set_parameter('oauth_callback', common_local_url('finishremotesubscribe'));
|
||||
|
||||
# XXX: test to see if endpoint accepts this signature method
|
||||
|
||||
$req->sign_request(omb_hmac_sha1(), $con, $tok);
|
||||
|
||||
# store all our info here
|
||||
|
||||
$omb['listenee'] = $user->nickname;
|
||||
$omb['listener'] = omb_local_id($omb[OAUTH_ENDPOINT_REQUEST]);
|
||||
$omb['token'] = $token;
|
||||
$omb['secret'] = $secret;
|
||||
# call doesn't work after bounce back so we cache; maybe serialization issue...?
|
||||
$omb['access_token_url'] = omb_service_uri($omb[OAUTH_ENDPOINT_ACCESS]);
|
||||
$omb['post_notice_url'] = omb_service_uri($omb[OMB_ENDPOINT_POSTNOTICE]);
|
||||
$omb['update_profile_url'] = omb_service_uri($omb[OMB_ENDPOINT_UPDATEPROFILE]);
|
||||
$target_url = $service->requestAuthorization(
|
||||
profile_to_omb_profile($user->uri, $profile),
|
||||
common_local_url('finishremotesubscribe'));
|
||||
|
||||
common_ensure_session();
|
||||
|
||||
$_SESSION['oauth_authorization_request'] = $omb;
|
||||
$_SESSION['oauth_authorization_request'] = serialize($service);
|
||||
|
||||
# Redirect to authorization service
|
||||
|
||||
common_redirect($req->to_url(), 303);
|
||||
return;
|
||||
/* Redirect to the remote service for authorization. */
|
||||
common_redirect($target_url, 303);
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -48,6 +48,7 @@ require_once INSTALLDIR.'/lib/feedlist.php';
|
|||
class RepliesAction extends OwnerDesignAction
|
||||
{
|
||||
var $page = null;
|
||||
var $notice;
|
||||
|
||||
/**
|
||||
* Prepare the object
|
||||
|
@ -84,6 +85,13 @@ class RepliesAction extends OwnerDesignAction
|
|||
|
||||
common_set_returnto($this->selfUrl());
|
||||
|
||||
$this->notice = $this->user->getReplies(($this->page-1) * NOTICES_PER_PAGE,
|
||||
NOTICES_PER_PAGE + 1);
|
||||
|
||||
if($this->page > 1 && $this->notice->N == 0){
|
||||
$this->serverError(_('No such page'),$code=404);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -159,10 +167,7 @@ class RepliesAction extends OwnerDesignAction
|
|||
|
||||
function showContent()
|
||||
{
|
||||
$notice = $this->user->getReplies(($this->page-1) * NOTICES_PER_PAGE,
|
||||
NOTICES_PER_PAGE + 1);
|
||||
|
||||
$nl = new NoticeList($notice, $this);
|
||||
$nl = new NoticeList($this->notice, $this);
|
||||
|
||||
$cnt = $nl->show();
|
||||
if (0 === $cnt) {
|
||||
|
@ -187,7 +192,9 @@ class RepliesAction extends OwnerDesignAction
|
|||
}
|
||||
}
|
||||
else {
|
||||
$message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname);
|
||||
$message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and then nudge %s or post a notice to his or her attention.'),
|
||||
(!common_config('site','openidonly')) ? 'register' : 'openidlogin',
|
||||
$this->user->nickname);
|
||||
}
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
|
|
|
@ -68,7 +68,8 @@ class RepliesrssAction extends Rss10Action
|
|||
'link' => common_local_url('replies',
|
||||
array('nickname' =>
|
||||
$user->nickname)),
|
||||
'description' => sprintf(_('Feed for replies to %s'), $user->nickname));
|
||||
'description' => sprintf(_('Replies to %1$s on %2$s!'),
|
||||
$user->nickname, common_config('site', 'name')));
|
||||
return $c;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ if (!defined('LACONICA')) {
|
|||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/omb.php';
|
||||
require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
|
||||
|
||||
/**
|
||||
* Request token action class.
|
||||
|
@ -49,17 +50,17 @@ class RequesttokenAction extends Action
|
|||
{
|
||||
/**
|
||||
* Is read only?
|
||||
*
|
||||
*
|
||||
* @return boolean false
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
function isReadOnly()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class handler.
|
||||
*
|
||||
*
|
||||
* @param array $args array of arguments
|
||||
*
|
||||
* @return void
|
||||
|
@ -68,14 +69,12 @@ class RequesttokenAction extends Action
|
|||
{
|
||||
parent::handle($args);
|
||||
try {
|
||||
common_remove_magic_from_request();
|
||||
$req = OAuthRequest::from_request('POST', common_local_url('requesttoken'));
|
||||
$server = omb_oauth_server();
|
||||
$token = $server->fetch_request_token($req);
|
||||
print $token;
|
||||
} catch (OAuthException $e) {
|
||||
$srv = new OMB_Service_Provider(null, omb_oauth_datastore(),
|
||||
omb_oauth_server());
|
||||
$srv->writeRequestToken();
|
||||
} catch (Exception $e) {
|
||||
$this->serverError($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
|
@ -114,6 +114,29 @@ class ShowfavoritesAction extends OwnerDesignAction
|
|||
|
||||
common_set_returnto($this->selfUrl());
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
if (!empty($cur) && $cur->id == $this->user->id) {
|
||||
|
||||
// Show imported/gateway notices as well as local if
|
||||
// the user is looking at his own favorites
|
||||
|
||||
$this->notice = $this->user->favoriteNotices(($this->page-1)*NOTICES_PER_PAGE,
|
||||
NOTICES_PER_PAGE + 1, true);
|
||||
} else {
|
||||
$this->notice = $this->user->favoriteNotices(($this->page-1)*NOTICES_PER_PAGE,
|
||||
NOTICES_PER_PAGE + 1, false);
|
||||
}
|
||||
|
||||
if (empty($this->notice)) {
|
||||
$this->serverError(_('Could not retrieve favorite notices.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if($this->page > 1 && $this->notice->N == 0){
|
||||
$this->serverError(_('No such page'),$code=404);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -173,7 +196,9 @@ class ShowfavoritesAction extends OwnerDesignAction
|
|||
}
|
||||
}
|
||||
else {
|
||||
$message = sprintf(_('%s hasn\'t added any notices to his favorites yet. Why not [register an account](%%%%action.register%%%%) and then post something interesting they would add to thier favorites :)'), $this->user->nickname);
|
||||
$message = sprintf(_('%s hasn\'t added any notices to his favorites yet. Why not [register an account](%%%%action.%s%%%%) and then post something interesting they would add to their favorites :)'),
|
||||
$this->user->nickname,
|
||||
(!common_config('site','openidonly')) ? 'register' : 'openidlogin');
|
||||
}
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
|
@ -191,26 +216,7 @@ class ShowfavoritesAction extends OwnerDesignAction
|
|||
|
||||
function showContent()
|
||||
{
|
||||
$cur = common_current_user();
|
||||
|
||||
if (!empty($cur) && $cur->id == $this->user->id) {
|
||||
|
||||
// Show imported/gateway notices as well as local if
|
||||
// the user is looking at his own favorites
|
||||
|
||||
$notice = $this->user->favoriteNotices(($this->page-1)*NOTICES_PER_PAGE,
|
||||
NOTICES_PER_PAGE + 1, true);
|
||||
} else {
|
||||
$notice = $this->user->favoriteNotices(($this->page-1)*NOTICES_PER_PAGE,
|
||||
NOTICES_PER_PAGE + 1, false);
|
||||
}
|
||||
|
||||
if (empty($notice)) {
|
||||
$this->serverError(_('Could not retrieve favorite notices.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$nl = new NoticeList($notice, $this);
|
||||
$nl = new NoticeList($this->notice, $this);
|
||||
|
||||
$cnt = $nl->show();
|
||||
if (0 == $cnt) {
|
||||
|
|
|
@ -130,8 +130,18 @@ class ShowgroupAction extends GroupDesignAction
|
|||
$this->group = User_group::staticGet('nickname', $nickname);
|
||||
|
||||
if (!$this->group) {
|
||||
$this->clientError(_('No such group'), 404);
|
||||
return false;
|
||||
$alias = Group_alias::staticGet('alias', $nickname);
|
||||
if ($alias) {
|
||||
$args = array('id' => $alias->group_id);
|
||||
if ($this->page != 1) {
|
||||
$args['page'] = $this->page;
|
||||
}
|
||||
common_redirect(common_local_url('groupbyid', $args), 301);
|
||||
return false;
|
||||
} else {
|
||||
$this->clientError(_('No such group'), 404);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
common_set_returnto($this->selfUrl());
|
||||
|
@ -440,8 +450,9 @@ class ShowgroupAction extends GroupDesignAction
|
|||
$m = sprintf(_('**%s** is a user group on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
|
||||
'based on the Free Software [Laconica](http://laconi.ca/) tool. Its members share ' .
|
||||
'short messages about their life and interests. '.
|
||||
'[Join now](%%%%action.register%%%%) to become part of this group and many more! ([Read more](%%%%doc.help%%%%))'),
|
||||
$this->group->nickname);
|
||||
'[Join now](%%%%action.%s%%%%) to become part of this group and many more! ([Read more](%%%%doc.help%%%%))'),
|
||||
$this->group->nickname,
|
||||
(!common_config('site','openidonly')) ? 'register' : 'openidlogin');
|
||||
} else {
|
||||
$m = sprintf(_('**%s** is a user group on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
|
||||
'based on the Free Software [Laconica](http://laconi.ca/) tool. Its members share ' .
|
||||
|
|
|
@ -103,8 +103,8 @@ class ShownoticeAction extends OwnerDesignAction
|
|||
|
||||
$this->user = User::staticGet('id', $this->profile->id);
|
||||
|
||||
if (empty($this->user)) {
|
||||
$this->serverError(_('Not a local notice'), 500);
|
||||
if (! $this->notice->is_local) {
|
||||
common_redirect($this->notice->uri);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -196,7 +196,7 @@ class ShownoticeAction extends OwnerDesignAction
|
|||
{
|
||||
parent::handle($args);
|
||||
|
||||
if ($this->notice->is_local == 0) {
|
||||
if ($this->notice->is_local == Notice::REMOTE_OMB) {
|
||||
if (!empty($this->notice->url)) {
|
||||
common_redirect($this->notice->url, 301);
|
||||
} else if (!empty($this->notice->uri) && preg_match('/^https?:/', $this->notice->uri)) {
|
||||
|
@ -284,16 +284,16 @@ class ShownoticeAction extends OwnerDesignAction
|
|||
$this->element('link',array('rel'=>'alternate',
|
||||
'type'=>'application/json+oembed',
|
||||
'href'=>common_local_url(
|
||||
'api',
|
||||
array('apiaction'=>'oembed','method'=>'oembed.json'),
|
||||
array('url'=>$this->notice->uri)),
|
||||
'oembed',
|
||||
array(),
|
||||
array('format'=>'json','url'=>$this->notice->uri)),
|
||||
'title'=>'oEmbed'),null);
|
||||
$this->element('link',array('rel'=>'alternate',
|
||||
'type'=>'text/xml+oembed',
|
||||
'href'=>common_local_url(
|
||||
'api',
|
||||
array('apiaction'=>'oembed','method'=>'oembed.xml'),
|
||||
array('url'=>$this->notice->uri)),
|
||||
'oembed',
|
||||
array(),
|
||||
array('format'=>'xml','url'=>$this->notice->uri)),
|
||||
'title'=>'oEmbed'),null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -358,7 +358,9 @@ class ShowstreamAction extends ProfileAction
|
|||
}
|
||||
}
|
||||
else {
|
||||
$message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname);
|
||||
$message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and then nudge %s or post a notice to his or her attention.'),
|
||||
(!common_config('site','openidonly')) ? 'register' : 'openidlogin',
|
||||
$this->user->nickname);
|
||||
}
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
|
@ -387,8 +389,10 @@ class ShowstreamAction extends ProfileAction
|
|||
if (!(common_config('site','closed') || common_config('site','inviteonly'))) {
|
||||
$m = sprintf(_('**%s** has an account on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
|
||||
'based on the Free Software [Laconica](http://laconi.ca/) tool. ' .
|
||||
'[Join now](%%%%action.register%%%%) to follow **%s**\'s notices and many more! ([Read more](%%%%doc.help%%%%))'),
|
||||
$this->user->nickname, $this->user->nickname);
|
||||
'[Join now](%%%%action.%s%%%%) to follow **%s**\'s notices and many more! ([Read more](%%%%doc.help%%%%))'),
|
||||
$this->user->nickname,
|
||||
(!common_config('site','openidonly')) ? 'register' : 'openidlogin',
|
||||
$this->user->nickname);
|
||||
} else {
|
||||
$m = sprintf(_('**%s** has an account on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
|
||||
'based on the Free Software [Laconica](http://laconi.ca/) tool. '),
|
||||
|
|
|
@ -80,6 +80,12 @@ class SmssettingsAction extends ConnectSettingsAction
|
|||
|
||||
function showContent()
|
||||
{
|
||||
if (!common_config('sms', 'enabled')) {
|
||||
$this->element('div', array('class' => 'error'),
|
||||
_('SMS is not available.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$user = common_current_user();
|
||||
|
||||
$this->elementStart('form', array('method' => 'post',
|
||||
|
|
|
@ -111,7 +111,9 @@ class SubscribersAction extends GalleryAction
|
|||
}
|
||||
}
|
||||
else {
|
||||
$message = sprintf(_('%s has no subscribers. Why not [register an account](%%%%action.register%%%%) and be the first?'), $this->user->nickname);
|
||||
$message = sprintf(_('%s has no subscribers. Why not [register an account](%%%%action.%s%%%%) and be the first?'),
|
||||
$this->user->nickname,
|
||||
(!common_config('site','openidonly')) ? 'register' : 'openidlogin');
|
||||
}
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
|
|
|
@ -174,14 +174,26 @@ class SubscriptionsListItem extends SubscriptionListItem
|
|||
return;
|
||||
}
|
||||
|
||||
if (!common_config('xmpp', 'enabled') && !common_config('sms', 'enabled')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->out->elementStart('form', array('id' => 'subedit-' . $this->profile->id,
|
||||
'method' => 'post',
|
||||
'class' => 'form_subscription_edit',
|
||||
'action' => common_local_url('subedit')));
|
||||
$this->out->hidden('token', common_session_token());
|
||||
$this->out->hidden('profile', $this->profile->id);
|
||||
$this->out->checkbox('jabber', _('Jabber'), $sub->jabber);
|
||||
$this->out->checkbox('sms', _('SMS'), $sub->sms);
|
||||
if (common_config('xmpp', 'enabled')) {
|
||||
$this->out->checkbox('jabber', _('Jabber'), $sub->jabber);
|
||||
} else {
|
||||
$this->out->hidden('jabber', $sub->jabber);
|
||||
}
|
||||
if (common_config('sms', 'enabled')) {
|
||||
$this->out->checkbox('sms', _('SMS'), $sub->sms);
|
||||
} else {
|
||||
$this->out->hidden('sms', $sub->sms);
|
||||
}
|
||||
$this->out->submit('save', _('Save'));
|
||||
$this->out->elementEnd('form');
|
||||
return;
|
||||
|
|
|
@ -21,6 +21,9 @@ if (!defined('LACONICA')) { exit(1); }
|
|||
|
||||
class TagAction extends Action
|
||||
{
|
||||
|
||||
var $notice;
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
@ -42,6 +45,12 @@ class TagAction extends Action
|
|||
|
||||
common_set_returnto($this->selfUrl());
|
||||
|
||||
$this->notice = Notice_tag::getStream($this->tag, (($this->page-1)*NOTICES_PER_PAGE), NOTICES_PER_PAGE + 1);
|
||||
|
||||
if($this->page > 1 && $this->notice->N == 0){
|
||||
$this->serverError(_('No such page'),$code=404);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -94,9 +103,7 @@ class TagAction extends Action
|
|||
|
||||
function showContent()
|
||||
{
|
||||
$notice = Notice_tag::getStream($this->tag, (($this->page-1)*NOTICES_PER_PAGE), NOTICES_PER_PAGE + 1);
|
||||
|
||||
$nl = new NoticeList($notice, $this);
|
||||
$nl = new NoticeList($this->notice, $this);
|
||||
|
||||
$cnt = $nl->show();
|
||||
|
||||
|
|
|
@ -61,7 +61,8 @@ class TagrssAction extends Rss10Action
|
|||
$c = array('url' => common_local_url('tagrss', array('tag' => $tagname)),
|
||||
'title' => $tagname,
|
||||
'link' => common_local_url('tagrss', array('tag' => $tagname)),
|
||||
'description' => sprintf(_('Microblog tagged with %s'), $tagname));
|
||||
'description' => sprintf(_('Updates tagged with %1$s on %2$s!'),
|
||||
$tagname, common_config('site', 'name')));
|
||||
return $c;
|
||||
}
|
||||
|
||||
|
|
|
@ -141,9 +141,10 @@ class Twitapidirect_messagesAction extends TwitterapiAction
|
|||
$code = 406, $apidata['content-type']);
|
||||
} else {
|
||||
$content_shortened = common_shorten_links($content);
|
||||
if (mb_strlen($content_shortened) > 140) {
|
||||
$this->clientError(_('That\'s too long. Max message size is 140 chars.'),
|
||||
$code = 406, $apidata['content-type']);
|
||||
if (Message::contentTooLong($content_shortened)) {
|
||||
$this->clientError(sprintf(_('That\'s too long. Max message size is %d chars.'),
|
||||
Message::maxContent()),
|
||||
$code = 406, $apidata['content-type']);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,103 @@ require_once INSTALLDIR.'/lib/twitterapi.php';
|
|||
class TwitapigroupsAction extends TwitterapiAction
|
||||
{
|
||||
|
||||
function list_groups($args, $apidata)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
common_debug("in groups api action");
|
||||
|
||||
$this->auth_user = $apidata['user'];
|
||||
$user = $this->get_user($apidata['api_arg'], $apidata);
|
||||
|
||||
if (empty($user)) {
|
||||
$this->clientError('Not Found', 404, $apidata['content-type']);
|
||||
return;
|
||||
}
|
||||
|
||||
$page = (int)$this->arg('page', 1);
|
||||
$count = (int)$this->arg('count', 20);
|
||||
$max_id = (int)$this->arg('max_id', 0);
|
||||
$since_id = (int)$this->arg('since_id', 0);
|
||||
$since = $this->arg('since');
|
||||
$group = $user->getGroups(($page-1)*$count,
|
||||
$count, $since_id, $max_id, $since);
|
||||
|
||||
$sitename = common_config('site', 'name');
|
||||
$title = sprintf(_("%s's groups"), $user->nickname);
|
||||
$taguribase = common_config('integration', 'taguri');
|
||||
$id = "tag:$taguribase:Groups";
|
||||
$link = common_root_url();
|
||||
$subtitle = sprintf(_("groups %s is a member of on %s"), $user->nickname, $sitename);
|
||||
|
||||
switch($apidata['content-type']) {
|
||||
case 'xml':
|
||||
$this->show_xml_groups($group);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->show_rss_groups($group, $title, $link, $subtitle);
|
||||
break;
|
||||
case 'atom':
|
||||
$selfuri = common_root_url() . 'api/laconica/groups/list/' . $user->id . '.atom';
|
||||
$this->show_atom_groups($group, $title, $id, $link,
|
||||
$subtitle, $selfuri);
|
||||
break;
|
||||
case 'json':
|
||||
$this->show_json_groups($group);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function list_all($args, $apidata)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
common_debug("in groups api action");
|
||||
|
||||
$page = (int)$this->arg('page', 1);
|
||||
$count = (int)$this->arg('count', 20);
|
||||
$max_id = (int)$this->arg('max_id', 0);
|
||||
$since_id = (int)$this->arg('since_id', 0);
|
||||
$since = $this->arg('since');
|
||||
|
||||
/* TODO:
|
||||
Use the $page, $count, $max_id, $since_id, and $since parameters
|
||||
*/
|
||||
$group = new User_group();
|
||||
$group->orderBy('created DESC');
|
||||
$group->find();
|
||||
|
||||
$sitename = common_config('site', 'name');
|
||||
$title = sprintf(_("%s groups"), $sitename);
|
||||
$taguribase = common_config('integration', 'taguri');
|
||||
$id = "tag:$taguribase:Groups";
|
||||
$link = common_root_url();
|
||||
$subtitle = sprintf(_("groups on %s"), $sitename);
|
||||
|
||||
switch($apidata['content-type']) {
|
||||
case 'xml':
|
||||
$this->show_xml_groups($group);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->show_rss_groups($group, $title, $link, $subtitle);
|
||||
break;
|
||||
case 'atom':
|
||||
$selfuri = common_root_url() . 'api/laconica/groups/list_all.atom';
|
||||
$this->show_atom_groups($group, $title, $id, $link,
|
||||
$subtitle, $selfuri);
|
||||
break;
|
||||
case 'json':
|
||||
$this->show_json_groups($group);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function show($args, $apidata)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
|
|
@ -242,14 +242,15 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||
|
||||
$status_shortened = common_shorten_links($status);
|
||||
|
||||
if (mb_strlen($status_shortened) > 140) {
|
||||
if (Notice::contentTooLong($status_shortened)) {
|
||||
|
||||
// XXX: Twitter truncates anything over 140, flags the status
|
||||
// as "truncated." Sending this error may screw up some clients
|
||||
// that assume Twitter will truncate for them. Should we just
|
||||
// truncate too? -- Zach
|
||||
$this->clientError(_('That\'s too long. Max notice size is 140 chars.'),
|
||||
$code = 406, $apidata['content-type']);
|
||||
$this->clientError(sprintf(_('That\'s too long. Max notice size is %d chars.'),
|
||||
Notice::maxContent()),
|
||||
$code = 406, $apidata['content-type']);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -455,7 +456,8 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||
function friends($args, $apidata)
|
||||
{
|
||||
parent::handle($args);
|
||||
return $this->subscriptions($apidata, 'subscribed', 'subscriber');
|
||||
$includeStatuses=! (boolean) $args['lite'];
|
||||
return $this->subscriptions($apidata, 'subscribed', 'subscriber', false, $includeStatuses);
|
||||
}
|
||||
|
||||
function friendsIDs($args, $apidata)
|
||||
|
@ -467,7 +469,8 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||
function followers($args, $apidata)
|
||||
{
|
||||
parent::handle($args);
|
||||
return $this->subscriptions($apidata, 'subscriber', 'subscribed');
|
||||
$includeStatuses=! (boolean) $args['lite'];
|
||||
return $this->subscriptions($apidata, 'subscriber', 'subscribed', false, $includeStatuses);
|
||||
}
|
||||
|
||||
function followersIDs($args, $apidata)
|
||||
|
@ -476,7 +479,7 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||
return $this->subscriptions($apidata, 'subscriber', 'subscribed', true);
|
||||
}
|
||||
|
||||
function subscriptions($apidata, $other_attr, $user_attr, $onlyIDs=false)
|
||||
function subscriptions($apidata, $other_attr, $user_attr, $onlyIDs=false, $includeStatuses=true)
|
||||
{
|
||||
$this->auth_user = $apidata['user'];
|
||||
$user = $this->get_user($apidata['api_arg'], $apidata);
|
||||
|
@ -532,26 +535,26 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||
if ($onlyIDs) {
|
||||
$this->showIDs($others, $type);
|
||||
} else {
|
||||
$this->show_profiles($others, $type);
|
||||
$this->show_profiles($others, $type, $includeStatuses);
|
||||
}
|
||||
|
||||
$this->end_document($type);
|
||||
}
|
||||
|
||||
function show_profiles($profiles, $type)
|
||||
function show_profiles($profiles, $type, $includeStatuses)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'xml':
|
||||
$this->elementStart('users', array('type' => 'array'));
|
||||
foreach ($profiles as $profile) {
|
||||
$this->show_profile($profile);
|
||||
$this->show_profile($profile,$type,null,$includeStatuses);
|
||||
}
|
||||
$this->elementEnd('users');
|
||||
break;
|
||||
case 'json':
|
||||
$arrays = array();
|
||||
foreach ($profiles as $profile) {
|
||||
$arrays[] = $this->twitter_user_array($profile, true);
|
||||
$arrays[] = $this->twitter_user_array($profile, $includeStatuses);
|
||||
}
|
||||
print json_encode($arrays);
|
||||
break;
|
||||
|
|
222
actions/twitterauthorization.php
Normal file
222
actions/twitterauthorization.php
Normal file
|
@ -0,0 +1,222 @@
|
|||
<?php
|
||||
/**
|
||||
* Laconica, the distributed open-source microblogging tool
|
||||
*
|
||||
* Class for doing OAuth authentication against Twitter
|
||||
*
|
||||
* 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 Twitter
|
||||
* @package Laconica
|
||||
* @author Zach Copely <zach@controlyourself.ca>
|
||||
* @copyright 2009 Control Yourself, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
if (!defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for doing OAuth authentication against Twitter
|
||||
*
|
||||
* Peforms the OAuth "dance" between Laconica and Twitter -- requests a token,
|
||||
* authorizes it, and exchanges it for an access token. It also creates a link
|
||||
* (Foreign_link) between the Laconica user and Twitter user and stores the
|
||||
* access token and secret in the link.
|
||||
*
|
||||
* @category Twitter
|
||||
* @package Laconica
|
||||
* @author Zach Copley <zach@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*
|
||||
*/
|
||||
class TwitterauthorizationAction extends Action
|
||||
{
|
||||
/**
|
||||
* Initialize class members. Looks for 'oauth_token' parameter.
|
||||
*
|
||||
* @param array $args misc. arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->oauth_token = $this->arg('oauth_token');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler method
|
||||
*
|
||||
* @param array $args is ignored since it's now passed in in prepare()
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if (!common_logged_in()) {
|
||||
$this->clientError(_('Not logged in.'), 403);
|
||||
}
|
||||
|
||||
$user = common_current_user();
|
||||
$flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
|
||||
|
||||
// If there's already a foreign link record, it means we already
|
||||
// have an access token, and this is unecessary. So go back.
|
||||
|
||||
if (isset($flink)) {
|
||||
common_redirect(common_local_url('twittersettings'));
|
||||
}
|
||||
|
||||
// $this->oauth_token is only populated once Twitter authorizes our
|
||||
// request token. If it's empty we're at the beginning of the auth
|
||||
// process
|
||||
|
||||
if (empty($this->oauth_token)) {
|
||||
$this->authorizeRequestToken();
|
||||
} else {
|
||||
$this->saveAccessToken();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks Twitter for a request token, and then redirects to Twitter
|
||||
* to authorize it.
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function authorizeRequestToken()
|
||||
{
|
||||
try {
|
||||
|
||||
// Get a new request token and authorize it
|
||||
|
||||
$client = new TwitterOAuthClient();
|
||||
$req_tok =
|
||||
$client->getRequestToken(TwitterOAuthClient::$requestTokenURL);
|
||||
|
||||
// Sock the request token away in the session temporarily
|
||||
|
||||
$_SESSION['twitter_request_token'] = $req_tok->key;
|
||||
$_SESSION['twitter_request_token_secret'] = $req_tok->secret;
|
||||
|
||||
$auth_link = $client->getAuthorizeLink($req_tok);
|
||||
|
||||
} catch (TwitterOAuthClientException $e) {
|
||||
$msg = sprintf('OAuth client cURL error - code: %1s, msg: %2s',
|
||||
$e->getCode(), $e->getMessage());
|
||||
$this->serverError(_('Couldn\'t link your Twitter account.'));
|
||||
}
|
||||
|
||||
common_redirect($auth_link);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when Twitter returns an authorized request token. Exchanges
|
||||
* it for an access token and stores it.
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function saveAccessToken()
|
||||
{
|
||||
|
||||
// Check to make sure Twitter returned the same request
|
||||
// token we sent them
|
||||
|
||||
if ($_SESSION['twitter_request_token'] != $this->oauth_token) {
|
||||
$this->serverError(_('Couldn\'t link your Twitter account.'));
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
$client = new TwitterOAuthClient($_SESSION['twitter_request_token'],
|
||||
$_SESSION['twitter_request_token_secret']);
|
||||
|
||||
// Exchange the request token for an access token
|
||||
|
||||
$atok = $client->getAccessToken(TwitterOAuthClient::$accessTokenURL);
|
||||
|
||||
// Test the access token and get the user's Twitter info
|
||||
|
||||
$client = new TwitterOAuthClient($atok->key, $atok->secret);
|
||||
$twitter_user = $client->verifyCredentials();
|
||||
|
||||
} catch (OAuthClientException $e) {
|
||||
$msg = sprintf('OAuth client cURL error - code: %1$s, msg: %2$s',
|
||||
$e->getCode(), $e->getMessage());
|
||||
$this->serverError(_('Couldn\'t link your Twitter account.'));
|
||||
}
|
||||
|
||||
// Save the access token and Twitter user info
|
||||
|
||||
$this->saveForeignLink($atok, $twitter_user);
|
||||
|
||||
// Clean up the the mess we made in the session
|
||||
|
||||
unset($_SESSION['twitter_request_token']);
|
||||
unset($_SESSION['twitter_request_token_secret']);
|
||||
|
||||
common_redirect(common_local_url('twittersettings'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a Foreign_link between Twitter user and local user,
|
||||
* which includes the access token and secret.
|
||||
*
|
||||
* @param OAuthToken $access_token the access token to save
|
||||
* @param mixed $twitter_user twitter API user object
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function saveForeignLink($access_token, $twitter_user)
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$flink = new Foreign_link();
|
||||
|
||||
$flink->user_id = $user->id;
|
||||
$flink->foreign_id = $twitter_user->id;
|
||||
$flink->service = TWITTER_SERVICE;
|
||||
|
||||
$creds = TwitterOAuthClient::packToken($access_token);
|
||||
|
||||
$flink->credentials = $creds;
|
||||
$flink->created = common_sql_now();
|
||||
|
||||
// Defaults: noticesync on, everything else off
|
||||
|
||||
$flink->set_flags(true, false, false, false);
|
||||
|
||||
$flink_id = $flink->insert();
|
||||
|
||||
if (empty($flink_id)) {
|
||||
common_log_db_error($flink, 'INSERT', __FILE__);
|
||||
$this->serverError(_('Couldn\'t link your Twitter account.'));
|
||||
}
|
||||
|
||||
save_twitter_user($twitter_user->id, $twitter_user->screen_name);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -34,8 +34,6 @@ if (!defined('LACONICA')) {
|
|||
require_once INSTALLDIR.'/lib/connectsettingsaction.php';
|
||||
require_once INSTALLDIR.'/lib/twitter.php';
|
||||
|
||||
define('SUBSCRIPTIONS', 80);
|
||||
|
||||
/**
|
||||
* Settings for Twitter integration
|
||||
*
|
||||
|
@ -69,9 +67,8 @@ class TwittersettingsAction extends ConnectSettingsAction
|
|||
|
||||
function getInstructions()
|
||||
{
|
||||
return _('Add your Twitter account to automatically send '.
|
||||
' your notices to Twitter, ' .
|
||||
'and subscribe to Twitter friends already here.');
|
||||
return _('Connect your Twitter account to share your updates ' .
|
||||
'with your Twitter friends and vice-versa.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -85,6 +82,12 @@ class TwittersettingsAction extends ConnectSettingsAction
|
|||
|
||||
function showContent()
|
||||
{
|
||||
if (!common_config('twitter', 'enabled')) {
|
||||
$this->element('div', array('class' => 'error'),
|
||||
_('Twitter is not available.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$user = common_current_user();
|
||||
|
||||
$profile = $user->getProfile();
|
||||
|
@ -93,7 +96,7 @@ class TwittersettingsAction extends ConnectSettingsAction
|
|||
|
||||
$flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
|
||||
|
||||
if ($flink) {
|
||||
if (!empty($flink)) {
|
||||
$fuser = $flink->getForeignUser();
|
||||
}
|
||||
|
||||
|
@ -102,192 +105,86 @@ class TwittersettingsAction extends ConnectSettingsAction
|
|||
'class' => 'form_settings',
|
||||
'action' =>
|
||||
common_local_url('twittersettings')));
|
||||
$this->elementStart('fieldset', array('id' => 'settings_twitter_account'));
|
||||
$this->element('legend', null, _('Twitter Account'));
|
||||
|
||||
$this->hidden('token', common_session_token());
|
||||
if ($fuser) {
|
||||
|
||||
$this->elementStart('fieldset', array('id' => 'settings_twitter_account'));
|
||||
|
||||
if (empty($fuser)) {
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li', array('id' => 'settings_twitter_remove'));
|
||||
$this->element('span', 'twitter_user', $fuser->nickname);
|
||||
$this->element('a', array('href' => $fuser->uri), $fuser->uri);
|
||||
$this->element('p', 'form_note',
|
||||
_('Current verified Twitter account.'));
|
||||
$this->hidden('flink_foreign_id', $flink->foreign_id);
|
||||
$this->elementStart('li', array('id' => 'settings_twitter_login_button'));
|
||||
$this->element('a', array('href' => common_local_url('twitterauthorization')),
|
||||
'Connect my Twitter account');
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
$this->submit('remove', _('Remove'));
|
||||
|
||||
$this->elementEnd('fieldset');
|
||||
} else {
|
||||
$this->element('legend', null, _('Twitter account'));
|
||||
$this->elementStart('p', array('id' => 'form_confirmed'));
|
||||
$this->element('a', array('href' => $fuser->uri), $fuser->nickname);
|
||||
$this->elementEnd('p');
|
||||
$this->element('p', 'form_note',
|
||||
_('Connected Twitter account'));
|
||||
|
||||
$this->submit('remove', _('Remove'));
|
||||
|
||||
$this->elementEnd('fieldset');
|
||||
|
||||
$this->elementStart('fieldset', array('id' => 'settings_twitter_preferences'));
|
||||
|
||||
$this->element('legend', null, _('Preferences'));
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li', array('id' => 'settings_twitter_login'));
|
||||
$this->input('twitter_username', _('Twitter user name'),
|
||||
($this->arg('twitter_username')) ?
|
||||
$this->arg('twitter_username') :
|
||||
$profile->nickname,
|
||||
_('No spaces, please.')); // hey, it's what Twitter says
|
||||
$this->elementStart('li');
|
||||
$this->checkbox('noticesend',
|
||||
_('Automatically send my notices to Twitter.'),
|
||||
($flink) ?
|
||||
($flink->noticesync & FOREIGN_NOTICE_SEND) :
|
||||
true);
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->password('twitter_password', _('Twitter password'));
|
||||
$this->elementend('li');
|
||||
$this->elementEnd('ul');
|
||||
}
|
||||
$this->elementEnd('fieldset');
|
||||
|
||||
$this->elementStart('fieldset',
|
||||
array('id' => 'settings_twitter_preferences'));
|
||||
$this->element('legend', null, _('Preferences'));
|
||||
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->checkbox('noticesend',
|
||||
_('Automatically send my notices to Twitter.'),
|
||||
($flink) ?
|
||||
($flink->noticesync & FOREIGN_NOTICE_SEND) :
|
||||
true);
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->checkbox('replysync',
|
||||
_('Send local "@" replies to Twitter.'),
|
||||
($flink) ?
|
||||
($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY) :
|
||||
true);
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->checkbox('friendsync',
|
||||
_('Subscribe to my Twitter friends here.'),
|
||||
($flink) ?
|
||||
($flink->friendsync & FOREIGN_FRIEND_RECV) :
|
||||
false);
|
||||
$this->elementEnd('li');
|
||||
|
||||
if (common_config('twitterbridge','enabled')) {
|
||||
$this->elementStart('li');
|
||||
$this->checkbox('noticerecv',
|
||||
_('Import my Friends Timeline.'),
|
||||
$this->checkbox('replysync',
|
||||
_('Send local "@" replies to Twitter.'),
|
||||
($flink) ?
|
||||
($flink->noticesync & FOREIGN_NOTICE_RECV) :
|
||||
($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY) :
|
||||
true);
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->checkbox('friendsync',
|
||||
_('Subscribe to my Twitter friends here.'),
|
||||
($flink) ?
|
||||
($flink->friendsync & FOREIGN_FRIEND_RECV) :
|
||||
false);
|
||||
$this->elementEnd('li');
|
||||
} else {
|
||||
// preserve setting even if bidrection bridge toggled off
|
||||
if ($flink && ($flink->noticesync & FOREIGN_NOTICE_RECV)) {
|
||||
$this->hidden('noticerecv', true, 'noticerecv');
|
||||
}
|
||||
}
|
||||
|
||||
$this->elementEnd('ul');
|
||||
|
||||
if ($flink) {
|
||||
$this->submit('save', _('Save'));
|
||||
} else {
|
||||
$this->submit('add', _('Add'));
|
||||
}
|
||||
$this->elementEnd('fieldset');
|
||||
|
||||
$this->showTwitterSubscriptions();
|
||||
|
||||
$this->elementEnd('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets some of the user's Twitter friends
|
||||
*
|
||||
* Gets the number of Twitter friends that are on this
|
||||
* instance of Laconica.
|
||||
*
|
||||
* @return array array of User objects
|
||||
*/
|
||||
|
||||
function subscribedTwitterUsers()
|
||||
{
|
||||
|
||||
$current_user = common_current_user();
|
||||
|
||||
$qry = 'SELECT "user".* ' .
|
||||
'FROM subscription ' .
|
||||
'JOIN "user" ON subscription.subscribed = "user".id ' .
|
||||
'JOIN foreign_link ON foreign_link.user_id = "user".id ' .
|
||||
'WHERE subscriber = %d ' .
|
||||
'ORDER BY "user".nickname';
|
||||
|
||||
$user = new User();
|
||||
|
||||
$user->query(sprintf($qry, $current_user->id));
|
||||
|
||||
$users = array();
|
||||
|
||||
while ($user->fetch()) {
|
||||
|
||||
// Don't include the user's own self-subscription
|
||||
if ($user->id != $current_user->id) {
|
||||
$users[] = clone($user);
|
||||
}
|
||||
}
|
||||
|
||||
return $users;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show user's Twitter friends
|
||||
*
|
||||
* Gets the number of Twitter friends that are on this
|
||||
* instance of Laconica, and shows their mini-avatars.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showTwitterSubscriptions()
|
||||
{
|
||||
|
||||
$friends = $this->subscribedTwitterUsers();
|
||||
|
||||
$friends_count = count($friends);
|
||||
|
||||
if ($friends_count > 0) {
|
||||
$this->elementStart('div', array('id' => 'entity_subscriptions',
|
||||
'class' => 'section'));
|
||||
$this->element('h2', null, _('Twitter Friends'));
|
||||
$this->elementStart('ul', 'entities users xoxo');
|
||||
|
||||
for ($i = 0; $i < min($friends_count, SUBSCRIPTIONS); $i++) {
|
||||
|
||||
$other = Profile::staticGet($friends[$i]->id);
|
||||
|
||||
if (!$other) {
|
||||
common_log_db_error($subs, 'SELECT', __FILE__);
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->elementStart('li', 'vcard');
|
||||
$this->elementStart('a', array('title' => ($other->fullname) ?
|
||||
$other->fullname :
|
||||
$other->nickname,
|
||||
'href' => $other->profileurl,
|
||||
'class' => 'url'));
|
||||
|
||||
$avatar = $other->getAvatar(AVATAR_MINI_SIZE);
|
||||
|
||||
$avatar_url = ($avatar) ?
|
||||
$avatar->displayUrl() :
|
||||
Avatar::defaultImage(AVATAR_MINI_SIZE);
|
||||
|
||||
$this->element('img', array('src' => $avatar_url,
|
||||
'width' => AVATAR_MINI_SIZE,
|
||||
'height' => AVATAR_MINI_SIZE,
|
||||
'class' => 'avatar photo',
|
||||
'alt' => ($other->fullname) ?
|
||||
$other->fullname :
|
||||
$other->nickname));
|
||||
|
||||
$this->element('span', 'fn nickname', $other->nickname);
|
||||
$this->elementEnd('a');
|
||||
if (common_config('twitterbridge','enabled')) {
|
||||
$this->elementStart('li');
|
||||
$this->checkbox('noticerecv',
|
||||
_('Import my Friends Timeline.'),
|
||||
($flink) ?
|
||||
($flink->noticesync & FOREIGN_NOTICE_RECV) :
|
||||
false);
|
||||
$this->elementEnd('li');
|
||||
|
||||
// preserve setting even if bidrection bridge toggled off
|
||||
|
||||
if ($flink && ($flink->noticesync & FOREIGN_NOTICE_RECV)) {
|
||||
$this->hidden('noticerecv', true, 'noticerecv');
|
||||
}
|
||||
}
|
||||
|
||||
$this->elementEnd('ul');
|
||||
$this->elementEnd('div');
|
||||
|
||||
if ($flink) {
|
||||
$this->submit('save', _('Save'));
|
||||
} else {
|
||||
$this->submit('add', _('Add'));
|
||||
}
|
||||
|
||||
$this->elementEnd('fieldset');
|
||||
}
|
||||
|
||||
$this->elementEnd('form');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -303,7 +200,6 @@ class TwittersettingsAction extends ConnectSettingsAction
|
|||
|
||||
function handlePost()
|
||||
{
|
||||
|
||||
// CSRF protection
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
|
@ -314,8 +210,6 @@ class TwittersettingsAction extends ConnectSettingsAction
|
|||
|
||||
if ($this->arg('save')) {
|
||||
$this->savePreferences();
|
||||
} else if ($this->arg('add')) {
|
||||
$this->addTwitterAccount();
|
||||
} else if ($this->arg('remove')) {
|
||||
$this->removeTwitterAccount();
|
||||
} else {
|
||||
|
@ -323,82 +217,6 @@ class TwittersettingsAction extends ConnectSettingsAction
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate a Twitter account with the user's account
|
||||
*
|
||||
* Validates post input; verifies it against Twitter; and if
|
||||
* successful stores in the database.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function addTwitterAccount()
|
||||
{
|
||||
$screen_name = $this->trimmed('twitter_username');
|
||||
$password = $this->trimmed('twitter_password');
|
||||
$noticesend = $this->boolean('noticesend');
|
||||
$noticerecv = $this->boolean('noticerecv');
|
||||
$replysync = $this->boolean('replysync');
|
||||
$friendsync = $this->boolean('friendsync');
|
||||
|
||||
if (!Validate::string($screen_name,
|
||||
array('min_length' => 1,
|
||||
'max_length' => 15,
|
||||
'format' => VALIDATE_NUM.VALIDATE_ALPHA.'_'))) {
|
||||
$this->showForm(_('Username must have only numbers, '.
|
||||
'upper- and lowercase letters, '.
|
||||
'and underscore (_). 15 chars max.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->verifyCredentials($screen_name, $password)) {
|
||||
$this->showForm(_('Could not verify your Twitter credentials!'));
|
||||
return;
|
||||
}
|
||||
|
||||
$twit_user = twitter_user_info($screen_name, $password);
|
||||
|
||||
if (!$twit_user) {
|
||||
$this->showForm(sprintf(_('Unable to retrieve account information '.
|
||||
'For "%s" from Twitter.'),
|
||||
$screen_name));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!save_twitter_user($twit_user->id, $screen_name)) {
|
||||
$this->showForm(_('Unable to save your Twitter settings!'));
|
||||
return;
|
||||
}
|
||||
|
||||
$user = common_current_user();
|
||||
|
||||
$flink = new Foreign_link();
|
||||
|
||||
$flink->user_id = $user->id;
|
||||
$flink->foreign_id = $twit_user->id;
|
||||
$flink->service = TWITTER_SERVICE;
|
||||
$flink->credentials = $password;
|
||||
$flink->created = common_sql_now();
|
||||
|
||||
$flink->set_flags($noticesend, $noticerecv, $replysync, $friendsync);
|
||||
|
||||
$flink_id = $flink->insert();
|
||||
|
||||
if (!$flink_id) {
|
||||
common_log_db_error($flink, 'INSERT', __FILE__);
|
||||
$this->showForm(_('Unable to save your Twitter settings!'));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($friendsync) {
|
||||
save_twitter_friends($user, $twit_user->id, $screen_name, $password);
|
||||
$flink->last_friendsync = common_sql_now();
|
||||
$flink->update();
|
||||
}
|
||||
|
||||
$this->showForm(_('Twitter settings saved.'), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disassociate an existing Twitter account from this account
|
||||
*
|
||||
|
@ -408,20 +226,11 @@ class TwittersettingsAction extends ConnectSettingsAction
|
|||
function removeTwitterAccount()
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$flink = Foreign_link::getByUserID($user->id, 1);
|
||||
|
||||
$flink_foreign_id = $this->arg('flink_foreign_id');
|
||||
|
||||
// Maybe an old tab open...?
|
||||
if ($flink->foreign_id != $flink_foreign_id) {
|
||||
$this->showForm(_('That is not your Twitter account.'));
|
||||
return;
|
||||
}
|
||||
$flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
|
||||
|
||||
$result = $flink->delete();
|
||||
|
||||
if (!$result) {
|
||||
if (empty($result)) {
|
||||
common_log_db_error($flink, 'DELETE', __FILE__);
|
||||
$this->serverError(_('Couldn\'t remove Twitter user.'));
|
||||
return;
|
||||
|
@ -444,32 +253,16 @@ class TwittersettingsAction extends ConnectSettingsAction
|
|||
$replysync = $this->boolean('replysync');
|
||||
|
||||
$user = common_current_user();
|
||||
$flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
|
||||
|
||||
$flink = Foreign_link::getByUserID($user->id, 1);
|
||||
|
||||
if (!$flink) {
|
||||
if (empty($flink)) {
|
||||
common_log_db_error($flink, 'SELECT', __FILE__);
|
||||
$this->showForm(_('Couldn\'t save Twitter preferences.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$twitter_id = $flink->foreign_id;
|
||||
$password = $flink->credentials;
|
||||
|
||||
$fuser = $flink->getForeignUser();
|
||||
|
||||
if (!$fuser) {
|
||||
common_log_db_error($fuser, 'SELECT', __FILE__);
|
||||
$this->showForm(_('Couldn\'t save Twitter preferences.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$screen_name = $fuser->nickname;
|
||||
|
||||
$original = clone($flink);
|
||||
|
||||
$flink->set_flags($noticesend, $noticerecv, $replysync, $friendsync);
|
||||
|
||||
$result = $flink->update($original);
|
||||
|
||||
if ($result === false) {
|
||||
|
@ -478,45 +271,7 @@ class TwittersettingsAction extends ConnectSettingsAction
|
|||
return;
|
||||
}
|
||||
|
||||
if ($friendsync) {
|
||||
save_twitter_friends($user, $flink->foreign_id, $screen_name, $password);
|
||||
}
|
||||
|
||||
$this->showForm(_('Twitter preferences saved.'), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies a username and password against Twitter's API
|
||||
*
|
||||
* @param string $screen_name Twitter user name
|
||||
* @param string $password Twitter password
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
|
||||
function verifyCredentials($screen_name, $password)
|
||||
{
|
||||
$uri = 'http://twitter.com/account/verify_credentials.json';
|
||||
|
||||
$data = get_twitter_data($uri, $screen_name, $password);
|
||||
|
||||
if (!$data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$user = json_decode($data);
|
||||
|
||||
if (!$user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$twitter_id = $user->id;
|
||||
|
||||
if ($twitter_id) {
|
||||
return $twitter_id;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
<?php
|
||||
/*
|
||||
/**
|
||||
* Unsubscribe handler
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Action
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @author Robin Millette <millette@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://laconi.ca/
|
||||
*
|
||||
* Laconica - a distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, 2009, Control Yourself, Inc.
|
||||
*
|
||||
|
@ -17,6 +28,20 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (!defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe handler
|
||||
*
|
||||
* @category Action
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @author Robin Millette <millette@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
class UnsubscribeAction extends Action
|
||||
{
|
||||
|
||||
|
@ -31,16 +56,18 @@ class UnsubscribeAction extends Action
|
|||
$user = common_current_user();
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
|
||||
common_redirect(common_local_url('subscriptions', array('nickname' => $user->nickname)));
|
||||
common_redirect(common_local_url('subscriptions',
|
||||
array('nickname' => $user->nickname)));
|
||||
return;
|
||||
}
|
||||
|
||||
# CSRF protection
|
||||
/* Use a session token for CSRF protection. */
|
||||
|
||||
$token = $this->trimmed('token');
|
||||
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->clientError(_('There was a problem with your session token. Try again, please.'));
|
||||
$this->clientError(_('There was a problem with your session token. ' .
|
||||
'Try again, please.'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -53,7 +80,7 @@ class UnsubscribeAction extends Action
|
|||
|
||||
$other = Profile::staticGet('id', $other_id);
|
||||
|
||||
if (!$other_id) {
|
||||
if (!$other) {
|
||||
$this->clientError(_('No profile with that id.'));
|
||||
return;
|
||||
}
|
||||
|
@ -76,8 +103,8 @@ class UnsubscribeAction extends Action
|
|||
$this->elementEnd('body');
|
||||
$this->elementEnd('html');
|
||||
} else {
|
||||
common_redirect(common_local_url('subscriptions', array('nickname' =>
|
||||
$user->nickname)),
|
||||
common_redirect(common_local_url('subscriptions',
|
||||
array('nickname' => $user->nickname)),
|
||||
303);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
<?php
|
||||
/*
|
||||
/**
|
||||
* Handle an updateprofile action
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Action
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @author Robin Millette <millette@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://laconi.ca/
|
||||
*
|
||||
* Laconica - a distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, 2009, Control Yourself, Inc.
|
||||
*
|
||||
|
@ -17,34 +28,34 @@
|
|||
* 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 INSTALLDIR.'/lib/omb.php';
|
||||
require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
|
||||
|
||||
/**
|
||||
* Handle an updateprofile action
|
||||
*
|
||||
* @category Action
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @author Robin Millette <millette@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
class UpdateprofileAction extends Action
|
||||
{
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
try {
|
||||
common_remove_magic_from_request();
|
||||
$req = OAuthRequest::from_request('POST', common_local_url('updateprofile'));
|
||||
# Note: server-to-server function!
|
||||
$server = omb_oauth_server();
|
||||
list($consumer, $token) = $server->verify_request($req);
|
||||
if ($this->update_profile($req, $consumer, $token)) {
|
||||
header('HTTP/1.1 200 OK');
|
||||
header('Content-type: text/plain');
|
||||
print "omb_version=".OMB_VERSION_01;
|
||||
}
|
||||
} catch (OAuthException $e) {
|
||||
$this->serverError($e->getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function update_profile($req, $consumer, $token)
|
||||
/**
|
||||
* For initializing members of the class.
|
||||
*
|
||||
* @param array $argarray misc. arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function prepare($argarray)
|
||||
{
|
||||
$version = $req->get_parameter('omb_version');
|
||||
if ($version != OMB_VERSION_01) {
|
||||
|
@ -79,7 +90,7 @@ class UpdateprofileAction extends Action
|
|||
$nickname = $req->get_parameter('omb_listenee_nickname');
|
||||
if ($nickname && !Validate::string($nickname, array('min_length' => 1,
|
||||
'max_length' => 64,
|
||||
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
|
||||
'format' => NICKNAME_FMT))) {
|
||||
$this->clientError(_('Nickname must have only lowercase letters and numbers and no spaces.'));
|
||||
return false;
|
||||
}
|
||||
|
@ -88,96 +99,20 @@ class UpdateprofileAction extends Action
|
|||
$this->clientError(sprintf(_("Invalid license URL '%s'"), $license));
|
||||
return false;
|
||||
}
|
||||
$profile_url = $req->get_parameter('omb_listenee_profile');
|
||||
if ($profile_url && !common_valid_http_url($profile_url)) {
|
||||
$this->clientError(sprintf(_("Invalid profile URL '%s'."), $profile_url));
|
||||
return false;
|
||||
}
|
||||
# optional stuff
|
||||
$fullname = $req->get_parameter('omb_listenee_fullname');
|
||||
if ($fullname && mb_strlen($fullname) > 255) {
|
||||
$this->clientError(_("Full name is too long (max 255 chars)."));
|
||||
return false;
|
||||
}
|
||||
$homepage = $req->get_parameter('omb_listenee_homepage');
|
||||
if ($homepage && (!common_valid_http_url($homepage) || mb_strlen($homepage) > 255)) {
|
||||
$this->clientError(sprintf(_("Invalid homepage '%s'"), $homepage));
|
||||
return false;
|
||||
}
|
||||
$bio = $req->get_parameter('omb_listenee_bio');
|
||||
if ($bio && mb_strlen($bio) > 140) {
|
||||
$this->clientError(_("Bio is too long (max 140 chars)."));
|
||||
return false;
|
||||
}
|
||||
$location = $req->get_parameter('omb_listenee_location');
|
||||
if ($location && mb_strlen($location) > 255) {
|
||||
$this->clientError(_("Location is too long (max 255 chars)."));
|
||||
return false;
|
||||
}
|
||||
$avatar = $req->get_parameter('omb_listenee_avatar');
|
||||
if ($avatar) {
|
||||
if (!common_valid_http_url($avatar) || strlen($avatar) > 255) {
|
||||
$this->clientError(sprintf(_("Invalid avatar URL '%s'"), $avatar));
|
||||
return false;
|
||||
}
|
||||
$size = @getimagesize($avatar);
|
||||
if (!$size) {
|
||||
$this->clientError(sprintf(_("Can't read avatar URL '%s'"), $avatar));
|
||||
return false;
|
||||
}
|
||||
if ($size[0] != AVATAR_PROFILE_SIZE || $size[1] != AVATAR_PROFILE_SIZE) {
|
||||
$this->clientError(sprintf(_("Wrong size image at '%s'"), $avatar));
|
||||
return false;
|
||||
}
|
||||
if (!in_array($size[2], array(IMAGETYPE_GIF, IMAGETYPE_JPEG,
|
||||
IMAGETYPE_PNG))) {
|
||||
$this->clientError(sprintf(_("Wrong image type for '%s'"), $avatar));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
$orig_profile = clone($profile);
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
/* Use values even if they are an empty string. Parsing an empty string in
|
||||
updateProfile is the specified way of clearing a parameter in OMB. */
|
||||
if (!is_null($nickname)) {
|
||||
$profile->nickname = $nickname;
|
||||
}
|
||||
if (!is_null($profile_url)) {
|
||||
$profile->profileurl = $profile_url;
|
||||
}
|
||||
if (!is_null($fullname)) {
|
||||
$profile->fullname = $fullname;
|
||||
}
|
||||
if (!is_null($homepage)) {
|
||||
$profile->homepage = $homepage;
|
||||
}
|
||||
if (!is_null($bio)) {
|
||||
$profile->bio = $bio;
|
||||
}
|
||||
if (!is_null($location)) {
|
||||
$profile->location = $location;
|
||||
}
|
||||
|
||||
if (!$profile->update($orig_profile)) {
|
||||
$this->serverError(_('Could not save new profile info'), 500);
|
||||
return false;
|
||||
} else {
|
||||
if ($avatar) {
|
||||
$temp_filename = tempnam(sys_get_temp_dir(), 'listenee_avatar');
|
||||
copy($avatar, $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));
|
||||
if (!$profile->setOriginal($filename)) {
|
||||
$this->serverError(_('Could not save avatar info'), 500);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
try {
|
||||
$srv = new OMB_Service_Provider(null, omb_oauth_datastore(),
|
||||
omb_oauth_server());
|
||||
$srv->handleUpdateProfile();
|
||||
} catch (Exception $e) {
|
||||
$this->serverError($e->getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,16 @@
|
|||
<?php
|
||||
/*
|
||||
/**
|
||||
* Let the user authorize a remote subscription request
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Action
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @author Robin Millette <millette@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://laconi.ca/
|
||||
*
|
||||
* Laconica - a distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, 2009, Control Yourself, Inc.
|
||||
*
|
||||
|
@ -17,9 +28,13 @@
|
|||
* 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 INSTALLDIR.'/lib/omb.php';
|
||||
require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
|
||||
require_once INSTALLDIR.'/extlib/libomb/profile.php';
|
||||
define('TIMESTAMP_THRESHOLD', 300);
|
||||
|
||||
class UserauthorizationAction extends Action
|
||||
|
@ -32,42 +47,62 @@ class UserauthorizationAction extends Action
|
|||
parent::handle($args);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
# CSRF protection
|
||||
/* Use a session token for CSRF protection. */
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$params = $this->getStoredParams();
|
||||
$this->showForm($params, _('There was a problem with your session token. '.
|
||||
'Try again, please.'));
|
||||
$srv = $this->getStoredParams();
|
||||
$this->showForm($srv->getRemoteUser(), _('There was a problem ' .
|
||||
'with your session token. Try again, ' .
|
||||
'please.'));
|
||||
return;
|
||||
}
|
||||
# We've shown the form, now post user's choice
|
||||
/* We've shown the form, now post user's choice. */
|
||||
$this->sendAuthorization();
|
||||
} else {
|
||||
if (!common_logged_in()) {
|
||||
# Go log in, and then come back
|
||||
/* Go log in, and then come back. */
|
||||
common_set_returnto($_SERVER['REQUEST_URI']);
|
||||
|
||||
common_redirect(common_local_url('login'));
|
||||
if (!common_config('site', 'openidonly')) {
|
||||
common_redirect(common_local_url('login'));
|
||||
} else {
|
||||
common_redirect(common_local_url('openidlogin'));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$user = common_current_user();
|
||||
$profile = $user->getProfile();
|
||||
if (!$profile) {
|
||||
common_log_db_error($user, 'SELECT', __FILE__);
|
||||
$this->serverError(_('User without matching profile'));
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: If no token is passed the user should get a prompt to enter
|
||||
it according to OAuth Core 1.0. */
|
||||
try {
|
||||
$this->validateRequest();
|
||||
$this->storeParams($_GET);
|
||||
$this->showForm($_GET);
|
||||
} catch (OAuthException $e) {
|
||||
$this->validateOmb();
|
||||
$srv = new OMB_Service_Provider(
|
||||
profile_to_omb_profile($user->uri, $profile),
|
||||
omb_oauth_datastore());
|
||||
|
||||
$remote_user = $srv->handleUserAuth();
|
||||
} catch (Exception $e) {
|
||||
$this->clearParams();
|
||||
$this->clientError($e->getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
$this->storeParams($srv);
|
||||
$this->showForm($remote_user);
|
||||
}
|
||||
}
|
||||
|
||||
function showForm($params, $error=null)
|
||||
{
|
||||
$this->params = $params;
|
||||
$this->error = $error;
|
||||
$this->error = $error;
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
|
@ -79,23 +114,24 @@ class UserauthorizationAction extends Action
|
|||
function showPageNotice()
|
||||
{
|
||||
$this->element('p', null, _('Please check these details to make sure '.
|
||||
'that you want to subscribe to this user\'s notices. '.
|
||||
'If you didn\'t just ask to subscribe to someone\'s notices, '.
|
||||
'click "Reject".'));
|
||||
'that you want to subscribe to this ' .
|
||||
'user’s notices. If you didn’t just ask ' .
|
||||
'to subscribe to someone’s notices, '.
|
||||
'click “Reject”.'));
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$params = $this->params;
|
||||
|
||||
$nickname = $params['omb_listenee_nickname'];
|
||||
$profile = $params['omb_listenee_profile'];
|
||||
$license = $params['omb_listenee_license'];
|
||||
$fullname = $params['omb_listenee_fullname'];
|
||||
$homepage = $params['omb_listenee_homepage'];
|
||||
$bio = $params['omb_listenee_bio'];
|
||||
$location = $params['omb_listenee_location'];
|
||||
$avatar = $params['omb_listenee_avatar'];
|
||||
$nickname = $params->getNickname();
|
||||
$profile = $params->getProfileURL();
|
||||
$license = $params->getLicenseURL();
|
||||
$fullname = $params->getFullname();
|
||||
$homepage = $params->getHomepage();
|
||||
$bio = $params->getBio();
|
||||
$location = $params->getLocation();
|
||||
$avatar = $params->getAvatarURL();
|
||||
|
||||
$this->elementStart('div', array('class' => 'profile'));
|
||||
$this->elementStart('div', 'entity_profile vcard');
|
||||
|
@ -172,11 +208,14 @@ class UserauthorizationAction extends Action
|
|||
'id' => 'userauthorization',
|
||||
'class' => 'form_user_authorization',
|
||||
'name' => 'userauthorization',
|
||||
'action' => common_local_url('userauthorization')));
|
||||
'action' => common_local_url(
|
||||
'userauthorization')));
|
||||
$this->hidden('token', common_session_token());
|
||||
|
||||
$this->submit('accept', _('Accept'), 'submit accept', null, _('Subscribe to this user'));
|
||||
$this->submit('reject', _('Reject'), 'submit reject', null, _('Reject this subscription'));
|
||||
$this->submit('accept', _('Accept'), 'submit accept', null,
|
||||
_('Subscribe to this user'));
|
||||
$this->submit('reject', _('Reject'), 'submit reject', null,
|
||||
_('Reject this subscription'));
|
||||
$this->elementEnd('form');
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
|
@ -186,218 +225,56 @@ class UserauthorizationAction extends Action
|
|||
|
||||
function sendAuthorization()
|
||||
{
|
||||
$params = $this->getStoredParams();
|
||||
$srv = $this->getStoredParams();
|
||||
|
||||
if (!$params) {
|
||||
if (is_null($srv)) {
|
||||
$this->clientError(_('No authorization request!'));
|
||||
return;
|
||||
}
|
||||
|
||||
$callback = $params['oauth_callback'];
|
||||
|
||||
if ($this->arg('accept')) {
|
||||
if (!$this->authorizeToken($params)) {
|
||||
$this->clientError(_('Error authorizing token'));
|
||||
}
|
||||
if (!$this->saveRemoteProfile($params)) {
|
||||
$this->clientError(_('Error saving remote profile'));
|
||||
}
|
||||
if (!$callback) {
|
||||
$this->showAcceptMessage($params['oauth_token']);
|
||||
} else {
|
||||
$newparams = array();
|
||||
$newparams['oauth_token'] = $params['oauth_token'];
|
||||
$newparams['omb_version'] = OMB_VERSION_01;
|
||||
$user = User::staticGet('uri', $params['omb_listener']);
|
||||
$profile = $user->getProfile();
|
||||
if (!$profile) {
|
||||
common_log_db_error($user, 'SELECT', __FILE__);
|
||||
$this->serverError(_('User without matching profile'));
|
||||
return;
|
||||
}
|
||||
$newparams['omb_listener_nickname'] = $user->nickname;
|
||||
$newparams['omb_listener_profile'] = common_local_url('showstream',
|
||||
array('nickname' => $user->nickname));
|
||||
if (!is_null($profile->fullname)) {
|
||||
$newparams['omb_listener_fullname'] = $profile->fullname;
|
||||
}
|
||||
if (!is_null($profile->homepage)) {
|
||||
$newparams['omb_listener_homepage'] = $profile->homepage;
|
||||
}
|
||||
if (!is_null($profile->bio)) {
|
||||
$newparams['omb_listener_bio'] = $profile->bio;
|
||||
}
|
||||
if (!is_null($profile->location)) {
|
||||
$newparams['omb_listener_location'] = $profile->location;
|
||||
}
|
||||
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
|
||||
if ($avatar) {
|
||||
$newparams['omb_listener_avatar'] = $avatar->url;
|
||||
}
|
||||
$parts = array();
|
||||
foreach ($newparams as $k => $v) {
|
||||
$parts[] = $k . '=' . OAuthUtil::urlencode_rfc3986($v);
|
||||
}
|
||||
$query_string = implode('&', $parts);
|
||||
$parsed = parse_url($callback);
|
||||
$url = $callback . (($parsed['query']) ? '&' : '?') . $query_string;
|
||||
common_redirect($url, 303);
|
||||
}
|
||||
$accepted = $this->arg('accept');
|
||||
try {
|
||||
list($val, $token) = $srv->continueUserAuth($accepted);
|
||||
} catch (Exception $e) {
|
||||
$this->clientError($e->getMessage());
|
||||
return;
|
||||
}
|
||||
if ($val !== false) {
|
||||
common_redirect($val, 303);
|
||||
} elseif ($accepted) {
|
||||
$this->showAcceptMessage($token);
|
||||
} else {
|
||||
if (!$callback) {
|
||||
$this->showRejectMessage();
|
||||
} else {
|
||||
# XXX: not 100% sure how to signal failure... just redirect without token?
|
||||
common_redirect($callback, 303);
|
||||
}
|
||||
$this->showRejectMessage();
|
||||
}
|
||||
}
|
||||
|
||||
function authorizeToken(&$params)
|
||||
{
|
||||
$token_field = $params['oauth_token'];
|
||||
$rt = new Token();
|
||||
$rt->tok = $token_field;
|
||||
$rt->type = 0;
|
||||
$rt->state = 0;
|
||||
if ($rt->find(true)) {
|
||||
$orig_rt = clone($rt);
|
||||
$rt->state = 1; # Authorized but not used
|
||||
if ($rt->update($orig_rt)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
# XXX: refactor with similar code in finishremotesubscribe.php
|
||||
|
||||
function saveRemoteProfile(&$params)
|
||||
{
|
||||
# FIXME: we should really do this when the consumer comes
|
||||
# back for an access token. If they never do, we've got stuff in a
|
||||
# weird state.
|
||||
|
||||
$nickname = $params['omb_listenee_nickname'];
|
||||
$fullname = $params['omb_listenee_fullname'];
|
||||
$profile_url = $params['omb_listenee_profile'];
|
||||
$homepage = $params['omb_listenee_homepage'];
|
||||
$bio = $params['omb_listenee_bio'];
|
||||
$location = $params['omb_listenee_location'];
|
||||
$avatar_url = $params['omb_listenee_avatar'];
|
||||
|
||||
$listenee = $params['omb_listenee'];
|
||||
$remote = Remote_profile::staticGet('uri', $listenee);
|
||||
|
||||
if ($remote) {
|
||||
$exists = true;
|
||||
$profile = Profile::staticGet($remote->id);
|
||||
$orig_remote = clone($remote);
|
||||
$orig_profile = clone($profile);
|
||||
} else {
|
||||
$exists = false;
|
||||
$remote = new Remote_profile();
|
||||
$remote->uri = $listenee;
|
||||
$profile = new Profile();
|
||||
}
|
||||
|
||||
$profile->nickname = $nickname;
|
||||
$profile->profileurl = $profile_url;
|
||||
|
||||
if (!is_null($fullname)) {
|
||||
$profile->fullname = $fullname;
|
||||
}
|
||||
if (!is_null($homepage)) {
|
||||
$profile->homepage = $homepage;
|
||||
}
|
||||
if (!is_null($bio)) {
|
||||
$profile->bio = $bio;
|
||||
}
|
||||
if (!is_null($location)) {
|
||||
$profile->location = $location;
|
||||
}
|
||||
|
||||
if ($exists) {
|
||||
$profile->update($orig_profile);
|
||||
} else {
|
||||
$profile->created = DB_DataObject_Cast::dateTime(); # current time
|
||||
$id = $profile->insert();
|
||||
if (!$id) {
|
||||
return false;
|
||||
}
|
||||
$remote->id = $id;
|
||||
}
|
||||
|
||||
if ($exists) {
|
||||
if (!$remote->update($orig_remote)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$remote->created = DB_DataObject_Cast::dateTime(); # current time
|
||||
if (!$remote->insert()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($avatar_url) {
|
||||
if (!$this->addAvatar($profile, $avatar_url)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$user = common_current_user();
|
||||
|
||||
$sub = new Subscription();
|
||||
$sub->subscriber = $user->id;
|
||||
$sub->subscribed = $remote->id;
|
||||
$sub->token = $params['oauth_token']; # NOTE: request token, not valid for use!
|
||||
$sub->created = DB_DataObject_Cast::dateTime(); # current time
|
||||
|
||||
if (!$sub->insert()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function addAvatar($profile, $url)
|
||||
{
|
||||
$temp_filename = tempnam(sys_get_temp_dir(), 'listenee_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);
|
||||
}
|
||||
|
||||
function showAcceptMessage($tok)
|
||||
{
|
||||
common_show_header(_('Subscription authorized'));
|
||||
$this->element('p', null,
|
||||
_('The subscription has been authorized, but no '.
|
||||
'callback URL was passed. Check with the site\'s instructions for '.
|
||||
'details on how to authorize the subscription. Your subscription token is:'));
|
||||
'callback URL was passed. Check with the site’s ' .
|
||||
'instructions for details on how to authorize the ' .
|
||||
'subscription. Your subscription token is:'));
|
||||
$this->element('blockquote', 'token', $tok);
|
||||
common_show_footer();
|
||||
}
|
||||
|
||||
function showRejectMessage($tok)
|
||||
function showRejectMessage()
|
||||
{
|
||||
common_show_header(_('Subscription rejected'));
|
||||
$this->element('p', null,
|
||||
_('The subscription has been rejected, but no '.
|
||||
'callback URL was passed. Check with the site\'s instructions for '.
|
||||
'details on how to fully reject the subscription.'));
|
||||
'callback URL was passed. Check with the site’s ' .
|
||||
'instructions for details on how to fully reject ' .
|
||||
'the subscription.'));
|
||||
common_show_footer();
|
||||
}
|
||||
|
||||
function storeParams($params)
|
||||
{
|
||||
common_ensure_session();
|
||||
$_SESSION['userauthorizationparams'] = $params;
|
||||
$_SESSION['userauthorizationparams'] = serialize($params);
|
||||
}
|
||||
|
||||
function clearParams()
|
||||
|
@ -409,138 +286,74 @@ class UserauthorizationAction extends Action
|
|||
function getStoredParams()
|
||||
{
|
||||
common_ensure_session();
|
||||
$params = $_SESSION['userauthorizationparams'];
|
||||
$params = unserialize($_SESSION['userauthorizationparams']);
|
||||
return $params;
|
||||
}
|
||||
|
||||
# Throws an OAuthException if anything goes wrong
|
||||
|
||||
function validateRequest()
|
||||
{
|
||||
/* Find token.
|
||||
TODO: If no token is passed the user should get a prompt to enter it
|
||||
according to OAuth Core 1.0 */
|
||||
$t = new Token();
|
||||
$t->tok = $_GET['oauth_token'];
|
||||
$t->type = 0;
|
||||
if (!$t->find(true)) {
|
||||
throw new OAuthException("Invalid request token: " . $_GET['oauth_token']);
|
||||
}
|
||||
|
||||
$this->validateOmb();
|
||||
return true;
|
||||
}
|
||||
|
||||
function validateOmb()
|
||||
{
|
||||
foreach (array('omb_version', 'omb_listener', 'omb_listenee',
|
||||
'omb_listenee_profile', 'omb_listenee_nickname',
|
||||
'omb_listenee_license') as $param)
|
||||
{
|
||||
if (!isset($_GET[$param]) || is_null($_GET[$param])) {
|
||||
throw new OAuthException("Required parameter '$param' not found");
|
||||
}
|
||||
}
|
||||
# Now, OMB stuff
|
||||
$version = $_GET['omb_version'];
|
||||
if ($version != OMB_VERSION_01) {
|
||||
throw new OAuthException("OpenMicroBlogging version '$version' not supported");
|
||||
}
|
||||
$listener = $_GET['omb_listener'];
|
||||
$listenee = $_GET['omb_listenee'];
|
||||
$nickname = $_GET['omb_listenee_nickname'];
|
||||
$profile = $_GET['omb_listenee_profile'];
|
||||
|
||||
$user = User::staticGet('uri', $listener);
|
||||
if (!$user) {
|
||||
throw new OAuthException("Listener URI '$listener' not found here");
|
||||
}
|
||||
$cur = common_current_user();
|
||||
if ($cur->id != $user->id) {
|
||||
throw new OAuthException("Can't add for another user!");
|
||||
}
|
||||
$listenee = $_GET['omb_listenee'];
|
||||
if (!Validate::uri($listenee) &&
|
||||
!common_valid_tag($listenee)) {
|
||||
throw new OAuthException("Listenee URI '$listenee' not a recognizable URI");
|
||||
throw new Exception(sprintf(_('Listener URI ‘%s’ not found here'),
|
||||
$listener));
|
||||
}
|
||||
|
||||
if (strlen($listenee) > 255) {
|
||||
throw new OAuthException("Listenee URI '$listenee' too long");
|
||||
throw new Exception(sprintf(_('Listenee URI ‘%s’ is too long.'),
|
||||
$listenee));
|
||||
}
|
||||
|
||||
$other = User::staticGet('uri', $listenee);
|
||||
if ($other) {
|
||||
throw new OAuthException("Listenee URI '$listenee' is local user");
|
||||
throw new Exception(sprintf(_('Listenee URI ‘%s’ is a local user.'),
|
||||
$listenee));
|
||||
}
|
||||
|
||||
$remote = Remote_profile::staticGet('uri', $listenee);
|
||||
if ($remote) {
|
||||
$sub = new Subscription();
|
||||
$sub = new Subscription();
|
||||
$sub->subscriber = $user->id;
|
||||
$sub->subscribed = $remote->id;
|
||||
if ($sub->find(true)) {
|
||||
throw new OAuthException("Already subscribed to user!");
|
||||
throw new Exception('You are already subscribed to this user.');
|
||||
}
|
||||
}
|
||||
$nickname = $_GET['omb_listenee_nickname'];
|
||||
if (!Validate::string($nickname, array('min_length' => 1,
|
||||
'max_length' => 64,
|
||||
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
|
||||
throw new OAuthException('Nickname must have only letters and numbers and no spaces.');
|
||||
}
|
||||
$profile = $_GET['omb_listenee_profile'];
|
||||
if (!common_valid_http_url($profile)) {
|
||||
throw new OAuthException("Invalid profile URL '$profile'.");
|
||||
|
||||
if ($profile == common_profile_url($nickname)) {
|
||||
throw new Exception(sprintf(_('Profile URL ‘%s’ is for a local user.'),
|
||||
$profile));
|
||||
|
||||
}
|
||||
|
||||
if ($profile == common_local_url('showstream', array('nickname' => $nickname))) {
|
||||
throw new OAuthException("Profile URL '$profile' is for a local user.");
|
||||
}
|
||||
|
||||
$license = $_GET['omb_listenee_license'];
|
||||
if (!common_valid_http_url($license)) {
|
||||
throw new OAuthException("Invalid license URL '$license'.");
|
||||
}
|
||||
$license = $_GET['omb_listenee_license'];
|
||||
$site_license = common_config('license', 'url');
|
||||
if (!common_compatible_license($license, $site_license)) {
|
||||
throw new OAuthException("Listenee stream license '$license' not compatible with site license '$site_license'.");
|
||||
}
|
||||
# optional stuff
|
||||
$fullname = $_GET['omb_listenee_fullname'];
|
||||
if ($fullname && mb_strlen($fullname) > 255) {
|
||||
throw new OAuthException("Full name '$fullname' too long.");
|
||||
}
|
||||
$homepage = $_GET['omb_listenee_homepage'];
|
||||
if ($homepage && (!common_valid_http_url($homepage) || mb_strlen($homepage) > 255)) {
|
||||
throw new OAuthException("Invalid homepage '$homepage'");
|
||||
}
|
||||
$bio = $_GET['omb_listenee_bio'];
|
||||
if ($bio && mb_strlen($bio) > 140) {
|
||||
throw new OAuthException("Bio too long '$bio'");
|
||||
}
|
||||
$location = $_GET['omb_listenee_location'];
|
||||
if ($location && mb_strlen($location) > 255) {
|
||||
throw new OAuthException("Location too long '$location'");
|
||||
throw new Exception(sprintf(_('Listenee stream license ‘%s’ is not ' .
|
||||
'compatible with site license ‘%s’.'),
|
||||
$license, $site_license));
|
||||
}
|
||||
|
||||
$avatar = $_GET['omb_listenee_avatar'];
|
||||
if ($avatar) {
|
||||
if (!common_valid_http_url($avatar) || strlen($avatar) > 255) {
|
||||
throw new OAuthException("Invalid avatar URL '$avatar'");
|
||||
throw new Exception(sprintf(_('Avatar URL ‘%s’ is not valid.'),
|
||||
$avatar));
|
||||
}
|
||||
$size = @getimagesize($avatar);
|
||||
if (!$size) {
|
||||
throw new OAuthException("Can't read avatar URL '$avatar'");
|
||||
}
|
||||
if ($size[0] != AVATAR_PROFILE_SIZE || $size[1] != AVATAR_PROFILE_SIZE) {
|
||||
throw new OAuthException("Wrong size image at '$avatar'");
|
||||
throw new Exception(sprintf(_('Can’t read avatar URL ‘%s’.'),
|
||||
$avatar));
|
||||
}
|
||||
if (!in_array($size[2], array(IMAGETYPE_GIF, IMAGETYPE_JPEG,
|
||||
IMAGETYPE_PNG))) {
|
||||
throw new OAuthException("Wrong image type for '$avatar'");
|
||||
throw new Exception(sprintf(_('Wrong image type for avatar URL '.
|
||||
'‘%s’.'), $avatar));
|
||||
}
|
||||
}
|
||||
$callback = $_GET['oauth_callback'];
|
||||
if ($callback && !common_valid_http_url($callback)) {
|
||||
throw new OAuthException("Invalid callback URL '$callback'");
|
||||
}
|
||||
if ($callback && $callback == common_local_url('finishremotesubscribe')) {
|
||||
throw new OAuthException("Callback URL '$callback' is for local site.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,9 +88,10 @@ class UserrssAction extends Rss10Action
|
|||
$c = array('url' => common_local_url('userrss',
|
||||
array('nickname' =>
|
||||
$user->nickname)),
|
||||
'title' => $user->nickname,
|
||||
'title' => sprintf(_('%s timeline'), $user->nickname),
|
||||
'link' => $profile->profileurl,
|
||||
'description' => sprintf(_('Microblog by %s'), $user->nickname));
|
||||
'description' => sprintf(_('Updates from %1$s on %2$s!'),
|
||||
$user->nickname, common_config('site', 'name')));
|
||||
return $c;
|
||||
}
|
||||
|
||||
|
|
112
actions/xrds.php
112
actions/xrds.php
|
@ -34,6 +34,8 @@ if (!defined('LACONICA')) {
|
|||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/omb.php';
|
||||
require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
|
||||
require_once INSTALLDIR.'/extlib/libomb/xrds_mapper.php';
|
||||
|
||||
/**
|
||||
* XRDS for OpenMicroBlogging
|
||||
|
@ -52,7 +54,7 @@ class XrdsAction extends Action
|
|||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
function isReadOnly()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -85,89 +87,31 @@ class XrdsAction extends Action
|
|||
*/
|
||||
function showXrds($user)
|
||||
{
|
||||
header('Content-Type: application/xrds+xml');
|
||||
$this->startXML();
|
||||
$this->elementStart('XRDS', array('xmlns' => 'xri://$xrds'));
|
||||
|
||||
$this->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
|
||||
'xml:id' => 'oauth',
|
||||
'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
|
||||
'version' => '2.0'));
|
||||
$this->element('Type', null, 'xri://$xrds*simple');
|
||||
$this->showService(OAUTH_ENDPOINT_REQUEST,
|
||||
common_local_url('requesttoken'),
|
||||
array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY),
|
||||
array(OAUTH_HMAC_SHA1),
|
||||
$user->uri);
|
||||
$this->showService(OAUTH_ENDPOINT_AUTHORIZE,
|
||||
common_local_url('userauthorization'),
|
||||
array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY),
|
||||
array(OAUTH_HMAC_SHA1));
|
||||
$this->showService(OAUTH_ENDPOINT_ACCESS,
|
||||
common_local_url('accesstoken'),
|
||||
array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY),
|
||||
array(OAUTH_HMAC_SHA1));
|
||||
$this->showService(OAUTH_ENDPOINT_RESOURCE,
|
||||
null,
|
||||
array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY),
|
||||
array(OAUTH_HMAC_SHA1));
|
||||
$this->elementEnd('XRD');
|
||||
|
||||
// XXX: decide whether to include user's ID/nickname in postNotice URL
|
||||
$this->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
|
||||
'xml:id' => 'omb',
|
||||
'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
|
||||
'version' => '2.0'));
|
||||
$this->element('Type', null, 'xri://$xrds*simple');
|
||||
$this->showService(OMB_ENDPOINT_POSTNOTICE,
|
||||
common_local_url('postnotice'));
|
||||
$this->showService(OMB_ENDPOINT_UPDATEPROFILE,
|
||||
common_local_url('updateprofile'));
|
||||
$this->elementEnd('XRD');
|
||||
$this->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
|
||||
'version' => '2.0'));
|
||||
$this->element('Type', null, 'xri://$xrds*simple');
|
||||
$this->showService(OAUTH_DISCOVERY,
|
||||
'#oauth');
|
||||
$this->showService(OMB_NAMESPACE,
|
||||
'#omb');
|
||||
$this->elementEnd('XRD');
|
||||
$this->elementEnd('XRDS');
|
||||
$this->endXML();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show service.
|
||||
*
|
||||
* @param string $type XRDS type
|
||||
* @param string $uri URI
|
||||
* @param array $params type parameters, null by default
|
||||
* @param array $sigs type signatures, null by default
|
||||
* @param string $localId local ID, null by default
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showService($type, $uri, $params=null, $sigs=null, $localId=null)
|
||||
{
|
||||
$this->elementStart('Service');
|
||||
if ($uri) {
|
||||
$this->element('URI', null, $uri);
|
||||
}
|
||||
$this->element('Type', null, $type);
|
||||
if ($params) {
|
||||
foreach ($params as $param) {
|
||||
$this->element('Type', null, $param);
|
||||
}
|
||||
}
|
||||
if ($sigs) {
|
||||
foreach ($sigs as $sig) {
|
||||
$this->element('Type', null, $sig);
|
||||
}
|
||||
}
|
||||
if ($localId) {
|
||||
$this->element('LocalID', null, $localId);
|
||||
}
|
||||
$this->elementEnd('Service');
|
||||
$srv = new OMB_Service_Provider(profile_to_omb_profile($user->uri,
|
||||
$user->getProfile()));
|
||||
/* Use libomb’s default XRDS Writer. */
|
||||
$xrds_writer = null;
|
||||
$srv->writeXRDS(new Laconica_XRDS_Mapper(), $xrds_writer);
|
||||
}
|
||||
}
|
||||
|
||||
class Laconica_XRDS_Mapper implements OMB_XRDS_Mapper
|
||||
{
|
||||
protected $urls;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->urls = array(
|
||||
OAUTH_ENDPOINT_REQUEST => 'requesttoken',
|
||||
OAUTH_ENDPOINT_AUTHORIZE => 'userauthorization',
|
||||
OAUTH_ENDPOINT_ACCESS => 'accesstoken',
|
||||
OMB_ENDPOINT_POSTNOTICE => 'postnotice',
|
||||
OMB_ENDPOINT_UPDATEPROFILE => 'updateprofile');
|
||||
}
|
||||
|
||||
public function getURL($action)
|
||||
{
|
||||
return common_local_url($this->urls[$action]);
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
|
129
classes/Config.php
Executable file
129
classes/Config.php
Executable file
|
@ -0,0 +1,129 @@
|
|||
<?php
|
||||
/*
|
||||
* Laconica - a distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, 2009, Control Yourself, 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('LACONICA')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Table Definition for config
|
||||
*/
|
||||
|
||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
|
||||
class Config extends Memcached_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
public $__table = 'config'; // table name
|
||||
public $section; // varchar(32) primary_key not_null
|
||||
public $setting; // varchar(32) primary_key not_null
|
||||
public $value; // varchar(255)
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Config',$k,$v); }
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
const settingsKey = 'config:settings';
|
||||
|
||||
static function loadSettings()
|
||||
{
|
||||
$settings = self::_getSettings();
|
||||
if (!empty($settings)) {
|
||||
self::_applySettings($settings);
|
||||
}
|
||||
}
|
||||
|
||||
static function _getSettings()
|
||||
{
|
||||
$c = self::memcache();
|
||||
|
||||
if (!empty($c)) {
|
||||
$settings = $c->get(common_cache_key(self::settingsKey));
|
||||
if (!empty($settings)) {
|
||||
return $settings;
|
||||
}
|
||||
}
|
||||
|
||||
$settings = array();
|
||||
|
||||
$config = new Config();
|
||||
|
||||
$config->find();
|
||||
|
||||
while ($config->fetch()) {
|
||||
$settings[] = array($config->section, $config->setting, $config->value);
|
||||
}
|
||||
|
||||
$config->free();
|
||||
|
||||
if (!empty($c)) {
|
||||
$c->set(common_cache_key(self::settingsKey), $settings);
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
static function _applySettings($settings)
|
||||
{
|
||||
global $config;
|
||||
|
||||
foreach ($settings as $s) {
|
||||
list($section, $setting, $value) = $s;
|
||||
$config[$section][$setting] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
function insert()
|
||||
{
|
||||
$result = parent::insert();
|
||||
if ($result) {
|
||||
Config::_blowSettingsCache();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function delete()
|
||||
{
|
||||
$result = parent::delete();
|
||||
if ($result) {
|
||||
Config::_blowSettingsCache();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function update($orig=null)
|
||||
{
|
||||
$result = parent::update($orig);
|
||||
if ($result) {
|
||||
Config::_blowSettingsCache();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function _blowSettingsCache()
|
||||
{
|
||||
$c = self::memcache();
|
||||
|
||||
if (!empty($c)) {
|
||||
$c->delete(common_cache_key(self::settingsKey));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -107,7 +107,7 @@ class Design extends Memcached_DataObject
|
|||
|
||||
static function toWebColor($color)
|
||||
{
|
||||
if (is_null($color)) {
|
||||
if ($color == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -115,7 +115,7 @@ class Design extends Memcached_DataObject
|
|||
return new WebColor($color);
|
||||
} catch (WebColorException $e) {
|
||||
// This shouldn't happen
|
||||
common_log(LOG_ERR, "Unable to create color for design $id.",
|
||||
common_log(LOG_ERR, "Unable to create web color for $color",
|
||||
__FILE__);
|
||||
return null;
|
||||
}
|
||||
|
@ -204,7 +204,10 @@ class Design extends Memcached_DataObject
|
|||
'disposition');
|
||||
|
||||
foreach ($attrs as $attr) {
|
||||
$siteDesign->$attr = common_config('design', $attr);
|
||||
$val = common_config('design', $attr);
|
||||
if ($val !== false) {
|
||||
$siteDesign->$attr = $val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -95,7 +95,8 @@ class File extends Memcached_DataObject
|
|||
if (empty($file_redir)) {
|
||||
$redir_data = File_redirection::where($given_url);
|
||||
$redir_url = $redir_data['url'];
|
||||
if ($redir_url === $given_url) {
|
||||
// TODO: max field length
|
||||
if ($redir_url === $given_url || strlen($redir_url) > 255) {
|
||||
$x = File::saveNew($redir_data, $given_url);
|
||||
$file_id = $x->id;
|
||||
} else {
|
||||
|
|
|
@ -29,34 +29,38 @@ class Foreign_link extends Memcached_DataObject
|
|||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
// XXX: This only returns a 1->1 single obj mapping. Change? Or make
|
||||
// a getForeignUsers() that returns more than one? --Zach
|
||||
static function getByUserID($user_id, $service)
|
||||
{
|
||||
if (empty($user_id) || empty($service)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$flink = new Foreign_link();
|
||||
|
||||
$flink->service = $service;
|
||||
$flink->user_id = $user_id;
|
||||
$flink->limit(1);
|
||||
|
||||
if ($flink->find(true)) {
|
||||
return $flink;
|
||||
}
|
||||
$result = $flink->find(true);
|
||||
|
||||
return empty($result) ? null : $flink;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static function getByForeignID($foreign_id, $service)
|
||||
{
|
||||
$flink = new Foreign_link();
|
||||
$flink->service = $service;
|
||||
$flink->foreign_id = $foreign_id;
|
||||
$flink->limit(1);
|
||||
if (empty($foreign_id) || empty($service)) {
|
||||
return null;
|
||||
} else {
|
||||
$flink = new Foreign_link();
|
||||
$flink->service = $service;
|
||||
$flink->foreign_id = $foreign_id;
|
||||
$flink->limit(1);
|
||||
|
||||
if ($flink->find(true)) {
|
||||
return $flink;
|
||||
$result = $flink->find(true);
|
||||
|
||||
return empty($result) ? null : $flink;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function set_flags($noticesend, $noticerecv, $replysync, $friendsync)
|
||||
|
@ -66,7 +70,7 @@ class Foreign_link extends Memcached_DataObject
|
|||
} else {
|
||||
$this->noticesync &= ~FOREIGN_NOTICE_SEND;
|
||||
}
|
||||
|
||||
|
||||
if ($noticerecv) {
|
||||
$this->noticesync |= FOREIGN_NOTICE_RECV;
|
||||
} else {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*/
|
||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
|
||||
class Message extends Memcached_DataObject
|
||||
class Message extends Memcached_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
@ -14,58 +14,73 @@ class Message extends Memcached_DataObject
|
|||
public $uri; // varchar(255) unique_key
|
||||
public $from_profile; // int(4) not_null
|
||||
public $to_profile; // int(4) not_null
|
||||
public $content; // varchar(140)
|
||||
public $rendered; // text()
|
||||
public $url; // varchar(255)
|
||||
public $content; // text()
|
||||
public $rendered; // text()
|
||||
public $url; // varchar(255)
|
||||
public $created; // datetime() not_null
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
public $source; // varchar(32)
|
||||
public $source; // varchar(32)
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=null)
|
||||
{ return Memcached_DataObject::staticGet('Message',$k,$v); }
|
||||
function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Message',$k,$v); }
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
|
||||
function getFrom()
|
||||
{
|
||||
return Profile::staticGet('id', $this->from_profile);
|
||||
}
|
||||
|
||||
|
||||
function getTo()
|
||||
{
|
||||
return Profile::staticGet('id', $this->to_profile);
|
||||
}
|
||||
|
||||
|
||||
static function saveNew($from, $to, $content, $source) {
|
||||
|
||||
|
||||
$msg = new Message();
|
||||
|
||||
|
||||
$msg->from_profile = $from;
|
||||
$msg->to_profile = $to;
|
||||
$msg->content = common_shorten_links($content);
|
||||
$msg->rendered = common_render_text($content);
|
||||
$msg->created = common_sql_now();
|
||||
$msg->source = $source;
|
||||
|
||||
|
||||
$result = $msg->insert();
|
||||
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($msg, 'INSERT', __FILE__);
|
||||
return _('Could not insert message.');
|
||||
}
|
||||
|
||||
|
||||
$orig = clone($msg);
|
||||
$msg->uri = common_local_url('showmessage', array('message' => $msg->id));
|
||||
|
||||
|
||||
$result = $msg->update($orig);
|
||||
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($msg, 'UPDATE', __FILE__);
|
||||
return _('Could not update message with new URI.');
|
||||
}
|
||||
|
||||
|
||||
return $msg;
|
||||
}
|
||||
|
||||
static function maxContent()
|
||||
{
|
||||
$desclimit = common_config('message', 'contentlimit');
|
||||
// null => use global limit (distinct from 0!)
|
||||
if (is_null($desclimit)) {
|
||||
$desclimit = common_config('site', 'textlimit');
|
||||
}
|
||||
return $desclimit;
|
||||
}
|
||||
|
||||
static function contentTooLong($content)
|
||||
{
|
||||
$contentlimit = self::maxContent();
|
||||
return ($contentlimit > 0 && !empty($content) && (mb_strlen($content) > $contentlimit));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,10 +29,6 @@ require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
|||
|
||||
define('NOTICE_CACHE_WINDOW', 61);
|
||||
|
||||
define('NOTICE_LOCAL_PUBLIC', 1);
|
||||
define('NOTICE_REMOTE_OMB', 0);
|
||||
define('NOTICE_LOCAL_NONPUBLIC', -1);
|
||||
|
||||
define('MAX_BOXCARS', 128);
|
||||
|
||||
class Notice extends Memcached_DataObject
|
||||
|
@ -44,7 +40,7 @@ class Notice extends Memcached_DataObject
|
|||
public $id; // int(4) primary_key not_null
|
||||
public $profile_id; // int(4) not_null
|
||||
public $uri; // varchar(255) unique_key
|
||||
public $content; // varchar(140)
|
||||
public $content; // text()
|
||||
public $rendered; // text()
|
||||
public $url; // varchar(255)
|
||||
public $created; // datetime() not_null
|
||||
|
@ -55,14 +51,16 @@ class Notice extends Memcached_DataObject
|
|||
public $conversation; // int(4)
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=NULL) {
|
||||
return Memcached_DataObject::staticGet('Notice',$k,$v);
|
||||
}
|
||||
function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Notice',$k,$v); }
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
const GATEWAY = -2;
|
||||
/* Notice types */
|
||||
const LOCAL_PUBLIC = 1;
|
||||
const REMOTE_OMB = 0;
|
||||
const LOCAL_NONPUBLIC = -1;
|
||||
const GATEWAY = -2;
|
||||
|
||||
function getProfile()
|
||||
{
|
||||
|
@ -148,13 +146,13 @@ class Notice extends Memcached_DataObject
|
|||
}
|
||||
|
||||
static function saveNew($profile_id, $content, $source=null,
|
||||
$is_local=1, $reply_to=null, $uri=null, $created=null) {
|
||||
$is_local=Notice::LOCAL_PUBLIC, $reply_to=null, $uri=null, $created=null) {
|
||||
|
||||
$profile = Profile::staticGet($profile_id);
|
||||
|
||||
$final = common_shorten_links($content);
|
||||
|
||||
if (mb_strlen($final) > 140) {
|
||||
if (Notice::contentTooLong($final)) {
|
||||
common_log(LOG_INFO, 'Rejecting notice that is too long.');
|
||||
return _('Problem saving notice. Too long.');
|
||||
}
|
||||
|
@ -191,7 +189,7 @@ class Notice extends Memcached_DataObject
|
|||
|
||||
if (($blacklist && in_array($profile_id, $blacklist)) ||
|
||||
($source && $autosource && in_array($source, $autosource))) {
|
||||
$notice->is_local = -1;
|
||||
$notice->is_local = Notice::LOCAL_NONPUBLIC;
|
||||
} else {
|
||||
$notice->is_local = $is_local;
|
||||
}
|
||||
|
@ -523,7 +521,7 @@ class Notice extends Memcached_DataObject
|
|||
|
||||
function blowPublicCache($blowLast=false)
|
||||
{
|
||||
if ($this->is_local == 1) {
|
||||
if ($this->is_local == Notice::LOCAL_PUBLIC) {
|
||||
$cache = common_memcache();
|
||||
if ($cache) {
|
||||
$cache->delete(common_cache_key('public'));
|
||||
|
@ -789,10 +787,11 @@ class Notice extends Memcached_DataObject
|
|||
}
|
||||
|
||||
if (common_config('public', 'localonly')) {
|
||||
$notice->whereAdd('is_local = 1');
|
||||
$notice->whereAdd('is_local = ' . Notice::LOCAL_PUBLIC);
|
||||
} else {
|
||||
# -1 == blacklisted
|
||||
$notice->whereAdd('is_local != -1');
|
||||
# -1 == blacklisted, -2 == gateway (i.e. Twitter)
|
||||
$notice->whereAdd('is_local !='. Notice::LOCAL_NONPUBLIC);
|
||||
$notice->whereAdd('is_local !='. Notice::GATEWAY);
|
||||
}
|
||||
|
||||
if ($since_id != 0) {
|
||||
|
@ -1354,4 +1353,20 @@ class Notice extends Memcached_DataObject
|
|||
return $last->id;
|
||||
}
|
||||
}
|
||||
|
||||
static function maxContent()
|
||||
{
|
||||
$contentlimit = common_config('notice', 'contentlimit');
|
||||
// null => use global limit (distinct from 0!)
|
||||
if (is_null($contentlimit)) {
|
||||
$contentlimit = common_config('site', 'textlimit');
|
||||
}
|
||||
return $contentlimit;
|
||||
}
|
||||
|
||||
static function contentTooLong($content)
|
||||
{
|
||||
$contentlimit = self::maxContent();
|
||||
return ($contentlimit > 0 && !empty($content) && (mb_strlen($content) > $contentlimit));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,14 +35,13 @@ class Profile extends Memcached_DataObject
|
|||
public $fullname; // varchar(255) multiple_key
|
||||
public $profileurl; // varchar(255)
|
||||
public $homepage; // varchar(255) multiple_key
|
||||
public $bio; // varchar(140) multiple_key
|
||||
public $bio; // text() multiple_key
|
||||
public $location; // varchar(255) multiple_key
|
||||
public $created; // datetime() not_null
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=null)
|
||||
{ return Memcached_DataObject::staticGet('Profile',$k,$v); }
|
||||
function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Profile',$k,$v); }
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
@ -461,4 +460,20 @@ class Profile extends Memcached_DataObject
|
|||
$c->delete(common_cache_key('profile:notice_count:'.$this->id));
|
||||
}
|
||||
}
|
||||
|
||||
static function maxBio()
|
||||
{
|
||||
$biolimit = common_config('profile', 'biolimit');
|
||||
// null => use global limit (distinct from 0!)
|
||||
if (is_null($biolimit)) {
|
||||
$biolimit = common_config('site', 'textlimit');
|
||||
}
|
||||
return $biolimit;
|
||||
}
|
||||
|
||||
static function bioTooLong($bio)
|
||||
{
|
||||
$biolimit = self::maxBio();
|
||||
return ($biolimit > 0 && !empty($bio) && (mb_strlen($bio) > $biolimit));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ class User_group extends Memcached_DataObject
|
|||
public $nickname; // varchar(64) unique_key
|
||||
public $fullname; // varchar(255)
|
||||
public $homepage; // varchar(255)
|
||||
public $description; // varchar(140)
|
||||
public $description; // text()
|
||||
public $location; // varchar(255)
|
||||
public $original_logo; // varchar(255)
|
||||
public $homepage_logo; // varchar(255)
|
||||
|
@ -297,4 +297,61 @@ class User_group extends Memcached_DataObject
|
|||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
static function maxDescription()
|
||||
{
|
||||
$desclimit = common_config('group', 'desclimit');
|
||||
// null => use global limit (distinct from 0!)
|
||||
if (is_null($desclimit)) {
|
||||
$desclimit = common_config('site', 'textlimit');
|
||||
}
|
||||
return $desclimit;
|
||||
}
|
||||
|
||||
static function descriptionTooLong($desc)
|
||||
{
|
||||
$desclimit = self::maxDescription();
|
||||
return ($desclimit > 0 && !empty($desc) && (mb_strlen($desc) > $desclimit));
|
||||
}
|
||||
|
||||
function asAtomEntry($namespace=false, $source=false)
|
||||
{
|
||||
$xs = new XMLStringer(true);
|
||||
|
||||
if ($namespace) {
|
||||
$attrs = array('xmlns' => 'http://www.w3.org/2005/Atom',
|
||||
'xmlns:thr' => 'http://purl.org/syndication/thread/1.0');
|
||||
} else {
|
||||
$attrs = array();
|
||||
}
|
||||
|
||||
$xs->elementStart('entry', $attrs);
|
||||
|
||||
if ($source) {
|
||||
$xs->elementStart('source');
|
||||
$xs->element('title', null, $profile->nickname . " - " . common_config('site', 'name'));
|
||||
$xs->element('link', array('href' => $this->permalink()));
|
||||
}
|
||||
|
||||
if ($source) {
|
||||
$xs->elementEnd('source');
|
||||
}
|
||||
|
||||
$xs->element('title', null, $this->nickname);
|
||||
$xs->element('summary', null, $this->description);
|
||||
|
||||
$xs->element('link', array('rel' => 'alternate',
|
||||
'href' => $this->permalink()));
|
||||
|
||||
$xs->element('id', null, $this->permalink());
|
||||
|
||||
$xs->element('published', null, common_date_w3dtf($this->created));
|
||||
$xs->element('updated', null, common_date_w3dtf($this->modified));
|
||||
|
||||
$xs->element('content', array('type' => 'html'), $this->description);
|
||||
|
||||
$xs->elementEnd('entry');
|
||||
|
||||
return $xs->getString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,15 @@ width = K
|
|||
height = K
|
||||
url = U
|
||||
|
||||
[config]
|
||||
section = 130
|
||||
setting = 130
|
||||
value = 2
|
||||
|
||||
[config__keys]
|
||||
section = K
|
||||
setting = K
|
||||
|
||||
[confirm_address]
|
||||
code = 130
|
||||
user_id = 129
|
||||
|
@ -239,7 +248,7 @@ id = 129
|
|||
uri = 2
|
||||
from_profile = 129
|
||||
to_profile = 129
|
||||
content = 2
|
||||
content = 34
|
||||
rendered = 34
|
||||
url = 2
|
||||
created = 142
|
||||
|
@ -266,7 +275,7 @@ ts = K
|
|||
id = 129
|
||||
profile_id = 129
|
||||
uri = 2
|
||||
content = 2
|
||||
content = 34
|
||||
rendered = 34
|
||||
url = 2
|
||||
created = 142
|
||||
|
@ -314,7 +323,7 @@ nickname = 130
|
|||
fullname = 2
|
||||
profileurl = 2
|
||||
homepage = 2
|
||||
bio = 2
|
||||
bio = 34
|
||||
location = 2
|
||||
created = 142
|
||||
modified = 384
|
||||
|
@ -486,7 +495,7 @@ id = 129
|
|||
nickname = 2
|
||||
fullname = 2
|
||||
homepage = 2
|
||||
description = 2
|
||||
description = 34
|
||||
location = 2
|
||||
original_logo = 2
|
||||
homepage_logo = 2
|
||||
|
|
|
@ -38,6 +38,8 @@ $config['site']['path'] = 'laconica';
|
|||
// $config['site']['closed'] = true;
|
||||
// Only allow registration for people invited by another user
|
||||
// $config['site']['inviteonly'] = true;
|
||||
// Only allow registrations and logins through OpenID
|
||||
// $config['site']['openidonly'] = true;
|
||||
// Make the site invisible to non-logged-in users
|
||||
// $config['site']['private'] = true;
|
||||
|
||||
|
@ -97,6 +99,9 @@ $config['sphinx']['port'] = 3312;
|
|||
// $config['xmpp']['public'][] = 'someindexer@example.net';
|
||||
// $config['xmpp']['debug'] = false;
|
||||
|
||||
// Disable OpenID
|
||||
// $config['openid']['enabled'] = false;
|
||||
|
||||
// Turn off invites
|
||||
// $config['invite']['enabled'] = false;
|
||||
|
||||
|
@ -164,6 +169,15 @@ $config['sphinx']['port'] = 3312;
|
|||
// $config['memcached']['server'] = 'localhost';
|
||||
// $config['memcached']['port'] = 11211;
|
||||
|
||||
// Disable post-by-email
|
||||
// $config['emailpost']['enabled'] = false;
|
||||
|
||||
// Disable SMS
|
||||
// $config['sms']['enabled'] = false;
|
||||
|
||||
// Disable Twitter integration
|
||||
// $config['twitter']['enabled'] = false;
|
||||
|
||||
// Twitter integration source attribute. Note: default is Laconica
|
||||
// $config['integration']['source'] = 'Laconica';
|
||||
|
||||
|
@ -173,6 +187,10 @@ $config['sphinx']['port'] = 3312;
|
|||
//
|
||||
// $config['twitterbridge']['enabled'] = true;
|
||||
|
||||
// Twitter OAuth settings
|
||||
// $config['twitter']['consumer_key'] = 'YOURKEY';
|
||||
// $config['twitter']['consumer_secret'] = 'YOURSECRET';
|
||||
|
||||
// Edit throttling. Off by default. If turned on, you can only post 20 notices
|
||||
// every 10 minutes. Admins may want to play with the settings to minimize inconvenience for
|
||||
// real users without getting uncontrollable floods from spammers or runaway bots.
|
||||
|
@ -243,5 +261,6 @@ $config['sphinx']['port'] = 3312;
|
|||
// $config['attachments']['user_quota'] = 50000000;
|
||||
// $config['attachments']['monthly_quota'] = 15000000;
|
||||
// $config['attachments']['uploads'] = true;
|
||||
// $config['attachments']['path'] = "/file/";
|
||||
|
||||
// $config['oohembed']['endpoint'] = 'http://oohembed.com/oohembed/';
|
||||
|
|
|
@ -1,2 +1,12 @@
|
|||
// SQL commands to update an 0.8.x version of Laconica
|
||||
// to 0.9.x.
|
||||
alter table notice
|
||||
modify column content text comment 'update content';
|
||||
|
||||
alter table message
|
||||
modify column content text comment 'message content';
|
||||
|
||||
alter table profile
|
||||
modify column bio text comment 'descriptive biography';
|
||||
|
||||
alter table user_group
|
||||
modify column description text comment 'group description';
|
||||
|
||||
|
|
2
db/08to09_pg.sql
Normal file
2
db/08to09_pg.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
// SQL commands to update an 0.8.x version of Laconica
|
||||
// to 0.9.x.
|
|
@ -6,7 +6,7 @@ create table profile (
|
|||
fullname varchar(255) comment 'display name',
|
||||
profileurl varchar(255) comment 'URL, cached so we dont regenerate',
|
||||
homepage varchar(255) comment 'identifying URL',
|
||||
bio varchar(140) comment 'descriptive biography',
|
||||
bio text comment 'descriptive biography',
|
||||
location varchar(255) comment 'physical location',
|
||||
created datetime not null comment 'date this record was created',
|
||||
modified timestamp comment 'date this record was modified',
|
||||
|
@ -110,7 +110,7 @@ create table notice (
|
|||
id integer auto_increment primary key comment 'unique identifier',
|
||||
profile_id integer not null comment 'who made the update' references profile (id),
|
||||
uri varchar(255) unique key comment 'universally unique identifier, usually a tag URI',
|
||||
content varchar(140) comment 'update content',
|
||||
content text comment 'update content',
|
||||
rendered text comment 'HTML version of the content',
|
||||
url varchar(255) comment 'URL of any attachment (image, video, bookmark, whatever)',
|
||||
created datetime not null comment 'date this record was created',
|
||||
|
@ -331,7 +331,7 @@ create table message (
|
|||
uri varchar(255) unique key comment 'universally unique identifier',
|
||||
from_profile integer not null comment 'who the message is from' references profile (id),
|
||||
to_profile integer not null comment 'who the message is to' references profile (id),
|
||||
content varchar(140) comment 'message content',
|
||||
content text comment 'message content',
|
||||
rendered text comment 'HTML version of the content',
|
||||
url varchar(255) comment 'URL of any attachment (image, video, bookmark, whatever)',
|
||||
created datetime not null comment 'date this record was created',
|
||||
|
@ -380,7 +380,7 @@ create table user_group (
|
|||
nickname varchar(64) unique key comment 'nickname for addressing',
|
||||
fullname varchar(255) comment 'display name',
|
||||
homepage varchar(255) comment 'URL, cached so we dont regenerate',
|
||||
description varchar(140) comment 'descriptive biography',
|
||||
description text comment 'group description',
|
||||
location varchar(255) comment 'related physical location, if any',
|
||||
|
||||
original_logo varchar(255) comment 'original size logo',
|
||||
|
@ -547,3 +547,13 @@ create table deleted_notice (
|
|||
index deleted_notice_profile_id_idx (profile_id)
|
||||
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
create table config (
|
||||
|
||||
section varchar(32) comment 'configuration section',
|
||||
setting varchar(32) comment 'configuration setting',
|
||||
value varchar(255) comment 'configuration value',
|
||||
|
||||
constraint primary key (section, setting)
|
||||
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
|
|
@ -22,6 +22,8 @@ VALUES
|
|||
('IdentiFox','IdentiFox','http://www.bitbucket.org/uncryptic/identifox/', now()),
|
||||
('identitwitch','IdentiTwitch','http://richfish.org/identitwitch/', now()),
|
||||
('LaTwit','LaTwit','http://latwit.mac65.com/', now()),
|
||||
('LiveTweeter', 'LiveTweeter', 'http://addons.songbirdnest.com/addon/1204', now()),
|
||||
('livetweeter', 'livetweeter', 'http://addons.songbirdnest.com/addon/1204', now()),
|
||||
('maisha', 'Maisha', 'http://maisha.grango.org/', now()),
|
||||
('mbpidgin','mbpidgin','http://code.google.com/p/microblog-purple/', now()),
|
||||
('Mobidentica', 'Mobidentica', 'http://www.substanceofcode.com/software/mobidentica/', now()),
|
||||
|
@ -34,6 +36,7 @@ VALUES
|
|||
('pocketwit','PockeTwit','http://code.google.com/p/pocketwit/', now()),
|
||||
('posty','Posty','http://spreadingfunkyness.com/posty/', now()),
|
||||
('qtwitter','qTwitter','http://qtwitter.ayoy.net/', now()),
|
||||
('qwit', 'Qwit', 'http://code.google.com/p/qwit/', now()),
|
||||
('royalewithcheese','Royale With Cheese','http://p.hellyeah.org/', now()),
|
||||
('rssdent','rssdent','http://github.com/zcopley/rssdent/tree/master', now()),
|
||||
('rygh.no','rygh.no','http://rygh.no/', now()),
|
||||
|
|
13
doc-src/im
13
doc-src/im
|
@ -32,4 +32,15 @@ currently-implemented commands:
|
|||
you subscribe to.
|
||||
* **off**: Turn off notifications. You'll no longer receive Jabber
|
||||
notifications.
|
||||
|
||||
* **stop**: Same as 'off'
|
||||
* **quit**: Same as 'off'
|
||||
* **help**: Show this help. List available Jabber/XMPP commands
|
||||
* **follow <nickname>**: Subscribe to <nickname>
|
||||
* **sub <nickname>**: Same as follow
|
||||
* **leave <nickname>**: Subscribe to <nickname>
|
||||
* **unsub <nickname>**: Same as leave
|
||||
* **d <nickname> <text>**: Send direct message to <nickname> with message body <text>
|
||||
* **get <nickname>**: Get last notice from <nickname>
|
||||
* **last <nickname>**: Same as 'get'
|
||||
* **whois <nickname>**: Get Profile info on <nickname>
|
||||
* **fav <nickname>**: Add user's last notice as a favorite
|
30
doc-src/sms
30
doc-src/sms
|
@ -44,24 +44,24 @@ You can use the following commands with %%site.name%%.
|
|||
* on - turn on notifications
|
||||
* off - turn off notifications
|
||||
* help - show this help
|
||||
* follow <nickname> - subscribe to user
|
||||
* leave <nickname> - unsubscribe from user
|
||||
* d <nickname> <text> - direct message to user
|
||||
* get <nickname> - get last notice from user
|
||||
* whois <nickname> - get profile info on user
|
||||
* fav <nickname> - add user's last notice as a 'fave'
|
||||
* follow <nickname> - subscribe to user
|
||||
* leave <nickname> - unsubscribe from user
|
||||
* d <nickname> <text> - direct message to user
|
||||
* get <nickname> - get last notice from user
|
||||
* whois <nickname> - get profile info on user
|
||||
* fav <nickname> - add user's last notice as a 'fave'
|
||||
* stats - get your stats
|
||||
* stop - same as 'off'
|
||||
* quit - same as 'off'
|
||||
* sub <nickname> - same as 'follow'
|
||||
* unsub <nickname> - same as 'leave'
|
||||
* last <nickname> - same as 'get'
|
||||
* on <nickname> - not yet implemented.
|
||||
* off <nickname> - not yet implemented.
|
||||
* nudge <nickname> - not yet implemented.
|
||||
* invite <phone number> - not yet implemented.
|
||||
* track <word> - not yet implemented.
|
||||
* untrack <word> - not yet implemented.
|
||||
* sub <nickname> - same as 'follow'
|
||||
* unsub <nickname> - same as 'leave'
|
||||
* last <nickname> - same as 'get'
|
||||
* on <nickname> - not yet implemented.
|
||||
* off <nickname> - not yet implemented.
|
||||
* nudge <nickname> - not yet implemented.
|
||||
* invite <phone number> - not yet implemented.
|
||||
* track <word> - not yet implemented.
|
||||
* untrack <word> - not yet implemented.
|
||||
* track off - not yet implemented.
|
||||
* untrack all - not yet implemented.
|
||||
* tracks - not yet implemented.
|
||||
|
|
51
extlib/libomb/base_url_xrds_mapper.php
Executable file
51
extlib/libomb/base_url_xrds_mapper.php
Executable file
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
require_once 'xrds_mapper.php';
|
||||
require_once 'constants.php';
|
||||
|
||||
/**
|
||||
* Map XRDS actions to URLs using base URLs.
|
||||
*
|
||||
* This interface specifies classes which write the XRDS file announcing
|
||||
* the OMB server. An instance of an implementing class should be passed to
|
||||
* OMB_Service_Provider->writeXRDS.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: 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/>.
|
||||
*
|
||||
* @package OMB
|
||||
* @author Adrian Lang <mail@adrianlang.de>
|
||||
* @copyright 2009 Adrian Lang
|
||||
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
|
||||
**/
|
||||
|
||||
class OMB_Base_URL_XRDS_Mapper implements OMB_XRDS_Mapper {
|
||||
|
||||
protected $urls;
|
||||
|
||||
public function __construct($oauth_base, $omb_base) {
|
||||
$this->urls = array(
|
||||
OAUTH_ENDPOINT_REQUEST => $oauth_base . 'requesttoken',
|
||||
OAUTH_ENDPOINT_AUTHORIZE => $oauth_base . 'userauthorization',
|
||||
OAUTH_ENDPOINT_ACCESS => $oauth_base . 'accesstoken',
|
||||
OMB_ENDPOINT_POSTNOTICE => $omb_base . 'postnotice',
|
||||
OMB_ENDPOINT_UPDATEPROFILE => $omb_base . 'updateprofile');
|
||||
}
|
||||
|
||||
public function getURL($action) {
|
||||
return $this->urls[$action];
|
||||
}
|
||||
}
|
||||
?>
|
58
extlib/libomb/constants.php
Normal file
58
extlib/libomb/constants.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
/**
|
||||
* Constants for libomb
|
||||
*
|
||||
* This file contains constant definitions for libomb. The defined constants
|
||||
* are service and namespace URIs for OAuth and OMB as used in XRDS.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: 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/>.
|
||||
*
|
||||
* @package OMB
|
||||
* @author Adrian Lang <mail@adrianlang.de>
|
||||
* @copyright 2009 Adrian Lang
|
||||
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
|
||||
**/
|
||||
|
||||
/**
|
||||
* The OMB constants.
|
||||
**/
|
||||
|
||||
define('OMB_VERSION_01', 'http://openmicroblogging.org/protocol/0.1');
|
||||
|
||||
/* The OMB version supported by this libomb version. */
|
||||
define('OMB_VERSION', OMB_VERSION_01);
|
||||
|
||||
define('OMB_ENDPOINT_UPDATEPROFILE', OMB_VERSION . '/updateProfile');
|
||||
define('OMB_ENDPOINT_POSTNOTICE', OMB_VERSION . '/postNotice');
|
||||
|
||||
/**
|
||||
* The OAuth constants.
|
||||
**/
|
||||
|
||||
define('OAUTH_NAMESPACE', 'http://oauth.net/core/1.0/');
|
||||
|
||||
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');
|
||||
|
||||
define('OAUTH_DISCOVERY', 'http://oauth.net/discovery/1.0');
|
||||
?>
|
200
extlib/libomb/datastore.php
Executable file
200
extlib/libomb/datastore.php
Executable file
|
@ -0,0 +1,200 @@
|
|||
<?php
|
||||
|
||||
require_once 'OAuth.php';
|
||||
|
||||
/**
|
||||
* Data access interface
|
||||
*
|
||||
* This interface specifies data access methods libomb needs. It should be
|
||||
* implemented by libomb users. OMB_Datastore is libomb’s main interface to the
|
||||
* application’s data. Objects corresponding to this interface are used in
|
||||
* OMB_Service_Provider and OMB_Service_Consumer.
|
||||
*
|
||||
* Note that it’s implemented as a class since OAuthDataStore is as well a
|
||||
* class, though only declaring methods.
|
||||
*
|
||||
* OMB_Datastore extends OAuthDataStore with two OAuth-related methods for token
|
||||
* revoking and authorizing and all OMB-related methods.
|
||||
* Refer to OAuth.php for a complete specification of OAuth-related methods.
|
||||
*
|
||||
* It is the user’s duty to signal and handle errors. libomb does not check
|
||||
* return values nor handle exceptions. It is suggested to use exceptions.
|
||||
* Note that lookup_token and getProfile return null if the requested object
|
||||
* is not available. This is NOT an error and should not raise an exception.
|
||||
* Same applies for lookup_nonce which returns a boolean value. These methods
|
||||
* may nevertheless throw an exception, for example in case of a storage errors.
|
||||
*
|
||||
* Most of the parameters passed to these methods are unescaped and unverified
|
||||
* user input. Therefore they should be handled with extra care to avoid
|
||||
* security problems like SQL injections.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: 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/>.
|
||||
*
|
||||
* @package OMB
|
||||
* @author Adrian Lang <mail@adrianlang.de>
|
||||
* @copyright 2009 Adrian Lang
|
||||
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
|
||||
**/
|
||||
|
||||
class OMB_Datastore extends OAuthDataStore {
|
||||
|
||||
/*********
|
||||
* OAUTH *
|
||||
*********/
|
||||
|
||||
/**
|
||||
* Revoke specified OAuth token
|
||||
*
|
||||
* Revokes the authorization token specified by $token_key.
|
||||
* Throws exceptions in case of error.
|
||||
*
|
||||
* @param string $token_key The key of the token to be revoked
|
||||
*
|
||||
* @access public
|
||||
**/
|
||||
public function revoke_token($token_key) {
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize specified OAuth token
|
||||
*
|
||||
* Authorizes the authorization token specified by $token_key.
|
||||
* Throws exceptions in case of error.
|
||||
*
|
||||
* @param string $token_key The key of the token to be authorized
|
||||
*
|
||||
* @access public
|
||||
**/
|
||||
public function authorize_token($token_key) {
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
/*********
|
||||
* OMB *
|
||||
*********/
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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($profile) {
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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. TODO: Ugly.
|
||||
* Throws exceptions in case of error.
|
||||
*
|
||||
* @param OMB_Notice $notice The OMB notice which should be saved
|
||||
*
|
||||
* @access public
|
||||
**/
|
||||
public function saveNotice(&$notice) {
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
?>
|
99
extlib/libomb/helper.php
Normal file
99
extlib/libomb/helper.php
Normal file
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
|
||||
require_once 'Validate.php';
|
||||
|
||||
/**
|
||||
* Helper functions for libomb
|
||||
*
|
||||
* This file contains helper functions for libomb.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: 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/>.
|
||||
*
|
||||
* @package OMB
|
||||
* @author Adrian Lang <mail@adrianlang.de>
|
||||
* @copyright 2009 Adrian Lang
|
||||
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
|
||||
**/
|
||||
|
||||
class OMB_Helper {
|
||||
|
||||
/**
|
||||
* Non-scalar constants
|
||||
*
|
||||
* The set of OMB and OAuth Services an OMB Server has to implement.
|
||||
*/
|
||||
|
||||
public static $OMB_SERVICES =
|
||||
array(OMB_ENDPOINT_UPDATEPROFILE, OMB_ENDPOINT_POSTNOTICE);
|
||||
public static $OAUTH_SERVICES =
|
||||
array(OAUTH_ENDPOINT_REQUEST, OAUTH_ENDPOINT_AUTHORIZE, OAUTH_ENDPOINT_ACCESS);
|
||||
|
||||
/**
|
||||
* Validate URL
|
||||
*
|
||||
* Basic URL validation. Currently http, https, ftp and gopher are supported
|
||||
* schemes.
|
||||
*
|
||||
* @param string $url The URL which is to be validated.
|
||||
*
|
||||
* @return bool Whether URL is valid.
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public static function validateURL($url) {
|
||||
return Validate::uri($url, array('allowed_schemes' => array('http', 'https',
|
||||
'gopher', 'ftp')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Media type
|
||||
*
|
||||
* Basic Media type validation. Checks for valid maintype and correct format.
|
||||
*
|
||||
* @param string $mediatype The Media type which is to be validated.
|
||||
*
|
||||
* @return bool Whether media type is valid.
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public static function validateMediaType($mediatype) {
|
||||
if (0 === preg_match('/^(\w+)\/([\w\d-+.]+)$/', $mediatype, $subtypes)) {
|
||||
return false;
|
||||
}
|
||||
if (!in_array(strtolower($subtypes[1]), array('application', 'audio', 'image',
|
||||
'message', 'model', 'multipart', 'text', 'video'))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove escaping from request parameters
|
||||
*
|
||||
* Neutralise the evil effects of magic_quotes_gpc in the current request.
|
||||
* This is used before handing a request off to OAuthRequest::from_request.
|
||||
* Many thanks to Ciaran Gultnieks for this fix.
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public static function removeMagicQuotesFromRequest() {
|
||||
if(get_magic_quotes_gpc() == 1) {
|
||||
$_POST = array_map('stripslashes', $_POST);
|
||||
$_GET = array_map('stripslashes', $_GET);
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
32
extlib/libomb/invalidparameterexception.php
Executable file
32
extlib/libomb/invalidparameterexception.php
Executable file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
/**
|
||||
* Exception stating that a passed parameter is invalid
|
||||
*
|
||||
* This exception is raised when a parameter does not obey the OMB standard.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: 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/>.
|
||||
*
|
||||
* @package OMB
|
||||
* @author Adrian Lang <mail@adrianlang.de>
|
||||
* @copyright 2009 Adrian Lang
|
||||
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
|
||||
**/
|
||||
class OMB_InvalidParameterException extends Exception {
|
||||
public function __construct($value, $type, $parameter) {
|
||||
parent::__construct("Invalid value $value for parameter $parameter in $type");
|
||||
}
|
||||
}
|
||||
?>
|
31
extlib/libomb/invalidyadisexception.php
Executable file
31
extlib/libomb/invalidyadisexception.php
Executable file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
/**
|
||||
* Exception stating that a requested url does not resolve to a valid yadis
|
||||
*
|
||||
* This exception is raised when OMB_Service is not able to discover a valid
|
||||
* yadis location with XRDS.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: 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/>.
|
||||
*
|
||||
* @package OMB
|
||||
* @author Adrian Lang <mail@adrianlang.de>
|
||||
* @copyright 2009 Adrian Lang
|
||||
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
|
||||
**/
|
||||
class OMB_InvalidYadisException extends Exception {
|
||||
|
||||
}
|
||||
?>
|
272
extlib/libomb/notice.php
Executable file
272
extlib/libomb/notice.php
Executable file
|
@ -0,0 +1,272 @@
|
|||
<?php
|
||||
require_once 'invalidparameterexception.php';
|
||||
require_once 'Validate.php';
|
||||
require_once 'helper.php';
|
||||
|
||||
/**
|
||||
* OMB Notice representation
|
||||
*
|
||||
* This class represents an OMB notice.
|
||||
*
|
||||
* Do not call the setters with null values. Instead, if you want to delete a
|
||||
* field, pass an empty string. The getters will return null for empty fields.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: 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/>.
|
||||
*
|
||||
* @package OMB
|
||||
* @author Adrian Lang <mail@adrianlang.de>
|
||||
* @copyright 2009 Adrian Lang
|
||||
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
|
||||
**/
|
||||
|
||||
class OMB_Notice {
|
||||
protected $author;
|
||||
protected $uri;
|
||||
protected $content;
|
||||
protected $url;
|
||||
protected $license_url; /* url is an own addition for clarification. */
|
||||
protected $seealso_url; /* url is an own addition for clarification. */
|
||||
protected $seealso_disposition;
|
||||
protected $seealso_mediatype;
|
||||
protected $seealso_license_url; /* url is an addition for clarification. */
|
||||
|
||||
/* The notice as OMB param array. Cached and rebuild on usage.
|
||||
false while outdated. */
|
||||
protected $param_array;
|
||||
|
||||
/**
|
||||
* Constructor for OMB_Notice
|
||||
*
|
||||
* Initializes the OMB_Notice object with author, uri and content.
|
||||
* These parameters are mandatory for postNotice.
|
||||
*
|
||||
* @param object $author An OMB_Profile object representing the author of the
|
||||
* notice.
|
||||
* @param string $uri The notice URI as defined by the OMB. A unique and
|
||||
* unchanging identifier for a notice.
|
||||
* @param string $content The content of the notice. 140 chars recommended,
|
||||
* but there is no limit.
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function __construct($author, $uri, $content) {
|
||||
$this->content = $content;
|
||||
if (is_null($author)) {
|
||||
throw new OMB_InvalidParameterException('', 'notice', 'omb_listenee');
|
||||
}
|
||||
$this->author = $author;
|
||||
|
||||
if (!Validate::uri($uri)) {
|
||||
throw new OMB_InvalidParameterException($uri, 'notice', 'omb_notice');
|
||||
}
|
||||
$this->uri = $uri;
|
||||
|
||||
$this->param_array = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the notice as array
|
||||
*
|
||||
* The method returns an array which contains the whole notice as array. The
|
||||
* array is cached and only rebuilt on changes of the notice.
|
||||
* Empty optional values are not passed.
|
||||
*
|
||||
* @access public
|
||||
* @returns array The notice as parameter array
|
||||
*/
|
||||
public function asParameters() {
|
||||
if ($this->param_array !== false) {
|
||||
return $this->param_array;
|
||||
}
|
||||
|
||||
$this->param_array = array(
|
||||
'omb_notice' => $this->uri,
|
||||
'omb_notice_content' => $this->content);
|
||||
|
||||
if (!is_null($this->url))
|
||||
$this->param_array['omb_notice_url'] = $this->url;
|
||||
|
||||
if (!is_null($this->license_url))
|
||||
$this->param_array['omb_notice_license'] = $this->license_url;
|
||||
|
||||
if (!is_null($this->seealso_url)) {
|
||||
$this->param_array['omb_seealso'] = $this->seealso_url;
|
||||
|
||||
/* This is actually a free interpretation of the OMB standard. We assume
|
||||
that additional seealso parameters are not of any use if seealso itself
|
||||
is not set. */
|
||||
if (!is_null($this->seealso_disposition))
|
||||
$this->param_array['omb_seealso_disposition'] =
|
||||
$this->seealso_disposition;
|
||||
|
||||
if (!is_null($this->seealso_mediatype))
|
||||
$this->param_array['omb_seealso_mediatype'] = $this->seealso_mediatype;
|
||||
|
||||
if (!is_null($this->seealso_license_url))
|
||||
$this->param_array['omb_seealso_license'] = $this->seealso_license_url;
|
||||
}
|
||||
return $this->param_array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an OMB_Notice object from array
|
||||
*
|
||||
* The method builds an OMB_Notice object from the passed parameters array.
|
||||
* The array MUST provide a notice URI and content. The array fields HAVE TO
|
||||
* be named according to the OMB standard, i. e. omb_notice_* and
|
||||
* omb_seealso_*. Values are handled as not passed if the corresponding array
|
||||
* fields are not set or the empty string.
|
||||
*
|
||||
* @param object $author An OMB_Profile object representing the author of
|
||||
* the notice.
|
||||
* @param string $parameters An array containing the notice parameters.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @returns OMB_Notice The built OMB_Notice.
|
||||
*/
|
||||
public static function fromParameters($author, $parameters) {
|
||||
$notice = new OMB_Notice($author, $parameters['omb_notice'],
|
||||
$parameters['omb_notice_content']);
|
||||
|
||||
if (isset($parameters['omb_notice_url'])) {
|
||||
$notice->setURL($parameters['omb_notice_url']);
|
||||
}
|
||||
|
||||
if (isset($parameters['omb_notice_license'])) {
|
||||
$notice->setLicenseURL($parameters['omb_notice_license']);
|
||||
}
|
||||
|
||||
if (isset($parameters['omb_seealso'])) {
|
||||
$notice->setSeealsoURL($parameters['omb_seealso']);
|
||||
}
|
||||
|
||||
if (isset($parameters['omb_seealso_disposition'])) {
|
||||
$notice->setSeealsoDisposition($parameters['omb_seealso_disposition']);
|
||||
}
|
||||
|
||||
if (isset($parameters['omb_seealso_mediatype'])) {
|
||||
$notice->setSeealsoMediatype($parameters['omb_seealso_mediatype']);
|
||||
}
|
||||
|
||||
if (isset($parameters['omb_seealso_license'])) {
|
||||
$notice->setSeealsoLicenseURL($parameters['omb_seealso_license']);
|
||||
}
|
||||
return $notice;
|
||||
}
|
||||
|
||||
public function getAuthor() {
|
||||
return $this->author;
|
||||
}
|
||||
|
||||
public function getIdentifierURI() {
|
||||
return $this->uri;
|
||||
}
|
||||
|
||||
public function getContent() {
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function getURL() {
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
public function getLicenseURL() {
|
||||
return $this->license_url;
|
||||
}
|
||||
|
||||
public function getSeealsoURL() {
|
||||
return $this->seealso_url;
|
||||
}
|
||||
|
||||
public function getSeealsoDisposition() {
|
||||
return $this->seealso_disposition;
|
||||
}
|
||||
|
||||
public function getSeealsoMediatype() {
|
||||
return $this->seealso_mediatype;
|
||||
}
|
||||
|
||||
public function getSeealsoLicenseURL() {
|
||||
return $this->seealso_license_url;
|
||||
}
|
||||
|
||||
public function setURL($url) {
|
||||
if ($url === '') {
|
||||
$url = null;
|
||||
} elseif (!OMB_Helper::validateURL($url)) {
|
||||
throw new OMB_InvalidParameterException($url, 'notice', 'omb_notice_url');
|
||||
}
|
||||
$this->url = $url;
|
||||
$this->param_array = false;
|
||||
}
|
||||
|
||||
public function setLicenseURL($license_url) {
|
||||
if ($license_url === '') {
|
||||
$license_url = null;
|
||||
} elseif (!OMB_Helper::validateURL($license_url)) {
|
||||
throw new OMB_InvalidParameterException($license_url, 'notice',
|
||||
'omb_notice_license');
|
||||
}
|
||||
$this->license_url = $license_url;
|
||||
$this->param_array = false;
|
||||
}
|
||||
|
||||
public function setSeealsoURL($seealso_url) {
|
||||
if ($seealso_url === '') {
|
||||
$seealso_url = null;
|
||||
} elseif (!OMB_Helper::validateURL($seealso_url)) {
|
||||
throw new OMB_InvalidParameterException($seealso_url, 'notice',
|
||||
'omb_seealso');
|
||||
}
|
||||
$this->seealso_url = $seealso_url;
|
||||
$this->param_array = false;
|
||||
}
|
||||
|
||||
public function setSeealsoDisposition($seealso_disposition) {
|
||||
if ($seealso_disposition === '') {
|
||||
$seealso_disposition = null;
|
||||
} elseif ($seealso_disposition !== 'link' && $seealso_disposition !== 'inline') {
|
||||
throw new OMB_InvalidParameterException($seealso_disposition, 'notice',
|
||||
'omb_seealso_disposition');
|
||||
}
|
||||
$this->seealso_disposition = $seealso_disposition;
|
||||
$this->param_array = false;
|
||||
}
|
||||
|
||||
public function setSeealsoMediatype($seealso_mediatype) {
|
||||
if ($seealso_mediatype === '') {
|
||||
$seealso_mediatype = null;
|
||||
} elseif (!OMB_Helper::validateMediaType($seealso_mediatype)) {
|
||||
throw new OMB_InvalidParameterException($seealso_mediatype, 'notice',
|
||||
'omb_seealso_mediatype');
|
||||
}
|
||||
$this->seealso_mediatype = $seealso_mediatype;
|
||||
$this->param_array = false;
|
||||
}
|
||||
|
||||
public function setSeealsoLicenseURL($seealso_license_url) {
|
||||
if ($seealso_license_url === '') {
|
||||
$seealso_license_url = null;
|
||||
} elseif (!OMB_Helper::validateURL($seealso_license_url)) {
|
||||
throw new OMB_InvalidParameterException($seealso_license_url, 'notice',
|
||||
'omb_seealso_license');
|
||||
}
|
||||
$this->seealso_license_url = $seealso_license_url;
|
||||
$this->param_array = false;
|
||||
}
|
||||
}
|
||||
?>
|
196
extlib/libomb/omb_yadis_xrds.php
Executable file
196
extlib/libomb/omb_yadis_xrds.php
Executable file
|
@ -0,0 +1,196 @@
|
|||
<?php
|
||||
|
||||
require_once 'Auth/Yadis/Yadis.php';
|
||||
require_once 'unsupportedserviceexception.php';
|
||||
require_once 'invalidyadisexception.php';
|
||||
|
||||
/**
|
||||
* OMB XRDS representation
|
||||
*
|
||||
* This class represents a Yadis XRDS file for OMB. It adds some useful methods to
|
||||
* Auth_Yadis_XRDS.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: 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/>.
|
||||
*
|
||||
* @package OMB
|
||||
* @author Adrian Lang <mail@adrianlang.de>
|
||||
* @copyright 2009 Adrian Lang
|
||||
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
|
||||
**/
|
||||
|
||||
class OMB_Yadis_XRDS extends Auth_Yadis_XRDS {
|
||||
|
||||
protected $fetcher;
|
||||
|
||||
/**
|
||||
* Create an instance from URL
|
||||
*
|
||||
* Constructs an OMB_Yadis_XRDS object from a given URL. A full Yadis
|
||||
* discovery is performed on the URL and the XRDS is parsed.
|
||||
* Throws an OMB_InvalidYadisException when no Yadis is discovered or the
|
||||
* detected XRDS file is broken.
|
||||
*
|
||||
* @param string $url The URL on which Yadis discovery
|
||||
* should be performed on
|
||||
* @param Auth_Yadis_HTTPFetcher $fetcher A fetcher used to get HTTP
|
||||
* resources
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return OMB_Yadis_XRDS The initialized object representing the given
|
||||
* resource
|
||||
**/
|
||||
public static function fromYadisURL($url, $fetcher) {
|
||||
/* Perform a Yadis discovery. */
|
||||
$yadis = Auth_Yadis_Yadis::discover($url, $fetcher);
|
||||
if ($yadis->failed) {
|
||||
throw new OMB_InvalidYadisException($url);
|
||||
}
|
||||
|
||||
/* Parse the XRDS file. */
|
||||
$xrds = OMB_Yadis_XRDS::parseXRDS($yadis->response_text);
|
||||
if ($xrds === null) {
|
||||
throw new OMB_InvalidYadisException($url);
|
||||
}
|
||||
$xrds->fetcher = $fetcher;
|
||||
return $xrds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific service
|
||||
*
|
||||
* Returns the Auth_Yadis_Service object corresponding to the given service
|
||||
* URI.
|
||||
* Throws an OMB_UnsupportedServiceException if the service is not available.
|
||||
*
|
||||
* @param string $service URI specifier of the requested service
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return Auth_Yadis_Service The object representing the requested service
|
||||
**/
|
||||
public function getService($service) {
|
||||
$match = $this->services(array( create_function('$s',
|
||||
"return in_array('$service', \$s->getTypes());")));
|
||||
if ($match === array()) {
|
||||
throw new OMB_UnsupportedServiceException($service);
|
||||
}
|
||||
return $match[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific XRD
|
||||
*
|
||||
* Returns the OMB_Yadis_XRDS object corresponding to the given URI.
|
||||
* Throws an OMB_UnsupportedServiceException if the XRD is not available.
|
||||
* Note that getXRD tries to resolve external XRD parts as well.
|
||||
*
|
||||
* @param string $uri URI specifier of the requested XRD
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return OMB_Yadis_XRDS The object representing the requested XRD
|
||||
**/
|
||||
public function getXRD($uri) {
|
||||
$nexthash = strpos($uri, '#');
|
||||
if ($nexthash !== 0) {
|
||||
if ($nexthash !== false) {
|
||||
$cururi = substr($uri, 0, $nexthash);
|
||||
$nexturi = substr($uri, $nexthash);
|
||||
}
|
||||
return
|
||||
OMB_Yadis_XRDS::fromYadisURL($cururi, $this->fetcher)->getXRD($nexturi);
|
||||
}
|
||||
|
||||
$id = substr($uri, 1);
|
||||
foreach ($this->allXrdNodes as $node) {
|
||||
$attrs = $this->parser->attributes($node);
|
||||
if (array_key_exists('xml:id', $attrs) && $attrs['xml:id'] == $id) {
|
||||
/* Trick the constructor into thinking this is the only node. */
|
||||
$bogus_nodes = array($node);
|
||||
return new OMB_Yadis_XRDS($this->parser, $bogus_nodes);
|
||||
}
|
||||
}
|
||||
throw new OMB_UnsupportedServiceException($uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an XML string containing a XRDS document
|
||||
*
|
||||
* Parse an XML string (XRDS document) and return either a
|
||||
* Auth_Yadis_XRDS object or null, depending on whether the
|
||||
* XRDS XML is valid.
|
||||
* Copy and paste from parent to select correct constructor.
|
||||
*
|
||||
* @param string $xml_string An XRDS XML string.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return mixed An instance of OMB_Yadis_XRDS or null,
|
||||
* depending on the validity of $xml_string
|
||||
**/
|
||||
|
||||
public function &parseXRDS($xml_string, $extra_ns_map = null) {
|
||||
$_null = null;
|
||||
|
||||
if (!$xml_string) {
|
||||
return $_null;
|
||||
}
|
||||
|
||||
$parser = Auth_Yadis_getXMLParser();
|
||||
|
||||
$ns_map = Auth_Yadis_getNSMap();
|
||||
|
||||
if ($extra_ns_map && is_array($extra_ns_map)) {
|
||||
$ns_map = array_merge($ns_map, $extra_ns_map);
|
||||
}
|
||||
|
||||
if (!($parser && $parser->init($xml_string, $ns_map))) {
|
||||
return $_null;
|
||||
}
|
||||
|
||||
// Try to get root element.
|
||||
$root = $parser->evalXPath('/xrds:XRDS[1]');
|
||||
if (!$root) {
|
||||
return $_null;
|
||||
}
|
||||
|
||||
if (is_array($root)) {
|
||||
$root = $root[0];
|
||||
}
|
||||
|
||||
$attrs = $parser->attributes($root);
|
||||
|
||||
if (array_key_exists('xmlns:xrd', $attrs) &&
|
||||
$attrs['xmlns:xrd'] != Auth_Yadis_XMLNS_XRDS) {
|
||||
return $_null;
|
||||
} else if (array_key_exists('xmlns', $attrs) &&
|
||||
preg_match('/xri/', $attrs['xmlns']) &&
|
||||
$attrs['xmlns'] != Auth_Yadis_XMLNS_XRD_2_0) {
|
||||
return $_null;
|
||||
}
|
||||
|
||||
// Get the last XRD node.
|
||||
$xrd_nodes = $parser->evalXPath('/xrds:XRDS[1]/xrd:XRD');
|
||||
|
||||
if (!$xrd_nodes) {
|
||||
return $_null;
|
||||
}
|
||||
|
||||
$xrds = new OMB_Yadis_XRDS($parser, $xrd_nodes);
|
||||
return $xrds;
|
||||
}
|
||||
}
|
124
extlib/libomb/plain_xrds_writer.php
Executable file
124
extlib/libomb/plain_xrds_writer.php
Executable file
|
@ -0,0 +1,124 @@
|
|||
<?php
|
||||
|
||||
require_once 'xrds_writer.php';
|
||||
|
||||
/**
|
||||
* Write OMB-specific XRDS using XMLWriter.
|
||||
*
|
||||
* This class writes the XRDS file announcing the OMB server. It uses
|
||||
* OMB_XMLWriter, which is a subclass of XMLWriter. An instance of
|
||||
* OMB_Plain_XRDS_Writer should be passed to OMB_Service_Provider->writeXRDS.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: 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/>.
|
||||
*
|
||||
* @package OMB
|
||||
* @author Adrian Lang <mail@adrianlang.de>
|
||||
* @copyright 2009 Adrian Lang
|
||||
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
|
||||
**/
|
||||
|
||||
class OMB_Plain_XRDS_Writer implements OMB_XRDS_Writer {
|
||||
public function writeXRDS($user, $mapper) {
|
||||
header('Content-Type: application/xrds+xml');
|
||||
$xw = new XMLWriter();
|
||||
$xw->openURI('php://output');
|
||||
$xw->setIndent(true);
|
||||
|
||||
$xw->startDocument('1.0', 'UTF-8');
|
||||
$this->writeFullElement($xw, 'XRDS', array('xmlns' => 'xri://$xrds'), array(
|
||||
array('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
|
||||
'xml:id' => 'oauth',
|
||||
'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
|
||||
'version' => '2.0'), array(
|
||||
array('Type', null, 'xri://$xrds*simple'),
|
||||
array('Service', null, array(
|
||||
array('Type', null, OAUTH_ENDPOINT_REQUEST),
|
||||
array('URI', null, $mapper->getURL(OAUTH_ENDPOINT_REQUEST)),
|
||||
array('Type', null, OAUTH_AUTH_HEADER),
|
||||
array('Type', null, OAUTH_POST_BODY),
|
||||
array('Type', null, OAUTH_HMAC_SHA1),
|
||||
array('LocalID', null, $user->getIdentifierURI())
|
||||
)),
|
||||
array('Service', null, array(
|
||||
array('Type', null, OAUTH_ENDPOINT_AUTHORIZE),
|
||||
array('URI', null, $mapper->getURL(OAUTH_ENDPOINT_AUTHORIZE)),
|
||||
array('Type', null, OAUTH_AUTH_HEADER),
|
||||
array('Type', null, OAUTH_POST_BODY),
|
||||
array('Type', null, OAUTH_HMAC_SHA1)
|
||||
)),
|
||||
array('Service', null, array(
|
||||
array('Type', null, OAUTH_ENDPOINT_ACCESS),
|
||||
array('URI', null, $mapper->getURL(OAUTH_ENDPOINT_ACCESS)),
|
||||
array('Type', null, OAUTH_AUTH_HEADER),
|
||||
array('Type', null, OAUTH_POST_BODY),
|
||||
array('Type', null, OAUTH_HMAC_SHA1)
|
||||
)),
|
||||
array('Service', null, array(
|
||||
array('Type', null, OAUTH_ENDPOINT_RESOURCE),
|
||||
array('Type', null, OAUTH_AUTH_HEADER),
|
||||
array('Type', null, OAUTH_POST_BODY),
|
||||
array('Type', null, OAUTH_HMAC_SHA1)
|
||||
))
|
||||
)),
|
||||
array('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
|
||||
'xml:id' => 'omb',
|
||||
'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
|
||||
'version' => '2.0'), array(
|
||||
array('Type', null, 'xri://$xrds*simple'),
|
||||
array('Service', null, array(
|
||||
array('Type', null, OMB_ENDPOINT_POSTNOTICE),
|
||||
array('URI', null, $mapper->getURL(OMB_ENDPOINT_POSTNOTICE))
|
||||
)),
|
||||
array('Service', null, array(
|
||||
array('Type', null, OMB_ENDPOINT_UPDATEPROFILE),
|
||||
array('URI', null, $mapper->getURL(OMB_ENDPOINT_UPDATEPROFILE))
|
||||
))
|
||||
)),
|
||||
array('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
|
||||
'version' => '2.0'), array(
|
||||
array('Type', null, 'xri://$xrds*simple'),
|
||||
array('Service', null, array(
|
||||
array('Type', null, OAUTH_DISCOVERY),
|
||||
array('URI', null, '#oauth')
|
||||
)),
|
||||
array('Service', null, array(
|
||||
array('Type', null, OMB_VERSION),
|
||||
array('URI', null, '#omb')
|
||||
))
|
||||
))
|
||||
));
|
||||
$xw->endDocument();
|
||||
$xw->flush();
|
||||
}
|
||||
|
||||
public static function writeFullElement($xw, $tag, $attributes, $content) {
|
||||
$xw->startElement($tag);
|
||||
if (!is_null($attributes)) {
|
||||
foreach ($attributes as $name => $value) {
|
||||
$xw->writeAttribute($name, $value);
|
||||
}
|
||||
}
|
||||
if (is_array($content)) {
|
||||
foreach ($content as $values) {
|
||||
OMB_Plain_XRDS_Writer::writeFullElement($xw, $values[0], $values[1], $values[2]);
|
||||
}
|
||||
} else {
|
||||
$xw->text($content);
|
||||
}
|
||||
$xw->fullEndElement();
|
||||
}
|
||||
}
|
||||
?>
|
317
extlib/libomb/profile.php
Executable file
317
extlib/libomb/profile.php
Executable file
|
@ -0,0 +1,317 @@
|
|||
<?php
|
||||
require_once 'invalidparameterexception.php';
|
||||
require_once 'Validate.php';
|
||||
require_once 'helper.php';
|
||||
|
||||
/**
|
||||
* OMB profile representation
|
||||
*
|
||||
* This class represents an OMB profile.
|
||||
*
|
||||
* Do not call the setters with null values. Instead, if you want to delete a
|
||||
* field, pass an empty string. The getters will return null for empty fields.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: 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/>.
|
||||
*
|
||||
* @package OMB
|
||||
* @author Adrian Lang <mail@adrianlang.de>
|
||||
* @copyright 2009 Adrian Lang
|
||||
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
|
||||
**/
|
||||
|
||||
class OMB_Profile {
|
||||
protected $identifier_uri;
|
||||
protected $profile_url;
|
||||
protected $nickname;
|
||||
protected $license_url;
|
||||
protected $fullname;
|
||||
protected $homepage;
|
||||
protected $bio;
|
||||
protected $location;
|
||||
protected $avatar_url;
|
||||
|
||||
/* The profile as OMB param array. Cached and rebuild on usage.
|
||||
false while outdated. */
|
||||
protected $param_array;
|
||||
|
||||
/**
|
||||
* Constructor for OMB_Profile
|
||||
*
|
||||
* Initializes the OMB_Profile object with an identifier uri.
|
||||
*
|
||||
* @param string $identifier_uri The profile URI as defined by the OMB. A unique
|
||||
* and unchanging identifier for a profile.
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function __construct($identifier_uri) {
|
||||
if (!Validate::uri($identifier_uri)) {
|
||||
throw new OMB_InvalidParameterException($identifier_uri, 'profile',
|
||||
'omb_listenee or omb_listener');
|
||||
}
|
||||
$this->identifier_uri = $identifier_uri;
|
||||
$this->param_array = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the profile as array
|
||||
*
|
||||
* The method returns an array which contains the whole profile as array. The
|
||||
* array is cached and only rebuilt on changes of the profile.
|
||||
*
|
||||
* @param bool $force_all Specifies whether empty fields should be added to
|
||||
* the array as well. This is neccessary to clear
|
||||
* fields via updateProfile.
|
||||
*
|
||||
* @param string $prefix The common prefix to the key for all parameters.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return array The profile as parameter array
|
||||
*/
|
||||
public function asParameters($prefix, $force_all = false) {
|
||||
if ($this->param_array === false) {
|
||||
$this->param_array = array('' => $this->identifier_uri);
|
||||
|
||||
if ($force_all || !is_null($this->profile_url)) {
|
||||
$this->param_array['_profile'] = $this->profile_url;
|
||||
}
|
||||
|
||||
if ($force_all || !is_null($this->homepage)) {
|
||||
$this->param_array['_homepage'] = $this->homepage;
|
||||
}
|
||||
|
||||
if ($force_all || !is_null($this->nickname)) {
|
||||
$this->param_array['_nickname'] = $this->nickname;
|
||||
}
|
||||
|
||||
if ($force_all || !is_null($this->license_url)) {
|
||||
$this->param_array['_license'] = $this->license_url;
|
||||
}
|
||||
|
||||
if ($force_all || !is_null($this->fullname)) {
|
||||
$this->param_array['_fullname'] = $this->fullname;
|
||||
}
|
||||
|
||||
if ($force_all || !is_null($this->bio)) {
|
||||
$this->param_array['_bio'] = $this->bio;
|
||||
}
|
||||
|
||||
if ($force_all || !is_null($this->location)) {
|
||||
$this->param_array['_location'] = $this->location;
|
||||
}
|
||||
|
||||
if ($force_all || !is_null($this->avatar_url)) {
|
||||
$this->param_array['_avatar'] = $this->avatar_url;
|
||||
}
|
||||
|
||||
}
|
||||
$ret = array();
|
||||
foreach ($this->param_array as $k => $v) {
|
||||
$ret[$prefix . $k] = $v;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an OMB_Profile object from array
|
||||
*
|
||||
* The method builds an OMB_Profile object from the passed parameters array. The
|
||||
* array MUST provide a profile URI. The array fields HAVE TO be named according
|
||||
* to the OMB standard. The prefix (omb_listener or omb_listenee) is passed as a
|
||||
* parameter.
|
||||
*
|
||||
* @param string $parameters An array containing the profile parameters.
|
||||
* @param string $prefix The common prefix of the profile parameter keys.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @returns OMB_Profile The built OMB_Profile.
|
||||
*/
|
||||
public static function fromParameters($parameters, $prefix) {
|
||||
if (!isset($parameters[$prefix])) {
|
||||
throw new OMB_InvalidParameterException('', 'profile', $prefix);
|
||||
}
|
||||
|
||||
$profile = new OMB_Profile($parameters[$prefix]);
|
||||
$profile->updateFromParameters($parameters, $prefix);
|
||||
return $profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update from array
|
||||
*
|
||||
* Updates from the passed parameters array. The array does not have to
|
||||
* provide a profile URI. The array fields HAVE TO be named according to the
|
||||
* OMB standard. The prefix (omb_listener or omb_listenee) is passed as a
|
||||
* parameter.
|
||||
*
|
||||
* @param string $parameters An array containing the profile parameters.
|
||||
* @param string $prefix The common prefix of the profile parameter keys.
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function updateFromParameters($parameters, $prefix) {
|
||||
if (isset($parameters[$prefix.'_profile'])) {
|
||||
$this->setProfileURL($parameters[$prefix.'_profile']);
|
||||
}
|
||||
|
||||
if (isset($parameters[$prefix.'_license'])) {
|
||||
$this->setLicenseURL($parameters[$prefix.'_license']);
|
||||
}
|
||||
|
||||
if (isset($parameters[$prefix.'_nickname'])) {
|
||||
$this->setNickname($parameters[$prefix.'_nickname']);
|
||||
}
|
||||
|
||||
if (isset($parameters[$prefix.'_fullname'])) {
|
||||
$this->setFullname($parameters[$prefix.'_fullname']);
|
||||
}
|
||||
|
||||
if (isset($parameters[$prefix.'_homepage'])) {
|
||||
$this->setHomepage($parameters[$prefix.'_homepage']);
|
||||
}
|
||||
|
||||
if (isset($parameters[$prefix.'_bio'])) {
|
||||
$this->setBio($parameters[$prefix.'_bio']);
|
||||
}
|
||||
|
||||
if (isset($parameters[$prefix.'_location'])) {
|
||||
$this->setLocation($parameters[$prefix.'_location']);
|
||||
}
|
||||
|
||||
if (isset($parameters[$prefix.'_avatar'])) {
|
||||
$this->setAvatarURL($parameters[$prefix.'_avatar']);
|
||||
}
|
||||
}
|
||||
|
||||
public function getIdentifierURI() {
|
||||
return $this->identifier_uri;
|
||||
}
|
||||
|
||||
public function getProfileURL() {
|
||||
return $this->profile_url;
|
||||
}
|
||||
|
||||
public function getHomepage() {
|
||||
return $this->homepage;
|
||||
}
|
||||
|
||||
public function getNickname() {
|
||||
return $this->nickname;
|
||||
}
|
||||
|
||||
public function getLicenseURL() {
|
||||
return $this->license_url;
|
||||
}
|
||||
|
||||
public function getFullname() {
|
||||
return $this->fullname;
|
||||
}
|
||||
|
||||
public function getBio() {
|
||||
return $this->bio;
|
||||
}
|
||||
|
||||
public function getLocation() {
|
||||
return $this->location;
|
||||
}
|
||||
|
||||
public function getAvatarURL() {
|
||||
return $this->avatar_url;
|
||||
}
|
||||
|
||||
public function setProfileURL($profile_url) {
|
||||
if (!OMB_Helper::validateURL($profile_url)) {
|
||||
throw new OMB_InvalidParameterException($profile_url, 'profile',
|
||||
'omb_listenee_profile or omb_listener_profile');
|
||||
}
|
||||
$this->profile_url = $profile_url;
|
||||
$this->param_array = false;
|
||||
}
|
||||
|
||||
public function setNickname($nickname) {
|
||||
if (!Validate::string($nickname,
|
||||
array('min_length' => 1,
|
||||
'max_length' => 64,
|
||||
'format' => VALIDATE_NUM . VALIDATE_ALPHA))) {
|
||||
throw new OMB_InvalidParameterException($nickname, 'profile', 'nickname');
|
||||
}
|
||||
|
||||
$this->nickname = $nickname;
|
||||
$this->param_array = false;
|
||||
}
|
||||
|
||||
public function setLicenseURL($license_url) {
|
||||
if (!OMB_Helper::validateURL($license_url)) {
|
||||
throw new OMB_InvalidParameterException($license_url, 'profile',
|
||||
'omb_listenee_license or omb_listener_license');
|
||||
}
|
||||
$this->license_url = $license_url;
|
||||
$this->param_array = false;
|
||||
}
|
||||
|
||||
public function setFullname($fullname) {
|
||||
if ($fullname === '') {
|
||||
$fullname = null;
|
||||
} elseif (!Validate::string($fullname, array('max_length' => 255))) {
|
||||
throw new OMB_InvalidParameterException($fullname, 'profile', 'fullname');
|
||||
}
|
||||
$this->fullname = $fullname;
|
||||
$this->param_array = false;
|
||||
}
|
||||
|
||||
public function setHomepage($homepage) {
|
||||
if ($homepage === '') {
|
||||
$homepage = null;
|
||||
}
|
||||
$this->homepage = $homepage;
|
||||
$this->param_array = false;
|
||||
}
|
||||
|
||||
public function setBio($bio) {
|
||||
if ($bio === '') {
|
||||
$bio = null;
|
||||
} elseif (!Validate::string($bio, array('max_length' => 140))) {
|
||||
throw new OMB_InvalidParameterException($bio, 'profile', 'fullname');
|
||||
}
|
||||
$this->bio = $bio;
|
||||
$this->param_array = false;
|
||||
}
|
||||
|
||||
public function setLocation($location) {
|
||||
if ($location === '') {
|
||||
$location = null;
|
||||
} elseif (!Validate::string($location, array('max_length' => 255))) {
|
||||
throw new OMB_InvalidParameterException($location, 'profile', 'fullname');
|
||||
}
|
||||
$this->location = $location;
|
||||
$this->param_array = false;
|
||||
}
|
||||
|
||||
public function setAvatarURL($avatar_url) {
|
||||
if ($avatar_url === '') {
|
||||
$avatar_url = null;
|
||||
} elseif (!OMB_Helper::validateURL($avatar_url)) {
|
||||
throw new OMB_InvalidParameterException($avatar_url, 'profile',
|
||||
'omb_listenee_avatar or omb_listener_avatar');
|
||||
}
|
||||
$this->avatar_url = $avatar_url;
|
||||
$this->param_array = false;
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
42
extlib/libomb/remoteserviceexception.php
Executable file
42
extlib/libomb/remoteserviceexception.php
Executable file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* Exception stating that the remote service had a failure
|
||||
*
|
||||
* This exception is raised when a remote service failed to return a valid
|
||||
* response to a request or send a valid request.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: 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/>.
|
||||
*
|
||||
* @package OMB
|
||||
* @author Adrian Lang <mail@adrianlang.de>
|
||||
* @copyright 2009 Adrian Lang
|
||||
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
|
||||
**/
|
||||
class OMB_RemoteServiceException extends Exception {
|
||||
public static function fromYadis($request_uri, $result) {
|
||||
if ($result->status == 200) {
|
||||
$err = 'Got wrong response ' . $result->body;
|
||||
} else {
|
||||
$err = 'Got error code ' . $result->status . ' with response ' . $result->body;
|
||||
}
|
||||
return new OMB_RemoteServiceException($request_uri . ': ' . $err);
|
||||
}
|
||||
|
||||
public static function forRequest($action_uri, $failure) {
|
||||
return new OMB_RemoteServiceException("Handler for $action_uri: " . $failure);
|
||||
}
|
||||
}
|
||||
?>
|
430
extlib/libomb/service_consumer.php
Executable file
430
extlib/libomb/service_consumer.php
Executable file
|
@ -0,0 +1,430 @@
|
|||
<?php
|
||||
|
||||
require_once 'constants.php';
|
||||
require_once 'Validate.php';
|
||||
require_once 'Auth/Yadis/Yadis.php';
|
||||
require_once 'OAuth.php';
|
||||
require_once 'unsupportedserviceexception.php';
|
||||
require_once 'remoteserviceexception.php';
|
||||
require_once 'omb_yadis_xrds.php';
|
||||
require_once 'helper.php';
|
||||
|
||||
/**
|
||||
* OMB service representation
|
||||
*
|
||||
* This class represents a complete remote OMB service. It provides discovery
|
||||
* and execution of the service’s methods.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: 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/>.
|
||||
*
|
||||
* @package OMB
|
||||
* @author Adrian Lang <mail@adrianlang.de>
|
||||
* @copyright 2009 Adrian Lang
|
||||
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
|
||||
**/
|
||||
|
||||
class OMB_Service_Consumer {
|
||||
protected $url; /* The service URL */
|
||||
protected $services; /* An array of strings mapping service URI to
|
||||
service URL */
|
||||
|
||||
protected $token; /* An OAuthToken */
|
||||
|
||||
protected $listener_uri; /* The URI identifying the listener, i. e. the
|
||||
remote user. */
|
||||
|
||||
protected $listenee_uri; /* The URI identifying the listenee, i. e. the
|
||||
local user during an auth request. */
|
||||
|
||||
/**
|
||||
* According to OAuth Core 1.0, an user authorization request is no full-blown
|
||||
* OAuth request. nonce, timestamp, consumer_key and signature are not needed
|
||||
* in this step. See http://laconi.ca/trac/ticket/827 for more informations.
|
||||
*
|
||||
* Since Laconica up to version 0.7.2 performs a full OAuth request check, a
|
||||
* correct request would fail.
|
||||
**/
|
||||
public $performLegacyAuthRequest = true;
|
||||
|
||||
/* Helper stuff we are going to need. */
|
||||
protected $fetcher;
|
||||
protected $oauth_consumer;
|
||||
protected $datastore;
|
||||
|
||||
/**
|
||||
* Constructor for OMB_Service_Consumer
|
||||
*
|
||||
* Initializes an OMB_Service_Consumer object representing the OMB service
|
||||
* specified by $service_url. Performs a complete service discovery using
|
||||
* Yadis.
|
||||
* Throws OMB_UnsupportedServiceException if XRDS file does not specify a
|
||||
* complete OMB service.
|
||||
*
|
||||
* @param string $service_url The URL of the service
|
||||
* @param string $consumer_url An URL representing the consumer
|
||||
* @param OMB_Datastore $datastore An instance of a class implementing
|
||||
* OMB_Datastore
|
||||
*
|
||||
* @access public
|
||||
**/
|
||||
public function __construct ($service_url, $consumer_url, $datastore) {
|
||||
$this->url = $service_url;
|
||||
$this->fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
|
||||
$this->datastore = $datastore;
|
||||
$this->oauth_consumer = new OAuthConsumer($consumer_url, '');
|
||||
|
||||
$xrds = OMB_Yadis_XRDS::fromYadisURL($service_url, $this->fetcher);
|
||||
|
||||
/* Detect our services. This performs a validation as well, since
|
||||
getService und getXRD throw exceptions on failure. */
|
||||
$this->services = array();
|
||||
|
||||
foreach (array(OAUTH_DISCOVERY => OMB_Helper::$OAUTH_SERVICES,
|
||||
OMB_VERSION => OMB_Helper::$OMB_SERVICES)
|
||||
as $service_root => $targetservices) {
|
||||
$uris = $xrds->getService($service_root)->getURIs();
|
||||
$xrd = $xrds->getXRD($uris[0]);
|
||||
foreach ($targetservices as $targetservice) {
|
||||
$yadis_service = $xrd->getService($targetservice);
|
||||
if ($targetservice == OAUTH_ENDPOINT_REQUEST) {
|
||||
$localid = $yadis_service->getElements('xrd:LocalID');
|
||||
$this->listener_uri = $yadis_service->parser->content($localid[0]);
|
||||
}
|
||||
$uris = $yadis_service->getURIs();
|
||||
$this->services[$targetservice] = $uris[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the handler URI for a service
|
||||
*
|
||||
* Returns the URI the remote web service has specified for the given
|
||||
* service.
|
||||
*
|
||||
* @param string $service The URI identifying the service
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return string The service handler URI
|
||||
**/
|
||||
public function getServiceURI($service) {
|
||||
return $this->services[$service];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the remote user’s URI
|
||||
*
|
||||
* Returns the URI of the remote user, i. e. the listener.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return string The remote user’s URI
|
||||
**/
|
||||
public function getRemoteUserURI() {
|
||||
return $this->listener_uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the listenee’s URI
|
||||
*
|
||||
* Returns the URI of the user being subscribed to, i. e. the local user.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return string The local user’s URI
|
||||
**/
|
||||
public function getListeneeURI() {
|
||||
return $this->listenee_uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request a request token
|
||||
*
|
||||
* Performs a token request on the service. Returns an OAuthToken on success.
|
||||
* Throws an exception if the request fails.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return OAuthToken An unauthorized request token
|
||||
**/
|
||||
public function requestToken() {
|
||||
/* Set the token to null just in case the user called setToken. */
|
||||
$this->token = null;
|
||||
|
||||
$result = $this->performAction(OAUTH_ENDPOINT_REQUEST,
|
||||
array('omb_listener' => $this->listener_uri));
|
||||
if ($result->status != 200) {
|
||||
throw OMB_RemoteServiceException::fromYadis(OAUTH_ENDPOINT_REQUEST,
|
||||
$result);
|
||||
}
|
||||
parse_str($result->body, $return);
|
||||
if (!isset($return['oauth_token']) || !isset($return['oauth_token_secret'])) {
|
||||
throw OMB_RemoteServiceException::fromYadis(OAUTH_ENDPOINT_REQUEST,
|
||||
$result);
|
||||
}
|
||||
$this->setToken($return['oauth_token'], $return['oauth_token_secret']);
|
||||
return $this->token;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Request authorization
|
||||
*
|
||||
* Returns an URL which equals to an authorization request. The end user
|
||||
* should be redirected to this location to perform authorization.
|
||||
* The $finish_url should be a local resource which invokes
|
||||
* OMB_Consumer::finishAuthorization on request.
|
||||
*
|
||||
* @param OMB_Profile $profile An OMB_Profile object representing the
|
||||
* soon-to-be subscribed (i. e. local) user
|
||||
* @param string $finish_url Target location after successful
|
||||
* authorization
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return string An URL representing an authorization request
|
||||
**/
|
||||
public function requestAuthorization($profile, $finish_url) {
|
||||
if ($this->performLegacyAuthRequest) {
|
||||
$params = $profile->asParameters('omb_listenee', false);
|
||||
$params['omb_listener'] = $this->listener_uri;
|
||||
$params['oauth_callback'] = $finish_url;
|
||||
|
||||
$url = $this->prepareAction(OAUTH_ENDPOINT_AUTHORIZE, $params, 'GET')->to_url();
|
||||
} else {
|
||||
|
||||
$params = array(
|
||||
'oauth_callback' => $finish_url,
|
||||
'oauth_token' => $this->token->key,
|
||||
'omb_version' => OMB_VERSION,
|
||||
'omb_listener' => $this->listener_uri);
|
||||
|
||||
$params = array_merge($profile->asParameters('omb_listenee', false). $params);
|
||||
|
||||
/* Build result URL. */
|
||||
$url = $this->services[OAUTH_ENDPOINT_AUTHORIZE];
|
||||
$url .= (strrpos($url, '?') === false ? '?' : '&');
|
||||
foreach ($params as $k => $v) {
|
||||
$url .= OAuthUtil::urlencode_rfc3986($k) . '=' . OAuthUtil::urlencode_rfc3986($v) . '&';
|
||||
}
|
||||
}
|
||||
|
||||
$this->listenee_uri = $profile->getIdentifierURI();
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish authorization
|
||||
*
|
||||
* Finish the subscription process by converting the received and authorized
|
||||
* request token into an access token. After that, the subscriber’s profile
|
||||
* and the subscription are stored in the database.
|
||||
* Expects an OAuthRequest in query parameters.
|
||||
* Throws exceptions on failure.
|
||||
*
|
||||
* @access public
|
||||
**/
|
||||
public function finishAuthorization() {
|
||||
OMB_Helper::removeMagicQuotesFromRequest();
|
||||
$req = OAuthRequest::from_request();
|
||||
if ($req->get_parameter('oauth_token') !=
|
||||
$this->token->key) {
|
||||
/* That’s not the token I wanted to get authorized. */
|
||||
throw new OAuthException('The authorized token does not equal the ' .
|
||||
'submitted token.');
|
||||
}
|
||||
|
||||
if ($req->get_parameter('omb_version') != OMB_VERSION) {
|
||||
throw new OMB_RemoteServiceException('The remote service uses an ' .
|
||||
'unsupported OMB version');
|
||||
}
|
||||
|
||||
/* Construct the profile to validate it. */
|
||||
|
||||
/* Fix OMB bug. Listener URI is not passed. */
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$params = $_POST;
|
||||
} else {
|
||||
$params = $_GET;
|
||||
}
|
||||
$params['omb_listener'] = $this->listener_uri;
|
||||
|
||||
require_once 'profile.php';
|
||||
$listener = OMB_Profile::fromParameters($params, 'omb_listener');
|
||||
|
||||
/* Ask the remote service to convert the authorized request token into an
|
||||
access token. */
|
||||
|
||||
$result = $this->performAction(OAUTH_ENDPOINT_ACCESS, array());
|
||||
if ($result->status != 200) {
|
||||
throw new OAuthException('Could not get access token');
|
||||
}
|
||||
|
||||
parse_str($result->body, $return);
|
||||
if (!isset($return['oauth_token']) || !isset($return['oauth_token_secret'])) {
|
||||
throw new OAuthException('Could not get access token');
|
||||
}
|
||||
$this->setToken($return['oauth_token'], $return['oauth_token_secret']);
|
||||
|
||||
/* Subscription is finished and valid. Now store the new subscriber and the
|
||||
subscription in the database. */
|
||||
|
||||
$this->datastore->saveProfile($listener);
|
||||
$this->datastore->saveSubscription($this->listener_uri,
|
||||
$this->listenee_uri,
|
||||
$this->token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the URI identifying the listener
|
||||
*
|
||||
* Returns the URI for the OMB user who tries to subscribe or already has
|
||||
* subscribed our user. This method is a workaround for a serious OMB flaw:
|
||||
* The Listener URI is not passed in the finishauthorization call.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return string the listener’s URI
|
||||
**/
|
||||
public function getListenerURI() {
|
||||
return $this->listener_uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform the service about a profile update
|
||||
*
|
||||
* Sends an updated profile to the service.
|
||||
*
|
||||
* @param OMB_Profile $profile The profile that has changed
|
||||
*
|
||||
* @access public
|
||||
**/
|
||||
public function updateProfile($profile) {
|
||||
$params = $profile->asParameters('omb_listenee', true);
|
||||
$this->performOMBAction(OMB_ENDPOINT_UPDATEPROFILE, $params, $profile->getIdentifierURI());
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform the service about a new notice
|
||||
*
|
||||
* Sends a notice to the service.
|
||||
*
|
||||
* @param OMB_Notice $notice The notice
|
||||
*
|
||||
* @access public
|
||||
**/
|
||||
public function postNotice($notice) {
|
||||
$params = $notice->asParameters();
|
||||
$params['omb_listenee'] = $notice->getAuthor()->getIdentifierURI();
|
||||
$this->performOMBAction(OMB_ENDPOINT_POSTNOTICE, $params, $params['omb_listenee']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the token member variable
|
||||
*
|
||||
* Initializes the token based on given token and secret token.
|
||||
*
|
||||
* @param string $token The token
|
||||
* @param string $secret The secret token
|
||||
*
|
||||
* @access public
|
||||
**/
|
||||
public function setToken($token, $secret) {
|
||||
$this->token = new OAuthToken($token, $secret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an OAuthRequest object
|
||||
*
|
||||
* Creates an OAuthRequest object mapping the request specified by the
|
||||
* parameters.
|
||||
*
|
||||
* @param string $action_uri The URI specifying the target service
|
||||
* @param array $params Additional parameters for the service call
|
||||
* @param string $method The HTTP method used to call the service
|
||||
* ('POST' or 'GET', usually)
|
||||
*
|
||||
* @access protected
|
||||
*
|
||||
* @return OAuthRequest the prepared request
|
||||
**/
|
||||
protected function prepareAction($action_uri, $params, $method) {
|
||||
$url = $this->services[$action_uri];
|
||||
|
||||
$url_params = array();
|
||||
parse_str(parse_url($url, PHP_URL_QUERY), $url_params);
|
||||
|
||||
/* Add OMB version. */
|
||||
$url_params['omb_version'] = OMB_VERSION;
|
||||
|
||||
/* Add user-defined parameters. */
|
||||
$url_params = array_merge($url_params, $params);
|
||||
|
||||
$req = OAuthRequest::from_consumer_and_token($this->oauth_consumer,
|
||||
$this->token, $method, $url, $url_params);
|
||||
|
||||
/* Sign the request. */
|
||||
$req->sign_request(new OAuthSignatureMethod_HMAC_SHA1(),
|
||||
$this->oauth_consumer, $this->token);
|
||||
|
||||
return $req;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a service call
|
||||
*
|
||||
* Creates an OAuthRequest object and execute the mapped call as POST request.
|
||||
*
|
||||
* @param string $action_uri The URI specifying the target service
|
||||
* @param array $params Additional parameters for the service call
|
||||
*
|
||||
* @access protected
|
||||
*
|
||||
* @return Auth_Yadis_HTTPResponse The POST request response
|
||||
**/
|
||||
protected function performAction($action_uri, $params) {
|
||||
$req = $this->prepareAction($action_uri, $params, 'POST');
|
||||
|
||||
/* Return result page. */
|
||||
return $this->fetcher->post($req->get_normalized_http_url(), $req->to_postdata(), array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an OMB action
|
||||
*
|
||||
* Executes an OMB action – to date, it’s one of updateProfile or postNotice.
|
||||
*
|
||||
* @param string $action_uri The URI specifying the target service
|
||||
* @param array $params Additional parameters for the service call
|
||||
* @param string $listenee_uri The URI identifying the local user for whom
|
||||
* the action is performed
|
||||
*
|
||||
* @access protected
|
||||
**/
|
||||
protected function performOMBAction($action_uri, $params, $listenee_uri) {
|
||||
$result = $this->performAction($action_uri, $params);
|
||||
if ($result->status == 403) {
|
||||
/* The remote user unsubscribed us. */
|
||||
$this->datastore->deleteSubscription($this->listener_uri, $listenee_uri);
|
||||
} else if ($result->status != 200 ||
|
||||
strpos($result->body, 'omb_version=' . OMB_VERSION) === false) {
|
||||
/* The server signaled an error or sent an incorrect response. */
|
||||
throw OMB_RemoteServiceException::fromYadis($action_uri, $result);
|
||||
}
|
||||
}
|
||||
}
|
425
extlib/libomb/service_provider.php
Executable file
425
extlib/libomb/service_provider.php
Executable file
|
@ -0,0 +1,425 @@
|
|||
<?php
|
||||
|
||||
require_once 'constants.php';
|
||||
require_once 'remoteserviceexception.php';
|
||||
require_once 'helper.php';
|
||||
|
||||
/**
|
||||
* OMB service realization
|
||||
*
|
||||
* This class realizes a complete, simple OMB service.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: 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/>.
|
||||
*
|
||||
* @package OMB
|
||||
* @author Adrian Lang <mail@adrianlang.de>
|
||||
* @copyright 2009 Adrian Lang
|
||||
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
|
||||
**/
|
||||
|
||||
class OMB_Service_Provider {
|
||||
protected $user; /* An OMB_Profile representing the user */
|
||||
protected $datastore; /* AN OMB_Datastore */
|
||||
|
||||
protected $remote_user; /* An OMB_Profile representing the remote user during
|
||||
the authorization process */
|
||||
|
||||
protected $oauth_server; /* An OAuthServer; should only be accessed via
|
||||
getOAuthServer. */
|
||||
|
||||
/**
|
||||
* Initialize an OMB_Service_Provider object
|
||||
*
|
||||
* Constructs an OMB_Service_Provider instance that provides OMB services
|
||||
* referring to a particular user.
|
||||
*
|
||||
* @param OMB_Profile $user An OMB_Profile; mandatory for XRDS
|
||||
* output, user auth handling and OMB
|
||||
* action performing
|
||||
* @param OMB_Datastore $datastore An OMB_Datastore; mandatory for
|
||||
* everything but XRDS output
|
||||
* @param OAuthServer $oauth_server An OAuthServer; used for token writing
|
||||
* and OMB action handling; will use
|
||||
* default value if not set
|
||||
*
|
||||
* @access public
|
||||
**/
|
||||
public function __construct ($user = null, $datastore = null, $oauth_server = null) {
|
||||
$this->user = $user;
|
||||
$this->datastore = $datastore;
|
||||
$this->oauth_server = $oauth_server;
|
||||
}
|
||||
|
||||
public function getRemoteUser() {
|
||||
return $this->remote_user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a XRDS document
|
||||
*
|
||||
* Writes a XRDS document specifying the OMB service. Optionally uses a
|
||||
* given object of a class implementing OMB_XRDS_Writer for output. Else
|
||||
* OMB_Plain_XRDS_Writer is used.
|
||||
*
|
||||
* @param OMB_XRDS_Mapper $xrds_mapper An object mapping actions to URLs
|
||||
* @param OMB_XRDS_Writer $xrds_writer Optional; The OMB_XRDS_Writer used to
|
||||
* write the XRDS document
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return mixed Depends on the used OMB_XRDS_Writer; OMB_Plain_XRDS_Writer
|
||||
* returns nothing.
|
||||
**/
|
||||
public function writeXRDS($xrds_mapper, $xrds_writer = null) {
|
||||
if ($xrds_writer == null) {
|
||||
require_once 'plain_xrds_writer.php';
|
||||
$xrds_writer = new OMB_Plain_XRDS_Writer();
|
||||
}
|
||||
return $xrds_writer->writeXRDS($this->user, $xrds_mapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Echo a request token
|
||||
*
|
||||
* Outputs an unauthorized request token for the query found in $_GET or
|
||||
* $_POST.
|
||||
*
|
||||
* @access public
|
||||
**/
|
||||
public function writeRequestToken() {
|
||||
OMB_Helper::removeMagicQuotesFromRequest();
|
||||
echo $this->getOAuthServer()->fetch_request_token(OAuthRequest::from_request());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an user authorization request.
|
||||
*
|
||||
* Parses an authorization request. This includes OAuth and OMB verification.
|
||||
* Throws exceptions on failures. Returns an OMB_Profile object representing
|
||||
* the remote user.
|
||||
*
|
||||
* The OMB_Profile passed to the constructor of OMB_Service_Provider should
|
||||
* not represent the user specified in the authorization request, but the one
|
||||
* currently logged in to the service. This condition being satisfied,
|
||||
* handleUserAuth will check whether the listener specified in the request is
|
||||
* identical to the logged in user.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return OMB_Profile The profile of the soon-to-be subscribed, i. e. remote
|
||||
* user
|
||||
**/
|
||||
public function handleUserAuth() {
|
||||
OMB_Helper::removeMagicQuotesFromRequest();
|
||||
|
||||
/* Verify the request token. */
|
||||
|
||||
$this->token = $this->datastore->lookup_token(null, "request", $_GET['oauth_token']);
|
||||
if (is_null($this->token)) {
|
||||
throw new OAuthException('The given request token has not been issued ' .
|
||||
'by this service.');
|
||||
}
|
||||
|
||||
/* Verify the OMB part. */
|
||||
|
||||
if ($_GET['omb_version'] !== OMB_VERSION) {
|
||||
throw OMB_RemoteServiceException::forRequest(OAUTH_ENDPOINT_AUTHORIZE,
|
||||
'Wrong OMB version ' . $_GET['omb_version']);
|
||||
}
|
||||
|
||||
if ($_GET['omb_listener'] !== $this->user->getIdentifierURI()) {
|
||||
throw OMB_RemoteServiceException::forRequest(OAUTH_ENDPOINT_AUTHORIZE,
|
||||
'Wrong OMB listener ' . $_GET['omb_listener']);
|
||||
}
|
||||
|
||||
foreach (array('omb_listenee', 'omb_listenee_profile',
|
||||
'omb_listenee_nickname', 'omb_listenee_license') as $param) {
|
||||
if (!isset($_GET[$param]) || is_null($_GET[$param])) {
|
||||
throw OMB_RemoteServiceException::forRequest(OAUTH_ENDPOINT_AUTHORIZE,
|
||||
"Required parameter '$param' not found");
|
||||
}
|
||||
}
|
||||
|
||||
/* Store given callback for later use. */
|
||||
if (isset($_GET['oauth_callback']) && $_GET['oauth_callback'] !== '') {
|
||||
$this->callback = $_GET['oauth_callback'];
|
||||
if (!OMB_Helper::validateURL($this->callback)) {
|
||||
throw OMB_RemoteServiceException::forRequest(OAUTH_ENDPOINT_AUTHORIZE,
|
||||
'Invalid callback URL specified');
|
||||
}
|
||||
}
|
||||
$this->remote_user = OMB_Profile::fromParameters($_GET, 'omb_listenee');
|
||||
|
||||
return $this->remote_user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Continue the OAuth dance after user authorization
|
||||
*
|
||||
* Performs the appropriate actions after user answered the authorization
|
||||
* request.
|
||||
*
|
||||
* @param bool $accepted Whether the user granted authorization
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return array A two-component array with the values:
|
||||
* - callback The callback URL or null if none given
|
||||
* - token The authorized request token or null if not
|
||||
* authorized.
|
||||
**/
|
||||
public function continueUserAuth($accepted) {
|
||||
$callback = $this->callback;
|
||||
if (!$accepted) {
|
||||
$this->datastore->revoke_token($this->token->key);
|
||||
$this->token = null;
|
||||
/* TODO: The handling is probably wrong in terms of OAuth 1.0 but the way
|
||||
laconica works. Moreover I don’t know the right way either. */
|
||||
|
||||
} else {
|
||||
$this->datastore->authorize_token($this->token->key);
|
||||
$this->datastore->saveProfile($this->remote_user);
|
||||
$this->datastore->saveSubscription($this->user->getIdentifierURI(),
|
||||
$this->remote_user->getIdentifierURI(), $this->token);
|
||||
|
||||
if (!is_null($this->callback)) {
|
||||
/* Callback wants to get some informations as well. */
|
||||
$params = $this->user->asParameters('omb_listener', false);
|
||||
|
||||
$params['oauth_token'] = $this->token->key;
|
||||
$params['omb_version'] = OMB_VERSION;
|
||||
|
||||
$callback .= (parse_url($this->callback, PHP_URL_QUERY) ? '&' : '?');
|
||||
foreach ($params as $k => $v) {
|
||||
$callback .= OAuthUtil::urlencode_rfc3986($k) . '=' .
|
||||
OAuthUtil::urlencode_rfc3986($v) . '&';
|
||||
}
|
||||
}
|
||||
}
|
||||
return array($callback, $this->token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Echo an access token
|
||||
*
|
||||
* Outputs an access token for the query found in $_POST. OMB 0.1 specifies
|
||||
* that the access token request has to be a POST even if OAuth allows GET as
|
||||
* well.
|
||||
*
|
||||
* @access public
|
||||
**/
|
||||
public function writeAccessToken() {
|
||||
OMB_Helper::removeMagicQuotesFromRequest();
|
||||
echo $this->getOAuthServer()->fetch_access_token(
|
||||
OAuthRequest::from_request('POST'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an updateprofile request
|
||||
*
|
||||
* Handles an updateprofile request posted to this service. Updates the
|
||||
* profile through the OMB_Datastore.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return OMB_Profile The updated profile
|
||||
**/
|
||||
public function handleUpdateProfile() {
|
||||
list($req, $profile) = $this->handleOMBRequest(OMB_ENDPOINT_UPDATEPROFILE);
|
||||
$profile->updateFromParameters($req->get_parameters(), 'omb_listenee');
|
||||
$this->datastore->saveProfile($profile);
|
||||
$this->finishOMBRequest();
|
||||
return $profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a postnotice request
|
||||
*
|
||||
* Handles a postnotice request posted to this service. Saves the notice
|
||||
* through the OMB_Datastore.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return OMB_Notice The received notice
|
||||
**/
|
||||
public function handlePostNotice() {
|
||||
list($req, $profile) = $this->handleOMBRequest(OMB_ENDPOINT_POSTNOTICE);
|
||||
require_once 'notice.php';
|
||||
$notice = OMB_Notice::fromParameters($profile, $req->get_parameters());
|
||||
$this->datastore->saveNotice($notice);
|
||||
$this->finishOMBRequest();
|
||||
return $notice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an OMB request
|
||||
*
|
||||
* Performs common OMB request handling.
|
||||
*
|
||||
* @param string $uri The URI defining the OMB endpoint being served
|
||||
*
|
||||
* @access protected
|
||||
*
|
||||
* @return array(OAuthRequest, OMB_Profile)
|
||||
**/
|
||||
protected function handleOMBRequest($uri) {
|
||||
|
||||
OMB_Helper::removeMagicQuotesFromRequest();
|
||||
$req = OAuthRequest::from_request('POST');
|
||||
$listenee = $req->get_parameter('omb_listenee');
|
||||
|
||||
try {
|
||||
list($consumer, $token) = $this->getOAuthServer()->verify_request($req);
|
||||
} catch (OAuthException $e) {
|
||||
header('HTTP/1.1 403 Forbidden');
|
||||
throw OMB_RemoteServiceException::forRequest($uri,
|
||||
'Revoked accesstoken for ' . $listenee);
|
||||
}
|
||||
|
||||
$version = $req->get_parameter('omb_version');
|
||||
if ($version !== OMB_VERSION) {
|
||||
header('HTTP/1.1 400 Bad Request');
|
||||
throw OMB_RemoteServiceException::forRequest($uri,
|
||||
'Wrong OMB version ' . $version);
|
||||
}
|
||||
|
||||
$profile = $this->datastore->getProfile($listenee);
|
||||
if (is_null($profile)) {
|
||||
header('HTTP/1.1 400 Bad Request');
|
||||
throw OMB_RemoteServiceException::forRequest($uri,
|
||||
'Unknown remote profile ' . $listenee);
|
||||
}
|
||||
|
||||
$subscribers = $this->datastore->getSubscriptions($listenee);
|
||||
if (count($subscribers) === 0) {
|
||||
header('HTTP/1.1 403 Forbidden');
|
||||
throw OMB_RemoteServiceException::forRequest($uri,
|
||||
'No subscriber for ' . $listenee);
|
||||
}
|
||||
|
||||
return array($req, $profile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes an OMB request handling
|
||||
*
|
||||
* Performs common OMB request handling finishing.
|
||||
*
|
||||
* @access protected
|
||||
**/
|
||||
protected function finishOMBRequest() {
|
||||
header('HTTP/1.1 200 OK');
|
||||
header('Content-type: text/plain');
|
||||
/* There should be no clutter but the version. */
|
||||
echo "omb_version=" . OMB_VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an OAuthServer
|
||||
*
|
||||
* Checks whether the OAuthServer is null. If so, initializes it with a
|
||||
* default value. Returns the OAuth server.
|
||||
*
|
||||
* @access protected
|
||||
**/
|
||||
protected function getOAuthServer() {
|
||||
if (is_null($this->oauth_server)) {
|
||||
$this->oauth_server = new OAuthServer($this->datastore);
|
||||
$this->oauth_server->add_signature_method(
|
||||
new OAuthSignatureMethod_HMAC_SHA1());
|
||||
}
|
||||
return $this->oauth_server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish a notice
|
||||
*
|
||||
* Posts an OMB notice. This includes storing the notice and posting it to
|
||||
* subscribed users.
|
||||
*
|
||||
* @param OMB_Notice $notice The new notice
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return array An array mapping subscriber URIs to the exception posting to
|
||||
* them has raised; Empty array if no exception occured
|
||||
**/
|
||||
public function postNotice($notice) {
|
||||
$uri = $this->user->getIdentifierURI();
|
||||
|
||||
/* $notice is passed by reference and may change. */
|
||||
$this->datastore->saveNotice($notice);
|
||||
$subscribers = $this->datastore->getSubscriptions($uri);
|
||||
|
||||
/* No one to post to. */
|
||||
if (is_null($subscribers)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
require_once 'service_consumer.php';
|
||||
|
||||
$err = array();
|
||||
foreach($subscribers as $subscriber) {
|
||||
try {
|
||||
$service = new OMB_Service_Consumer($subscriber['uri'], $uri, $this->datastore);
|
||||
$service->setToken($subscriber['token'], $subscriber['secret']);
|
||||
$service->postNotice($notice);
|
||||
} catch (Exception $e) {
|
||||
$err[$subscriber['uri']] = $e;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return $err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish a profile update
|
||||
*
|
||||
* Posts the current profile as an OMB profile update. This includes updating
|
||||
* the stored profile and posting it to subscribed users.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return array An array mapping subscriber URIs to the exception posting to
|
||||
* them has raised; Empty array if no exception occured
|
||||
**/
|
||||
public function updateProfile() {
|
||||
$uri = $this->user->getIdentifierURI();
|
||||
|
||||
$this->datastore->saveProfile($this->user);
|
||||
$subscribers = $this->datastore->getSubscriptions($uri);
|
||||
|
||||
/* No one to post to. */
|
||||
if (is_null($subscribers)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
require_once 'service_consumer.php';
|
||||
|
||||
$err = array();
|
||||
foreach($subscribers as $subscriber) {
|
||||
try {
|
||||
$service = new OMB_Service_Consumer($subscriber['uri'], $uri, $this->datastore);
|
||||
$service->setToken($subscriber['token'], $subscriber['secret']);
|
||||
$service->updateProfile($this->user);
|
||||
} catch (Exception $e) {
|
||||
$err[$subscriber['uri']] = $e;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return $err;
|
||||
}
|
||||
}
|
31
extlib/libomb/unsupportedserviceexception.php
Executable file
31
extlib/libomb/unsupportedserviceexception.php
Executable file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
/**
|
||||
* Exception stating that a requested service is not available
|
||||
*
|
||||
* This exception is raised when OMB_Service is asked to call a service the remote
|
||||
* server does not provide.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: 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/>.
|
||||
*
|
||||
* @package OMB
|
||||
* @author Adrian Lang <mail@adrianlang.de>
|
||||
* @copyright 2009 Adrian Lang
|
||||
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
|
||||
**/
|
||||
class OMB_UnsupportedServiceException extends Exception {
|
||||
|
||||
}
|
||||
?>
|
33
extlib/libomb/xrds_mapper.php
Executable file
33
extlib/libomb/xrds_mapper.php
Executable file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
/**
|
||||
* Map XRDS actions to URLs
|
||||
*
|
||||
* This interface specifies classes which write the XRDS file announcing
|
||||
* the OMB server. An instance of an implementing class should be passed to
|
||||
* OMB_Service_Provider->writeXRDS.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: 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/>.
|
||||
*
|
||||
* @package OMB
|
||||
* @author Adrian Lang <mail@adrianlang.de>
|
||||
* @copyright 2009 Adrian Lang
|
||||
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
|
||||
**/
|
||||
|
||||
interface OMB_XRDS_Mapper {
|
||||
public function getURL($action);
|
||||
}
|
||||
?>
|
33
extlib/libomb/xrds_writer.php
Executable file
33
extlib/libomb/xrds_writer.php
Executable file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
/**
|
||||
* Write OMB-specific XRDS
|
||||
*
|
||||
* This interface specifies classes which write the XRDS file announcing
|
||||
* the OMB server. An instance of an implementing class should be passed to
|
||||
* OMB_Service_Provider->writeXRDS.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: 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/>.
|
||||
*
|
||||
* @package OMB
|
||||
* @author Adrian Lang <mail@adrianlang.de>
|
||||
* @copyright 2009 Adrian Lang
|
||||
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
|
||||
**/
|
||||
|
||||
interface OMB_XRDS_Writer {
|
||||
public function writeXRDS($user, $mapper);
|
||||
}
|
||||
?>
|
23
index.php
23
index.php
|
@ -73,7 +73,7 @@ function handleError($error)
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
function checkMirror($action_obj)
|
||||
function checkMirror($action_obj, $args)
|
||||
{
|
||||
global $config;
|
||||
|
||||
|
@ -120,6 +120,25 @@ function isLoginAction($action)
|
|||
|
||||
function main()
|
||||
{
|
||||
// fake HTTP redirects using lighttpd's 404 redirects
|
||||
if (strpos($_SERVER['SERVER_SOFTWARE'], 'lighttpd') !== false) {
|
||||
$_lighty_url = $base_url.$_SERVER['REQUEST_URI'];
|
||||
$_lighty_url = @parse_url($_lighty_url);
|
||||
|
||||
if ($_lighty_url['path'] != '/index.php' && $_lighty_url['path'] != '/') {
|
||||
$_lighty_path = preg_replace('/^'.preg_quote(common_config('site','path')).'\//', '', substr($_lighty_url['path'], 1));
|
||||
$_SERVER['QUERY_STRING'] = 'p='.$_lighty_path;
|
||||
if ($_lighty_url['query'])
|
||||
$_SERVER['QUERY_STRING'] .= '&'.$_lighty_url['query'];
|
||||
parse_str($_lighty_url['query'], $_lighty_query);
|
||||
foreach ($_lighty_query as $key => $val) {
|
||||
$_GET[$key] = $_REQUEST[$key] = $val;
|
||||
}
|
||||
$_GET['p'] = $_REQUEST['p'] = $_lighty_path;
|
||||
}
|
||||
}
|
||||
$_SERVER['REDIRECT_URL'] = preg_replace("/\?.+$/", "", $_SERVER['REQUEST_URI']);
|
||||
|
||||
// quick check for fancy URL auto-detection support in installer.
|
||||
if (isset($_SERVER['REDIRECT_URL']) && (preg_replace("/^\/$/","",(dirname($_SERVER['REQUEST_URI']))) . '/check-fancy') === $_SERVER['REDIRECT_URL']) {
|
||||
die("Fancy URL support detection succeeded. We suggest you enable this to get fancy (pretty) URLs.");
|
||||
|
@ -191,7 +210,7 @@ function main()
|
|||
} else {
|
||||
$action_obj = new $action_class();
|
||||
|
||||
checkMirror($action_obj);
|
||||
checkMirror($action_obj, $args);
|
||||
|
||||
try {
|
||||
if ($action_obj->prepare($args)) {
|
||||
|
|
132
install.php
132
install.php
|
@ -163,7 +163,7 @@ E_O_T;
|
|||
function updateStatus($status, $error=false)
|
||||
{
|
||||
?>
|
||||
<li <?php echo ($error) ? 'class="error"': ''; ?>><?print $status;?></li>
|
||||
<li <?php echo ($error) ? 'class="error"': ''; ?>><?php echo $status;?></li>
|
||||
|
||||
<?php
|
||||
}
|
||||
|
@ -180,6 +180,9 @@ function handlePost()
|
|||
$password = $_POST['password'];
|
||||
$sitename = $_POST['sitename'];
|
||||
$fancy = !empty($_POST['fancy']);
|
||||
$server = $_SERVER['HTTP_HOST'];
|
||||
$path = substr(dirname($_SERVER['PHP_SELF']), 1);
|
||||
|
||||
?>
|
||||
<dl class="system_notice">
|
||||
<dt>Page notice</dt>
|
||||
|
@ -219,20 +222,42 @@ function handlePost()
|
|||
}
|
||||
|
||||
switch($dbtype) {
|
||||
case 'mysql': mysql_db_installer($host, $database, $username, $password, $sitename, $fancy);
|
||||
break;
|
||||
case 'pgsql': pgsql_db_installer($host, $database, $username, $password, $sitename, $fancy);
|
||||
break;
|
||||
default:
|
||||
case 'mysql':
|
||||
$db = mysql_db_installer($host, $database, $username, $password);
|
||||
break;
|
||||
case 'pgsql':
|
||||
$db = pgsql_db_installer($host, $database, $username, $password);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
if ($path) $path .= '/';
|
||||
updateStatus("You can visit your <a href='/$path'>new Laconica site</a>.");
|
||||
|
||||
if (!$db) {
|
||||
// database connection failed, do not move on to create config file.
|
||||
return false;
|
||||
}
|
||||
|
||||
updateStatus("Writing config file...");
|
||||
$res = writeConf($sitename, $server, $path, $fancy, $db);
|
||||
|
||||
if (!$res) {
|
||||
updateStatus("Can't write config file.", true);
|
||||
showForm();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
TODO https needs to be considered
|
||||
*/
|
||||
$link = "http://".$server.'/'.$path;
|
||||
|
||||
updateStatus("Laconica has been installed at $link");
|
||||
updateStatus("You can visit your <a href='$link'>new Laconica site</a>.");
|
||||
?>
|
||||
|
||||
<?php
|
||||
}
|
||||
|
||||
function pgsql_db_installer($host, $database, $username, $password, $sitename, $fancy) {
|
||||
function pgsql_db_installer($host, $database, $username, $password) {
|
||||
$connstring = "dbname=$database host=$host user=$username";
|
||||
|
||||
//No password would mean trust authentication used.
|
||||
|
@ -265,7 +290,7 @@ function pgsql_db_installer($host, $database, $username, $password, $sitename, $
|
|||
if ($res === false) {
|
||||
updateStatus("Can't run database script.", true);
|
||||
showForm();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
foreach (array('sms_carrier' => 'SMS carrier',
|
||||
'notice_source' => 'notice source',
|
||||
|
@ -276,29 +301,24 @@ function pgsql_db_installer($host, $database, $username, $password, $sitename, $
|
|||
if ($res === false) {
|
||||
updateStatus(sprintf("Can't run %d script.", $name), true);
|
||||
showForm();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
pg_query($conn, 'COMMIT');
|
||||
|
||||
updateStatus("Writing config file...");
|
||||
if (empty($password)) {
|
||||
$sqlUrl = "pgsql://$username@$host/$database";
|
||||
}
|
||||
else {
|
||||
$sqlUrl = "pgsql://$username:$password@$host/$database";
|
||||
}
|
||||
$res = writeConf($sitename, $sqlUrl, $fancy, 'pgsql');
|
||||
if (!$res) {
|
||||
updateStatus("Can't write config file.", true);
|
||||
showForm();
|
||||
return;
|
||||
}
|
||||
updateStatus("Done!");
|
||||
|
||||
|
||||
$db = array('type' => 'pgsql', 'database' => $sqlUrl);
|
||||
|
||||
return $db;
|
||||
}
|
||||
|
||||
function mysql_db_installer($host, $database, $username, $password, $sitename, $fancy) {
|
||||
function mysql_db_installer($host, $database, $username, $password) {
|
||||
updateStatus("Starting installation...");
|
||||
updateStatus("Checking database...");
|
||||
|
||||
|
@ -306,21 +326,21 @@ function mysql_db_installer($host, $database, $username, $password, $sitename, $
|
|||
if (!$conn) {
|
||||
updateStatus("Can't connect to server '$host' as '$username'.", true);
|
||||
showForm();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
updateStatus("Changing to database...");
|
||||
$res = mysql_select_db($database, $conn);
|
||||
if (!$res) {
|
||||
updateStatus("Can't change to database.", true);
|
||||
showForm();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
updateStatus("Running database script...");
|
||||
$res = runDbScript(INSTALLDIR.'/db/laconica.sql', $conn);
|
||||
if ($res === false) {
|
||||
updateStatus("Can't run database script.", true);
|
||||
showForm();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
foreach (array('sms_carrier' => 'SMS carrier',
|
||||
'notice_source' => 'notice source',
|
||||
|
@ -331,35 +351,44 @@ function mysql_db_installer($host, $database, $username, $password, $sitename, $
|
|||
if ($res === false) {
|
||||
updateStatus(sprintf("Can't run %d script.", $name), true);
|
||||
showForm();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
updateStatus("Writing config file...");
|
||||
$sqlUrl = "mysqli://$username:$password@$host/$database";
|
||||
$res = writeConf($sitename, $sqlUrl, $fancy);
|
||||
if (!$res) {
|
||||
updateStatus("Can't write config file.", true);
|
||||
showForm();
|
||||
return;
|
||||
}
|
||||
updateStatus("Done!");
|
||||
}
|
||||
function writeConf($sitename, $sqlUrl, $fancy, $type='mysql')
|
||||
$db = array('type' => 'mysql', 'database' => $sqlUrl);
|
||||
return $db;
|
||||
}
|
||||
|
||||
function writeConf($sitename, $server, $path, $fancy, $db)
|
||||
{
|
||||
$res = file_put_contents(INSTALLDIR.'/config.php',
|
||||
"<?php\n".
|
||||
"if (!defined('LACONICA')) { exit(1); }\n\n".
|
||||
"\$config['site']['name'] = \"$sitename\";\n\n".
|
||||
($fancy ? "\$config['site']['fancy'] = true;\n\n":'').
|
||||
"\$config['db']['database'] = \"$sqlUrl\";\n\n".
|
||||
($type == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n" .
|
||||
"\$config['db']['type'] = \"$type\";\n\n" : '').
|
||||
"?>");
|
||||
// assemble configuration file in a string
|
||||
$cfg = "<?php\n".
|
||||
"if (!defined('LACONICA')) { exit(1); }\n\n".
|
||||
|
||||
// site name
|
||||
"\$config['site']['name'] = '$sitename';\n\n".
|
||||
|
||||
// site location
|
||||
"\$config['site']['server'] = '$server';\n".
|
||||
"\$config['site']['path'] = '$path'; \n\n".
|
||||
|
||||
// checks if fancy URLs are enabled
|
||||
($fancy ? "\$config['site']['fancy'] = true;\n\n":'').
|
||||
|
||||
// database
|
||||
"\$config['db']['database'] = '{$db['database']}';\n\n".
|
||||
($type == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n":'').
|
||||
"\$config['db']['type'] = '{$db['type']}';\n\n".
|
||||
|
||||
"?>";
|
||||
// write configuration file out to install directory
|
||||
$res = file_put_contents(INSTALLDIR.'/config.php', $cfg);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
function runDbScript($filename, $conn, $type='mysql')
|
||||
function runDbScript($filename, $conn, $type = 'mysql')
|
||||
{
|
||||
$sql = trim(file_get_contents($filename));
|
||||
$stmts = explode(';', $sql);
|
||||
|
@ -368,10 +397,15 @@ function runDbScript($filename, $conn, $type='mysql')
|
|||
if (!mb_strlen($stmt)) {
|
||||
continue;
|
||||
}
|
||||
if ($type == 'mysql') {
|
||||
$res = mysql_query($stmt, $conn);
|
||||
} elseif ($type=='pgsql') {
|
||||
$res = pg_query($conn, $stmt);
|
||||
switch ($type) {
|
||||
case 'mysql':
|
||||
$res = mysql_query($stmt, $conn);
|
||||
break;
|
||||
case 'pgsql':
|
||||
$res = pg_query($conn, $stmt);
|
||||
break;
|
||||
default:
|
||||
updateStatus("runDbScript() error: unknown database type ". $type ." provided.");
|
||||
}
|
||||
if ($res === false) {
|
||||
updateStatus("FAILED SQL: $stmt");
|
||||
|
|
163
js/jcrop/jquery.Jcrop.min.js
vendored
Normal file
163
js/jcrop/jquery.Jcrop.min.js
vendored
Normal file
|
@ -0,0 +1,163 @@
|
|||
/**
|
||||
* Jcrop v.0.9.8 (minimized)
|
||||
* (c) 2008 Kelly Hallman and DeepLiquid.com
|
||||
* More information: http://deepliquid.com/content/Jcrop.html
|
||||
* Released under MIT License - this header must remain with code
|
||||
*/
|
||||
|
||||
|
||||
(function($){$.Jcrop=function(obj,opt)
|
||||
{var obj=obj,opt=opt;if(typeof(obj)!=='object')obj=$(obj)[0];if(typeof(opt)!=='object')opt={};if(!('trackDocument'in opt))
|
||||
{opt.trackDocument=$.browser.msie?false:true;if($.browser.msie&&$.browser.version.split('.')[0]=='8')
|
||||
opt.trackDocument=true;}
|
||||
if(!('keySupport'in opt))
|
||||
opt.keySupport=$.browser.msie?false:true;var defaults={trackDocument:false,baseClass:'jcrop',addClass:null,bgColor:'black',bgOpacity:.6,borderOpacity:.4,handleOpacity:.5,handlePad:5,handleSize:9,handleOffset:5,edgeMargin:14,aspectRatio:0,keySupport:true,cornerHandles:true,sideHandles:true,drawBorders:true,dragEdges:true,boxWidth:0,boxHeight:0,boundary:8,animationDelay:20,swingSpeed:3,allowSelect:true,allowMove:true,allowResize:true,minSelect:[0,0],maxSize:[0,0],minSize:[0,0],onChange:function(){},onSelect:function(){}};var options=defaults;setOptions(opt);var $origimg=$(obj);var $img=$origimg.clone().removeAttr('id').css({position:'absolute'});$img.width($origimg.width());$img.height($origimg.height());$origimg.after($img).hide();presize($img,options.boxWidth,options.boxHeight);var boundx=$img.width(),boundy=$img.height(),$div=$('<div />').width(boundx).height(boundy).addClass(cssClass('holder')).css({position:'relative',backgroundColor:options.bgColor}).insertAfter($origimg).append($img);;if(options.addClass)$div.addClass(options.addClass);var $img2=$('<img />').attr('src',$img.attr('src')).css('position','absolute').width(boundx).height(boundy);var $img_holder=$('<div />').width(pct(100)).height(pct(100)).css({zIndex:310,position:'absolute',overflow:'hidden'}).append($img2);var $hdl_holder=$('<div />').width(pct(100)).height(pct(100)).css('zIndex',320);var $sel=$('<div />').css({position:'absolute',zIndex:300}).insertBefore($img).append($img_holder,$hdl_holder);var bound=options.boundary;var $trk=newTracker().width(boundx+(bound*2)).height(boundy+(bound*2)).css({position:'absolute',top:px(-bound),left:px(-bound),zIndex:290}).mousedown(newSelection);var xlimit,ylimit,xmin,ymin;var xscale,yscale,enabled=true;var docOffset=getPos($img),btndown,lastcurs,dimmed,animating,shift_down;var Coords=function()
|
||||
{var x1=0,y1=0,x2=0,y2=0,ox,oy;function setPressed(pos)
|
||||
{var pos=rebound(pos);x2=x1=pos[0];y2=y1=pos[1];};function setCurrent(pos)
|
||||
{var pos=rebound(pos);ox=pos[0]-x2;oy=pos[1]-y2;x2=pos[0];y2=pos[1];};function getOffset()
|
||||
{return[ox,oy];};function moveOffset(offset)
|
||||
{var ox=offset[0],oy=offset[1];if(0>x1+ox)ox-=ox+x1;if(0>y1+oy)oy-=oy+y1;if(boundy<y2+oy)oy+=boundy-(y2+oy);if(boundx<x2+ox)ox+=boundx-(x2+ox);x1+=ox;x2+=ox;y1+=oy;y2+=oy;};function getCorner(ord)
|
||||
{var c=getFixed();switch(ord)
|
||||
{case'ne':return[c.x2,c.y];case'nw':return[c.x,c.y];case'se':return[c.x2,c.y2];case'sw':return[c.x,c.y2];}};function getFixed()
|
||||
{if(!options.aspectRatio)return getRect();var aspect=options.aspectRatio,min_x=options.minSize[0]/xscale,min_y=options.minSize[1]/yscale,max_x=options.maxSize[0]/xscale,max_y=options.maxSize[1]/yscale,rw=x2-x1,rh=y2-y1,rwa=Math.abs(rw),rha=Math.abs(rh),real_ratio=rwa/rha,xx,yy;if(max_x==0){max_x=boundx*10}
|
||||
if(max_y==0){max_y=boundy*10}
|
||||
if(real_ratio<aspect)
|
||||
{yy=y2;w=rha*aspect;xx=rw<0?x1-w:w+x1;if(xx<0)
|
||||
{xx=0;h=Math.abs((xx-x1)/aspect);yy=rh<0?y1-h:h+y1;}
|
||||
else if(xx>boundx)
|
||||
{xx=boundx;h=Math.abs((xx-x1)/aspect);yy=rh<0?y1-h:h+y1;}}
|
||||
else
|
||||
{xx=x2;h=rwa/aspect;yy=rh<0?y1-h:y1+h;if(yy<0)
|
||||
{yy=0;w=Math.abs((yy-y1)*aspect);xx=rw<0?x1-w:w+x1;}
|
||||
else if(yy>boundy)
|
||||
{yy=boundy;w=Math.abs(yy-y1)*aspect;xx=rw<0?x1-w:w+x1;}}
|
||||
if(xx>x1){if(xx-x1<min_x){xx=x1+min_x;}else if(xx-x1>max_x){xx=x1+max_x;}
|
||||
if(yy>y1){yy=y1+(xx-x1)/aspect;}else{yy=y1-(xx-x1)/aspect;}}else if(xx<x1){if(x1-xx<min_x){xx=x1-min_x}else if(x1-xx>max_x){xx=x1-max_x;}
|
||||
if(yy>y1){yy=y1+(x1-xx)/aspect;}else{yy=y1-(x1-xx)/aspect;}}
|
||||
if(xx<0){x1-=xx;xx=0;}else if(xx>boundx){x1-=xx-boundx;xx=boundx;}
|
||||
if(yy<0){y1-=yy;yy=0;}else if(yy>boundy){y1-=yy-boundy;yy=boundy;}
|
||||
return last=makeObj(flipCoords(x1,y1,xx,yy));};function rebound(p)
|
||||
{if(p[0]<0)p[0]=0;if(p[1]<0)p[1]=0;if(p[0]>boundx)p[0]=boundx;if(p[1]>boundy)p[1]=boundy;return[p[0],p[1]];};function flipCoords(x1,y1,x2,y2)
|
||||
{var xa=x1,xb=x2,ya=y1,yb=y2;if(x2<x1)
|
||||
{xa=x2;xb=x1;}
|
||||
if(y2<y1)
|
||||
{ya=y2;yb=y1;}
|
||||
return[Math.round(xa),Math.round(ya),Math.round(xb),Math.round(yb)];};function getRect()
|
||||
{var xsize=x2-x1;var ysize=y2-y1;if(xlimit&&(Math.abs(xsize)>xlimit))
|
||||
x2=(xsize>0)?(x1+xlimit):(x1-xlimit);if(ylimit&&(Math.abs(ysize)>ylimit))
|
||||
y2=(ysize>0)?(y1+ylimit):(y1-ylimit);if(ymin&&(Math.abs(ysize)<ymin))
|
||||
y2=(ysize>0)?(y1+ymin):(y1-ymin);if(xmin&&(Math.abs(xsize)<xmin))
|
||||
x2=(xsize>0)?(x1+xmin):(x1-xmin);if(x1<0){x2-=x1;x1-=x1;}
|
||||
if(y1<0){y2-=y1;y1-=y1;}
|
||||
if(x2<0){x1-=x2;x2-=x2;}
|
||||
if(y2<0){y1-=y2;y2-=y2;}
|
||||
if(x2>boundx){var delta=x2-boundx;x1-=delta;x2-=delta;}
|
||||
if(y2>boundy){var delta=y2-boundy;y1-=delta;y2-=delta;}
|
||||
if(x1>boundx){var delta=x1-boundy;y2-=delta;y1-=delta;}
|
||||
if(y1>boundy){var delta=y1-boundy;y2-=delta;y1-=delta;}
|
||||
return makeObj(flipCoords(x1,y1,x2,y2));};function makeObj(a)
|
||||
{return{x:a[0],y:a[1],x2:a[2],y2:a[3],w:a[2]-a[0],h:a[3]-a[1]};};return{flipCoords:flipCoords,setPressed:setPressed,setCurrent:setCurrent,getOffset:getOffset,moveOffset:moveOffset,getCorner:getCorner,getFixed:getFixed};}();var Selection=function()
|
||||
{var start,end,dragmode,awake,hdep=370;var borders={};var handle={};var seehandles=false;var hhs=options.handleOffset;if(options.drawBorders){borders={top:insertBorder('hline').css('top',$.browser.msie?px(-1):px(0)),bottom:insertBorder('hline'),left:insertBorder('vline'),right:insertBorder('vline')};}
|
||||
if(options.dragEdges){handle.t=insertDragbar('n');handle.b=insertDragbar('s');handle.r=insertDragbar('e');handle.l=insertDragbar('w');}
|
||||
options.sideHandles&&createHandles(['n','s','e','w']);options.cornerHandles&&createHandles(['sw','nw','ne','se']);function insertBorder(type)
|
||||
{var jq=$('<div />').css({position:'absolute',opacity:options.borderOpacity}).addClass(cssClass(type));$img_holder.append(jq);return jq;};function dragDiv(ord,zi)
|
||||
{var jq=$('<div />').mousedown(createDragger(ord)).css({cursor:ord+'-resize',position:'absolute',zIndex:zi});$hdl_holder.append(jq);return jq;};function insertHandle(ord)
|
||||
{return dragDiv(ord,hdep++).css({top:px(-hhs+1),left:px(-hhs+1),opacity:options.handleOpacity}).addClass(cssClass('handle'));};function insertDragbar(ord)
|
||||
{var s=options.handleSize,o=hhs,h=s,w=s,t=o,l=o;switch(ord)
|
||||
{case'n':case's':w=pct(100);break;case'e':case'w':h=pct(100);break;}
|
||||
return dragDiv(ord,hdep++).width(w).height(h).css({top:px(-t+1),left:px(-l+1)});};function createHandles(li)
|
||||
{for(i in li)handle[li[i]]=insertHandle(li[i]);};function moveHandles(c)
|
||||
{var midvert=Math.round((c.h/2)-hhs),midhoriz=Math.round((c.w/2)-hhs),north=west=-hhs+1,east=c.w-hhs,south=c.h-hhs,x,y;'e'in handle&&handle.e.css({top:px(midvert),left:px(east)})&&handle.w.css({top:px(midvert)})&&handle.s.css({top:px(south),left:px(midhoriz)})&&handle.n.css({left:px(midhoriz)});'ne'in handle&&handle.ne.css({left:px(east)})&&handle.se.css({top:px(south),left:px(east)})&&handle.sw.css({top:px(south)});'b'in handle&&handle.b.css({top:px(south)})&&handle.r.css({left:px(east)});};function moveto(x,y)
|
||||
{$img2.css({top:px(-y),left:px(-x)});$sel.css({top:px(y),left:px(x)});};function resize(w,h)
|
||||
{$sel.width(w).height(h);};function refresh()
|
||||
{var c=Coords.getFixed();Coords.setPressed([c.x,c.y]);Coords.setCurrent([c.x2,c.y2]);updateVisible();};function updateVisible()
|
||||
{if(awake)return update();};function update()
|
||||
{var c=Coords.getFixed();resize(c.w,c.h);moveto(c.x,c.y);options.drawBorders&&borders['right'].css({left:px(c.w-1)})&&borders['bottom'].css({top:px(c.h-1)});seehandles&&moveHandles(c);awake||show();options.onChange(unscale(c));};function show()
|
||||
{$sel.show();$img.css('opacity',options.bgOpacity);awake=true;};function release()
|
||||
{disableHandles();$sel.hide();$img.css('opacity',1);awake=false;};function showHandles()
|
||||
{if(seehandles)
|
||||
{moveHandles(Coords.getFixed());$hdl_holder.show();}};function enableHandles()
|
||||
{seehandles=true;if(options.allowResize)
|
||||
{moveHandles(Coords.getFixed());$hdl_holder.show();return true;}};function disableHandles()
|
||||
{seehandles=false;$hdl_holder.hide();};function animMode(v)
|
||||
{(animating=v)?disableHandles():enableHandles();};function done()
|
||||
{animMode(false);refresh();};var $track=newTracker().mousedown(createDragger('move')).css({cursor:'move',position:'absolute',zIndex:360})
|
||||
$img_holder.append($track);disableHandles();return{updateVisible:updateVisible,update:update,release:release,refresh:refresh,setCursor:function(cursor){$track.css('cursor',cursor);},enableHandles:enableHandles,enableOnly:function(){seehandles=true;},showHandles:showHandles,disableHandles:disableHandles,animMode:animMode,done:done};}();var Tracker=function()
|
||||
{var onMove=function(){},onDone=function(){},trackDoc=options.trackDocument;if(!trackDoc)
|
||||
{$trk.mousemove(trackMove).mouseup(trackUp).mouseout(trackUp);}
|
||||
function toFront()
|
||||
{$trk.css({zIndex:450});if(trackDoc)
|
||||
{$(document).mousemove(trackMove).mouseup(trackUp);}}
|
||||
function toBack()
|
||||
{$trk.css({zIndex:290});if(trackDoc)
|
||||
{$(document).unbind('mousemove',trackMove).unbind('mouseup',trackUp);}}
|
||||
function trackMove(e)
|
||||
{onMove(mouseAbs(e));};function trackUp(e)
|
||||
{e.preventDefault();e.stopPropagation();if(btndown)
|
||||
{btndown=false;onDone(mouseAbs(e));options.onSelect(unscale(Coords.getFixed()));toBack();onMove=function(){};onDone=function(){};}
|
||||
return false;};function activateHandlers(move,done)
|
||||
{btndown=true;onMove=move;onDone=done;toFront();return false;};function setCursor(t){$trk.css('cursor',t);};$img.before($trk);return{activateHandlers:activateHandlers,setCursor:setCursor};}();var KeyManager=function()
|
||||
{var $keymgr=$('<input type="radio" />').css({position:'absolute',left:'-30px'}).keypress(parseKey).blur(onBlur),$keywrap=$('<div />').css({position:'absolute',overflow:'hidden'}).append($keymgr);function watchKeys()
|
||||
{if(options.keySupport)
|
||||
{$keymgr.show();$keymgr.focus();}};function onBlur(e)
|
||||
{$keymgr.hide();};function doNudge(e,x,y)
|
||||
{if(options.allowMove){Coords.moveOffset([x,y]);Selection.updateVisible();};e.preventDefault();e.stopPropagation();};function parseKey(e)
|
||||
{if(e.ctrlKey)return true;shift_down=e.shiftKey?true:false;var nudge=shift_down?10:1;switch(e.keyCode)
|
||||
{case 37:doNudge(e,-nudge,0);break;case 39:doNudge(e,nudge,0);break;case 38:doNudge(e,0,-nudge);break;case 40:doNudge(e,0,nudge);break;case 27:Selection.release();break;case 9:return true;}
|
||||
return nothing(e);};if(options.keySupport)$keywrap.insertBefore($img);return{watchKeys:watchKeys};}();function px(n){return''+parseInt(n)+'px';};function pct(n){return''+parseInt(n)+'%';};function cssClass(cl){return options.baseClass+'-'+cl;};function getPos(obj)
|
||||
{var pos=$(obj).offset();return[pos.left,pos.top];};function mouseAbs(e)
|
||||
{return[(e.pageX-docOffset[0]),(e.pageY-docOffset[1])];};function myCursor(type)
|
||||
{if(type!=lastcurs)
|
||||
{Tracker.setCursor(type);lastcurs=type;}};function startDragMode(mode,pos)
|
||||
{docOffset=getPos($img);Tracker.setCursor(mode=='move'?mode:mode+'-resize');if(mode=='move')
|
||||
return Tracker.activateHandlers(createMover(pos),doneSelect);var fc=Coords.getFixed();var opp=oppLockCorner(mode);var opc=Coords.getCorner(oppLockCorner(opp));Coords.setPressed(Coords.getCorner(opp));Coords.setCurrent(opc);Tracker.activateHandlers(dragmodeHandler(mode,fc),doneSelect);};function dragmodeHandler(mode,f)
|
||||
{return function(pos){if(!options.aspectRatio)switch(mode)
|
||||
{case'e':pos[1]=f.y2;break;case'w':pos[1]=f.y2;break;case'n':pos[0]=f.x2;break;case's':pos[0]=f.x2;break;}
|
||||
else switch(mode)
|
||||
{case'e':pos[1]=f.y+1;break;case'w':pos[1]=f.y+1;break;case'n':pos[0]=f.x+1;break;case's':pos[0]=f.x+1;break;}
|
||||
Coords.setCurrent(pos);Selection.update();};};function createMover(pos)
|
||||
{var lloc=pos;KeyManager.watchKeys();return function(pos)
|
||||
{Coords.moveOffset([pos[0]-lloc[0],pos[1]-lloc[1]]);lloc=pos;Selection.update();};};function oppLockCorner(ord)
|
||||
{switch(ord)
|
||||
{case'n':return'sw';case's':return'nw';case'e':return'nw';case'w':return'ne';case'ne':return'sw';case'nw':return'se';case'se':return'nw';case'sw':return'ne';};};function createDragger(ord)
|
||||
{return function(e){if(options.disabled)return false;if((ord=='move')&&!options.allowMove)return false;btndown=true;startDragMode(ord,mouseAbs(e));e.stopPropagation();e.preventDefault();return false;};};function presize($obj,w,h)
|
||||
{var nw=$obj.width(),nh=$obj.height();if((nw>w)&&w>0)
|
||||
{nw=w;nh=(w/$obj.width())*$obj.height();}
|
||||
if((nh>h)&&h>0)
|
||||
{nh=h;nw=(h/$obj.height())*$obj.width();}
|
||||
xscale=$obj.width()/nw;yscale=$obj.height()/nh;$obj.width(nw).height(nh);};function unscale(c)
|
||||
{return{x:parseInt(c.x*xscale),y:parseInt(c.y*yscale),x2:parseInt(c.x2*xscale),y2:parseInt(c.y2*yscale),w:parseInt(c.w*xscale),h:parseInt(c.h*yscale)};};function doneSelect(pos)
|
||||
{var c=Coords.getFixed();if(c.w>options.minSelect[0]&&c.h>options.minSelect[1])
|
||||
{Selection.enableHandles();Selection.done();}
|
||||
else
|
||||
{Selection.release();}
|
||||
Tracker.setCursor(options.allowSelect?'crosshair':'default');};function newSelection(e)
|
||||
{if(options.disabled)return false;if(!options.allowSelect)return false;btndown=true;docOffset=getPos($img);Selection.disableHandles();myCursor('crosshair');var pos=mouseAbs(e);Coords.setPressed(pos);Tracker.activateHandlers(selectDrag,doneSelect);KeyManager.watchKeys();Selection.update();e.stopPropagation();e.preventDefault();return false;};function selectDrag(pos)
|
||||
{Coords.setCurrent(pos);Selection.update();};function newTracker()
|
||||
{var trk=$('<div></div>').addClass(cssClass('tracker'));$.browser.msie&&trk.css({opacity:0,backgroundColor:'white'});return trk;};function animateTo(a)
|
||||
{var x1=a[0]/xscale,y1=a[1]/yscale,x2=a[2]/xscale,y2=a[3]/yscale;if(animating)return;var animto=Coords.flipCoords(x1,y1,x2,y2);var c=Coords.getFixed();var animat=initcr=[c.x,c.y,c.x2,c.y2];var interv=options.animationDelay;var x=animat[0];var y=animat[1];var x2=animat[2];var y2=animat[3];var ix1=animto[0]-initcr[0];var iy1=animto[1]-initcr[1];var ix2=animto[2]-initcr[2];var iy2=animto[3]-initcr[3];var pcent=0;var velocity=options.swingSpeed;Selection.animMode(true);var animator=function()
|
||||
{return function()
|
||||
{pcent+=(100-pcent)/velocity;animat[0]=x+((pcent/100)*ix1);animat[1]=y+((pcent/100)*iy1);animat[2]=x2+((pcent/100)*ix2);animat[3]=y2+((pcent/100)*iy2);if(pcent<100)animateStart();else Selection.done();if(pcent>=99.8)pcent=100;setSelectRaw(animat);};}();function animateStart()
|
||||
{window.setTimeout(animator,interv);};animateStart();};function setSelect(rect)
|
||||
{setSelectRaw([rect[0]/xscale,rect[1]/yscale,rect[2]/xscale,rect[3]/yscale]);};function setSelectRaw(l)
|
||||
{Coords.setPressed([l[0],l[1]]);Coords.setCurrent([l[2],l[3]]);Selection.update();};function setOptions(opt)
|
||||
{if(typeof(opt)!='object')opt={};options=$.extend(options,opt);if(typeof(options.onChange)!=='function')
|
||||
options.onChange=function(){};if(typeof(options.onSelect)!=='function')
|
||||
options.onSelect=function(){};};function tellSelect()
|
||||
{return unscale(Coords.getFixed());};function tellScaled()
|
||||
{return Coords.getFixed();};function setOptionsNew(opt)
|
||||
{setOptions(opt);interfaceUpdate();};function disableCrop()
|
||||
{options.disabled=true;Selection.disableHandles();Selection.setCursor('default');Tracker.setCursor('default');};function enableCrop()
|
||||
{options.disabled=false;interfaceUpdate();};function cancelCrop()
|
||||
{Selection.done();Tracker.activateHandlers(null,null);};function destroy()
|
||||
{$div.remove();$origimg.show();};function interfaceUpdate(alt)
|
||||
{options.allowResize?alt?Selection.enableOnly():Selection.enableHandles():Selection.disableHandles();Tracker.setCursor(options.allowSelect?'crosshair':'default');Selection.setCursor(options.allowMove?'move':'default');$div.css('backgroundColor',options.bgColor);if('setSelect'in options){setSelect(opt.setSelect);Selection.done();delete(options.setSelect);}
|
||||
if('trueSize'in options){xscale=options.trueSize[0]/boundx;yscale=options.trueSize[1]/boundy;}
|
||||
xlimit=options.maxSize[0]||0;ylimit=options.maxSize[1]||0;xmin=options.minSize[0]||0;ymin=options.minSize[1]||0;if('outerImage'in options)
|
||||
{$img.attr('src',options.outerImage);delete(options.outerImage);}
|
||||
Selection.refresh();};$hdl_holder.hide();interfaceUpdate(true);var api={animateTo:animateTo,setSelect:setSelect,setOptions:setOptionsNew,tellSelect:tellSelect,tellScaled:tellScaled,disable:disableCrop,enable:enableCrop,cancel:cancelCrop,focus:KeyManager.watchKeys,getBounds:function(){return[boundx*xscale,boundy*yscale];},getWidgetSize:function(){return[boundx,boundy];},release:Selection.release,destroy:destroy};$origimg.data('Jcrop',api);return api;};$.fn.Jcrop=function(options)
|
||||
{function attachWhenDone(from)
|
||||
{var loadsrc=options.useImg||from.src;var img=new Image();img.onload=function(){$.Jcrop(from,options);};img.src=loadsrc;};if(typeof(options)!=='object')options={};this.each(function()
|
||||
{if($(this).data('Jcrop'))
|
||||
{if(options=='api')return $(this).data('Jcrop');else $(this).data('Jcrop').setOptions(options);}
|
||||
else attachWhenDone(this);});return this;};})(jQuery);
|
File diff suppressed because one or more lines are too long
|
@ -27,13 +27,14 @@ $(document).ready(function() {
|
|||
}
|
||||
}
|
||||
|
||||
/* rgb2hex written by R0bb13 <robertorebollo@gmail.com> */
|
||||
function rgb2hex(rgb) {
|
||||
rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
|
||||
function hex(x) {
|
||||
hexDigits = new Array("0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F");
|
||||
return isNaN(x) ? "00" : hexDigits[(x - x % 16) / 16] + hexDigits[x % 16];
|
||||
}
|
||||
return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
|
||||
return '#' + dec2hex(rgb[1]) + dec2hex(rgb[2]) + dec2hex(rgb[3]);
|
||||
}
|
||||
function dec2hex(x) {
|
||||
hexDigits = new Array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
|
||||
return isNaN(x) ? '00' : hexDigits[(x - x % 16) / 16] + hexDigits[x % 16];
|
||||
}
|
||||
|
||||
function UpdateColors(S) {
|
||||
|
|
92
js/util.js
92
js/util.js
|
@ -17,37 +17,72 @@
|
|||
*/
|
||||
|
||||
$(document).ready(function(){
|
||||
var counterBlackout = false;
|
||||
|
||||
// count character on keyup
|
||||
function counter(event){
|
||||
var maxLength = 140;
|
||||
if (maxLength <= 0) {
|
||||
return;
|
||||
}
|
||||
var currentLength = $("#notice_data-text").val().length;
|
||||
var remaining = maxLength - currentLength;
|
||||
var counter = $("#notice_text-count");
|
||||
counter.text(remaining);
|
||||
|
||||
if (remaining.toString() != counter.text()) {
|
||||
if (!counterBlackout || remaining == 0) {
|
||||
if (counter.text() != String(remaining)) {
|
||||
counter.text(remaining);
|
||||
}
|
||||
|
||||
if (remaining <= 0) {
|
||||
$("#form_notice").addClass("warning");
|
||||
} else {
|
||||
$("#form_notice").removeClass("warning");
|
||||
}
|
||||
if (remaining < 0) {
|
||||
$("#form_notice").addClass("warning");
|
||||
} else {
|
||||
$("#form_notice").removeClass("warning");
|
||||
}
|
||||
// Skip updates for the next 500ms.
|
||||
// On slower hardware, updating on every keypress is unpleasant.
|
||||
if (!counterBlackout) {
|
||||
counterBlackout = true;
|
||||
window.setTimeout(clearCounterBlackout, 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clearCounterBlackout() {
|
||||
// Allow keyup events to poke the counter again
|
||||
counterBlackout = false;
|
||||
// Check if the string changed since we last looked
|
||||
counter(null);
|
||||
}
|
||||
|
||||
function submitonreturn(event) {
|
||||
if (event.keyCode == 13) {
|
||||
if (event.keyCode == 13 || event.keyCode == 10) {
|
||||
// iPhone sends \n not \r for 'return'
|
||||
$("#form_notice").submit();
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
$("#notice_data-text").blur();
|
||||
$("body").focus();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($("#notice_data-text").length) {
|
||||
$("#notice_data-text").bind("keyup", counter);
|
||||
$("#notice_data-text").bind("keydown", submitonreturn);
|
||||
// define maxLength if it wasn't defined already
|
||||
|
||||
// run once in case there's something in there
|
||||
counter();
|
||||
if (typeof(maxLength) == "undefined") {
|
||||
maxLength = 140;
|
||||
}
|
||||
|
||||
if ($("#notice_data-text").length) {
|
||||
if (maxLength > 0) {
|
||||
$("#notice_data-text").bind("keyup", counter);
|
||||
// run once in case there's something in there
|
||||
counter();
|
||||
}
|
||||
|
||||
$("#notice_data-text").bind("keydown", submitonreturn);
|
||||
|
||||
if($('body')[0].id != 'conversation') {
|
||||
$("#notice_data-text").focus();
|
||||
|
@ -57,6 +92,10 @@ $(document).ready(function(){
|
|||
// XXX: refactor this code
|
||||
|
||||
var favoptions = { dataType: 'xml',
|
||||
beforeSubmit: function(data, target, options) {
|
||||
$(target).addClass('processing');
|
||||
return true;
|
||||
},
|
||||
success: function(xml) { var new_form = document._importNode($('form', xml).get(0), true);
|
||||
var dis = new_form.id;
|
||||
var fav = dis.replace('disfavor', 'favor');
|
||||
|
@ -66,6 +105,10 @@ $(document).ready(function(){
|
|||
};
|
||||
|
||||
var disoptions = { dataType: 'xml',
|
||||
beforeSubmit: function(data, target, options) {
|
||||
$(target).addClass('processing');
|
||||
return true;
|
||||
},
|
||||
success: function(xml) { var new_form = document._importNode($('form', xml).get(0), true);
|
||||
var fav = new_form.id;
|
||||
var dis = fav.replace('favor', 'disfavor');
|
||||
|
@ -185,7 +228,9 @@ $(document).ready(function(){
|
|||
}
|
||||
else {
|
||||
$("#notice_data-text").val("");
|
||||
counter();
|
||||
if (maxLength > 0) {
|
||||
counter();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -225,7 +270,9 @@ $(document).ready(function(){
|
|||
$("#notice_data-attach").val("");
|
||||
$("#notice_in-reply-to").val("");
|
||||
$('#notice_data-attach_selected').remove();
|
||||
counter();
|
||||
if (maxLength > 0) {
|
||||
counter();
|
||||
}
|
||||
}
|
||||
$("#form_notice").removeClass("processing");
|
||||
$("#notice_action-submit").removeAttr("disabled");
|
||||
|
@ -244,7 +291,7 @@ function NoticeReply() {
|
|||
$('#content .notice').each(function() {
|
||||
var notice = $(this)[0];
|
||||
$($('.notice_reply', notice)[0]).click(function() {
|
||||
var nickname = ($('.author .nickname', notice).length > 0) ? $($('.author .nickname', notice)[0]) : $('.author .nickname');
|
||||
var nickname = ($('.author .nickname', notice).length > 0) ? $($('.author .nickname', notice)[0]) : $('.author .nickname.uid');
|
||||
NoticeReplySet(nickname.text(), $($('.notice_id', notice)[0]).text());
|
||||
return false;
|
||||
});
|
||||
|
@ -255,11 +302,16 @@ function NoticeReply() {
|
|||
function NoticeReplySet(nick,id) {
|
||||
rgx_username = /^[0-9a-zA-Z\-_.]*$/;
|
||||
if (nick.match(rgx_username)) {
|
||||
replyto = "@" + nick + " ";
|
||||
if ($("#notice_data-text").length) {
|
||||
$("#notice_data-text").val(replyto);
|
||||
var text = $("#notice_data-text");
|
||||
if (text.length) {
|
||||
replyto = "@" + nick + " ";
|
||||
text.val(replyto + text.val().replace(RegExp(replyto, 'i'), ''));
|
||||
$("#form_notice input#notice_in-reply-to").val(id);
|
||||
$("#notice_data-text").focus();
|
||||
if (text.get(0).setSelectionRange) {
|
||||
var len = text.val().length;
|
||||
text.get(0).setSelectionRange(len,len);
|
||||
text.get(0).focus();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -196,21 +196,12 @@ class Action extends HTMLOutputter // lawsuit
|
|||
if (Event::handle('StartShowStyles', array($this))) {
|
||||
|
||||
if (Event::handle('StartShowLaconicaStyles', array($this))) {
|
||||
$this->element('link', array('rel' => 'stylesheet',
|
||||
'type' => 'text/css',
|
||||
'href' => theme_path('css/display.css', null) . '?version=' . LACONICA_VERSION,
|
||||
'media' => 'screen, projection, tv'));
|
||||
$this->cssLink('css/display.css',null,'screen, projection, tv');
|
||||
if (common_config('site', 'mobile')) {
|
||||
$this->element('link', array('rel' => 'stylesheet',
|
||||
'type' => 'text/css',
|
||||
'href' => theme_path('css/mobile.css', 'base') . '?version=' . LACONICA_VERSION,
|
||||
// TODO: "handheld" CSS for other mobile devices
|
||||
'media' => 'only screen and (max-device-width: 480px)')); // Mobile WebKit
|
||||
// TODO: "handheld" CSS for other mobile devices
|
||||
$this->cssLink('css/mobile.css','base','only screen and (max-device-width: 480px)'); // Mobile WebKit
|
||||
}
|
||||
$this->element('link', array('rel' => 'stylesheet',
|
||||
'type' => 'text/css',
|
||||
'href' => theme_path('css/print.css', 'base') . '?version=' . LACONICA_VERSION,
|
||||
'media' => 'print'));
|
||||
$this->cssLink('css/print.css','base','print');
|
||||
Event::handle('EndShowLaconicaStyles', array($this));
|
||||
}
|
||||
|
||||
|
@ -256,26 +247,14 @@ class Action extends HTMLOutputter // lawsuit
|
|||
{
|
||||
if (Event::handle('StartShowScripts', array($this))) {
|
||||
if (Event::handle('StartShowJQueryScripts', array($this))) {
|
||||
$this->element('script', array('type' => 'text/javascript',
|
||||
'src' => common_path('js/jquery.min.js')),
|
||||
' ');
|
||||
$this->element('script', array('type' => 'text/javascript',
|
||||
'src' => common_path('js/jquery.form.js')),
|
||||
' ');
|
||||
|
||||
$this->element('script', array('type' => 'text/javascript',
|
||||
'src' => common_path('js/jquery.joverlay.min.js')),
|
||||
' ');
|
||||
|
||||
$this->script('js/jquery.min.js');
|
||||
$this->script('js/jquery.form.js');
|
||||
$this->script('js/jquery.joverlay.min.js');
|
||||
Event::handle('EndShowJQueryScripts', array($this));
|
||||
}
|
||||
if (Event::handle('StartShowLaconicaScripts', array($this))) {
|
||||
$this->element('script', array('type' => 'text/javascript',
|
||||
'src' => common_path('js/xbImportNode.js')),
|
||||
' ');
|
||||
$this->element('script', array('type' => 'text/javascript',
|
||||
'src' => common_path('js/util.js?version='.LACONICA_VERSION)),
|
||||
' ');
|
||||
$this->script('js/xbImportNode.js');
|
||||
$this->script('js/util.js');
|
||||
// Frame-busting code to avoid clickjacking attacks.
|
||||
$this->element('script', array('type' => 'text/javascript'),
|
||||
'if (window.top !== window.self) { window.top.location.href = window.self.location.href; }');
|
||||
|
@ -426,6 +405,14 @@ class Action extends HTMLOutputter // lawsuit
|
|||
function showPrimaryNav()
|
||||
{
|
||||
$user = common_current_user();
|
||||
$connect = '';
|
||||
if (common_config('xmpp', 'enabled')) {
|
||||
$connect = 'imsettings';
|
||||
} else if (common_config('sms', 'enabled')) {
|
||||
$connect = 'smssettings';
|
||||
} else if (common_config('twitter', 'enabled')) {
|
||||
$connect = 'twittersettings';
|
||||
}
|
||||
|
||||
$this->elementStart('dl', array('id' => 'site_nav_global_primary'));
|
||||
$this->element('dt', null, _('Primary site navigation'));
|
||||
|
@ -437,12 +424,9 @@ class Action extends HTMLOutputter // lawsuit
|
|||
_('Home'), _('Personal profile and friends timeline'), false, 'nav_home');
|
||||
$this->menuItem(common_local_url('profilesettings'),
|
||||
_('Account'), _('Change your email, avatar, password, profile'), false, 'nav_account');
|
||||
if (common_config('xmpp', 'enabled')) {
|
||||
$this->menuItem(common_local_url('imsettings'),
|
||||
_('Connect'), _('Connect to IM, SMS, Twitter'), false, 'nav_connect');
|
||||
} else {
|
||||
$this->menuItem(common_local_url('smssettings'),
|
||||
_('Connect'), _('Connect to SMS, Twitter'), false, 'nav_connect');
|
||||
if ($connect) {
|
||||
$this->menuItem(common_local_url($connect),
|
||||
_('Connect'), _('Connect to services'), false, 'nav_connect');
|
||||
}
|
||||
if (common_config('invite', 'enabled')) {
|
||||
$this->menuItem(common_local_url('invite'),
|
||||
|
@ -455,17 +439,24 @@ class Action extends HTMLOutputter // lawsuit
|
|||
_('Logout'), _('Logout from the site'), false, 'nav_logout');
|
||||
}
|
||||
else {
|
||||
if (!common_config('site', 'closed')) {
|
||||
$this->menuItem(common_local_url('register'),
|
||||
_('Register'), _('Create an account'), false, 'nav_register');
|
||||
if (!common_config('site', 'openidonly')) {
|
||||
if (!common_config('site', 'closed')) {
|
||||
$this->menuItem(common_local_url('register'),
|
||||
_('Register'), _('Create an account'), false, 'nav_register');
|
||||
}
|
||||
$this->menuItem(common_local_url('login'),
|
||||
_('Login'), _('Login to the site'), false, 'nav_login');
|
||||
} else {
|
||||
$this->menuItem(common_local_url('openidlogin'),
|
||||
_('OpenID'), _('Login with OpenID'), false, 'nav_openid');
|
||||
}
|
||||
$this->menuItem(common_local_url('login'),
|
||||
_('Login'), _('Login to the site'), false, 'nav_login');
|
||||
}
|
||||
$this->menuItem(common_local_url('doc', array('title' => 'help')),
|
||||
_('Help'), _('Help me!'), false, 'nav_help');
|
||||
$this->menuItem(common_local_url('peoplesearch'),
|
||||
_('Search'), _('Search for people or text'), false, 'nav_search');
|
||||
if ($user || !common_config('site', 'private')) {
|
||||
$this->menuItem(common_local_url('peoplesearch'),
|
||||
_('Search'), _('Search for people or text'), false, 'nav_search');
|
||||
}
|
||||
Event::handle('EndPrimaryNav', array($this));
|
||||
}
|
||||
$this->elementEnd('ul');
|
||||
|
|
|
@ -25,12 +25,14 @@ class ArrayWrapper
|
|||
{
|
||||
var $_items = null;
|
||||
var $_count = 0;
|
||||
var $N = 0;
|
||||
var $_i = -1;
|
||||
|
||||
function __construct($items)
|
||||
{
|
||||
$this->_items = $items;
|
||||
$this->_count = count($this->_items);
|
||||
$this->N = $this->_count;
|
||||
}
|
||||
|
||||
function fetch()
|
||||
|
@ -76,4 +78,4 @@ class ArrayWrapper
|
|||
$item =& $this->_items[$this->_i];
|
||||
return call_user_func_array(array($item, $name), $args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -21,6 +21,8 @@ if (!defined('LACONICA')) { exit(1); }
|
|||
|
||||
define('LACONICA_VERSION', '0.9.0dev');
|
||||
|
||||
// XXX: move these to class variables
|
||||
|
||||
define('AVATAR_PROFILE_SIZE', 96);
|
||||
define('AVATAR_STREAM_SIZE', 48);
|
||||
define('AVATAR_MINI_SIZE', 24);
|
||||
|
@ -82,7 +84,7 @@ if (isset($server)) {
|
|||
if (isset($path)) {
|
||||
$_path = $path;
|
||||
} else {
|
||||
$_path = array_key_exists('SCRIPT_NAME', $_SERVER) ?
|
||||
$_path = (array_key_exists('SERVER_NAME', $_SERVER) && array_key_exists('SCRIPT_NAME', $_SERVER)) ?
|
||||
_sn_to_path($_SERVER['SCRIPT_NAME']) :
|
||||
null;
|
||||
}
|
||||
|
@ -109,11 +111,14 @@ $config =
|
|||
'broughtbyurl' => null,
|
||||
'closed' => false,
|
||||
'inviteonly' => false,
|
||||
'openidonly' => false,
|
||||
'private' => false,
|
||||
'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
|
||||
|
@ -137,7 +142,8 @@ $config =
|
|||
array('blacklist' => array(),
|
||||
'featured' => array()),
|
||||
'profile' =>
|
||||
array('banned' => array()),
|
||||
array('banned' => array(),
|
||||
'biolimit' => null),
|
||||
'avatar' =>
|
||||
array('server' => null,
|
||||
'dir' => INSTALLDIR . '/avatar/',
|
||||
|
@ -169,6 +175,8 @@ $config =
|
|||
'host' => null, # only set if != server
|
||||
'debug' => false, # print extra debug info
|
||||
'public' => array()), # JIDs of users who want to receive the public stream
|
||||
'openid' =>
|
||||
array('enabled' => true),
|
||||
'invite' =>
|
||||
array('enabled' => true),
|
||||
'sphinx' =>
|
||||
|
@ -183,11 +191,20 @@ $config =
|
|||
array('piddir' => '/var/run',
|
||||
'user' => false,
|
||||
'group' => false),
|
||||
'emailpost' =>
|
||||
array('enabled' => true),
|
||||
'sms' =>
|
||||
array('enabled' => true),
|
||||
'twitter' =>
|
||||
array('enabled' => true),
|
||||
'twitterbridge' =>
|
||||
array('enabled' => false),
|
||||
'integration' =>
|
||||
array('source' => 'Laconica', # source attribute for Twitter
|
||||
'taguri' => $_server.',2009'), # base for tag URIs
|
||||
'twitter' =>
|
||||
array('consumer_key' => null,
|
||||
'consumer_secret' => null),
|
||||
'memcached' =>
|
||||
array('enabled' => false,
|
||||
'server' => 'localhost',
|
||||
|
@ -246,7 +263,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'),
|
||||
|
@ -261,6 +279,10 @@ $config =
|
|||
'linkcolor' => null,
|
||||
'backgroundimage' => null,
|
||||
'disposition' => null),
|
||||
'notice' =>
|
||||
array('contentlimit' => null),
|
||||
'message' =>
|
||||
array('contentlimit' => null),
|
||||
);
|
||||
|
||||
$config['db'] = &PEAR::getStaticProperty('DB_DataObject','options');
|
||||
|
@ -361,25 +383,11 @@ if ($_db_name != 'laconica' && !array_key_exists('ini_'.$_db_name, $config['db']
|
|||
$config['db']['ini_'.$_db_name] = INSTALLDIR.'/classes/laconica.ini';
|
||||
}
|
||||
|
||||
// XXX: how many of these could be auto-loaded on use?
|
||||
// Ignore openidonly if OpenID is disabled
|
||||
|
||||
require_once 'Validate.php';
|
||||
require_once 'markdown.php';
|
||||
|
||||
require_once INSTALLDIR.'/lib/util.php';
|
||||
require_once INSTALLDIR.'/lib/action.php';
|
||||
require_once INSTALLDIR.'/lib/theme.php';
|
||||
require_once INSTALLDIR.'/lib/mail.php';
|
||||
require_once INSTALLDIR.'/lib/subs.php';
|
||||
require_once INSTALLDIR.'/lib/Shorturl_api.php';
|
||||
require_once INSTALLDIR.'/lib/twitter.php';
|
||||
|
||||
require_once INSTALLDIR.'/lib/clientexception.php';
|
||||
require_once INSTALLDIR.'/lib/serverexception.php';
|
||||
|
||||
// XXX: other formats here
|
||||
|
||||
define('NICKNAME_FMT', VALIDATE_NUM.VALIDATE_ALPHA_LOWER);
|
||||
if (!$config['openid']['enabled']) {
|
||||
$config['site']['openidonly'] = false;
|
||||
}
|
||||
|
||||
function __autoload($cls)
|
||||
{
|
||||
|
@ -397,6 +405,32 @@ function __autoload($cls)
|
|||
}
|
||||
}
|
||||
|
||||
// XXX: how many of these could be auto-loaded on use?
|
||||
// XXX: note that these files should not use config options
|
||||
// at compile time since DB config options are not yet loaded.
|
||||
|
||||
require_once 'Validate.php';
|
||||
require_once 'markdown.php';
|
||||
|
||||
require_once INSTALLDIR.'/lib/util.php';
|
||||
require_once INSTALLDIR.'/lib/action.php';
|
||||
require_once INSTALLDIR.'/lib/theme.php';
|
||||
require_once INSTALLDIR.'/lib/mail.php';
|
||||
require_once INSTALLDIR.'/lib/subs.php';
|
||||
require_once INSTALLDIR.'/lib/Shorturl_api.php';
|
||||
require_once INSTALLDIR.'/lib/twitter.php';
|
||||
|
||||
require_once INSTALLDIR.'/lib/clientexception.php';
|
||||
require_once INSTALLDIR.'/lib/serverexception.php';
|
||||
|
||||
// Load settings from database; note we need autoload for this
|
||||
|
||||
Config::loadSettings();
|
||||
|
||||
// XXX: other formats here
|
||||
|
||||
define('NICKNAME_FMT', VALIDATE_NUM.VALIDATE_ALPHA_LOWER);
|
||||
|
||||
// Give plugins a chance to initialize in a fully-prepared environment
|
||||
|
||||
Event::handle('InitializePlugin');
|
||||
|
|
|
@ -99,25 +99,27 @@ class ConnectSettingsNav extends Widget
|
|||
function show()
|
||||
{
|
||||
# action => array('prompt', 'title')
|
||||
$menu =
|
||||
array('imsettings' =>
|
||||
array(_('IM'),
|
||||
_('Updates by instant messenger (IM)')),
|
||||
'smssettings' =>
|
||||
array(_('SMS'),
|
||||
_('Updates by SMS')),
|
||||
'twittersettings' =>
|
||||
array(_('Twitter'),
|
||||
_('Twitter integration options')));
|
||||
$menu = array();
|
||||
if (common_config('xmpp', 'enabled')) {
|
||||
$menu['imsettings'] =
|
||||
array(_('IM'),
|
||||
_('Updates by instant messenger (IM)'));
|
||||
}
|
||||
if (common_config('sms', 'enabled')) {
|
||||
$menu['smssettings'] =
|
||||
array(_('SMS'),
|
||||
_('Updates by SMS'));
|
||||
}
|
||||
if (common_config('twitter', 'enabled')) {
|
||||
$menu['twittersettings'] =
|
||||
array(_('Twitter'),
|
||||
_('Twitter integration options'));
|
||||
}
|
||||
|
||||
$action_name = $this->action->trimmed('action');
|
||||
$this->action->elementStart('ul', array('class' => 'nav'));
|
||||
|
||||
foreach ($menu as $menuaction => $menudesc) {
|
||||
if ($menuaction == 'imsettings' &&
|
||||
!common_config('xmpp', 'enabled')) {
|
||||
continue;
|
||||
}
|
||||
$this->action->menuItem(common_local_url($menuaction),
|
||||
$menudesc[0],
|
||||
$menudesc[1],
|
||||
|
|
|
@ -311,13 +311,7 @@ class DesignSettingsAction extends AccountSettingsAction
|
|||
function showStylesheets()
|
||||
{
|
||||
parent::showStylesheets();
|
||||
$farbtasticStyle =
|
||||
common_path('theme/base/css/farbtastic.css?version='.LACONICA_VERSION);
|
||||
|
||||
$this->element('link', array('rel' => 'stylesheet',
|
||||
'type' => 'text/css',
|
||||
'href' => $farbtasticStyle,
|
||||
'media' => 'screen, projection, tv'));
|
||||
$this->cssLink('css/farbtastic.css','base','screen, projection, tv');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -330,13 +324,8 @@ class DesignSettingsAction extends AccountSettingsAction
|
|||
{
|
||||
parent::showScripts();
|
||||
|
||||
$farbtasticPack = common_path('js/farbtastic/farbtastic.js');
|
||||
$userDesignGo = common_path('js/userdesign.go.js');
|
||||
|
||||
$this->element('script', array('type' => 'text/javascript',
|
||||
'src' => $farbtasticPack));
|
||||
$this->element('script', array('type' => 'text/javascript',
|
||||
'src' => $userDesignGo));
|
||||
$this->script('js/farbtastic/farbtastic.js');
|
||||
$this->script('js/farbtastic/farbtastic.go.js');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -72,7 +72,7 @@ class ErrorAction extends Action
|
|||
$status_string = $this->status[$this->code];
|
||||
header('HTTP/1.1 '.$this->code.' '.$status_string);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Display content.
|
||||
*
|
||||
|
@ -97,11 +97,11 @@ class ErrorAction extends Action
|
|||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
function showPage()
|
||||
|
||||
function showPage()
|
||||
{
|
||||
parent::showPage();
|
||||
|
||||
|
||||
// We don't want to have any more output after this
|
||||
exit();
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user