Merge branch '0.9.x' of git@gitorious.org:statusnet/mainline into 0.9.x

This commit is contained in:
Evan Prodromou 2009-09-15 17:16:35 -04:00
commit 13147143fc
73 changed files with 2049 additions and 661 deletions

View File

@ -247,3 +247,10 @@ StartLoadDoc: before loading a help doc (hook this to show your own documentatio
EndLoadDoc: after loading a help doc (hook this to modify other documentation) EndLoadDoc: after loading a help doc (hook this to modify other documentation)
- $title: title of the document - $title: title of the document
- $output: HTML output to show - $output: HTML output to show
StartApiRss: after the rss <channel> element is started
- $action: action object being shown
StartApiAtom: after the <feed> element is started
- $action: action object being shown

1
README
View File

@ -146,6 +146,7 @@ Your PHP installation must include the following PHP extensions:
- GD. For scaling down avatar images. - GD. For scaling down avatar images.
- mbstring. For handling Unicode (UTF-8) encoded strings. - mbstring. For handling Unicode (UTF-8) encoded strings.
- gettext. For multiple languages. Default on many PHP installs. - gettext. For multiple languages. Default on many PHP installs.
- tidy. Used to clean up HTML/URLs for the URL shortener to consume.
For some functionality, you will also need the following extensions: For some functionality, you will also need the following extensions:

View File

@ -1,5 +1,5 @@
<?php <?php
/* /**
* StatusNet - the distributed open-source microblogging tool * StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2008, 2009, StatusNet, Inc. * Copyright (C) 2008, 2009, StatusNet, Inc.
* *
@ -15,9 +15,29 @@
* *
* You should have received a copy of the GNU Affero General Public License * 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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Actions
* @package Actions
* @author Evan Prodromou <evan@prodromou.name>
* @author Evan Prodromou <evan@controlyourself.ca>
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Robin Millette <millette@controlyourself.ca>
* @author Adrian Lang <mail@adrianlang.de>
* @author Meitar Moscovitz <meitarm@gmail.com>
* @author Sarven Capadisli <csarven@controlyourself.ca>
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@controlezvous.ca>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@controlyourself.ca>
* @author csarven <csarven@controlyourself.ca>
* @license GNU Affero General Public License http://www.gnu.org/licenses/
* @link http://status.net
*/ */
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR.'/lib/personalgroupnav.php'; require_once INSTALLDIR.'/lib/personalgroupnav.php';
require_once INSTALLDIR.'/lib/noticelist.php'; require_once INSTALLDIR.'/lib/noticelist.php';
@ -43,8 +63,8 @@ class AllAction extends ProfileAction
$this->notice = $this->user->noticesWithFriends(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1); $this->notice = $this->user->noticesWithFriends(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
} }
if($this->page > 1 && $this->notice->N == 0){ if ($this->page > 1 && $this->notice->N == 0) {
$this->serverError(_('No such page'),$code=404); $this->serverError(_('No such page'), $code = 404);
} }
return true; return true;
@ -73,20 +93,33 @@ class AllAction extends ProfileAction
function getFeeds() function getFeeds()
{ {
return array(new Feed(Feed::RSS1, return array(
common_local_url('allrss', array('nickname' => new Feed(Feed::RSS1,
$this->user->nickname)), common_local_url(
sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->user->nickname)), 'allrss', array(
new Feed(Feed::RSS2, 'nickname' =>
common_local_url('api', array('apiaction' => 'statuses', $this->user->nickname)
'method' => 'friends_timeline', ),
'argument' => $this->user->nickname.'.rss')), sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->user->nickname)),
sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->user->nickname)), new Feed(Feed::RSS2,
new Feed(Feed::ATOM, common_local_url(
common_local_url('api', array('apiaction' => 'statuses', 'api', array(
'method' => 'friends_timeline', 'apiaction' => 'statuses',
'argument' => $this->user->nickname.'.atom')), 'method' => 'friends_timeline',
sprintf(_('Feed for friends of %s (Atom)'), $this->user->nickname))); 'argument' => $this->user->nickname.'.rss'
)
),
sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->user->nickname)),
new Feed(Feed::ATOM,
common_local_url(
'api', array(
'apiaction' => 'statuses',
'method' => 'friends_timeline',
'argument' => $this->user->nickname.'.atom'
)
),
sprintf(_('Feed for friends of %s (Atom)'), $this->user->nickname))
);
} }
function showLocalNav() function showLocalNav()
@ -106,8 +139,7 @@ class AllAction extends ProfileAction
} else { } else {
$message .= sprintf(_('You can try to [nudge %s](../%s) from his profile or [post something to his or her attention](%%%%action.newnotice%%%%?status_textarea=%s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname); $message .= sprintf(_('You can try to [nudge %s](../%s) from his profile or [post something to his or her attention](%%%%action.newnotice%%%%?status_textarea=%s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname);
} }
} } else {
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.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname);
} }
@ -126,17 +158,19 @@ class AllAction extends ProfileAction
$this->showEmptyListMessage(); $this->showEmptyListMessage();
} }
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE, $this->pagination(
$this->page, 'all', array('nickname' => $this->user->nickname)); $this->page > 1, $cnt > NOTICES_PER_PAGE,
$this->page, 'all', array('nickname' => $this->user->nickname)
);
} }
function showPageTitle() function showPageTitle()
{ {
$user =& common_current_user(); $user =& common_current_user();
if ($user && ($user->id == $this->user->id)) { if ($user && ($user->id == $this->user->id)) {
$this->element('h1', NULL, _("You and friends")); $this->element('h1', null, _("You and friends"));
} else { } else {
$this->element('h1', NULL, sprintf(_('%s and friends'), $this->user->nickname)); $this->element('h1', null, sprintf(_('%s and friends'), $this->user->nickname));
} }
} }

View File

@ -1,5 +1,5 @@
<?php <?php
/* /**
* StatusNet - the distributed open-source microblogging tool * StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2008, 2009, StatusNet, Inc. * Copyright (C) 2008, 2009, StatusNet, Inc.
* *
@ -15,9 +15,30 @@
* *
* You should have received a copy of the GNU Affero General Public License * 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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Actions
* @package Actions
* @author Evan Prodromou <evan@controlyourself.ca>
* @author Evan Prodromou <evan@prodromou.name>
* @author Brenda Wallace <shiny@cpan.org>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Robin Millette <millette@controlyourself.ca>
* @author Tom Adams <tom@holizz.com>
* @author Christopher Vollick <psycotica0@gmail.com>
* @author CiaranG <ciaran@ciarang.com>
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@controlezvous.ca>
* @author Evan Prodromou <evan@status.net>
* @author Gina Haeussge <osd@foosel.net>
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Sarven Capadisli <csarven@controlyourself.ca>
* @license GNU Affero General Public License http://www.gnu.org/licenses/
* @link http://status.net
*/ */
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
class ApiAction extends Action class ApiAction extends Action
{ {
@ -27,6 +48,8 @@ class ApiAction extends Action
var $api_arg; var $api_arg;
var $api_method; var $api_method;
var $api_action; var $api_action;
var $auth_user;
var $auth_pw;
function handle($args) function handle($args)
{ {
@ -35,6 +58,7 @@ class ApiAction extends Action
$this->api_action = $this->arg('apiaction'); $this->api_action = $this->arg('apiaction');
$method = $this->arg('method'); $method = $this->arg('method');
$argument = $this->arg('argument'); $argument = $this->arg('argument');
$this->basic_auth_process_header();
if (isset($argument)) { if (isset($argument)) {
$cmdext = explode('.', $argument); $cmdext = explode('.', $argument);
@ -43,30 +67,30 @@ class ApiAction extends Action
$this->content_type = strtolower($cmdext[1]); $this->content_type = strtolower($cmdext[1]);
} else { } else {
# Requested format / content-type will be an extension on the method //Requested format / content-type will be an extension on the method
$cmdext = explode('.', $method); $cmdext = explode('.', $method);
$this->api_method = $cmdext[0]; $this->api_method = $cmdext[0];
$this->content_type = strtolower($cmdext[1]); $this->content_type = strtolower($cmdext[1]);
} }
if ($this->requires_auth()) { if ($this->requires_auth()) {
if (!isset($_SERVER['PHP_AUTH_USER'])) { if (!isset($this->auth_user)) {
# This header makes basic auth go //This header makes basic auth go
header('WWW-Authenticate: Basic realm="StatusNet API"'); header('WWW-Authenticate: Basic realm="StatusNet API"');
# If the user hits cancel -- bam! //If the user hits cancel -- bam!
$this->show_basic_auth_error(); $this->show_basic_auth_error();
} else { } else {
$nickname = $_SERVER['PHP_AUTH_USER']; $nickname = $this->auth_user;
$password = $_SERVER['PHP_AUTH_PW']; $password = $this->auth_pw;
$user = common_check_user($nickname, $password); $user = common_check_user($nickname, $password);
if ($user) { if ($user) {
$this->user = $user; $this->user = $user;
$this->process_command(); $this->process_command();
} else { } else {
# basic authentication failed //basic authentication failed
list($proxy, $ip) = common_client_ip(); list($proxy, $ip) = common_client_ip();
common_log(LOG_WARNING, "Failed API auth attempt, nickname = $nickname, proxy = $proxy, ip = $ip."); common_log(LOG_WARNING, "Failed API auth attempt, nickname = $nickname, proxy = $proxy, ip = $ip.");
@ -76,12 +100,12 @@ class ApiAction extends Action
} else { } else {
// Caller might give us a username even if not required // Caller might give us a username even if not required
if (isset($_SERVER['PHP_AUTH_USER'])) { if (isset($this->auth_user)) {
$user = User::staticGet('nickname', $_SERVER['PHP_AUTH_USER']); $user = User::staticGet('nickname', $this->auth_user);
if ($user) { if ($user) {
$this->user = $user; $this->user = $user;
} }
# Twitter doesn't throw an error if the user isn't found //Twitter doesn't throw an error if the user isn't found
} }
$this->process_command(); $this->process_command();
@ -94,7 +118,7 @@ class ApiAction extends Action
$actionfile = INSTALLDIR."/actions/$action.php"; $actionfile = INSTALLDIR."/actions/$action.php";
if (file_exists($actionfile)) { if (file_exists($actionfile)) {
require_once($actionfile); include_once $actionfile;
$action_class = ucfirst($action)."Action"; $action_class = ucfirst($action)."Action";
$action_obj = new $action_class(); $action_obj = new $action_class();
@ -110,10 +134,10 @@ class ApiAction extends Action
call_user_func(array($action_obj, $this->api_method), $_REQUEST, $apidata); call_user_func(array($action_obj, $this->api_method), $_REQUEST, $apidata);
} else { } else {
$this->clientError("API method not found!", $code=404); $this->clientError("API method not found!", $code = 404);
} }
} else { } else {
$this->clientError("API method not found!", $code=404); $this->clientError("API method not found!", $code = 404);
} }
} }
@ -133,6 +157,8 @@ class ApiAction extends Action
'groups/show', 'groups/show',
'groups/timeline', 'groups/timeline',
'groups/list_all', 'groups/list_all',
'groups/membership',
'groups/is_member',
'groups/timeline'); 'groups/timeline');
static $bareauth = array('statuses/user_timeline', static $bareauth = array('statuses/user_timeline',
@ -179,10 +205,11 @@ class ApiAction extends Action
$user_id = $this->arg('user_id'); $user_id = $this->arg('user_id');
$screen_name = $this->arg('screen_name'); $screen_name = $this->arg('screen_name');
if (empty($this->api_arg) && if (empty($this->api_arg)
empty($id) && && empty($id)
empty($user_id) && && empty($user_id)
empty($screen_name)) { && empty($screen_name)
) {
return true; return true;
} else { } else {
return false; return false;
@ -201,6 +228,33 @@ class ApiAction extends Action
} }
} }
function basic_auth_process_header()
{
if (isset($_SERVER['AUTHORIZATION']) || isset($_SERVER['HTTP_AUTHORIZATION'])) {
$authorization_header = isset($_SERVER['HTTP_AUTHORIZATION'])? $_SERVER['HTTP_AUTHORIZATION'] : $_SERVER['AUTHORIZATION'];
}
if (isset($_SERVER['PHP_AUTH_USER'])) {
$this->auth_user = $_SERVER['PHP_AUTH_USER'];
$this->auth_pw = $_SERVER['PHP_AUTH_PW'];
} elseif (isset($authorization_header) && strstr(substr($authorization_header, 0, 5), 'Basic')) {
// decode the HTTP_AUTHORIZATION header on php-cgi server self
// on fcgid server the header name is AUTHORIZATION
$auth_hash = base64_decode(substr($authorization_header, 6));
list($this->auth_user, $this->auth_pw) = explode(':', $auth_hash);
// set all to null on a empty basic auth request
if ($this->auth_user == "") {
$this->auth_user = null;
$this->auth_pw = null;
}
} else {
$this->auth_user = null;
$this->auth_pw = null;
}
}
function show_basic_auth_error() function show_basic_auth_error()
{ {
header('HTTP/1.1 401 Unauthorized'); header('HTTP/1.1 401 Unauthorized');
@ -214,7 +268,7 @@ class ApiAction extends Action
$this->element('request', null, $_SERVER['REQUEST_URI']); $this->element('request', null, $_SERVER['REQUEST_URI']);
$this->elementEnd('hash'); $this->elementEnd('hash');
$this->endXML(); $this->endXML();
} else if ($this->content_type == 'json') { } else if ($this->content_type == 'json') {
header('Content-Type: application/json; charset=utf-8'); header('Content-Type: application/json; charset=utf-8');
$error_array = array('error' => $msg, 'request' => $_SERVER['REQUEST_URI']); $error_array = array('error' => $msg, 'request' => $_SERVER['REQUEST_URI']);
print(json_encode($error_array)); print(json_encode($error_array));

View File

@ -399,5 +399,7 @@ class AvatarsettingsAction extends AccountSettingsAction
$this->script('js/jcrop/jquery.Jcrop.min.js'); $this->script('js/jcrop/jquery.Jcrop.min.js');
$this->script('js/jcrop/jquery.Jcrop.go.js'); $this->script('js/jcrop/jquery.Jcrop.go.js');
} }
$this->autofocus('avatarfile');
} }
} }

View File

@ -160,6 +160,12 @@ class EditgroupAction extends GroupDesignAction
} }
} }
function showScripts()
{
parent::showScripts();
$this->autofocus('nickname');
}
function trySave() function trySave()
{ {
$cur = common_current_user(); $cur = common_current_user();

View File

@ -71,6 +71,12 @@ class EmailsettingsAction extends AccountSettingsAction
return _('Manage how you get email from %%site.name%%.'); return _('Manage how you get email from %%site.name%%.');
} }
function showScripts()
{
parent::showScripts();
$this->autofocus('email');
}
/** /**
* Content area of the page * Content area of the page
* *

View File

@ -146,8 +146,10 @@ class FoafAction extends Action
while ($sub->fetch()) { while ($sub->fetch()) {
if ($sub->token) { if ($sub->token) {
$other = Remote_profile::staticGet('id', $sub->subscriber); $other = Remote_profile::staticGet('id', $sub->subscriber);
$profile = Profile::staticGet('id', $sub->subscriber);
} else { } else {
$other = User::staticGet('id', $sub->subscriber); $other = User::staticGet('id', $sub->subscriber);
$profile = Profile::staticGet('id', $sub->subscriber);
} }
if (!$other) { if (!$other) {
common_debug('Got a bad subscription: '.print_r($sub,true)); common_debug('Got a bad subscription: '.print_r($sub,true));
@ -158,12 +160,15 @@ class FoafAction extends Action
} else { } else {
$person[$other->uri] = array(LISTENER, $person[$other->uri] = array(LISTENER,
$other->id, $other->id,
$other->nickname, $profile->nickname,
(empty($sub->token)) ? 'User' : 'Remote_profile'); (empty($sub->token)) ? 'User' : 'Remote_profile');
} }
$other->free(); $other->free();
$other = null; $other = null;
unset($other); unset($other);
$profile->free();
$profile = null;
unset($profile);
} }
} }
@ -254,8 +259,10 @@ class FoafAction extends Action
while ($sub->fetch()) { while ($sub->fetch()) {
if (!empty($sub->token)) { if (!empty($sub->token)) {
$other = Remote_profile::staticGet('id', $sub->subscribed); $other = Remote_profile::staticGet('id', $sub->subscribed);
$profile = Profile::staticGet('id', $sub->subscribed);
} else { } else {
$other = User::staticGet('id', $sub->subscribed); $other = User::staticGet('id', $sub->subscribed);
$profile = Profile::staticGet('id', $sub->subscribed);
} }
if (empty($other)) { if (empty($other)) {
common_debug('Got a bad subscription: '.print_r($sub,true)); common_debug('Got a bad subscription: '.print_r($sub,true));
@ -264,11 +271,14 @@ class FoafAction extends Action
$this->element('sioc:follows', array('rdf:resource' => $other->uri.'#acct')); $this->element('sioc:follows', array('rdf:resource' => $other->uri.'#acct'));
$person[$other->uri] = array(LISTENEE, $person[$other->uri] = array(LISTENEE,
$other->id, $other->id,
$other->nickname, $profile->nickname,
(empty($sub->token)) ? 'User' : 'Remote_profile'); (empty($sub->token)) ? 'User' : 'Remote_profile');
$other->free(); $other->free();
$other = null; $other = null;
unset($other); unset($other);
$profile->free();
$profile = null;
unset($profile);
} }
} }

View File

@ -445,6 +445,8 @@ class GrouplogoAction extends GroupDesignAction
$this->script('js/jcrop/jquery.Jcrop.min.js'); $this->script('js/jcrop/jquery.Jcrop.min.js');
$this->script('js/jcrop/jquery.Jcrop.go.js'); $this->script('js/jcrop/jquery.Jcrop.go.js');
} }
$this->autofocus('avatarfile');
} }
function showLocalNav() function showLocalNav()

View File

@ -90,6 +90,12 @@ class GroupsearchAction extends SearchAction
$user_group->free(); $user_group->free();
} }
} }
function showScripts()
{
parent::showScripts();
$this->autofocus('q');
}
} }
class GroupSearchResults extends GroupList class GroupSearchResults extends GroupList

View File

@ -98,6 +98,12 @@ class InviteAction extends CurrentUserDesignAction
$this->showPage(); $this->showPage();
} }
function showScripts()
{
parent::showScripts();
$this->autofocus('addresses');
}
function title() function title()
{ {
if ($this->mode == 'sent') { if ($this->mode == 'sent') {

View File

@ -22,6 +22,7 @@
* @category Login * @category Login
* @package StatusNet * @package StatusNet
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @author Sarven Capadisli <csarven@status.net>
* @copyright 2008-2009 StatusNet, Inc. * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
@ -37,6 +38,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @category Personal * @category Personal
* @package StatusNet * @package StatusNet
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
@ -158,6 +160,12 @@ class LoginAction extends Action
$this->showPage(); $this->showPage();
} }
function showScripts()
{
parent::showScripts();
$this->autofocus('nickname');
}
/** /**
* Title of the page * Title of the page
* *

View File

@ -135,6 +135,12 @@ class NoticesearchAction extends SearchAction
$this->pagination($page > 1, $cnt > NOTICES_PER_PAGE, $this->pagination($page > 1, $cnt > NOTICES_PER_PAGE,
$page, 'noticesearch', array('q' => $q)); $page, 'noticesearch', array('q' => $q));
} }
function showScripts()
{
parent::showScripts();
$this->autofocus('q');
}
} }
class SearchNoticeList extends NoticeList { class SearchNoticeList extends NoticeList {
@ -190,7 +196,7 @@ class SearchNoticeListItem extends NoticeListItem {
$result = preg_replace($pattern, '<strong>\\1</strong>', $text); $result = preg_replace($pattern, '<strong>\\1</strong>', $text);
/* Remove highlighting from inside links, loop incase multiple highlights in links */ /* Remove highlighting from inside links, loop incase multiple highlights in links */
$pattern = '/(href="[^"]*)<strong>('.$options.')<\/strong>([^"]*")/iU'; $pattern = '/(\w+="[^"]*)<strong>('.$options.')<\/strong>([^"]*")/iU';
do { do {
$result = preg_replace($pattern, '\\1\\2\\3', $result, -1, $count); $result = preg_replace($pattern, '\\1\\2\\3', $result, -1, $count);
} while ($count); } while ($count);

View File

@ -71,6 +71,12 @@ class OthersettingsAction extends AccountSettingsAction
return _('Manage various other options.'); return _('Manage various other options.');
} }
function showScripts()
{
parent::showScripts();
$this->autofocus('urlshorteningservice');
}
/** /**
* Content area of the page * Content area of the page
* *
@ -91,19 +97,20 @@ class OthersettingsAction extends AccountSettingsAction
$this->elementStart('fieldset'); $this->elementStart('fieldset');
$this->hidden('token', common_session_token()); $this->hidden('token', common_session_token());
// I18N $services=array();
global $_shorteners;
$services = array( if($_shorteners){
'' => 'None', foreach($_shorteners as $name=>$value)
'ur1.ca' => 'ur1.ca (free service)', {
'2tu.us' => '2tu.us (free service)', $services[$name]=$name;
'ptiturl.com' => 'ptiturl.com', if($value['info']['freeService']){
'bit.ly' => 'bit.ly', // I18N
'tinyurl.com' => 'tinyurl.com', $services[$name].=' (free service)';
'is.gd' => 'is.gd', }
'snipr.com' => 'snipr.com', }
'metamark.net' => 'metamark.net' }
); asort($services);
$services['']='None';
$this->elementStart('ul', 'form_data'); $this->elementStart('ul', 'form_data');
$this->elementStart('li'); $this->elementStart('li');

View File

@ -69,6 +69,12 @@ class PasswordsettingsAction extends AccountSettingsAction
return _('Change your password.'); return _('Change your password.');
} }
function showScripts()
{
parent::showScripts();
$this->autofocus('oldpassword');
}
/** /**
* Content area of the page * Content area of the page
* *

View File

@ -85,6 +85,12 @@ class PeoplesearchAction extends SearchAction
$profile->free(); $profile->free();
} }
} }
function showScripts()
{
parent::showScripts();
$this->autofocus('q');
}
} }
/** /**

View File

@ -23,6 +23,7 @@
* @package StatusNet * @package StatusNet
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @author Sarven Capadisli <csarven@status.net>
* @copyright 2008-2009 StatusNet, Inc. * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
@ -41,6 +42,7 @@ require_once INSTALLDIR.'/lib/accountsettingsaction.php';
* @package StatusNet * @package StatusNet
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
@ -70,6 +72,12 @@ class ProfilesettingsAction extends AccountSettingsAction
'so people know more about you.'); 'so people know more about you.');
} }
function showScripts()
{
parent::showScripts();
$this->autofocus('nickname');
}
/** /**
* Content area of the page * Content area of the page
* *

View File

@ -225,10 +225,10 @@ class PublicAction extends Action
function showAnonymousMessage() function showAnonymousMessage()
{ {
if (! (common_config('site','closed') || common_config('site','inviteonly'))) { 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 ' . $m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
'based on the Free Software [StatusNet](http://status.net/) tool. ' . 'based on the Free Software [StatusNet](http://status.net/) tool. ' .
'[Join now](%%%%action.register%%%%) to share notices about yourself with friends, family, and colleagues! ' . '[Join now](%%action.register%%) to share notices about yourself with friends, family, and colleagues! ' .
'([Read more](%%%%doc.help%%%%))'); '([Read more](%%doc.help%%))');
} else { } else {
$m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . $m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
'based on the Free Software [StatusNet](http://status.net/) tool.'); 'based on the Free Software [StatusNet](http://status.net/) tool.');

View File

@ -136,6 +136,12 @@ class RegisterAction extends Action
} }
} }
function showScripts()
{
parent::showScripts();
$this->autofocus('nickname');
}
/** /**
* Try to register a user * Try to register a user
* *

View File

@ -69,6 +69,12 @@ class SmssettingsAction extends ConnectSettingsAction
return _('You can receive SMS messages through email from %%site.name%%.'); return _('You can receive SMS messages through email from %%site.name%%.');
} }
function showScripts()
{
parent::showScripts();
$this->autofocus('sms');
}
/** /**
* Content area of the page * Content area of the page
* *

View File

@ -107,6 +107,12 @@ class SubscriptionsAction extends GalleryAction
array('nickname' => $this->user->nickname)); array('nickname' => $this->user->nickname));
} }
function showScripts()
{
parent::showScripts();
$this->autofocus('tag');
}
function showEmptyListMessage() function showEmptyListMessage()
{ {
if (common_logged_in()) { if (common_logged_in()) {

View File

@ -99,6 +99,12 @@ class TwitapifriendshipsAction extends TwitterapiAction
$other = $this->get_profile($id); $other = $this->get_profile($id);
$user = $apidata['user']; // Alwyas the auth user $user = $apidata['user']; // Alwyas the auth user
if ($user->id == $other->id) {
$this->clientError(_("You cannot unfollow yourself!"),
403, $apidata['content-type']);
return;
}
$sub = new Subscription(); $sub = new Subscription();
$sub->subscriber = $user->id; $sub->subscriber = $user->id;
$sub->subscribed = $other->id; $sub->subscribed = $other->id;

View File

@ -21,7 +21,7 @@
* *
* @category Twitter * @category Twitter
* @package StatusNet * @package StatusNet
* @author Craig Andrews * @author Craig Andrews <candrews@integralblue.com>
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc. * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
@ -41,7 +41,7 @@ require_once INSTALLDIR.'/lib/twitterapi.php';
* *
* @category Twitter * @category Twitter
* @package StatusNet * @package StatusNet
* @author Craig Andrews * @author Craig Andrews <candrews@integralblue.com>
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc. * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
@ -233,4 +233,97 @@ require_once INSTALLDIR.'/lib/twitterapi.php';
} }
} }
function membership($args, $apidata)
{
parent::handle($args);
common_debug("in groups api action");
$this->auth_user = $apidata['user'];
$group = $this->get_group($apidata['api_arg'], $apidata);
if (empty($group)) {
$this->clientError('Not Found', 404, $apidata['content-type']);
return;
}
$sitename = common_config('site', 'name');
$title = sprintf(_("Members of %s group"), $group->nickname);
$taguribase = common_config('integration', 'taguri');
$id = "tag:$taguribase:GroupMembership:".$group->id;
$link = common_local_url('showgroup',
array('nickname' => $group->nickname));
$subtitle = sprintf(_('Members of %1$s on %2$s'),
$group->nickname, $sitename);
$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');
$member = $group->getMembers(($page-1)*$count,
$count, $since_id, $max_id, $since);
switch($apidata['content-type']) {
case 'xml':
$this->show_twitter_xml_users($member);
break;
//TODO implement the RSS and ATOM content types
/*case 'rss':
$this->show_rss_users($member, $title, $link, $subtitle);
break;*/
/*case 'atom':
if (isset($apidata['api_arg'])) {
$selfuri = common_root_url() .
'api/statusnet/groups/membership/' .
$apidata['api_arg'] . '.atom';
} else {
$selfuri = common_root_url() .
'api/statusnet/groups/membership.atom';
}
$this->show_atom_users($member, $title, $id, $link,
$subtitle, null, $selfuri);
break;*/
case 'json':
$this->show_json_users($member);
break;
default:
$this->clientError(_('API method not found!'), $code = 404);
}
}
function is_member($args, $apidata)
{
parent::handle($args);
common_debug("in groups api action");
$this->auth_user = $apidata['user'];
$group = User_group::staticGet($args['group_id']);
if(! $group){
$this->clientError(_('Group not found'), $code = 500);
}
$user = User::staticGet('id', $args['user_id']);
if(! $user){
$this->clientError(_('User not found'), $code = 500);
}
$is_member=$user->isMember($group);
switch($apidata['content-type']) {
case 'xml':
$this->init_document('xml');
$this->element('is_member', null, $is_member);
$this->end_document('xml');
break;
case 'json':
$this->init_document('json');
$this->show_json_objects(array('is_member'=>$is_member));
$this->end_document('json');
break;
default:
$this->clientError(_('API method not found!'), $code = 404);
}
}
} }

View File

@ -21,7 +21,7 @@
* *
* @category Twitter * @category Twitter
* @package StatusNet * @package StatusNet
* @author Craig Andrews * @author Craig Andrews <candrews@integralblue.com>
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc. * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
@ -41,7 +41,7 @@ require_once INSTALLDIR.'/lib/twitterapi.php';
* *
* @category Twitter * @category Twitter
* @package StatusNet * @package StatusNet
* @author Craig Andrews * @author Craig Andrews <candrews@integralblue.com>
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc. * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0

View File

@ -165,7 +165,7 @@ class TwittersettingsAction extends ConnectSettingsAction
($flink->noticesync & FOREIGN_NOTICE_RECV) : ($flink->noticesync & FOREIGN_NOTICE_RECV) :
false); false);
$this->elementEnd('li'); $this->elementEnd('li');
} else {
// preserve setting even if bidrection bridge toggled off // preserve setting even if bidrection bridge toggled off
if ($flink && ($flink->noticesync & FOREIGN_NOTICE_RECV)) { if ($flink && ($flink->noticesync & FOREIGN_NOTICE_RECV)) {

View File

@ -78,14 +78,14 @@ class File extends Memcached_DataObject
$file_id = $x->insert(); $file_id = $x->insert();
if (isset($redir_data['type']) if (isset($redir_data['type'])
&& ('text/html' === substr($redir_data['type'], 0, 9)) && (('text/html' === substr($redir_data['type'], 0, 9) || 'application/xhtml+xml' === substr($redir_data['type'], 0, 21)))
&& ($oembed_data = File_oembed::_getOembed($given_url))) { && ($oembed_data = File_oembed::_getOembed($given_url))) {
File_oembed::saveNew($oembed_data, $file_id); File_oembed::saveNew($oembed_data, $file_id);
} }
return $x; return $x;
} }
function processNew($given_url, $notice_id) { function processNew($given_url, $notice_id=null) {
if (empty($given_url)) return -1; // error, no url to process if (empty($given_url)) return -1; // error, no url to process
$given_url = File_redirection::_canonUrl($given_url); $given_url = File_redirection::_canonUrl($given_url);
if (empty($given_url)) return -1; // error, no url to process if (empty($given_url)) return -1; // error, no url to process
@ -119,7 +119,9 @@ class File extends Memcached_DataObject
} }
} }
File_to_post::processNew($file_id, $notice_id); if (!empty($notice_id)) {
File_to_post::processNew($file_id, $notice_id);
}
return $x; return $x;
} }

View File

@ -260,17 +260,6 @@ class Notice extends Memcached_DataObject
$notice->saveUrls(); $notice->saveUrls();
// FIXME: why do we have to re-render the content?
// Remove this if it's not necessary.
$orig2 = clone($notice);
$notice->rendered = common_render_content($final, $notice);
if (!$notice->update($orig2)) {
common_log_db_error($notice, 'UPDATE', __FILE__);
return _('Problem saving notice.');
}
$notice->query('COMMIT'); $notice->query('COMMIT');
Event::handle('EndNoticeSave', array($notice)); Event::handle('EndNoticeSave', array($notice));
@ -755,6 +744,10 @@ class Notice extends Memcached_DataObject
return new ArrayWrapper($notices); return new ArrayWrapper($notices);
} else { } else {
$notice = new Notice(); $notice = new Notice();
if (empty($ids)) {
//if no IDs requested, just return the notice object
return $notice;
}
$notice->whereAdd('id in (' . implode(', ', $ids) . ')'); $notice->whereAdd('id in (' . implode(', ', $ids) . ')');
$notice->orderBy('id DESC'); $notice->orderBy('id DESC');

View File

@ -54,7 +54,7 @@ class Status_network extends DB_DataObject
global $config; global $config;
$config['db']['database_'.$dbname] = "mysqli://$dbuser:$dbpass@$dbhost/$dbname"; $config['db']['database_'.$dbname] = "mysqli://$dbuser:$dbpass@$dbhost/$dbname";
$config['db']['ini_'.$dbname] = INSTALLDIR.'/classes/statusnet.ini'; $config['db']['ini_'.$dbname] = INSTALLDIR.'/classes/status_network.ini';
$config['db']['table_status_network'] = $dbname; $config['db']['table_status_network'] = $dbname;
self::$cache = new Memcache(); self::$cache = new Memcache();

View File

@ -103,10 +103,7 @@ class User extends Memcached_DataObject
} }
$toupdate = implode(', ', $parts); $toupdate = implode(', ', $parts);
$table = $this->tableName(); $table = common_database_tablename($this->tableName());
if(common_config('db','quote_identifiers')) {
$table = '"' . $table . '"';
}
$qry = 'UPDATE ' . $table . ' SET ' . $toupdate . $qry = 'UPDATE ' . $table . ' SET ' . $toupdate .
' WHERE id = ' . $this->id; ' WHERE id = ' . $this->id;
$orig->decache(); $orig->decache();
@ -630,11 +627,7 @@ class User extends Memcached_DataObject
'ORDER BY subscription.created DESC '; 'ORDER BY subscription.created DESC ';
if ($offset) { if ($offset) {
if (common_config('db','type') == 'pgsql') { $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
} else {
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
}
} }
$profile = new Profile(); $profile = new Profile();
@ -657,11 +650,7 @@ class User extends Memcached_DataObject
'AND subscription.subscribed != subscription.subscriber ' . 'AND subscription.subscribed != subscription.subscriber ' .
'ORDER BY subscription.created DESC '; 'ORDER BY subscription.created DESC ';
if (common_config('db','type') == 'pgsql') { $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
} else {
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
}
$profile = new Profile(); $profile = new Profile();

View File

@ -12,3 +12,23 @@ alter table user_group
alter table file_oembed alter table file_oembed
add column mimetype varchar(50) comment 'mime type of resource'; add column mimetype varchar(50) comment 'mime type of resource';
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;
create table user_role (
user_id integer not null comment 'user having the role' references user (id),
role varchar(32) not null comment 'string representing the role',
created datetime not null comment 'date the role was granted',
constraint primary key (user_id, role)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;

View File

@ -1,2 +1,40 @@
// SQL commands to update an 0.8.x version of Laconica -- SQL commands to update an 0.8.x version of Laconica
// to 0.9.x. -- to 0.9.x.
--these are just comments
/*
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';
*/
alter table file_oembed
add column mimetype varchar(50) /*comment 'mime type of resource'*/;
create table config (
section varchar(32) /* comment 'configuration section'*/,
setting varchar(32) /* comment 'configuration setting'*/,
value varchar(255) /* comment 'configuration value'*/,
primary key (section, setting)
);
create table user_role (
user_id integer not null /* comment 'user having the role'*/ references "user" (id),
role varchar(32) not null /* comment 'string representing the role'*/,
created timestamp /* not null comment 'date the role was granted'*/,
primary key (user_id, role)
);

View File

@ -549,3 +549,23 @@ create index noticecontent_idx on notice using gist(to_tsvector('english',conten
create trigger textsearchupdate before insert or update on profile for each row create trigger textsearchupdate before insert or update on profile for each row
execute procedure tsvector_update_trigger(textsearch, 'pg_catalog.english', nickname, fullname, location, bio, homepage); execute procedure tsvector_update_trigger(textsearch, 'pg_catalog.english', nickname, fullname, location, bio, homepage);
create table config (
section varchar(32) /* comment 'configuration section'*/,
setting varchar(32) /* comment 'configuration setting'*/,
value varchar(255) /* comment 'configuration value'*/,
primary key (section, setting)
);
create table user_role (
user_id integer not null /* comment 'user having the role'*/ references "user" (id),
role varchar(32) not null /* comment 'string representing the role'*/,
created timestamp /* not null comment 'date the role was granted'*/,
primary key (user_id, role)
);

View File

@ -13,7 +13,7 @@ Bugs
---- ----
If you think you've found a bug in the [StatusNet](http://status.net/) software, If you think you've found a bug in the [StatusNet](http://status.net/) software,
or if there's a new feature you'd like to see, add it into the [StatusNet bug database](http://status.net/PITS/HomePage). Don't forget to check the list of or if there's a new feature you'd like to see, add it into the [StatusNet bug database](http://status.net/bugs/). Don't forget to check the list of
existing bugs to make sure it hasn't already been reported! existing bugs to make sure it hasn't already been reported!
Email Email

View File

@ -199,7 +199,8 @@ class OAuthRequest {/*{{{*/
} else { } else {
// collect request parameters from query string (GET) and post-data (POST) if appropriate (note: POST vars have priority) // collect request parameters from query string (GET) and post-data (POST) if appropriate (note: POST vars have priority)
$req_parameters = $_GET; $req_parameters = $_GET;
if ($http_method == "POST" && @strstr($request_headers["Content-Type"], "application/x-www-form-urlencoded") ) { if ($http_method == "POST" &&
( @strstr($request_headers["Content-Type"], "application/x-www-form-urlencoded") || @strstr($_ENV["CONTENT_TYPE"], "application/x-www-form-urlencoded") )) {
$req_parameters = array_merge($req_parameters, $_POST); $req_parameters = array_merge($req_parameters, $_POST);
} }

View File

@ -256,7 +256,7 @@ class Services_oEmbed
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (substr($code, 0, 1) != '2') { if (substr($code, 0, 1) != '2') {
throw new Services_oEmbed_Exception('Non-200 code returned'); throw new Services_oEmbed_Exception('Non-200 code returned. Got code ' . $code);
} }
curl_close($ch); curl_close($ch);
@ -302,8 +302,8 @@ class Services_oEmbed
// Find all <link /> tags that have a valid oembed type set. We then // Find all <link /> tags that have a valid oembed type set. We then
// extract the href attribute for each type. // extract the href attribute for each type.
$regexp = '#<link([^>]*)type="' . $regexp = '#<link([^>]*)type[\s\n]*=[\s\n]*"' .
'(application/json|text/xml)\+oembed"([^>]*)>#i'; '(application/json|text/xml)\+oembed"([^>]*)>#im';
$m = $ret = array(); $m = $ret = array();
if (!preg_match_all($regexp, $body, $m)) { if (!preg_match_all($regexp, $body, $m)) {
@ -314,7 +314,7 @@ class Services_oEmbed
foreach ($m[0] as $i => $link) { foreach ($m[0] as $i => $link) {
$h = array(); $h = array();
if (preg_match('/href="([^"]+)"/i', $link, $h)) { if (preg_match('/[\s\n]+href[\s\n]*=[\s\n]*"([^"]+)"/im', $link, $h)) {
$ret[$m[2][$i]] = $h[1]; $ret[$m[2][$i]] = $h[1];
} }
} }
@ -347,7 +347,7 @@ class Services_oEmbed
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (substr($code, 0, 1) != '2') { if (substr($code, 0, 1) != '2') {
throw new Services_oEmbed_Exception('Non-200 code returned'); throw new Services_oEmbed_Exception('Non-200 code returned. Got code ' . $code);
} }
return $result; return $result;

View File

@ -454,7 +454,7 @@ class Stomp
*/ */
public function disconnect () public function disconnect ()
{ {
$header = array(); $headers = array();
if ($this->clientId != null) { if ($this->clientId != null) {
$headers["client-id"] = $this->clientId; $headers["client-id"] = $this->clientId;

View File

@ -15,6 +15,24 @@
* *
* You should have received a copy of the GNU Affero General Public License * 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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category StatusNet
* @package StatusNet
* @license GNU Affero General Public License http://www.gnu.org/licenses/
* @author Brenda Wallace <shiny@cpan.org>
* @author Christopher Vollick <psycotica0@gmail.com>
* @author CiaranG <ciaran@ciarang.com>
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@controlezvous.ca>
* @author Evan Prodromou <evan@controlyourself.ca>
* @author Evan Prodromou <evan@prodromou.name>
* @author Evan Prodromou <evan@status.net>
* @author Gina Haeussge <osd@foosel.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Robin Millette <millette@controlyourself.ca>
* @author Sarven Capadisli <csarven@controlyourself.ca>
* @author Tom Adams <tom@holizz.com>
*/ */
define('INSTALLDIR', dirname(__FILE__)); define('INSTALLDIR', dirname(__FILE__));
@ -29,7 +47,8 @@ $action = null;
function getPath($req) function getPath($req)
{ {
if ((common_config('site', 'fancy') || !array_key_exists('PATH_INFO', $_SERVER)) if ((common_config('site', 'fancy') || !array_key_exists('PATH_INFO', $_SERVER))
&& array_key_exists('p', $req)) { && array_key_exists('p', $req)
) {
return $req['p']; return $req['p'];
} else if (array_key_exists('PATH_INFO', $_SERVER)) { } else if (array_key_exists('PATH_INFO', $_SERVER)) {
return $_SERVER['PATH_INFO']; return $_SERVER['PATH_INFO'];
@ -45,28 +64,35 @@ function handleError($error)
} }
$logmsg = "PEAR error: " . $error->getMessage(); $logmsg = "PEAR error: " . $error->getMessage();
if(common_config('site', 'logdebug')) { if (common_config('site', 'logdebug')) {
$logmsg .= " : ". $error->getDebugInfo(); $logmsg .= " : ". $error->getDebugInfo();
} }
common_log(LOG_ERR, $logmsg); common_log(LOG_ERR, $logmsg);
if(common_config('site', 'logdebug')) { if (common_config('site', 'logdebug')) {
$bt = $error->getBacktrace(); $bt = $error->getBacktrace();
foreach ($bt as $line) { foreach ($bt as $line) {
common_log(LOG_ERR, $line); common_log(LOG_ERR, $line);
} }
} }
if ($error instanceof DB_DataObject_Error || if ($error instanceof DB_DataObject_Error
$error instanceof DB_Error) { || $error instanceof DB_Error
$msg = sprintf(_('The database for %s isn\'t responding correctly, '. ) {
'so the site won\'t work properly. '. $msg = sprintf(
'The site admins probably know about the problem, '. _(
'but you can contact them at %s to make sure. '. 'The database for %s isn\'t responding correctly, '.
'Otherwise, wait a few minutes and try again.'), 'so the site won\'t work properly. '.
common_config('site', 'name'), 'The site admins probably know about the problem, '.
common_config('site', 'email')); 'but you can contact them at %s to make sure. '.
'Otherwise, wait a few minutes and try again.'
),
common_config('site', 'name'),
common_config('site', 'email')
);
} else { } else {
$msg = _('An important error occured, probably related to email setup. '. $msg = _(
'Check logfiles for more info..'); 'An important error occured, probably related to email setup. '.
'Check logfiles for more info..'
);
} }
$dac = new DBErrorAction($msg, 500); $dac = new DBErrorAction($msg, 500);
@ -127,10 +153,11 @@ function main()
$_lighty_url = @parse_url($_lighty_url); $_lighty_url = @parse_url($_lighty_url);
if ($_lighty_url['path'] != '/index.php' && $_lighty_url['path'] != '/') { if ($_lighty_url['path'] != '/index.php' && $_lighty_url['path'] != '/') {
$_lighty_path = preg_replace('/^'.preg_quote(common_config('site','path')).'\//', '', substr($_lighty_url['path'], 1)); $_lighty_path = preg_replace('/^'.preg_quote(common_config('site', 'path')).'\//', '', substr($_lighty_url['path'], 1));
$_SERVER['QUERY_STRING'] = 'p='.$_lighty_path; $_SERVER['QUERY_STRING'] = 'p='.$_lighty_path;
if ($_lighty_url['query']) if ($_lighty_url['query']) {
$_SERVER['QUERY_STRING'] .= '&'.$_lighty_url['query']; $_SERVER['QUERY_STRING'] .= '&'.$_lighty_url['query'];
}
parse_str($_lighty_url['query'], $_lighty_query); parse_str($_lighty_url['query'], $_lighty_query);
foreach ($_lighty_query as $key => $val) { foreach ($_lighty_query as $key => $val) {
$_GET[$key] = $_REQUEST[$key] = $val; $_GET[$key] = $_REQUEST[$key] = $val;
@ -141,7 +168,7 @@ function main()
$_SERVER['REDIRECT_URL'] = preg_replace("/\?.+$/", "", $_SERVER['REQUEST_URI']); $_SERVER['REDIRECT_URL'] = preg_replace("/\?.+$/", "", $_SERVER['REQUEST_URI']);
// quick check for fancy URL auto-detection support in installer. // 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']) { 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."); die("Fancy URL support detection succeeded. We suggest you enable this to get fancy (pretty) URLs.");
} }
global $user, $action; global $user, $action;
@ -149,8 +176,12 @@ function main()
Snapshot::check(); Snapshot::check();
if (!_have_config()) { if (!_have_config()) {
$msg = sprintf(_("No configuration file found. Try running ". $msg = sprintf(
"the installation program first.")); _(
"No configuration file found. Try running ".
"the installation program first."
)
);
$sac = new ServerErrorAction($msg); $sac = new ServerErrorAction($msg);
$sac->showPage(); $sac->showPage();
return; return;
@ -196,9 +227,10 @@ function main()
// If the site is private, and they're not on one of the "public" // If the site is private, and they're not on one of the "public"
// parts of the site, redirect to login // parts of the site, redirect to login
if (!$user && common_config('site', 'private') && if (!$user && common_config('site', 'private')
!isLoginAction($action) && && !isLoginAction($action)
!preg_match('/rss$/', $action)) { && !preg_match('/rss$/', $action)
) {
common_redirect(common_local_url('login')); common_redirect(common_local_url('login'));
return; return;
} }

View File

@ -15,6 +15,23 @@
* *
* You should have received a copy of the GNU Affero General Public License * 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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Installation
* @package Installation
*
* @author Adrian Lang <mail@adrianlang.de>
* @author Brenda Wallace <shiny@cpan.org>
* @author Brett Taylor <brett@webfroot.co.nz>
* @author Brion Vibber <brion@pobox.com>
* @author CiaranG <ciaran@ciarang.com>
* @author Craig Andrews <candrews@integralblue.com>
* @author Eric Helgeson <helfire@Erics-MBP.local>
* @author Evan Prodromou <evan@controlyourself.ca>
* @author Evan Prodromou <evan@status.net>
* @author Robin Millette <millette@controlyourself.ca>
* @author Sarven Capadisli <csarven@controlyourself.ca>
* @author Tom Adams <tom@holizz.com>
* @license GNU Affero General Public License http://www.gnu.org/licenses/
*/ */
define('INSTALLDIR', dirname(__FILE__)); define('INSTALLDIR', dirname(__FILE__));
@ -181,17 +198,34 @@ $external_libraries=array(
'check_class'=>'Validate' 'check_class'=>'Validate'
) )
); );
$dbModules = array(
'mysql' => array(
'name' => 'MySQL',
'check_module' => 'mysql', // mysqli?
'installer' => 'mysql_db_installer',
),
'pgsql' => array(
'name' => 'PostgreSQL',
'check_module' => 'pgsql',
'installer' => 'pgsql_db_installer',
),
);
/**
* the actual installation.
* If call libraries are present, then install
*
* @return void
*/
function main() function main()
{ {
if (!checkPrereqs()) if (!checkPrereqs()) {
{
return; return;
} }
if( $_GET['checklibs'] ){ if ($_GET['checklibs']) {
showLibs(); showLibs();
}else{ } else {
if ($_SERVER['REQUEST_METHOD'] == 'POST') { if ($_SERVER['REQUEST_METHOD'] == 'POST') {
handlePost(); handlePost();
} else { } else {
@ -200,71 +234,97 @@ function main()
} }
} }
/**
* checks if an external libary is present
*
* @param string $external_library Name of library
*
* @return boolean indicates if library present
*/
function haveExternalLibrary($external_library) function haveExternalLibrary($external_library)
{ {
if(isset($external_library['include']) && ! include_once($external_library['include'])){ if (isset($external_library['include']) && ! include_once $external_library['include'] ) {
return false; return false;
} }
if(isset($external_library['check_function']) && ! function_exists($external_library['check_function'])){ if (isset($external_library['check_function']) && ! function_exists($external_library['check_function'])) {
return false; return false;
} }
if(isset($external_library['check_class']) && ! class_exists($external_library['check_class'])){ if (isset($external_library['check_class']) && ! class_exists($external_library['check_class'])) {
return false; return false;
} }
return true; return true;
} }
/**
* Check if all is ready for installation
*
* @return void
*/
function checkPrereqs() function checkPrereqs()
{ {
$pass = true; $pass = true;
if (file_exists(INSTALLDIR.'/config.php')) { if (file_exists(INSTALLDIR.'/config.php')) {
?><p class="error">Config file &quot;config.php&quot; already exists.</p> printf('<p class="error">Config file &quot;config.php&quot; already exists.</p>');
<?php
$pass = false; $pass = false;
} }
if (version_compare(PHP_VERSION, '5.2.3', '<')) { if (version_compare(PHP_VERSION, '5.2.3', '<')) {
?><p class="error">Require PHP version 5.2.3 or greater.</p><?php printf('<p class="error">Require PHP version 5.2.3 or greater.</p>');
$pass = false; $pass = false;
} }
$reqs = array('gd', 'curl', $reqs = array('gd', 'curl',
'xmlwriter', 'mbstring'); 'xmlwriter', 'mbstring','tidy');
foreach ($reqs as $req) { foreach ($reqs as $req) {
if (!checkExtension($req)) { if (!checkExtension($req)) {
?><p class="error">Cannot load required extension: <code><?php echo $req; ?></code></p><?php printf('<p class="error">Cannot load required extension: <code>%s</code></p>', $req);
$pass = false; $pass = false;
} }
} }
if (!checkExtension('pgsql') && !checkExtension('mysql')) { // Make sure we have at least one database module available
?><p class="error">Cannot find mysql or pgsql extension. You need one or the other: <code><?php echo $req; ?></code></p><?php global $dbModules;
$pass = false; $missingExtensions = array();
foreach ($dbModules as $type => $info) {
if (!checkExtension($info['check_module'])) {
$missingExtensions[] = $info['check_module'];
}
} }
if (!is_writable(INSTALLDIR)) { if (count($missingExtensions) == count($dbModules)) {
?><p class="error">Cannot write config file to: <code><?php echo INSTALLDIR; ?></code></p> $req = implode(', ', $missingExtensions);
<p>On your server, try this command: <code>chmod a+w <?php echo INSTALLDIR; ?></code> printf('<p class="error">Cannot find mysql or pgsql extension. You need one or the other: <code>%s</code></p>', $req);
<?php $pass = false;
$pass = false; }
}
// Check the subdirs used for file uploads if (!is_writable(INSTALLDIR)) {
$fileSubdirs = array('avatar', 'background', 'file'); printf('<p class="error">Cannot write config file to: <code>%s</code></p>', INSTALLDIR);
foreach ($fileSubdirs as $fileSubdir) { printf('<p>On your server, try this command: <code>chmod a+w %s</code>', INSTALLDIR);
$fileFullPath = INSTALLDIR."/$fileSubdir/"; $pass = false;
if (!is_writable($fileFullPath)) { }
?><p class="error">Cannot write <?php echo $fileSubdir; ?> directory: <code><?php echo $fileFullPath; ?></code></p>
<p>On your server, try this command: <code>chmod a+w <?php echo $fileFullPath; ?></code></p>
<?php
$pass = false;
}
}
return $pass; // Check the subdirs used for file uploads
$fileSubdirs = array('avatar', 'background', 'file');
foreach ($fileSubdirs as $fileSubdir) {
$fileFullPath = INSTALLDIR."/$fileSubdir/";
if (!is_writable($fileFullPath)) {
printf('<p class="error">Cannot write to %s directory: <code>%s</code></p>', $fileSubdir, $fileFullPath);
printf('<p>On your server, try this command: <code>chmod a+w %s</code></p>', $fileFullPath);
$pass = false;
}
}
return $pass;
} }
/**
* Checks if a php extension is both installed and loaded
*
* @param string $name of extension to check
*
* @return boolean whether extension is installed and loaded
*/
function checkExtension($name) function checkExtension($name)
{ {
if (!extension_loaded($name)) { if (!extension_loaded($name)) {
@ -275,15 +335,20 @@ function checkExtension($name)
return true; return true;
} }
/**
* Show list of libraries
*
* @return void
*/
function showLibs() function showLibs()
{ {
global $external_libraries; global $external_libraries;
$present_libraries=array(); $present_libraries=array();
$absent_libraries=array(); $absent_libraries=array();
foreach($external_libraries as $external_library){ foreach ($external_libraries as $external_library) {
if(haveExternalLibrary($external_library)){ if (haveExternalLibrary($external_library)) {
$present_libraries[]=$external_library; $present_libraries[]=$external_library;
}else{ } else {
$absent_libraries[]=$external_library; $absent_libraries[]=$external_library;
} }
} }
@ -298,22 +363,21 @@ function showLibs()
<h2>Absent Libraries</h2> <h2>Absent Libraries</h2>
<ul id="absent_libraries"> <ul id="absent_libraries">
E_O_T; E_O_T;
foreach($absent_libraries as $library) foreach ($absent_libraries as $library) {
{
echo '<li>'; echo '<li>';
if($library['url']){ if ($library['url']) {
echo '<a href=">'.$library['url'].'">'.htmlentities($library['name']).'</a>'; echo '<a href=">'.$library['url'].'">'.htmlentities($library['name']).'</a>';
}else{ } else {
echo htmlentities($library['name']); echo htmlentities($library['name']);
} }
echo '<ul>'; echo '<ul>';
if($library['deb']){ if ($library['deb']) {
echo '<li class="deb package">deb: <a href="apt:' . urlencode($library['deb']) . '">' . htmlentities($library['deb']) . '</a></li>'; echo '<li class="deb package">deb: <a href="apt:' . urlencode($library['deb']) . '">' . htmlentities($library['deb']) . '</a></li>';
} }
if($library['rpm']){ if ($library['rpm']) {
echo '<li class="rpm package">rpm: ' . htmlentities($library['rpm']) . '</li>'; echo '<li class="rpm package">rpm: ' . htmlentities($library['rpm']) . '</li>';
} }
if($library['pear']){ if ($library['pear']) {
echo '<li class="pear package">pear: ' . htmlentities($library['pear']) . '</li>'; echo '<li class="pear package">pear: ' . htmlentities($library['pear']) . '</li>';
} }
echo '</ul>'; echo '</ul>';
@ -323,12 +387,11 @@ E_O_T;
<h2>Installed Libraries</h2> <h2>Installed Libraries</h2>
<ul id="present_libraries"> <ul id="present_libraries">
E_O_T; E_O_T;
foreach($present_libraries as $library) foreach ($present_libraries as $library) {
{
echo '<li>'; echo '<li>';
if($library['url']){ if ($library['url']) {
echo '<a href=">'.$library['url'].'">'.htmlentities($library['name']).'</a>'; echo '<a href=">'.$library['url'].'">'.htmlentities($library['name']).'</a>';
}else{ } else {
echo htmlentities($library['name']); echo htmlentities($library['name']);
} }
echo '</li>'; echo '</li>';
@ -340,6 +403,15 @@ E_O_T;
function showForm() function showForm()
{ {
global $dbModules;
$dbRadios = '';
$checked = 'checked="checked" '; // Check the first one which exists
foreach ($dbModules as $type => $info) {
if (checkExtension($info['check_module'])) {
$dbRadios .= "<input type=\"radio\" name=\"dbtype\" id=\"dbtype-$type\" value=\"$type\" $checked/> $info[name]<br />\n";
$checked = '';
}
}
echo<<<E_O_T echo<<<E_O_T
</ul> </ul>
</dd> </dd>
@ -376,8 +448,7 @@ function showForm()
<li> <li>
<label for="dbtype">Type</label> <label for="dbtype">Type</label>
<input type="radio" name="dbtype" id="fancy-mysql" value="mysql" checked='checked' /> MySQL<br /> $dbRadios
<input type="radio" name="dbtype" id="dbtype-pgsql" value="pgsql" /> PostgreSQL<br />
<p class="form_guide">Database type</p> <p class="form_guide">Database type</p>
</li> </li>
@ -406,17 +477,12 @@ E_O_T;
function updateStatus($status, $error=false) function updateStatus($status, $error=false)
{ {
?> echo '<li ' . ($error) ? 'class="error"': '';
<li <?php echo ($error) ? 'class="error"': ''; ?>><?php echo $status;?></li> echo ">$status</li>";
<?php
} }
function handlePost() function handlePost()
{ {
?>
<?php
$host = $_POST['host']; $host = $_POST['host'];
$dbtype = $_POST['dbtype']; $dbtype = $_POST['dbtype'];
$database = $_POST['database']; $database = $_POST['database'];
@ -427,55 +493,41 @@ function handlePost()
$server = $_SERVER['HTTP_HOST']; $server = $_SERVER['HTTP_HOST'];
$path = substr(dirname($_SERVER['PHP_SELF']), 1); $path = substr(dirname($_SERVER['PHP_SELF']), 1);
?> echo <<<STR
<dl class="system_notice"> <dl class="system_notice">
<dt>Page notice</dt> <dt>Page notice</dt>
<dd> <dd>
<ul> <ul>
<?php STR;
$fail = false; $fail = false;
if (empty($host)) { if (empty($host)) {
updateStatus("No hostname specified.", true); updateStatus("No hostname specified.", true);
$fail = true; $fail = true;
} }
if (empty($database)) { if (empty($database)) {
updateStatus("No database specified.", true); updateStatus("No database specified.", true);
$fail = true; $fail = true;
} }
if (empty($username)) { if (empty($username)) {
updateStatus("No username specified.", true); updateStatus("No username specified.", true);
$fail = true; $fail = true;
} }
// if (empty($password)) {
// updateStatus("No password specified.", true);
// $fail = true;
// }
if (empty($sitename)) { if (empty($sitename)) {
updateStatus("No sitename specified.", true); updateStatus("No sitename specified.", true);
$fail = true; $fail = true;
} }
if($fail){ if ($fail) {
showForm(); showForm();
return; return;
} }
// FIXME: use PEAR::DB or PDO instead of our own switch global $dbModules;
$db = call_user_func($dbModules[$dbtype]['installer'], $host, $database, $username, $password);
switch($dbtype) {
case 'mysql':
$db = mysql_db_installer($host, $database, $username, $password);
break;
case 'pgsql':
$db = pgsql_db_installer($host, $database, $username, $password);
break;
default:
}
if (!$db) { if (!$db) {
// database connection failed, do not move on to create config file. // database connection failed, do not move on to create config file.
@ -498,112 +550,110 @@ function handlePost()
updateStatus("StatusNet has been installed at $link"); updateStatus("StatusNet has been installed at $link");
updateStatus("You can visit your <a href='$link'>new StatusNet site</a>."); updateStatus("You can visit your <a href='$link'>new StatusNet site</a>.");
?>
<?php
} }
function pgsql_db_installer($host, $database, $username, $password) { function Pgsql_Db_installer($host, $database, $username, $password)
$connstring = "dbname=$database host=$host user=$username"; {
$connstring = "dbname=$database host=$host user=$username";
//No password would mean trust authentication used. //No password would mean trust authentication used.
if (!empty($password)) { if (!empty($password)) {
$connstring .= " password=$password"; $connstring .= " password=$password";
} }
updateStatus("Starting installation..."); updateStatus("Starting installation...");
updateStatus("Checking database..."); updateStatus("Checking database...");
$conn = pg_connect($connstring); $conn = pg_connect($connstring);
if ($conn ===false) { if ($conn ===false) {
updateStatus("Failed to connect to database: $connstring"); updateStatus("Failed to connect to database: $connstring");
showForm(); showForm();
return false; return false;
} }
//ensure database encoding is UTF8 //ensure database encoding is UTF8
$record = pg_fetch_object(pg_query($conn, 'SHOW server_encoding')); $record = pg_fetch_object(pg_query($conn, 'SHOW server_encoding'));
if ($record->server_encoding != 'UTF8') { if ($record->server_encoding != 'UTF8') {
updateStatus("StatusNet requires UTF8 character encoding. Your database is ". htmlentities($record->server_encoding)); updateStatus("StatusNet requires UTF8 character encoding. Your database is ". htmlentities($record->server_encoding));
showForm(); showForm();
return false; return false;
} }
updateStatus("Running database script..."); updateStatus("Running database script...");
//wrap in transaction; //wrap in transaction;
pg_query($conn, 'BEGIN'); pg_query($conn, 'BEGIN');
$res = runDbScript(INSTALLDIR.'/db/statusnet_pg.sql', $conn, 'pgsql'); $res = runDbScript(INSTALLDIR.'/db/statusnet_pg.sql', $conn, 'pgsql');
if ($res === false) { if ($res === false) {
updateStatus("Can't run database script.", true); updateStatus("Can't run database script.", true);
showForm(); showForm();
return false; return false;
} }
foreach (array('sms_carrier' => 'SMS carrier', foreach (array('sms_carrier' => 'SMS carrier',
'notice_source' => 'notice source', 'notice_source' => 'notice source',
'foreign_services' => 'foreign service') 'foreign_services' => 'foreign service')
as $scr => $name) { as $scr => $name) {
updateStatus(sprintf("Adding %s data to database...", $name)); updateStatus(sprintf("Adding %s data to database...", $name));
$res = runDbScript(INSTALLDIR.'/db/'.$scr.'.sql', $conn, 'pgsql'); $res = runDbScript(INSTALLDIR.'/db/'.$scr.'.sql', $conn, 'pgsql');
if ($res === false) { if ($res === false) {
updateStatus(sprintf("Can't run %d script.", $name), true); updateStatus(sprintf("Can't run %d script.", $name), true);
showForm(); showForm();
return false; return false;
} }
} }
pg_query($conn, 'COMMIT'); pg_query($conn, 'COMMIT');
if (empty($password)) { if (empty($password)) {
$sqlUrl = "pgsql://$username@$host/$database"; $sqlUrl = "pgsql://$username@$host/$database";
} } else {
else { $sqlUrl = "pgsql://$username:$password@$host/$database";
$sqlUrl = "pgsql://$username:$password@$host/$database"; }
}
$db = array('type' => 'pgsql', 'database' => $sqlUrl); $db = array('type' => 'pgsql', 'database' => $sqlUrl);
return $db; return $db;
} }
function mysql_db_installer($host, $database, $username, $password) { function Mysql_Db_installer($host, $database, $username, $password)
updateStatus("Starting installation..."); {
updateStatus("Checking database..."); updateStatus("Starting installation...");
updateStatus("Checking database...");
$conn = mysql_connect($host, $username, $password); $conn = mysql_connect($host, $username, $password);
if (!$conn) { if (!$conn) {
updateStatus("Can't connect to server '$host' as '$username'.", true); updateStatus("Can't connect to server '$host' as '$username'.", true);
showForm(); showForm();
return false; return false;
} }
updateStatus("Changing to database..."); updateStatus("Changing to database...");
$res = mysql_select_db($database, $conn); $res = mysql_select_db($database, $conn);
if (!$res) { if (!$res) {
updateStatus("Can't change to database.", true); updateStatus("Can't change to database.", true);
showForm(); showForm();
return false; return false;
} }
updateStatus("Running database script..."); updateStatus("Running database script...");
$res = runDbScript(INSTALLDIR.'/db/statusnet.sql', $conn); $res = runDbScript(INSTALLDIR.'/db/statusnet.sql', $conn);
if ($res === false) { if ($res === false) {
updateStatus("Can't run database script.", true); updateStatus("Can't run database script.", true);
showForm(); showForm();
return false; return false;
} }
foreach (array('sms_carrier' => 'SMS carrier', foreach (array('sms_carrier' => 'SMS carrier',
'notice_source' => 'notice source', 'notice_source' => 'notice source',
'foreign_services' => 'foreign service') 'foreign_services' => 'foreign service')
as $scr => $name) { as $scr => $name) {
updateStatus(sprintf("Adding %s data to database...", $name)); updateStatus(sprintf("Adding %s data to database...", $name));
$res = runDbScript(INSTALLDIR.'/db/'.$scr.'.sql', $conn); $res = runDbScript(INSTALLDIR.'/db/'.$scr.'.sql', $conn);
if ($res === false) { if ($res === false) {
updateStatus(sprintf("Can't run %d script.", $name), true); updateStatus(sprintf("Can't run %d script.", $name), true);
showForm(); showForm();
return false; return false;
} }
} }
$sqlUrl = "mysqli://$username:$password@$host/$database"; $sqlUrl = "mysqli://$username:$password@$host/$database";
$db = array('type' => 'mysql', 'database' => $sqlUrl); $db = array('type' => 'mysql', 'database' => $sqlUrl);
return $db; return $db;
} }
function writeConf($sitename, $server, $path, $fancy, $db) function writeConf($sitename, $server, $path, $fancy, $db)
@ -624,7 +674,7 @@ function writeConf($sitename, $server, $path, $fancy, $db)
// database // database
"\$config['db']['database'] = '{$db['database']}';\n\n". "\$config['db']['database'] = '{$db['database']}';\n\n".
($type == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n":''). ($db['type'] == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n":'').
"\$config['db']['type'] = '{$db['type']}';\n\n". "\$config['db']['type'] = '{$db['type']}';\n\n".
"?>"; "?>";
@ -634,7 +684,16 @@ function writeConf($sitename, $server, $path, $fancy, $db)
return $res; return $res;
} }
function runDbScript($filename, $conn, $type = 'mysql') /**
* Install schema into the database
*
* @param string $filename location of database schema file
* @param dbconn $conn connection to database
* @param string $type type of database, currently mysql or pgsql
*
* @return boolean - indicating success or failure
*/
function runDbScript($filename, $conn, $type = 'mysqli')
{ {
$sql = trim(file_get_contents($filename)); $sql = trim(file_get_contents($filename));
$stmts = explode(';', $sql); $stmts = explode(';', $sql);
@ -645,7 +704,7 @@ function runDbScript($filename, $conn, $type = 'mysql')
} }
// FIXME: use PEAR::DB or PDO instead of our own switch // FIXME: use PEAR::DB or PDO instead of our own switch
switch ($type) { switch ($type) {
case 'mysql': case 'mysqli':
$res = mysql_query($stmt, $conn); $res = mysql_query($stmt, $conn);
if ($res === false) { if ($res === false) {
$error = mysql_error(); $error = mysql_error();

View File

@ -19,7 +19,7 @@
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
class ShortUrlApi abstract class ShortUrlApi
{ {
protected $service_url; protected $service_url;
protected $long_limit = 27; protected $long_limit = 27;
@ -35,11 +35,9 @@ class ShortUrlApi
return $url; return $url;
} }
protected function shorten_imp($url) { protected abstract function shorten_imp($url);
return "To Override";
}
private function is_long($url) { protected function is_long($url) {
return strlen($url) >= common_config('site', 'shorturllength'); return strlen($url) >= common_config('site', 'shorturllength');
} }
@ -71,61 +69,3 @@ class ShortUrlApi
} }
} }
class LilUrl extends ShortUrlApi
{
function __construct()
{
parent::__construct('http://ur1.ca/');
}
protected function shorten_imp($url) {
$data['longurl'] = $url;
$response = $this->http_post($data);
if (!$response) return $url;
$y = @simplexml_load_string($response);
if (!isset($y->body)) return $url;
$x = $y->body->p[0]->a->attributes();
if (isset($x['href'])) return $x['href'];
return $url;
}
}
class PtitUrl extends ShortUrlApi
{
function __construct()
{
parent::__construct('http://ptiturl.com/?creer=oui&action=Reduire&url=');
}
protected function shorten_imp($url) {
$response = $this->http_get($url);
if (!$response) return $url;
$response = $this->tidy($response);
$y = @simplexml_load_string($response);
if (!isset($y->body)) return $url;
$xml = $y->body->center->table->tr->td->pre->a->attributes();
if (isset($xml['href'])) return $xml['href'];
return $url;
}
}
class TightUrl extends ShortUrlApi
{
function __construct()
{
parent::__construct('http://2tu.us/?save=y&url=');
}
protected function shorten_imp($url) {
$response = $this->http_get($url);
if (!$response) return $url;
$response = $this->tidy($response);
$y = @simplexml_load_string($response);
if (!isset($y->body)) return $url;
$xml = $y->body->p[0]->code[0]->a->attributes();
if (isset($xml['href'])) return $xml['href'];
return $url;
}
}

View File

@ -114,7 +114,6 @@ class StatsCommand extends Command
class FavCommand extends Command class FavCommand extends Command
{ {
var $other = null; var $other = null;
function __construct($user, $other) function __construct($user, $other)
@ -158,6 +157,108 @@ class FavCommand extends Command
$channel->output($this->user, _('Notice marked as fave.')); $channel->output($this->user, _('Notice marked as fave.'));
} }
}
class JoinCommand extends Command
{
var $other = null;
function __construct($user, $other)
{
parent::__construct($user);
$this->other = $other;
}
function execute($channel)
{
$nickname = common_canonical_nickname($this->other);
$group = User_group::staticGet('nickname', $nickname);
$cur = $this->user;
if (!$group) {
$channel->error($cur, _('No such group.'));
return;
}
if ($cur->isMember($group)) {
$channel->error($cur, _('You are already a member of that group'));
return;
}
if (Group_block::isBlocked($group, $cur->getProfile())) {
$channel->error($cur, _('You have been blocked from that group by the admin.'));
return;
}
$member = new Group_member();
$member->group_id = $group->id;
$member->profile_id = $cur->id;
$member->created = common_sql_now();
$result = $member->insert();
if (!$result) {
common_log_db_error($member, 'INSERT', __FILE__);
$channel->error($cur, sprintf(_('Could not join user %s to group %s'),
$cur->nickname, $group->nickname));
return;
}
$channel->output($cur, sprintf(_('%s joined group %s'),
$cur->nickname,
$group->nickname));
}
}
class DropCommand extends Command
{
var $other = null;
function __construct($user, $other)
{
parent::__construct($user);
$this->other = $other;
}
function execute($channel)
{
$nickname = common_canonical_nickname($this->other);
$group = User_group::staticGet('nickname', $nickname);
$cur = $this->user;
if (!$group) {
$channel->error($cur, _('No such group.'));
return;
}
if (!$cur->isMember($group)) {
$channel->error($cur, _('You are not a member of that group.'));
return;
}
$member = new Group_member();
$member->group_id = $group->id;
$member->profile_id = $cur->id;
if (!$member->find(true)) {
$channel->error($cur,_('Could not find membership record.'));
return;
}
$result = $member->delete();
if (!$result) {
common_log_db_error($member, 'INSERT', __FILE__);
$channel->error($cur, sprintf(_('Could not remove user %s to group %s'),
$cur->nickname, $group->nickname));
return;
}
$channel->output($cur, sprintf(_('%s left group %s'),
$cur->nickname,
$group->nickname));
}
} }
class WhoisCommand extends Command class WhoisCommand extends Command
@ -396,6 +497,8 @@ class HelpCommand extends Command
"get <nickname> - get last notice from user\n". "get <nickname> - get last notice from user\n".
"whois <nickname> - get profile info on user\n". "whois <nickname> - get profile info on user\n".
"fav <nickname> - add user's last notice as a 'fave'\n". "fav <nickname> - add user's last notice as a 'fave'\n".
"join <group> - join group\n".
"drop <group> - leave group\n".
"stats - get your stats\n". "stats - get your stats\n".
"stop - same as 'off'\n". "stop - same as 'off'\n".
"quit - same as 'off'\n". "quit - same as 'off'\n".

View File

@ -70,6 +70,26 @@ class CommandInterpreter
} else { } else {
return new OffCommand($user); return new OffCommand($user);
} }
case 'join':
if (!$arg) {
return null;
}
list($other, $extra) = explode(' ', $arg, 2);
if ($extra) {
return null;
} else {
return new JoinCommand($user, $other);
}
case 'drop':
if (!$arg) {
return null;
}
list($other, $extra) = explode(' ', $arg, 2);
if ($extra) {
return null;
} else {
return new DropCommand($user, $other);
}
case 'follow': case 'follow':
case 'sub': case 'sub':
if (!$arg) { if (!$arg) {

View File

@ -327,6 +327,8 @@ class DesignSettingsAction extends AccountSettingsAction
$this->script('js/farbtastic/farbtastic.js'); $this->script('js/farbtastic/farbtastic.js');
$this->script('js/farbtastic/farbtastic.go.js'); $this->script('js/farbtastic/farbtastic.go.js');
$this->script('js/userdesign.go.js'); $this->script('js/userdesign.go.js');
$this->autofocus('design_background-image_file');
} }
/** /**

View File

@ -132,13 +132,16 @@ class GalleryAction extends OwnerDesignAction
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementStart('li', array('id'=>'filter_tags_item')); $this->elementStart('li', array('id'=>'filter_tags_item'));
$this->elementStart('form', array('name' => 'bytag', $this->elementStart('form', array('name' => 'bytag',
'id' => 'bytag', 'id' => 'form_filter_bytag',
'action' => common_path('?action=' . $this->trimmed('action')), 'action' => common_path('?action=' . $this->trimmed('action')),
'method' => 'post')); 'method' => 'post'));
$this->elementStart('fieldset');
$this->element('legend', null, _('Select tag to filter'));
$this->dropdown('tag', _('Tag'), $content, $this->dropdown('tag', _('Tag'), $content,
_('Choose a tag to narrow list'), false, $tag); _('Choose a tag to narrow list'), false, $tag);
$this->hidden('nickname', $this->user->nickname); $this->hidden('nickname', $this->user->nickname);
$this->submit('submit', _('Go')); $this->submit('submit', _('Go'));
$this->elementEnd('fieldset');
$this->elementEnd('form'); $this->elementEnd('form');
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementEnd('ul'); $this->elementEnd('ul');

View File

@ -412,4 +412,29 @@ class HTMLOutputter extends XMLOutputter
$this->element('p', 'form_guide', $instructions); $this->element('p', 'form_guide', $instructions);
} }
} }
/**
* Internal script to autofocus the given element on page onload.
*
* @param string $id element ID, must refer to an existing element
*
* @return void
*
*/
function autofocus($id)
{
$this->elementStart('script', array('type' => 'text/javascript'));
$this->raw('
<!--
$(document).ready(function() {
var el = $("#' . $id . '");
if (el.length) {
el.focus();
}
});
-->
');
$this->elementEnd('script');
}
} }

View File

@ -213,26 +213,20 @@ class MailboxAction extends CurrentUserDesignAction
} }
$this->elementStart('div', 'entry-content'); $this->elementStart('div', 'entry-content');
$this->elementStart('dl', 'timestamp');
$this->element('dt', null, _('Published'));
$this->elementStart('dd', null);
$dt = common_date_iso8601($message->created);
$this->elementStart('a', array('rel' => 'bookmark', $this->elementStart('a', array('rel' => 'bookmark',
'class' => 'timestamp',
'href' => $messageurl)); 'href' => $messageurl));
$dt = common_date_iso8601($message->created);
$this->element('abbr', array('class' => 'published', $this->element('abbr', array('class' => 'published',
'title' => $dt), 'title' => $dt),
common_date_string($message->created)); common_date_string($message->created));
$this->elementEnd('a'); $this->elementEnd('a');
$this->elementEnd('dd');
$this->elementEnd('dl');
if ($message->source) { if ($message->source) {
$this->elementStart('dl', 'device'); $this->elementStart('span', 'source');
$this->elementStart('dt'); $this->text(_('from'));
$this->text(_('From')); $this->element('span', 'device', $this->showSource($message->source));
$this->elementEnd('dt'); $this->elementEnd('span');
$this->showSource($message->source);
$this->elementEnd('dl');
} }
$this->elementEnd('div'); $this->elementEnd('div');
@ -277,18 +271,18 @@ class MailboxAction extends CurrentUserDesignAction
case 'mail': case 'mail':
case 'omb': case 'omb':
case 'api': case 'api':
$this->element('dd', null, $source_name); $this->element('span', 'device', $source_name);
break; break;
default: default:
$ns = Notice_source::staticGet($source); $ns = Notice_source::staticGet($source);
if ($ns) { if ($ns) {
$this->elementStart('dd', null); $this->elementStart('span', 'device');
$this->element('a', array('href' => $ns->url, $this->element('a', array('href' => $ns->url,
'rel' => 'external'), 'rel' => 'external'),
$ns->name); $ns->name);
$this->elementEnd('dd'); $this->elementEnd('span');
} else { } else {
$this->element('dd', null, $source_name); $this->out->element('span', 'device', $source_name);
} }
break; break;
} }

View File

@ -22,7 +22,7 @@
* @category Action * @category Action
* @package StatusNet * @package StatusNet
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2008 StatusNet, Inc. * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */

View File

@ -76,4 +76,18 @@ class Plugin
{ {
return true; return true;
} }
/*
* the name of the shortener
* shortenerInfo associative array with additional information. One possible element is 'freeService' which can be true or false
* shortener array, first element is the name of the class, second element is an array to be passed as constructor parameters to the class
*/
function registerUrlShortener($name, $shortenerInfo, $shortener)
{
global $_shorteners;
if(!is_array($_shorteners)){
$_shorteners=array();
}
$_shorteners[$name]=array('info'=>$shortenerInfo, 'callInfo'=>$shortener);
}
} }

View File

@ -154,80 +154,134 @@ function broadcast_twitter($notice)
TWITTER_SERVICE); TWITTER_SERVICE);
if (is_twitter_bound($notice, $flink)) { if (is_twitter_bound($notice, $flink)) {
if (TwitterOAuthClient::isPackedToken($flink->credentials)) {
$user = $flink->getUser(); return broadcast_oauth($notice, $flink);
} else {
// XXX: Hack to get around PHP cURL's use of @ being a a meta character return broadcast_basicauth($notice, $flink);
$statustxt = preg_replace('/^@/', ' @', $notice->content);
$token = TwitterOAuthClient::unpackToken($flink->credentials);
$client = new TwitterOAuthClient($token->key, $token->secret);
$status = null;
try {
$status = $client->statusesUpdate($statustxt);
} catch (OAuthClientCurlException $e) {
if ($e->getMessage() == 'The requested URL returned error: 401') {
$errmsg = sprintf('User %1$s (user id: %2$s) has an invalid ' .
'Twitter OAuth access token.',
$user->nickname, $user->id);
common_log(LOG_WARNING, $errmsg);
// Bad auth token! We need to delete the foreign_link
// to Twitter and inform the user.
remove_twitter_link($flink);
return true;
} else {
// Some other error happened, so we should probably
// try to send again later.
$errmsg = sprintf('cURL error trying to send notice to Twitter ' .
'for user %1$s (user id: %2$s) - ' .
'code: %3$s message: $4$s.',
$user->nickname, $user->id,
$e->getCode(), $e->getMessage());
common_log(LOG_WARNING, $errmsg);
return false;
}
} }
if (empty($status)) {
// This could represent a failure posting,
// or the Twitter API might just be behaving flakey.
$errmsg = sprint('No data returned by Twitter API when ' .
'trying to send update for %1$s (user id %2$s).',
$user->nickname, $user->id);
common_log(LOG_WARNING, $errmsg);
return false;
}
// Notice crossed the great divide
$msg = sprintf('Twitter bridge posted notice %s to Twitter.',
$notice->id);
common_log(LOG_INFO, $msg);
} }
return true; return true;
} }
function broadcast_oauth($notice, $flink) {
$user = $flink->getUser();
$statustxt = format_status($notice);
// Convert !groups to #hashes
$statustxt = preg_replace('/(^|\s)!([A-Za-z0-9]{1,64})/', "\\1#\\2", $statustxt);
$token = TwitterOAuthClient::unpackToken($flink->credentials);
$client = new TwitterOAuthClient($token->key, $token->secret);
$status = null;
try {
$status = $client->statusesUpdate($statustxt);
} catch (OAuthClientCurlException $e) {
return process_error($e, $flink);
}
if (empty($status)) {
// This could represent a failure posting,
// or the Twitter API might just be behaving flakey.
$errmsg = sprintf('Twitter bridge - No data returned by Twitter API when ' .
'trying to send update for %1$s (user id %2$s).',
$user->nickname, $user->id);
common_log(LOG_WARNING, $errmsg);
return false;
}
// Notice crossed the great divide
$msg = sprintf('Twitter bridge - posted notice %s to Twitter using OAuth.',
$notice->id);
common_log(LOG_INFO, $msg);
return true;
}
function broadcast_basicauth($notice, $flink)
{
$user = $flink->getUser();
$statustxt = format_status($notice);
$client = new TwitterBasicAuthClient($flink);
$status = null;
try {
$status = $client->statusesUpdate($statustxt);
} catch (BasicAuthCurlException $e) {
return process_error($e, $flink);
}
if (empty($status)) {
$errmsg = sprintf('Twitter bridge - No data returned by Twitter API when ' .
'trying to send update for %1$s (user id %2$s).',
$user->nickname, $user->id);
common_log(LOG_WARNING, $errmsg);
$errmsg = sprintf('No data returned by Twitter API when ' .
'trying to send update for %1$s (user id %2$s).',
$user->nickname, $user->id);
common_log(LOG_WARNING, $errmsg);
return false;
}
$msg = sprintf('Twitter bridge - posted notice %s to Twitter using basic auth.',
$notice->id);
common_log(LOG_INFO, $msg);
return true;
}
function process_error($e, $flink)
{
$user = $flink->getUser();
$errmsg = $e->getMessage();
$delivered = false;
switch($errmsg) {
case 'The requested URL returned error: 401':
$logmsg = sprintf('Twiter bridge - User %1$s (user id: %2$s) has an invalid ' .
'Twitter screen_name/password combo or an invalid acesss token.',
$user->nickname, $user->id);
$delivered = true;
remove_twitter_link($flink);
break;
case 'The requested URL returned error: 403':
$logmsg = sprintf('Twitter bridge - User %1$s (user id: %2$s) has exceeded ' .
'his/her Twitter request limit.',
$user->nickname, $user->id);
break;
default:
$logmsg = sprintf('Twitter bridge - cURL error trying to send notice to Twitter ' .
'for user %1$s (user id: %2$s) - ' .
'code: %3$s message: %4$s.',
$user->nickname, $user->id,
$e->getCode(), $e->getMessage());
break;
}
common_log(LOG_WARNING, $logmsg);
return $delivered;
}
function format_status($notice)
{
// XXX: Hack to get around PHP cURL's use of @ being a a meta character
return preg_replace('/^@/', ' @', $notice->content);
}
function remove_twitter_link($flink) function remove_twitter_link($flink)
{ {
$user = $flink->getUser(); $user = $flink->getUser();
common_log(LOG_INFO, 'Removing Twitter bridge Foreign link for ' . common_log(LOG_INFO, 'Removing Twitter bridge Foreign link for ' .
"user $user->nickname (user id: $user->id)."); "user $user->nickname (user id: $user->id).");
$result = $flink->delete(); $result = $flink->delete();

View File

@ -595,7 +595,6 @@ class TwitterapiAction extends Action
$this->init_document('rss'); $this->init_document('rss');
$this->elementStart('channel');
$this->element('title', null, $title); $this->element('title', null, $title);
$this->element('link', null, $link); $this->element('link', null, $link);
if (!is_null($suplink)) { if (!is_null($suplink)) {
@ -621,7 +620,6 @@ class TwitterapiAction extends Action
} }
} }
$this->elementEnd('channel');
$this->end_twitter_rss(); $this->end_twitter_rss();
} }
@ -668,7 +666,6 @@ class TwitterapiAction extends Action
$this->init_document('rss'); $this->init_document('rss');
$this->elementStart('channel');
$this->element('title', null, $title); $this->element('title', null, $title);
$this->element('link', null, $link); $this->element('link', null, $link);
$this->element('description', null, $subtitle); $this->element('description', null, $subtitle);
@ -687,7 +684,6 @@ class TwitterapiAction extends Action
} }
} }
$this->elementEnd('channel');
$this->end_twitter_rss(); $this->end_twitter_rss();
} }
@ -792,6 +788,52 @@ class TwitterapiAction extends Action
$this->end_document('xml'); $this->end_document('xml');
} }
function show_twitter_xml_users($user)
{
$this->init_document('xml');
$this->elementStart('users', array('type' => 'array'));
if (is_array($user)) {
foreach ($group as $g) {
$twitter_user = $this->twitter_user_array($g);
$this->show_twitter_xml_user($twitter_user,'user');
}
} else {
while ($user->fetch()) {
$twitter_user = $this->twitter_user_array($user);
$this->show_twitter_xml_user($twitter_user);
}
}
$this->elementEnd('users');
$this->end_document('xml');
}
function show_json_users($user)
{
$this->init_document('json');
$users = array();
if (is_array($user)) {
foreach ($user as $u) {
$twitter_user = $this->twitter_user_array($u);
array_push($users, $twitter_user);
}
} else {
while ($user->fetch()) {
$twitter_user = $this->twitter_user_array($user);
array_push($users, $twitter_user);
}
}
$this->show_json_objects($users);
$this->end_document('json');
}
function show_single_json_group($group) function show_single_json_group($group)
{ {
$this->init_document('json'); $this->init_document('json');
@ -944,11 +986,14 @@ class TwitterapiAction extends Action
function init_twitter_rss() function init_twitter_rss()
{ {
$this->startXML(); $this->startXML();
$this->elementStart('rss', array('version' => '2.0')); $this->elementStart('rss', array('version' => '2.0', 'xmlns:atom'=>'http://www.w3.org/2005/Atom'));
$this->elementStart('channel');
Event::handle('StartApiRss', array($this));
} }
function end_twitter_rss() function end_twitter_rss()
{ {
$this->elementEnd('channel');
$this->elementEnd('rss'); $this->elementEnd('rss');
$this->endXML(); $this->endXML();
} }
@ -960,6 +1005,7 @@ class TwitterapiAction extends Action
$this->elementStart('feed', array('xmlns' => 'http://www.w3.org/2005/Atom', $this->elementStart('feed', array('xmlns' => 'http://www.w3.org/2005/Atom',
'xml:lang' => 'en-US', 'xml:lang' => 'en-US',
'xmlns:thr' => 'http://purl.org/syndication/thread/1.0')); 'xmlns:thr' => 'http://purl.org/syndication/thread/1.0'));
Event::handle('StartApiAtom', array($this));
} }
function end_twitter_atom() function end_twitter_atom()

View File

@ -0,0 +1,236 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Class for doing OAuth calls 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 Integration
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
/**
* Exception wrapper for cURL errors
*
* @category Integration
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*
*/
class BasicAuthCurlException extends Exception
{
}
/**
* Class for talking to the Twitter API with HTTP Basic Auth.
*
* @category Integration
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*
*/
class TwitterBasicAuthClient
{
var $screen_name = null;
var $password = null;
/**
* constructor
*
* @param Foreign_link $flink a Foreign_link storing the
* Twitter user's password, etc.
*/
function __construct($flink)
{
$fuser = $flink->getForeignUser();
$this->screen_name = $fuser->nickname;
$this->password = $flink->credentials;
}
/**
* Calls Twitter's /statuses/update API method
*
* @param string $status text of the status
* @param int $in_reply_to_status_id optional id of the status it's
* a reply to
*
* @return mixed the status
*/
function statusesUpdate($status, $in_reply_to_status_id = null)
{
$url = 'https://twitter.com/statuses/update.json';
$params = array('status' => $status,
'source' => common_config('integration', 'source'),
'in_reply_to_status_id' => $in_reply_to_status_id);
$response = $this->httpRequest($url, $params);
$status = json_decode($response);
return $status;
}
/**
* Calls Twitter's /statuses/friends_timeline API method
*
* @param int $since_id show statuses after this id
* @param int $max_id show statuses before this id
* @param int $cnt number of statuses to show
* @param int $page page number
*
* @return mixed an array of statuses
*/
function statusesFriendsTimeline($since_id = null, $max_id = null,
$cnt = null, $page = null)
{
$url = 'https://twitter.com/statuses/friends_timeline.json';
$params = array('since_id' => $since_id,
'max_id' => $max_id,
'count' => $cnt,
'page' => $page);
$qry = http_build_query($params);
if (!empty($qry)) {
$url .= "?$qry";
}
$response = $this->httpRequest($url);
$statuses = json_decode($response);
return $statuses;
}
/**
* Calls Twitter's /statuses/friends API method
*
* @param int $id id of the user whom you wish to see friends of
* @param int $user_id numerical user id
* @param int $screen_name screen name
* @param int $page page number
*
* @return mixed an array of twitter users and their latest status
*/
function statusesFriends($id = null, $user_id = null, $screen_name = null,
$page = null)
{
$url = "https://twitter.com/statuses/friends.json";
$params = array('id' => $id,
'user_id' => $user_id,
'screen_name' => $screen_name,
'page' => $page);
$qry = http_build_query($params);
if (!empty($qry)) {
$url .= "?$qry";
}
$response = $this->httpRequest($url);
$friends = json_decode($response);
return $friends;
}
/**
* Calls Twitter's /statuses/friends/ids API method
*
* @param int $id id of the user whom you wish to see friends of
* @param int $user_id numerical user id
* @param int $screen_name screen name
* @param int $page page number
*
* @return mixed a list of ids, 100 per page
*/
function friendsIds($id = null, $user_id = null, $screen_name = null,
$page = null)
{
$url = "https://twitter.com/friends/ids.json";
$params = array('id' => $id,
'user_id' => $user_id,
'screen_name' => $screen_name,
'page' => $page);
$qry = http_build_query($params);
if (!empty($qry)) {
$url .= "?$qry";
}
$response = $this->httpRequest($url);
$ids = json_decode($response);
return $ids;
}
/**
* Make a HTTP request using cURL.
*
* @param string $url Where to make the request
* @param array $params post parameters
*
* @return mixed the request
*/
function httpRequest($url, $params = null, $auth = true)
{
$options = array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FAILONERROR => true,
CURLOPT_HEADER => false,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_USERAGENT => 'StatusNet',
CURLOPT_CONNECTTIMEOUT => 120,
CURLOPT_TIMEOUT => 120,
CURLOPT_HTTPAUTH => CURLAUTH_ANY,
CURLOPT_SSL_VERIFYPEER => false,
// Twitter is strict about accepting invalid "Expect" headers
CURLOPT_HTTPHEADER => array('Expect:')
);
if (isset($params)) {
$options[CURLOPT_POST] = true;
$options[CURLOPT_POSTFIELDS] = $params;
}
if ($auth) {
$options[CURLOPT_USERPWD] = $this->screen_name .
':' . $this->password;
}
$ch = curl_init($url);
curl_setopt_array($ch, $options);
$response = curl_exec($ch);
if ($response === false) {
$msg = curl_error($ch);
$code = curl_errno($ch);
throw new BasicAuthCurlException($msg, $code);
}
curl_close($ch);
return $response;
}
}

View File

@ -22,7 +22,7 @@
* @category Integration * @category Integration
* @package StatusNet * @package StatusNet
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2008 StatusNet, Inc. * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
@ -81,6 +81,15 @@ class TwitterOAuthClient extends OAuthClient
return new OAuthToken($vals[0], $vals[1]); return new OAuthToken($vals[0], $vals[1]);
} }
static function isPackedToken($str)
{
if (strpos($str, chr(0)) === false) {
return false;
} else {
return true;
}
}
/** /**
* Builds a link to Twitter's endpoint for authorizing a request token * Builds a link to Twitter's endpoint for authorizing a request token
* *
@ -109,7 +118,7 @@ class TwitterOAuthClient extends OAuthClient
} }
/** /**
* Calls Twitter's /stutuses/update API method * Calls Twitter's /statuses/update API method
* *
* @param string $status text of the status * @param string $status text of the status
* @param int $in_reply_to_status_id optional id of the status it's * @param int $in_reply_to_status_id optional id of the status it's
@ -128,7 +137,7 @@ class TwitterOAuthClient extends OAuthClient
} }
/** /**
* Calls Twitter's /stutuses/friends_timeline API method * Calls Twitter's /statuses/friends_timeline API method
* *
* @param int $since_id show statuses after this id * @param int $since_id show statuses after this id
* @param int $max_id show statuses before this id * @param int $max_id show statuses before this id
@ -158,7 +167,7 @@ class TwitterOAuthClient extends OAuthClient
} }
/** /**
* Calls Twitter's /stutuses/friends API method * Calls Twitter's /statuses/friends API method
* *
* @param int $id id of the user whom you wish to see friends of * @param int $id id of the user whom you wish to see friends of
* @param int $user_id numerical user id * @param int $user_id numerical user id
@ -188,7 +197,7 @@ class TwitterOAuthClient extends OAuthClient
} }
/** /**
* Calls Twitter's /stutuses/friends/ids API method * Calls Twitter's /statuses/friends/ids API method
* *
* @param int $id id of the user whom you wish to see friends of * @param int $id id of the user whom you wish to see friends of
* @param int $user_id numerical user id * @param int $user_id numerical user id

View File

@ -59,7 +59,7 @@ function common_init_language()
textdomain("statusnet"); textdomain("statusnet");
setlocale(LC_CTYPE, 'C'); setlocale(LC_CTYPE, 'C');
if(!$locale_set) { if(!$locale_set) {
common_log(LOG_INFO,'Language requested:'.$language.' - locale could not be set:',__FILE__); common_log(LOG_INFO, 'Language requested:' . $language . ' - locale could not be set. Perhaps that system locale is not installed.', __FILE__);
} }
} }
@ -413,7 +413,7 @@ function common_replace_urls_callback($text, $callback, $notice_id = null) {
// Start off with a regex // Start off with a regex
$regex = '#'. $regex = '#'.
'(?:^|[\s\(\)\[\]\{\}\\\'\\\";]+)(?![\@\!\#])'. '(?:^|[\s\(\)\[\]\{\}\\\'\\\";]+)(?![\@\!\#])'.
'(?P<url>'. '('.
'(?:'. '(?:'.
'(?:'. //Known protocols '(?:'. //Known protocols
'(?:'. '(?:'.
@ -421,7 +421,7 @@ function common_replace_urls_callback($text, $callback, $notice_id = null) {
'|'. '|'.
'(?:(?:mailto|aim|tel|xmpp):)'. '(?:(?:mailto|aim|tel|xmpp):)'.
')'. ')'.
'(?:[\pN\pL\-\_\+]+(?::[\pN\pL\-\_\+]+)?\@)?'. //user:pass@ '(?:[\pN\pL\-\_\+\%\~]+(?::[\pN\pL\-\_\+\%\~]+)?\@)?'. //user:pass@
'(?:'. '(?:'.
'(?:'. '(?:'.
'\[[\pN\pL\-\_\:\.]+(?<![\.\:])\]'. //[dns] '\[[\pN\pL\-\_\:\.]+(?<![\.\:])\]'. //[dns]
@ -432,9 +432,9 @@ function common_replace_urls_callback($text, $callback, $notice_id = null) {
')'. ')'.
'|(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'. //IPv4 '|(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'. //IPv4
'|(?:'. //IPv6 '|(?:'. //IPv6
'\[?(?:(?:(?:[0-9A-Fa-f]{1,4}:){7}(?:(?:[0-9A-Fa-f]{1,4})|:))|(?:(?:[0-9A-Fa-f]{1,4}:){6}(?::|(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})|(?::[0-9A-Fa-f]{1,4})))|(?:(?:[0-9A-Fa-f]{1,4}:){5}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){4}(?::[0-9A-Fa-f]{1,4}){0,1}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){3}(?::[0-9A-Fa-f]{1,4}){0,2}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){2}(?::[0-9A-Fa-f]{1,4}){0,3}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:)(?::[0-9A-Fa-f]{1,4}){0,4}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?::(?::[0-9A-Fa-f]{1,4}){0,5}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})))\]?'. '\[?(?:(?:(?:[0-9A-Fa-f]{1,4}:){7}(?:(?:[0-9A-Fa-f]{1,4})|:))|(?:(?:[0-9A-Fa-f]{1,4}:){6}(?::|(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})|(?::[0-9A-Fa-f]{1,4})))|(?:(?:[0-9A-Fa-f]{1,4}:){5}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){4}(?::[0-9A-Fa-f]{1,4}){0,1}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){3}(?::[0-9A-Fa-f]{1,4}){0,2}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){2}(?::[0-9A-Fa-f]{1,4}){0,3}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:)(?::[0-9A-Fa-f]{1,4}){0,4}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?::(?::[0-9A-Fa-f]{1,4}){0,5}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})))\]?(?<!:)'.
')|(?:'. //DNS ')|(?:'. //DNS
'(?:[\pN\pL\-\_\+]+(?:\:[\pN\pL\-\_\+]+)?\@)?'. //user:pass@ '(?:[\pN\pL\-\_\+\%\~]+(?:\:[\pN\pL\-\_\+\%\~]+)?\@)?'. //user:pass@
'[\pN\pL\-\_]+(?:\.[\pN\pL\-\_]+)*\.'. '[\pN\pL\-\_]+(?:\.[\pN\pL\-\_]+)*\.'.
//tld list from http://data.iana.org/TLD/tlds-alpha-by-domain.txt, also added local, loc, and onion //tld list from http://data.iana.org/TLD/tlds-alpha-by-domain.txt, also added local, loc, and onion
'(?:AC|AD|AE|AERO|AF|AG|AI|AL|AM|AN|AO|AQ|AR|ARPA|AS|ASIA|AT|AU|AW|AX|AZ|BA|BB|BD|BE|BF|BG|BH|BI|BIZ|BJ|BM|BN|BO|BR|BS|BT|BV|BW|BY|BZ|CA|CAT|CC|CD|CF|CG|CH|CI|CK|CL|CM|CN|CO|COM|COOP|CR|CU|CV|CX|CY|CZ|DE|DJ|DK|DM|DO|DZ|EC|EDU|EE|EG|ER|ES|ET|EU|FI|FJ|FK|FM|FO|FR|GA|GB|GD|GE|GF|GG|GH|GI|GL|GM|GN|GOV|GP|GQ|GR|GS|GT|GU|GW|GY|HK|HM|HN|HR|HT|HU|ID|IE|IL|IM|IN|INFO|INT|IO|IQ|IR|IS|IT|JE|JM|JO|JOBS|JP|KE|KG|KH|KI|KM|KN|KP|KR|KW|KY|KZ|LA|LB|LC|LI|LK|LR|LS|LT|LU|LV|LY|MA|MC|MD|ME|MG|MH|MIL|MK|ML|MM|MN|MO|MOBI|MP|MQ|MR|MS|MT|MU|MUSEUM|MV|MW|MX|MY|MZ|NA|NAME|NC|NE|NET|NF|NG|NI|NL|NO|NP|NR|NU|NZ|OM|ORG|PA|PE|PF|PG|PH|PK|PL|PM|PN|PR|PRO|PS|PT|PW|PY|QA|RE|RO|RS|RU|RW|SA|SB|SC|SD|SE|SG|SH|SI|SJ|SK|SL|SM|SN|SO|SR|ST|SU|SV|SY|SZ|TC|TD|TEL|TF|TG|TH|TJ|TK|TL|TM|TN|TO|TP|TR|TRAVEL|TT|TV|TW|TZ|UA|UG|UK|US|UY|UZ|VA|VC|VE|VG|VI|VN|VU|WF|WS|XN--0ZWM56D|测试|XN--11B5BS3A9AJ6G|परीक्षा|XN--80AKHBYKNJ4F|испытание|XN--9T4B11YI5A|테스트|XN--DEBA0AD|טעסט|XN--G6W251D|測試|XN--HGBK6AJ7F53BBA|آزمایشی|XN--HLCJ6AYA9ESC7A|பரிட்சை|XN--JXALPDLP|δοκιμή|XN--KGBECHTV|إختبار|XN--ZCKZAH|テスト|YE|YT|YU|ZA|ZM|ZW|local|loc|onion)'. '(?:AC|AD|AE|AERO|AF|AG|AI|AL|AM|AN|AO|AQ|AR|ARPA|AS|ASIA|AT|AU|AW|AX|AZ|BA|BB|BD|BE|BF|BG|BH|BI|BIZ|BJ|BM|BN|BO|BR|BS|BT|BV|BW|BY|BZ|CA|CAT|CC|CD|CF|CG|CH|CI|CK|CL|CM|CN|CO|COM|COOP|CR|CU|CV|CX|CY|CZ|DE|DJ|DK|DM|DO|DZ|EC|EDU|EE|EG|ER|ES|ET|EU|FI|FJ|FK|FM|FO|FR|GA|GB|GD|GE|GF|GG|GH|GI|GL|GM|GN|GOV|GP|GQ|GR|GS|GT|GU|GW|GY|HK|HM|HN|HR|HT|HU|ID|IE|IL|IM|IN|INFO|INT|IO|IQ|IR|IS|IT|JE|JM|JO|JOBS|JP|KE|KG|KH|KI|KM|KN|KP|KR|KW|KY|KZ|LA|LB|LC|LI|LK|LR|LS|LT|LU|LV|LY|MA|MC|MD|ME|MG|MH|MIL|MK|ML|MM|MN|MO|MOBI|MP|MQ|MR|MS|MT|MU|MUSEUM|MV|MW|MX|MY|MZ|NA|NAME|NC|NE|NET|NF|NG|NI|NL|NO|NP|NR|NU|NZ|OM|ORG|PA|PE|PF|PG|PH|PK|PL|PM|PN|PR|PRO|PS|PT|PW|PY|QA|RE|RO|RS|RU|RW|SA|SB|SC|SD|SE|SG|SH|SI|SJ|SK|SL|SM|SN|SO|SR|ST|SU|SV|SY|SZ|TC|TD|TEL|TF|TG|TH|TJ|TK|TL|TM|TN|TO|TP|TR|TRAVEL|TT|TV|TW|TZ|UA|UG|UK|US|UY|UZ|VA|VC|VE|VG|VI|VN|VU|WF|WS|XN--0ZWM56D|测试|XN--11B5BS3A9AJ6G|परीक्षा|XN--80AKHBYKNJ4F|испытание|XN--9T4B11YI5A|테스트|XN--DEBA0AD|טעסט|XN--G6W251D|測試|XN--HGBK6AJ7F53BBA|آزمایشی|XN--HLCJ6AYA9ESC7A|பரிட்சை|XN--JXALPDLP|δοκιμή|XN--KGBECHTV|إختبار|XN--ZCKZAH|テスト|YE|YT|YU|ZA|ZM|ZW|local|loc|onion)'.
@ -442,19 +442,19 @@ function common_replace_urls_callback($text, $callback, $notice_id = null) {
')'. ')'.
'(?:'. '(?:'.
'(?:\:\d+)?'. //:port '(?:\:\d+)?'. //:port
'(?:/[\pN\pL$\[\]\,\!\(\)\.\-\_\+\/\=\&\;]*)?'. // /path '(?:/[\pN\pL$\[\]\,\!\(\)\.\:\-\_\+\/\=\&\;\%\~\*\$\+\'\"]*)?'. // /path
'(?:\?[\pN\pL\$\[\]\,\!\(\)\.\-\_\+\/\=\&\;\/]*)?'. // ?query string '(?:\?[\pN\pL\$\[\]\,\!\(\)\.\:\-\_\+\/\=\&\;\%\~\*\$\+\'\"\/]*)?'. // ?query string
'(?:\#[\pN\pL$\[\]\,\!\(\)\.\-\_\+\/\=\&\;\/\?\#]*)?'. // #fragment '(?:\#[\pN\pL$\[\]\,\!\(\)\.\:\-\_\+\/\=\&\;\%\~\*\$\+\'\"\/\?\#]*)?'. // #fragment
')(?<![\?\.\,\#\,])'. ')(?<![\?\.\,\#\,])'.
')'. ')'.
'#ixu'; '#ixu';
preg_match_all($regex,$text,$matches); //preg_match_all($regex,$text,$matches);
//print_r($matches); //print_r($matches);
return preg_replace_callback($regex, curry(callback_helper,$callback,$notice_id) ,$text); return preg_replace_callback($regex, curry('callback_helper',$callback,$notice_id) ,$text);
} }
function callback_helper($matches, $callback, $notice_id) { function callback_helper($matches, $callback, $notice_id) {
$url=$matches['url']; $url=$matches[1];
$left = strpos($matches[0],$url); $left = strpos($matches[0],$url);
$right = $left+strlen($url); $right = $left+strlen($url);
@ -492,12 +492,10 @@ function callback_helper($matches, $callback, $notice_id) {
} }
}while($original_url!=$url); }while($original_url!=$url);
if(empty($notice_id)){ if(empty($notice_id)){
$result = call_user_func_array($callback,$url); $result = call_user_func_array($callback,$url);
}else{ }else{
$result = call_user_func_array($callback, array($url,$notice_id) ); $result = call_user_func_array($callback, array(array($url,$notice_id)) );
} }
return substr($matches[0],0,$left) . $result . substr($matches[0],$right); return substr($matches[0],0,$left) . $result . substr($matches[0],$right);
} }
@ -508,16 +506,13 @@ function curry($fn) {
array_shift($args); array_shift($args);
$id = uniqid('_partial'); $id = uniqid('_partial');
$GLOBALS[$id] = array($fn, $args); $GLOBALS[$id] = array($fn, $args);
return create_function( return create_function('',
'', '$args = func_get_args(); '.
' 'return call_user_func_array('.
$args = func_get_args(); '$GLOBALS["'.$id.'"][0],'.
return call_user_func_array( 'array_merge('.
$GLOBALS["'.$id.'"][0], '$args,'.
array_merge( '$GLOBALS["'.$id.'"][1]));');
$args,
$GLOBALS["'.$id.'"][1]));
');
} }
function common_linkify($url) { function common_linkify($url) {
@ -525,7 +520,7 @@ function common_linkify($url) {
// functions // functions
$url = htmlspecialchars_decode($url); $url = htmlspecialchars_decode($url);
if(strpos($url, '@')!==false && strpos($url, ':')===false){ if(strpos($url, '@') !== false && strpos($url, ':') === false) {
//url is an email address without the mailto: protocol //url is an email address without the mailto: protocol
return XMLStringer::estring('a', array('href' => "mailto:$url", 'rel' => 'external'), $url); return XMLStringer::estring('a', array('href' => "mailto:$url", 'rel' => 'external'), $url);
} }
@ -547,42 +542,30 @@ function common_linkify($url) {
$attachment_id = null; $attachment_id = null;
$has_thumb = false; $has_thumb = false;
// Check to see whether there's a filename associated with this URL. // Check to see whether this is a known "attachment" URL.
// If there is, it's an upload and qualifies as an attachment
$localfile = File::staticGet('url', $longurl); $f = File::staticGet('url', $longurl);
if (!empty($localfile)) { if (empty($f)) {
if (isset($localfile->filename)) { // XXX: this writes to the database. :<
$is_attachment = true; $f = File::processNew($longurl);
$attachment_id = $localfile->id;
}
} }
// if this URL is an attachment, then we set class='attachment' and id='attahcment-ID' if (!empty($f)) {
// where ID is the id of the attachment for the given URL. if (isset($f->filename)) {
// $is_attachment = true;
// we need a better test telling what can be shown as an attachment $attachment_id = $f->id;
// we're currently picking up oembeds only. } else { // if it has OEmbed info, it's an attachment, too
// I think the best option is another file_view table in the db $foe = File_oembed::staticGet('file_id', $f->id);
// and associated dbobject. if (!empty($foe)) {
$is_attachment = true;
$attachment_id = $f->id;
$query = "select file_oembed.file_id as file_id from file join file_oembed on file.id = file_oembed.file_id where file.url='$longurl'"; $thumb = File_thumbnail::staticGet('file_id', $f->id);
$file = new File; if (!empty($thumb)) {
$file->query($query); $has_thumb = true;
$file->fetch(); }
}
if (!empty($file->file_id)) {
$is_attachment = true;
$attachment_id = $file->file_id;
$query = "select file_thumbnail.file_id as file_id from file join file_thumbnail on file.id = file_thumbnail.file_id where file.url='$longurl'";
$file2 = new File;
$file2->query($query);
$file2->fetch();
if (!empty($file2)) {
$has_thumb = true;
} }
} }
@ -1390,58 +1373,19 @@ function common_shorten_url($long_url)
} else { } else {
$svc = $user->urlshorteningservice; $svc = $user->urlshorteningservice;
} }
global $_shorteners;
$curlh = curl_init(); if(! $_shorteners[$svc]){
curl_setopt($curlh, CURLOPT_CONNECTTIMEOUT, 20); // # seconds to wait //the user selected service doesn't exist, so default to ur1.ca
curl_setopt($curlh, CURLOPT_USERAGENT, 'StatusNet'); $svc = 'ur1.ca';
curl_setopt($curlh, CURLOPT_RETURNTRANSFER, true);
switch($svc) {
case 'ur1.ca':
require_once INSTALLDIR.'/lib/Shorturl_api.php';
$short_url_service = new LilUrl;
$short_url = $short_url_service->shorten($long_url);
break;
case '2tu.us':
$short_url_service = new TightUrl;
require_once INSTALLDIR.'/lib/Shorturl_api.php';
$short_url = $short_url_service->shorten($long_url);
break;
case 'ptiturl.com':
require_once INSTALLDIR.'/lib/Shorturl_api.php';
$short_url_service = new PtitUrl;
$short_url = $short_url_service->shorten($long_url);
break;
case 'bit.ly':
curl_setopt($curlh, CURLOPT_URL, 'http://bit.ly/api?method=shorten&long_url='.urlencode($long_url));
$short_url = current(json_decode(curl_exec($curlh))->results)->hashUrl;
break;
case 'is.gd':
curl_setopt($curlh, CURLOPT_URL, 'http://is.gd/api.php?longurl='.urlencode($long_url));
$short_url = curl_exec($curlh);
break;
case 'snipr.com':
curl_setopt($curlh, CURLOPT_URL, 'http://snipr.com/site/snip?r=simple&link='.urlencode($long_url));
$short_url = curl_exec($curlh);
break;
case 'metamark.net':
curl_setopt($curlh, CURLOPT_URL, 'http://metamark.net/api/rest/simple?long_url='.urlencode($long_url));
$short_url = curl_exec($curlh);
break;
case 'tinyurl.com':
curl_setopt($curlh, CURLOPT_URL, 'http://tinyurl.com/api-create.php?url='.urlencode($long_url));
$short_url = curl_exec($curlh);
break;
default:
$short_url = false;
} }
curl_close($curlh); $reflectionObj = new ReflectionClass($_shorteners[$svc]['callInfo'][0]);
$short_url_service = $reflectionObj->newInstanceArgs($_shorteners[$svc]['callInfo'][1]);
$short_url = $short_url_service->shorten($long_url);
if(substr($short_url,0,7)=='http://'){
$short_url = substr($short_url,7);
}
return $short_url; return $short_url;
} }

View File

@ -0,0 +1,64 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Plugin to push RSS/Atom updates to a PubSubHubBub hub
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Plugin
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @copyright 2009 Craig Andrews http://candrews.integralblue.com
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once(INSTALLDIR.'/lib/Shorturl_api.php');
class LilUrlPlugin extends Plugin
{
function __construct()
{
parent::__construct();
}
function onInitializePlugin(){
$this->registerUrlShortener(
'ur1.ca',
array('freeService'=>true),
array('LilUrl',array('http://ur1.ca/'))
);
}
}
class LilUrl extends ShortUrlApi
{
protected function shorten_imp($url) {
$data['longurl'] = $url;
$response = $this->http_post($data);
if (!$response) return $url;
$y = @simplexml_load_string($response);
if (!isset($y->body)) return $url;
$x = $y->body->p[0]->a->attributes();
if (isset($x['href'])) return $x['href'];
return $url;
}
}

View File

@ -75,6 +75,8 @@ class LinkbackPlugin extends Plugin
function linkbackUrl($url) function linkbackUrl($url)
{ {
common_log(LOG_DEBUG,"Attempting linkback for " . $url);
$orig = $url; $orig = $url;
$url = htmlspecialchars_decode($orig); $url = htmlspecialchars_decode($orig);
$scheme = parse_url($url, PHP_URL_SCHEME); $scheme = parse_url($url, PHP_URL_SCHEME);
@ -134,15 +136,20 @@ class LinkbackPlugin extends Plugin
"User-Agent: " . $this->userAgent(), "User-Agent: " . $this->userAgent(),
'content' => $request))); 'content' => $request)));
$file = file_get_contents($endpoint, false, $context); $file = file_get_contents($endpoint, false, $context);
$response = xmlrpc_decode($file); if (!$file) {
if (xmlrpc_is_fault($response)) {
common_log(LOG_WARNING, common_log(LOG_WARNING,
"Pingback request failed for '$url' ($endpoint)");
} else {
$response = xmlrpc_decode($file);
if (xmlrpc_is_fault($response)) {
common_log(LOG_WARNING,
"Pingback error for '$url' ($endpoint): ". "Pingback error for '$url' ($endpoint): ".
"$response[faultString] ($response[faultCode])"); "$response[faultString] ($response[faultCode])");
} else { } else {
common_log(LOG_INFO, common_log(LOG_INFO,
"Pingback success for '$url' ($endpoint): ". "Pingback success for '$url' ($endpoint): ".
"'$response'"); "'$response'");
}
} }
} }

View File

@ -84,6 +84,12 @@ class OpenidloginAction extends Action
} }
} }
function showScripts()
{
parent::showScripts();
$this->autofocus('openid_url');
}
function title() function title()
{ {
return _('OpenID Login'); return _('OpenID Login');

View File

@ -72,6 +72,12 @@ class OpenidsettingsAction extends AccountSettingsAction
' Manage your associated OpenIDs from here.'); ' Manage your associated OpenIDs from here.');
} }
function showScripts()
{
parent::showScripts();
$this->autofocus('openid_url');
}
/** /**
* Show the form for OpenID management * Show the form for OpenID management
* *

View File

@ -0,0 +1,62 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Plugin to push RSS/Atom updates to a PubSubHubBub hub
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Plugin
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @copyright 2009 Craig Andrews http://candrews.integralblue.com
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
class PtitUrlPlugin extends Plugin
{
function __construct()
{
parent::__construct();
}
function onInitializePlugin(){
$this->registerUrlShortener(
'ptiturl.com',
array(),
array('PtitUrl',array('http://ptiturl.com/?creer=oui&action=Reduire&url='))
);
}
}
class PtitUrl extends ShortUrlApi
{
protected function shorten_imp($url) {
$response = $this->http_get($url);
if (!$response) return $url;
$response = $this->tidy($response);
$y = @simplexml_load_string($response);
if (!isset($y->body)) return $url;
$xml = $y->body->center->table->tr->td->pre->a->attributes();
if (isset($xml['href'])) return $xml['href'];
return $url;
}
}

View File

@ -0,0 +1,122 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Plugin to push RSS/Atom updates to a PubSubHubBub hub
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Plugin
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @copyright 2009 Craig Andrews http://candrews.integralblue.com
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
define('DEFAULT_HUB','http://2pubsubhubbub.appspot.com');
require_once(INSTALLDIR.'/plugins/PubSubHubBub/publisher.php');
class PubSubHubBubPlugin extends Plugin
{
private $hub;
function __construct()
{
parent::__construct();
}
function onInitializePlugin(){
$this->hub = common_config('PubSubHubBub', 'hub');
if(empty($this->hub)){
$this->hub = DEFAULT_HUB;
}
}
function onStartApiAtom($action){
$action->element('link',array('rel'=>'hub','href'=>$this->hub),null);
}
function onStartApiRss($action){
$action->element('atom:link',array('rel'=>'hub','href'=>$this->hub),null);
}
function onEndNoticeSave($notice){
$publisher = new Publisher($this->hub);
$feeds = array();
//public timeline feeds
$feeds[]=common_local_url('api',array('apiaction' => 'statuses','method' => 'public_timeline.rss'));
$feeds[]=common_local_url('api',array('apiaction' => 'statuses','method' => 'public_timeline.atom'));
//author's own feeds
$user = User::staticGet('id',$notice->profile_id);
$feeds[]=common_local_url('api',array('apiaction' => 'statuses','method' => 'user_timeline','argument' => $user->nickname.'.rss'));
$feeds[]=common_local_url('api',array('apiaction' => 'statuses','method' => 'user_timeline','argument' => $user->nickname.'.atom'));
//tag feeds
$tag = new Notice_tag();
$tag->notice_id = $notice->id;
if ($tag->find()) {
while ($tag->fetch()) {
$feeds[]=common_local_url('api',array('apiaction' => 'tags','method' => 'timeline', 'argument'=>$tag->tag.'.atom'));
$feeds[]=common_local_url('api',array('apiaction' => 'tags','method' => 'timeline', 'argument'=>$tag->tag.'.rss'));
}
}
//group feeds
$group_inbox = new Group_inbox();
$group_inbox->notice_id = $notice->id;
if ($group_inbox->find()) {
while ($group_inbox->fetch()) {
$group = User_group::staticGet('id',$group_inbox->group_id);
$feeds[]=common_local_url('api',array('apiaction' => 'groups','method' => 'timeline','argument' => $group->nickname.'.rss'));
$feeds[]=common_local_url('api',array('apiaction' => 'groups','method' => 'timeline','argument' => $group->nickname.'.atom'));
}
}
//feed of each user that subscribes to the notice's author
$notice_inbox = new Notice_inbox();
$notice_inbox->notice_id = $notice->id;
if ($notice_inbox->find()) {
while ($notice_inbox->fetch()) {
$user = User::staticGet('id',$notice_inbox->user_id);
$feeds[]=common_local_url('api',array('apiaction' => 'statuses','method' => 'user_timeline','argument' => $user->nickname.'.rss'));
$feeds[]=common_local_url('api',array('apiaction' => 'statuses','method' => 'user_timeline','argument' => $user->nickname.'.atom'));
}
}
/* TODO: when the reply page gets RSS and ATOM feeds, implement this
//feed of user replied to
if($notice->reply_to){
$user = User::staticGet('id',$notice->reply_to);
$feeds[]=common_local_url('api',array('apiaction' => 'statuses','method' => 'user_timeline','argument' => $user->nickname.'.rss'));
$feeds[]=common_local_url('api',array('apiaction' => 'statuses','method' => 'user_timeline','argument' => $user->nickname.'.atom'));
}*/
foreach(array_unique($feeds) as $feed){
if(! $publisher->publish_update($feed)){
common_log_line(LOG_WARNING,$feed.' was not published to hub at '.$this->hub.':'.$publisher->last_response());
}
}
}
}

View File

@ -0,0 +1,86 @@
<?php
// a PHP client library for pubsubhubbub
// as defined at http://code.google.com/p/pubsubhubbub/
// written by Josh Fraser | joshfraser.com | josh@eventvue.com
// Released under Apache License 2.0
class Publisher {
protected $hub_url;
protected $last_response;
// create a new Publisher
public function __construct($hub_url) {
if (!isset($hub_url))
throw new Exception('Please specify a hub url');
if (!preg_match("|^https?://|i",$hub_url))
throw new Exception('The specified hub url does not appear to be valid: '.$hub_url);
$this->hub_url = $hub_url;
}
// accepts either a single url or an array of urls
public function publish_update($topic_urls, $http_function = false) {
if (!isset($topic_urls))
throw new Exception('Please specify a topic url');
// check that we're working with an array
if (!is_array($topic_urls)) {
$topic_urls = array($topic_urls);
}
// set the mode to publish
$post_string = "hub.mode=publish";
// loop through each topic url
foreach ($topic_urls as $topic_url) {
// lightweight check that we're actually working w/ a valid url
if (!preg_match("|^https?://|i",$topic_url))
throw new Exception('The specified topic url does not appear to be valid: '.$topic_url);
// append the topic url parameters
$post_string .= "&hub.url=".urlencode($topic_url);
}
// make the http post request and return true/false
// easy to over-write to use your own http function
if ($http_function)
return $http_function($this->hub_url,$post_string);
else
return $this->http_post($this->hub_url,$post_string);
}
// returns any error message from the latest request
public function last_response() {
return $this->last_response;
}
// default http function that uses curl to post to the hub endpoint
private function http_post($url, $post_string) {
// add any additional curl options here
$options = array(CURLOPT_URL => $url,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $post_string,
CURLOPT_USERAGENT => "PubSubHubbub-Publisher-PHP/1.0");
$ch = curl_init();
curl_setopt_array($ch, $options);
$response = curl_exec($ch);
$this->last_response = $response;
$info = curl_getinfo($ch);
curl_close($ch);
// all good
if ($info['http_code'] == 204)
return true;
return false;
}
}
?>

View File

@ -0,0 +1,79 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Plugin to push RSS/Atom updates to a PubSubHubBub hub
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Plugin
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @copyright 2009 Craig Andrews http://candrews.integralblue.com
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
class SimpleUrlPlugin extends Plugin
{
function __construct()
{
parent::__construct();
}
function onInitializePlugin(){
$this->registerUrlShortener(
'is.gd',
array(),
array('SimpleUrl',array('http://is.gd/api.php?longurl='))
);
$this->registerUrlShortener(
'snipr.com',
array(),
array('SimpleUrl',array('http://snipr.com/site/snip?r=simple&link='))
);
$this->registerUrlShortener(
'metamark.net',
array(),
array('SimpleUrl',array('http://metamark.net/api/rest/simple?long_url='))
);
$this->registerUrlShortener(
'tinyurl.com',
array(),
array('SimpleUrl',array('http://tinyurl.com/api-create.php?url='))
);
}
}
class SimpleUrl extends ShortUrlApi
{
protected function shorten_imp($url) {
$curlh = curl_init();
curl_setopt($curlh, CURLOPT_CONNECTTIMEOUT, 20); // # seconds to wait
curl_setopt($curlh, CURLOPT_USERAGENT, 'StatusNet');
curl_setopt($curlh, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curlh, CURLOPT_URL, $this->service_url.urlencode($url));
$short_url = curl_exec($curlh);
curl_close($curlh);
return $short_url;
}
}

View File

@ -0,0 +1,62 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Plugin to push RSS/Atom updates to a PubSubHubBub hub
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Plugin
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @copyright 2009 Craig Andrews http://candrews.integralblue.com
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
class TightUrlPlugin extends Plugin
{
function __construct()
{
parent::__construct();
}
function onInitializePlugin(){
$this->registerUrlShortener(
'2tu.us',
array('freeService'=>true),
array('TightUrl',array('http://2tu.us/?save=y&url='))
);
}
}
class TightUrl extends ShortUrlApi
{
protected function shorten_imp($url) {
$response = $this->http_get($url);
if (!$response) return $url;
$response = $this->tidy($response);
$y = @simplexml_load_string($response);
if (!isset($y->body)) return $url;
$xml = $y->body->p[0]->code[0]->a->attributes();
if (isset($xml['href'])) return $xml['href'];
return $url;
}
}

View File

@ -142,13 +142,20 @@ class SyncTwitterFriendsDaemon extends ParallelizingDaemon
{ {
$friends = array(); $friends = array();
$token = TwitterOAuthClient::unpackToken($flink->credentials); $client = null;
$client = new TwitterOAuthClient($token->key, $token->secret); if (TwitterOAuthClient::isPackedToken($flink->credentials)) {
$token = TwitterOAuthClient::unpackToken($flink->credentials);
$client = new TwitterOAuthClient($token->key, $token->secret);
common_debug($this->name() . '- Grabbing friends IDs with OAuth.');
} else {
$client = new TwitterBasicAuthClient($flink);
common_debug($this->name() . '- Grabbing friends IDs with basic auth.');
}
try { try {
$friends_ids = $client->friendsIds(); $friends_ids = $client->friendsIds();
} catch (OAuthCurlException $e) { } catch (Exception $e) {
common_log(LOG_WARNING, $this->name() . common_log(LOG_WARNING, $this->name() .
' - cURL error getting friend ids ' . ' - cURL error getting friend ids ' .
$e->getCode() . ' - ' . $e->getMessage()); $e->getCode() . ' - ' . $e->getMessage());
@ -177,7 +184,7 @@ class SyncTwitterFriendsDaemon extends ParallelizingDaemon
try { try {
$more_friends = $client->statusesFriends(null, null, null, $i); $more_friends = $client->statusesFriends(null, null, null, $i);
} catch (OAuthCurlException $e) { } catch (Exception $e) {
common_log(LOG_WARNING, $this->name() . common_log(LOG_WARNING, $this->name() .
' - cURL error getting Twitter statuses/friends ' . ' - cURL error getting Twitter statuses/friends ' .
"page $i - " . $e->getCode() . ' - ' . "page $i - " . $e->getCode() . ' - ' .

View File

@ -148,9 +148,9 @@ class TwitterStatusFetcher extends ParallelizingDaemon
function getTimeline($flink) function getTimeline($flink)
{ {
if (empty($flink)) { if (empty($flink)) {
common_log(LOG_WARNING, $this->name() . common_log(LOG_WARNING, $this->name() .
" - Can't retrieve Foreign_link for foreign ID $fid"); " - Can't retrieve Foreign_link for foreign ID $fid");
return; return;
} }
@ -161,17 +161,24 @@ class TwitterStatusFetcher extends ParallelizingDaemon
// to start importing? How many statuses? Right now I'm going // to start importing? How many statuses? Right now I'm going
// with the default last 20. // with the default last 20.
$token = TwitterOAuthClient::unpackToken($flink->credentials); $client = null;
$client = new TwitterOAuthClient($token->key, $token->secret); if (TwitterOAuthClient::isPackedToken($flink->credentials)) {
$token = TwitterOAuthClient::unpackToken($flink->credentials);
$client = new TwitterOAuthClient($token->key, $token->secret);
common_debug($this->name() . ' - Grabbing friends timeline with OAuth.');
} else {
$client = new TwitterBasicAuthClient($flink);
common_debug($this->name() . ' - Grabbing friends timeline with basic auth.');
}
$timeline = null; $timeline = null;
try { try {
$timeline = $client->statusesFriendsTimeline(); $timeline = $client->statusesFriendsTimeline();
} catch (OAuthClientCurlException $e) { } catch (Exception $e) {
common_log(LOG_WARNING, $this->name() . common_log(LOG_WARNING, $this->name() .
' - OAuth client unable to get friends timeline for user ' . ' - Twitter client unable to get friends timeline for user ' .
$flink->user_id . ' - code: ' . $flink->user_id . ' - code: ' .
$e->getCode() . 'msg: ' . $e->getMessage()); $e->getCode() . 'msg: ' . $e->getMessage());
} }

View File

@ -25,14 +25,36 @@ class URLDetectionTest extends PHPUnit_Framework_TestCase
static public function provider() static public function provider()
{ {
return array( return array(
array('not a link :: no way',
'not a link :: no way'),
array('http://127.0.0.1', array('http://127.0.0.1',
'<a href="http://127.0.0.1/" rel="external">http://127.0.0.1</a>'), '<a href="http://127.0.0.1/" rel="external">http://127.0.0.1</a>'),
array('127.0.0.1', array('127.0.0.1',
'<a href="http://127.0.0.1/" rel="external">127.0.0.1</a>'), '<a href="http://127.0.0.1/" rel="external">127.0.0.1</a>'),
array('127.0.0.1:99', array('127.0.0.1:99',
'<a href="http://127.0.0.1:99/" rel="external">127.0.0.1:99</a>'), '<a href="http://127.0.0.1:99/" rel="external">127.0.0.1:99</a>'),
array('127.0.0.1/test.php', array('127.0.0.1/Name:test.php',
'<a href="http://127.0.0.1/test.php" rel="external">127.0.0.1/test.php</a>'), '<a href="http://127.0.0.1/Name:test.php" rel="external">127.0.0.1/Name:test.php</a>'),
array('127.0.0.1/~test',
'<a href="http://127.0.0.1/~test" rel="external">127.0.0.1/~test</a>'),
array('127.0.0.1/+test',
'<a href="http://127.0.0.1/+test" rel="external">127.0.0.1/+test</a>'),
array('127.0.0.1/$test',
'<a href="http://127.0.0.1/$test" rel="external">127.0.0.1/$test</a>'),
array('127.0.0.1/\'test',
'<a href="http://127.0.0.1/\'test" rel="external">127.0.0.1/\'test</a>'),
array('127.0.0.1/"test',
'<a href="http://127.0.0.1/&quot;test" rel="external">127.0.0.1/&quot;test</a>'),
array('127.0.0.1/-test',
'<a href="http://127.0.0.1/-test" rel="external">127.0.0.1/-test</a>'),
array('127.0.0.1/_test',
'<a href="http://127.0.0.1/_test" rel="external">127.0.0.1/_test</a>'),
array('127.0.0.1/!test',
'<a href="http://127.0.0.1/!test" rel="external">127.0.0.1/!test</a>'),
array('127.0.0.1/*test',
'<a href="http://127.0.0.1/*test" rel="external">127.0.0.1/*test</a>'),
array('127.0.0.1/test%20stuff',
'<a href="http://127.0.0.1/test%20stuff" rel="external">127.0.0.1/test%20stuff</a>'),
array('http://[::1]:99/test.php', array('http://[::1]:99/test.php',
'<a href="http://[::1]:99/test.php" rel="external">http://[::1]:99/test.php</a>'), '<a href="http://[::1]:99/test.php" rel="external">http://[::1]:99/test.php</a>'),
array('http://::1/test.php', array('http://::1/test.php',

View File

@ -156,7 +156,8 @@ font-weight:bold;
#form_notice_delete legend, #form_notice_delete legend,
#form_password_recover legend, #form_password_recover legend,
#form_password_change legend, #form_password_change legend,
.form_entity_block legend { .form_entity_block legend,
#form_filter_bytag legend {
display:none; display:none;
} }
@ -510,6 +511,7 @@ margin-top:7px;
margin-bottom:7px; margin-bottom:7px;
margin-left:18px; margin-left:18px;
float:left; float:left;
max-width:322px;
} }
#form_notice .error, #form_notice .error,
#form_notice .success { #form_notice .success {
@ -1049,36 +1051,37 @@ display:none;
#filter_tags ul { #filter_tags ul {
list-style-type:none; list-style-type:none;
} }
#filter_tags ul li { #filter_tags li {
float:left; float:left;
margin-left:7px; margin-left:7px;
padding-left:7px; padding-left:7px;
border-left-width:1px; border-left-width:1px;
border-left-style:solid; border-left-style:solid;
} }
#filter_tags ul li.child_1 { #filter_tags #filter_tags_all {
margin-left:0; margin-left:0;
border-left:0; border-left:0;
padding-left:0; padding-left:0;
} }
#filter_tags ul li#filter_tags_all a { #filter_tags_all a {
font-weight:bold; font-weight:bold;
margin-top:7px; margin-top:7px;
float:left; float:left;
} }
#filter_tags ul li#filter_tags_item label { #filter_tags_item label {
margin-right:7px; margin-right:7px;
} }
#filter_tags ul li#filter_tags_item label, #filter_tags_item label,
#filter_tags ul li#filter_tags_item select { #filter_tags_item select {
display:inline;
}
#filter_tags ul li#filter_tags_item p {
float:left; float:left;
}
#filter_tags_item p {
float:left;
clear:both;
margin-left:38px; margin-left:38px;
} }
#filter_tags ul li#filter_tags_item input { #filter_tags_item .submit {
position:relative; position:relative;
top:3px; top:3px;
left:3px; left:3px;

View File

@ -849,6 +849,10 @@ float:left;
font-size:1.025em; font-size:1.025em;
} }
.notice div.entry-content .timestamp {
display:inline-block;
}
.notice div.entry-content dl, .notice div.entry-content dl,
.notice div.entry-content dt, .notice div.entry-content dt,
.notice div.entry-content dd { .notice div.entry-content dd {
@ -866,15 +870,12 @@ display:inline-block;
text-transform:lowercase; text-transform:lowercase;
} }
.notice-options { .notice-options {
padding-left:2%;
float:left;
width:50%;
position:relative; position:relative;
font-size:0.95em; font-size:0.95em;
width:12.5%; width:90px;
float:right; float:right;
margin-right:11px;
} }
.notice-options a { .notice-options a {
@ -897,38 +898,28 @@ left:29px;
.notice-options .notice_delete { .notice-options .notice_delete {
right:0; right:0;
} }
.notice-options .notice_reply dt {
display:none;
}
.notice-options input, .notice-options input,
.notice-options a { .notice-options a {
text-indent:-9999px; text-indent:-9999px;
outline:none; outline:none;
} }
.notice-options .notice_reply a,
.notice-options input.submit { .notice-options input.submit {
display:block; display:block;
border:0; border:0;
} }
.notice-options .notice_reply a, .notice-options .notice_reply,
.notice-options .notice_delete a { .notice-options .notice_delete {
text-decoration:none; text-decoration:none;
padding-left:16px; padding-left:16px;
} }
.notice-options form input.submit { .notice-options form input.submit {
width:16px; width:16px;
padding:2px 0; padding:2px 0;
} }
.notice-options .notice_delete dt,
.notice-options .form_favor legend, .notice-options .form_favor legend,
.notice-options .form_disfavor legend { .notice-options .form_disfavor legend {
display:none; display:none;
} }
.notice-options .notice_delete fieldset,
.notice-options .form_favor fieldset, .notice-options .form_favor fieldset,
.notice-options .form_disfavor fieldset { .notice-options .form_disfavor fieldset {
border:0; border:0;

View File

@ -30,10 +30,10 @@ font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif;
} }
input, textarea, select, input, textarea, select,
.entity_remote_subscribe { .entity_remote_subscribe {
border-color:#aaa; border-color:#AAAAAA;
} }
#filter_tags ul li { #filter_tags ul li {
border-color:#ddd; border-color:#DDDDDD;
} }
.form_settings input.form_action-primary { .form_settings input.form_action-primary {
@ -50,11 +50,14 @@ background-color:#9BB43E;
input:focus, textarea:focus, select:focus, input:focus, textarea:focus, select:focus,
#form_notice.warning #notice_data-text { #form_notice.warning #notice_data-text {
border-color:#9BB43E; border-color:#9BB43E;
box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
-moz-box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
-webkit-box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
} }
input.submit, input.submit,
.entity_remote_subscribe, .entity_remote_subscribe,
#site_nav_local_views a { #site_nav_local_views a {
color:#fff; color:#FFFFFF;
} }
a, a,
@ -62,10 +65,13 @@ a,
div.notice-options input, div.notice-options input,
.form_user_block input.submit, .form_user_block input.submit,
.form_user_unblock input.submit, .form_user_unblock input.submit,
.form_group_block input.submit,
.form_group_unblock input.submit,
.entity_send-a-message a, .entity_send-a-message a,
.form_user_nudge input.submit, .form_user_nudge input.submit,
.entity_nudge p, .entity_nudge p,
.form_settings input.form_action-primary { .form_settings input.form_action-primary,
.form_make_admin input.submit {
color:#002E6E; color:#002E6E;
} }
@ -82,13 +88,6 @@ border-top-color:#CEE1E9;
border-top-color:#87B4C8; border-top-color:#87B4C8;
} }
#content .notice p.entry-content a:visited {
background-color:#fcfcfc;
}
#content .notice p.entry-content .vcard a {
background-color:#fcfffc;
}
.aside .section { .aside .section {
background-color:#F1F5F8; background-color:#F1F5F8;
background-position:100% 0; background-position:100% 0;
@ -97,10 +96,10 @@ background-repeat:no-repeat;
} }
#notice_text-count { #notice_text-count {
color:#333; color:#333333;
} }
#form_notice.warning #notice_text-count { #form_notice.warning #notice_text-count {
color:#000; color:#000000;
} }
#form_notice label[for=notice_data-attach] { #form_notice label[for=notice_data-attach] {
background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no-repeat 0 45%; background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no-repeat 0 45%;
@ -109,28 +108,43 @@ background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no
opacity:0; opacity:0;
} }
#form_notice.processing #notice_action-submit { #wrap form.processing input.submit {
background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%; background:#FFFFFF url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
cursor:wait; cursor:wait;
text-indent:-9999px; text-indent:-9999px;
outline:none;
} }
#content {
box-shadow:5px 7px 7px rgba(194, 194, 194, 0.3);
-moz-box-shadow:5px 7px 7px rgba(194, 194, 194, 0.3);
-webkit-box-shadow:5px 7px 7px rgba(194, 194, 194, 0.3);
}
#content, #content,
#site_nav_local_views a, #site_nav_local_views a,
.aside .section { .aside .section {
border-color:#fff; border-color:#FFFFFF;
} }
#content, #content,
#site_nav_local_views .current a { #site_nav_local_views .current a {
background-color:#fff; background-color:#FFFFFF;
} }
#site_nav_local_views li {
box-shadow:3px 7px 5px rgba(194, 194, 194, 0.5);
-moz-box-shadow:3px 7px 5px rgba(194, 194, 194, 0.5);
-webkit-box-shadow:3px 7px 5px rgba(194, 194, 194, 0.5);
}
#site_nav_local_views a { #site_nav_local_views a {
background-color:rgba(135, 180, 200, 0.3); background-color:rgba(194, 194, 194, 0.5);
} }
#site_nav_local_views a:hover { #site_nav_local_views a:hover {
background-color:rgba(255, 255, 255, 0.7); background-color:rgba(255, 255, 255, 0.7);
} }
#site_nav_local_views .current a {
text-shadow: rgba(194,194,194,0.5) 1px 1px 1px;
}
.error { .error {
background-color:#F7E8E8; background-color:#F7E8E8;
@ -140,10 +154,7 @@ background-color:#EFF3DC;
} }
#anon_notice { #anon_notice {
color:#fff; color:#FFFFFF;
}
#showstream #anon_notice {
} }
#export_data li a { #export_data li a {
@ -165,7 +176,10 @@ background-image:url(../../base/images/icons/icon_foaf.gif);
.form_user_nudge input.submit, .form_user_nudge input.submit,
.form_user_block input.submit, .form_user_block input.submit,
.form_user_unblock input.submit, .form_user_unblock input.submit,
.entity_nudge p { .form_group_block input.submit,
.form_group_unblock input.submit,
.entity_nudge p,
.form_make_admin input.submit {
background-position: 0 40%; background-position: 0 40%;
background-repeat: no-repeat; background-repeat: no-repeat;
background-color:transparent; background-color:transparent;
@ -175,7 +189,7 @@ background-color:transparent;
.form_user_subscribe input.submit, .form_user_subscribe input.submit,
.form_user_unsubscribe input.submit { .form_user_unsubscribe input.submit {
background-color:#9BB43E; background-color:#9BB43E;
color:#fff; color:#FFFFFF;
} }
.form_user_unsubscribe input.submit, .form_user_unsubscribe input.submit,
.form_group_leave input.submit, .form_group_leave input.submit,
@ -194,20 +208,23 @@ background-image:url(../../base/images/icons/twotone/green/quote.gif);
background-image:url(../../base/images/icons/twotone/green/mail.gif); background-image:url(../../base/images/icons/twotone/green/mail.gif);
} }
.form_user_block input.submit, .form_user_block input.submit,
.form_user_unblock input.submit { .form_user_unblock input.submit,
.form_group_block input.submit,
.form_group_unblock input.submit {
background-image:url(../../base/images/icons/twotone/green/shield.gif); background-image:url(../../base/images/icons/twotone/green/shield.gif);
} }
.form_make_admin input.submit {
background-image:url(../../base/images/icons/twotone/green/admin.gif);
}
/* NOTICES */ /* NOTICES */
.notices li.over { .notice .attachment {
background-color:#fcfcfc; background:transparent url(../../base/images/icons/twotone/green/clip-02.gif) no-repeat 0 45%;
} }
#attachments .attachment {
.notice-options .notice_reply a, background:none;
.notice-options form input.submit {
background-color:transparent;
} }
.notice-options .notice_reply a { .notice-options .notice_reply {
background:transparent url(../../base/images/icons/twotone/green/reply.gif) no-repeat 0 45%; background:transparent url(../../base/images/icons/twotone/green/reply.gif) no-repeat 0 45%;
} }
.notice-options form.form_favor input.submit { .notice-options form.form_favor input.submit {
@ -216,7 +233,7 @@ background:transparent url(../../base/images/icons/twotone/green/favourite.gif)
.notice-options form.form_disfavor input.submit { .notice-options form.form_disfavor input.submit {
background:transparent url(../../base/images/icons/twotone/green/disfavourite.gif) no-repeat 0 45%; background:transparent url(../../base/images/icons/twotone/green/disfavourite.gif) no-repeat 0 45%;
} }
.notice-options .notice_delete a { .notice-options .notice_delete {
background:transparent url(../../base/images/icons/twotone/green/trash.gif) no-repeat 0 45%; background:transparent url(../../base/images/icons/twotone/green/trash.gif) no-repeat 0 45%;
} }
@ -224,19 +241,32 @@ background:transparent url(../../base/images/icons/twotone/green/trash.gif) no-r
.notices div.notice-options { .notices div.notice-options {
opacity:0.4; opacity:0.4;
} }
.notices li.hover div.entry-content, .notices li:hover div.entry-content,
.notices li.hover div.notice-options { .notices li:hover div.notice-options {
opacity:1; opacity:1;
} }
div.entry-content {
color:#333;
}
div.notice-options a, div.notice-options a,
div.notice-options input { div.notice-options input {
font-family:sans-serif; font-family:sans-serif;
} }
.notices li.hover { #content .notices li:hover {
background-color:#fcfcfc; background-color:rgba(240, 240, 240, 0.2);
}
#conversation .notices li:hover {
background-color:transparent;
}
.notices .notices {
background-color:rgba(200, 200, 200, 0.050);
}
.notices .notices .notices {
background-color:rgba(200, 200, 200, 0.100);
}
.notices .notices .notices .notices {
background-color:rgba(200, 200, 200, 0.150);
}
.notices .notices .notices .notices .notices {
background-color:rgba(200, 200, 200, 0.300);
} }
/*END: NOTICES */ /*END: NOTICES */

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -94,10 +94,11 @@ background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no
opacity:0; opacity:0;
} }
#form_notice.processing #notice_action-submit { #wrap form.processing input.submit {
background:#FFFFFF url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%; background:#FFFFFF url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
cursor:wait; cursor:wait;
text-indent:-9999px; text-indent:-9999px;
outline:none;
} }
#content { #content {
@ -223,10 +224,6 @@ background:transparent url(../../base/images/icons/twotone/green/favourite.gif)
.notice-options form.form_disfavor input.submit { .notice-options form.form_disfavor input.submit {
background:transparent url(../../base/images/icons/twotone/green/disfavourite.gif) no-repeat 0 45%; background:transparent url(../../base/images/icons/twotone/green/disfavourite.gif) no-repeat 0 45%;
} }
.notice-options form.form_favor.processing input.submit,
.notice-options form.form_disfavor.processing input.submit {
background:transparent url(../../base/images/icons/icon_processing.gif) no-repeat 0 45%;
}
.notice-options .notice_delete { .notice-options .notice_delete {
background:transparent url(../../base/images/icons/twotone/green/trash.gif) no-repeat 0 45%; background:transparent url(../../base/images/icons/twotone/green/trash.gif) no-repeat 0 45%;
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -94,10 +94,11 @@ background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no
opacity:0; opacity:0;
} }
#form_notice.processing #notice_action-submit { #wrap form.processing input.submit {
background:#FFFFFF url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%; background:#FFFFFF url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
cursor:wait; cursor:wait;
text-indent:-9999px; text-indent:-9999px;
outline:none;
} }
#content { #content {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB