summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorEvan Prodromou <evan@status.net>2009-12-22 16:44:19 -0800
committerEvan Prodromou <evan@status.net>2009-12-22 16:44:19 -0800
commitf6bf9529805cd58fdd1671dd9b133bde05e8ae87 (patch)
treecf272bd1105da48f016b635db4d9c34810adcbda /lib
parentf987273f118a12d443b6789c2ab59d7a4b01f678 (diff)
parent30c2e2ce83282f0bc268153d7ec465fbb5cf00ca (diff)
Merge branch 'testing'
Diffstat (limited to 'lib')
-rw-r--r--lib/action.php32
-rw-r--r--lib/api.php63
-rw-r--r--lib/apiauth.php2
-rw-r--r--lib/command.php100
-rw-r--r--lib/commandinterpreter.php19
-rw-r--r--lib/common.php4
-rw-r--r--lib/curry.php36
-rw-r--r--lib/default.php5
-rw-r--r--lib/error.php2
-rw-r--r--lib/htmloutputter.php100
-rw-r--r--lib/language.php127
-rw-r--r--lib/messageform.php3
-rw-r--r--lib/noticeform.php3
-rw-r--r--lib/noticelist.php85
-rw-r--r--lib/oauthstore.php5
-rw-r--r--lib/plugin.php29
-rw-r--r--lib/profileformaction.php4
-rw-r--r--lib/repeatform.php145
-rw-r--r--lib/router.php30
-rw-r--r--lib/rssaction.php2
-rw-r--r--lib/schema.php18
-rw-r--r--lib/subs.php6
-rw-r--r--lib/util.php86
-rw-r--r--lib/xmloutputter.php5
24 files changed, 800 insertions, 111 deletions
diff --git a/lib/action.php b/lib/action.php
index 8ad391755..dac0e2583 100644
--- a/lib/action.php
+++ b/lib/action.php
@@ -68,7 +68,7 @@ class Action extends HTMLOutputter // lawsuit
* @see XMLOutputter::__construct
* @see HTMLOutputter::__construct
*/
- function __construct($output='php://output', $indent=true)
+ function __construct($output='php://output', $indent=null)
{
parent::__construct($output, $indent);
}
@@ -952,6 +952,36 @@ class Action extends HTMLOutputter // lawsuit
}
/**
+ * Integer value of an argument
+ *
+ * @param string $key query key we're interested in
+ * @param string $defValue optional default value (default null)
+ * @param string $maxValue optional max value (default null)
+ * @param string $minValue optional min value (default null)
+ *
+ * @return integer integer value
+ */
+
+ function int($key, $defValue=null, $maxValue=null, $minValue=null)
+ {
+ $arg = strtolower($this->trimmed($key));
+
+ if (is_null($arg) || !is_integer($arg)) {
+ return $defValue;
+ }
+
+ if (!is_null($maxValue)) {
+ $arg = min($arg, $maxValue);
+ }
+
+ if (!is_null($minValue)) {
+ $arg = max($arg, $minValue);
+ }
+
+ return $arg;
+ }
+
+ /**
* Server error
*
* @param string $msg error message to display
diff --git a/lib/api.php b/lib/api.php
index 5a3bb5ee4..4ed49e452 100644
--- a/lib/api.php
+++ b/lib/api.php
@@ -53,13 +53,14 @@ if (!defined('STATUSNET')) {
class ApiAction extends Action
{
- var $format = null;
- var $user = null;
- var $page = null;
- var $count = null;
- var $max_id = null;
- var $since_id = null;
- var $since = null;
+ var $format = null;
+ var $user = null;
+ var $auth_user = null;
+ var $page = null;
+ var $count = null;
+ var $max_id = null;
+ var $since_id = null;
+ var $since = null;
/**
* Initialization.
@@ -190,13 +191,14 @@ class ApiAction extends Action
$twitter_user['following'] = false;
$twitter_user['notifications'] = false;
- if (isset($apidata['user'])) {
+ if (isset($this->auth_user)) {
- $twitter_user['following'] = $apidata['user']->isSubscribed($profile);
+ $twitter_user['following'] = $this->auth_user->isSubscribed($profile);
// Notifications on?
$sub = Subscription::pkeyGet(array('subscriber' =>
- $apidata['user']->id, 'subscribed' => $profile->id));
+ $this->auth_user->id,
+ 'subscribed' => $profile->id));
if ($sub) {
$twitter_user['notifications'] = ($sub->jabber || $sub->sms);
@@ -216,6 +218,21 @@ class ApiAction extends Action
function twitterStatusArray($notice, $include_user=true)
{
+ $base = $this->twitterSimpleStatusArray($notice, $include_user);
+
+ if (!empty($notice->repeat_of)) {
+ $original = Notice::staticGet('id', $notice->repeat_of);
+ if (!empty($original)) {
+ $original_array = $this->twitterSimpleStatusArray($original, $include_user);
+ $base['retweeted_status'] = $original_array;
+ }
+ }
+
+ return $base;
+ }
+
+ function twitterSimpleStatusArray($notice, $include_user=true)
+ {
$profile = $notice->getProfile();
$twitter_status = array();
@@ -448,9 +465,9 @@ class ApiAction extends Action
}
}
- function showTwitterXmlStatus($twitter_status)
+ function showTwitterXmlStatus($twitter_status, $tag='status')
{
- $this->elementStart('status');
+ $this->elementStart($tag);
foreach($twitter_status as $element => $value) {
switch ($element) {
case 'user':
@@ -465,11 +482,14 @@ class ApiAction extends Action
case 'geo':
$this->showGeoRSS($value);
break;
+ case 'retweeted_status':
+ $this->showTwitterXmlStatus($value, 'retweeted_status');
+ break;
default:
$this->element($element, null, $value);
}
}
- $this->elementEnd('status');
+ $this->elementEnd($tag);
}
function showTwitterXmlGroup($twitter_group)
@@ -588,7 +608,7 @@ class ApiAction extends Action
$this->endDocument('xml');
}
- function showRssTimeline($notice, $title, $link, $subtitle, $suplink=null)
+ function showRssTimeline($notice, $title, $link, $subtitle, $suplink=null, $logo=null)
{
$this->initDocument('rss');
@@ -602,6 +622,15 @@ class ApiAction extends Action
'href' => $suplink,
'type' => 'application/json'));
}
+
+ if (!is_null($logo)) {
+ $this->elementStart('image');
+ $this->element('link', null, $link);
+ $this->element('title', null, $title);
+ $this->element('url', null, $logo);
+ $this->elementEnd('image');
+ }
+
$this->element('description', null, $subtitle);
$this->element('language', null, 'en-us');
$this->element('ttl', null, '40');
@@ -621,7 +650,7 @@ class ApiAction extends Action
$this->endTwitterRss();
}
- function showAtomTimeline($notice, $title, $id, $link, $subtitle=null, $suplink=null, $selfuri=null)
+ function showAtomTimeline($notice, $title, $id, $link, $subtitle=null, $suplink=null, $selfuri=null, $logo=null)
{
$this->initDocument('atom');
@@ -630,6 +659,10 @@ class ApiAction extends Action
$this->element('id', null, $id);
$this->element('link', array('href' => $link, 'rel' => 'alternate', 'type' => 'text/html'), null);
+ if (!is_null($logo)) {
+ $this->element('logo',null,$logo);
+ }
+
if (!is_null($suplink)) {
# For FriendFeed's SUP protocol
$this->element('link', array('rel' => 'http://api.friendfeed.com/2008/03#sup',
diff --git a/lib/apiauth.php b/lib/apiauth.php
index 0d1613d38..7102764cb 100644
--- a/lib/apiauth.php
+++ b/lib/apiauth.php
@@ -53,8 +53,6 @@ require_once INSTALLDIR . '/lib/api.php';
class ApiAuthAction extends ApiAction
{
- var $auth_user = null;
-
/**
* Take arguments for running, and output basic auth header if needed
*
diff --git a/lib/command.php b/lib/command.php
index bcc551c81..67140c348 100644
--- a/lib/command.php
+++ b/lib/command.php
@@ -372,6 +372,7 @@ class MessageCommand extends Command
}
$message = Message::saveNew($this->user->id, $other->id, $this->text, $channel->source());
if ($message) {
+ $message->notify();
$channel->output($this->user, sprintf(_('Direct message to %s sent'), $this->other));
} else {
$channel->error($this->user, _('Error sending direct message.'));
@@ -379,6 +380,65 @@ class MessageCommand extends Command
}
}
+class RepeatCommand extends Command
+{
+ var $other = null;
+ function __construct($user, $other)
+ {
+ parent::__construct($user);
+ $this->other = $other;
+ }
+
+ function execute($channel)
+ {
+ if(substr($this->other,0,1)=='#'){
+ //repeating a specific notice_id
+
+ $notice = Notice::staticGet(substr($this->other,1));
+ if (!$notice) {
+ $channel->error($this->user, _('Notice with that id does not exist'));
+ return;
+ }
+ $recipient = $notice->getProfile();
+ }else{
+ //repeating a given user's last notice
+
+ $recipient =
+ common_relative_profile($this->user, common_canonical_nickname($this->other));
+
+ if (!$recipient) {
+ $channel->error($this->user, _('No such user.'));
+ return;
+ }
+ $notice = $recipient->getCurrentNotice();
+ if (!$notice) {
+ $channel->error($this->user, _('User has no last notice'));
+ return;
+ }
+ }
+
+ if($this->user->id == $notice->profile_id)
+ {
+ $channel->error($this->user, _('Cannot repeat your own notice'));
+ return;
+ }
+
+ if ($recipient->hasRepeated($notice->id)) {
+ $channel->error($this->user, _('Already repeated that notice'));
+ return;
+ }
+
+ $repeat = $notice->repeat($this->user->id, $channel->source);
+
+ if ($repeat) {
+ common_broadcast_notice($repeat);
+ $channel->output($this->user, sprintf(_('Notice from %s repeated'), $recipient->nickname));
+ } else {
+ $channel->error($this->user, _('Error repeating notice.'));
+ }
+ }
+}
+
class ReplyCommand extends Command
{
var $other = null;
@@ -433,8 +493,9 @@ class ReplyCommand extends Command
return;
}
- $notice = Notice::saveNew($this->user->id, $this->text, $channel->source(), 1,
- $notice->id);
+ $notice = Notice::saveNew($this->user->id, $this->text, $channel->source(),
+ array('reply_to' => $notice->id));
+
if ($notice) {
$channel->output($this->user, sprintf(_('Reply to %s sent'), $recipient->nickname));
} else {
@@ -579,6 +640,38 @@ class OnCommand extends Command
}
}
+class LoginCommand extends Command
+{
+ function execute($channel)
+ {
+ $disabled = common_config('logincommand','disabled');
+ $disabled = isset($disabled) && $disabled;
+ if($disabled) {
+ $channel->error($this->user, _('Login command is disabled'));
+ return;
+ }
+ $login_token = Login_token::staticGet('user_id',$this->user->id);
+ if($login_token){
+ $login_token->delete();
+ }
+ $login_token = new Login_token();
+ $login_token->user_id = $this->user->id;
+ $login_token->token = common_good_rand(16);
+ $login_token->created = common_sql_now();
+ $result = $login_token->insert();
+ if (!$result) {
+ common_log_db_error($login_token, 'INSERT', __FILE__);
+ $channel->error($this->user, sprintf(_('Could not create login token for %s'),
+ $this->user->nickname));
+ return;
+ }
+ $channel->output($this->user,
+ sprintf(_('This link is useable only once, and is good for only 2 minutes: %s'),
+ common_local_url('login',
+ array('user_id'=>$login_token->user_id, 'token'=>$login_token->token))));
+ }
+}
+
class SubscriptionsCommand extends Command
{
function execute($channel)
@@ -663,9 +756,12 @@ class HelpCommand extends Command
"whois <nickname> - get profile info on user\n".
"fav <nickname> - add user's last notice as a 'fave'\n".
"fav #<notice_id> - add notice with the given id as a 'fave'\n".
+ "repeat #<notice_id> - repeat a notice with a given id\n".
+ "repeat <nickname> - repeat the last notice from user\n".
"reply #<notice_id> - reply to notice with a given id\n".
"reply <nickname> - reply to the last notice from user\n".
"join <group> - join group\n".
+ "login - Get a link to login to the web interface\n".
"drop <group> - leave group\n".
"stats - get your stats\n".
"stop - same as 'off'\n".
diff --git a/lib/commandinterpreter.php b/lib/commandinterpreter.php
index 25f2e4b3e..c2add7299 100644
--- a/lib/commandinterpreter.php
+++ b/lib/commandinterpreter.php
@@ -41,6 +41,12 @@ class CommandInterpreter
return null;
}
return new HelpCommand($user);
+ case 'login':
+ if ($arg) {
+ return null;
+ } else {
+ return new LoginCommand($user);
+ }
case 'subscribers':
if ($arg) {
return null;
@@ -163,6 +169,19 @@ class CommandInterpreter
} else {
return new ReplyCommand($user, $other, $extra);
}
+ case 'repeat':
+ case 'rp':
+ case 'rt':
+ case 'rd':
+ if (!$arg) {
+ return null;
+ }
+ list($other, $extra) = $this->split_arg($arg);
+ if ($extra) {
+ return null;
+ } else {
+ return new RepeatCommand($user, $other);
+ }
case 'whois':
if (!$arg) {
return null;
diff --git a/lib/common.php b/lib/common.php
index 9b3ded037..7fa1910af 100644
--- a/lib/common.php
+++ b/lib/common.php
@@ -20,9 +20,9 @@
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
//exit with 200 response, if this is checking fancy from the installer
-if (isset($_REQUEST['p']) && $_REQUEST['p'] == 'check-fancy') { exit; }
+if (isset($_REQUEST['p']) && $_REQUEST['p'] == 'check-fancy') { exit; }
-define('STATUSNET_VERSION', '0.9.0rc1');
+define('STATUSNET_VERSION', '0.9.0rc2');
define('LACONICA_VERSION', STATUSNET_VERSION); // compatibility
define('STATUSNET_CODENAME', 'Stand');
diff --git a/lib/curry.php b/lib/curry.php
new file mode 100644
index 000000000..6136dcdc3
--- /dev/null
+++ b/lib/curry.php
@@ -0,0 +1,36 @@
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * PHP 5.3 implementation of function currying, using native closures.
+ * On 5.2 and lower we use the fallback implementation in util.php
+ *
+ * @param callback $fn
+ * @param ... any remaining arguments will be appended to call-time params
+ * @return callback
+ */
+function curry($fn) {
+ $extra_args = func_get_args();
+ array_shift($extra_args);
+ return function() use ($fn, $extra_args) {
+ $args = func_get_args();
+ return call_user_func_array($fn,
+ array_merge($args, $extra_args));
+ };
+}
diff --git a/lib/default.php b/lib/default.php
index d4ef045ea..42d4623b1 100644
--- a/lib/default.php
+++ b/lib/default.php
@@ -53,6 +53,7 @@ $default =
'shorturllength' => 30,
'dupelimit' => 60, # default for same person saying the same thing
'textlimit' => 140,
+ 'indent' => true,
),
'db' =>
array('database' => 'YOU HAVE TO SET THIS IN config.php',
@@ -74,7 +75,7 @@ $default =
array('enabled' => false,
'subsystem' => 'db', # default to database, or 'stomp'
'stomp_server' => null,
- 'queue_basename' => 'statusnet',
+ 'queue_basename' => '/queue/statusnet/',
'stomp_username' => null,
'stomp_password' => null,
),
@@ -228,4 +229,6 @@ $default =
array('namespace' => 1), // 1 = geonames, 2 = Yahoo Where on Earth
'omb' =>
array('timeout' => 5), // HTTP request timeout in seconds when contacting remote hosts for OMB updates
+ 'logincommand' =>
+ array('disabled' => true),
);
diff --git a/lib/error.php b/lib/error.php
index 3162cfe65..87a4d913b 100644
--- a/lib/error.php
+++ b/lib/error.php
@@ -50,7 +50,7 @@ class ErrorAction extends Action
var $message = null;
var $default = null;
- function __construct($message, $code, $output='php://output', $indent=true)
+ function __construct($message, $code, $output='php://output', $indent=null)
{
parent::__construct($output, $indent);
diff --git a/lib/htmloutputter.php b/lib/htmloutputter.php
index d267526c8..2091c6e2c 100644
--- a/lib/htmloutputter.php
+++ b/lib/htmloutputter.php
@@ -67,7 +67,7 @@ class HTMLOutputter extends XMLOutputter
* @param boolean $indent Whether to indent output, default true
*/
- function __construct($output='php://output', $indent=true)
+ function __construct($output='php://output', $indent=null)
{
parent::__construct($output, $indent);
}
@@ -350,14 +350,43 @@ class HTMLOutputter extends XMLOutputter
*/
function script($src, $type='text/javascript')
{
- $url = parse_url($src);
- if( empty($url->scheme) && empty($url->host) && empty($url->query) && empty($url->fragment))
- {
- $src = common_path($src) . '?version=' . STATUSNET_VERSION;
+ if(Event::handle('StartScriptElement', array($this,&$src,&$type))) {
+ $url = parse_url($src);
+ if( empty($url->scheme) && empty($url->host) && empty($url->query) && empty($url->fragment))
+ {
+ $src = common_path($src) . '?version=' . STATUSNET_VERSION;
+ }
+ $this->element('script', array('type' => $type,
+ 'src' => $src),
+ ' ');
+ Event::handle('EndScriptElement', array($this,$src,$type));
+ }
+ }
+
+ /**
+ * output a script (almost always javascript) tag with inline
+ * code.
+ *
+ * @param string $code code to put in the script tag
+ * @param string $type 'type' attribute value of the tag
+ *
+ * @return void
+ */
+
+ function inlineScript($code, $type='text/javascript')
+ {
+ if(Event::handle('StartInlineScriptElement', array($this,&$code,&$type))) {
+ $this->elementStart('script', array('type' => $type));
+ if($type == 'text/javascript') {
+ $this->raw('/*<![CDATA[*/ '); // XHTML compat
+ }
+ $this->raw($code);
+ if($type == 'text/javascript') {
+ $this->raw(' /*]]>*/'); // XHTML compat
+ }
+ $this->elementEnd('script');
+ Event::handle('EndInlineScriptElement', array($this,$code,$type));
}
- $this->element('script', array('type' => $type,
- 'src' => $src),
- ' ');
}
/**
@@ -371,19 +400,44 @@ class HTMLOutputter extends XMLOutputter
*/
function cssLink($src,$theme=null,$media=null)
{
- $url = parse_url($src);
- if( empty($url->scheme) && empty($url->host) && empty($url->query) && empty($url->fragment))
- {
- if(file_exists(Theme::file($src,$theme))){
- $src = Theme::path($src, $theme) . '?version=' . STATUSNET_VERSION;
- }else{
- $src = common_path($src);
+ if(Event::handle('StartCssLinkElement', array($this,&$src,&$theme,&$media))) {
+ $url = parse_url($src);
+ if( empty($url->scheme) && empty($url->host) && empty($url->query) && empty($url->fragment))
+ {
+ if(file_exists(Theme::file($src,$theme))){
+ $src = Theme::path($src, $theme);
+ }else{
+ $src = common_path($src);
+ }
+ $src.= '?version=' . STATUSNET_VERSION;
}
+ $this->element('link', array('rel' => 'stylesheet',
+ 'type' => 'text/css',
+ 'href' => $src,
+ 'media' => $media));
+ Event::handle('EndCssLinkElement', array($this,$src,$theme,$media));
+ }
+ }
+
+ /**
+ * output a style (almost always css) tag with inline
+ * code.
+ *
+ * @param string $code code to put in the style tag
+ * @param string $type 'type' attribute value of the tag
+ * @param string $media 'media' attribute value of the tag
+ *
+ * @return void
+ */
+
+ function style($code, $type = 'text/css', $media = null)
+ {
+ if(Event::handle('StartStyleElement', array($this,&$code,&$type,&$media))) {
+ $this->elementStart('style', array('type' => $type, 'media' => $media));
+ $this->raw($code);
+ $this->elementEnd('style');
+ Event::handle('EndStyleElement', array($this,$code,$type,$media));
}
- $this->element('link', array('rel' => 'stylesheet',
- 'type' => 'text/css',
- 'href' => $src,
- 'media' => $media));
}
/**
@@ -414,7 +468,6 @@ class HTMLOutputter extends XMLOutputter
}
}
-
/**
* Internal script to autofocus the given element on page onload.
*
@@ -425,13 +478,10 @@ class HTMLOutputter extends XMLOutputter
*/
function autofocus($id)
{
- $this->elementStart('script', array('type' => 'text/javascript'));
- $this->raw('/*<![CDATA[*/'.
+ $this->inlineScript(
' $(document).ready(function() {'.
' var el = $("#' . $id . '");'.
' if (el.length) { el.focus(); }'.
- ' });'.
- ' /*]]>*/');
- $this->elementEnd('script');
+ ' });');
}
}
diff --git a/lib/language.php b/lib/language.php
index 4fc45bafe..d8f529201 100644
--- a/lib/language.php
+++ b/lib/language.php
@@ -36,6 +36,33 @@ if (!function_exists('gettext')) {
require_once("php-gettext/gettext.inc");
}
+
+if (!function_exists('dpgettext')) {
+ /**
+ * Context-aware dgettext wrapper; use when messages in different contexts
+ * won't be distinguished from the English source but need different translations.
+ * The context string will appear as msgctxt in the .po files.
+ *
+ * Not currently exposed in PHP's gettext module; implemented to be compat
+ * with gettext.h's macros.
+ *
+ * @param string $domain domain identifier, or null for default domain
+ * @param string $context context identifier, should be some key like "menu|file"
+ * @param string $msgid English source text
+ * @return string original or translated message
+ */
+ function dpgettext($domain, $context, $msg)
+ {
+ $msgid = $context . "\004" . $msg;
+ $out = dcgettext($domain, $msgid, LC_MESSAGES);
+ if ($out == $msgid) {
+ return $msg;
+ } else {
+ return $out;
+ }
+ }
+}
+
if (!function_exists('pgettext')) {
/**
* Context-aware gettext wrapper; use when messages in different contexts
@@ -51,8 +78,30 @@ if (!function_exists('pgettext')) {
*/
function pgettext($context, $msg)
{
+ return dpgettext(textdomain(NULL), $context, $msg);
+ }
+}
+
+if (!function_exists('dnpgettext')) {
+ /**
+ * Context-aware dngettext wrapper; use when messages in different contexts
+ * won't be distinguished from the English source but need different translations.
+ * The context string will appear as msgctxt in the .po files.
+ *
+ * Not currently exposed in PHP's gettext module; implemented to be compat
+ * with gettext.h's macros.
+ *
+ * @param string $domain domain identifier, or null for default domain
+ * @param string $context context identifier, should be some key like "menu|file"
+ * @param string $msg singular English source text
+ * @param string $plural plural English source text
+ * @param int $n number of items to control plural selection
+ * @return string original or translated message
+ */
+ function dnpgettext($domain, $context, $msg, $plural, $n)
+ {
$msgid = $context . "\004" . $msg;
- $out = dcgettext(textdomain(NULL), $msgid, LC_MESSAGES);
+ $out = dcngettext($domain, $msgid, $plural, $n, LC_MESSAGES);
if ($out == $msgid) {
return $msg;
} else {
@@ -78,14 +127,78 @@ if (!function_exists('npgettext')) {
*/
function npgettext($context, $msg, $plural, $n)
{
- $msgid = $context . "\004" . $msg;
- $out = dcngettext(textdomain(NULL), $msgid, $plural, $n, LC_MESSAGES);
- if ($out == $msgid) {
- return $msg;
+ return dnpgettext(textdomain(NULL), $msgid, $plural, $n, LC_MESSAGES);
+ }
+}
+
+/**
+ * Shortcut for *gettext functions with smart domain detection.
+ *
+ * If calling from a plugin, this function checks which plugin was
+ * being called from and uses that as text domain, which will have
+ * been set up during plugin initialization.
+ *
+ * Also handles plurals and contexts depending on what parameters
+ * are passed to it:
+ *
+ * gettext -> _m($msg)
+ * ngettext -> _m($msg1, $msg2, $n)
+ * pgettext -> _m($ctx, $msg)
+ * npgettext -> _m($ctx, $msg1, $msg2, $n)
+ *
+ * @fixme may not work properly in eval'd code
+ *
+ * @param string $msg
+ * @return string
+ */
+function _m($msg/*, ...*/)
+{
+ $domain = _mdomain(debug_backtrace());
+ $args = func_get_args();
+ switch(count($args)) {
+ case 1: return dgettext($domain, $msg);
+ case 2: return dpgettext($domain, $args[0], $args[1]);
+ case 3: return dngettext($domain, $args[0], $args[1], $args[2]);
+ case 4: return dnpgettext($domain, $args[0], $args[1], $args[2], $args[3]);
+ default: throw new Exception("Bad parameter count to _m()");
+ }
+}
+
+/**
+ * Looks for which plugin we've been called from to set the gettext domain.
+ *
+ * @param array $backtrace debug_backtrace() output
+ * @return string
+ * @private
+ * @fixme could explode if SN is under a 'plugins' folder or share name.
+ */
+function _mdomain($backtrace)
+{
+ /*
+ 0 =>
+ array
+ 'file' => string '/var/www/mublog/plugins/FeedSub/FeedSubPlugin.php' (length=49)
+ 'line' => int 77
+ 'function' => string '_m' (length=2)
+ 'args' =>
+ array
+ 0 => &string 'Feeds' (length=5)
+ */
+ static $cached;
+ $path = $backtrace[0]['file'];
+ if (!isset($cached[$path])) {
+ if (DIRECTORY_SEPARATOR !== '/') {
+ $path = strtr($path, DIRECTORY_SEPARATOR, '/');
+ }
+ $cut = strpos($path, '/plugins/') + 9;
+ $cut2 = strpos($path, '/', $cut);
+ if ($cut && $cut2) {
+ $cached[$path] = substr($path, $cut, $cut2 - $cut);
} else {
- return $out;
+ return null;
}
}
+ return $cached[$path];
}
@@ -159,6 +272,7 @@ function get_nice_language_list()
function get_all_languages() {
return array(
'ar' => array('q' => 0.8, 'lang' => 'ar', 'name' => 'Arabic', 'direction' => 'rtl'),
+ 'arz' => array('q' => 0.8, 'lang' => 'arz', 'name' => 'Egyptian Spoken Arabic', 'direction' => 'rtl'),
'bg' => array('q' => 0.8, 'lang' => 'bg', 'name' => 'Bulgarian', 'direction' => 'ltr'),
'ca' => array('q' => 0.5, 'lang' => 'ca', 'name' => 'Catalan', 'direction' => 'ltr'),
'cs' => array('q' => 0.5, 'lang' => 'cs', 'name' => 'Czech', 'direction' => 'ltr'),
@@ -173,6 +287,7 @@ function get_all_languages() {
'ga' => array('q' => 0.5, 'lang' => 'ga', 'name' => 'Galician', 'direction' => 'ltr'),
'he' => array('q' => 0.5, 'lang' => 'he', 'name' => 'Hebrew', 'direction' => 'rtl'),
'hsb' => array('q' => 0.8, 'lang' => 'hsb', 'name' => 'Upper Sorbian', 'direction' => 'ltr'),
+ 'ia' => array('q' => 0.8, 'lang' => 'ia', 'name' => 'Interlingua', 'direction' => 'ltr'),
'is' => array('q' => 0.1, 'lang' => 'is', 'name' => 'Icelandic', 'direction' => 'ltr'),
'it' => array('q' => 1, 'lang' => 'it', 'name' => 'Italian', 'direction' => 'ltr'),
'jp' => array('q' => 0.5, 'lang' => 'ja', 'name' => 'Japanese', 'direction' => 'ltr'),
diff --git a/lib/messageform.php b/lib/messageform.php
index b034be312..0c568e1bd 100644
--- a/lib/messageform.php
+++ b/lib/messageform.php
@@ -154,9 +154,6 @@ class MessageForm extends Form
$contentLimit = Message::maxContent();
- $this->out->element('script', array('type' => 'text/javascript'),
- 'maxLength = ' . $contentLimit . ';');
-
if ($contentLimit > 0) {
$this->out->elementStart('dl', 'form_note');
$this->out->element('dt', null, _('Available characters'));
diff --git a/lib/noticeform.php b/lib/noticeform.php
index ec8624597..593a1e932 100644
--- a/lib/noticeform.php
+++ b/lib/noticeform.php
@@ -178,9 +178,6 @@ class NoticeForm extends Form
$contentLimit = Notice::maxContent();
- $this->out->element('script', array('type' => 'text/javascript'),
- 'maxLength = ' . $contentLimit . ';');
-
if ($contentLimit > 0) {
$this->out->elementStart('dl', 'form_note');
$this->out->element('dt', null, _('Available characters'));
diff --git a/lib/noticelist.php b/lib/noticelist.php
index 21cec528f..4c11ceed6 100644
--- a/lib/noticelist.php
+++ b/lib/noticelist.php
@@ -147,6 +147,10 @@ class NoticeListItem extends Widget
var $notice = null;
+ /** The notice that was repeated. */
+
+ var $repeat = null;
+
/** The profile of the author of the notice, extracted once for convenience. */
var $profile = null;
@@ -162,8 +166,18 @@ class NoticeListItem extends Widget
function __construct($notice, $out=null)
{
parent::__construct($out);
- $this->notice = $notice;
- $this->profile = $notice->getProfile();
+ if (!empty($notice->repeat_of)) {
+ $original = Notice::staticGet('id', $notice->repeat_of);
+ if (empty($original)) { // could have been deleted
+ $this->notice = $notice;
+ } else {
+ $this->notice = $original;
+ $this->repeat = $notice;
+ }
+ } else {
+ $this->notice = $notice;
+ }
+ $this->profile = $this->notice->getProfile();
}
/**
@@ -202,6 +216,7 @@ class NoticeListItem extends Widget
$this->showNoticeSource();
$this->showNoticeLocation();
$this->showContext();
+ $this->showRepeat();
$this->out->elementEnd('div');
}
@@ -212,6 +227,7 @@ class NoticeListItem extends Widget
$this->out->elementStart('div', 'notice-options');
$this->showFaveForm();
$this->showReplyLink();
+ $this->showRepeatForm();
$this->showDeleteLink();
$this->out->elementEnd('div');
}
@@ -227,8 +243,9 @@ class NoticeListItem extends Widget
{
// XXX: RDFa
// TODO: add notice_type class e.g., notice_video, notice_image
+ $id = (empty($this->repeat)) ? $this->notice->id : $this->repeat->id;
$this->out->elementStart('li', array('class' => 'hentry notice',
- 'id' => 'notice-' . $this->notice->id));
+ 'id' => 'notice-' . $id));
}
/**
@@ -508,6 +525,40 @@ class NoticeListItem extends Widget
}
/**
+ * show a link to the author of repeat
+ *
+ * @return void
+ */
+
+ function showRepeat()
+ {
+ if (!empty($this->repeat)) {
+
+ $repeater = Profile::staticGet('id', $this->repeat->profile_id);
+
+ $attrs = array('href' => $repeater->profileurl,
+ 'class' => 'url');
+
+ if (!empty($repeater->fullname)) {
+ $attrs['title'] = $repeater->fullname . ' (' . $repeater->nickname . ')';
+ }
+
+ $this->out->elementStart('span', 'repeat vcard');
+
+ $this->out->raw(_('Repeated by'));
+
+ $avatar = $repeater->getAvatar(AVATAR_MINI_SIZE);
+
+ $this->out->elementStart('a', $attrs);
+
+ $this->out->element('span', 'nickname', $repeater->nickname);
+ $this->out->elementEnd('a');
+
+ $this->out->elementEnd('span');
+ }
+ }
+
+ /**
* show a link to reply to the current notice
*
* Should either do the reply in the current notice form (if available), or
@@ -540,11 +591,13 @@ class NoticeListItem extends Widget
{
$user = common_current_user();
+ $todel = (empty($this->repeat)) ? $this->notice : $this->repeat;
+
if (!empty($user) &&
- ($this->notice->profile_id == $user->id || $user->hasRight(Right::DELETEOTHERSNOTICE))) {
+ ($todel->profile_id == $user->id || $user->hasRight(Right::DELETEOTHERSNOTICE))) {
$deleteurl = common_local_url('deletenotice',
- array('notice' => $this->notice->id));
+ array('notice' => $todel->id));
$this->out->element('a', array('href' => $deleteurl,
'class' => 'notice_delete',
'title' => _('Delete this notice')), _('Delete'));
@@ -552,6 +605,28 @@ class NoticeListItem extends Widget
}
/**
+ * show the form to repeat a notice
+ *
+ * @return void
+ */
+
+ function showRepeatForm()
+ {
+ $user = common_current_user();
+ if ($user && $user->id != $this->notice->profile_id) {
+ $profile = $user->getProfile();
+ if ($profile->hasRepeated($this->notice->id)) {
+ $this->out->element('span', array('class' => 'repeated',
+ 'title' => _('Notice repeated')),
+ _('Repeated'));
+ } else {
+ $rf = new RepeatForm($this->out, $this->notice);
+ $rf->show();
+ }
+ }
+ }
+
+ /**
* finish the notice
*
* Close the last elements in the notice list item
diff --git a/lib/oauthstore.php b/lib/oauthstore.php
index e34bf8a5e..df63cc151 100644
--- a/lib/oauthstore.php
+++ b/lib/oauthstore.php
@@ -359,9 +359,8 @@ class StatusNetOAuthDataStore extends OAuthDataStore
$notice = Notice::saveNew($author->id,
$omb_notice->getContent(),
'omb',
- false,
- null,
- $omb_notice->getIdentifierURI());
+ array('is_local' => Notice::REMOTE_OMB,
+ 'uri' => $omb_notice->getIdentifierURI()));
common_broadcast_notice($notice, true);
}
diff --git a/lib/plugin.php b/lib/plugin.php
index 87d7be5a7..de7313e59 100644
--- a/lib/plugin.php
+++ b/lib/plugin.php
@@ -65,6 +65,8 @@ class Plugin
Event::addHandler(mb_substr($method, 2), array($this, $method));
}
}
+
+ $this->setupGettext();
}
function initialize()
@@ -76,4 +78,31 @@ class Plugin
{
return true;
}
+
+ /**
+ * Checks if this plugin has localization that needs to be set up.
+ * Gettext localizations can be called via the _m() helper function.
+ */
+ protected function setupGettext()
+ {
+ $class = get_class($this);
+ if (substr($class, -6) == 'Plugin') {
+ $name = substr($class, 0, -6);
+ $path = INSTALLDIR . "/plugins/$name/locale";
+ if (file_exists($path) && is_dir($path)) {
+ bindtextdomain($name, $path);
+ }
+ }
+ }
+
+ protected function log($level, $msg)
+ {
+ common_log($level, get_class($this) . ': '.$msg);
+ }
+
+ protected function debug($msg)
+ {
+ $this->log(LOG_DEBUG, $msg);
+ }
}
+
diff --git a/lib/profileformaction.php b/lib/profileformaction.php
index 8cb5f6a93..8a934666e 100644
--- a/lib/profileformaction.php
+++ b/lib/profileformaction.php
@@ -120,7 +120,7 @@ class ProfileFormAction extends Action
if ($action) {
common_redirect(common_local_url($action, $args), 303);
} else {
- $this->clientError(_("No return-to arguments"));
+ $this->clientError(_("No return-to arguments."));
}
}
@@ -134,6 +134,6 @@ class ProfileFormAction extends Action
function handlePost()
{
- $this->serverError(_("unimplemented method"));
+ $this->serverError(_("Unimplemented method."));
}
}
diff --git a/lib/repeatform.php b/lib/repeatform.php
new file mode 100644
index 000000000..50e5d6dbe
--- /dev/null
+++ b/lib/repeatform.php
@@ -0,0 +1,145 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Form for repeating a notice
+ *
+ * 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 Form
+ * @package StatusNet
+ * @author Evan Prodromou <evan@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')) {
+ exit(1);
+}
+
+/**
+ * Form for repeating a notice
+ *
+ * @category Form
+ * @package StatusNet
+ * @author Evan Prodromou <evan@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 RepeatForm extends Form
+{
+ /**
+ * Notice to repeat
+ */
+
+ var $notice = null;
+
+ /**
+ * Constructor
+ *
+ * @param HTMLOutputter $out output channel
+ * @param Notice $notice notice to repeat
+ */
+
+ function __construct($out=null, $notice=null)
+ {
+ parent::__construct($out);
+
+ $this->notice = $notice;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+
+ function id()
+ {
+ return 'repeat-' . $this->notice->id;
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+
+ function action()
+ {
+ return common_local_url('repeat');
+ }
+
+ /**
+ * Include a session token for CSRF protection
+ *
+ * @return void
+ */
+
+ function sessionToken()
+ {
+ $this->out->hidden('token-' . $this->notice->id,
+ common_session_token());
+ }
+
+ /**
+ * Legend of the Form
+ *
+ * @return void
+ */
+ function formLegend()
+ {
+ $this->out->element('legend', null, _('Repeat this notice'));
+ }
+
+ /**
+ * Data elements
+ *
+ * @return void
+ */
+
+ function formData()
+ {
+ $this->out->hidden('notice-n'.$this->notice->id,
+ $this->notice->id,
+ 'notice');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ $this->out->submit('repeat-submit-' . $this->notice->id,
+ _('Repeat'), 'submit', null, _('Repeat this notice'));
+ }
+
+ /**
+ * Class of the form.
+ *
+ * @return string the form's class
+ */
+
+ function formClass()
+ {
+ return 'form_repeat';
+ }
+}
diff --git a/lib/router.php b/lib/router.php
index 1a090861e..474e05996 100644
--- a/lib/router.php
+++ b/lib/router.php
@@ -88,6 +88,8 @@ class Router
$m->connect('doc/:title', array('action' => 'doc'));
+ $m->connect('main/login?user_id=:user_id&token=:token', array('action'=>'login'), array('user_id'=> '[0-9]+', 'token'=>'.+'));
+
// main stuff is repetitive
$main = array('login', 'logout', 'register', 'subscribe',
@@ -97,6 +99,7 @@ class Router
'groupblock', 'groupunblock',
'sandbox', 'unsandbox',
'silence', 'unsilence',
+ 'repeat',
'deleteuser');
foreach ($main as $a) {
@@ -280,12 +283,13 @@ class Router
array('action' => 'ApiTimelineFriends',
'id' => '[a-zA-Z0-9]+',
'format' => '(xml|json|rss|atom)'));
+
$m->connect('api/statuses/home_timeline.:format',
- array('action' => 'ApiTimelineFriends',
+ array('action' => 'ApiTimelineHome',
'format' => '(xml|json|rss|atom)'));
$m->connect('api/statuses/home_timeline/:id.:format',
- array('action' => 'ApiTimelineFriends',
+ array('action' => 'ApiTimelineHome',
'id' => '[a-zA-Z0-9]+',
'format' => '(xml|json|rss|atom)'));
@@ -316,6 +320,18 @@ class Router
'id' => '[a-zA-Z0-9]+',
'format' => '(xml|json|rss|atom)'));
+ $m->connect('api/statuses/retweeted_by_me.:format',
+ array('action' => 'ApiTimelineRetweetedByMe',
+ 'format' => '(xml|json|atom)'));
+
+ $m->connect('api/statuses/retweeted_to_me.:format',
+ array('action' => 'ApiTimelineRetweetedToMe',
+ 'format' => '(xml|json|atom)'));
+
+ $m->connect('api/statuses/retweets_of_me.:format',
+ array('action' => 'ApiTimelineRetweetsOfMe',
+ 'format' => '(xml|json|atom)'));
+
$m->connect('api/statuses/friends.:format',
array('action' => 'ApiUserFriends',
'format' => '(xml|json)'));
@@ -356,6 +372,16 @@ class Router
'id' => '[0-9]+',
'format' => '(xml|json)'));
+ $m->connect('api/statuses/retweet/:id.:format',
+ array('action' => 'ApiStatusesRetweet',
+ 'id' => '[0-9]+',
+ 'format' => '(xml|json)'));
+
+ $m->connect('api/statuses/retweets/:id.:format',
+ array('action' => 'ApiStatusesRetweets',
+ 'id' => '[0-9]+',
+ 'format' => '(xml|json)'));
+
// users
$m->connect('api/users/show.:format',
diff --git a/lib/rssaction.php b/lib/rssaction.php
index d591c99ed..62e3f21b6 100644
--- a/lib/rssaction.php
+++ b/lib/rssaction.php
@@ -52,7 +52,7 @@ class Rss10Action extends Action
* @see Action::__construct
*/
- function __construct($output='php://output', $indent=true)
+ function __construct($output='php://output', $indent=null)
{
parent::__construct($output, $indent);
}
diff --git a/lib/schema.php b/lib/schema.php
index df7cb65f5..a8ba91b87 100644
--- a/lib/schema.php
+++ b/lib/schema.php
@@ -94,7 +94,7 @@ class Schema
public function getTableDef($name)
{
- $res =& $this->conn->query('DESCRIBE ' . $name);
+ $res = $this->conn->query('DESCRIBE ' . $name);
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
@@ -213,7 +213,7 @@ class Schema
$sql .= "); ";
- $res =& $this->conn->query($sql);
+ $res = $this->conn->query($sql);
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
@@ -234,7 +234,7 @@ class Schema
public function dropTable($name)
{
- $res =& $this->conn->query("DROP TABLE $name");
+ $res = $this->conn->query("DROP TABLE $name");
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
@@ -269,7 +269,7 @@ class Schema
$name = "$table_".implode("_", $columnNames)."_idx";
}
- $res =& $this->conn->query("ALTER TABLE $table ".
+ $res = $this->conn->query("ALTER TABLE $table ".
"ADD INDEX $name (".
implode(",", $columnNames).")");
@@ -291,7 +291,7 @@ class Schema
public function dropIndex($table, $name)
{
- $res =& $this->conn->query("ALTER TABLE $table DROP INDEX $name");
+ $res = $this->conn->query("ALTER TABLE $table DROP INDEX $name");
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
@@ -314,7 +314,7 @@ class Schema
{
$sql = "ALTER TABLE $table ADD COLUMN " . $this->_columnSql($columndef);
- $res =& $this->conn->query($sql);
+ $res = $this->conn->query($sql);
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
@@ -339,7 +339,7 @@ class Schema
$sql = "ALTER TABLE $table MODIFY COLUMN " .
$this->_columnSql($columndef);
- $res =& $this->conn->query($sql);
+ $res = $this->conn->query($sql);
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
@@ -363,7 +363,7 @@ class Schema
{
$sql = "ALTER TABLE $table DROP COLUMN $columnName";
- $res =& $this->conn->query($sql);
+ $res = $this->conn->query($sql);
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
@@ -446,7 +446,7 @@ class Schema
$sql = 'ALTER TABLE ' . $tableName . ' ' . implode(', ', $phrase);
- $res =& $this->conn->query($sql);
+ $res = $this->conn->query($sql);
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
diff --git a/lib/subs.php b/lib/subs.php
index 2fc3160de..4b6b03967 100644
--- a/lib/subs.php
+++ b/lib/subs.php
@@ -127,6 +127,12 @@ function subs_unsubscribe_to($user, $other)
if (!$user->isSubscribed($other))
return _('Not subscribed!');
+ // Don't allow deleting self subs
+
+ if ($user->id == $other->id) {
+ return _('Couldn\'t delete self-subscription.');
+ }
+
$sub = DB_DataObject::factory('subscription');
$sub->subscriber = $user->id;
diff --git a/lib/util.php b/lib/util.php
index 5d20ed82d..ed81aeba1 100644
--- a/lib/util.php
+++ b/lib/util.php
@@ -135,7 +135,7 @@ function common_check_user($nickname, $password)
if (0 == strcmp(common_munge_password($password, $user->id),
$user->password)) {
//internal checking passed
- $authenticatedUser =& $user;
+ $authenticatedUser = $user;
}
}
}
@@ -531,19 +531,23 @@ function callback_helper($matches, $callback, $notice_id) {
return substr($matches[0],0,$left) . $result . substr($matches[0],$right);
}
-function curry($fn) {
- //TODO switch to a PHP 5.3 function closure based approach if PHP 5.3 is used
- $args = func_get_args();
- array_shift($args);
- $id = uniqid('_partial');
- $GLOBALS[$id] = array($fn, $args);
- return create_function('',
- '$args = func_get_args(); '.
- 'return call_user_func_array('.
- '$GLOBALS["'.$id.'"][0],'.
- 'array_merge('.
- '$args,'.
- '$GLOBALS["'.$id.'"][1]));');
+if (version_compare(PHP_VERSION, '5.3.0', 'ge')) {
+ // lambda implementation in a separate file; PHP 5.2 won't parse it.
+ require_once INSTALLDIR . "/lib/curry.php";
+} else {
+ function curry($fn) {
+ $args = func_get_args();
+ array_shift($args);
+ $id = uniqid('_partial');
+ $GLOBALS[$id] = array($fn, $args);
+ return create_function('',
+ '$args = func_get_args(); '.
+ 'return call_user_func_array('.
+ '$GLOBALS["'.$id.'"][0],'.
+ 'array_merge('.
+ '$args,'.
+ '$GLOBALS["'.$id.'"][1]));');
+ }
}
function common_linkify($url) {
@@ -1078,18 +1082,21 @@ function common_request_id()
function common_log($priority, $msg, $filename=null)
{
- $msg = '[' . common_request_id() . '] ' . $msg;
- $logfile = common_config('site', 'logfile');
- if ($logfile) {
- $log = fopen($logfile, "a");
- if ($log) {
- $output = common_log_line($priority, $msg);
- fwrite($log, $output);
- fclose($log);
+ if(Event::handle('StartLog', array(&$priority, &$msg, &$filename))){
+ $msg = '[' . common_request_id() . '] ' . $msg;
+ $logfile = common_config('site', 'logfile');
+ if ($logfile) {
+ $log = fopen($logfile, "a");
+ if ($log) {
+ $output = common_log_line($priority, $msg);
+ fwrite($log, $output);
+ fclose($log);
+ }
+ } else {
+ common_ensure_syslog();
+ syslog($priority, $msg);
}
- } else {
- common_ensure_syslog();
- syslog($priority, $msg);
+ Event::handle('EndLog', array($priority, $msg, $filename));
}
}
@@ -1245,8 +1252,12 @@ function common_copy_args($from)
return $to;
}
-// Neutralise the evil effects of magic_quotes_gpc in the current request.
-// This is used before handing a request off to OAuthRequest::from_request.
+/**
+ * Neutralise the evil effects of magic_quotes_gpc in the current request.
+ * This is used before handing a request off to OAuthRequest::from_request.
+ * @fixme Doesn't consider vars other than _POST and _GET?
+ * @fixme Can't be undone and could corrupt data if run twice.
+ */
function common_remove_magic_from_request()
{
if(get_magic_quotes_gpc()) {
@@ -1448,6 +1459,17 @@ function common_database_tablename($tablename)
return $tablename;
}
+/**
+ * Shorten a URL with the current user's configured shortening service,
+ * or ur1.ca if configured, or not at all if no shortening is set up.
+ * Length is not considered.
+ *
+ * @param string $long_url
+ * @return string may return the original URL if shortening failed
+ *
+ * @fixme provide a way to specify a particular shortener
+ * @fixme provide a way to specify to use a given user's shortening preferences
+ */
function common_shorten_url($long_url)
{
$user = common_current_user();
@@ -1468,6 +1490,16 @@ function common_shorten_url($long_url)
}
}
+/**
+ * @return mixed array($proxy, $ip) for web requests; proxy may be null
+ * null if not a web request
+ *
+ * @fixme X-Forwarded-For can be chained by multiple proxies;
+ we should parse the list and provide a cleaner array
+ * @fixme X-Forwarded-For can be forged by clients; only use them if trusted
+ * @fixme X_Forwarded_For headers will override X-Forwarded-For read through $_SERVER;
+ * use function to get exact request headers from Apache if possible.
+ */
function common_client_ip()
{
if (!isset($_SERVER) || !array_key_exists('REQUEST_METHOD', $_SERVER)) {
diff --git a/lib/xmloutputter.php b/lib/xmloutputter.php
index 5f06e491d..15b18e7d9 100644
--- a/lib/xmloutputter.php
+++ b/lib/xmloutputter.php
@@ -67,10 +67,13 @@ class XMLOutputter
* @param boolean $indent Whether to indent output, default true
*/
- function __construct($output='php://output', $indent=true)
+ function __construct($output='php://output', $indent=null)
{
$this->xw = new XMLWriter();
$this->xw->openURI($output);
+ if(is_null($indent)) {
+ $indent = common_config('site', 'indent');
+ }
$this->xw->setIndent($indent);
}