From 399669b1fb955d2d8c18098a7b551184d534a94c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 6 Mar 2009 16:26:28 -0800 Subject: [PATCH 01/58] Upstream changes to OAuth.php --- extlib/OAuth.php | 135 ++++++++++++++++++++++++++--------------------- 1 file changed, 75 insertions(+), 60 deletions(-) diff --git a/extlib/OAuth.php b/extlib/OAuth.php index 6dc6b3f356..029166175c 100644 --- a/extlib/OAuth.php +++ b/extlib/OAuth.php @@ -16,6 +16,10 @@ class OAuthConsumer {/*{{{*/ $this->secret = $secret; $this->callback_url = $callback_url; }/*}}}*/ + + function __toString() {/*{{{*/ + return "OAuthConsumer[key=$this->key,secret=$this->secret]"; + }/*}}}*/ }/*}}}*/ class OAuthToken {/*{{{*/ @@ -37,8 +41,8 @@ class OAuthToken {/*{{{*/ * would respond to request_token and access_token calls with */ function to_string() {/*{{{*/ - return "oauth_token=" . OAuthUtil::urlencodeRFC3986($this->key) . - "&oauth_token_secret=" . OAuthUtil::urlencodeRFC3986($this->secret); + return "oauth_token=" . OAuthUtil::urlencode_rfc3986($this->key) . + "&oauth_token_secret=" . OAuthUtil::urlencode_rfc3986($this->secret); }/*}}}*/ function __toString() {/*{{{*/ @@ -67,7 +71,7 @@ class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {/*{{{*/ ($token) ? $token->secret : "" ); - $key_parts = array_map(array('OAuthUtil','urlencodeRFC3986'), $key_parts); + $key_parts = OAuthUtil::urlencode_rfc3986($key_parts); $key = implode('&', $key_parts); return base64_encode( hash_hmac('sha1', $base_string, $key, true)); @@ -81,11 +85,11 @@ class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {/*{{{*/ public function build_signature($request, $consumer, $token) {/*{{{*/ $sig = array( - OAuthUtil::urlencodeRFC3986($consumer->secret) + OAuthUtil::urlencode_rfc3986($consumer->secret) ); if ($token) { - array_push($sig, OAuthUtil::urlencodeRFC3986($token->secret)); + array_push($sig, OAuthUtil::urlencode_rfc3986($token->secret)); } else { array_push($sig, ''); } @@ -94,7 +98,7 @@ class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {/*{{{*/ // for debug purposes $request->base_string = $raw; - return OAuthUtil::urlencodeRFC3986($raw); + return OAuthUtil::urlencode_rfc3986($raw); }/*}}}*/ }/*}}}*/ @@ -182,7 +186,7 @@ class OAuthRequest {/*{{{*/ */ public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) {/*{{{*/ $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") ? 'http' : 'https'; - @$http_url or $http_url = $scheme . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; + @$http_url or $http_url = $scheme . '://' . $_SERVER['HTTP_HOST'] . ':' . $_SERVER['SERVER_PORT'] . $_SERVER['REQUEST_URI']; @$http_method or $http_method = $_SERVER['REQUEST_METHOD']; $request_headers = OAuthRequest::get_headers(); @@ -192,27 +196,23 @@ class OAuthRequest {/*{{{*/ // do this if ($parameters) { $req = new OAuthRequest($http_method, $http_url, $parameters); + } else { + // collect request parameters from query string (GET) and post-data (POST) if appropriate (note: POST vars have priority) + $req_parameters = $_GET; + if ($http_method == "POST" && @strstr($request_headers["Content-Type"], "application/x-www-form-urlencoded") ) { + $req_parameters = array_merge($req_parameters, $_POST); + } + + // next check for the auth header, we need to do some extra stuff + // if that is the case, namely suck in the parameters from GET or POST + // so that we can include them in the signature + if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") { + $header_parameters = OAuthRequest::split_header($request_headers['Authorization']); + $parameters = array_merge($req_parameters, $header_parameters); + $req = new OAuthRequest($http_method, $http_url, $parameters); + } else $req = new OAuthRequest($http_method, $http_url, $req_parameters); } - // next check for the auth header, we need to do some extra stuff - // if that is the case, namely suck in the parameters from GET or POST - // so that we can include them in the signature - else if (@substr($request_headers['Authorization'], 0, 5) == "OAuth") { - $header_parameters = OAuthRequest::split_header($request_headers['Authorization']); - if ($http_method == "GET") { - $req_parameters = $_GET; - } - else if ($http_method == "POST") { - $req_parameters = $_POST; - } - $parameters = array_merge($header_parameters, $req_parameters); - $req = new OAuthRequest($http_method, $http_url, $parameters); - } - else if ($http_method == "GET") { - $req = new OAuthRequest($http_method, $http_url, $_GET); - } - else if ($http_method == "POST") { - $req = new OAuthRequest($http_method, $http_url, $_POST); - } + return $req; }/*}}}*/ @@ -238,7 +238,7 @@ class OAuthRequest {/*{{{*/ }/*}}}*/ public function get_parameter($name) {/*{{{*/ - return $this->parameters[$name]; + return isset($this->parameters[$name]) ? $this->parameters[$name] : null; }/*}}}*/ public function get_parameters() {/*{{{*/ @@ -267,12 +267,12 @@ class OAuthRequest {/*{{{*/ } // Urlencode both keys and values - $keys = array_map(array('OAuthUtil', 'urlencodeRFC3986'), array_keys($params)); - $values = array_map(array('OAuthUtil', 'urlencodeRFC3986'), array_values($params)); + $keys = OAuthUtil::urlencode_rfc3986(array_keys($params)); + $values = OAuthUtil::urlencode_rfc3986(array_values($params)); $params = array_combine($keys, $values); // Sort by keys (natsort) - uksort($params, 'strnatcmp'); + uksort($params, 'strcmp'); // Generate key=value pairs $pairs = array(); @@ -307,7 +307,7 @@ class OAuthRequest {/*{{{*/ $this->get_signable_parameters() ); - $parts = array_map(array('OAuthUtil', 'urlencodeRFC3986'), $parts); + $parts = OAuthUtil::urlencode_rfc3986($parts); return implode('&', $parts); }/*}}}*/ @@ -351,11 +351,21 @@ class OAuthRequest {/*{{{*/ /** * builds the data one would send in a POST request + * + * TODO(morten.fangel): + * this function might be easily replaced with http_build_query() + * and corrections for rfc3986 compatibility.. but not sure */ public function to_postdata() {/*{{{*/ $total = array(); foreach ($this->parameters as $k => $v) { - $total[] = OAuthUtil::urlencodeRFC3986($k) . "=" . OAuthUtil::urlencodeRFC3986($v); + if (is_array($v)) { + foreach ($v as $va) { + $total[] = OAuthUtil::urlencode_rfc3986($k) . "[]=" . OAuthUtil::urlencode_rfc3986($va); + } + } else { + $total[] = OAuthUtil::urlencode_rfc3986($k) . "=" . OAuthUtil::urlencode_rfc3986($v); + } } $out = implode("&", $total); return $out; @@ -364,12 +374,13 @@ class OAuthRequest {/*{{{*/ /** * builds the Authorization: header */ - public function to_header($realm="") {/*{{{*/ - $out ='"Authorization: OAuth realm="' . $realm . '",'; + public function to_header() {/*{{{*/ + $out ='Authorization: OAuth realm=""'; $total = array(); foreach ($this->parameters as $k => $v) { if (substr($k, 0, 5) != "oauth") continue; - $out .= ',' . OAuthUtil::urlencodeRFC3986($k) . '="' . OAuthUtil::urlencodeRFC3986($v) . '"'; + if (is_array($v)) throw new OAuthException('Arrays not supported in headers'); + $out .= ',' . OAuthUtil::urlencode_rfc3986($k) . '="' . OAuthUtil::urlencode_rfc3986($v) . '"'; } return $out; }/*}}}*/ @@ -412,24 +423,22 @@ class OAuthRequest {/*{{{*/ * parameters, has to do some unescaping */ private static function split_header($header) {/*{{{*/ - // remove 'OAuth ' at the start of a header - $header = substr($header, 6); - - // error cases: commas in parameter values? - $parts = explode(",", $header); - $out = array(); - foreach ($parts as $param) { - $param = ltrim($param); - // skip the "realm" param, nobody ever uses it anyway - if (substr($param, 0, 5) != "oauth") continue; - - $param_parts = explode("=", $param); - - // rawurldecode() used because urldecode() will turn a "+" in the - // value into a space - $out[$param_parts[0]] = rawurldecode(substr($param_parts[1], 1, -1)); + $pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/'; + $offset = 0; + $params = array(); + while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) { + $match = $matches[0]; + $header_name = $matches[2][0]; + $header_content = (isset($matches[5])) ? $matches[5][0] : $matches[4][0]; + $params[$header_name] = OAuthUtil::urldecode_rfc3986( $header_content ); + $offset = $match[1] + strlen($match[0]); } - return $out; + + if (isset($params['realm'])) { + unset($params['realm']); + } + + return $params; }/*}}}*/ /** @@ -506,6 +515,7 @@ class OAuthServer {/*{{{*/ // requires authorized request token $token = $this->get_token($request, $consumer, "request"); + $this->check_signature($request, $consumer, $token); $new_token = $this->data_store->new_access_token($token, $consumer); @@ -654,11 +664,11 @@ class OAuthDataStore {/*{{{*/ // implement me }/*}}}*/ - function fetch_request_token($consumer) {/*{{{*/ + function new_request_token($consumer) {/*{{{*/ // return a new token attached to this consumer }/*}}}*/ - function fetch_access_token($token, $consumer) {/*{{{*/ + function new_access_token($token, $consumer) {/*{{{*/ // return a new access token attached to this consumer // for the user associated with this token if the request token // is authorized @@ -737,17 +747,22 @@ class SimpleOAuthDataStore extends OAuthDataStore {/*{{{*/ }/*}}}*/ class OAuthUtil {/*{{{*/ - public static function urlencodeRFC3986($string) {/*{{{*/ - return str_replace('+', ' ', - str_replace('%7E', '~', rawurlencode($string))); - + public static function urlencode_rfc3986($input) {/*{{{*/ + if (is_array($input)) { + return array_map(array('OAuthUtil','urlencode_rfc3986'), $input); + } else if (is_scalar($input)) { + return str_replace('+', ' ', + str_replace('%7E', '~', rawurlencode($input))); + } else { + return ''; + } }/*}}}*/ // This decode function isn't taking into consideration the above // modifications to the encoding process. However, this method doesn't // seem to be used anywhere so leaving it as is. - public static function urldecodeRFC3986($string) {/*{{{*/ + public static function urldecode_rfc3986($string) {/*{{{*/ return rawurldecode($string); }/*}}}*/ }/*}}}*/ From e8f36b4f6a183bdc3bf76969b5d79ff4c6cbe3a5 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 6 Mar 2009 16:26:28 -0800 Subject: [PATCH 02/58] Upstream changes to OAuth.php --- extlib/OAuth.php | 135 ++++++++++++++++++++++++++--------------------- 1 file changed, 75 insertions(+), 60 deletions(-) diff --git a/extlib/OAuth.php b/extlib/OAuth.php index 6dc6b3f356..029166175c 100644 --- a/extlib/OAuth.php +++ b/extlib/OAuth.php @@ -16,6 +16,10 @@ class OAuthConsumer {/*{{{*/ $this->secret = $secret; $this->callback_url = $callback_url; }/*}}}*/ + + function __toString() {/*{{{*/ + return "OAuthConsumer[key=$this->key,secret=$this->secret]"; + }/*}}}*/ }/*}}}*/ class OAuthToken {/*{{{*/ @@ -37,8 +41,8 @@ class OAuthToken {/*{{{*/ * would respond to request_token and access_token calls with */ function to_string() {/*{{{*/ - return "oauth_token=" . OAuthUtil::urlencodeRFC3986($this->key) . - "&oauth_token_secret=" . OAuthUtil::urlencodeRFC3986($this->secret); + return "oauth_token=" . OAuthUtil::urlencode_rfc3986($this->key) . + "&oauth_token_secret=" . OAuthUtil::urlencode_rfc3986($this->secret); }/*}}}*/ function __toString() {/*{{{*/ @@ -67,7 +71,7 @@ class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {/*{{{*/ ($token) ? $token->secret : "" ); - $key_parts = array_map(array('OAuthUtil','urlencodeRFC3986'), $key_parts); + $key_parts = OAuthUtil::urlencode_rfc3986($key_parts); $key = implode('&', $key_parts); return base64_encode( hash_hmac('sha1', $base_string, $key, true)); @@ -81,11 +85,11 @@ class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {/*{{{*/ public function build_signature($request, $consumer, $token) {/*{{{*/ $sig = array( - OAuthUtil::urlencodeRFC3986($consumer->secret) + OAuthUtil::urlencode_rfc3986($consumer->secret) ); if ($token) { - array_push($sig, OAuthUtil::urlencodeRFC3986($token->secret)); + array_push($sig, OAuthUtil::urlencode_rfc3986($token->secret)); } else { array_push($sig, ''); } @@ -94,7 +98,7 @@ class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {/*{{{*/ // for debug purposes $request->base_string = $raw; - return OAuthUtil::urlencodeRFC3986($raw); + return OAuthUtil::urlencode_rfc3986($raw); }/*}}}*/ }/*}}}*/ @@ -182,7 +186,7 @@ class OAuthRequest {/*{{{*/ */ public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) {/*{{{*/ $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") ? 'http' : 'https'; - @$http_url or $http_url = $scheme . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; + @$http_url or $http_url = $scheme . '://' . $_SERVER['HTTP_HOST'] . ':' . $_SERVER['SERVER_PORT'] . $_SERVER['REQUEST_URI']; @$http_method or $http_method = $_SERVER['REQUEST_METHOD']; $request_headers = OAuthRequest::get_headers(); @@ -192,27 +196,23 @@ class OAuthRequest {/*{{{*/ // do this if ($parameters) { $req = new OAuthRequest($http_method, $http_url, $parameters); + } else { + // collect request parameters from query string (GET) and post-data (POST) if appropriate (note: POST vars have priority) + $req_parameters = $_GET; + if ($http_method == "POST" && @strstr($request_headers["Content-Type"], "application/x-www-form-urlencoded") ) { + $req_parameters = array_merge($req_parameters, $_POST); + } + + // next check for the auth header, we need to do some extra stuff + // if that is the case, namely suck in the parameters from GET or POST + // so that we can include them in the signature + if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") { + $header_parameters = OAuthRequest::split_header($request_headers['Authorization']); + $parameters = array_merge($req_parameters, $header_parameters); + $req = new OAuthRequest($http_method, $http_url, $parameters); + } else $req = new OAuthRequest($http_method, $http_url, $req_parameters); } - // next check for the auth header, we need to do some extra stuff - // if that is the case, namely suck in the parameters from GET or POST - // so that we can include them in the signature - else if (@substr($request_headers['Authorization'], 0, 5) == "OAuth") { - $header_parameters = OAuthRequest::split_header($request_headers['Authorization']); - if ($http_method == "GET") { - $req_parameters = $_GET; - } - else if ($http_method == "POST") { - $req_parameters = $_POST; - } - $parameters = array_merge($header_parameters, $req_parameters); - $req = new OAuthRequest($http_method, $http_url, $parameters); - } - else if ($http_method == "GET") { - $req = new OAuthRequest($http_method, $http_url, $_GET); - } - else if ($http_method == "POST") { - $req = new OAuthRequest($http_method, $http_url, $_POST); - } + return $req; }/*}}}*/ @@ -238,7 +238,7 @@ class OAuthRequest {/*{{{*/ }/*}}}*/ public function get_parameter($name) {/*{{{*/ - return $this->parameters[$name]; + return isset($this->parameters[$name]) ? $this->parameters[$name] : null; }/*}}}*/ public function get_parameters() {/*{{{*/ @@ -267,12 +267,12 @@ class OAuthRequest {/*{{{*/ } // Urlencode both keys and values - $keys = array_map(array('OAuthUtil', 'urlencodeRFC3986'), array_keys($params)); - $values = array_map(array('OAuthUtil', 'urlencodeRFC3986'), array_values($params)); + $keys = OAuthUtil::urlencode_rfc3986(array_keys($params)); + $values = OAuthUtil::urlencode_rfc3986(array_values($params)); $params = array_combine($keys, $values); // Sort by keys (natsort) - uksort($params, 'strnatcmp'); + uksort($params, 'strcmp'); // Generate key=value pairs $pairs = array(); @@ -307,7 +307,7 @@ class OAuthRequest {/*{{{*/ $this->get_signable_parameters() ); - $parts = array_map(array('OAuthUtil', 'urlencodeRFC3986'), $parts); + $parts = OAuthUtil::urlencode_rfc3986($parts); return implode('&', $parts); }/*}}}*/ @@ -351,11 +351,21 @@ class OAuthRequest {/*{{{*/ /** * builds the data one would send in a POST request + * + * TODO(morten.fangel): + * this function might be easily replaced with http_build_query() + * and corrections for rfc3986 compatibility.. but not sure */ public function to_postdata() {/*{{{*/ $total = array(); foreach ($this->parameters as $k => $v) { - $total[] = OAuthUtil::urlencodeRFC3986($k) . "=" . OAuthUtil::urlencodeRFC3986($v); + if (is_array($v)) { + foreach ($v as $va) { + $total[] = OAuthUtil::urlencode_rfc3986($k) . "[]=" . OAuthUtil::urlencode_rfc3986($va); + } + } else { + $total[] = OAuthUtil::urlencode_rfc3986($k) . "=" . OAuthUtil::urlencode_rfc3986($v); + } } $out = implode("&", $total); return $out; @@ -364,12 +374,13 @@ class OAuthRequest {/*{{{*/ /** * builds the Authorization: header */ - public function to_header($realm="") {/*{{{*/ - $out ='"Authorization: OAuth realm="' . $realm . '",'; + public function to_header() {/*{{{*/ + $out ='Authorization: OAuth realm=""'; $total = array(); foreach ($this->parameters as $k => $v) { if (substr($k, 0, 5) != "oauth") continue; - $out .= ',' . OAuthUtil::urlencodeRFC3986($k) . '="' . OAuthUtil::urlencodeRFC3986($v) . '"'; + if (is_array($v)) throw new OAuthException('Arrays not supported in headers'); + $out .= ',' . OAuthUtil::urlencode_rfc3986($k) . '="' . OAuthUtil::urlencode_rfc3986($v) . '"'; } return $out; }/*}}}*/ @@ -412,24 +423,22 @@ class OAuthRequest {/*{{{*/ * parameters, has to do some unescaping */ private static function split_header($header) {/*{{{*/ - // remove 'OAuth ' at the start of a header - $header = substr($header, 6); - - // error cases: commas in parameter values? - $parts = explode(",", $header); - $out = array(); - foreach ($parts as $param) { - $param = ltrim($param); - // skip the "realm" param, nobody ever uses it anyway - if (substr($param, 0, 5) != "oauth") continue; - - $param_parts = explode("=", $param); - - // rawurldecode() used because urldecode() will turn a "+" in the - // value into a space - $out[$param_parts[0]] = rawurldecode(substr($param_parts[1], 1, -1)); + $pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/'; + $offset = 0; + $params = array(); + while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) { + $match = $matches[0]; + $header_name = $matches[2][0]; + $header_content = (isset($matches[5])) ? $matches[5][0] : $matches[4][0]; + $params[$header_name] = OAuthUtil::urldecode_rfc3986( $header_content ); + $offset = $match[1] + strlen($match[0]); } - return $out; + + if (isset($params['realm'])) { + unset($params['realm']); + } + + return $params; }/*}}}*/ /** @@ -506,6 +515,7 @@ class OAuthServer {/*{{{*/ // requires authorized request token $token = $this->get_token($request, $consumer, "request"); + $this->check_signature($request, $consumer, $token); $new_token = $this->data_store->new_access_token($token, $consumer); @@ -654,11 +664,11 @@ class OAuthDataStore {/*{{{*/ // implement me }/*}}}*/ - function fetch_request_token($consumer) {/*{{{*/ + function new_request_token($consumer) {/*{{{*/ // return a new token attached to this consumer }/*}}}*/ - function fetch_access_token($token, $consumer) {/*{{{*/ + function new_access_token($token, $consumer) {/*{{{*/ // return a new access token attached to this consumer // for the user associated with this token if the request token // is authorized @@ -737,17 +747,22 @@ class SimpleOAuthDataStore extends OAuthDataStore {/*{{{*/ }/*}}}*/ class OAuthUtil {/*{{{*/ - public static function urlencodeRFC3986($string) {/*{{{*/ - return str_replace('+', ' ', - str_replace('%7E', '~', rawurlencode($string))); - + public static function urlencode_rfc3986($input) {/*{{{*/ + if (is_array($input)) { + return array_map(array('OAuthUtil','urlencode_rfc3986'), $input); + } else if (is_scalar($input)) { + return str_replace('+', ' ', + str_replace('%7E', '~', rawurlencode($input))); + } else { + return ''; + } }/*}}}*/ // This decode function isn't taking into consideration the above // modifications to the encoding process. However, this method doesn't // seem to be used anywhere so leaving it as is. - public static function urldecodeRFC3986($string) {/*{{{*/ + public static function urldecode_rfc3986($string) {/*{{{*/ return rawurldecode($string); }/*}}}*/ }/*}}}*/ From 16a6aa53907de29c6d993fd18e62d45e4380f451 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 6 Mar 2009 17:18:21 -0800 Subject: [PATCH 03/58] Some fixes for OpenID and OMB URLs --- lib/router.php | 7 +++---- lib/util.php | 9 ++++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/router.php b/lib/router.php index 516b481227..d34b84cd43 100644 --- a/lib/router.php +++ b/lib/router.php @@ -49,6 +49,8 @@ class Router { var $m = null; static $inst = null; + static $bare = array('requesttoken', 'accesstoken', 'userauthorization', + 'postnotice', 'updateprofile', 'finishremotesubscribe'); static function get() { @@ -118,8 +120,7 @@ class Router $m->connect('main/remote', array('action' => 'remotesubscribe')); $m->connect('main/remote?nickname=:nickname', array('action' => 'remotesubscribe'), array('nickname' => '[A-Za-z0-9_-]+')); - foreach (array('requesttoken', 'accesstoken', 'userauthorization', - 'postnotice', 'updateprofile', 'finishremotesubscribe') as $action) { + foreach (Router::$bare as $action) { $m->connect('index.php?action=' . $action, array('action' => $action)); } @@ -277,7 +278,6 @@ class Router 'apiaction' => 'friendships'), array('method' => 'exists(\.(xml|json|rss|atom))')); - // Social graph $m->connect('api/friends/ids/:argument', @@ -352,7 +352,6 @@ class Router array('action' => 'api', 'apiaction' => 'laconica')); - // search $m->connect('api/search.atom', array('action' => 'twitapisearchatom')); $m->connect('api/search.json', array('action' => 'twitapisearchjson')); diff --git a/lib/util.php b/lib/util.php index 9637dc5063..ca8376f287 100644 --- a/lib/util.php +++ b/lib/util.php @@ -722,12 +722,15 @@ function common_local_url($action, $args=null, $params=null, $fragment=null) { $r = Router::get(); $path = $r->build($action, $args, $params, $fragment); - if ($path) { - } + if (common_config('site','fancy')) { $url = common_path(mb_substr($path, 1)); } else { - $url = common_path('index.php'.$path); + if (mb_strpos($path, '/index.php') === 0) { + $url = common_path(mb_substr($path, 1)); + } else { + $url = common_path('index.php'.$path); + } } return $url; } From ac7170bf6cbf36699cf182ccb1bd5214f6e8741e Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 6 Mar 2009 21:09:43 -0800 Subject: [PATCH 04/58] Atom search results for Twitter-compatible API + phpcs stuff --- actions/twitapisearchatom.php | 368 ++++++++++++++++++++++++++++++++++ actions/twitapisearchjson.php | 6 +- lib/jsonsearchresultslist.php | 69 ++++--- 3 files changed, 411 insertions(+), 32 deletions(-) create mode 100644 actions/twitapisearchatom.php diff --git a/actions/twitapisearchatom.php b/actions/twitapisearchatom.php new file mode 100644 index 0000000000..3ab82bfb64 --- /dev/null +++ b/actions/twitapisearchatom.php @@ -0,0 +1,368 @@ +. + * + * @category Search + * @package Laconica + * @author Zach Copley + * @copyright 2008-2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR.'/lib/twitterapi.php'; + +/** + * Action for outputting search results in Twitter compatible Atom + * format. + * + * TODO: abstract Atom stuff into a ruseable base class like + * RSS10Action. + * + * @category Search + * @package Laconica + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * + * @see TwitterapiAction + */ + +class TwitapisearchatomAction extends TwitterapiAction +{ + + var $notices; + var $cnt; + var $query; + var $lang; + var $rpp; + var $page; + var $since_id; + var $geocode; + + /** + * Constructor + * + * Just wraps the Action constructor. + * + * @param string $output URI to output to, default = stdout + * @param boolean $indent Whether to indent output, default true + * + * @see Action::__construct + */ + + function __construct($output='php://output', $indent=true) + { + parent::__construct($output, $indent); + } + + /** + * Do we need to write to the database? + * + * @return boolean true + */ + + function isReadonly() + { + return true; + } + + /** + * Read arguments and initialize members + * + * @param array $args Arguments from $_REQUEST + * + * @return boolean success + * + */ + + function prepare($args) + { + parent::prepare($args); + + $this->query = $this->trimmed('q'); + $this->lang = $this->trimmed('lang'); + $this->rpp = $this->trimmed('rpp'); + + if (!$this->rpp) { + $this->rpp = 15; + } + + if ($this->rpp > 100) { + $this->rpp = 100; + } + + $this->page = $this->trimmed('page'); + + if (!$this->page) { + $this->page = 1; + } + + // TODO: Suppport since_id -- we need to tweak the backend + // Search classes to support it. + + $this->since_id = $this->trimmed('since_id'); + $this->geocode = $this->trimmed('geocode'); + + // TODO: Also, language and geocode + + return true; + } + + /** + * Handle a request + * + * @param array $args Arguments from $_REQUEST + * + * @return void + */ + + function handle($args) + { + parent::handle($args); + $this->showAtom(); + } + + /** + * Get the notices to output as results. This also sets some class + * attrs so we can use them to calculate pagination, and output + * since_id and max_id. + * + * @return array an array of Notice objects sorted in reverse chron + */ + + function getNotices() + { + // TODO: Support search operators like from: and to:, boolean, etc. + + $notice = new Notice(); + + // lcase it for comparison + $q = strtolower($this->query); + + $search_engine = $notice->getSearchEngine('identica_notices'); + $search_engine->set_sort_mode('chron'); + $search_engine->limit(($this->page - 1) * $this->rpp, + $this->rpp + 1, true); + $search_engine->query($q); + $this->cnt = $notice->find(); + + $cnt = 0; + + while ($notice->fetch()) { + + ++$cnt; + + if (!$this->max_id) { + $this->max_id = $notice->id; + } + + if ($cnt > $this->rpp) { + break; + } + + $notices[] = clone($notice); + } + + return $notices; + } + + /** + * Output search results as an Atom feed + * + * @return void + */ + + function showAtom() + { + $notices = $this->getNotices(); + + $this->initAtom(); + $this->showFeed(); + + foreach ($notices as $n) { + $this->showEntry($n); + } + + $this->endAtom(); + } + + /** + * Show feed specific Atom elements + * + * @return void + */ + + function showFeed() + { + // TODO: A9 OpenSearch stuff like search.twitter.com? + + $lang = common_config('site', 'language'); + $server = common_config('site', 'server'); + $sitename = common_config('site', 'name'); + + // XXX: Use xmlns:laconica instead? + + $this->elementStart('feed', + array('xmlns' => 'http://www.w3.org/2005/Atom', + 'xmlns:twitter' => 'http://api.twitter.com/', + 'xml:lang' => $lang)); + + $year = date('Y'); + $this->element('id', null, "tag:$server,$year:search/$server"); + + $site_uri = common_path(false); + + $search_uri = $site_uri . 'api/search.atom?q=' . urlencode($this->query); + + if ($this->rpp != 15) { + $search_uri .= '&rpp=' . $this->rpp; + } + + // FIXME: this alternate link is not quite right because our + // web-based notice search doesn't support a rpp (responses per + // page) param yet + + $this->element('link', array('type' => 'text/html', + 'rel' => 'alternate', + 'href' => $site_uri . 'search/notice?q=' . + urlencode($this->query))); + + // self link + + $self_uri = $search_uri . '&page=' . $this->page; + + $this->element('link', array('type' => 'application/atom+xml', + 'rel' => 'self', + 'href' => $self_uri)); + + $this->element('title', null, "$this->query - $sitename Search"); + + // refresh link + + $refresh_uri = $search_uri . "&since_id=" . $this->max_id; + + $this->element('link', array('type' => 'application/atom+xml', + 'rel' => 'refresh', + 'href' => $refresh_uri)); + + // pagination links + + if ($this->cnt > $this->rpp) { + + $next_uri = $search_uri . "&max_id=" . $this->max_id . + '&page=' . ($this->page + 1); + + $this->element('link', array('type' => 'application/atom+xml', + 'rel' => 'next', + 'href' => $next_uri)); + } + + if ($this->page > 1) { + + $previous_uri = $search_uri . "&max_id=" . $this->max_id . + '&page=' . ($this->page - 1); + + $this->element('link', array('type' => 'application/atom+xml', + 'rel' => 'previous', + 'href' => $previous_uri)); + } + + } + + /** + * Build an Atom entry similar to search.twitter.com's based on + * a given notice + * + * @param Notice $notice the notice to use + * + * @return void + */ + + function showEntry($notice) + { + $server = common_config('site', 'server'); + $profile = $notice->getProfile(); + $nurl = common_local_url('shownotice', array('notice' => $notice->id)); + + $this->elementStart('entry'); + + $year = date('Y', strtotime($notice->created)); + + $this->element('id', null, "tag:$server,$year:$notice->id"); + $this->element('published', null, common_date_w3dtf($notice->created)); + $this->element('link', array('type' => 'text/html', + 'rel' => 'alternate', + 'href' => $nurl)); + $this->element('title', null, common_xml_safe_str(trim($notice->content))); + $this->element('content', array('type' => 'text/html'), $notice->rendered); + $this->element('updated', null, common_date_w3dtf($notice->created)); + $this->element('link', array('type' => 'image/png', + 'rel' => 'image', + 'href' => $profile->avatarUrl())); + + // TODO: Here is where we'd put in a link to an atom feed for threads + + $this->element("twitter:source", null, + htmlentities($this->source_link($notice->source))); + + $this->elementStart('author'); + + $name = $profile->nickname; + + if ($profile->fullname) { + $name .= ' (' . $profile->fullname . ')'; + } + + $this->element('name', null, $name); + $this->element('uri', null, common_profile_uri($profile)); + $this->elementEnd('author'); + + $this->elementEnd('entry'); + } + + /** + * Initialize the Atom output, send headers + * + * @return void + */ + + function initAtom() + { + header('Content-Type: application/atom+xml; charset=utf-8'); + $this->startXml(); + } + + /** + * End the Atom feed + * + * @return void + */ + + function endAtom() + { + $this->elementEnd('feed'); + } + +} diff --git a/actions/twitapisearchjson.php b/actions/twitapisearchjson.php index b50aa86b7a..0f9f523a14 100644 --- a/actions/twitapisearchjson.php +++ b/actions/twitapisearchjson.php @@ -2,7 +2,7 @@ /** * Laconica, the distributed open-source microblogging tool * - * List of replies + * Action for showing Twitter-like JSON search results * * PHP version 5 * @@ -114,7 +114,7 @@ class TwitapisearchjsonAction extends TwitterapiAction function showResults() { - // TODO: Support search operators like from: and to: + // TODO: Support search operators like from: and to:, boolean, etc. $notice = new Notice(); @@ -137,7 +137,7 @@ class TwitapisearchjsonAction extends TwitterapiAction } /** - * This is a read-only action + * Do we need to write to the database? * * @return boolean true */ diff --git a/lib/jsonsearchresultslist.php b/lib/jsonsearchresultslist.php index 171e1db4d6..0cdcf0c516 100644 --- a/lib/jsonsearchresultslist.php +++ b/lib/jsonsearchresultslist.php @@ -22,7 +22,7 @@ * @category Search * @package Laconica * @author Zach Copley - * @copyright 2008-2009 Control Yourself, Inc. + * @copyright 2009 Control Yourself, Inc. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://laconi.ca/ */ @@ -62,14 +62,19 @@ class JSONSearchResultsList /** * constructor * - * @param Notice $notice stream of notices from DB_DataObject + * @param Notice $notice stream of notices from DB_DataObject + * @param string $query the original search query + * @param int $rpp the number of results to display per page + * @param int $page a page offset + * @param int $since_id only display notices newer than this */ function __construct($notice, $query, $rpp, $page, $since_id = 0) { $this->notice = $notice; $this->query = urlencode($query); - $this->results_per_page = $this->rpp = $rpp; + $this->results_per_page = $rpp; + $this->rpp = $rpp; $this->page = $page; $this->since_id = $since_id; $this->results = array(); @@ -78,7 +83,7 @@ class JSONSearchResultsList /** * show the list of search results * - * @return int count of the search results listed. + * @return int $count of the search results listed. */ function show() @@ -103,7 +108,7 @@ class JSONSearchResultsList array_push($this->results, $item); } - $time_end = microtime(true); + $time_end = microtime(true); $this->completed_in = $time_end - $time_start; // Set other attrs @@ -197,7 +202,7 @@ class ResultItem function buildResult() { - $this->text = $this->notice->content; + $this->text = $this->notice->content; $replier_profile = null; if ($this->notice->reply_to) { @@ -209,18 +214,21 @@ class ResultItem $this->to_user_id = ($replier_profile) ? intval($replier_profile->id) : null; - $this->to_user = ($replier_profile) ? + $this->to_user = ($replier_profile) ? $replier_profile->nickname : null; - $this->from_user = $this->profile->nickname; - $this->id = $this->notice->id; + + $this->from_user = $this->profile->nickname; + $this->id = $this->notice->id; $this->from_user_id = $this->profile->id; $user = User::staticGet('id', $this->profile->id); + $this->iso_language_code = $this->user->language; $this->source = $this->getSourceLink($this->notice->source); $avatar = $this->profile->getAvatar(AVATAR_STREAM_SIZE); + $this->profile_image_url = ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_STREAM_SIZE); @@ -233,27 +241,30 @@ class ResultItem * Either the name (and link) of the API client that posted the notice, * or one of other other channels. * - * @return string the source of the Notice + * @param string $source the source of the Notice + * + * @return string a fully rendered source of the Notice */ - function getSourceLink($source) - { - $source_name = _($source); - switch ($source) { - case 'web': - case 'xmpp': - case 'mail': - case 'omb': - case 'api': - break; - default: - $ns = Notice_source::staticGet($source); - if ($ns) { - $source_name = '' . $ns->name . ''; - } - break; - } - return $source_name; - } + function getSourceLink($source) + { + $source_name = _($source); + switch ($source) { + case 'web': + case 'xmpp': + case 'mail': + case 'omb': + case 'api': + break; + default: + $ns = Notice_source::staticGet($source); + if ($ns) { + $source_name = '' . $ns->name . ''; + } + break; + } + + return $source_name; + } } From 162da3cbc5f05d4e01c678019c1db92a940d4da5 Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Sat, 7 Mar 2009 10:16:05 +0100 Subject: [PATCH 05/58] Correct api method names for rss2 and atom feeds in all.php action. --- actions/all.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actions/all.php b/actions/all.php index 08dcccbddb..8e67ec0f3b 100644 --- a/actions/all.php +++ b/actions/all.php @@ -77,12 +77,12 @@ class AllAction extends Action sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->user->nickname)), new Feed(Feed::RSS2, common_local_url('api', array('apiaction' => 'statuses', - 'method' => 'friends', + 'method' => 'friends_timeline', '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', + 'method' => 'friends_timeline', 'argument' => $this->user->nickname.'.atom')), sprintf(_('Feed for friends of %s (Atom)'), $this->user->nickname))); } From 3383e780635a29d3457a7d983a137b86c63b27ef Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Sat, 7 Mar 2009 13:52:52 +0100 Subject: [PATCH 06/58] More api actions which need no auth when called with parameter. --- actions/api.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/actions/api.php b/actions/api.php index a27d244929..c18d551b6d 100644 --- a/actions/api.php +++ b/actions/api.php @@ -127,7 +127,9 @@ class ApiAction extends Action 'laconica/wadl'); static $bareauth = array('statuses/user_timeline', + 'statuses/friends_timeline', 'statuses/friends', + 'statuses/replies', 'statuses/followers', 'favorites/favorites'); From 986a32223177a759b0ef071822d227011ee1b3c7 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 7 Mar 2009 09:43:50 -0800 Subject: [PATCH 07/58] Limit duplicate notices in a particular time period (default 60s) We disallow posting a notice with duplicate content more than once a minute. Conflicts: config.php.sample --- README | 2 ++ classes/Notice.php | 47 +++++++++++++++++++++++++++++++++++++++------- config.php.sample | 6 ++++++ lib/common.php | 3 ++- 4 files changed, 50 insertions(+), 8 deletions(-) diff --git a/README b/README index 388d67ed2a..ec2e2ec4f7 100644 --- a/README +++ b/README @@ -879,6 +879,8 @@ notice: A plain string that will appear on every page. A good place to put introductory information about your service, or info about upgrades and outages, or other community info. Any HTML will be escaped. +dupelimit: Time in which it's not OK for the same person to post the + same notice; default = 60 seconds. db -- diff --git a/classes/Notice.php b/classes/Notice.php index 907239b084..eac90ce95b 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -121,6 +121,8 @@ class Notice extends Memcached_DataObject $profile = Profile::staticGet($profile_id); + $final = common_shorten_links($content); + if (!$profile) { common_log(LOG_ERR, 'Problem saving notice. Unknown user.'); return _('Problem saving notice. Unknown user.'); @@ -131,7 +133,12 @@ class Notice extends Memcached_DataObject return _('Too many notices too fast; take a breather and post again in a few minutes.'); } - $banned = common_config('profile', 'banned'); + if (common_config('site', 'dupelimit') > 0 && !Notice::checkDupes($profile_id, $final)) { + common_log(LOG_WARNING, 'Dupe posting by profile #' . $profile_id . '; throttled.'); + return _('Too many duplicate messages too quickly; take a breather and post again in a few minutes.'); + } + + $banned = common_config('profile', 'banned'); if ( in_array($profile_id, $banned) || in_array($profile->nickname, $banned)) { common_log(LOG_WARNING, "Attempted post from banned user: $profile->nickname (user id = $profile_id)."); @@ -155,12 +162,12 @@ class Notice extends Memcached_DataObject $notice->query('BEGIN'); - $notice->reply_to = $reply_to; - $notice->created = common_sql_now(); - $notice->content = common_shorten_links($content); - $notice->rendered = common_render_content($notice->content, $notice); - $notice->source = $source; - $notice->uri = $uri; + $notice->reply_to = $reply_to; + $notice->created = common_sql_now(); + $notice->content = $final; + $notice->rendered = common_render_content($final, $notice); + $notice->source = $source; + $notice->uri = $uri; if (Event::handle('StartNoticeSave', array(&$notice))) { @@ -204,6 +211,32 @@ class Notice extends Memcached_DataObject return $notice; } + static function checkDupes($profile_id, $content) { + $profile = Profile::staticGet($profile_id); + if (!$profile) { + return false; + } + $notice = $profile->getNotices(0, NOTICE_CACHE_WINDOW); + if ($notice) { + $last = 0; + while ($notice->fetch()) { + if (time() - strtotime($notice->created) >= common_config('site', 'dupelimit')) { + return true; + } else if ($notice->content == $content) { + return false; + } + } + } + # If we get here, oldest item in cache window is not + # old enough for dupe limit; do direct check against DB + $notice = new Notice(); + $notice->profile_id = $profile_id; + $notice->content = $content; + $notice->whereAdd('now() - created < ' . common_config('notice', 'dupelimit')); + $cnt = $notice->count(); + return ($cnt > 0); + } + static function checkEditThrottle($profile_id) { $profile = Profile::staticGet($profile_id); if (!$profile) { diff --git a/config.php.sample b/config.php.sample index a6cada77a2..c2b27408cd 100644 --- a/config.php.sample +++ b/config.php.sample @@ -159,3 +159,9 @@ $config['sphinx']['port'] = 3312; # Add Google Analytics # require_once('plugins/GoogleAnalyticsPlugin.php'); # $ga = new GoogleAnalyticsPlugin('your secret code'); + +#Don't allow saying the same thing more than once per hour +#$config['site']['dupelimit'] = 3600; +#Don't enforce the dupe limit +#$config['site']['dupelimit'] = -1; + diff --git a/lib/common.php b/lib/common.php index 0355d01e3a..917fdeafa4 100644 --- a/lib/common.php +++ b/lib/common.php @@ -85,7 +85,8 @@ $config = 'broughtbyurl' => null, 'closed' => false, 'inviteonly' => false, - 'private' => false), + 'private' => false, + 'dupelimit' => 60), # default for same person saying the same thing 'syslog' => array('appname' => 'laconica', # for syslog 'priority' => 'debug'), # XXX: currently ignored From 1980f166a78954b15ed53e1421164452ec692497 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 7 Mar 2009 11:36:10 -0800 Subject: [PATCH 08/58] change trust root calculation --- lib/openid.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/openid.php b/lib/openid.php index 5c3d460daf..3aa488b6d4 100644 --- a/lib/openid.php +++ b/lib/openid.php @@ -160,7 +160,7 @@ function oid_authenticate($openid_url, $returnto, $immediate=false) $auth_request->addExtension($sreg_request); } - $trust_root = common_local_url('public'); + $trust_root = common_path(''); $process_url = common_local_url($returnto); if ($auth_request->shouldSendRedirect()) { From 0570c16e6ceb42d6b3afa93c1054e024091a3e08 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 7 Mar 2009 11:56:01 -0800 Subject: [PATCH 09/58] Add local directory for plugins, themes, etc. Added a local directory for locally-installed software. This is where you should put any code you write, themes, plugins, etc. so they don't get stomped by upgrades. --- classes/User.php | 3 ++- local/.gitignore | 0 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 local/.gitignore diff --git a/classes/User.php b/classes/User.php index 8b0b9acd50..d9f30bec58 100644 --- a/classes/User.php +++ b/classes/User.php @@ -121,7 +121,8 @@ class User extends Memcached_DataObject static $blacklist = array('rss', 'xrds', 'doc', 'main', 'settings', 'notice', 'user', 'search', 'avatar', 'tag', 'tags', - 'api', 'message', 'group', 'groups'); + 'api', 'message', 'group', 'groups', + 'local'); $merged = array_merge($blacklist, common_config('nickname', 'blacklist')); return !in_array($nickname, $merged); } diff --git a/local/.gitignore b/local/.gitignore new file mode 100644 index 0000000000..e69de29bb2 From 22742c3b72a02c29eef0e678abd839e378a783c4 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 7 Mar 2009 12:38:22 -0800 Subject: [PATCH 10/58] Make OpenID login and registration URLs work The OpenID login and registration URLs were not generating correctly. I added them to the list of "bare" actions in the router class, and they work great now. --- lib/router.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/router.php b/lib/router.php index d34b84cd43..52051fdb50 100644 --- a/lib/router.php +++ b/lib/router.php @@ -50,7 +50,8 @@ class Router var $m = null; static $inst = null; static $bare = array('requesttoken', 'accesstoken', 'userauthorization', - 'postnotice', 'updateprofile', 'finishremotesubscribe'); + 'postnotice', 'updateprofile', 'finishremotesubscribe', + 'finishopenidlogin', 'finishaddopenid'); static function get() { From 1179ecd13d68e76d74ad94e2d3ca22d9681eeffe Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 7 Mar 2009 12:55:09 -0800 Subject: [PATCH 11/58] Fix nonce usage in OAuth store The OAuth store was failing on getting a request token, because the token value was forced to be non-null in the DB. Let this value be null, and use the correct primary key (consumer, timestamp, nonce). Drop the reference to token table, and don't ever use it. --- classes/Nonce.php | 9 ++++----- classes/laconica.ini | 4 ++-- db/laconica.sql | 5 ++--- lib/oauthstore.php | 3 +-- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/classes/Nonce.php b/classes/Nonce.php index 2c0edfa14d..486a65a3c7 100644 --- a/classes/Nonce.php +++ b/classes/Nonce.php @@ -4,22 +4,21 @@ */ require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; -class Nonce extends Memcached_DataObject +class Nonce extends Memcached_DataObject { ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ public $__table = 'nonce'; // table name public $consumer_key; // varchar(255) primary_key not_null - public $tok; // char(32) primary_key not_null + public $tok; // char(32) public $nonce; // char(32) primary_key not_null - public $ts; // datetime() not_null + public $ts; // datetime() primary_key not_null public $created; // datetime() not_null public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP /* Static get */ - function staticGet($k,$v=null) - { return Memcached_DataObject::staticGet('Nonce',$k,$v); } + function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Nonce',$k,$v); } /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE diff --git a/classes/laconica.ini b/classes/laconica.ini index 5fd2cd1f86..529454d99b 100755 --- a/classes/laconica.ini +++ b/classes/laconica.ini @@ -145,7 +145,7 @@ id = N [nonce] consumer_key = 130 -tok = 130 +tok = 2 nonce = 130 ts = 142 created = 142 @@ -153,8 +153,8 @@ modified = 384 [nonce__keys] consumer_key = K -tok = K nonce = K +ts = K [notice] id = 129 diff --git a/db/laconica.sql b/db/laconica.sql index c2cd887dee..098fa4fd1a 100644 --- a/db/laconica.sql +++ b/db/laconica.sql @@ -181,15 +181,14 @@ create table token ( create table nonce ( consumer_key varchar(255) not null comment 'unique identifier, root URL', - tok char(32) not null comment 'identifying value', + tok char(32) null comment 'buggy old value, ignored', nonce char(32) not null comment 'nonce', ts datetime not null comment 'timestamp sent', created datetime not null comment 'date this record was created', modified timestamp comment 'date this record was modified', - constraint primary key (consumer_key, tok, nonce), - constraint foreign key (consumer_key, tok) references token (consumer_key, tok) + constraint primary key (consumer_key, ts, nonce) ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; /* One-to-many relationship of user to openid_url */ diff --git a/lib/oauthstore.php b/lib/oauthstore.php index 9af05ea2de..7d2e1f27b6 100644 --- a/lib/oauthstore.php +++ b/lib/oauthstore.php @@ -58,12 +58,11 @@ class LaconicaOAuthDataStore extends OAuthDataStore { $n = new Nonce(); $n->consumer_key = $consumer->key; - $n->tok = $token->key; + $n->ts = $timestamp; $n->nonce = $nonce; if ($n->find(true)) { return true; } else { - $n->ts = $timestamp; $n->created = DB_DataObject_Cast::dateTime(); $n->insert(); return false; From 2400589c2fc9355679b5da318286ecf96e386133 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 7 Mar 2009 13:00:13 -0800 Subject: [PATCH 12/58] helpful documentation for oauthstore nonce stuff --- lib/oauthstore.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/oauthstore.php b/lib/oauthstore.php index 7d2e1f27b6..183164e170 100644 --- a/lib/oauthstore.php +++ b/lib/oauthstore.php @@ -54,6 +54,12 @@ class LaconicaOAuthDataStore extends OAuthDataStore } } + // http://oauth.net/core/1.0/#nonce + // "The Consumer SHALL then generate a Nonce value that is unique for + // all requests with that timestamp." + + // XXX: It's not clear why the token is here + function lookup_nonce($consumer, $token, $nonce, $timestamp) { $n = new Nonce(); From ba9c589bb2616fb1bdcb2416a934a8f91cd401e5 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 7 Mar 2009 13:32:44 -0800 Subject: [PATCH 13/58] fix for change in OAuthUtil upstream --- actions/userauthorization.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/userauthorization.php b/actions/userauthorization.php index 0dc1841d4f..5fd8f8ccec 100644 --- a/actions/userauthorization.php +++ b/actions/userauthorization.php @@ -197,7 +197,7 @@ class UserauthorizationAction extends Action } $parts = array(); foreach ($params as $k => $v) { - $parts[] = $k . '=' . OAuthUtil::urlencodeRFC3986($v); + $parts[] = $k . '=' . OAuthUtil::urlencode_RFC3986($v); } $query_string = implode('&', $parts); $parsed = parse_url($callback); From 1a63d7d8299259dc13c8b21700bf441123947d3a Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 7 Mar 2009 13:35:19 -0800 Subject: [PATCH 14/58] fix case of OAuthUtil method --- actions/userauthorization.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/userauthorization.php b/actions/userauthorization.php index 5fd8f8ccec..0566b4b70b 100644 --- a/actions/userauthorization.php +++ b/actions/userauthorization.php @@ -197,7 +197,7 @@ class UserauthorizationAction extends Action } $parts = array(); foreach ($params as $k => $v) { - $parts[] = $k . '=' . OAuthUtil::urlencode_RFC3986($v); + $parts[] = $k . '=' . OAuthUtil::urlencode_rfc3986($v); } $query_string = implode('&', $parts); $parsed = parse_url($callback); From c21d61840dcacb8dac3f511decef61f2fb3a80d9 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 7 Mar 2009 14:13:33 -0800 Subject: [PATCH 15/58] Let people view friends_timeline of others Add some code to view others' friends timelines through API. --- actions/twitapistatuses.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/actions/twitapistatuses.php b/actions/twitapistatuses.php index 216835026d..63e29068b1 100644 --- a/actions/twitapistatuses.php +++ b/actions/twitapistatuses.php @@ -115,9 +115,14 @@ class TwitapistatusesAction extends TwitterapiAction $since = strtotime($this->arg('since')); - $user = $this->get_user(null, $apidata); + $user = $this->get_user($apidata['api_arg'], $apidata); $this->auth_user = $user; + if (empty($user)) { + $this->clientError(_('No such user!'), 404, $apidata['content-type']); + return; + } + $profile = $user->getProfile(); $sitename = common_config('site', 'name'); From a4091c878a923d7a0919098665906225ebeeb136 Mon Sep 17 00:00:00 2001 From: CiaranG Date: Sat, 7 Mar 2009 23:28:59 +0000 Subject: [PATCH 16/58] PostgreSQL - propogated nonce table fix from MySQL version - see bug #1251 or 1179ecd13d68e76d74ad94e2d3ca22d9681eeffe --- db/laconica_pg.sql | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/db/laconica_pg.sql b/db/laconica_pg.sql index 2d83f784a2..d9e0c6da70 100644 --- a/db/laconica_pg.sql +++ b/db/laconica_pg.sql @@ -180,14 +180,13 @@ create table token ( create table nonce ( consumer_key varchar(255) not null /* comment 'unique identifier, root URL' */, tok char(32) not null /* comment 'identifying value' */, - nonce char(32) not null /* comment 'nonce' */, + nonce char(32) null /* comment 'buggy old value, ignored */, ts integer not null /* comment 'timestamp sent' values are epoch, and only used internally */, created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */, modified timestamp /* comment 'date this record was modified' */, - primary key (consumer_key, tok, nonce), - foreign key (consumer_key, tok) references token (consumer_key, tok) + primary key (consumer_key, ts, nonce) ); /* One-to-many relationship of user to openid_url */ From f8d13817174a63dc8452ed60a00b7d336633fa88 Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Sun, 8 Mar 2009 01:30:11 +0100 Subject: [PATCH 17/58] Corrected redirect targets for some group actions. These redirects can occur when the canonical name differs from the passed name. --- actions/grouplogo.php | 2 +- actions/joingroup.php | 2 +- actions/leavegroup.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/actions/grouplogo.php b/actions/grouplogo.php index 499db4ae8d..fe6127da29 100644 --- a/actions/grouplogo.php +++ b/actions/grouplogo.php @@ -83,7 +83,7 @@ class GrouplogoAction extends Action if ($nickname_arg != $nickname) { $args = array('nickname' => $nickname); - common_redirect(common_local_url('editgroup', $args), 301); + common_redirect(common_local_url('grouplogo', $args), 301); return false; } diff --git a/actions/joingroup.php b/actions/joingroup.php index 1888ecdab2..eeea4a37bf 100644 --- a/actions/joingroup.php +++ b/actions/joingroup.php @@ -73,7 +73,7 @@ class JoingroupAction extends Action if ($nickname_arg != $nickname) { $args = array('nickname' => $nickname); - common_redirect(common_local_url('editgroup', $args), 301); + common_redirect(common_local_url('joingroup', $args), 301); return false; } diff --git a/actions/leavegroup.php b/actions/leavegroup.php index c7152e3c0e..1d85aa3d52 100644 --- a/actions/leavegroup.php +++ b/actions/leavegroup.php @@ -73,7 +73,7 @@ class LeavegroupAction extends Action if ($nickname_arg != $nickname) { $args = array('nickname' => $nickname); - common_redirect(common_local_url('editgroup', $args), 301); + common_redirect(common_local_url('leavegroup', $args), 301); return false; } From f9a7ae27b8879569a3f0eff478cbd3b650bdca28 Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Sun, 8 Mar 2009 01:31:25 +0100 Subject: [PATCH 18/58] Remove leave button from grouplist if current user is admin of that group. --- lib/grouplist.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/grouplist.php b/lib/grouplist.php index 4c448e250d..8f3b0abd87 100644 --- a/lib/grouplist.php +++ b/lib/grouplist.php @@ -164,8 +164,10 @@ class GroupList extends Widget # XXX: special-case for user looking at own # subscriptions page if ($user->isMember($this->group)) { - $lf = new LeaveForm($this->out, $this->group); - $lf->show(); + if (!$user->isAdmin($this->group)) { + $lf = new LeaveForm($this->out, $this->group); + $lf->show(); + } } else { $jf = new JoinForm($this->out, $this->group); $jf->show(); From ad83998f10952c3841b4b999b5a340ca26d329f7 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 7 Mar 2009 17:16:52 -0800 Subject: [PATCH 19/58] Revert "Remove leave button from grouplist if current user is admin of that group." People shouldn't be forced to be part of a group, even if they are the admin. If a group has no admin, we need to figure out what to do with it, but it's wrong to force anyone to be part of a group. This reverts commit f9a7ae27b8879569a3f0eff478cbd3b650bdca28. --- lib/grouplist.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/grouplist.php b/lib/grouplist.php index 8e2637fec9..1b85474998 100644 --- a/lib/grouplist.php +++ b/lib/grouplist.php @@ -164,10 +164,8 @@ class GroupList extends Widget # XXX: special-case for user looking at own # subscriptions page if ($user->isMember($this->group)) { - if (!$user->isAdmin($this->group)) { - $lf = new LeaveForm($this->out, $this->group); - $lf->show(); - } + $lf = new LeaveForm($this->out, $this->group); + $lf->show(); } else { $jf = new JoinForm($this->out, $this->group); $jf->show(); From 7d7d78b7f7a5065a866468c2e8b5bd536f56611a Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 7 Mar 2009 17:43:59 -0800 Subject: [PATCH 20/58] you can _so_ leave a group if you're its admin --- actions/leavegroup.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/actions/leavegroup.php b/actions/leavegroup.php index 1d85aa3d52..eb30d0e505 100644 --- a/actions/leavegroup.php +++ b/actions/leavegroup.php @@ -96,12 +96,6 @@ class LeavegroupAction extends Action return false; } - if ($cur->isAdmin($this->group)) { - $this->clientError(_('You may not leave a group while you are its administrator.'), 403); - return false; - - } - return true; } From bea3fca1899dddda8d1c52c16a761dd23c9ce8b8 Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Sat, 7 Mar 2009 23:04:30 +0100 Subject: [PATCH 21/58] Fix bug in dupe checking on notice post when there is no notice in cache. --- classes/Notice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/Notice.php b/classes/Notice.php index eac90ce95b..ac4db944f2 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -234,7 +234,7 @@ class Notice extends Memcached_DataObject $notice->content = $content; $notice->whereAdd('now() - created < ' . common_config('notice', 'dupelimit')); $cnt = $notice->count(); - return ($cnt > 0); + return ($cnt == 0); } static function checkEditThrottle($profile_id) { From f66775658c0f231c8bcf9ea310fc8ac0dbf19bfd Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 7 Mar 2009 17:47:43 -0800 Subject: [PATCH 22/58] trying to kill the can't-leave-a-group bug --- actions/showgroup.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/actions/showgroup.php b/actions/showgroup.php index c20941a35e..b6022840bf 100644 --- a/actions/showgroup.php +++ b/actions/showgroup.php @@ -275,10 +275,8 @@ class ShowgroupAction extends Action $cur = common_current_user(); if ($cur) { if ($cur->isMember($this->group)) { - if (!$cur->isAdmin($this->group)) { - $lf = new LeaveForm($this, $this->group); - $lf->show(); - } + $lf = new LeaveForm($this, $this->group); + $lf->show(); } else { $jf = new JoinForm($this, $this->group); $jf->show(); From a89d7ceab0baeeaa4cc69684ae4c342a63814e2f Mon Sep 17 00:00:00 2001 From: CiaranG Date: Sun, 8 Mar 2009 11:58:27 +0000 Subject: [PATCH 23/58] PostgreSQL - added equivalent of the MySQL-specific rebuilddb.sh script, for upgrading --- README | 19 +++++++++++-------- scripts/rebuilddb_psql.sh | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 8 deletions(-) create mode 100755 scripts/rebuilddb_psql.sh diff --git a/README b/README index ec2e2ec4f7..07957c09e9 100644 --- a/README +++ b/README @@ -745,16 +745,19 @@ to the end first before trying them. directory to your new directory. 9. Copy htaccess.sample to .htaccess in the new directory. Change the RewriteBase to use the correct path. -10. Rebuild the database. Go to your Laconica directory and run the - rebuilddb.sh script like this: +10. Rebuild the database. For MySQL, go to your Laconica directory and + run the rebuilddb.sh script like this: - ./scripts/rebuilddb.sh rootuser rootpassword database db/laconica.sql + ./scripts/rebuilddb.sh rootuser rootpassword database db/laconica.sql - Here, rootuser and rootpassword are the username and password for a - user who can drop and create databases as well as tables; typically - that's _not_ the user Laconica runs as. -11. Use mysql client to log into your database and make sure that the - notice, user, profile, subscription etc. tables are non-empty. + Here, rootuser and rootpassword are the username and password for a + user who can drop and create databases as well as tables; typically + that's _not_ the user Laconica runs as. + For PostgreSQL databases there is an equivalent, rebuilddb_psql.sh, + which operates slightly differently. Read the documentation in that + script before running it. +11. Use mysql or psql client to log into your database and make sure that + the notice, user, profile, subscription etc. tables are non-empty. 12. Turn back on the Web server, and check that things still work. 13. Turn back on XMPP bots and email maildaemon. Note that the XMPP bots have changed since version 0.5; see above for details. diff --git a/scripts/rebuilddb_psql.sh b/scripts/rebuilddb_psql.sh new file mode 100755 index 0000000000..ac169c205d --- /dev/null +++ b/scripts/rebuilddb_psql.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# +# ******************************* WARNING ********************************* +# Do not run this script until you have read and understood the information +# below, AND backed up your database. Failure to observe these instructions +# may result in losing all the data in your database. +# +# This script is used to upgrade Laconica's PostgreSQL database to the +# latest version. It does the following: +# +# 1. Dumps the existing data to /tmp/rebuilddb_psql.sql +# 2. Clears out the objects (tables, etc) in the database schema +# 3. Reconstructs the database schema using the latest script +# 4. Restores the data dumped in step 1 +# +# You MUST run this script as the 'postgres' user. +# You MUST be able to write to /tmp/rebuilddb_psql.sql +# You MUST specify the laconica database user and database name on the +# command line, e.g. ./rebuilddb_psql.sh myuser mydbname +# + +user=$1 +DB=$2 + +cd `dirname $0` + +pg_dump -a -D --disable-trigger $DB > /tmp/rebuilddb_psql.sql +psql -c "drop schema public cascade; create schema public;" $DB +psql -c "grant all privileges on schema public to $user;" $DB +psql $DB < ../db/laconica_pg.sql +psql $DB < /tmp/rebuilddb_psql.sql +for tab in `psql -c '\dts' $DB -tA | cut -d\| -f2`; do + psql -c "ALTER TABLE \"$tab\" OWNER TO $user;" $DB +done From a5f11248305f1ec66eee215e9e12ba010ed97691 Mon Sep 17 00:00:00 2001 From: CiaranG Date: Sun, 8 Mar 2009 15:51:31 +0000 Subject: [PATCH 24/58] PostgreSQL - use the specific sequence names required by DB_DataObject, otherwise rebuilding can't work --- db/laconica_pg.sql | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/db/laconica_pg.sql b/db/laconica_pg.sql index d9e0c6da70..f879d7936f 100644 --- a/db/laconica_pg.sql +++ b/db/laconica_pg.sql @@ -1,7 +1,8 @@ /* local and remote users have profiles */ +create sequence profile_seq; create table profile ( - id serial primary key /* comment 'unique identifier' */, + id bigint default nextval('profile_seq') primary key /* comment 'unique identifier' */, nickname varchar(64) not null /* comment 'nickname or username' */, fullname varchar(255) /* comment 'display name' */, profileurl varchar(255) /* comment 'URL, cached so we dont regenerate' */, @@ -30,8 +31,9 @@ create table avatar ( ); create index avatar_profile_id_idx on avatar using btree(profile_id); +create sequence sms_carrier_seq; create table sms_carrier ( - id serial primary key /* comment 'primary key for SMS carrier' */, + id bigint default nextval('sms_carrier_seq') primary key /* comment 'primary key for SMS carrier' */, name varchar(64) unique /* comment 'name of the carrier' */, email_pattern varchar(255) not null /* comment 'sprintf pattern for making an email address from a phone number' */, created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */, @@ -101,9 +103,10 @@ create table subscription ( create index subscription_subscriber_idx on subscription using btree(subscriber); create index subscription_subscribed_idx on subscription using btree(subscribed); +create sequence notice_seq; create table notice ( - id serial primary key /* comment 'unique identifier' */, + id bigint default nextval('notice_seq') primary key /* comment 'unique identifier' */, profile_id integer not null /* comment 'who made the update' */ references profile (id) , uri varchar(255) unique /* comment 'universally unique identifier, usually a tag URI' */, content varchar(140) /* comment 'update content' */, @@ -317,9 +320,10 @@ create table invitation ( create index invitation_address_idx on invitation using btree(address,address_type); create index invitation_user_id_idx on invitation using btree(user_id); +create sequence message_seq; create table message ( - id serial primary key /* comment 'unique identifier' */, + id bigint default nextval('message_seq') primary key /* comment 'unique identifier' */, uri varchar(255) unique /* comment 'universally unique identifier' */, from_profile integer not null /* comment 'who the message is from' */ references profile (id), to_profile integer not null /* comment 'who the message is to' */ references profile (id), @@ -367,9 +371,10 @@ create table profile_block ( ); +create sequence user_group_seq; create table user_group ( - id serial primary key /* comment 'unique identifier' */, + id bigint default nextval('user_group_seq') primary key /* comment 'unique identifier' */, nickname varchar(64) unique /* comment 'nickname for addressing' */, fullname varchar(255) /* comment 'display name' */, From 2133d5a4e7fc694b097fe65282e557d99ee109ad Mon Sep 17 00:00:00 2001 From: CiaranG Date: Sun, 8 Mar 2009 16:16:10 +0000 Subject: [PATCH 25/58] PostgreSQL - some more fixes to make queries compatible with both databases. (submitted by oxygene) --- actions/postnotice.php | 2 +- actions/twittersettings.php | 8 ++++---- lib/jabber.php | 4 ++-- lib/util.php | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/actions/postnotice.php b/actions/postnotice.php index 0b47352964..c32d8ca94b 100644 --- a/actions/postnotice.php +++ b/actions/postnotice.php @@ -79,7 +79,7 @@ class PostnoticeAction extends Action } $notice = Notice::staticGet('uri', $notice_uri); if (!$notice) { - $notice = Notice::saveNew($remote_profile->id, $content, 'omb', false, 0, $notice_uri); + $notice = Notice::saveNew($remote_profile->id, $content, 'omb', false, null, $notice_uri); if (is_string($notice)) { common_server_serror($notice, 500); return false; diff --git a/actions/twittersettings.php b/actions/twittersettings.php index a79859bbf0..45725d3ff4 100644 --- a/actions/twittersettings.php +++ b/actions/twittersettings.php @@ -186,12 +186,12 @@ class TwittersettingsAction extends ConnectSettingsAction $current_user = common_current_user(); - $qry = 'SELECT user.* ' . + $qry = 'SELECT "user".* ' . 'FROM subscription ' . - 'JOIN user ON subscription.subscribed = user.id ' . - 'JOIN foreign_link ON foreign_link.user_id = user.id ' . + 'JOIN "user" ON subscription.subscribed = "user".id ' . + 'JOIN foreign_link ON foreign_link.user_id = "user".id ' . 'WHERE subscriber = %d ' . - 'ORDER BY user.nickname'; + 'ORDER BY "user".nickname'; $user = new User(); diff --git a/lib/jabber.php b/lib/jabber.php index 3fbb3e1ab9..3cd3b0d37e 100644 --- a/lib/jabber.php +++ b/lib/jabber.php @@ -410,8 +410,8 @@ function jabber_broadcast_notice($notice) "ON $UT.id = notice_inbox.user_id " . 'WHERE notice_inbox.notice_id = ' . $notice->id . ' ' . 'AND notice_inbox.source = 2 ' . - 'AND user.jabber is not null ' . - 'AND user.jabbernotify = 1 '); + "AND $UT.jabber is not null " . + "AND $UT.jabbernotify = 1 "); while ($user->fetch()) { if (!array_key_exists($user->id, $sent_to)) { diff --git a/lib/util.php b/lib/util.php index ca8376f287..221175ccd2 100644 --- a/lib/util.php +++ b/lib/util.php @@ -688,7 +688,7 @@ function common_relative_profile($sender, $nickname, $dt=null) $recipient = new Profile(); // XXX: use a join instead of a subquery $recipient->whereAdd('EXISTS (SELECT subscribed from subscription where subscriber = '.$sender->id.' and subscribed = id)', 'AND'); - $recipient->whereAdd('nickname = "' . trim($nickname) . '"', 'AND'); + $recipient->whereAdd("nickname = '" . trim($nickname) . "'", 'AND'); if ($recipient->find(true)) { // XXX: should probably differentiate between profiles with // the same name by date of most recent update @@ -698,7 +698,7 @@ function common_relative_profile($sender, $nickname, $dt=null) $recipient = new Profile(); // XXX: use a join instead of a subquery $recipient->whereAdd('EXISTS (SELECT subscriber from subscription where subscribed = '.$sender->id.' and subscriber = id)', 'AND'); - $recipient->whereAdd('nickname = "' . trim($nickname) . '"', 'AND'); + $recipient->whereAdd("nickname = '" . trim($nickname) . "'", 'AND'); if ($recipient->find(true)) { // XXX: should probably differentiate between profiles with // the same name by date of most recent update From 1df3eeba861f9f5b7be7fd1ad4298f614a6cbee5 Mon Sep 17 00:00:00 2001 From: CiaranG Date: Sun, 8 Mar 2009 17:40:45 +0000 Subject: [PATCH 26/58] Added the new pinghandler to the stopdaemons script and improved the behaviour and output of the script --- scripts/stopdaemons.sh | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/scripts/stopdaemons.sh b/scripts/stopdaemons.sh index fd4406d415..2bb8f9ecb2 100755 --- a/scripts/stopdaemons.sh +++ b/scripts/stopdaemons.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Laconica - a distributed open-source microblogging tool @@ -23,19 +23,30 @@ SDIR=`dirname $0` DIR=`php $SDIR/getpiddir.php` -for f in jabberhandler ombhandler publichandler smshandler \ +for f in jabberhandler ombhandler publichandler smshandler pinghandler \ xmppconfirmhandler xmppdaemon twitterhandler facebookhandler ; do FILES="$DIR/$f.*.pid" for ff in "$FILES" ; do - echo -n "Stopping $f..." - PID=`cat $ff` - kill -3 $PID - if kill -9 $PID ; then - echo "DONE." - else - echo "FAILED." + PID=`cat $ff 2>/dev/null` + if [ -n "$PID" ] ; then + echo -n "Stopping $f ($PID)..." + if kill -3 $PID 2>/dev/null ; then + count=0 + while kill -0 $PID 2>/dev/null ; do + sleep 1 + count=$(($count + 1)) + if [ $count -gt 5 ]; then break; fi + done + if kill -9 $PID 2>/dev/null ; then + echo "FORCIBLY TERMINATED" + else + echo "STOPPED CLEANLY" + fi + else + echo "NOT FOUND" + fi fi rm -f $ff done From e55808698bedb489e8f9b6d46a81dceb0e32e07d Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 8 Mar 2009 11:49:34 -0700 Subject: [PATCH 27/58] use call_user_func for callbacks --- lib/util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/util.php b/lib/util.php index 221175ccd2..ca9006d64e 100644 --- a/lib/util.php +++ b/lib/util.php @@ -467,7 +467,7 @@ function common_replace_urls_callback($text, $callback) { $url = (mb_strpos($orig_url, htmlspecialchars($url)) === FALSE) ? $url:htmlspecialchars($url); // Call user specified func - $modified_url = $callback($url); + $modified_url = call_user_func($callback, $url); // Replace it! $start = mb_strpos($text, $url, $offset); From c97142ad3edea1652f39e7fb58c8c3443f8a0f67 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 8 Mar 2009 11:50:55 -0700 Subject: [PATCH 28/58] first version of plugin for pingback and trackback (no trackback yet) --- plugins/LinkbackPlugin.php | 140 +++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 plugins/LinkbackPlugin.php diff --git a/plugins/LinkbackPlugin.php b/plugins/LinkbackPlugin.php new file mode 100644 index 0000000000..77adfa87d1 --- /dev/null +++ b/plugins/LinkbackPlugin.php @@ -0,0 +1,140 @@ +. + * + * @category Plugin + * @package Laconica + * @author Evan Prodromou + * @copyright 2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +require_once('Auth/Yadis/Yadis.php'); + +define('LINKBACKPLUGIN_VERSION', '0.1'); + +/** + * Plugin to do linkbacks for notices containing URLs + * + * After new notices are saved, we check their text for URLs. If there + * are URLs, we test each URL to see if it supports any + * + * @category Plugin + * @package Laconica + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * + * @see Event + */ + +class LinkbackPlugin extends Plugin +{ + var $notice = null; + + function __construct() + { + parent::__construct(); + } + + function onEndNoticeSave($notice) + { + if ($notice->is_local == 1) { + // Try to avoid actually mucking with the + // notice content + $c = $notice->content; + $this->notice = $notice; + // Ignoring results + common_replace_urls_callback($c, + array($this, 'linkbackUrl')); + } + return true; + } + + function linkbackUrl($url) + { + $orig = $url; + $url = htmlspecialchars_decode($orig); + $scheme = parse_url($url, PHP_URL_SCHEME); + if (!in_array($scheme, array('http', 'https'))) { + return $orig; + } + + // XXX: Do a HEAD first to save some time/bandwidth + + $fetcher = Auth_Yadis_Yadis::getHTTPFetcher(); + + $result = $fetcher->get($url, + array('User-Agent: ' . $this->userAgent(), + 'Accept: application/html+xml,text/html')); + + if (!in_array($result->status, array('200', '206'))) { + return $orig; + } + + if (array_key_exists('X-Pingback', $result->headers)) { + $endpoint = $result->headers['X-Pingback']; + } else if (preg_match('//', + $result->body, + $match)) { + $endpoint = $match[1]; + } else { + // XXX: do Trackback lookup + return $orig; + } + + $this->pingback($url, $endpoint); + return $orig; + } + + function pingback($url, $endpoint) + { + $args = array($this->notice->uri, $url); + + $request = xmlrpc_encode_request('pingback.ping', $args); + $context = stream_context_create(array('http' => array('method' => "POST", + 'header' => + "Content-Type: text/xml\r\n". + "User-Agent: " . $this->userAgent(), + 'content' => $request))); + $file = file_get_contents($endpoint, false, $context); + $response = xmlrpc_decode($file); + if (xmlrpc_is_fault($response)) { + common_log(LOG_WARNING, + "Pingback error for '$url' ($endpoint): ". + "$response[faultString] ($response[faultCode])"); + } else { + common_log(LOG_INFO, + "Pingback success for '$url' ($endpoint): ". + "'$response'"); + } + } + + function userAgent() + { + return 'LinkbackPlugin/'.LINKBACKPLUGIN_VERSION . + ' Laconica/' . LACONICA_VERSION; + } +} From c8b10381a9157144f8c92dede1ebabc6b05390c0 Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Sun, 8 Mar 2009 01:54:21 +0100 Subject: [PATCH 29/58] Add subedit to the main/ routes. --- lib/router.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/router.php b/lib/router.php index 52051fdb50..902f25d8a5 100644 --- a/lib/router.php +++ b/lib/router.php @@ -101,7 +101,7 @@ class Router $main = array('login', 'logout', 'register', 'subscribe', 'unsubscribe', 'confirmaddress', 'recoverpassword', 'invite', 'favor', 'disfavor', 'sup', - 'block'); + 'block', 'subedit'); foreach ($main as $a) { $m->connect('main/'.$a, array('action' => $a)); From e8e40439961160989c32e1cd661ecce94b75fcee Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Sun, 8 Mar 2009 17:04:48 +0100 Subject: [PATCH 30/58] Typo in lib/omb.php updateprofile request handling. --- lib/omb.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/omb.php b/lib/omb.php index befcf4666a..c302a7b649 100644 --- a/lib/omb.php +++ b/lib/omb.php @@ -295,7 +295,7 @@ function omb_update_profile($profile, $remote_profile, $subscription) common_debug('Got HTTP result "'.print_r($result,true).'"', __FILE__); - if (empty($result) || $result) { + if (empty($result) || !$result) { common_debug("Unable to contact " . $req->get_normalized_http_url()); } else if ($result->status == 403) { # not authorized, don't send again common_debug('403 result, deleting subscription', __FILE__); From 4c8c9bb9dfe962e0d34f1acb2df20ddd2728920c Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Sat, 7 Mar 2009 02:19:18 +0100 Subject: [PATCH 31/58] Define undefined variable. --- actions/allrss.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/actions/allrss.php b/actions/allrss.php index 0114c43962..45f3946a61 100644 --- a/actions/allrss.php +++ b/actions/allrss.php @@ -81,8 +81,9 @@ class AllrssAction extends Rss10Action */ function getNotices($limit=0) { - $user = $this->user; - $notice = $user->noticesWithFriends(0, $limit); + $user = $this->user; + $notice = $user->noticesWithFriends(0, $limit); + $notices = array(); while ($notice->fetch()) { $notices[] = clone($notice); From 6ab9d6b14016cf97fe1a31d89591e1a0e919c8a7 Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Sun, 8 Mar 2009 17:09:09 +0100 Subject: [PATCH 32/58] Remove additional output as response to updateprofile. This output breaks our own response validation and is not part of the OMB spec. --- actions/updateprofile.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/actions/updateprofile.php b/actions/updateprofile.php index 4751a04ff3..2268c432f1 100644 --- a/actions/updateprofile.php +++ b/actions/updateprofile.php @@ -34,6 +34,8 @@ class UpdateprofileAction extends Action $server = omb_oauth_server(); list($consumer, $token) = $server->verify_request($req); if ($this->update_profile($req, $consumer, $token)) { + header('HTTP/1.1 200 OK'); + header('Content-type: text/plain'); print "omb_version=".OMB_VERSION_01; } } catch (OAuthException $e) { @@ -173,10 +175,6 @@ class UpdateprofileAction extends Action return false; } } - header('HTTP/1.1 200 OK'); - header('Content-type: text/plain'); - print 'Updated profile'; - print "\n"; return true; } } From fbe794e44d235d2f66ef418796f87947631afb6a Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Tue, 3 Mar 2009 16:12:05 +0100 Subject: [PATCH 33/58] Improve handling of null values in profile parameters. This commit fixes two issues: - Allowing remote users to clear profile parameters via OMB. - Improved handling of profile parameters which evaluate to false ('0' for example) --- actions/finishremotesubscribe.php | 8 ++++---- actions/remotesubscribe.php | 8 ++++---- actions/updateprofile.php | 14 ++++++++------ actions/userauthorization.php | 26 +++++++++++++------------- lib/profilelist.php | 10 +++++----- 5 files changed, 34 insertions(+), 32 deletions(-) diff --git a/actions/finishremotesubscribe.php b/actions/finishremotesubscribe.php index acfacbdc1c..eaf57c2d8f 100644 --- a/actions/finishremotesubscribe.php +++ b/actions/finishremotesubscribe.php @@ -136,16 +136,16 @@ class FinishremotesubscribeAction extends Action $profile->nickname = $nickname; $profile->profileurl = $profile_url; - if ($fullname) { + if (!is_null($fullname)) { $profile->fullname = $fullname; } - if ($homepage) { + if (!is_null($homepage)) { $profile->homepage = $homepage; } - if ($bio) { + if (!is_null($bio)) { $profile->bio = $bio; } - if ($location) { + if (!is_null($location)) { $profile->location = $location; } diff --git a/actions/remotesubscribe.php b/actions/remotesubscribe.php index 7ea7acd6d3..a2e01bd3ae 100644 --- a/actions/remotesubscribe.php +++ b/actions/remotesubscribe.php @@ -367,16 +367,16 @@ class RemotesubscribeAction extends Action return; } - if ($profile->fullname) { + if (!is_null($profile->fullname)) { $req->set_parameter('omb_listenee_fullname', $profile->fullname); } - if ($profile->homepage) { + if (!is_null($profile->homepage)) { $req->set_parameter('omb_listenee_homepage', $profile->homepage); } - if ($profile->bio) { + if (!is_null($profile->bio)) { $req->set_parameter('omb_listenee_bio', $profile->bio); } - if ($profile->location) { + if (!is_null($profile->location)) { $req->set_parameter('omb_listenee_location', $profile->location); } $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE); diff --git a/actions/updateprofile.php b/actions/updateprofile.php index 2268c432f1..7dc52fda9e 100644 --- a/actions/updateprofile.php +++ b/actions/updateprofile.php @@ -138,22 +138,24 @@ class UpdateprofileAction extends Action $orig_profile = clone($profile); - if ($nickname) { + /* Use values even if they are an empty string. Parsing an empty string in + updateProfile is the specified way of clearing a parameter in OMB. */ + if (!is_null($nickname)) { $profile->nickname = $nickname; } - if ($profile_url) { + if (!is_null($profile_url)) { $profile->profileurl = $profile_url; } - if ($fullname) { + if (!is_null($fullname)) { $profile->fullname = $fullname; } - if ($homepage) { + if (!is_null($homepage)) { $profile->homepage = $homepage; } - if ($bio) { + if (!is_null($bio)) { $profile->bio = $bio; } - if ($location) { + if (!is_null($location)) { $profile->location = $location; } diff --git a/actions/userauthorization.php b/actions/userauthorization.php index 0566b4b70b..6a76e3a4c2 100644 --- a/actions/userauthorization.php +++ b/actions/userauthorization.php @@ -113,9 +113,9 @@ class UserauthorizationAction extends Action $this->element('a', array('href' => $profile, 'class' => 'external profile nickname'), $nickname); - if ($fullname) { + if (!is_null($fullname)) { $this->elementStart('div', 'fullname'); - if ($homepage) { + if (!is_null($homepage)) { $this->element('a', array('href' => $homepage), $fullname); } else { @@ -123,10 +123,10 @@ class UserauthorizationAction extends Action } $this->elementEnd('div'); } - if ($location) { + if (!is_null($location)) { $this->element('div', 'location', $location); } - if ($bio) { + if (!is_null($bio)) { $this->element('div', 'bio', $bio); } $this->elementStart('div', 'license'); @@ -179,16 +179,16 @@ class UserauthorizationAction extends Action $params['omb_listener_nickname'] = $user->nickname; $params['omb_listener_profile'] = common_local_url('showstream', array('nickname' => $user->nickname)); - if ($profile->fullname) { + if (!is_null($profile->fullname)) { $params['omb_listener_fullname'] = $profile->fullname; } - if ($profile->homepage) { + if (!is_null($profile->homepage)) { $params['omb_listener_homepage'] = $profile->homepage; } - if ($profile->bio) { + if (!is_null($profile->bio)) { $params['omb_listener_bio'] = $profile->bio; } - if ($profile->location) { + if (!is_null($profile->location)) { $params['omb_listener_location'] = $profile->location; } $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE); @@ -267,16 +267,16 @@ class UserauthorizationAction extends Action $profile->nickname = $nickname; $profile->profileurl = $profile_url; - if ($fullname) { + if (!is_null($fullname)) { $profile->fullname = $fullname; } - if ($homepage) { + if (!is_null($homepage)) { $profile->homepage = $homepage; } - if ($bio) { + if (!is_null($bio)) { $profile->bio = $bio; } - if ($location) { + if (!is_null($location)) { $profile->location = $location; } @@ -409,7 +409,7 @@ class UserauthorizationAction extends Action 'omb_listenee_profile', 'omb_listenee_nickname', 'omb_listenee_license') as $param) { - if (!$req->get_parameter($param)) { + if (is_null($req->get_parameter($param))) { throw new OAuthException("Required parameter '$param' not found"); } } diff --git a/lib/profilelist.php b/lib/profilelist.php index c2040fbc23..75053b7a42 100644 --- a/lib/profilelist.php +++ b/lib/profilelist.php @@ -102,13 +102,13 @@ class ProfileList extends Widget 'alt' => ($this->profile->fullname) ? $this->profile->fullname : $this->profile->nickname)); - $hasFN = ($this->profile->fullname) ? 'nickname' : 'fn nickname'; + $hasFN = ($this->profile->fullname !== '') ? 'nickname' : 'fn nickname'; $this->out->elementStart('span', $hasFN); $this->out->raw($this->highlight($this->profile->nickname)); $this->out->elementEnd('span'); $this->out->elementEnd('a'); - if ($this->profile->fullname) { + if ($this->profile->fullname !== '') { $this->out->elementStart('dl', 'entity_fn'); $this->out->element('dt', null, 'Full name'); $this->out->elementStart('dd'); @@ -118,7 +118,7 @@ class ProfileList extends Widget $this->out->elementEnd('dd'); $this->out->elementEnd('dl'); } - if ($this->profile->location) { + if ($this->profile->location !== '') { $this->out->elementStart('dl', 'entity_location'); $this->out->element('dt', null, _('Location')); $this->out->elementStart('dd', 'label'); @@ -126,7 +126,7 @@ class ProfileList extends Widget $this->out->elementEnd('dd'); $this->out->elementEnd('dl'); } - if ($this->profile->homepage) { + if ($this->profile->homepage !== '') { $this->out->elementStart('dl', 'entity_url'); $this->out->element('dt', null, _('URL')); $this->out->elementStart('dd'); @@ -137,7 +137,7 @@ class ProfileList extends Widget $this->out->elementEnd('dd'); $this->out->elementEnd('dl'); } - if ($this->profile->bio) { + if ($this->profile->bio !== '') { $this->out->elementStart('dl', 'entity_note'); $this->out->element('dt', null, _('Note')); $this->out->elementStart('dd', 'note'); From f87ef9b72b8e054296a3fd37c74f07af5f6a6c38 Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Mon, 9 Mar 2009 09:45:40 +0100 Subject: [PATCH 34/58] Fixes #1277: Typo in variable name in actions/twitapidirect_messages.php. --- actions/twitapidirect_messages.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/twitapidirect_messages.php b/actions/twitapidirect_messages.php index db55e8cd02..ce98bf6ec2 100644 --- a/actions/twitapidirect_messages.php +++ b/actions/twitapidirect_messages.php @@ -190,7 +190,7 @@ class Twitapidirect_messagesAction extends TwitterapiAction $this->init_document('xml'); $this->elementStart('direct-messages', array('type' => 'array')); - if (is_array($messages)) { + if (is_array($message)) { foreach ($message as $m) { $twitter_dm = $this->twitter_dmsg_array($m); $this->show_twitter_xml_dmsg($twitter_dm); From 8d3d16f2f8fbbffc6824efcee4bd0ce25b314e14 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Mon, 9 Mar 2009 19:43:46 +0000 Subject: [PATCH 35/58] Updated URL patterns for identica Profiles for YahooSearchMonkey app. Added app to show custom identica notices. Note that these files can be used as templates for other laconica instances. --- scripts/SearchMonkey-MrH.0.txt | 1 + scripts/SearchMonkey-Om3.0.txt | 2 +- scripts/SearchMonkey-yQP.0.txt | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 scripts/SearchMonkey-MrH.0.txt diff --git a/scripts/SearchMonkey-MrH.0.txt b/scripts/SearchMonkey-MrH.0.txt new file mode 100644 index 0000000000..34191d90a8 --- /dev/null +++ b/scripts/SearchMonkey-MrH.0.txt @@ -0,0 +1 @@ +b2.PXYLSJBuLkZnUQ7H.2gOSSTbVllQM_XyN0ya4sO9CNt5uBUATEGyKd3LkkR0QXTSduKb7xj7Bp1TX6.8XdIDsOVVuXe.3HPnPLtSacZm66.NLY3JGhJv1MfGvcJU42YEQiUvpAhZRe46E.lv38ZPzxvhjjAmGFyFv8UNuhdw6sNIlTwBdct3k1GKA1YSEeVJ_xLiAVa8IaU_XG8PlxMovsBPePOry8__.aAp5loHtmqX6vEVu3lcHEn5NvSZ502QoWkK_20Y.6oja.Fqqxtr6eli_AQXaVzWWDEu_D4_rDV9Mz_.EC8KzXKo.YdUaWQfS9akqNm1v54wTNM4ZDegsbKnaNUR7J0OYgzpzcPj4L57yWKFm7k2af.v2loGrUOKJGO3rBcOQSfUz5jyCKDdd29cdd2L96XA0Uy31RjvdWSsprigS94HjoE9e5TUMHHZt47Wi50DsMq5R87uznHTouuHOKyxT3c_wCejxb_A0lVM5JL4VnrjVEo0CkY5ju1fDXfXG.Q8T4WYbnW_4i4W.DAuaFiRxIsLtrSG5bpMvJWQ8MTfc39gaLkNtGACL_O8IxX7iyFjARapuIXPhu3v3ndEt6qlgcUsEBl6zhxe6WcTQssBTUSDSPQWMmbA8TCYe1xwHd3ukSdqkhkALdIri2oeLLhkbNQRKxouIWHqL5aH0r7CCKM.P87rJE1meb28ux00FrBg4Fa62RM5S5Wn24u0odvPGK9JGmzisi.zM2cULr8C03gwBEeGDXzLIPevVnoqcYvtUfs8_B9xtaFzsKEM.04JX94e5Y_qWqfJs2.vWdY02BwWNsM1ONUzsS5qBzFhNpVnvZYHkNuOGXLb7cg7sL0Zm9pGMQPJsffThK2KY5EGSxbCB_JMqZmu9UtmcFyrsny7Yo1z6uCgu7GzN9_6Tc_DGW4OyuOm6XaLZSbGApmGosEKRKIODNAUGyT6QChSEwnPxhgYVpIn1TYualgrBtwvON5d84Up5.mxTH5ZHDjQcW04oE1dp2mBQhlUHvTF.PbEuUztvA8mMuLZgERcE01oOKkDlh9gvjZNiMs6f8SPmulKmtvheecitvB4Urgkae_PiXbcD4aOL4PyjwByX4zpCw9NG8Ga.6JLv1nH.vEE5XBCzh0_rnEmv0XzNBjiE8nj_p2pntfxmdpEeSGrA8WzigZTHrjawltlC_sMGLqR0EfRqoVrs3NtH8jafQ8DoqKUnR1wiG1BFC9PiQzPbPunYvVT_vMILkfwHDS7gY4bfZAlLrfbC0n8EKumGJc1o1ag_VsfnO2O8vE9667oVTaAGMmxXA_g1qpPVJTDWHRm4kwA6SWTZ6RCSb0Scd_DTXN4cevjn3sSGOCKE5Tocd1s4JRCuDPGQ9XI1OXGSKZrUuuM8mUlZqj6A.FWgdv2c5qXoRla.Qlb6encfFh8gnBNNoIR5X4F9PFl7.Yq38Vi0BJ7zIJVYAU8UXqJqPKKN.qH4A941m8jG7trm9NBrsRIkyCJBE5W1UVZ4x4sBDSuJMT_UCYCyn_qsjHkYpJOaYt44c7PT5U_S8oVUUe0qtuvmQ5DK.cZAU1hdw9fINikie3yGxO66lWRPtmM1rqTHwEHqaJXkn4mnRhQmHE.pqB.N_Byir3AiezaA2EGi6Z7.G99XrOjxJ0tIyim39AkoPZbeWqVlLDL.4AGCzPLQyndMClwWJdjcHBaSrxGGL1OpZ9cGA6w1zLD_6uyP4gK2pGTGxvOk4TFqrpc07eX7j6agiBfkUzYykXSm_JYDVZqiivMwKVEynFsX24erN0kd379wr_QI8Ov2nfXudbZn9EY1bhmupuAtMqpW.dNGk7YJ3AD31zrfz2KcZjdQuLkTYwqW4zI3YEI0jFqk0WYXSUmCNRzbdvmoZI1kAWRw2COuUnYeMfoTiMeJGgUd.g-- \ No newline at end of file diff --git a/scripts/SearchMonkey-Om3.0.txt b/scripts/SearchMonkey-Om3.0.txt index 45b782d0b2..6f8840962e 100644 --- a/scripts/SearchMonkey-Om3.0.txt +++ b/scripts/SearchMonkey-Om3.0.txt @@ -1 +1 @@ -BE9KrPPSJAPljm0ykS59yJQmWBFY9RPVJFhZsiF_5Wcf_tkGwf4FP2Ncjs7qGfHFCb2pv.eDr5y0zhKrF4s3ugs89DbLaA.hrbRJwglsNym5TDwDycrGw3TvjfCVmHBx4VzOZ2QzUyXBIs0T30paT6PYQfARKBdMkieKbbQ1tfl.f.ul35_kcpoXZt_lTDWFDaia2RM41uDLHJyVbCcRkqfHCLabgNeOq_MGFXGA6DjnKQx7TNyQe.2N6IyVd1quVapHn6jUOsWNkahehPMHtO72yvPpugS0UHCKBqcd.UCcbIhmtzLnKoBQAH2AJqUrmfg1XRwqFvTo6y9Z5XmDQK2hRnv97InV5he1AMIqNUotAcIrYjq5Tn42whYsznnMYhMY44UqZGoJI_ZwsSvnH6Je.AhKU3hBW9Tsmggpxgnhx_o2vhyNw2QAgPJng0FKxaevCmPnFtLntwluhxLbiTo2IiIotP4VjIVKs76hHzAsmXYuvS01OU.XB43Gmcw5yP9OUIoh5fEA1ANxOb.ba8aVxu2FdvedbOECgO6gvr.kYilrdxwwnVbHwVP6esrOiYE32dRs0_tWdgfvJfyloLjj_M5stZLEBcVfoUSQHsxX6jW5jrs4BTEHhKrxlOzdBt8f8T2E6eA9x2h7B8zK4eRtC2NBrcj1jzYCVWUT7IdbN05NZBjGYvxtmX1KRW91QwdFXgytfOINFkDk0scNCGGt4OYDzKLJ7sRBy0iKhHNfTC3noUhWf1372uXQ_yiWDWB7cTfxF9meAU3TWrTS7DjGTkwLvCVUJ43QyCxBQd1jWU6sp_VvytDeHx7cqrkNsa3JRN9dht3POqq_mVL0c5MX_XRpV8O.tPSGmfUPUrR5qnV8Z739D6PGWkOQzfzTTv6vGkf4jj1xyDEfUqr767_yL7gHeI2VlbdD2ammzwEhRK9f8ME8FbrZTTgX1OD0.v1cFULt1lew.rtCOtKf4F2MBbi90edst.TpOoUh_TvFkgKf0zgteNo2JjzrmCO.uviLCM2weGksARL70mdU6W9N932YWr6E8HbUc02S8ifSnbMpiUTHwNzMErsg7BSyRVJngGLDreBkBEIjXkNoApJR7kMPMaYVwtvjU.8wLmyFLZ.PHqqcrADTr7R50hL3UKj1mLsL19gQL3cP9J7_zJJM4Q1GDj2dPWBLhJMosUVhW8XBFPhW0aEdmgqhpsAJ_qv52xfjBeEPyPmKHu1p.1G2QEmOqFm_swbVAPHnra5zd8x4OOlHGFeL3qPLW9_LXN46chs6cOpUdYaWRzT2YuOUHHE8RDV9Mev22p7WjrbgC8hY3wK55Cpw_fCekaHcJX2jU3FPl09httjI1i5yGU04yD5MpOQF5EadbSlfjDEg8H.GoOFZcyKKDnqj_8SYdrXWq4aTqAnWgvBPh.bznvmevDgEpH.9gtzLcao4Dzmk.K0PnRgvkzyaN5IGk60TiD4Fk0u3f4bqKaPCOIKCTajbNGIasyND0J5ROtAa_IlXljCpzeEYPhSASSFV6fWmlqHFiGa2cKlLNr157MAUVQg52dJRRyid1YDcHK8ZuMc4BX8QA0olb2CDbUHKxxwv0zbIsgUTL8gvKIAPwBfF0cPfV9v6Phs1rPFXnysxdnunXnr6r6ZCN00rZeA7XbH68f.UjW0.ERGvB72kMnB8fBhfEgD22Y0ZFkwxI00UVAm5yiwkjYx86EdCpkMLBVDR1kWictX04pFLzxZK8iRflPBy74Nx2SFO19qJFnQmKEV2IN2wlrH6z14902LEI2Vuh_dVxNphr1k5mJ9x2VNGmvol.vvHmaLCufHIrOMRkAFMxeP37Mnzyk6NpxAQbdV0KwC.YTfoK9Y5knYAherlh7x8NqELX6XqutF2Lm11dikoK8Yu8u3Rkhoaef00PISV0LOb0E.D1LRjFFGzUCt5Ezcq68Tt0rFNEF1gm5Xl9Rygln_67F0KMgacpKTJ2PBIqcteyRZoRohFBRUTLkKn784KacSBsWFkogD5n7blv943wWeZFvUcKsFyYZny1WLvGEQX01kbjyaDCLDxiEQWSvlDuD.2wOra0JO5.Bo2PpPK5tbNexZDVx3k1yb48ev2UC4J4IlD6oK1KYe46Y.7NX9kDYCcdRiQOVnLJ4PSbPhDW0hcE2SNtxmFdpAf2xQOiekXY35lkuNxvebVhKuoFWxUgQmFEfreJQsC5qf_dunxGquD6u3SXnLbTg8aNWZqtR74dr3s7C5kwBK6eBGwJfkAx8Z2JKwLr5QHdISfa0wLl7aIejz5Mg_tfeATLIwW8SiIQdJiZ992Bx1k_50XQVeHOdyEc8J1Tjnkrji_ZY9PFn3AZc94wXD8erpANuJIbDIdLUp1idqF_TDtmqSK2qQgz26IkewcZnSIQnm98qxkHf9DAIbE6_GUP0ZeWqLQrn0CdhejhOPsKsovcDI7zBHMQABquMeBh9YC1.QCO9br6YmYEAV30n5IsZgl5PRiRDjkhXv8VaE.fnRNndSy7BX6kmxSmDWQfY0FvbUBWBQm7tfU3Mrk2Ojm4ALIYUZnJxl.5xj6VvD.2ZX3ug_1zo7mAiAYG_F939DMccfgCVFUcdtbF9Q9YFeC2bVMfgX5gA75nBCu5R8KopeWfTjdqZBtJoT6HxFmCSLQqIdjrxD7X2RapCI0QoDsp9xyzRZJ5NF5ygVBJqtNn2lAwFENasqFvGRSb35B.sjTQoHW5WBoBjFy5tNF1vWYJENfKRjWn5Pr0FvFdQfBKqeiWrLtStAnGrd49frviyK5VtYa.eSuRyX32SGb7.Pxo0Hf0bhER4uvPBktf3ec5UjL_xRI3eQ__F7tRiGu2tRYIUYcUkhLKAGYoDx2_gdMOXcow5W3KwtuVNtZ4UMRmuB3ccyBUzDTRWNLFISq56JXU46_v7ANub44kTLDfGuJExu.0NaOuW6isndAIYslJlcCs6NJ6j_6Ag55G.UhQFfzDKVOEt.L \ No newline at end of file +WJofugbSJAtzh.lFcHxO_WHM64iJd7qHJFbsqC9VLnpiqoBxdbE0iwoKozxZC331Svk6O9Un9jonWUrQeTndGO8hldPlxqGdFdbl6OjoucDGG_h6qBw3Ugnbethbyuew1qOaUr6ItfU4Pe9O2GtUj2KbqxZpUAvMeiS20hykHbIZ8n_1.fl.fTToLiJn58zcLc1_ryM0f5jbkIGwmGX_SG6isGJRzC4.BiNmntpJ5ZCKa80e7oUH9S6NlM5SEmXoA3zhuzkbBxF_fKLendcC7EafnTT34MbgD5s4uwTyubSBJvdmBu.mWSO9xrnojM903Vo8h3.UdG.id1LmFrj4xxd24IQqZM2v4zOfl8ugF8ChHaIzp82A1AOuk0ulkqKgiALia6bsZMbKdPZtlu_HGrF06tCt5VGvu5f0ZgjRk_kOlP_f_oppyVKRWzZpSH9GryOpoqJA2vlxgEH2BvZqaaUYEmaYJjIh7eNkLRLVorbK7rGhPf_L5qfHir.31Ar1zZxWgvhjSW7ipkvsNr_3j7oOh1LSTVWNHo.dpLT0_dib6syFopav2FqStJG0RTsWNXkQ_6h.jf439DjwuZmCLMcbUrMAMrRVcsUyR5nfqP5cP0igSx8m.oONA7O.txOXSzc3HjqvIVSTRO8BIHx.vTMJ6mq4NUmZ6_pHWapHbO9esUlIyXf5CF2qhtlM9aulr2fwCf8BqtjQctAtvYLrI_qKP95wNaB_qhcuFsZN1aiql.FtigHe2YYTix4SWg9.67VSBAyOqjWcA5jbyoomf8Gxzks9PZQfSuKbkbw_x3XOshGl4QMo6CEypV0qIYVVW77bOJc7I0WgwgxuAKg6lROlmsIdN0.SeTV4sY1ZcoLEgdNCNb81SVstXdE0iPXPZZsEStez.qluWnQoVkkWfOaBe78PxPZUvQS02RaR0FCH4bksqGWXLA8chAHIe4vPNerCLJwskKG3rA43xRDEZY7sgdEfA93iTztmIRq8dkYA6dJOxOMtvpSdh9jds04xpdmfhb23bVYp1XCp3qWka6JoKlzvQU2THqFr7gNU3KMCbr2ngHHkDTZGNO__MLa3SKlp2Vg3qHXxkivFUmWTNUz5vuW7v.FhsKOVFIFfSrTl3pjJMD3hyIlxzf_HJ60q1LRBkwqxrA9e8Fr5tqWQj.evL5kqz_r26MdHFeMTx9VwfDnHLaVx3eu5Wy2NJmLVPRLNn4t1VhexsEdLquy0ynBVBOBBRa2HbYgv0lXOP.QRl5twTKwJO6fx6J4_L_HhPv6jhcQej1LtUyGyKwLuXrHxnHCOqD.e9ZL_xnqSRthM6NvBsvbnZOPr7falUuQWPzbikXMFUvSlckeetPi2Z11l9pH.cxZDj19B38v7jwT5zZMQN9FzQvTCvzrQCpHxfIxwh3a2cx18BEMKHL7MJWDsoYVURtI3iIdR84WzXcr3kkCz.LM8tqTKVkzHLk8Grx8KT3dF5ZIVhWK5yyb05RFOZdoZQ4cWXmvsaQhDUd6Dm2KRJiypSFntLLSp34URsLaqzxaakMnywHvfmsINah4oKBBy8.NFBRULU9SqTyIOwf6_ggWG06J1WJxWV94RRCD1rMNNM9ISMOo4yB_dmfLHnXKOZm1lOnisEN36gsxniy_psLN3Ed1ozRtbbD.wALfE.92DrDA9ASPOdu08P7xer76iXVbdt_4cg5whY59Hq2N.A1mrSbetDbSu7NeziZ.nBvSUg_YpVvMo2H3elySL.1UsLPFznStGuYfbISN79MZecU.ScSCtaeZQ2cBFekXMNT77HWZmv6YLsz84ceQwL_MidvAYqPh6PUNiBl8iwFR5PCpTB54.g0m3zuALOqF9hJ598v9rh9Zlu1SfE.UfmGpUICMSuXH7C8zHMq4TFZGzCuBY9EOuBc.JQaCfBr8N3jnDq2bwlQjDmgbVW2xm2WpPMCB0OxkqoggA0i4ZZA3gSfqhlZ9mdmr_l9mUe0dOd_EkyWyu0l.Z1.VQLY2KJHl.8pZWyP6S_RAFmABOlEGP3m1E8NxaMP87o9ot_BNg21DeHbwADKbv16deRlDrKmntHoPwfsaTPNo5KembI_4nHxQ3y2B2OjsUPcLYFZZtsP4ukLBhYusR8SdtsEC._plxsMQzS9nH.zRP8nbluMlUjCKgfepGN_rCq.NeGON.L_.FowXEOcX7M1SD.IfihdAHqk0zUpuyTfe.9E77aEu26iIZOGmyOwSqRvN9HksJx.iMk5xL.xah7hl.NByMBbmkRDS52wDMxygNpPXsIHdvu8OyLxq.ZsNBGF.IHs0qiquX4.RZ2TBqTQ6O4AhzOTpFeZlG3UzdmxsEtDI2a7tY_27Gg39apf_83ijjiLaJE2RG5Mb9krZ2RCIAXaFez74o_oqli5dy6WyT4lEIKtw38T7m1bJ_xpLju5FBQUE54RpsK.ZWSAoyh3c05b2mBeN2id_NV7sM4MinY7rEsOgNVevUNrWebNrrdunUF8gsa59cXdGSKvmUw9kEKW_Z6Y14AICD43zlmVGYDYlSLqpHsu32m9aGuQFlqzBlHCKPg9uD9dyFKsZJI8l2yq91sEj9snlYhApmHLVQzGWLiOJCJUclByiPmVD_.OnHE84lBcv0bkXKFYXvUhFs2Xu1VrN1mGXz50KkG4Xovzkw0ueuWlJ2vozPUf9CkJ1mlOA4jwuFLMrQZmN04aXyR3ZWFN8pdSVITI0ADqNr9OGacCra.emTRIWdBLEj18kp39vhlR6BpxI2V0FQjC_27n2hkDUNAUNFaJ1Q84OO2mgzZnPXcN7NYz57W3lB_mMVUtKngnRlTNWn1sFdN6.WFQ1szScjtpFa68NBv5pLUOvKy49VWjn14uS4aUoDL_fbMi9tGw0tlrMEr74fm5hJNwPX1QKd3cy0jqDHLIpZTb1aNxIz_KU4XIJ2wx0gZZQH2zV7eTxsrozzo3J0TtiQC6pPOqbnsRF1TuX1..DV5LzUdKX0TUXyO8x0710.EF4z6pim0HuVKzV2VBKmG6qtzpIRCKzVk14lx2E9YkJTQusU9qZnw9Ixu_YL0Ue_4LachvurMZDYTIRcSyd4St3TmtZswmeLPS6Md6NtHwxQEy.RVLhuCmliiZcw9hB.CH6v0UX1i9E6r_FZyboWtnzX42mZDrJR4n1u2nGFzYwJrDN_kJ3uHKs4EoV9ESEd5AojHDWSkOs4lKbyRlYwhGrHgB25mZ2xRdBtkHMDupYisNjOJ.QEIXzpK291wKHWTL.VdeTOLqGxsthxoR7AOdnzalMIuUItxagzB14Gw2eZ5PcIZvcgO9C4BouZW4SAg0D0Xhmd4A0MW0an7NqzXM4VDVg6WMgeBHqL54yfHjK4oMkwDUQTvqNH13AKINKbtr5t5JJzfpSN0fmfysA1Z1PdkJROhFkyH1_ZXcoMJp2XbYSk6ZXm69U4j4QCYe_vmkp3NM802bMpohywJRxYstmfIxinJukmZOEiSClAk1MhRGVlj60w8ggV29QYa_pdqUjTm0DwYZQF1Z_NVkhVXVv7bQMpRQJPIMwf3TggPPHVAMA1tk0OdPFOCx1207E- \ No newline at end of file diff --git a/scripts/SearchMonkey-yQP.0.txt b/scripts/SearchMonkey-yQP.0.txt index e42a04e160..dcfc31ad19 100644 --- a/scripts/SearchMonkey-yQP.0.txt +++ b/scripts/SearchMonkey-yQP.0.txt @@ -1 +1 @@ -bzN6aQzSJBM8jb6JDpNRvtfEMpxOC6r2ffo5VJf0ah_Q3kXs8gwvDzGy0KGHkwDDijfnJAwhb.BIcFihUZVWe.vAy2xZZN8XUMxHwc16HwCsgDyOC9sH5WzOV0dvJcVZ.9ipAgI7RuXsAvZdJv90N89iOh1WmD6QwWyzyvnu.FjQDrQH1DlGwFs3ZNzY5lsd5uYhtJ3puBXrzSmGcR68_7OEw4QzAV9SyPSHSskXF56cpH8pUey8WiQieM4X_uuKsMjQfWEUdqNb6teXDplvPDRqHwP5rC6X1_oHBiocfgWiBfUfKOXE1g5J.JtqXYIBee8ROyx3sVIc7V2I0eotZCCiCJ1k74ru2OGC9UhX__ZESGrp9b0JZGZFO6w97IL1Y3BTgVXNox8L3FcFjl11s7YcYBhc_3e3WbJA4pZzczPzd0ouZiCjUcBCZXNu6fnM6XerBbsVj584ZbPdjQ6A5TcrED8dTcFdgfMWlMu7bHsE7e0QIJYmc2g5NWeur2ovAOPVxhELrvnJ6X6Z.06vAmwdJcl4hyYRVqA.9QynHlH2dezXS5y0eKXFUzg.tHNqZboEGutLL316mZQYvwZwATZFc8iO3EuiNV3MWbiCrLX.n3nbXp82A4v7Bv.PVJoeOTmiPmq8vuxts8nUEPf7gA3j6.DmlDvfZQNx9.WNmNFps0B08hzDMvKX98.ft9.GJlftPCYCk2qHRtWm3tjB2R9O6mF6XYvOLUK7aQ4rz5oCxHwmrF.n56G07MS5GS1pjV3ByUO88PI1i_rPbim_Up0jIO5q7PqXudyFE.nG0Dc8yaExZk7PryBfSHk2yMQVXcBjy3XQBVmrIwPwKs.YUFC1qLSThfA8UNckik2xuDZKvf29xpGvHlMbH67UV5HhY5CTeqlgvapRThmfrexqaBTTPPqR.Sy3Pvr9vHX.0UC6kNCTlxW3CExrx9EipRKUvRVClNLEG6M9hm5MQkdfgmd2Dmj5DmjcrZkWOqnNfLn_mtYdoD3nK4zCk.NZwXTFlx5FVr5bOzyncalNdb77qLEH9E9R8d2KUA4Axljx29kycILhZCvy3Qz22Vz_M72lVFKQAFnGlERRS7NLu2rB00e.MNeH9aB01uj.y9UHpfjTAwOJSFEBf7yKRCkVzqFpGAQo7txlC3NRgSyI3kQtW0WeWiNzghBv8c_5iXWkXqFyRfVZUCw2qqow3BF6SDtkhXAr8d.JrprGdG67U66ZD3JB10OLmmAaDiiCr81eVOkrsz3ONdigZOlP7RrYtodAORnheCZ10SAYbaru0sKmsJx4sB41QKn79dieWs5oihI5Rr3jUzPjfYgav5jeEfUYz5qHTtmps4vVJjt9s4zueRiT8AYzg.Xv.wdC1dvBr_kpGxwrkMEZJ0QfZkH.TDWBSWyxeG9gtuKd1gy9CGQTXlLvonJWHwK9gwWZwRKIanV4gnMfWz4pvhGixzEaiRU6g9giKYHpVKe.w0cwPfSDIhbBYqrlvuxkSTXfuFNyTpHM0Mgc6PMNnH6GooeLVK3IO2M8dRdDbL7EHykIJWe85pm5BxSqFTcWXn1nGuVWQV.F.J1XYJj1KheT725MVRlrE3sH.MgY6m4hKCUXT7mIgJ6xsfAQ8dWn7V1fCpqoIYub55iw_dg8yfZ7Yfgwj9bqN81lvTWQzBMLKYpG6pOh37JsTikpXa9kTSJfbJm0_GYZv_Bu10D1WqiO0UCvJXrlqkl5F610fkXkhwRXvmIQL2Mv_R71zSKqMr1g5RmnNifUv43jpXoOWmOKscg59pv8eOyb2JG26BtyVS2XOTDw6pHpHKuksqRKt62i1z83uv_ve5rO0zIKeMnWGlvXKHn8ld3fqGyJvqZ7wqYpnV_LTE3p73XCLEeniClXyk5Q_Icu1PgakYh3GIz8RVBjbjgrZIsvvkEp0Kgeo6oFY0wnboIwDlaUVHIue1nPkuAIsVk9i_IJWeqoRV0eO0wUGWgQ5.HT9RzcKdFVe2kl84RKuQkvoibiCfGlfTXpOfLOZtwsfl2TuNgZtP5oG1Wfsgi6g2a1N8B2WHYN8kZuG8pMnc4NQDIoO8BDnz89lDt7Y9JCslIM3O2Y25EGsylNKamKPJZr.ZSvvTVJG5sxftLxvF8vc8h5_pJD9Akj.84CjqQyfsnzFqc_.EqBaRVSy35wHHrdWTBsvjcobtSed8wXs.5En6HdubdATcgthozHWMEMsUdA29XkenPic2cR.8bQ5VdGZ2_YkJIXrxgt_XoEFFB8tgy061cghyL2fc2fHMQm4KBEc1vjkZjwRo9adWbg9dzAl782AwKC.C72bw-- \ No newline at end of file +8Yd1y.bSJBPj3Ul5NjhQHFX0dN0NuJAfBObEdgIY2QDh0bVXkzcJbNlBamPSFBZqHojxbPzIj5GlY3XdxGMY6ttYzBHvc_FK5krngYtlLSmBtjRArxI_bBfngIxeI2kFC3wPvHIdzp8gygRp2.IlDahWHABFhAPrPrxAkAOqv6O3tKUTTzcnZX22eOdoXVXQSMiphlDQIxpfbdpLnduBvMxvI.hwrfAW4iIVY7iBjkdnrtdAVj4N2.u65khGuAwaX9i6Buca3XQJm601Atf6fjM57yOFA0.laixrOss1_F36iqrc4mOeWnYI_UDw8SgIrXroswrJ.KwXlqCdICxel3Ui0hfrOoGnCt4HHT9tiObu9VG.GxM2KQ_tjb1LwFFX0WEisFKXfQwpR_2NU..0j1icWhnmPHFJGsImvX1dFgeTqcNvoAcfZ0y9c8KQKzV5CbQeg9_oPC7uviIdxQK2lJ7SzgRfZAw4FDeDXKDxuVZRE7jZYQEWtkmp9dFlFLM_L0dPk4kiJuRrRPJ8DAyWSiex_ib1mJ3bHAxbsEcWoUunIOivWVdZDudCBath8AdoAQ0P8_f.fl8jYgbZil49Qhg.WmFD_H0w7ikdEi1iHsWnjSrDORtAjENGvoEje0h.gMBf38FbQ6vW2BbKC.RBKp.cQhVPvDHel1UFtqZ8IJm7mTP0BDSDG2iFJp1_N7L5MUoUxEwgskMxeQf99vE1UybdR4q0kbx6i_RR3_6.AQ5QKk1EBeKAfnVYDdwcLGVgWd9JxxvekkL7Scl1ncZ9ViLvlC3Hfrbtrm2Q5rr17pIG6L.a6gDKKH1NGgapyLUCVtKZ27Ysd9ExMF1yHfMAyOKL5I7KaJmZTZnxWQ9ex.hHS6tZ9WjPFhjvpve7H_mB8ZXNBdEc4bL.iRdknHNe3WSSgCLWf2RVFZ4wmVMYW4KwGpIp7iGbaUDBYdBFkcCmv6zeneEsLGJHUYipsay5unopuFyBe611pwFRNHZ3XznmqaK8TXl18k_PCmQ6g93.fXFeWKmszw_FArltYuXHNIm3zwRobvDo7Rp0znnt76Q0ha3q5WHggFd6.QmC6jywGLpki_09v0Pc6qGh4gpGt1vZeZrA1OGQ7VSB7Muo4Mr4TbQU_6342nXeG0tBImIanPZsQrew1.tOmAfn16UpzcCuEC3NWw99yipIaEZirdr4teITB7xX3x6UGRcjtoAlz8oo6VEYaFX7ybG6Bo.K4hspnJLWH6jKK4hcpYedE2qSB0W4z_ieFy6Y.2qrx8_3CL1_8h5w6PjXOFTmsyk0v0DXQVuGh8QxPgPVyrWyDzlXJZ.5_mHTohGRGCI41I6jGJcCOh3qEQZKF2VYb.3o00Le9YlXxpBIBh7rBw5vNypp9jSd.W6VPnQ53xM6QzVbYW4OV3gkVE__AgvKNUzfRHiK9dN7evwvKX66W4tUPGQapjGbRWnFc3Q_0__oMYTtSR3EMxs0Lvkjh87s0SMxy0gzvVCfNt4VrdZCzdBd8N8Tcj5Pc4KJ09ikPtNB3V8i6jtcVUuKzs32B37O6AA2iOydQdsPDEhfkDA0S_ocu3DqqBsJOYmzjRq39e1WFhlRijNftxHF6DRvzpSIIm5VzcwIg8LLl4zbHyeRXEmBDp.KvlfP_.z2IUqilhGeccCmV2XFD_VFidZclzscmceMmuBOXYmaplSW3sX94eM7mp2dyDjVXtR4igukNU8Fabaqilu98OKIv9mLdTlE9u7t25KNqMHQQOsYNM4BUocalSN1K3JOot544vz9VbWJfIljF2L6DCduJd6h9aDH5wLMjljRqrteltA3yz86ensnOZ5wmU8X3NMpPN.OCXM8zxqdhEGxE_jeXkpf4AKIFWYrn8zH84sFU60gpy3xMOleKK6NfrFDRdzxkBIJGV7yhBaDi1_0iZuwm8hVLFe2odNyEKbllCeXYpeMJwe3w_e7XQD1T2Zv4bvK69qYPhmkngPs7_nCYYUFWKlvkg0njZyxn3kNSTONHjzrLSlTWMvGobei1GV74wJzWmmZpC1yQNOe_8Stjbj5Lg47iELys5kCMWU1NyIQf16AT35xTlPCYJ_RNVy3yDNeh5kqy9AMX_HIJOHw8xwJEUoiqKzWzLV.BWmpzcny9_7P2naXBrzRlOYmYyWUtp.P0gGNxLZXtEaKKGgdQB.fYXUyuKH0ptXqj1YCl1g1KWo3.AwndjDy0PE8ZYCaCjz.EyXqx.8bvfJycccGRw5RVU74aydE0DRCC3vF6VI9qbPWK89HNTMWxPSSTHdChY6yAhNsc5UhDwsAmhZ_UIYynZ8AM_oCS232.einbw9fYI4X6yZm_fD60DJ1FsBweU9ivf3Y4X2ucLFY8xPp_8SxZ5UtaP67TKflzMYjuvhGXAUF9.1u8ZKJGOliFmMxIwJ7lPJs93HfZgLN2eyH6F.rZjREeyd0fbsRzZ_vMEs4fx6sX4eIGVoyVFpO5b11kxnBqlKnATI_nw1.exkl5sQj00clwphsecXiVLaDFCEjG94ve_1cw2foqQUoX6pUfqr_hSSpnacdacPclbxWPehuN5LpjMso_5b4v.rj4s9VtzRqxovBinIgBdTFAH560aN5f7wuN5ZZT_BT5aCFNwQBYoDfCTaU9jw3aaXU29vEJmYZcvC9WCpU0RTntciGlx8rIbagu7cUGrYFvLbU2ZekazCMklPO5Sno_z5zzxLnTpFxesNoreOj7M3Cp1RHKUmqAog04bYC9kPFvH_q.jF2g507LEN3nPL9EJUx460UG_o4HRQOhDi2YrmrHk.gLZECgnMwCN770fhL \ No newline at end of file From 945bbf00dc9ee106359e9387956c72c1290d12fc Mon Sep 17 00:00:00 2001 From: CiaranG Date: Mon, 9 Mar 2009 20:24:56 +0000 Subject: [PATCH 36/58] PostgreSQL - a couple more GROUP BY queries that needed to be explicit --- actions/favorited.php | 2 +- lib/topposterssection.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/actions/favorited.php b/actions/favorited.php index 5082f4a4eb..231b978973 100644 --- a/actions/favorited.php +++ b/actions/favorited.php @@ -178,7 +178,7 @@ class FavoritedAction extends Action $qry = 'SELECT notice.*, '. $weightexpr . ' as weight ' . 'FROM notice JOIN fave ON notice.id = fave.notice_id ' . - 'GROUP BY fave.notice_id ' . + 'GROUP BY id,profile_id,uri,content,rendered,url,created,notice.modified,reply_to,is_local,source ' . 'ORDER BY weight DESC'; $offset = ($this->page - 1) * NOTICES_PER_PAGE; diff --git a/lib/topposterssection.php b/lib/topposterssection.php index 4bd59ac797..1a2ce00140 100644 --- a/lib/topposterssection.php +++ b/lib/topposterssection.php @@ -51,7 +51,7 @@ class TopPostersSection extends ProfileSection $qry = 'SELECT profile.*, count(*) as value ' . 'FROM profile JOIN notice ON profile.id = notice.profile_id ' . (common_config('public', 'localonly') ? 'WHERE is_local = 1 ' : '') . - 'GROUP BY profile.id ' . + 'GROUP BY profile.id,nickname,fullname,profileurl,homepage,bio,location,profile.created,profile.modified,textsearch ' . 'ORDER BY value DESC '; $limit = PROFILES_PER_SECTION; From c6cd87c106b763ed5610dae64e5a02ba86609ece Mon Sep 17 00:00:00 2001 From: Eric Helgeson Date: Mon, 9 Mar 2009 20:01:35 -0500 Subject: [PATCH 37/58] Changed all $config[][] calls to common_config() --- actions/finishopenidlogin.php | 3 +-- actions/noticesearchrss.php | 3 +-- actions/publicrss.php | 5 ++--- actions/remotesubscribe.php | 4 +--- lib/mail.php | 7 +++---- lib/omb.php | 1 - lib/searchaction.php | 4 +--- lib/twitter.php | 3 +-- lib/util.php | 11 ++++------- 9 files changed, 14 insertions(+), 27 deletions(-) diff --git a/actions/finishopenidlogin.php b/actions/finishopenidlogin.php index 6d92cb9aae..52d9be29c1 100644 --- a/actions/finishopenidlogin.php +++ b/actions/finishopenidlogin.php @@ -62,9 +62,8 @@ class FinishopenidloginAction extends Action if ($this->error) { $this->element('div', array('class' => 'error'), $this->error); } else { - global $config; $this->element('div', 'instructions', - sprintf(_('This is the first time you\'ve logged into %s so we must connect your OpenID to a local account. You can either create a new account, or connect with your existing account, if you have one.'), $config['site']['name'])); + sprintf(_('This is the first time you\'ve logged into %s so we must connect your OpenID to a local account. You can either create a new account, or connect with your existing account, if you have one.'), common_config('site', 'name'))); } } diff --git a/actions/noticesearchrss.php b/actions/noticesearchrss.php index 7172977ee7..0f98ed04bb 100644 --- a/actions/noticesearchrss.php +++ b/actions/noticesearchrss.php @@ -82,10 +82,9 @@ class NoticesearchrssAction extends Rss10Action function getChannel() { - global $config; $q = $this->trimmed('q'); $c = array('url' => common_local_url('noticesearchrss', array('q' => $q)), - 'title' => $config['site']['name'] . sprintf(_(' Search Stream for "%s"'), $q), + 'title' => common_config('site', 'name') . sprintf(_(' Search Stream for "%s"'), $q), 'link' => common_local_url('noticesearch', array('q' => $q)), 'description' => sprintf(_('All updates matching search term "%s"'), $q)); return $c; diff --git a/actions/publicrss.php b/actions/publicrss.php index c358779971..77e26e0f4c 100644 --- a/actions/publicrss.php +++ b/actions/publicrss.php @@ -84,12 +84,11 @@ class PublicrssAction extends Rss10Action */ function getChannel() { - global $config; $c = array( 'url' => common_local_url('publicrss') - , 'title' => sprintf(_('%s Public Stream'), $config['site']['name']) + , 'title' => sprintf(_('%s Public Stream'), common_config('site', 'name')) , 'link' => common_local_url('public') - , 'description' => sprintf(_('All updates for %s'), $config['site']['name'])); + , 'description' => sprintf(_('All updates for %s'), common_config('site', 'name'))); return $c; } diff --git a/actions/remotesubscribe.php b/actions/remotesubscribe.php index a2e01bd3ae..af130f4258 100644 --- a/actions/remotesubscribe.php +++ b/actions/remotesubscribe.php @@ -333,8 +333,6 @@ class RemotesubscribeAction extends Action function requestAuthorization($user, $omb, $token, $secret) { - global $config; # for license URL - $con = omb_oauth_consumer(); $tok = new OAuthToken($token, $secret); @@ -358,7 +356,7 @@ class RemotesubscribeAction extends Action $req->set_parameter('omb_listenee', $user->uri); $req->set_parameter('omb_listenee_profile', common_profile_url($user->nickname)); $req->set_parameter('omb_listenee_nickname', $user->nickname); - $req->set_parameter('omb_listenee_license', $config['license']['url']); + $req->set_parameter('omb_listenee_license', common_config('license', 'url')); $profile = $user->getProfile(); if (!$profile) { diff --git a/lib/mail.php b/lib/mail.php index 9fa86de5cc..dde7571ebe 100644 --- a/lib/mail.php +++ b/lib/mail.php @@ -50,10 +50,9 @@ function mail_backend() static $backend = null; if (!$backend) { - global $config; - $backend = Mail::factory($config['mail']['backend'], - ($config['mail']['params']) ? - $config['mail']['params'] : + $backend = Mail::factory(common_config('mail', 'backend'), + (common_config('mail', 'params')) ? + common_config('mail', 'params') : array()); if (PEAR::isError($backend)) { common_server_error($backend->getMessage(), 500); diff --git a/lib/omb.php b/lib/omb.php index c302a7b649..878c735dae 100644 --- a/lib/omb.php +++ b/lib/omb.php @@ -251,7 +251,6 @@ function omb_broadcast_profile($profile) function omb_update_profile($profile, $remote_profile, $subscription) { - global $config; # for license URL $user = User::staticGet($profile->id); $con = omb_oauth_consumer(); $token = new OAuthToken($subscription->token, $subscription->secret); diff --git a/lib/searchaction.php b/lib/searchaction.php index df68764459..c762db16f0 100644 --- a/lib/searchaction.php +++ b/lib/searchaction.php @@ -110,8 +110,6 @@ class SearchAction extends Action function showForm($error=null) { - global $config; - $q = $this->trimmed('q'); $page = $this->trimmed('page', 1); $this->elementStart('form', array('method' => 'get', @@ -122,7 +120,7 @@ class SearchAction extends Action $this->element('legend', null, _('Search site')); $this->elementStart('ul', 'form_data'); $this->elementStart('li'); - if (!isset($config['site']['fancy']) || !$config['site']['fancy']) { + if (!common_config('site', 'fancy')) { $this->hidden('action', $this->trimmed('action')); } $this->input('q', 'Keyword(s)', $q); diff --git a/lib/twitter.php b/lib/twitter.php index deb6fd276b..a3929524ba 100644 --- a/lib/twitter.php +++ b/lib/twitter.php @@ -224,7 +224,6 @@ function is_twitter_bound($notice, $flink) { function broadcast_twitter($notice) { - global $config; $success = true; $flink = Foreign_link::getByUserID($notice->profile_id, @@ -248,7 +247,7 @@ function broadcast_twitter($notice) CURLOPT_POSTFIELDS => array( 'status' => $statustxt, - 'source' => $config['integration']['source'] + 'source' => common_config('integration', 'source') ), CURLOPT_RETURNTRANSFER => true, CURLOPT_FAILONERROR => true, diff --git a/lib/util.php b/lib/util.php index ca9006d64e..6341438cae 100644 --- a/lib/util.php +++ b/lib/util.php @@ -72,8 +72,7 @@ function common_timezone() } } - global $config; - return $config['site']['timezone']; + return common_config('site', 'timezone'); } function common_language() @@ -737,9 +736,8 @@ function common_local_url($action, $args=null, $params=null, $fragment=null) function common_path($relative) { - global $config; - $pathpart = ($config['site']['path']) ? $config['site']['path']."/" : ''; - return "http://".$config['site']['server'].'/'.$pathpart.$relative; + $pathpart = (common_config('site', 'path')) ? common_config('site', 'path')."/" : ''; + return "http://".common_config('site', 'server').'/'.$pathpart.$relative; } function common_date_string($dt) @@ -992,8 +990,7 @@ function common_ensure_syslog() { static $initialized = false; if (!$initialized) { - global $config; - openlog($config['syslog']['appname'], 0, LOG_USER); + openlog(common_config('syslog', 'appname'), 0, LOG_USER); $initialized = true; } } From 91980c73a76bcbedd5f23a3232988a32aa8c7127 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 10 Mar 2009 16:15:57 -0700 Subject: [PATCH 38/58] Updates to the API to improve Atom feeds --- actions/twitapidirect_messages.php | 22 ++++-- actions/twitapifavorites.php | 14 ++-- actions/twitapistatuses.php | 53 ++++++++++----- lib/common.php | 3 +- lib/router.php | 8 +-- lib/twitterapi.php | 103 ++++++----------------------- 6 files changed, 90 insertions(+), 113 deletions(-) diff --git a/actions/twitapidirect_messages.php b/actions/twitapidirect_messages.php index ce98bf6ec2..7101db8df5 100644 --- a/actions/twitapidirect_messages.php +++ b/actions/twitapidirect_messages.php @@ -38,7 +38,6 @@ class Twitapidirect_messagesAction extends TwitterapiAction function show_messages($args, $apidata, $type) { - $user = $apidata['user']; $count = $this->arg('count'); @@ -102,7 +101,17 @@ class Twitapidirect_messagesAction extends TwitterapiAction $this->show_rss_dmsgs($message, $title, $link, $subtitle); break; case 'atom': - $this->show_atom_dmsgs($message, $title, $link, $subtitle); + $selfuri = common_root_url() . 'api/direct_messages'; + $selfuri .= ($type == 'received') ? '.atom' : '/sent.atom'; + $taguribase = common_config('integration', 'taguri'); + + if ($type == 'sent') { + $id = "tag:$taguribase:SentDirectMessages:" . $user->id; + } else { + $id = "tag:$taguribase:DirectMessages:" . $user->id; + } + + $this->show_atom_dmsgs($message, $title, $link, $subtitle, $selfuri, $id); break; case 'json': $this->show_json_dmsgs($message); @@ -261,16 +270,17 @@ class Twitapidirect_messagesAction extends TwitterapiAction } - function show_atom_dmsgs($message, $title, $link, $subtitle) + function show_atom_dmsgs($message, $title, $link, $subtitle, $selfuri, $id) { $this->init_document('atom'); $this->element('title', null, $title); - $siteserver = common_config('site', 'server'); - $this->element('id', null, "tag:$siteserver,2008:DirectMessage"); + $this->element('id', null, $id); $this->element('link', array('href' => $link, 'rel' => 'alternate', 'type' => 'text/html'), null); - $this->element('updated', null, common_date_iso8601(strftime('%c'))); + $this->element('link', array('href' => $selfuri, 'rel' => 'self', + 'type' => 'application/atom+xml'), null); + $this->element('updated', null, common_date_iso8601('now')); $this->element('subtitle', null, $subtitle); if (is_array($message)) { diff --git a/actions/twitapifavorites.php b/actions/twitapifavorites.php index 737b7229f0..31dce341b7 100644 --- a/actions/twitapifavorites.php +++ b/actions/twitapifavorites.php @@ -61,10 +61,9 @@ class TwitapifavoritesAction extends TwitterapiAction } $sitename = common_config('site', 'name'); - $siteserver = common_config('site', 'server'); - $title = sprintf(_('%s / Favorites from %s'), $sitename, $user->nickname); - $id = "tag:$siteserver:favorites:".$user->id; + $taguribase = common_config('integration', 'taguri'); + $id = "tag:$taguribase:Favorites:".$user->id; $link = common_local_url('favorites', array('nickname' => $user->nickname)); $subtitle = sprintf(_('%s updates favorited by %s / %s.'), $sitename, $profile->getBestName(), $user->nickname); @@ -76,7 +75,14 @@ class TwitapifavoritesAction extends TwitterapiAction $this->show_rss_timeline($notice, $title, $link, $subtitle); break; case 'atom': - $this->show_atom_timeline($notice, $title, $id, $link, $subtitle); + if (isset($apidata['api_arg'])) { + $selfuri = $selfuri = common_root_url() . + 'api/favorites/' . $apidata['api_arg'] . '.atom'; + } else { + $selfuri = $selfuri = common_root_url() . + 'api/favorites.atom'; + } + $this->show_atom_timeline($notice, $title, $id, $link, $subtitle, null, $selfuri); break; case 'json': $this->show_json_timeline($notice); diff --git a/actions/twitapistatuses.php b/actions/twitapistatuses.php index 63e29068b1..b50a17abde 100644 --- a/actions/twitapistatuses.php +++ b/actions/twitapistatuses.php @@ -29,10 +29,12 @@ class TwitapistatusesAction extends TwitterapiAction parent::handle($args); $sitename = common_config('site', 'name'); - $siteserver = common_config('site', 'server'); $title = sprintf(_("%s public timeline"), $sitename); - $id = "tag:$siteserver:Statuses"; + + $taguribase = common_config('integration', 'taguri'); + $id = "tag:$taguribase:PublicTimeline"; $link = common_root_url(); + $subtitle = sprintf(_("%s updates from everyone!"), $sitename); // Number of public statuses to return by default -- Twitter sends 20 @@ -70,7 +72,8 @@ class TwitapistatusesAction extends TwitterapiAction $this->show_rss_timeline($notice, $title, $link, $subtitle); break; case 'atom': - $this->show_atom_timeline($notice, $title, $id, $link, $subtitle); + $selfuri = common_root_url() . 'api/statuses/public_timeline.atom'; + $this->show_atom_timeline($notice, $title, $id, $link, $subtitle, null, $selfuri); break; case 'json': $this->show_json_timeline($notice); @@ -114,7 +117,6 @@ class TwitapistatusesAction extends TwitterapiAction } $since = strtotime($this->arg('since')); - $user = $this->get_user($apidata['api_arg'], $apidata); $this->auth_user = $user; @@ -124,12 +126,10 @@ class TwitapistatusesAction extends TwitterapiAction } $profile = $user->getProfile(); - $sitename = common_config('site', 'name'); - $siteserver = common_config('site', 'server'); - $title = sprintf(_("%s and friends"), $user->nickname); - $id = "tag:$siteserver:friends:" . $user->id; + $taguribase = common_config('integration', 'taguri'); + $id = "tag:$taguribase:FriendsTimeline:" . $user->id; $link = common_local_url('all', array('nickname' => $user->nickname)); $subtitle = sprintf(_('Updates from %1$s and friends on %2$s!'), $user->nickname, $sitename); @@ -143,7 +143,14 @@ class TwitapistatusesAction extends TwitterapiAction $this->show_rss_timeline($notice, $title, $link, $subtitle); break; case 'atom': - $this->show_atom_timeline($notice, $title, $id, $link, $subtitle); + if (isset($apidata['api_arg'])) { + $selfuri = $selfuri = common_root_url() . + 'api/statuses/friends_timeline/' . $apidata['api_arg'] . '.atom'; + } else { + $selfuri = $selfuri = common_root_url() . + 'api/statuses/friends_timeline.atom'; + } + $this->show_atom_timeline($notice, $title, $id, $link, $subtitle, null, $selfuri); break; case 'json': $this->show_json_timeline($notice); @@ -199,10 +206,9 @@ class TwitapistatusesAction extends TwitterapiAction $since = strtotime($this->arg('since')); $sitename = common_config('site', 'name'); - $siteserver = common_config('site', 'server'); - $title = sprintf(_("%s timeline"), $user->nickname); - $id = "tag:$siteserver:user:".$user->id; + $taguribase = common_config('integration', 'taguri'); + $id = "tag:$taguribase:UserTimeline:".$user->id; $link = common_local_url('showstream', array('nickname' => $user->nickname)); $subtitle = sprintf(_('Updates from %1$s on %2$s!'), $user->nickname, $sitename); @@ -224,7 +230,14 @@ class TwitapistatusesAction extends TwitterapiAction $this->show_rss_timeline($notice, $title, $link, $subtitle, $suplink); break; case 'atom': - $this->show_atom_timeline($notice, $title, $id, $link, $subtitle, $suplink); + if (isset($apidata['api_arg'])) { + $selfuri = $selfuri = common_root_url() . + 'api/statuses/user_timeline/' . $apidata['api_arg'] . '.atom'; + } else { + $selfuri = $selfuri = common_root_url() . + 'api/statuses/user_timeline.atom'; + } + $this->show_atom_timeline($notice, $title, $id, $link, $subtitle, $suplink, $selfuri); break; case 'json': $this->show_json_timeline($notice); @@ -347,10 +360,9 @@ class TwitapistatusesAction extends TwitterapiAction $profile = $user->getProfile(); $sitename = common_config('site', 'name'); - $siteserver = common_config('site', 'server'); - $title = sprintf(_('%1$s / Updates replying to %2$s'), $sitename, $user->nickname); - $id = "tag:$siteserver:replies:".$user->id; + $taguribase = common_config('integration', 'taguri'); + $id = "tag:$taguribase:Replies:".$user->id; $link = common_local_url('replies', array('nickname' => $user->nickname)); $subtitle = sprintf(_('%1$s updates that reply to updates from %2$s / %3$s.'), $sitename, $user->nickname, $profile->getBestName()); @@ -388,7 +400,14 @@ class TwitapistatusesAction extends TwitterapiAction $this->show_rss_timeline($notices, $title, $link, $subtitle); break; case 'atom': - $this->show_atom_timeline($notices, $title, $id, $link, $subtitle); + if (isset($apidata['api_arg'])) { + $selfuri = $selfuri = common_root_url() . + 'api/statuses/replies/' . $apidata['api_arg'] . '.atom'; + } else { + $selfuri = $selfuri = common_root_url() . + 'api/statuses/replies.atom'; + } + $this->show_atom_timeline($notices, $title, $id, $link, $subtitle, null, $selfuri); break; case 'json': $this->show_json_timeline($notices); diff --git a/lib/common.php b/lib/common.php index 917fdeafa4..c3d697aeed 100644 --- a/lib/common.php +++ b/lib/common.php @@ -140,7 +140,8 @@ $config = 'user' => false, 'group' => false), 'integration' => - array('source' => 'Laconica'), # source attribute for Twitter + array('source' => 'Laconica', # source attribute for Twitter + 'taguri' => $_server.',2009'), # base for tag URIs 'memcached' => array('enabled' => false, 'server' => 'localhost', diff --git a/lib/router.php b/lib/router.php index 902f25d8a5..50d5a4ee13 100644 --- a/lib/router.php +++ b/lib/router.php @@ -226,7 +226,7 @@ class Router $m->connect('api/statuses/:method/:argument', array('action' => 'api', 'apiaction' => 'statuses'), - array('method' => '(user_timeline|friends_timeline|show|destroy|friends|followers)')); + array('method' => '(user_timeline|friends_timeline|replies|show|destroy|friends|followers)')); // users @@ -257,7 +257,7 @@ class Router } foreach (array('xml', 'json', 'rss', 'atom') as $e) { - $m->connect('api/direct_message/sent.'.$e, + $m->connect('api/direct_messages/sent.'.$e, array('action' => 'api', 'apiaction' => 'direct_messages', 'method' => 'sent.'.$e)); @@ -277,7 +277,7 @@ class Router $m->connect('api/friendships/:method', array('action' => 'api', 'apiaction' => 'friendships'), - array('method' => 'exists(\.(xml|json|rss|atom))')); + array('method' => 'exists(\.(xml|json))')); // Social graph @@ -360,7 +360,7 @@ class Router // user stuff - foreach (array('subscriptions', 'subscribers', + foreach (array('subscriptions', 'subscribers', 'nudge', 'xrds', 'all', 'foaf', 'replies', 'inbox', 'outbox', 'microsummary') as $a) { $m->connect(':nickname/'.$a, diff --git a/lib/twitterapi.php b/lib/twitterapi.php index 1de169a0b1..e7239acd5e 100644 --- a/lib/twitterapi.php +++ b/lib/twitterapi.php @@ -127,8 +127,6 @@ class TwitterapiAction extends Action { $profile = $notice->getProfile(); - - $server = common_config('site', 'server'); $entry = array(); # We trim() to avoid extraneous whitespace in the output @@ -137,8 +135,12 @@ class TwitterapiAction extends Action $entry['title'] = $profile->nickname . ': ' . common_xml_safe_str(trim($notice->content)); $entry['link'] = common_local_url('shownotice', array('notice' => $notice->id)); $entry['published'] = common_date_iso8601($notice->created); - $entry['id'] = "tag:$server,2008:$entry[link]"; + + $taguribase = common_config('integration', 'taguri'); + $entry['id'] = "tag:$taguribase:$entry[link]"; + $entry['updated'] = $entry['published']; + $entry['author'] = $profile->getBestName(); # RSS Item specific $entry['description'] = $entry['content']; @@ -151,7 +153,6 @@ class TwitterapiAction extends Action function twitter_rss_dmsg_array($message) { - $server = common_config('site', 'server'); $entry = array(); $entry['title'] = sprintf('Message from %s to %s', @@ -160,8 +161,12 @@ class TwitterapiAction extends Action $entry['content'] = common_xml_safe_str(trim($message->content)); $entry['link'] = common_local_url('showmessage', array('message' => $message->id)); $entry['published'] = common_date_iso8601($message->created); - $entry['id'] = "tag:$server,2008:$entry[link]"; + + $taguribase = common_config('integration', 'taguri'); + + $entry['id'] = "tag:$taguribase,:$entry[link]"; $entry['updated'] = $entry['published']; + $entry['author'] = $message->getFrom()->getBestName(); # RSS Item specific $entry['description'] = $entry['content']; @@ -242,6 +247,9 @@ class TwitterapiAction extends Action $this->element('published', null, $entry['published']); $this->element('updated', null, $entry['updated']); $this->element('link', array('href' => $entry['link'], 'rel' => 'alternate', 'type' => 'text/html'), null); + $this->elementStart('author'); + $this->element('name', null, $entry['author']); + $this->elementEnd('author'); $this->elementEnd('entry'); } @@ -358,7 +366,7 @@ class TwitterapiAction extends Action $this->end_twitter_rss(); } - function show_atom_timeline($notice, $title, $id, $link, $subtitle=null, $suplink=null) + function show_atom_timeline($notice, $title, $id, $link, $subtitle=null, $suplink=null, $selfuri=null) { $this->init_document('atom'); @@ -366,12 +374,20 @@ class TwitterapiAction extends Action $this->element('title', null, $title); $this->element('id', null, $id); $this->element('link', array('href' => $link, 'rel' => 'alternate', 'type' => 'text/html'), null); + if (!is_null($suplink)) { # For FriendFeed's SUP protocol $this->element('link', array('rel' => 'http://api.friendfeed.com/2008/03#sup', 'href' => $suplink, 'type' => 'application/json')); } + + if (!is_null($selfuri)) { + $this->element('link', array('href' => $selfuri, + 'rel' => 'self', 'type' => 'application/atom+xml'), null); + } + + $this->element('updated', null, common_date_iso8601('now')); $this->element('subtitle', null, $subtitle); if (is_array($notice)) { @@ -634,79 +650,4 @@ class TwitterapiAction extends Action return $source_name; } - function show_extended_profile($user, $apidata) - { - - $this->auth_user = $apidata['user']; - - $profile = $user->getProfile(); - - if (!$profile) { - common_server_error(_('User has no profile.')); - return; - } - - $twitter_user = $this->twitter_user_array($profile, true); - - // Add in extended user fields offered up by this method - $twitter_user['created_at'] = $this->date_twitter($profile->created); - - $subbed = DB_DataObject::factory('subscription'); - $subbed->subscriber = $profile->id; - $subbed_count = (int) $subbed->count() - 1; - - $notices = DB_DataObject::factory('notice'); - $notices->profile_id = $profile->id; - $notice_count = (int) $notices->count(); - - $twitter_user['friends_count'] = (is_int($subbed_count)) ? $subbed_count : 0; - $twitter_user['statuses_count'] = (is_int($notice_count)) ? $notice_count : 0; - - // Other fields Twitter sends... - $twitter_user['profile_background_color'] = ''; - $twitter_user['profile_text_color'] = ''; - $twitter_user['profile_link_color'] = ''; - $twitter_user['profile_sidebar_fill_color'] = ''; - - $faves = DB_DataObject::factory('fave'); - $faves->user_id = $user->id; - $faves_count = (int) $faves->count(); - $twitter_user['favourites_count'] = $faves_count; - - $timezone = 'UTC'; - - if ($user->timezone) { - $timezone = $user->timezone; - } - - $t = new DateTime; - $t->setTimezone(new DateTimeZone($timezone)); - $twitter_user['utc_offset'] = $t->format('Z'); - $twitter_user['time_zone'] = $timezone; - - $following = 'false'; - - if (isset($this->auth_user)) { - if ($this->auth_user->isSubscribed($profile)) { - $following = 'true'; - } - - // Not implemented yet - $twitter_user['notifications'] = 'false'; - } - - $twitter_user['following'] = $following; - - if ($apidata['content-type'] == 'xml') { - $this->init_document('xml'); - $this->show_twitter_xml_user($twitter_user); - $this->end_document('xml'); - } elseif ($apidata['content-type'] == 'json') { - $this->init_document('json'); - $this->show_json_objects($twitter_user); - $this->end_document('json'); - } - - } - } From 5caeeabfc266985c8ac2cc19a2143092f9e1b5fd Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 10 Mar 2009 16:24:46 -0700 Subject: [PATCH 39/58] Updated config.php.sample with example Tag URI configs --- config.php.sample | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config.php.sample b/config.php.sample index c2b27408cd..e9052bbf9e 100644 --- a/config.php.sample +++ b/config.php.sample @@ -165,3 +165,9 @@ $config['sphinx']['port'] = 3312; #Don't enforce the dupe limit #$config['site']['dupelimit'] = -1; +#Base string for minting Tag URIs in Atom feeds. Defaults to +#"yourserver,2009". This needs to be configured properly for your Atom +#feeds to validate. See: http://www.faqs.org/rfcs/rfc4151.html and +#http://taguri.org/ Examples: +#$config['integration']['taguri'] = 'example.net,2008'; +#$config['integration']['taguri'] = 'admin@example.net,2009-03-09' From df07786f28e89474f66a910eeb3d454e3a5b75ba Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 10 Mar 2009 16:48:14 -0700 Subject: [PATCH 40/58] Allow unauthenticated users to view /api/statuses/replies/id.format (they can already see @replies via friends_timeline anyway). --- actions/twitapistatuses.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/twitapistatuses.php b/actions/twitapistatuses.php index b50a17abde..323c4f1f88 100644 --- a/actions/twitapistatuses.php +++ b/actions/twitapistatuses.php @@ -355,8 +355,8 @@ class TwitapistatusesAction extends TwitterapiAction $since_id = $this->arg('since_id'); $before_id = $this->arg('before_id'); + $user = $this->get_user($apidata['api_arg'], $apidata); $this->auth_user = $apidata['user']; - $user = $this->auth_user; $profile = $user->getProfile(); $sitename = common_config('site', 'name'); From a989c58c11004f850ff0d7bb633df570c7f68f45 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 10 Mar 2009 17:20:43 -0700 Subject: [PATCH 41/58] Fix tag URIs in Atom feeds for search thru the API --- actions/twitapisearchatom.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/actions/twitapisearchatom.php b/actions/twitapisearchatom.php index 3ab82bfb64..c0e55df053 100644 --- a/actions/twitapisearchatom.php +++ b/actions/twitapisearchatom.php @@ -229,8 +229,8 @@ class TwitapisearchatomAction extends TwitterapiAction 'xmlns:twitter' => 'http://api.twitter.com/', 'xml:lang' => $lang)); - $year = date('Y'); - $this->element('id', null, "tag:$server,$year:search/$server"); + $taguribase = common_config('integration', 'taguri'); + $this->element('id', null, "tag:$taguribase:search/$server"); $site_uri = common_path(false); @@ -258,6 +258,7 @@ class TwitapisearchatomAction extends TwitterapiAction 'href' => $self_uri)); $this->element('title', null, "$this->query - $sitename Search"); + $this->element('updated', null, common_date_iso8601('now')); // refresh link @@ -308,9 +309,9 @@ class TwitapisearchatomAction extends TwitterapiAction $this->elementStart('entry'); - $year = date('Y', strtotime($notice->created)); + $taguribase = common_config('integration', 'taguri'); - $this->element('id', null, "tag:$server,$year:$notice->id"); + $this->element('id', null, "tag:$taguribase:$notice->id"); $this->element('published', null, common_date_w3dtf($notice->created)); $this->element('link', array('type' => 'text/html', 'rel' => 'alternate', From 1e29cbd6919380aee54b57db62e08c5d1497d763 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 10 Mar 2009 18:17:20 -0700 Subject: [PATCH 42/58] Make search API Atom feeds more valid --- actions/twitapisearchatom.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/actions/twitapisearchatom.php b/actions/twitapisearchatom.php index c0e55df053..c5f724c12f 100644 --- a/actions/twitapisearchatom.php +++ b/actions/twitapisearchatom.php @@ -52,7 +52,6 @@ require_once INSTALLDIR.'/lib/twitterapi.php'; class TwitapisearchatomAction extends TwitterapiAction { - var $notices; var $cnt; var $query; var $lang; @@ -156,6 +155,7 @@ class TwitapisearchatomAction extends TwitterapiAction { // TODO: Support search operators like from: and to:, boolean, etc. + $notices = array(); $notice = new Notice(); // lcase it for comparison @@ -226,6 +226,10 @@ class TwitapisearchatomAction extends TwitterapiAction $this->elementStart('feed', array('xmlns' => 'http://www.w3.org/2005/Atom', + + // XXX: xmlns:twitter causes Atom validation to fail + // It's used for the source attr on notices + 'xmlns:twitter' => 'http://api.twitter.com/', 'xml:lang' => $lang)); @@ -251,7 +255,8 @@ class TwitapisearchatomAction extends TwitterapiAction // self link - $self_uri = $search_uri . '&page=' . $this->page; + $self_uri = $search_uri; + $self_uri .= ($this->page > 1) ? '&page=' . $this->page : ''; $this->element('link', array('type' => 'application/atom+xml', 'rel' => 'self', @@ -317,10 +322,11 @@ class TwitapisearchatomAction extends TwitterapiAction 'rel' => 'alternate', 'href' => $nurl)); $this->element('title', null, common_xml_safe_str(trim($notice->content))); - $this->element('content', array('type' => 'text/html'), $notice->rendered); + $this->element('content', array('type' => 'html'), $notice->rendered); $this->element('updated', null, common_date_w3dtf($notice->created)); $this->element('link', array('type' => 'image/png', - 'rel' => 'image', + // XXX: Twitter uses rel="image" (not valid) + 'rel' => 'related', 'href' => $profile->avatarUrl())); // TODO: Here is where we'd put in a link to an atom feed for threads From 622cc150d86265cbb1dcd35ae11f4941d42ffdeb Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 10 Mar 2009 18:30:58 -0700 Subject: [PATCH 43/58] Fix xml:lang attr --- actions/twitapisearchatom.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/actions/twitapisearchatom.php b/actions/twitapisearchatom.php index c5f724c12f..eb9ab5d8e9 100644 --- a/actions/twitapisearchatom.php +++ b/actions/twitapisearchatom.php @@ -218,7 +218,6 @@ class TwitapisearchatomAction extends TwitterapiAction { // TODO: A9 OpenSearch stuff like search.twitter.com? - $lang = common_config('site', 'language'); $server = common_config('site', 'server'); $sitename = common_config('site', 'name'); @@ -231,7 +230,7 @@ class TwitapisearchatomAction extends TwitterapiAction // It's used for the source attr on notices 'xmlns:twitter' => 'http://api.twitter.com/', - 'xml:lang' => $lang)); + 'xml:lang' => 'en-US')); // XXX Other locales ? $taguribase = common_config('integration', 'taguri'); $this->element('id', null, "tag:$taguribase:search/$server"); @@ -265,6 +264,9 @@ class TwitapisearchatomAction extends TwitterapiAction $this->element('title', null, "$this->query - $sitename Search"); $this->element('updated', null, common_date_iso8601('now')); + // XXX: The below "rel" links are not valid Atom, but it's what + // Twitter does... + // refresh link $refresh_uri = $search_uri . "&since_id=" . $this->max_id; From b9194e792369506cd2514dcad3e26ce483e6b72d Mon Sep 17 00:00:00 2001 From: CiaranG Date: Wed, 11 Mar 2009 09:12:39 +0000 Subject: [PATCH 44/58] Correction to recently added dupe-checking feature - was using wrong config value --- classes/Notice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/Notice.php b/classes/Notice.php index ac4db944f2..1e3b330f26 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -232,7 +232,7 @@ class Notice extends Memcached_DataObject $notice = new Notice(); $notice->profile_id = $profile_id; $notice->content = $content; - $notice->whereAdd('now() - created < ' . common_config('notice', 'dupelimit')); + $notice->whereAdd('now() - created < ' . common_config('site', 'dupelimit')); $cnt = $notice->count(); return ($cnt == 0); } From a547c5f642c23dd4f1c83b4a1500914c0ef1c861 Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Fri, 6 Mar 2009 21:50:19 +0100 Subject: [PATCH 45/58] Fix array access on possibly undefined index. --- lib/omb.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/omb.php b/lib/omb.php index 878c735dae..e8e1acc413 100644 --- a/lib/omb.php +++ b/lib/omb.php @@ -305,7 +305,7 @@ function omb_update_profile($profile, $remote_profile, $subscription) return false; } else { # success! parse_str($result->body, $return); - if ($return['omb_version'] == OMB_VERSION_01) { + if (isset($return['omb_version']) && $return['omb_version'] === OMB_VERSION_01) { return true; } else { return false; From 00c14d22ded3868939f4999daa0a3c3e4203c20e Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Sat, 7 Mar 2009 01:43:55 +0100 Subject: [PATCH 46/58] Remove comparison with member variable of null variable, cleaned code a bit. --- lib/profilelist.php | 12 +++++------- lib/subgroupnav.php | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/profilelist.php b/lib/profilelist.php index 75053b7a42..898200d2db 100644 --- a/lib/profilelist.php +++ b/lib/profilelist.php @@ -89,6 +89,7 @@ class ProfileList extends Widget 'id' => 'profile-' . $this->profile->id)); $user = common_current_user(); + $is_own = !is_null($user) && ($user->id === $this->user->id); $this->out->elementStart('div', 'entity_profile vcard'); @@ -154,7 +155,7 @@ class ProfileList extends Widget $this->out->elementStart('dl', 'entity_tags'); $this->out->elementStart('dt'); - if ($user->id == $this->owner->id) { + if ($is_own) { $this->out->element('a', array('href' => common_local_url('tagother', array('id' => $this->profile->id))), _('Tags')); @@ -183,7 +184,7 @@ class ProfileList extends Widget $this->out->elementEnd('dl'); } - if ($user && $user->id == $this->owner->id) { + if ($is_own) { $this->showOwnerControls($this->profile); } @@ -193,11 +194,11 @@ class ProfileList extends Widget $this->out->elementStart('ul'); - if ($user && $user->id != $this->profile->id) { + if (!$is_own) { # XXX: special-case for user looking at own # subscriptions page $this->out->elementStart('li', 'entity_subscribe'); - if ($user->isSubscribed($this->profile)) { + if (!is_null($user) && $user->isSubscribed($this->profile)) { $usf = new UnsubscribeForm($this->out, $this->profile); $usf->show(); } else { @@ -206,9 +207,6 @@ class ProfileList extends Widget } $this->out->elementEnd('li'); $this->out->elementStart('li', 'entity_block'); - if ($user && $user->id == $this->owner->id) { - $this->showBlockForm(); - } $this->out->elementEnd('li'); } diff --git a/lib/subgroupnav.php b/lib/subgroupnav.php index 5fd8a72a25..31c3ea0b56 100644 --- a/lib/subgroupnav.php +++ b/lib/subgroupnav.php @@ -98,7 +98,7 @@ class SubGroupNav extends Widget $this->user->nickname), $action == 'usergroups', 'nav_usergroups'); - if ($this->user->id == $cur->id) { + if (!is_null($cur) && $this->user->id === $cur->id) { $this->out->menuItem(common_local_url('invite'), _('Invite'), sprintf(_('Invite friends and colleagues to join you on %s'), From c0db74dcfbff431970ae1d829e776f466f1c4091 Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Sat, 7 Mar 2009 02:03:45 +0100 Subject: [PATCH 47/58] Another undefined object member. --- lib/profilelist.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/profilelist.php b/lib/profilelist.php index 898200d2db..766189ab4c 100644 --- a/lib/profilelist.php +++ b/lib/profilelist.php @@ -89,7 +89,7 @@ class ProfileList extends Widget 'id' => 'profile-' . $this->profile->id)); $user = common_current_user(); - $is_own = !is_null($user) && ($user->id === $this->user->id); + $is_own = !is_null($user) && isset($this->user) && ($user->id === $this->user->id); $this->out->elementStart('div', 'entity_profile vcard'); From c0f44ca44d9530c3658d22c0b3ac311a60cbff6c Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Sat, 7 Mar 2009 02:19:38 +0100 Subject: [PATCH 48/58] Check if that $_SERVER param is set before accessing. --- lib/action.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/action.php b/lib/action.php index 812df635e3..45ce56ac01 100644 --- a/lib/action.php +++ b/lib/action.php @@ -819,9 +819,8 @@ class Action extends HTMLOutputter // lawsuit } if ($lm) { header('Last-Modified: ' . date(DATE_RFC1123, $lm)); - $if_modified_since = $_SERVER['HTTP_IF_MODIFIED_SINCE']; - if ($if_modified_since) { - $ims = strtotime($if_modified_since); + if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { + $ims = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']); if ($lm <= $ims) { $if_none_match = $_SERVER['HTTP_IF_NONE_MATCH']; if (!$if_none_match || From 048bc770777f325aea76315f44afedb2daf90f76 Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Sat, 7 Mar 2009 23:22:57 +0100 Subject: [PATCH 49/58] Add nullcheck for foreign profile. --- lib/twitter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/twitter.php b/lib/twitter.php index a3929524ba..7abb401516 100644 --- a/lib/twitter.php +++ b/lib/twitter.php @@ -210,7 +210,7 @@ function save_twitter_friends($user, $twitter_id, $screen_name, $password) function is_twitter_bound($notice, $flink) { // Check to see if notice should go to Twitter - if (($flink->noticesync & FOREIGN_NOTICE_SEND)) { + if ($flink->noticesync & FOREIGN_NOTICE_SEND) { // If it's not a Twitter-style reply, or if the user WANTS to send replies. if (!preg_match('/^@[a-zA-Z0-9_]{1,15}\b/u', $notice->content) || @@ -231,7 +231,7 @@ function broadcast_twitter($notice) // XXX: Not sure WHERE to check whether a notice should go to // Twitter. Should we even put in the queue if it shouldn't? --Zach - if (is_twitter_bound($notice, $flink)) { + if (!is_null($flink) && is_twitter_bound($notice, $flink)) { $fuser = $flink->getForeignUser(); $twitter_user = $fuser->nickname; From 2cbb67c21e77e76a4faa73532751bf2eb8dd44a9 Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Sat, 7 Mar 2009 23:38:42 +0100 Subject: [PATCH 50/58] Define undefined variable. --- actions/userrss.php | 1 + 1 file changed, 1 insertion(+) diff --git a/actions/userrss.php b/actions/userrss.php index a3e5a3aab7..d3bf352d8d 100644 --- a/actions/userrss.php +++ b/actions/userrss.php @@ -53,6 +53,7 @@ class UserrssAction extends Rss10Action $notice = $user->getNotices(0, ($limit == 0) ? NOTICES_PER_PAGE : $limit); + $notices = array(); while ($notice->fetch()) { $notices[] = clone($notice); } From e6a3e6d4511cbda1dc15def14a33073eb96627e0 Mon Sep 17 00:00:00 2001 From: CiaranG Date: Wed, 11 Mar 2009 16:37:03 +0000 Subject: [PATCH 51/58] Updated update_pot.sh to point to renamed file and generated new laconica.po with all the latest translatable text included --- locale/laconica.po | 1173 ++++++++++++++++++++++++++++++++--------- scripts/update_pot.sh | 2 +- 2 files changed, 911 insertions(+), 264 deletions(-) diff --git a/locale/laconica.po b/locale/laconica.po index d3c1dc8097..85b949a089 100644 --- a/locale/laconica.po +++ b/locale/laconica.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-01-25 16:24+0000\n" +"POT-Creation-Date: 2009-03-11 09:33+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -35,17 +35,18 @@ msgid " from " msgstr "" #: ../actions/twitapistatuses.php:478 actions/twitapistatuses.php:412 -#: actions/twitapistatuses.php:347 +#: actions/twitapistatuses.php:347 actions/twitapistatuses.php:363 #, php-format msgid "%1$s / Updates replying to %2$s" msgstr "" #: ../actions/invite.php:168 actions/invite.php:176 actions/invite.php:211 +#: actions/invite.php:218 #, php-format msgid "%1$s has invited you to join them on %2$s" msgstr "" -#: ../actions/invite.php:170 +#: ../actions/invite.php:170 actions/invite.php:220 #, php-format msgid "" "%1$s has invited you to join them on %2$s (%3$s).\n" @@ -77,6 +78,7 @@ msgid "" msgstr "" #: ../lib/mail.php:124 lib/mail.php:124 lib/mail.php:126 lib/mail.php:241 +#: lib/mail.php:236 #, php-format msgid "%1$s is now listening to your notices on %2$s." msgstr "" @@ -93,7 +95,7 @@ msgid "" msgstr "" #: ../actions/twitapistatuses.php:482 actions/twitapistatuses.php:415 -#: actions/twitapistatuses.php:350 +#: actions/twitapistatuses.php:350 actions/twitapistatuses.php:367 #, php-format msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "" @@ -121,47 +123,49 @@ msgstr "" #: actions/allrss.php:60 actions/twitapistatuses.php:155 lib/personal.php:51 #: actions/all.php:65 actions/allrss.php:103 actions/facebookhome.php:164 #: actions/twitapistatuses.php:126 lib/personalgroupnav.php:99 +#: actions/all.php:68 actions/all.php:114 actions/allrss.php:106 +#: actions/facebookhome.php:163 actions/twitapistatuses.php:130 #, php-format msgid "%s and friends" msgstr "" #: ../actions/twitapistatuses.php:49 actions/twitapistatuses.php:49 -#: actions/twitapistatuses.php:33 +#: actions/twitapistatuses.php:33 actions/twitapistatuses.php:32 #, php-format msgid "%s public timeline" msgstr "" -#: ../lib/mail.php:206 lib/mail.php:212 lib/mail.php:411 +#: ../lib/mail.php:206 lib/mail.php:212 lib/mail.php:411 lib/mail.php:412 #, php-format msgid "%s status" msgstr "" #: ../actions/twitapistatuses.php:338 actions/twitapistatuses.php:265 -#: actions/twitapistatuses.php:199 +#: actions/twitapistatuses.php:199 actions/twitapistatuses.php:209 #, php-format msgid "%s timeline" msgstr "" #: ../actions/twitapistatuses.php:52 actions/twitapistatuses.php:52 -#: actions/twitapistatuses.php:36 +#: actions/twitapistatuses.php:36 actions/twitapistatuses.php:38 #, php-format msgid "%s updates from everyone!" msgstr "" -#: ../actions/register.php:213 +#: ../actions/register.php:213 actions/register.php:497 msgid "" "(You should receive a message by email momentarily, with instructions on how " "to confirm your email address.)" msgstr "" -#: ../lib/util.php:257 lib/util.php:273 lib/action.php:605 +#: ../lib/util.php:257 lib/util.php:273 lib/action.php:605 lib/action.php:702 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." "broughtby%%](%%site.broughtbyurl%%). " msgstr "" -#: ../lib/util.php:259 lib/util.php:275 lib/action.php:607 +#: ../lib/util.php:259 lib/util.php:275 lib/action.php:607 lib/action.php:704 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "" @@ -178,6 +182,7 @@ msgid "1-64 lowercase letters or numbers, no punctuation or spaces" msgstr "" #: ../actions/register.php:152 actions/register.php:166 +#: actions/register.php:368 msgid "1-64 lowercase letters or numbers, no punctuation or spaces. Required." msgstr "" @@ -197,6 +202,7 @@ msgid "6 or more characters. Required." msgstr "" #: ../actions/imsettings.php:197 actions/imsettings.php:205 +#: actions/imsettings.php:321 #, php-format msgid "" "A confirmation code was sent to the IM address you added. You must approve %" @@ -204,6 +210,7 @@ msgid "" msgstr "" #: ../actions/emailsettings.php:213 actions/emailsettings.php:231 +#: actions/emailsettings.php:350 msgid "" "A confirmation code was sent to the email address you added. Check your " "inbox (and spam box!) for the code and instructions on how to use it." @@ -233,7 +240,12 @@ msgstr "" #: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228 #: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392 #: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429 -#: actions/twitapiusers.php:32 +#: actions/twitapiusers.php:32 actions/twitapidirect_messages.php:120 +#: actions/twitapifavorites.php:91 actions/twitapifavorites.php:108 +#: actions/twitapistatuses.php:82 actions/twitapistatuses.php:159 +#: actions/twitapistatuses.php:246 actions/twitapistatuses.php:257 +#: actions/twitapistatuses.php:416 actions/twitapistatuses.php:426 +#: actions/twitapistatuses.php:453 msgid "API method not found!" msgstr "" @@ -256,11 +268,14 @@ msgstr "" #: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143 #: actions/twitapihelp.php:52 actions/twitapilaconica.php:172 #: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37 -#: actions/twitapistatuses.php:562 +#: actions/twitapistatuses.php:562 actions/twitapiaccount.php:46 +#: actions/twitapiaccount.php:98 actions/twitapiaccount.php:104 +#: actions/twitapidirect_messages.php:193 actions/twitapifavorites.php:149 +#: actions/twitapistatuses.php:625 actions/twitapitrends.php:87 msgid "API method under construction." msgstr "" -#: ../lib/util.php:324 lib/util.php:340 lib/action.php:568 +#: ../lib/util.php:324 lib/util.php:340 lib/action.php:568 lib/action.php:661 msgid "About" msgstr "" @@ -276,6 +291,7 @@ msgstr "" #: actions/twittersettings.php:85 actions/emailsettings.php:120 #: actions/imsettings.php:127 actions/openidsettings.php:111 #: actions/smssettings.php:133 actions/twittersettings.php:163 +#: actions/twittersettings.php:166 msgid "Add" msgstr "" @@ -298,6 +314,7 @@ msgid "Address" msgstr "" #: ../actions/invite.php:131 actions/invite.php:139 actions/invite.php:176 +#: actions/invite.php:181 msgid "Addresses of friends to invite (one per line)" msgstr "" @@ -332,7 +349,7 @@ msgid "Already subscribed!." msgstr "" #: ../actions/deletenotice.php:54 actions/deletenotice.php:55 -#: actions/deletenotice.php:113 +#: actions/deletenotice.php:113 actions/deletenotice.php:114 msgid "Are you sure you want to delete this notice?" msgstr "" @@ -342,11 +359,13 @@ msgid "Authorize subscription" msgstr "" #: ../actions/login.php:104 ../actions/register.php:178 -#: actions/register.php:192 +#: actions/register.php:192 actions/login.php:218 actions/openidlogin.php:117 +#: actions/register.php:416 msgid "Automatically login in the future; not for shared computers!" msgstr "" #: ../actions/profilesettings.php:65 actions/profilesettings.php:98 +#: actions/profilesettings.php:144 msgid "" "Automatically subscribe to whoever subscribes to me (best for non-humans)" msgstr "" @@ -354,15 +373,17 @@ msgstr "" #: ../actions/avatar.php:32 ../lib/settingsaction.php:90 #: actions/profilesettings.php:34 actions/avatarsettings.php:65 #: actions/showgroup.php:209 lib/accountsettingsaction.php:107 +#: actions/avatarsettings.php:67 actions/showgroup.php:211 msgid "Avatar" msgstr "" #: ../actions/avatar.php:113 actions/profilesettings.php:350 -#: actions/avatarsettings.php:395 +#: actions/avatarsettings.php:395 actions/avatarsettings.php:346 msgid "Avatar updated." msgstr "" #: ../actions/imsettings.php:55 actions/imsettings.php:56 +#: actions/imsettings.php:108 #, php-format msgid "" "Awaiting confirmation on this address. Check your Jabber/GTalk account for a " @@ -370,6 +391,7 @@ msgid "" msgstr "" #: ../actions/emailsettings.php:54 actions/emailsettings.php:55 +#: actions/emailsettings.php:107 msgid "" "Awaiting confirmation on this address. Check your inbox (and spam box!) for " "a message with further instructions." @@ -394,7 +416,7 @@ msgstr "" #: ../actions/updateprofile.php:103 actions/profilesettings.php:216 #: actions/register.php:89 actions/updateprofile.php:104 #: actions/profilesettings.php:205 actions/register.php:174 -#: actions/updateprofile.php:107 +#: actions/updateprofile.php:107 actions/updateprofile.php:109 msgid "Bio is too long (max 140 chars)." msgstr "" @@ -403,7 +425,7 @@ msgid "Can't delete this notice." msgstr "" #: ../actions/updateprofile.php:119 actions/updateprofile.php:120 -#: actions/updateprofile.php:123 +#: actions/updateprofile.php:123 actions/updateprofile.php:125 #, php-format msgid "Can't read avatar URL '%s'" msgstr "" @@ -411,6 +433,7 @@ msgstr "" #: ../actions/password.php:85 ../actions/recoverpassword.php:300 #: actions/profilesettings.php:404 actions/recoverpassword.php:313 #: actions/passwordsettings.php:169 actions/recoverpassword.php:347 +#: actions/passwordsettings.php:174 msgid "Can't save new password." msgstr "" @@ -423,6 +446,7 @@ msgid "Cancel" msgstr "" #: ../lib/openid.php:121 lib/openid.php:121 lib/openid.php:130 +#: lib/openid.php:133 msgid "Cannot instantiate OpenID consumer object." msgstr "" @@ -432,7 +456,7 @@ msgid "Cannot normalize that Jabber ID" msgstr "" #: ../actions/emailsettings.php:181 actions/emailsettings.php:199 -#: actions/emailsettings.php:311 +#: actions/emailsettings.php:311 actions/emailsettings.php:318 msgid "Cannot normalize that email address" msgstr "" @@ -478,7 +502,7 @@ msgstr "" #: ../actions/smssettings.php:245 actions/emailsettings.php:256 #: actions/imsettings.php:230 actions/smssettings.php:253 #: actions/emailsettings.php:379 actions/imsettings.php:361 -#: actions/smssettings.php:374 +#: actions/smssettings.php:374 actions/emailsettings.php:386 msgid "Confirmation cancelled." msgstr "" @@ -492,7 +516,7 @@ msgstr "" msgid "Confirmation code not found." msgstr "" -#: ../actions/register.php:202 +#: ../actions/register.php:202 actions/register.php:473 #, php-format msgid "" "Congratulations, %s! And welcome to %%%%site.name%%%%. From here, you may " @@ -512,7 +536,8 @@ msgid "" msgstr "" #: ../actions/finishopenidlogin.php:91 actions/finishopenidlogin.php:97 -#: actions/finishopenidlogin.php:119 lib/action.php:330 +#: actions/finishopenidlogin.php:119 lib/action.php:330 lib/action.php:403 +#: lib/action.php:406 msgid "Connect" msgstr "" @@ -521,11 +546,12 @@ msgstr "" msgid "Connect existing account" msgstr "" -#: ../lib/util.php:332 lib/util.php:348 lib/action.php:576 +#: ../lib/util.php:332 lib/util.php:348 lib/action.php:576 lib/action.php:669 msgid "Contact" msgstr "" #: ../lib/openid.php:178 lib/openid.php:178 lib/openid.php:187 +#: lib/openid.php:190 #, php-format msgid "Could not create OpenID form: %s" msgstr "" @@ -543,17 +569,18 @@ msgid "Could not follow user: User not found." msgstr "" #: ../lib/openid.php:160 lib/openid.php:160 lib/openid.php:169 +#: lib/openid.php:172 #, php-format msgid "Could not redirect to server: %s" msgstr "" #: ../actions/updateprofile.php:162 actions/updateprofile.php:163 -#: actions/updateprofile.php:166 +#: actions/updateprofile.php:166 actions/updateprofile.php:176 msgid "Could not save avatar info" msgstr "" #: ../actions/updateprofile.php:155 actions/updateprofile.php:156 -#: actions/updateprofile.php:159 +#: actions/updateprofile.php:159 actions/updateprofile.php:163 msgid "Could not save new profile info" msgstr "" @@ -581,6 +608,7 @@ msgstr "" #: actions/imsettings.php:226 actions/smssettings.php:249 #: actions/confirmaddress.php:126 actions/emailsettings.php:375 #: actions/imsettings.php:357 actions/smssettings.php:370 +#: actions/emailsettings.php:382 msgid "Couldn't delete email confirmation." msgstr "" @@ -589,7 +617,7 @@ msgid "Couldn't delete subscription." msgstr "" #: ../actions/twitapistatuses.php:93 actions/twitapistatuses.php:98 -#: actions/twitapistatuses.php:84 +#: actions/twitapistatuses.php:84 actions/twitapistatuses.php:87 msgid "Couldn't find any statuses." msgstr "" @@ -602,7 +630,7 @@ msgstr "" #: ../actions/smssettings.php:206 actions/emailsettings.php:223 #: actions/imsettings.php:195 actions/smssettings.php:214 #: actions/emailsettings.php:337 actions/imsettings.php:311 -#: actions/smssettings.php:325 +#: actions/smssettings.php:325 actions/emailsettings.php:344 msgid "Couldn't insert confirmation code." msgstr "" @@ -614,6 +642,7 @@ msgstr "" #: ../actions/profilesettings.php:184 ../actions/twitapiaccount.php:96 #: actions/profilesettings.php:299 actions/twitapiaccount.php:94 #: actions/profilesettings.php:302 actions/twitapiaccount.php:81 +#: actions/twitapiaccount.php:82 msgid "Couldn't save profile." msgstr "" @@ -625,6 +654,8 @@ msgstr "" #: ../actions/emailsettings.php:280 ../actions/emailsettings.php:294 #: actions/emailsettings.php:298 actions/emailsettings.php:312 #: actions/emailsettings.php:440 actions/emailsettings.php:462 +#: actions/emailsettings.php:447 actions/emailsettings.php:469 +#: actions/smssettings.php:515 actions/smssettings.php:539 msgid "Couldn't update user record." msgstr "" @@ -640,7 +671,8 @@ msgstr "" #: actions/emailsettings.php:411 actions/imsettings.php:252 #: actions/imsettings.php:395 actions/othersettings.php:162 #: actions/profilesettings.php:259 actions/smssettings.php:266 -#: actions/smssettings.php:408 +#: actions/smssettings.php:408 actions/emailsettings.php:287 +#: actions/emailsettings.php:418 msgid "Couldn't update user." msgstr "" @@ -684,23 +716,25 @@ msgid "Currently" msgstr "" #: ../classes/Notice.php:72 classes/Notice.php:86 classes/Notice.php:91 +#: classes/Notice.php:114 #, php-format msgid "DB error inserting hashtag: %s" msgstr "" #: ../lib/util.php:1061 lib/util.php:1110 classes/Notice.php:698 +#: classes/Notice.php:757 #, php-format msgid "DB error inserting reply: %s" msgstr "" #: ../actions/deletenotice.php:41 actions/deletenotice.php:41 -#: actions/deletenotice.php:79 +#: actions/deletenotice.php:79 actions/deletenotice.php:111 msgid "Delete notice" msgstr "" #: ../actions/profilesettings.php:51 ../actions/register.php:172 #: actions/profilesettings.php:84 actions/register.php:186 -#: actions/profilesettings.php:114 +#: actions/profilesettings.php:114 actions/register.php:404 msgid "Describe yourself and your interests in 140 chars" msgstr "" @@ -735,6 +769,7 @@ msgid "Email address, like \"UserName@example.org\"" msgstr "" #: ../actions/invite.php:129 actions/invite.php:137 actions/invite.php:174 +#: actions/invite.php:179 msgid "Email addresses" msgstr "" @@ -754,7 +789,7 @@ msgid "Error authorizing token" msgstr "" #: ../actions/finishopenidlogin.php:253 actions/finishopenidlogin.php:259 -#: actions/finishopenidlogin.php:297 +#: actions/finishopenidlogin.php:297 actions/finishopenidlogin.php:302 msgid "Error connecting user to OpenID." msgstr "" @@ -789,15 +824,17 @@ msgid "Error saving remote profile" msgstr "" #: ../lib/openid.php:226 lib/openid.php:226 lib/openid.php:235 +#: lib/openid.php:238 msgid "Error saving the profile." msgstr "" #: ../lib/openid.php:237 lib/openid.php:237 lib/openid.php:246 +#: lib/openid.php:249 msgid "Error saving the user." msgstr "" #: ../actions/password.php:80 actions/profilesettings.php:399 -#: actions/passwordsettings.php:164 +#: actions/passwordsettings.php:164 actions/passwordsettings.php:169 msgid "Error saving user; invalid." msgstr "" @@ -806,6 +843,7 @@ msgstr "" #: actions/login.php:47 actions/login.php:73 actions/recoverpassword.php:320 #: actions/register.php:108 actions/login.php:112 actions/login.php:138 #: actions/recoverpassword.php:354 actions/register.php:198 +#: actions/login.php:120 msgid "Error setting user." msgstr "" @@ -829,29 +867,31 @@ msgstr "" msgid "Existing nickname" msgstr "" -#: ../lib/util.php:326 lib/util.php:342 lib/action.php:570 +#: ../lib/util.php:326 lib/util.php:342 lib/action.php:570 lib/action.php:663 msgid "FAQ" msgstr "" #: ../actions/avatar.php:115 actions/profilesettings.php:352 -#: actions/avatarsettings.php:397 +#: actions/avatarsettings.php:397 actions/avatarsettings.php:349 msgid "Failed updating avatar." msgstr "" #: ../actions/all.php:61 ../actions/allrss.php:64 actions/all.php:61 #: actions/allrss.php:64 actions/all.php:75 actions/allrss.php:107 +#: actions/allrss.php:110 #, php-format msgid "Feed for friends of %s" msgstr "" #: ../actions/replies.php:65 ../actions/repliesrss.php:80 #: actions/replies.php:65 actions/repliesrss.php:66 actions/replies.php:134 -#: actions/repliesrss.php:71 +#: actions/repliesrss.php:71 actions/replies.php:136 #, php-format msgid "Feed for replies to %s" msgstr "" #: ../actions/tag.php:55 actions/tag.php:55 actions/tag.php:61 +#: actions/tag.php:68 #, php-format msgid "Feed for tag %s" msgstr "" @@ -866,7 +906,7 @@ msgstr "" msgid "Find people on this site" msgstr "" -#: ../actions/login.php:122 +#: ../actions/login.php:122 actions/login.php:247 msgid "" "For security reasons, please re-enter your user name and password before " "changing your settings." @@ -877,6 +917,8 @@ msgstr "" #: actions/profilesettings.php:103 actions/register.php:391 #: actions/showgroup.php:235 actions/showstream.php:262 #: actions/tagother.php:105 lib/groupeditform.php:142 +#: actions/showgroup.php:237 actions/showstream.php:255 +#: actions/tagother.php:104 msgid "Full name" msgstr "" @@ -885,16 +927,17 @@ msgstr "" #: actions/register.php:86 actions/updateprofile.php:94 #: actions/editgroup.php:195 actions/newgroup.php:146 #: actions/profilesettings.php:202 actions/register.php:171 -#: actions/updateprofile.php:97 +#: actions/updateprofile.php:97 actions/updateprofile.php:99 msgid "Full name is too long (max 255 chars)." msgstr "" #: ../lib/util.php:322 lib/util.php:338 lib/action.php:344 lib/action.php:566 +#: lib/action.php:421 lib/action.php:659 msgid "Help" msgstr "" #: ../lib/util.php:298 lib/util.php:314 lib/action.php:322 -#: lib/facebookaction.php:200 +#: lib/facebookaction.php:200 lib/action.php:393 lib/facebookaction.php:213 msgid "Home" msgstr "" @@ -913,7 +956,7 @@ msgid "Homepage is not a valid URL." msgstr "" #: ../actions/emailsettings.php:91 actions/emailsettings.php:98 -#: actions/emailsettings.php:173 +#: actions/emailsettings.php:173 actions/emailsettings.php:178 msgid "I want to post notices by email." msgstr "" @@ -939,13 +982,13 @@ msgid "" "connect it to your OpenID." msgstr "" -#: ../actions/openidsettings.php:45 +#: ../actions/openidsettings.php:45 actions/openidsettings.php:96 msgid "" "If you want to add an OpenID to your account, enter it in the box below and " "click \"Add\"." msgstr "" -#: ../actions/recoverpassword.php:137 +#: ../actions/recoverpassword.php:137 actions/recoverpassword.php:152 msgid "" "If you've forgotten or lost your password, you can get a new one sent to the " "email address you have stored in your account." @@ -958,28 +1001,29 @@ msgid "Incoming email" msgstr "" #: ../actions/emailsettings.php:283 actions/emailsettings.php:301 -#: actions/emailsettings.php:443 +#: actions/emailsettings.php:443 actions/emailsettings.php:450 +#: actions/smssettings.php:518 msgid "Incoming email address removed." msgstr "" #: ../actions/password.php:69 actions/profilesettings.php:388 -#: actions/passwordsettings.php:153 +#: actions/passwordsettings.php:153 actions/passwordsettings.php:158 msgid "Incorrect old password" msgstr "" #: ../actions/login.php:67 actions/login.php:67 actions/facebookhome.php:131 -#: actions/login.php:132 +#: actions/login.php:132 actions/facebookhome.php:130 actions/login.php:114 msgid "Incorrect username or password." msgstr "" -#: ../actions/recoverpassword.php:265 +#: ../actions/recoverpassword.php:265 actions/recoverpassword.php:304 msgid "" "Instructions for recovering your password have been sent to the email " "address registered to your account." msgstr "" #: ../actions/updateprofile.php:114 actions/updateprofile.php:115 -#: actions/updateprofile.php:118 +#: actions/updateprofile.php:118 actions/updateprofile.php:120 #, php-format msgid "Invalid avatar URL '%s'" msgstr "" @@ -990,13 +1034,13 @@ msgid "Invalid email address: %s" msgstr "" #: ../actions/updateprofile.php:98 actions/updateprofile.php:99 -#: actions/updateprofile.php:102 +#: actions/updateprofile.php:102 actions/updateprofile.php:104 #, php-format msgid "Invalid homepage '%s'" msgstr "" #: ../actions/updateprofile.php:82 actions/updateprofile.php:83 -#: actions/updateprofile.php:86 +#: actions/updateprofile.php:86 actions/updateprofile.php:88 #, php-format msgid "Invalid license URL '%s'" msgstr "" @@ -1017,7 +1061,7 @@ msgid "Invalid notice url" msgstr "" #: ../actions/updateprofile.php:87 actions/updateprofile.php:88 -#: actions/updateprofile.php:91 +#: actions/updateprofile.php:91 actions/updateprofile.php:93 #, php-format msgid "Invalid profile URL '%s'." msgstr "" @@ -1041,7 +1085,7 @@ msgstr "" #: ../actions/register.php:111 actions/finishopenidlogin.php:241 #: actions/register.php:103 actions/register.php:121 #: actions/finishopenidlogin.php:279 actions/register.php:193 -#: actions/register.php:211 +#: actions/register.php:211 actions/finishopenidlogin.php:284 msgid "Invalid username or password." msgstr "" @@ -1054,7 +1098,7 @@ msgid "Invitation(s) sent to the following people:" msgstr "" #: ../lib/util.php:306 lib/util.php:322 lib/facebookaction.php:207 -#: lib/subgroupnav.php:103 +#: lib/subgroupnav.php:103 lib/facebookaction.php:220 msgid "Invite" msgstr "" @@ -1062,7 +1106,7 @@ msgstr "" msgid "Invite new users" msgstr "" -#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609 +#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609 lib/action.php:706 #, php-format msgid "" "It runs the [Laconica](http://laconi.ca/) microblogging software, version %" @@ -1076,6 +1120,7 @@ msgid "Jabber ID already belongs to another user." msgstr "" #: ../actions/imsettings.php:62 actions/imsettings.php:63 +#: actions/imsettings.php:120 #, php-format msgid "" "Jabber or GTalk address, like \"UserName@example.org\". First, make sure to " @@ -1097,7 +1142,8 @@ msgstr "" #: actions/profilesettings.php:117 actions/register.php:408 #: actions/showgroup.php:244 actions/showstream.php:271 #: actions/tagother.php:113 lib/groupeditform.php:156 lib/grouplist.php:126 -#: lib/profilelist.php:125 +#: lib/profilelist.php:125 actions/showgroup.php:246 +#: actions/showstream.php:264 actions/tagother.php:112 lib/profilelist.php:123 msgid "Location" msgstr "" @@ -1106,7 +1152,7 @@ msgstr "" #: actions/register.php:92 actions/updateprofile.php:109 #: actions/editgroup.php:201 actions/newgroup.php:152 #: actions/profilesettings.php:208 actions/register.php:177 -#: actions/updateprofile.php:112 +#: actions/updateprofile.php:112 actions/updateprofile.php:114 msgid "Location is too long (max 255 chars)." msgstr "" @@ -1115,18 +1161,20 @@ msgstr "" #: actions/login.php:106 actions/openidlogin.php:77 lib/util.php:326 #: actions/facebooklogin.php:93 actions/login.php:186 actions/login.php:239 #: actions/openidlogin.php:112 lib/action.php:335 lib/facebookaction.php:288 -#: lib/facebookaction.php:315 lib/logingroupnav.php:75 +#: lib/facebookaction.php:315 lib/logingroupnav.php:75 actions/login.php:169 +#: actions/login.php:222 actions/openidlogin.php:121 lib/action.php:412 +#: lib/facebookaction.php:293 lib/facebookaction.php:319 #, php-format msgid "Login" msgstr "" #: ../actions/openidlogin.php:44 actions/openidlogin.php:52 -#: actions/openidlogin.php:62 +#: actions/openidlogin.php:62 actions/openidlogin.php:70 #, php-format msgid "Login with an [OpenID](%%doc.openid%%) account." msgstr "" -#: ../actions/login.php:126 +#: ../actions/login.php:126 actions/login.php:251 #, php-format msgid "" "Login with your username and password. Don't have a username yet? [Register]" @@ -1134,7 +1182,7 @@ msgid "" "%). " msgstr "" -#: ../lib/util.php:308 lib/util.php:324 lib/action.php:332 +#: ../lib/util.php:308 lib/util.php:324 lib/action.php:332 lib/action.php:409 msgid "Logout" msgstr "" @@ -1144,12 +1192,13 @@ msgid "Longer name, preferably your \"real\" name" msgstr "" #: ../actions/login.php:110 actions/login.php:110 actions/login.php:245 -#: lib/facebookaction.php:320 +#: lib/facebookaction.php:320 actions/login.php:228 lib/facebookaction.php:325 msgid "Lost or forgotten password?" msgstr "" #: ../actions/emailsettings.php:80 ../actions/smssettings.php:89 #: actions/emailsettings.php:81 actions/smssettings.php:89 +#: actions/emailsettings.php:139 actions/smssettings.php:150 msgid "Make a new email address for posting to; cancels the old one." msgstr "" @@ -1169,7 +1218,7 @@ msgstr "" msgid "Microblog by %s" msgstr "" -#: ../actions/smssettings.php:304 +#: ../actions/smssettings.php:304 actions/smssettings.php:464 #, php-format msgid "" "Mobile carrier for your phone. If you know a carrier that accepts SMS over " @@ -1179,6 +1228,7 @@ msgstr "" #: ../actions/finishopenidlogin.php:79 ../actions/register.php:188 #: actions/finishopenidlogin.php:85 actions/register.php:202 #: actions/finishopenidlogin.php:107 actions/register.php:429 +#: actions/register.php:430 msgid "My text and files are available under " msgstr "" @@ -1194,7 +1244,8 @@ msgid "New email address for posting to %s" msgstr "" #: ../actions/emailsettings.php:297 actions/emailsettings.php:315 -#: actions/emailsettings.php:465 +#: actions/emailsettings.php:465 actions/emailsettings.php:472 +#: actions/smssettings.php:542 msgid "New incoming email address added." msgstr "" @@ -1214,7 +1265,7 @@ msgstr "" msgid "New password" msgstr "" -#: ../actions/recoverpassword.php:314 +#: ../actions/recoverpassword.php:314 actions/recoverpassword.php:361 msgid "New password successfully saved. You are now logged in." msgstr "" @@ -1224,7 +1275,9 @@ msgstr "" #: actions/login.php:228 actions/profilesettings.php:98 #: actions/register.php:367 actions/showgroup.php:224 #: actions/showstream.php:251 actions/tagother.php:95 -#: lib/facebookaction.php:308 lib/groupeditform.php:137 +#: lib/facebookaction.php:308 lib/groupeditform.php:137 actions/login.php:211 +#: actions/showgroup.php:226 actions/showstream.php:244 +#: actions/tagother.php:94 lib/facebookaction.php:312 msgid "Nickname" msgstr "" @@ -1242,7 +1295,9 @@ msgstr "" #: actions/finishopenidlogin.php:171 actions/profilesettings.php:203 #: actions/register.php:74 actions/updateprofile.php:78 #: actions/finishopenidlogin.php:205 actions/profilesettings.php:192 -#: actions/updateprofile.php:81 +#: actions/updateprofile.php:81 actions/editgroup.php:179 +#: actions/newgroup.php:130 actions/register.php:156 +#: actions/updateprofile.php:83 msgid "Nickname must have only lowercase letters and numbers and no spaces." msgstr "" @@ -1263,6 +1318,7 @@ msgstr "" #: ../actions/deletenotice.php:59 actions/deletenotice.php:60 #: actions/block.php:147 actions/deletenotice.php:118 +#: actions/deletenotice.php:116 msgid "No" msgstr "" @@ -1294,11 +1350,12 @@ msgstr "" #: ../actions/newnotice.php:44 actions/newmessage.php:53 #: actions/newnotice.php:44 classes/Command.php:197 actions/newmessage.php:109 #: actions/newnotice.php:126 classes/Command.php:223 +#: actions/newmessage.php:142 actions/newnotice.php:131 lib/command.php:223 msgid "No content!" msgstr "" #: ../actions/emailsettings.php:174 actions/emailsettings.php:192 -#: actions/emailsettings.php:304 +#: actions/emailsettings.php:304 actions/emailsettings.php:311 msgid "No email address." msgstr "" @@ -1307,7 +1364,8 @@ msgid "No id." msgstr "" #: ../actions/emailsettings.php:271 actions/emailsettings.php:289 -#: actions/emailsettings.php:430 +#: actions/emailsettings.php:430 actions/emailsettings.php:437 +#: actions/smssettings.php:505 msgid "No incoming email address." msgstr "" @@ -1325,7 +1383,7 @@ msgstr "" #: ../actions/smssettings.php:229 actions/emailsettings.php:240 #: actions/imsettings.php:214 actions/smssettings.php:237 #: actions/emailsettings.php:363 actions/imsettings.php:345 -#: actions/smssettings.php:358 +#: actions/smssettings.php:358 actions/emailsettings.php:370 msgid "No pending confirmation to cancel." msgstr "" @@ -1352,7 +1410,7 @@ msgstr "" #: ../actions/noticesearch.php:64 ../actions/peoplesearch.php:64 #: actions/noticesearch.php:69 actions/peoplesearch.php:69 #: actions/groupsearch.php:81 actions/noticesearch.php:104 -#: actions/peoplesearch.php:85 +#: actions/peoplesearch.php:85 actions/noticesearch.php:117 msgid "No results" msgstr "" @@ -1363,12 +1421,13 @@ msgstr "" #: ../actions/twitapistatuses.php:595 actions/twitapifavorites.php:136 #: actions/twitapistatuses.php:520 actions/twitapifavorites.php:112 -#: actions/twitapistatuses.php:446 +#: actions/twitapistatuses.php:446 actions/twitapifavorites.php:118 +#: actions/twitapistatuses.php:470 msgid "No status found with that ID." msgstr "" #: ../actions/twitapistatuses.php:555 actions/twitapistatuses.php:478 -#: actions/twitapistatuses.php:418 +#: actions/twitapistatuses.php:418 actions/twitapistatuses.php:442 msgid "No status with that ID found." msgstr "" @@ -1422,7 +1481,9 @@ msgstr "" #: actions/usergroups.php:92 actions/userrss.php:38 actions/xrds.php:73 #: classes/Command.php:140 classes/Command.php:185 classes/Command.php:234 #: classes/Command.php:271 lib/galleryaction.php:60 lib/mailbox.php:82 -#: lib/subs.php:34 lib/subs.php:109 +#: lib/subs.php:34 lib/subs.php:109 actions/all.php:56 actions/allrss.php:68 +#: actions/favoritesrss.php:74 lib/command.php:140 lib/command.php:185 +#: lib/command.php:234 lib/command.php:271 lib/mailbox.php:84 msgid "No such user." msgstr "" @@ -1448,7 +1509,8 @@ msgstr "" #: ../lib/twitterapi.php:226 ../lib/twitterapi.php:247 #: ../lib/twitterapi.php:332 lib/twitterapi.php:391 lib/twitterapi.php:418 #: lib/twitterapi.php:502 lib/twitterapi.php:448 lib/twitterapi.php:476 -#: lib/twitterapi.php:566 +#: lib/twitterapi.php:566 lib/twitterapi.php:483 lib/twitterapi.php:511 +#: lib/twitterapi.php:601 msgid "Not a supported data format." msgstr "" @@ -1458,11 +1520,12 @@ msgid "Not a valid Jabber ID" msgstr "" #: ../lib/openid.php:131 lib/openid.php:131 lib/openid.php:140 +#: lib/openid.php:143 msgid "Not a valid OpenID." msgstr "" #: ../actions/emailsettings.php:185 actions/emailsettings.php:203 -#: actions/emailsettings.php:315 +#: actions/emailsettings.php:315 actions/emailsettings.php:322 msgid "Not a valid email address" msgstr "" @@ -1493,7 +1556,7 @@ msgid "Not a valid profile URL (no YADIS document)." msgstr "" #: ../actions/avatar.php:95 actions/profilesettings.php:332 -#: lib/imagefile.php:87 +#: lib/imagefile.php:87 lib/imagefile.php:90 msgid "Not an image or corrupt file." msgstr "" @@ -1508,7 +1571,7 @@ msgid "Not expecting this response!" msgstr "" #: ../actions/twitapistatuses.php:422 actions/twitapistatuses.php:361 -#: actions/twitapistatuses.php:309 +#: actions/twitapistatuses.php:309 actions/twitapistatuses.php:327 msgid "Not found" msgstr "" @@ -1524,7 +1587,7 @@ msgstr "" #: actions/newmessage.php:83 actions/newnotice.php:90 actions/nudge.php:63 #: actions/subedit.php:31 actions/subscribe.php:30 actions/unblock.php:60 #: actions/unsubscribe.php:27 lib/deleteaction.php:66 -#: lib/settingsaction.php:72 +#: lib/settingsaction.php:72 actions/newmessage.php:87 msgid "Not logged in." msgstr "" @@ -1551,12 +1614,12 @@ msgstr "" #: ../actions/showstream.php:316 actions/showstream.php:331 #: actions/showstream.php:504 lib/facebookaction.php:477 lib/mailbox.php:116 -#: lib/noticelist.php:87 +#: lib/noticelist.php:87 lib/facebookaction.php:581 lib/mailbox.php:118 msgid "Notices" msgstr "" #: ../actions/tag.php:35 ../actions/tag.php:81 actions/tag.php:35 -#: actions/tag.php:81 actions/tag.php:41 +#: actions/tag.php:81 actions/tag.php:41 actions/tag.php:49 #, php-format msgid "Notices tagged with %s" msgstr "" @@ -1568,7 +1631,7 @@ msgstr "" #: ../lib/settingsaction.php:96 ../lib/util.php:314 lib/settingsaction.php:90 #: lib/util.php:330 lib/accountsettingsaction.php:116 lib/action.php:341 -#: lib/logingroupnav.php:81 +#: lib/logingroupnav.php:81 lib/action.php:418 msgid "OpenID" msgstr "" @@ -1578,6 +1641,7 @@ msgid "OpenID Account Setup" msgstr "" #: ../lib/openid.php:180 lib/openid.php:180 lib/openid.php:266 +#: lib/openid.php:269 msgid "OpenID Auto-Submit" msgstr "" @@ -1585,12 +1649,14 @@ msgstr "" #: ../actions/openidlogin.php:60 actions/finishaddopenid.php:99 #: actions/finishopenidlogin.php:146 actions/openidlogin.php:68 #: actions/finishaddopenid.php:170 actions/openidlogin.php:80 +#: actions/openidlogin.php:89 msgid "OpenID Login" msgstr "" #: ../actions/openidlogin.php:65 ../actions/openidsettings.php:49 #: actions/openidlogin.php:74 actions/openidsettings.php:50 #: actions/openidlogin.php:102 actions/openidsettings.php:101 +#: actions/openidlogin.php:111 msgid "OpenID URL" msgstr "" @@ -1608,6 +1674,7 @@ msgid "OpenID authentication failed: %s" msgstr "" #: ../lib/openid.php:133 lib/openid.php:133 lib/openid.php:142 +#: lib/openid.php:145 #, php-format msgid "OpenID failure: %s" msgstr "" @@ -1623,11 +1690,12 @@ msgid "OpenID settings" msgstr "" #: ../actions/invite.php:135 actions/invite.php:143 actions/invite.php:180 +#: actions/invite.php:186 msgid "Optionally add a personal message to the invitation." msgstr "" #: ../actions/avatar.php:84 actions/profilesettings.php:321 -#: lib/imagefile.php:75 +#: lib/imagefile.php:75 lib/imagefile.php:79 msgid "Partial upload." msgstr "" @@ -1637,6 +1705,7 @@ msgstr "" #: actions/register.php:167 actions/finishopenidlogin.php:118 #: actions/login.php:231 actions/register.php:372 #: lib/accountsettingsaction.php:110 lib/facebookaction.php:311 +#: actions/login.php:214 lib/facebookaction.php:315 msgid "Password" msgstr "" @@ -1659,12 +1728,14 @@ msgstr "" #: ../actions/password.php:89 ../actions/recoverpassword.php:313 #: actions/profilesettings.php:408 actions/recoverpassword.php:326 #: actions/passwordsettings.php:173 actions/recoverpassword.php:200 +#: actions/passwordsettings.php:178 msgid "Password saved." msgstr "" #: ../actions/password.php:61 ../actions/register.php:88 #: actions/profilesettings.php:380 actions/register.php:98 #: actions/passwordsettings.php:145 actions/register.php:183 +#: actions/passwordsettings.php:150 msgid "Passwords don't match." msgstr "" @@ -1688,10 +1759,12 @@ msgid "Personal" msgstr "" #: ../actions/invite.php:133 actions/invite.php:141 actions/invite.php:178 +#: actions/invite.php:184 msgid "Personal message" msgstr "" #: ../actions/smssettings.php:69 actions/smssettings.php:69 +#: actions/smssettings.php:128 msgid "Phone number, no punctuation or spaces, with area code" msgstr "" @@ -1712,7 +1785,7 @@ msgstr "" #: actions/imsettings.php:68 actions/smssettings.php:94 #: actions/twittersettings.php:70 actions/emailsettings.php:147 #: actions/imsettings.php:133 actions/smssettings.php:157 -#: actions/twittersettings.php:134 +#: actions/twittersettings.php:134 actions/twittersettings.php:137 msgid "Preferences" msgstr "" @@ -1721,6 +1794,7 @@ msgstr "" #: actions/imsettings.php:152 actions/smssettings.php:171 #: actions/emailsettings.php:286 actions/imsettings.php:258 #: actions/othersettings.php:168 actions/smssettings.php:272 +#: actions/emailsettings.php:293 msgid "Preferences saved." msgstr "" @@ -1729,12 +1803,13 @@ msgstr "" msgid "Preferred language" msgstr "" -#: ../lib/util.php:328 lib/util.php:344 lib/action.php:572 +#: ../lib/util.php:328 lib/util.php:344 lib/action.php:572 lib/action.php:665 msgid "Privacy" msgstr "" #: ../classes/Notice.php:95 ../classes/Notice.php:106 classes/Notice.php:109 #: classes/Notice.php:119 classes/Notice.php:145 classes/Notice.php:155 +#: classes/Notice.php:178 classes/Notice.php:188 msgid "Problem saving notice." msgstr "" @@ -1757,6 +1832,7 @@ msgstr "" #: ../actions/postnotice.php:51 ../actions/updateprofile.php:52 #: actions/postnotice.php:52 actions/updateprofile.php:53 #: actions/postnotice.php:55 actions/updateprofile.php:56 +#: actions/updateprofile.php:58 msgid "Profile unknown" msgstr "" @@ -1765,7 +1841,7 @@ msgid "Public Stream Feed" msgstr "" #: ../actions/public.php:33 actions/public.php:33 actions/public.php:109 -#: lib/publicgroupnav.php:77 +#: lib/publicgroupnav.php:77 actions/public.php:112 lib/publicgroupnav.php:79 msgid "Public timeline" msgstr "" @@ -1775,7 +1851,7 @@ msgid "Publish a MicroID for my Jabber/GTalk address." msgstr "" #: ../actions/emailsettings.php:94 actions/emailsettings.php:101 -#: actions/emailsettings.php:178 +#: actions/emailsettings.php:178 actions/emailsettings.php:183 msgid "Publish a MicroID for my email address." msgstr "" @@ -1803,6 +1879,7 @@ msgstr "" #: actions/register.php:152 actions/register.php:207 lib/util.php:328 #: actions/register.php:69 actions/register.php:436 lib/action.php:338 #: lib/facebookaction.php:277 lib/logingroupnav.php:78 +#: actions/register.php:438 lib/action.php:415 lib/facebookaction.php:279 msgid "Register" msgstr "" @@ -1823,12 +1900,12 @@ msgstr "" #: ../actions/login.php:103 ../actions/register.php:176 actions/login.php:103 #: actions/register.php:190 actions/login.php:234 actions/openidlogin.php:107 -#: actions/register.php:414 +#: actions/register.php:414 actions/login.php:217 actions/openidlogin.php:116 msgid "Remember me" msgstr "" #: ../actions/updateprofile.php:70 actions/updateprofile.php:71 -#: actions/updateprofile.php:74 +#: actions/updateprofile.php:74 actions/updateprofile.php:76 msgid "Remote profile with no matching profile" msgstr "" @@ -1847,6 +1924,7 @@ msgstr "" #: actions/emailsettings.php:134 actions/imsettings.php:102 #: actions/openidsettings.php:166 actions/smssettings.php:103 #: actions/smssettings.php:146 actions/twittersettings.php:115 +#: actions/twittersettings.php:118 msgid "Remove" msgstr "" @@ -1855,7 +1933,7 @@ msgstr "" msgid "Remove OpenID" msgstr "" -#: ../actions/openidsettings.php:73 +#: ../actions/openidsettings.php:73 actions/openidsettings.php:128 msgid "" "Removing your only OpenID would make it impossible to log in! If you need to " "remove it, add another OpenID first." @@ -1868,7 +1946,7 @@ msgstr "" #: ../actions/replies.php:47 ../actions/repliesrss.php:76 ../lib/stream.php:56 #: actions/replies.php:47 actions/repliesrss.php:62 lib/personal.php:56 #: actions/replies.php:116 actions/repliesrss.php:67 -#: lib/personalgroupnav.php:104 +#: lib/personalgroupnav.php:104 actions/replies.php:118 #, php-format msgid "Replies to %s" msgstr "" @@ -1885,6 +1963,7 @@ msgstr "" #: ../lib/settingsaction.php:99 lib/settingsaction.php:93 #: actions/subscriptions.php:123 lib/connectsettingsaction.php:107 +#: actions/subscriptions.php:125 msgid "SMS" msgstr "" @@ -1898,7 +1977,7 @@ msgstr "" msgid "SMS Settings" msgstr "" -#: ../lib/mail.php:219 lib/mail.php:225 lib/mail.php:437 +#: ../lib/mail.php:219 lib/mail.php:225 lib/mail.php:437 lib/mail.php:438 msgid "SMS confirmation" msgstr "" @@ -1921,12 +2000,14 @@ msgstr "" #: actions/othersettings.php:117 actions/profilesettings.php:150 #: actions/smssettings.php:169 actions/subscriptions.php:124 #: actions/tagother.php:152 actions/twittersettings.php:161 -#: lib/groupeditform.php:171 +#: lib/groupeditform.php:171 actions/emailsettings.php:187 +#: actions/subscriptions.php:126 actions/tagother.php:154 +#: actions/twittersettings.php:164 msgid "Save" msgstr "" #: ../lib/searchaction.php:84 ../lib/util.php:300 lib/searchaction.php:84 -#: lib/util.php:316 lib/action.php:325 +#: lib/util.php:316 lib/action.php:325 lib/action.php:396 msgid "Search" msgstr "" @@ -1936,14 +2017,14 @@ msgid "Search Stream Feed" msgstr "" #: ../actions/noticesearch.php:30 actions/noticesearch.php:30 -#: actions/noticesearch.php:57 +#: actions/noticesearch.php:57 actions/noticesearch.php:68 #, php-format msgid "" "Search for notices on %%site.name%% by their contents. Separate search terms " "by spaces; they must be 3 characters or more." msgstr "" -#: ../actions/peoplesearch.php:28 +#: ../actions/peoplesearch.php:28 actions/peoplesearch.php:52 #, php-format msgid "" "Search for people on %%site.name%% by their name, location, or interests. " @@ -1957,7 +2038,8 @@ msgstr "" #: ../actions/invite.php:137 ../lib/util.php:1172 actions/invite.php:145 #: lib/util.php:1306 lib/util.php:1731 actions/invite.php:182 -#: lib/messageform.php:167 lib/noticeform.php:177 +#: lib/messageform.php:167 lib/noticeform.php:177 actions/invite.php:189 +#: lib/messageform.php:165 msgid "Send" msgstr "" @@ -1978,16 +2060,19 @@ msgid "Send me notices through Jabber/GTalk." msgstr "" #: ../actions/smssettings.php:97 actions/smssettings.php:97 +#: actions/smssettings.php:162 msgid "" "Send me notices through SMS; I understand I may incur exorbitant charges " "from my carrier." msgstr "" #: ../actions/imsettings.php:76 actions/imsettings.php:77 +#: actions/imsettings.php:147 msgid "Send me replies through Jabber/GTalk from people I'm not subscribed to." msgstr "" #: ../lib/util.php:304 lib/util.php:320 lib/facebookaction.php:215 +#: lib/facebookaction.php:228 msgid "Settings" msgstr "" @@ -2021,18 +2106,19 @@ msgstr "" msgid "Sorry, that is not your incoming email address." msgstr "" -#: ../lib/util.php:330 lib/util.php:346 lib/action.php:574 +#: ../lib/util.php:330 lib/util.php:346 lib/action.php:574 lib/action.php:667 msgid "Source" msgstr "" #: ../actions/showstream.php:296 actions/showstream.php:311 -#: actions/showstream.php:476 +#: actions/showstream.php:476 actions/showgroup.php:375 msgid "Statistics" msgstr "" #: ../actions/finishopenidlogin.php:182 ../actions/finishopenidlogin.php:246 #: actions/finishopenidlogin.php:188 actions/finishopenidlogin.php:252 #: actions/finishopenidlogin.php:222 actions/finishopenidlogin.php:290 +#: actions/finishopenidlogin.php:295 msgid "Stored OpenID not found." msgstr "" @@ -2052,12 +2138,12 @@ msgid "Subscribers" msgstr "" #: ../actions/userauthorization.php:310 actions/userauthorization.php:322 -#: actions/userauthorization.php:338 +#: actions/userauthorization.php:338 actions/userauthorization.php:344 msgid "Subscription authorized" msgstr "" #: ../actions/userauthorization.php:320 actions/userauthorization.php:332 -#: actions/userauthorization.php:349 +#: actions/userauthorization.php:349 actions/userauthorization.php:355 msgid "Subscription rejected" msgstr "" @@ -2070,14 +2156,15 @@ msgid "Subscriptions" msgstr "" #: ../actions/avatar.php:87 actions/profilesettings.php:324 -#: lib/imagefile.php:78 +#: lib/imagefile.php:78 lib/imagefile.php:82 msgid "System error uploading file." msgstr "" #: ../actions/tag.php:41 ../lib/util.php:301 actions/tag.php:41 #: lib/util.php:317 actions/profilesettings.php:122 actions/showstream.php:297 #: actions/tagother.php:147 actions/tagother.php:207 lib/profilelist.php:162 -#: lib/profilelist.php:164 +#: lib/profilelist.php:164 actions/showstream.php:290 actions/tagother.php:149 +#: actions/tagother.php:209 lib/profilelist.php:160 msgid "Tags" msgstr "" @@ -2086,7 +2173,7 @@ msgid "Text" msgstr "" #: ../actions/noticesearch.php:34 actions/noticesearch.php:34 -#: actions/noticesearch.php:67 +#: actions/noticesearch.php:67 actions/noticesearch.php:78 msgid "Text search" msgstr "" @@ -2106,6 +2193,7 @@ msgid "That confirmation code is not for you!" msgstr "" #: ../actions/emailsettings.php:191 actions/emailsettings.php:209 +#: actions/emailsettings.php:328 msgid "That email address already belongs to another user." msgstr "" @@ -2120,7 +2208,7 @@ msgid "That is already your Jabber ID." msgstr "" #: ../actions/emailsettings.php:188 actions/emailsettings.php:206 -#: actions/emailsettings.php:318 +#: actions/emailsettings.php:318 actions/emailsettings.php:325 msgid "That is already your email address." msgstr "" @@ -2135,7 +2223,7 @@ msgid "That is not your Jabber ID." msgstr "" #: ../actions/emailsettings.php:249 actions/emailsettings.php:267 -#: actions/emailsettings.php:397 +#: actions/emailsettings.php:397 actions/emailsettings.php:404 msgid "That is not your email address." msgstr "" @@ -2147,6 +2235,7 @@ msgstr "" #: ../actions/emailsettings.php:226 ../actions/imsettings.php:210 #: actions/emailsettings.php:244 actions/imsettings.php:218 #: actions/emailsettings.php:367 actions/imsettings.php:349 +#: actions/emailsettings.php:374 msgid "That is the wrong IM address." msgstr "" @@ -2163,15 +2252,18 @@ msgstr "" #: ../actions/newnotice.php:49 ../actions/twitapistatuses.php:408 #: actions/newnotice.php:49 actions/twitapistatuses.php:330 #: actions/facebookhome.php:243 actions/twitapistatuses.php:276 +#: actions/newnotice.php:136 actions/twitapistatuses.php:294 +#: lib/facebookaction.php:485 msgid "That's too long. Max notice size is 140 chars." msgstr "" #: ../actions/twitapiaccount.php:74 actions/twitapiaccount.php:72 -#: actions/twitapiaccount.php:62 +#: actions/twitapiaccount.php:62 actions/twitapiaccount.php:63 msgid "That's too long. Max notice size is 255 chars." msgstr "" #: ../actions/confirmaddress.php:92 actions/confirmaddress.php:92 +#: actions/confirmaddress.php:159 #, php-format msgid "The address \"%s\" has been confirmed for your account." msgstr "" @@ -2180,18 +2272,18 @@ msgstr "" #: ../actions/smssettings.php:274 actions/emailsettings.php:282 #: actions/imsettings.php:258 actions/smssettings.php:282 #: actions/emailsettings.php:416 actions/imsettings.php:402 -#: actions/smssettings.php:413 +#: actions/smssettings.php:413 actions/emailsettings.php:423 msgid "The address was removed." msgstr "" -#: ../actions/userauthorization.php:312 +#: ../actions/userauthorization.php:312 actions/userauthorization.php:346 msgid "" "The subscription has been authorized, but no callback URL was passed. Check " "with the site's instructions for details on how to authorize the " "subscription. Your subscription token is:" msgstr "" -#: ../actions/userauthorization.php:322 +#: ../actions/userauthorization.php:322 actions/userauthorization.php:357 msgid "" "The subscription has been rejected, but no callback URL was passed. Check " "with the site's instructions for details on how to fully reject the " @@ -2199,20 +2291,24 @@ msgid "" msgstr "" #: ../actions/subscribers.php:35 actions/subscribers.php:35 +#: actions/subscribers.php:67 #, php-format msgid "These are the people who listen to %s's notices." msgstr "" #: ../actions/subscribers.php:33 actions/subscribers.php:33 +#: actions/subscribers.php:63 msgid "These are the people who listen to your notices." msgstr "" #: ../actions/subscriptions.php:35 actions/subscriptions.php:35 +#: actions/subscriptions.php:69 #, php-format msgid "These are the people whose notices %s listens to." msgstr "" #: ../actions/subscriptions.php:33 actions/subscriptions.php:33 +#: actions/subscriptions.php:65 msgid "These are the people whose notices you listen to." msgstr "" @@ -2221,11 +2317,11 @@ msgid "" "These people are already users and you were automatically subscribed to them:" msgstr "" -#: ../actions/recoverpassword.php:88 +#: ../actions/recoverpassword.php:88 actions/recoverpassword.php:97 msgid "This confirmation code is too old. Please start again." msgstr "" -#: ../lib/openid.php:195 +#: ../lib/openid.php:195 lib/openid.php:206 msgid "" "This form should automatically submit itself. If not, click the submit " "button to go to your OpenID provider." @@ -2244,6 +2340,7 @@ msgstr "" #: actions/twitapifavorites.php:127 actions/twitapifriendships.php:108 #: actions/twitapistatuses.php:511 actions/twitapifavorites.php:97 #: actions/twitapifriendships.php:85 actions/twitapistatuses.php:436 +#: actions/twitapifavorites.php:103 actions/twitapistatuses.php:460 msgid "This method requires a POST or DELETE." msgstr "" @@ -2252,11 +2349,12 @@ msgstr "" #: actions/twitapidirect_messages.php:114 actions/twitapifriendships.php:44 #: actions/twitapistatuses.php:303 actions/twitapiaccount.php:53 #: actions/twitapidirect_messages.php:122 actions/twitapifriendships.php:32 -#: actions/twitapistatuses.php:244 +#: actions/twitapistatuses.php:244 actions/twitapiaccount.php:54 +#: actions/twitapidirect_messages.php:131 actions/twitapistatuses.php:262 msgid "This method requires a POST." msgstr "" -#: ../lib/util.php:164 lib/util.php:246 +#: ../lib/util.php:164 lib/util.php:246 lib/htmloutputter.php:104 msgid "This page is not available in a media type you accept" msgstr "" @@ -2270,7 +2368,7 @@ msgstr "" msgid "Timezone not selected." msgstr "" -#: ../actions/remotesubscribe.php:43 +#: ../actions/remotesubscribe.php:43 actions/remotesubscribe.php:74 #, php-format msgid "" "To subscribe, you can [login](%%action.login%%), or [register](%%action." @@ -2285,7 +2383,7 @@ msgstr "" #: ../actions/profilesettings.php:48 ../actions/register.php:169 #: actions/profilesettings.php:81 actions/register.php:183 -#: actions/profilesettings.php:109 +#: actions/profilesettings.php:109 actions/register.php:398 msgid "URL of your homepage, blog, or profile on another site" msgstr "" @@ -2302,6 +2400,8 @@ msgstr "" #: actions/emailsettings.php:242 actions/grouplogo.php:317 #: actions/imsettings.php:214 actions/recoverpassword.php:44 #: actions/smssettings.php:236 actions/twittersettings.php:302 +#: actions/avatarsettings.php:263 actions/emailsettings.php:247 +#: actions/grouplogo.php:324 actions/twittersettings.php:306 msgid "Unexpected form submission." msgstr "" @@ -2339,11 +2439,12 @@ msgstr "" #: ../actions/postnotice.php:44 ../actions/updateprofile.php:45 #: actions/postnotice.php:45 actions/updateprofile.php:46 #: actions/postnotice.php:48 actions/updateprofile.php:49 +#: actions/updateprofile.php:51 msgid "Unsupported OMB version" msgstr "" #: ../actions/avatar.php:105 actions/profilesettings.php:342 -#: lib/imagefile.php:102 +#: lib/imagefile.php:102 lib/imagefile.php:99 msgid "Unsupported image file format." msgstr "" @@ -2358,19 +2459,20 @@ msgid "Updates by instant messenger (IM)" msgstr "" #: ../actions/twitapistatuses.php:241 actions/twitapistatuses.php:158 -#: actions/twitapistatuses.php:129 +#: actions/twitapistatuses.php:129 actions/twitapistatuses.php:134 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "" #: ../actions/twitapistatuses.php:341 actions/twitapistatuses.php:268 -#: actions/twitapistatuses.php:202 +#: actions/twitapistatuses.php:202 actions/twitapistatuses.php:213 #, php-format msgid "Updates from %1$s on %2$s!" msgstr "" #: ../actions/avatar.php:68 actions/profilesettings.php:161 #: actions/avatarsettings.php:162 actions/grouplogo.php:232 +#: actions/avatarsettings.php:165 actions/grouplogo.php:238 msgid "Upload" msgstr "" @@ -2392,7 +2494,8 @@ msgid "" msgstr "" #: ../actions/register.php:159 ../actions/register.php:162 -#: actions/register.php:173 actions/register.php:176 +#: actions/register.php:173 actions/register.php:176 actions/register.php:382 +#: actions/register.php:386 msgid "Used only for updates, announcements, and password recovery" msgstr "" @@ -2416,6 +2519,8 @@ msgstr "" #: actions/twitapifavorites.php:42 actions/twitapistatuses.php:167 #: actions/twitapistatuses.php:503 actions/twitapiusers.php:55 #: actions/usergroups.php:99 lib/galleryaction.php:67 lib/twitterapi.php:626 +#: actions/twitapiaccount.php:71 actions/twitapistatuses.php:179 +#: actions/twitapistatuses.php:535 actions/twitapiusers.php:59 msgid "User has no profile." msgstr "" @@ -2440,18 +2545,18 @@ msgstr "" #: ../actions/profilesettings.php:54 ../actions/register.php:175 #: actions/profilesettings.php:87 actions/register.php:189 -#: actions/profilesettings.php:119 +#: actions/profilesettings.php:119 actions/register.php:410 msgid "Where you are, like \"City, State (or Region), Country\"" msgstr "" #: ../actions/updateprofile.php:128 actions/updateprofile.php:129 -#: actions/updateprofile.php:132 +#: actions/updateprofile.php:132 actions/updateprofile.php:134 #, php-format msgid "Wrong image type for '%s'" msgstr "" #: ../actions/updateprofile.php:123 actions/updateprofile.php:124 -#: actions/updateprofile.php:127 +#: actions/updateprofile.php:127 actions/updateprofile.php:129 #, php-format msgid "Wrong size image at '%s'" msgstr "" @@ -2459,7 +2564,7 @@ msgstr "" #: ../actions/deletenotice.php:63 ../actions/deletenotice.php:72 #: actions/deletenotice.php:64 actions/deletenotice.php:79 #: actions/block.php:148 actions/deletenotice.php:122 -#: actions/deletenotice.php:141 +#: actions/deletenotice.php:141 actions/deletenotice.php:115 msgid "Yes" msgstr "" @@ -2502,20 +2607,21 @@ msgstr "" msgid "You can receive SMS messages through email from %%site.name%%." msgstr "" -#: ../actions/openidsettings.php:86 +#: ../actions/openidsettings.php:86 actions/openidsettings.php:143 msgid "" "You can remove an OpenID from your account by clicking the button marked " "\"Remove\"." msgstr "" #: ../actions/imsettings.php:28 actions/imsettings.php:28 +#: actions/imsettings.php:70 #, php-format msgid "" "You can send and receive notices through Jabber/GTalk [instant messages](%%" "doc.im%%). Configure your address and settings below." msgstr "" -#: ../actions/profilesettings.php:27 +#: ../actions/profilesettings.php:27 actions/profilesettings.php:69 msgid "" "You can update your personal profile info here so people know more about you." msgstr "" @@ -2529,16 +2635,16 @@ msgstr "" #: ../actions/finishopenidlogin.php:33 ../actions/register.php:61 #: actions/finishopenidlogin.php:38 actions/register.php:68 -#: actions/finishopenidlogin.php:43 +#: actions/finishopenidlogin.php:43 actions/register.php:149 msgid "You can't register if you don't agree to the license." msgstr "" #: ../actions/updateprofile.php:63 actions/updateprofile.php:64 -#: actions/updateprofile.php:67 +#: actions/updateprofile.php:67 actions/updateprofile.php:69 msgid "You did not send us that profile" msgstr "" -#: ../lib/mail.php:147 +#: ../lib/mail.php:147 lib/mail.php:289 #, php-format msgid "" "You have a new posting address on %1$s.\n" @@ -2552,7 +2658,7 @@ msgid "" msgstr "" #: ../actions/twitapistatuses.php:612 actions/twitapistatuses.php:537 -#: actions/twitapistatuses.php:463 +#: actions/twitapistatuses.php:463 actions/twitapistatuses.php:486 msgid "You may not delete another user's status." msgstr "" @@ -2567,67 +2673,67 @@ msgid "" "on the site. Thanks for growing the community!" msgstr "" -#: ../actions/recoverpassword.php:149 +#: ../actions/recoverpassword.php:149 actions/recoverpassword.php:158 msgid "You've been identified. Enter a new password below. " msgstr "" #: ../actions/openidlogin.php:67 actions/openidlogin.php:76 -#: actions/openidlogin.php:104 +#: actions/openidlogin.php:104 actions/openidlogin.php:113 msgid "Your OpenID URL" msgstr "" -#: ../actions/recoverpassword.php:164 +#: ../actions/recoverpassword.php:164 actions/recoverpassword.php:188 msgid "Your nickname on this server, or your registered email address." msgstr "" -#: ../actions/openidsettings.php:28 +#: ../actions/openidsettings.php:28 actions/openidsettings.php:70 #, php-format msgid "" "[OpenID](%%doc.openid%%) lets you log into many sites with the same user " "account. Manage your associated OpenIDs from here." msgstr "" -#: ../lib/util.php:943 lib/util.php:992 lib/util.php:945 +#: ../lib/util.php:943 lib/util.php:992 lib/util.php:945 lib/util.php:756 msgid "a few seconds ago" msgstr "" -#: ../lib/util.php:955 lib/util.php:1004 lib/util.php:957 +#: ../lib/util.php:955 lib/util.php:1004 lib/util.php:957 lib/util.php:768 #, php-format msgid "about %d days ago" msgstr "" -#: ../lib/util.php:951 lib/util.php:1000 lib/util.php:953 +#: ../lib/util.php:951 lib/util.php:1000 lib/util.php:953 lib/util.php:764 #, php-format msgid "about %d hours ago" msgstr "" -#: ../lib/util.php:947 lib/util.php:996 lib/util.php:949 +#: ../lib/util.php:947 lib/util.php:996 lib/util.php:949 lib/util.php:760 #, php-format msgid "about %d minutes ago" msgstr "" -#: ../lib/util.php:959 lib/util.php:1008 lib/util.php:961 +#: ../lib/util.php:959 lib/util.php:1008 lib/util.php:961 lib/util.php:772 #, php-format msgid "about %d months ago" msgstr "" -#: ../lib/util.php:953 lib/util.php:1002 lib/util.php:955 +#: ../lib/util.php:953 lib/util.php:1002 lib/util.php:955 lib/util.php:766 msgid "about a day ago" msgstr "" -#: ../lib/util.php:945 lib/util.php:994 lib/util.php:947 +#: ../lib/util.php:945 lib/util.php:994 lib/util.php:947 lib/util.php:758 msgid "about a minute ago" msgstr "" -#: ../lib/util.php:957 lib/util.php:1006 lib/util.php:959 +#: ../lib/util.php:957 lib/util.php:1006 lib/util.php:959 lib/util.php:770 msgid "about a month ago" msgstr "" -#: ../lib/util.php:961 lib/util.php:1010 lib/util.php:963 +#: ../lib/util.php:961 lib/util.php:1010 lib/util.php:963 lib/util.php:774 msgid "about a year ago" msgstr "" -#: ../lib/util.php:949 lib/util.php:998 lib/util.php:951 +#: ../lib/util.php:949 lib/util.php:998 lib/util.php:951 lib/util.php:762 msgid "about an hour ago" msgstr "" @@ -2654,7 +2760,8 @@ msgid "same as password above" msgstr "" #: ../actions/twitapistatuses.php:755 actions/twitapistatuses.php:678 -#: actions/twitapistatuses.php:555 +#: actions/twitapistatuses.php:555 actions/twitapistatuses.php:596 +#: actions/twitapistatuses.php:618 msgid "unsupported file type" msgstr "" @@ -2675,6 +2782,14 @@ msgstr "" #: actions/finishopenidlogin.php:38 actions/invite.php:54 actions/nudge.php:80 #: actions/openidlogin.php:37 actions/recoverpassword.php:316 #: actions/subscribe.php:46 actions/unblock.php:65 actions/unsubscribe.php:43 +#: actions/avatarsettings.php:251 actions/emailsettings.php:229 +#: actions/grouplogo.php:314 actions/imsettings.php:200 actions/login.php:103 +#: actions/newmessage.php:133 actions/newnotice.php:96 +#: actions/openidsettings.php:188 actions/othersettings.php:136 +#: actions/passwordsettings.php:131 actions/profilesettings.php:172 +#: actions/register.php:113 actions/remotesubscribe.php:53 +#: actions/smssettings.php:216 actions/subedit.php:38 actions/tagother.php:166 +#: actions/twittersettings.php:294 actions/userauthorization.php:39 msgid "There was a problem with your session token. Try again, please." msgstr "" @@ -2690,7 +2805,7 @@ msgstr "" msgid "Favor" msgstr "" -#: actions/emailsettings.php:92 +#: actions/emailsettings.php:92 actions/emailsettings.php:157 msgid "Send me email when someone adds my notice as a favorite." msgstr "" @@ -2699,13 +2814,14 @@ msgid "Send me email when someone sends me a private message." msgstr "" #: actions/favor.php:53 actions/twitapifavorites.php:142 actions/favor.php:81 -#: actions/twitapifavorites.php:118 +#: actions/twitapifavorites.php:118 actions/twitapifavorites.php:124 msgid "This notice is already a favorite!" msgstr "" #: actions/favor.php:60 actions/twitapifavorites.php:151 #: classes/Command.php:132 actions/favor.php:86 #: actions/twitapifavorites.php:125 classes/Command.php:152 +#: actions/twitapifavorites.php:131 lib/command.php:152 msgid "Could not create favorite." msgstr "" @@ -2715,11 +2831,13 @@ msgstr "" #: actions/favoritesrss.php:60 actions/showfavorites.php:47 #: actions/favoritesrss.php:100 actions/showfavorites.php:77 +#: actions/favoritesrss.php:110 #, php-format msgid "%s favorite notices" msgstr "" #: actions/favoritesrss.php:64 actions/favoritesrss.php:104 +#: actions/favoritesrss.php:114 #, php-format msgid "Feed of favorite notices of %s" msgstr "" @@ -2759,33 +2877,38 @@ msgid "Login with your username and password. " msgstr "" #: actions/newmessage.php:58 actions/twitapidirect_messages.php:130 -#: actions/twitapidirect_messages.php:141 +#: actions/twitapidirect_messages.php:141 actions/newmessage.php:148 +#: actions/twitapidirect_messages.php:150 msgid "That's too long. Max message size is 140 chars." msgstr "" #: actions/newmessage.php:65 actions/newmessage.php:128 +#: actions/newmessage.php:155 msgid "No recipient specified." msgstr "" #: actions/newmessage.php:68 actions/newmessage.php:113 #: classes/Command.php:206 actions/newmessage.php:131 #: actions/newmessage.php:168 classes/Command.php:237 +#: actions/newmessage.php:119 actions/newmessage.php:158 lib/command.php:237 msgid "You can't send a message to this user." msgstr "" #: actions/newmessage.php:71 actions/twitapidirect_messages.php:146 #: classes/Command.php:209 actions/twitapidirect_messages.php:158 -#: classes/Command.php:240 +#: classes/Command.php:240 actions/newmessage.php:161 +#: actions/twitapidirect_messages.php:167 lib/command.php:240 msgid "" "Don't send a message to yourself; just say it to yourself quietly instead." msgstr "" #: actions/newmessage.php:108 actions/microsummary.php:62 -#: actions/newmessage.php:163 +#: actions/newmessage.php:163 actions/newmessage.php:114 msgid "No such user" msgstr "" #: actions/newmessage.php:117 actions/newmessage.php:67 +#: actions/newmessage.php:71 msgid "New message" msgstr "" @@ -2839,6 +2962,8 @@ msgstr "" #: actions/avatarsettings.php:104 actions/avatarsettings.php:179 #: actions/grouplogo.php:177 actions/remotesubscribe.php:367 #: actions/userauthorization.php:176 actions/userrss.php:82 +#: actions/avatarsettings.php:106 actions/avatarsettings.php:182 +#: actions/grouplogo.php:183 actions/remotesubscribe.php:366 msgid "User without matching profile" msgstr "" @@ -2867,6 +2992,7 @@ msgid "New password successfully saved. " msgstr "" #: actions/register.php:95 actions/register.php:180 +#: actions/passwordsettings.php:147 msgid "Password must be 6 or more characters." msgstr "" @@ -2887,12 +3013,14 @@ msgid "To subscribe, you can [login](%%action.login%%)," msgstr "" #: actions/showfavorites.php:61 actions/showfavorites.php:145 +#: actions/showfavorites.php:147 #, php-format msgid "Feed for favorites of %s" msgstr "" #: actions/showfavorites.php:84 actions/twitapifavorites.php:85 #: actions/showfavorites.php:202 actions/twitapifavorites.php:59 +#: actions/showfavorites.php:179 msgid "Could not retrieve favorite notices." msgstr "" @@ -2900,7 +3028,7 @@ msgstr "" msgid "No such message." msgstr "" -#: actions/showmessage.php:42 +#: actions/showmessage.php:42 actions/showmessage.php:98 msgid "Only the sender and recipient may read this message." msgstr "" @@ -2924,51 +3052,61 @@ msgid "Mobile carrier for your phone. " msgstr "" #: actions/twitapidirect_messages.php:76 actions/twitapidirect_messages.php:68 +#: actions/twitapidirect_messages.php:67 #, php-format msgid "Direct messages to %s" msgstr "" #: actions/twitapidirect_messages.php:77 actions/twitapidirect_messages.php:69 +#: actions/twitapidirect_messages.php:68 #, php-format msgid "All the direct messages sent to %s" msgstr "" #: actions/twitapidirect_messages.php:81 actions/twitapidirect_messages.php:73 +#: actions/twitapidirect_messages.php:72 msgid "Direct Messages You've Sent" msgstr "" #: actions/twitapidirect_messages.php:82 actions/twitapidirect_messages.php:74 +#: actions/twitapidirect_messages.php:73 #, php-format msgid "All the direct messages sent from %s" msgstr "" #: actions/twitapidirect_messages.php:128 #: actions/twitapidirect_messages.php:137 +#: actions/twitapidirect_messages.php:146 msgid "No message text!" msgstr "" #: actions/twitapidirect_messages.php:138 #: actions/twitapidirect_messages.php:150 +#: actions/twitapidirect_messages.php:159 msgid "Recipient user not found." msgstr "" #: actions/twitapidirect_messages.php:141 #: actions/twitapidirect_messages.php:153 +#: actions/twitapidirect_messages.php:162 msgid "Can't send direct messages to users who aren't your friend." msgstr "" #: actions/twitapifavorites.php:92 actions/twitapifavorites.php:66 +#: actions/twitapifavorites.php:64 #, php-format msgid "%s / Favorites from %s" msgstr "" #: actions/twitapifavorites.php:95 actions/twitapifavorites.php:69 +#: actions/twitapifavorites.php:68 #, php-format msgid "%s updates favorited by %s / %s." msgstr "" #: actions/twitapifavorites.php:187 lib/mail.php:275 #: actions/twitapifavorites.php:164 lib/mail.php:553 +#: actions/twitapifavorites.php:170 lib/mail.php:554 #, php-format msgid "%s added your notice as a favorite" msgstr "" @@ -2987,14 +3125,17 @@ msgid "" msgstr "" #: actions/twittersettings.php:41 actions/twittersettings.php:60 +#: actions/twittersettings.php:61 msgid "Twitter settings" msgstr "" #: actions/twittersettings.php:48 actions/twittersettings.php:105 +#: actions/twittersettings.php:106 msgid "Twitter Account" msgstr "" #: actions/twittersettings.php:56 actions/twittersettings.php:113 +#: actions/twittersettings.php:114 msgid "Current verified Twitter account." msgstr "" @@ -3003,6 +3144,7 @@ msgid "Twitter Username" msgstr "" #: actions/twittersettings.php:65 actions/twittersettings.php:123 +#: actions/twittersettings.php:126 msgid "No spaces, please." msgstr "" @@ -3011,24 +3153,28 @@ msgid "Twitter Password" msgstr "" #: actions/twittersettings.php:72 actions/twittersettings.php:139 +#: actions/twittersettings.php:142 msgid "Automatically send my notices to Twitter." msgstr "" #: actions/twittersettings.php:75 actions/twittersettings.php:146 +#: actions/twittersettings.php:149 msgid "Send local \"@\" replies to Twitter." msgstr "" #: actions/twittersettings.php:78 actions/twittersettings.php:153 +#: actions/twittersettings.php:156 msgid "Subscribe to my Twitter friends here." msgstr "" -#: actions/twittersettings.php:122 +#: actions/twittersettings.php:122 actions/twittersettings.php:331 msgid "" "Username must have only numbers, upper- and lowercase letters, and " "underscore (_). 15 chars max." msgstr "" #: actions/twittersettings.php:128 actions/twittersettings.php:334 +#: actions/twittersettings.php:338 msgid "Could not verify your Twitter credentials!" msgstr "" @@ -3039,33 +3185,39 @@ msgstr "" #: actions/twittersettings.php:151 actions/twittersettings.php:170 #: actions/twittersettings.php:348 actions/twittersettings.php:368 +#: actions/twittersettings.php:352 actions/twittersettings.php:372 msgid "Unable to save your Twitter settings!" msgstr "" #: actions/twittersettings.php:174 actions/twittersettings.php:376 +#: actions/twittersettings.php:380 msgid "Twitter settings saved." msgstr "" #: actions/twittersettings.php:192 actions/twittersettings.php:395 +#: actions/twittersettings.php:399 msgid "That is not your Twitter account." msgstr "" #: actions/twittersettings.php:200 actions/twittersettings.php:208 -#: actions/twittersettings.php:403 +#: actions/twittersettings.php:403 actions/twittersettings.php:407 msgid "Couldn't remove Twitter user." msgstr "" #: actions/twittersettings.php:212 actions/twittersettings.php:407 +#: actions/twittersettings.php:411 msgid "Twitter account removed." msgstr "" #: actions/twittersettings.php:225 actions/twittersettings.php:239 #: actions/twittersettings.php:428 actions/twittersettings.php:439 -#: actions/twittersettings.php:453 +#: actions/twittersettings.php:453 actions/twittersettings.php:432 +#: actions/twittersettings.php:443 actions/twittersettings.php:457 msgid "Couldn't save Twitter preferences." msgstr "" #: actions/twittersettings.php:245 actions/twittersettings.php:461 +#: actions/twittersettings.php:465 msgid "Twitter preferences saved." msgstr "" @@ -3082,18 +3234,19 @@ msgid "The subscription has been rejected, but no " msgstr "" #: classes/Channel.php:113 classes/Channel.php:132 classes/Channel.php:151 +#: lib/channel.php:138 lib/channel.php:158 msgid "Command results" msgstr "" -#: classes/Channel.php:148 classes/Channel.php:204 +#: classes/Channel.php:148 classes/Channel.php:204 lib/channel.php:210 msgid "Command complete" msgstr "" -#: classes/Channel.php:158 classes/Channel.php:215 +#: classes/Channel.php:158 classes/Channel.php:215 lib/channel.php:221 msgid "Command failed" msgstr "" -#: classes/Command.php:39 classes/Command.php:44 +#: classes/Command.php:39 classes/Command.php:44 lib/command.php:44 msgid "Sorry, this command is not yet implemented." msgstr "" @@ -3103,89 +3256,89 @@ msgid "Subscriptions: %1$s\n" msgstr "" #: classes/Command.php:125 classes/Command.php:242 classes/Command.php:145 -#: classes/Command.php:276 +#: classes/Command.php:276 lib/command.php:145 lib/command.php:276 msgid "User has no last notice" msgstr "" -#: classes/Command.php:146 classes/Command.php:166 +#: classes/Command.php:146 classes/Command.php:166 lib/command.php:166 msgid "Notice marked as fave." msgstr "" -#: classes/Command.php:166 classes/Command.php:189 +#: classes/Command.php:166 classes/Command.php:189 lib/command.php:189 #, php-format msgid "%1$s (%2$s)" msgstr "" -#: classes/Command.php:169 classes/Command.php:192 +#: classes/Command.php:169 classes/Command.php:192 lib/command.php:192 #, php-format msgid "Fullname: %s" msgstr "" -#: classes/Command.php:172 classes/Command.php:195 +#: classes/Command.php:172 classes/Command.php:195 lib/command.php:195 #, php-format msgid "Location: %s" msgstr "" -#: classes/Command.php:175 classes/Command.php:198 +#: classes/Command.php:175 classes/Command.php:198 lib/command.php:198 #, php-format msgid "Homepage: %s" msgstr "" -#: classes/Command.php:178 classes/Command.php:201 +#: classes/Command.php:178 classes/Command.php:201 lib/command.php:201 #, php-format msgid "About: %s" msgstr "" -#: classes/Command.php:200 classes/Command.php:228 +#: classes/Command.php:200 classes/Command.php:228 lib/command.php:228 #, php-format msgid "Message too long - maximum is 140 characters, you sent %d" msgstr "" -#: classes/Command.php:214 classes/Command.php:245 +#: classes/Command.php:214 classes/Command.php:245 lib/command.php:245 #, php-format msgid "Direct message to %s sent" msgstr "" -#: classes/Command.php:216 classes/Command.php:247 +#: classes/Command.php:216 classes/Command.php:247 lib/command.php:247 msgid "Error sending direct message." msgstr "" -#: classes/Command.php:263 classes/Command.php:300 +#: classes/Command.php:263 classes/Command.php:300 lib/command.php:300 msgid "Specify the name of the user to subscribe to" msgstr "" -#: classes/Command.php:270 classes/Command.php:307 +#: classes/Command.php:270 classes/Command.php:307 lib/command.php:307 #, php-format msgid "Subscribed to %s" msgstr "" -#: classes/Command.php:288 classes/Command.php:328 +#: classes/Command.php:288 classes/Command.php:328 lib/command.php:328 msgid "Specify the name of the user to unsubscribe from" msgstr "" -#: classes/Command.php:295 classes/Command.php:335 +#: classes/Command.php:295 classes/Command.php:335 lib/command.php:335 #, php-format msgid "Unsubscribed from %s" msgstr "" #: classes/Command.php:310 classes/Command.php:330 classes/Command.php:353 -#: classes/Command.php:376 +#: classes/Command.php:376 lib/command.php:353 lib/command.php:376 msgid "Command not yet implemented." msgstr "" -#: classes/Command.php:313 classes/Command.php:356 +#: classes/Command.php:313 classes/Command.php:356 lib/command.php:356 msgid "Notification off." msgstr "" -#: classes/Command.php:315 classes/Command.php:358 +#: classes/Command.php:315 classes/Command.php:358 lib/command.php:358 msgid "Can't turn off notification." msgstr "" -#: classes/Command.php:333 classes/Command.php:379 +#: classes/Command.php:333 classes/Command.php:379 lib/command.php:379 msgid "Notification on." msgstr "" -#: classes/Command.php:335 classes/Command.php:381 +#: classes/Command.php:335 classes/Command.php:381 lib/command.php:381 msgid "Can't turn on notification." msgstr "" @@ -3212,7 +3365,7 @@ msgid "" "\n" msgstr "" -#: lib/mail.php:249 lib/mail.php:508 +#: lib/mail.php:249 lib/mail.php:508 lib/mail.php:509 #, php-format msgid "New private message from %s" msgstr "" @@ -3224,7 +3377,7 @@ msgid "" "\n" msgstr "" -#: lib/mailbox.php:43 lib/mailbox.php:89 +#: lib/mailbox.php:43 lib/mailbox.php:89 lib/mailbox.php:91 msgid "Only the user can read their own mailboxes." msgstr "" @@ -3270,6 +3423,7 @@ msgid "Twitter integration options" msgstr "" #: lib/util.php:1718 lib/messageform.php:139 lib/noticelist.php:422 +#: lib/messageform.php:137 lib/noticelist.php:425 msgid "To" msgstr "" @@ -3277,7 +3431,8 @@ msgstr "" msgid "Could not parse message." msgstr "" -#: actions/all.php:63 actions/facebookhome.php:162 +#: actions/all.php:63 actions/facebookhome.php:162 actions/all.php:66 +#: actions/facebookhome.php:161 #, php-format msgid "%s and friends, page %d" msgstr "" @@ -3287,21 +3442,27 @@ msgid "You can upload your personal avatar." msgstr "" #: actions/avatarsettings.php:117 actions/avatarsettings.php:191 -#: actions/grouplogo.php:250 +#: actions/grouplogo.php:250 actions/avatarsettings.php:119 +#: actions/avatarsettings.php:194 actions/grouplogo.php:256 msgid "Avatar settings" msgstr "" #: actions/avatarsettings.php:124 actions/avatarsettings.php:199 #: actions/grouplogo.php:198 actions/grouplogo.php:258 +#: actions/avatarsettings.php:126 actions/avatarsettings.php:202 +#: actions/grouplogo.php:204 actions/grouplogo.php:264 msgid "Original" msgstr "" #: actions/avatarsettings.php:139 actions/avatarsettings.php:211 #: actions/grouplogo.php:209 actions/grouplogo.php:270 +#: actions/avatarsettings.php:141 actions/avatarsettings.php:214 +#: actions/grouplogo.php:215 actions/grouplogo.php:276 msgid "Preview" msgstr "" #: actions/avatarsettings.php:225 actions/grouplogo.php:284 +#: actions/avatarsettings.php:228 actions/grouplogo.php:291 msgid "Crop" msgstr "" @@ -3318,21 +3479,24 @@ msgid "There was a problem with your session token. " msgstr "" #: actions/avatarsettings.php:303 actions/grouplogo.php:360 +#: actions/avatarsettings.php:308 msgid "Pick a square area of the image to be your avatar" msgstr "" #: actions/avatarsettings.php:327 actions/grouplogo.php:384 +#: actions/avatarsettings.php:323 actions/grouplogo.php:382 msgid "Lost our file data." msgstr "" #: actions/avatarsettings.php:334 actions/grouplogo.php:391 -#: classes/User_group.php:112 +#: classes/User_group.php:112 lib/imagefile.php:112 msgid "Lost our file." msgstr "" #: actions/avatarsettings.php:349 actions/avatarsettings.php:383 #: actions/grouplogo.php:406 actions/grouplogo.php:440 -#: classes/User_group.php:129 classes/User_group.php:161 +#: classes/User_group.php:129 classes/User_group.php:161 lib/imagefile.php:144 +#: lib/imagefile.php:191 msgid "Unknown file type" msgstr "" @@ -3381,27 +3545,30 @@ msgstr "" #: actions/editgroup.php:66 actions/groupbyid.php:72 actions/grouplogo.php:66 #: actions/joingroup.php:60 actions/newgroup.php:65 actions/showgroup.php:100 +#: actions/grouplogo.php:70 actions/grouprss.php:80 msgid "Inboxes must be enabled for groups to work" msgstr "" #: actions/editgroup.php:71 actions/grouplogo.php:71 actions/newgroup.php:70 +#: actions/grouplogo.php:75 msgid "You must be logged in to create a group." msgstr "" #: actions/editgroup.php:87 actions/grouplogo.php:87 #: actions/groupmembers.php:76 actions/joingroup.php:81 -#: actions/showgroup.php:121 +#: actions/showgroup.php:121 actions/grouplogo.php:91 actions/grouprss.php:96 msgid "No nickname" msgstr "" #: actions/editgroup.php:99 actions/groupbyid.php:88 actions/grouplogo.php:100 #: actions/groupmembers.php:83 actions/joingroup.php:88 -#: actions/showgroup.php:128 +#: actions/showgroup.php:128 actions/grouplogo.php:104 +#: actions/grouprss.php:103 msgid "No such group" msgstr "" #: actions/editgroup.php:106 actions/editgroup.php:165 -#: actions/grouplogo.php:107 +#: actions/grouplogo.php:107 actions/grouplogo.php:111 msgid "You must be an admin to edit the group" msgstr "" @@ -3438,7 +3605,7 @@ msgstr "" msgid "Send me email when someone " msgstr "" -#: actions/emailsettings.php:168 +#: actions/emailsettings.php:168 actions/emailsettings.php:173 msgid "Allow friends to nudge me and send me an email." msgstr "" @@ -3464,23 +3631,26 @@ msgstr "" msgid "Allow %s to update my Facebook status" msgstr "" -#: actions/facebookhome.php:218 +#: actions/facebookhome.php:218 actions/facebookhome.php:223 msgid "Skip" msgstr "" -#: actions/facebookhome.php:235 +#: actions/facebookhome.php:235 lib/facebookaction.php:479 msgid "No notice content!" msgstr "" #: actions/facebookhome.php:295 lib/action.php:870 lib/facebookaction.php:399 +#: actions/facebookhome.php:253 lib/action.php:973 lib/facebookaction.php:433 msgid "Pagination" msgstr "" #: actions/facebookhome.php:304 lib/action.php:879 lib/facebookaction.php:408 +#: actions/facebookhome.php:262 lib/action.php:982 lib/facebookaction.php:442 msgid "After" msgstr "" #: actions/facebookhome.php:312 lib/action.php:887 lib/facebookaction.php:416 +#: actions/facebookhome.php:270 lib/action.php:990 lib/facebookaction.php:450 msgid "Before" msgstr "" @@ -3493,22 +3663,22 @@ msgstr "" msgid "Invitations have been sent to the following users:" msgstr "" -#: actions/facebookinvite.php:96 +#: actions/facebookinvite.php:96 actions/facebookinvite.php:102 #, php-format msgid "You have been invited to %s" msgstr "" -#: actions/facebookinvite.php:105 +#: actions/facebookinvite.php:105 actions/facebookinvite.php:111 #, php-format msgid "Invite your friends to use %s" msgstr "" -#: actions/facebookinvite.php:113 +#: actions/facebookinvite.php:113 actions/facebookinvite.php:126 #, php-format msgid "Friends already using %s:" msgstr "" -#: actions/facebookinvite.php:130 +#: actions/facebookinvite.php:130 actions/facebookinvite.php:143 #, php-format msgid "Send invitations" msgstr "" @@ -3555,7 +3725,8 @@ msgid "Disfavor favorite" msgstr "" #: actions/favorited.php:65 lib/popularnoticesection.php:76 -#: lib/publicgroupnav.php:91 +#: lib/publicgroupnav.php:91 lib/popularnoticesection.php:82 +#: lib/publicgroupnav.php:93 msgid "Popular notices" msgstr "" @@ -3569,7 +3740,7 @@ msgid "The most popular notices on the site right now." msgstr "" #: actions/featured.php:69 lib/featureduserssection.php:82 -#: lib/publicgroupnav.php:87 +#: lib/publicgroupnav.php:87 lib/publicgroupnav.php:89 msgid "Featured users" msgstr "" @@ -3592,6 +3763,7 @@ msgid "No ID" msgstr "" #: actions/grouplogo.php:138 actions/grouplogo.php:191 +#: actions/grouplogo.php:144 actions/grouplogo.php:197 msgid "Group logo" msgstr "" @@ -3599,11 +3771,11 @@ msgstr "" msgid "You can upload a logo image for your group." msgstr "" -#: actions/grouplogo.php:448 +#: actions/grouplogo.php:448 actions/grouplogo.php:401 msgid "Logo updated." msgstr "" -#: actions/grouplogo.php:450 +#: actions/grouplogo.php:450 actions/grouplogo.php:403 msgid "Failed updating logo." msgstr "" @@ -3622,7 +3794,7 @@ msgid "A list of the users in this group." msgstr "" #: actions/groups.php:62 actions/showstream.php:518 lib/publicgroupnav.php:79 -#: lib/subgroupnav.php:96 +#: lib/subgroupnav.php:96 lib/publicgroupnav.php:81 msgid "Groups" msgstr "" @@ -3637,6 +3809,7 @@ msgid "%%%%site.name%%%% groups let you find and talk with " msgstr "" #: actions/groups.php:106 actions/usergroups.php:124 lib/groupeditform.php:123 +#: actions/usergroups.php:125 msgid "Create a new group" msgstr "" @@ -3706,21 +3879,21 @@ msgstr "" msgid "You may not leave a group while you are its administrator." msgstr "" -#: actions/leavegroup.php:130 +#: actions/leavegroup.php:130 actions/leavegroup.php:124 msgid "Could not find membership record." msgstr "" -#: actions/leavegroup.php:138 +#: actions/leavegroup.php:138 actions/leavegroup.php:132 #, php-format msgid "Could not remove user %s to group %s" msgstr "" -#: actions/leavegroup.php:145 +#: actions/leavegroup.php:145 actions/leavegroup.php:139 #, php-format msgid "%s left group %s" msgstr "" -#: actions/login.php:225 lib/facebookaction.php:304 +#: actions/login.php:225 lib/facebookaction.php:304 actions/login.php:208 msgid "Login to site" msgstr "" @@ -3752,11 +3925,12 @@ msgstr "" msgid "Don't send a message to yourself; " msgstr "" -#: actions/newnotice.php:166 +#: actions/newnotice.php:166 actions/newnotice.php:174 msgid "Notice posted" msgstr "" -#: actions/newnotice.php:200 classes/Channel.php:163 +#: actions/newnotice.php:200 classes/Channel.php:163 actions/newnotice.php:208 +#: lib/channel.php:170 msgid "Ajax Error" msgstr "" @@ -3773,7 +3947,7 @@ msgstr "" msgid "Nudge sent!" msgstr "" -#: actions/openidlogin.php:97 +#: actions/openidlogin.php:97 actions/openidlogin.php:106 msgid "OpenID login" msgstr "" @@ -3813,12 +3987,12 @@ msgstr "" msgid "Password change" msgstr "" -#: actions/peopletag.php:35 +#: actions/peopletag.php:35 actions/peopletag.php:70 #, php-format msgid "Not a valid people tag: %s" msgstr "" -#: actions/peopletag.php:47 +#: actions/peopletag.php:47 actions/peopletag.php:144 #, php-format msgid "Users self-tagged with %s - page %d" msgstr "" @@ -3842,6 +4016,7 @@ msgid "Automatically subscribe to whoever " msgstr "" #: actions/profilesettings.php:229 actions/tagother.php:176 +#: actions/tagother.php:178 #, php-format msgid "Invalid tag: \"%s\"" msgstr "" @@ -3850,12 +4025,12 @@ msgstr "" msgid "Couldn't save tags." msgstr "" -#: actions/public.php:107 +#: actions/public.php:107 actions/public.php:110 #, php-format msgid "Public timeline, page %d" msgstr "" -#: actions/public.php:173 +#: actions/public.php:173 actions/public.php:184 msgid "Could not retrieve public stream." msgstr "" @@ -3928,7 +4103,7 @@ msgstr "" msgid "That's a local profile! Login to subscribe." msgstr "" -#: actions/replies.php:118 +#: actions/replies.php:118 actions/replies.php:120 #, php-format msgid "Replies to %s, page %d" msgstr "" @@ -3948,40 +4123,45 @@ msgstr "" msgid "%s group, page %d" msgstr "" -#: actions/showgroup.php:206 +#: actions/showgroup.php:206 actions/showgroup.php:208 msgid "Group profile" msgstr "" #: actions/showgroup.php:251 actions/showstream.php:278 #: actions/tagother.php:119 lib/grouplist.php:134 lib/profilelist.php:133 +#: actions/showgroup.php:253 actions/showstream.php:271 +#: actions/tagother.php:118 lib/profilelist.php:131 msgid "URL" msgstr "" #: actions/showgroup.php:262 actions/showstream.php:289 #: actions/tagother.php:129 lib/grouplist.php:145 lib/profilelist.php:144 +#: actions/showgroup.php:264 actions/showstream.php:282 +#: actions/tagother.php:128 lib/profilelist.php:142 msgid "Note" msgstr "" -#: actions/showgroup.php:270 +#: actions/showgroup.php:270 actions/showgroup.php:272 msgid "Group actions" msgstr "" -#: actions/showgroup.php:323 +#: actions/showgroup.php:323 actions/showgroup.php:304 #, php-format msgid "Notice feed for %s group" msgstr "" -#: actions/showgroup.php:357 lib/groupnav.php:90 +#: actions/showgroup.php:357 lib/groupnav.php:90 actions/showgroup.php:339 +#: actions/showgroup.php:384 msgid "Members" msgstr "" #: actions/showgroup.php:363 actions/showstream.php:413 #: actions/showstream.php:442 actions/showstream.php:524 lib/section.php:95 -#: lib/tagcloudsection.php:71 +#: lib/tagcloudsection.php:71 actions/showgroup.php:344 msgid "(None)" msgstr "" -#: actions/showgroup.php:370 +#: actions/showgroup.php:370 actions/showgroup.php:350 msgid "All members" msgstr "" @@ -4006,14 +4186,16 @@ msgid "'s profile" msgstr "" #: actions/showstream.php:236 actions/tagother.php:77 +#: actions/showstream.php:220 msgid "User profile" msgstr "" #: actions/showstream.php:240 actions/tagother.php:81 +#: actions/showstream.php:224 msgid "Photo" msgstr "" -#: actions/showstream.php:317 +#: actions/showstream.php:317 actions/showstream.php:309 msgid "User actions" msgstr "" @@ -4110,16 +4292,16 @@ msgstr "" msgid "These are the people whose " msgstr "" -#: actions/subscriptions.php:122 +#: actions/subscriptions.php:122 actions/subscriptions.php:124 msgid "Jabber" msgstr "" -#: actions/tag.php:43 +#: actions/tag.php:43 actions/tag.php:51 #, php-format msgid "Notices tagged with %s, page %d" msgstr "" -#: actions/tag.php:66 +#: actions/tag.php:66 actions/tag.php:73 #, php-format msgid "Messages tagged \"%s\", most recent first" msgstr "" @@ -4141,7 +4323,7 @@ msgstr "" msgid "Tag user" msgstr "" -#: actions/tagother.php:149 +#: actions/tagother.php:149 actions/tagother.php:151 msgid "" "Tags for this user (letters, numbers, -, ., and _), comma- or space- " "separated" @@ -4151,16 +4333,16 @@ msgstr "" msgid "There was a problem with your session token." msgstr "" -#: actions/tagother.php:191 +#: actions/tagother.php:191 actions/tagother.php:193 msgid "" "You can only tag people you are subscribed to or who are subscribed to you." msgstr "" -#: actions/tagother.php:198 +#: actions/tagother.php:198 actions/tagother.php:200 msgid "Could not save tags." msgstr "" -#: actions/tagother.php:233 +#: actions/tagother.php:233 actions/tagother.php:235 msgid "Use this form to add tags to your subscribers or subscriptions." msgstr "" @@ -4168,7 +4350,7 @@ msgstr "" msgid "No such tag." msgstr "" -#: actions/tagrss.php:66 +#: actions/tagrss.php:66 actions/tagrss.php:64 #, php-format msgid "Microblog tagged with %s" msgstr "" @@ -4181,7 +4363,7 @@ msgstr "" msgid "Unblock user failed." msgstr "" -#: actions/twitapiusers.php:48 +#: actions/twitapiusers.php:48 actions/twitapiusers.php:52 msgid "Not found." msgstr "" @@ -4189,15 +4371,15 @@ msgstr "" msgid "Add your Twitter account to automatically send " msgstr "" -#: actions/twittersettings.php:119 +#: actions/twittersettings.php:119 actions/twittersettings.php:122 msgid "Twitter user name" msgstr "" -#: actions/twittersettings.php:126 +#: actions/twittersettings.php:126 actions/twittersettings.php:129 msgid "Twitter password" msgstr "" -#: actions/twittersettings.php:228 +#: actions/twittersettings.php:228 actions/twittersettings.php:232 msgid "Twitter Friends" msgstr "" @@ -4236,16 +4418,16 @@ msgstr "" msgid "%s groups, page %d" msgstr "" -#: classes/Notice.php:104 +#: classes/Notice.php:104 classes/Notice.php:128 msgid "Problem saving notice. Unknown user." msgstr "" -#: classes/Notice.php:109 +#: classes/Notice.php:109 classes/Notice.php:133 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" -#: classes/Notice.php:116 +#: classes/Notice.php:116 classes/Notice.php:145 msgid "You are banned from posting notices on this site." msgstr "" @@ -4261,84 +4443,84 @@ msgstr "" msgid "Other options" msgstr "" -#: lib/action.php:130 +#: lib/action.php:130 lib/action.php:132 #, php-format msgid "%s - %s" msgstr "" -#: lib/action.php:145 +#: lib/action.php:145 lib/action.php:147 msgid "Untitled page" msgstr "" -#: lib/action.php:316 +#: lib/action.php:316 lib/action.php:387 msgid "Primary site navigation" msgstr "" -#: lib/action.php:322 +#: lib/action.php:322 lib/action.php:393 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:325 +#: lib/action.php:325 lib/action.php:396 msgid "Search for people or text" msgstr "" -#: lib/action.php:328 +#: lib/action.php:328 lib/action.php:399 msgid "Account" msgstr "" -#: lib/action.php:328 +#: lib/action.php:328 lib/action.php:399 msgid "Change your email, avatar, password, profile" msgstr "" -#: lib/action.php:330 +#: lib/action.php:330 lib/action.php:403 msgid "Connect to IM, SMS, Twitter" msgstr "" -#: lib/action.php:332 +#: lib/action.php:332 lib/action.php:409 msgid "Logout from the site" msgstr "" -#: lib/action.php:335 +#: lib/action.php:335 lib/action.php:412 msgid "Login to the site" msgstr "" -#: lib/action.php:338 +#: lib/action.php:338 lib/action.php:415 msgid "Create an account" msgstr "" -#: lib/action.php:341 +#: lib/action.php:341 lib/action.php:418 msgid "Login with OpenID" msgstr "" -#: lib/action.php:344 +#: lib/action.php:344 lib/action.php:421 msgid "Help me!" msgstr "" -#: lib/action.php:362 +#: lib/action.php:362 lib/action.php:441 msgid "Site notice" msgstr "" -#: lib/action.php:417 +#: lib/action.php:417 lib/action.php:504 msgid "Local views" msgstr "" -#: lib/action.php:472 +#: lib/action.php:472 lib/action.php:559 msgid "Page notice" msgstr "" -#: lib/action.php:562 +#: lib/action.php:562 lib/action.php:654 msgid "Secondary site navigation" msgstr "" -#: lib/action.php:602 lib/action.php:623 +#: lib/action.php:602 lib/action.php:623 lib/action.php:699 lib/action.php:720 msgid "Laconica software license" msgstr "" -#: lib/action.php:630 +#: lib/action.php:630 lib/action.php:727 msgid "All " msgstr "" -#: lib/action.php:635 +#: lib/action.php:635 lib/action.php:732 msgid "license." msgstr "" @@ -4359,11 +4541,12 @@ msgstr "" msgid "To use the %s Facebook Application you need to login " msgstr "" -#: lib/facebookaction.php:271 +#: lib/facebookaction.php:271 lib/facebookaction.php:273 msgid " a new account." msgstr "" #: lib/facebookaction.php:557 lib/mailbox.php:214 lib/noticelist.php:354 +#: lib/facebookaction.php:675 lib/mailbox.php:216 lib/noticelist.php:357 msgid "Published" msgstr "" @@ -4500,7 +4683,7 @@ msgid "" "\n" msgstr "" -#: lib/mail.php:461 +#: lib/mail.php:461 lib/mail.php:462 #, php-format msgid "You've been nudged by %s" msgstr "" @@ -4515,11 +4698,12 @@ msgstr "" msgid "%1$s just added your notice from %2$s" msgstr "" -#: lib/mailbox.php:229 lib/noticelist.php:380 +#: lib/mailbox.php:229 lib/noticelist.php:380 lib/mailbox.php:231 +#: lib/noticelist.php:383 msgid "From" msgstr "" -#: lib/messageform.php:110 +#: lib/messageform.php:110 lib/messageform.php:109 msgid "Send a direct notice" msgstr "" @@ -4531,23 +4715,26 @@ msgstr "" msgid "Available characters" msgstr "" -#: lib/noticelist.php:426 +#: lib/noticelist.php:426 lib/noticelist.php:429 msgid "in reply to" msgstr "" -#: lib/noticelist.php:447 lib/noticelist.php:450 +#: lib/noticelist.php:447 lib/noticelist.php:450 lib/noticelist.php:451 +#: lib/noticelist.php:454 msgid "Reply to this notice" msgstr "" -#: lib/noticelist.php:451 +#: lib/noticelist.php:451 lib/noticelist.php:455 msgid "Reply" msgstr "" -#: lib/noticelist.php:471 lib/noticelist.php:474 +#: lib/noticelist.php:471 lib/noticelist.php:474 lib/noticelist.php:476 +#: lib/noticelist.php:479 msgid "Delete this notice" msgstr "" -#: lib/noticelist.php:474 +#: lib/noticelist.php:474 actions/avatarsettings.php:148 +#: lib/noticelist.php:479 msgid "Delete" msgstr "" @@ -4568,27 +4755,28 @@ msgstr "" msgid "Tags in %s's notices" msgstr "" -#: lib/profilelist.php:182 +#: lib/profilelist.php:182 lib/profilelist.php:180 msgid "(none)" msgstr "" -#: lib/publicgroupnav.php:76 +#: lib/publicgroupnav.php:76 lib/publicgroupnav.php:78 msgid "Public" msgstr "" -#: lib/publicgroupnav.php:80 +#: lib/publicgroupnav.php:80 lib/publicgroupnav.php:82 msgid "User groups" msgstr "" #: lib/publicgroupnav.php:82 lib/publicgroupnav.php:83 +#: lib/publicgroupnav.php:84 lib/publicgroupnav.php:85 msgid "Recent tags" msgstr "" -#: lib/publicgroupnav.php:86 +#: lib/publicgroupnav.php:86 lib/publicgroupnav.php:88 msgid "Featured" msgstr "" -#: lib/publicgroupnav.php:90 +#: lib/publicgroupnav.php:90 lib/publicgroupnav.php:92 msgid "Popular" msgstr "" @@ -4651,3 +4839,462 @@ msgstr "" #: lib/unsubscribeform.php:113 lib/unsubscribeform.php:137 msgid "Unsubscribe from this user" msgstr "" + +#: actions/all.php:77 +#, php-format +msgid "Feed for friends of %s (RSS 1.0)" +msgstr "" + +#: actions/all.php:82 +#, php-format +msgid "Feed for friends of %s (RSS 2.0)" +msgstr "" + +#: actions/all.php:87 +#, php-format +msgid "Feed for friends of %s (Atom)" +msgstr "" + +#: actions/all.php:112 +msgid "You and friends" +msgstr "" + +#: actions/avatarsettings.php:78 +#, php-format +msgid "You can upload your personal avatar. The maximum file size is %s." +msgstr "" + +#: actions/avatarsettings.php:373 +msgid "Avatar deleted." +msgstr "" + +#: actions/block.php:129 +msgid "" +"Are you sure you want to block this user? Afterwards, they will be " +"unsubscribed from you, unable to subscribe to you in the future, and you " +"will not be notified of any @-replies from them." +msgstr "" + +#: actions/deletenotice.php:73 +msgid "" +"You are about to permanently delete a notice. Once this is done, it cannot " +"be undone." +msgstr "" + +#: actions/deletenotice.php:127 +msgid "There was a problem with your session token. Try again, please." +msgstr "" + +#: actions/emailsettings.php:168 +msgid "Send me email when someone sends me an \"@-reply\"." +msgstr "" + +#: actions/facebookhome.php:193 +#, php-format +msgid "" +"If you would like the %s app to automatically update your Facebook status " +"with your latest notice, you need to give it permission." +msgstr "" + +#: actions/facebookhome.php:217 +#, php-format +msgid "Okay, do it!" +msgstr "" + +#: actions/facebooksettings.php:124 +#, php-format +msgid "" +"If you would like %s to automatically update your Facebook status with your " +"latest notice, you need to give it permission." +msgstr "" + +#: actions/grouplogo.php:155 +#, php-format +msgid "" +"You can upload a logo image for your group. The maximum file size is %s." +msgstr "" + +#: actions/grouplogo.php:367 +msgid "Pick a square area of the image to be the logo." +msgstr "" + +#: actions/grouprss.php:136 +#, php-format +msgid "Microblog by %s group" +msgstr "" + +#: actions/groupsearch.php:57 +#, php-format +msgid "" +"Search for groups on %%site.name%% by their name, location, or description. " +"Separate the terms by spaces; they must be 3 characters or more." +msgstr "" + +#: actions/groups.php:90 +#, php-format +msgid "" +"%%%%site.name%%%% groups let you find and talk with people of similar " +"interests. After you join a group you can send messages to all other members " +"using the syntax \"!groupname\". Don't see a group you like? Try [searching " +"for one](%%%%action.groupsearch%%%%) or [start your own!](%%%%action.newgroup" +"%%%%)" +msgstr "" + +#: actions/newmessage.php:102 +msgid "Only logged-in users can send direct messages." +msgstr "" + +#: actions/noticesearch.php:91 +#, php-format +msgid "Search results for \"%s\" on %s" +msgstr "" + +#: actions/openidlogin.php:66 +#, php-format +msgid "" +"For security reasons, please re-login with your [OpenID](%%doc.openid%%) " +"before changing your settings." +msgstr "" + +#: actions/public.php:125 +msgid "Public Stream Feed (RSS 1.0)" +msgstr "" + +#: actions/public.php:130 +msgid "Public Stream Feed (RSS 2.0)" +msgstr "" + +#: actions/public.php:135 +msgid "Public Stream Feed (Atom)" +msgstr "" + +#: actions/public.php:210 +#, php-format +msgid "" +"This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-" +"blogging) service based on the Free Software [Laconica](http://laconi.ca/) " +"tool. [Join now](%%action.register%%) to share notices about yourself with " +"friends, family, and colleagues! ([Read more](%%doc.help%%))" +msgstr "" + +#: actions/register.php:286 +#, php-format +msgid "" +"With this form you can create a new account. You can then post notices and " +"link up to friends and colleagues. (Have an [OpenID](http://openid.net/)? " +"Try our [OpenID registration](%%action.openidlogin%%)!)" +msgstr "" + +#: actions/register.php:432 +msgid "Creative Commons Attribution 3.0" +msgstr "" + +#: actions/register.php:433 +msgid "" +" except this private data: password, email address, IM address, and phone " +"number." +msgstr "" + +#: actions/showgroup.php:378 +msgid "Created" +msgstr "" + +#: actions/showgroup.php:393 +#, php-format +msgid "" +"**%s** is a user group on %%%%site.name%%%%, a [micro-blogging](http://en." +"wikipedia.org/wiki/Micro-blogging) service based on the Free Software " +"[Laconica](http://laconi.ca/) tool. Its members share short messages about " +"their life and interests. [Join now](%%%%action.register%%%%) to become part " +"of this group and many more! ([Read more](%%%%doc.help%%%%))" +msgstr "" + +#: actions/showstream.php:147 +msgid "Your profile" +msgstr "" + +#: actions/showstream.php:149 +#, php-format +msgid "%s's profile" +msgstr "" + +#: actions/showstream.php:163 +#, php-format +msgid "Notice feed for %s (RSS 1.0)" +msgstr "" + +#: actions/showstream.php:170 +#, php-format +msgid "Notice feed for %s (RSS 2.0)" +msgstr "" + +#: actions/showstream.php:177 +#, php-format +msgid "Notice feed for %s (Atom)" +msgstr "" + +#: actions/showstream.php:182 +#, php-format +msgid "FOAF for %s" +msgstr "" + +#: actions/showstream.php:237 +msgid "Edit Avatar" +msgstr "" + +#: actions/showstream.php:316 +msgid "Edit profile settings" +msgstr "" + +#: actions/showstream.php:317 +msgid "Edit" +msgstr "" + +#: actions/showstream.php:542 +#, php-format +msgid "" +"**%s** has an account on %%%%site.name%%%%, a [micro-blogging](http://en." +"wikipedia.org/wiki/Micro-blogging) service based on the Free Software " +"[Laconica](http://laconi.ca/) tool. [Join now](%%%%action.register%%%%) to " +"follow **%s**'s notices and many more! ([Read more](%%%%doc.help%%%%))" +msgstr "" + +#: actions/smssettings.php:335 +msgid "" +"A confirmation code was sent to the phone number you added. Check your phone " +"for the code and instructions on how to use it." +msgstr "" + +#: actions/twitapifavorites.php:171 lib/mail.php:556 +#, php-format +msgid "" +"%1$s just added your notice from %2$s as one of their favorites.\n" +"\n" +"In case you forgot, you can see the text of your notice here:\n" +"\n" +"%3$s\n" +"\n" +"You can see the list of %1$s's favorites here:\n" +"\n" +"%4$s\n" +"\n" +"Faithfully yours,\n" +"%5$s\n" +msgstr "" + +#: actions/twitapistatuses.php:124 +msgid "No such user!" +msgstr "" + +#: actions/twittersettings.php:72 +msgid "" +"Add your Twitter account to automatically send your notices to Twitter, and " +"subscribe to Twitter friends already here." +msgstr "" + +#: actions/twittersettings.php:345 +#, php-format +msgid "Unable to retrieve account information For \"%s\" from Twitter." +msgstr "" + +#: actions/userauthorization.php:86 +msgid "" +"Please check these details to make sure that you want to subscribe to this " +"user's notices. If you didn't just ask to subscribe to someone's notices, " +"click \"Reject\"." +msgstr "" + +#: actions/usergroups.php:131 +msgid "Search for more groups" +msgstr "" + +#: classes/Notice.php:138 +msgid "" +"Too many duplicate messages too quickly; take a breather and post again in a " +"few minutes." +msgstr "" + +#: lib/action.php:406 +msgid "Connect to SMS, Twitter" +msgstr "" + +#: lib/action.php:671 +msgid "Badge" +msgstr "" + +#: lib/command.php:113 +#, php-format +msgid "" +"Subscriptions: %1$s\n" +"Subscribers: %2$s\n" +"Notices: %3$s" +msgstr "" + +#: lib/command.php:392 +msgid "" +"Commands:\n" +"on - turn on notifications\n" +"off - turn off notifications\n" +"help - show this help\n" +"follow - subscribe to user\n" +"leave - unsubscribe from user\n" +"d - direct message to user\n" +"get - get last notice from user\n" +"whois - get profile info on user\n" +"fav - add user's last notice as a 'fave'\n" +"stats - get your stats\n" +"stop - same as 'off'\n" +"quit - same as 'off'\n" +"sub - same as 'follow'\n" +"unsub - same as 'leave'\n" +"last - same as 'get'\n" +"on - not yet implemented.\n" +"off - not yet implemented.\n" +"nudge - not yet implemented.\n" +"invite - not yet implemented.\n" +"track - not yet implemented.\n" +"untrack - not yet implemented.\n" +"track off - not yet implemented.\n" +"untrack all - not yet implemented.\n" +"tracks - not yet implemented.\n" +"tracking - not yet implemented.\n" +msgstr "" + +#: lib/dberroraction.php:60 +msgid "Database error" +msgstr "" + +#: lib/facebookaction.php:271 +#, php-format +msgid "" +"To use the %s Facebook Application you need to login with your username and " +"password. Don't have a username yet? " +msgstr "" + +#: lib/feed.php:85 +msgid "RSS 1.0" +msgstr "" + +#: lib/feed.php:87 +msgid "RSS 2.0" +msgstr "" + +#: lib/feed.php:89 +msgid "Atom" +msgstr "" + +#: lib/feed.php:91 +msgid "FOAF" +msgstr "" + +#: lib/imagefile.php:75 +#, php-format +msgid "That file is too big. The maximum file size is %d." +msgstr "" + +#: lib/mail.php:175 +#, php-format +msgid "" +"Hey, %s.\n" +"\n" +"Someone just entered this email address on %s.\n" +"\n" +"If it was you, and you want to confirm your entry, use the URL below:\n" +"\n" +"\t%s\n" +"\n" +"If not, just ignore this message.\n" +"\n" +"Thanks for your time, \n" +"%s\n" +msgstr "" + +#: lib/mail.php:241 +#, php-format +msgid "" +"%1$s is now listening to your notices on %2$s.\n" +"\n" +"\t%3$s\n" +"\n" +"%4$s%5$s%6$s\n" +"Faithfully yours,\n" +"%7$s.\n" +"\n" +"----\n" +"Change your email address or notification options at %8$s\n" +msgstr "" + +#: lib/mail.php:466 +#, php-format +msgid "" +"%1$s (%2$s) is wondering what you are up to these days and is inviting you " +"to post some news.\n" +"\n" +"So let's hear from you :)\n" +"\n" +"%3$s\n" +"\n" +"Don't reply to this email; it won't get to them.\n" +"\n" +"With kind regards,\n" +"%4$s\n" +msgstr "" + +#: lib/mail.php:513 +#, php-format +msgid "" +"%1$s (%2$s) sent you a private message:\n" +"\n" +"------------------------------------------------------\n" +"%3$s\n" +"------------------------------------------------------\n" +"\n" +"You can reply to their message here:\n" +"\n" +"%4$s\n" +"\n" +"Don't reply to this email; it won't get to them.\n" +"\n" +"With kind regards,\n" +"%5$s\n" +msgstr "" + +#: lib/mail.php:598 +#, php-format +msgid "%s sent a notice to your attention" +msgstr "" + +#: lib/mail.php:600 +#, php-format +msgid "" +"%1$s just sent a notice to your attention (an '@-reply') on %2$s.\n" +"\n" +"The notice is here:\n" +"\n" +"\t%3$s\n" +"\n" +"It reads:\n" +"\n" +"\t%4$s\n" +"\n" +"You can reply back here:\n" +"\n" +"\t%5$s\n" +"\n" +"The list of all @-replies for you here:\n" +"\n" +"%6$s\n" +"\n" +"Faithfully yours,\n" +"%2$s\n" +"\n" +"P.S. You can turn off these email notifications here: %7$s\n" +msgstr "" + +#: lib/searchaction.php:122 +msgid "Search site" +msgstr "" + +#: lib/section.php:106 +msgid "More..." +msgstr "" diff --git a/scripts/update_pot.sh b/scripts/update_pot.sh index f3526d514c..a7f5e4d3a0 100755 --- a/scripts/update_pot.sh +++ b/scripts/update_pot.sh @@ -1,3 +1,3 @@ cd `dirname $0` cd .. -xgettext --from-code=UTF-8 --default-domain=laconica --output=locale/laconica.pot --language=PHP --join-existing actions/*.php classes/*.php lib/*.php scripts/*.php +xgettext --from-code=UTF-8 --default-domain=laconica --output=locale/laconica.po --language=PHP --join-existing actions/*.php classes/*.php lib/*.php scripts/*.php From 70d5fc46845804507640e354c9d9e06367a53fb0 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 11 Mar 2009 16:21:10 -0400 Subject: [PATCH 52/58] Document the site-logo configuration option The configuration option for site logo wasn't well documented, so I added it to the README file, config.php.sample, and common.php. --- README | 2 ++ config.php.sample | 3 +++ lib/common.php | 1 + 3 files changed, 6 insertions(+) diff --git a/README b/README index 07957c09e9..1c2cbe681f 100644 --- a/README +++ b/README @@ -884,6 +884,8 @@ notice: A plain string that will appear on every page. A good place be escaped. dupelimit: Time in which it's not OK for the same person to post the same notice; default = 60 seconds. +logo: URL of an image file to use as the logo for the site. Overrides + the logo in the theme, if any. db -- diff --git a/config.php.sample b/config.php.sample index e9052bbf9e..529e86f15f 100644 --- a/config.php.sample +++ b/config.php.sample @@ -37,6 +37,9 @@ $config['site']['path'] = 'laconica'; # Enables extra log information, for example full details of PEAR DB errors #$config['site']['logdebug'] = true; +#To set your own logo, overriding the one in the theme +#$config['site']['logo'] = '/mylogo.png'; + # This is a PEAR DB DSN, see http://pear.php.net/manual/en/package.database.db.intro-dsn.php # Set it to match your actual database diff --git a/lib/common.php b/lib/common.php index c3d697aeed..7739d94752 100644 --- a/lib/common.php +++ b/lib/common.php @@ -73,6 +73,7 @@ $config = 'theme' => 'default', 'path' => $_path, 'logfile' => null, + 'logo' => null, 'logdebug' => false, 'fancy' => false, 'locale_path' => INSTALLDIR.'/locale', From dfd9e318599a527e2b8ad9b3374143cfcdd02fda Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 11 Mar 2009 19:42:53 -0400 Subject: [PATCH 53/58] Add initial trackback support --- plugins/LinkbackPlugin.php | 95 +++++++++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 6 deletions(-) diff --git a/plugins/LinkbackPlugin.php b/plugins/LinkbackPlugin.php index 77adfa87d1..1b5365100e 100644 --- a/plugins/LinkbackPlugin.php +++ b/plugins/LinkbackPlugin.php @@ -94,18 +94,25 @@ class LinkbackPlugin extends Plugin return $orig; } + $pb = null; + $tb = null; + if (array_key_exists('X-Pingback', $result->headers)) { - $endpoint = $result->headers['X-Pingback']; + $pb = $result->headers['X-Pingback']; } else if (preg_match('//', $result->body, $match)) { - $endpoint = $match[1]; - } else { - // XXX: do Trackback lookup - return $orig; + $pb = $match[1]; + } + + $tb = $this->getTrackback($result->body, $result->final_url); + + if (!empty($tb)) { + $this->trackback($result->final_url, $tb); + } else if (!empty($pb)) { + $this->pingback($result->final_url, $pb); } - $this->pingback($url, $endpoint); return $orig; } @@ -132,6 +139,82 @@ class LinkbackPlugin extends Plugin } } + // Largely cadged from trackback_cls.php by + // Ran Aroussi , GPL2 + // http://phptrackback.sourceforge.net/ + + function getTrackback($text, $url) + { + if (preg_match_all('/()/sm', $text, $match, PREG_SET_ORDER)) { + for ($i = 0; $i < count($match); $i++) { + if (preg_match('|dc:identifier="' . preg_quote($url) . '"|ms', $match[$i][1])) { + $rdf_array[] = trim($match[$i][1]); + } + } + + // Loop through the RDFs array and extract trackback URIs + + $tb_array = array(); // <- holds list of trackback URIs + + if (!empty($rdf_array)) { + + for ($i = 0; $i < count($rdf_array); $i++) { + if (preg_match('/trackback:ping="([^"]+)"/', $rdf_array[$i], $array)) { + $tb_array[] = trim($array[1]); + break; + } + } + } + + // Return Trackbacks + + if (empty($tb_array)) { + return null; + } else { + return $tb_array[0]; + } + } + + if (preg_match_all('/(]*?rel=[\'"]trackback[\'"][^>]*?>)/', $text, $match)) { + foreach ($match[1] as $atag) { + if (preg_match('/href=[\'"]([^\'"]*?)[\'"]/', $atag, $url)) { + return $url[1]; + } + } + } + + return null; + + } + + function trackback($url, $endpoint) + { + $profile = $this->notice->getProfile(); + + $args = array('title' => sprintf(_('%1$s\'s status on %2$s'), + $profile->nickname, + common_exact_date($this->notice->created)), + 'excerpt' => $this->notice->content, + 'url' => $this->notice->uri, + 'blog_name' => $profile->nickname); + + $fetcher = Auth_Yadis_Yadis::getHTTPFetcher(); + + $result = $fetcher->post($endpoint, + http_build_query($args), + array('User-Agent: ' . $this->userAgent())); + + if ($result->status != '200') { + common_log(LOG_WARNING, + "Trackback error for '$url' ($endpoint): ". + "$result->body"); + } else { + common_log(LOG_INFO, + "Trackback success for '$url' ($endpoint): ". + "'$result->body'"); + } + } + function userAgent() { return 'LinkbackPlugin/'.LINKBACKPLUGIN_VERSION . From c08e4d904ec80144379c5728e2274e3513e6c819 Mon Sep 17 00:00:00 2001 From: CiaranG Date: Wed, 11 Mar 2009 23:41:30 +0000 Subject: [PATCH 54/58] PostgreSQL - a few more query compatibility issues (submitted by oxygene) --- actions/peopletag.php | 2 +- actions/sup.php | 4 +++- classes/Notice.php | 6 +++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/actions/peopletag.php b/actions/peopletag.php index 6b1e34f1ab..5add754858 100644 --- a/actions/peopletag.php +++ b/actions/peopletag.php @@ -119,7 +119,7 @@ class PeopletagAction extends Action 'FROM profile JOIN profile_tag ' . 'ON profile.id = profile_tag.tagger ' . 'WHERE profile_tag.tagger = profile_tag.tagged ' . - 'AND tag = "%s" ' . + "AND tag = '%s' " . 'ORDER BY profile_tag.modified DESC%s'; $profile->query(sprintf($qry, $this->tag, $lim)); diff --git a/actions/sup.php b/actions/sup.php index f4b1cda230..8ef9207fac 100644 --- a/actions/sup.php +++ b/actions/sup.php @@ -65,7 +65,9 @@ class SupAction extends Action $notice->query('SELECT profile_id, max(id) AS max_id ' . 'FROM notice ' . - 'WHERE created > (now() - ' . $seconds . ') ' . + ((common_config('db','type') == 'pgsql') ? + 'WHERE extract(epoch from created) > (extract(epoch from now()) - ' . $seconds . ') ' : + 'WHERE created > (now() - ' . $seconds . ') ' ) . 'GROUP BY profile_id'); $updates = array(); diff --git a/classes/Notice.php b/classes/Notice.php index 1e3b330f26..3087e39a78 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -232,7 +232,11 @@ class Notice extends Memcached_DataObject $notice = new Notice(); $notice->profile_id = $profile_id; $notice->content = $content; - $notice->whereAdd('now() - created < ' . common_config('site', 'dupelimit')); + if (common_config('db','type') == 'pgsql') + $notice->whereAdd('extract(epoch from now() - created) < ' . common_config('site', 'dupelimit')); + else + $notice->whereAdd('now() - created < ' . common_config('site', 'dupelimit')); + $cnt = $notice->count(); return ($cnt == 0); } From 254e5e502017dad767a6b57aa2c5c9422d6e02e5 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 11 Mar 2009 22:28:42 -0400 Subject: [PATCH 55/58] Update README and version number Update the README and the version number for this release. --- README | 50 ++++++++++++++++++++++++++++++++++++++++++++++---- lib/common.php | 2 +- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/README b/README index 1c2cbe681f..a7798a26a8 100644 --- a/README +++ b/README @@ -2,8 +2,8 @@ README ------ -Laconica 0.7.1 ("West of the Fields") -6 February 2009 +Laconica 0.7.2 ("Talk about the Passion") +11 March 2009 This is the README file for Laconica, the Open Source microblogging platform. It includes installation instructions, descriptions of @@ -71,8 +71,47 @@ for additional terms. New this version ================ -This is a minor bug-fix release since version 0.7.0, released Jan 29 -2009. Notable changes this version: +This is a minor bug-fix and feature release since version 0.7.1, +released Feb 9 2009. Notable changes this version: + +- First version of a web-based installer +- Use Net_URL_Mapper instead of mod_rewrite to map "fancy URLs", + for a much simpler installation and use of PATH_INFO on sites + that don't have mod_rewrite. +- A plugin framework for system events, to make it easier to build + server-side plugins. +- A plugin for Google Analytics +- A plugin to use blogspam.net to check notices for spam +- A plugin to send linkbacks for notices about blog posts +- Configurable check for duplicate notices in a specific time + period +- Better Atom feeds +- First implementation of Twitter Search API +- Add streamlined mobile device-friendly styles when enabled in config. +- A queue server for sending notices to Twitter +- A queue server for sending notices to Facebook +- A queue server for sending notices to a ping server +- Fixed a bug in nonces for OAuth in OpenMicroBlogging +- Fixed bugs in transfer of avatars in OpenMicroBlogging +- @-links go to permalinks for local users +- Better handling of DB errors (instead of dreaded DB_DataObject blank + screen) +- Initial version of an RPM spec file +- More consistent display of notices in notice search +- A stylesheet for printed output +- "Social graph" methods for Twitter API +- Documentation for the JavaScript badge +- Debugged a ton of problems that happened with E_NOTICE on +- Better caching in RSS feeds +- Optionally send email when an @-message is received +- Automatically add tags for every group message +- Add framebusting JavaScript to help avoid clickjacking attacks. +- Optionally ignore some notice sources for public page. +- Add default SMS carriers and notice sources to distribution file. +- Change titles to use mixed case instead of all uppercase. +- Use exceptions for error handling. + +Changes in version 0.7.1: - Vast improvement in auto-linking to URLs. - Link to group search from user's group page @@ -1228,6 +1267,9 @@ if anyone's been overlooked in error. * Ken Sheppardson (Trac server, man-about-town) * Tiago 'gouki' Faria (i18n managerx) * Sean Murphy +* Leslie Michael Orchard +* Eric Helgeson +* Ken Sedgwick Thanks also to the developers of our upstream library code and to the thousands of people who have tried out Identi.ca, installed Laconi.ca, diff --git a/lib/common.php b/lib/common.php index 7739d94752..44ed270d78 100644 --- a/lib/common.php +++ b/lib/common.php @@ -19,7 +19,7 @@ if (!defined('LACONICA')) { exit(1); } -define('LACONICA_VERSION', '0.7.1'); +define('LACONICA_VERSION', '0.7.2'); define('AVATAR_PROFILE_SIZE', 96); define('AVATAR_STREAM_SIZE', 48); From 745cdd206cb5b0c286c9b84bea6ee98ce4868d95 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 11 Mar 2009 23:43:03 -0400 Subject: [PATCH 56/58] fixup config errors --- index.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/index.php b/index.php index dae1ae7514..e83d08c13e 100644 --- a/index.php +++ b/index.php @@ -63,7 +63,7 @@ function handleError($error) function main() { - global $user, $action; + global $user, $action, $config; if (!_have_config()) { $msg = sprintf(_("No configuration file found. Try running ". @@ -131,11 +131,11 @@ function main() if (common_config('db', 'mirror') && $action_obj->isReadOnly()) { if (is_array(common_config('db', 'mirror'))) { // "load balancing", ha ha - $k = array_rand($config['db']['mirror']); - - $mirror = $config['db']['mirror'][$k]; + $arr = common_config('db', 'mirror'); + $k = array_rand($arr); + $mirror = $arr[$k]; } else { - $mirror = $config['db']['mirror']; + $mirror = common_config('db', 'mirror'); } $config['db']['database'] = $mirror; } From 93030ae7b65f9a6b508dac0365dbcff302b65b90 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 12 Mar 2009 00:02:25 -0400 Subject: [PATCH 57/58] add missing PEAR_Exception file --- extlib/PEAR/Exception.php | 397 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 397 insertions(+) create mode 100644 extlib/PEAR/Exception.php diff --git a/extlib/PEAR/Exception.php b/extlib/PEAR/Exception.php new file mode 100644 index 0000000000..b3d75b20c9 --- /dev/null +++ b/extlib/PEAR/Exception.php @@ -0,0 +1,397 @@ + + * @author Hans Lellelid + * @author Bertrand Mansion + * @author Greg Beaver + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Exception.php,v 1.29 2008/01/03 20:26:35 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.3.3 + */ + + +/** + * Base PEAR_Exception Class + * + * 1) Features: + * + * - Nestable exceptions (throw new PEAR_Exception($msg, $prev_exception)) + * - Definable triggers, shot when exceptions occur + * - Pretty and informative error messages + * - Added more context info available (like class, method or cause) + * - cause can be a PEAR_Exception or an array of mixed + * PEAR_Exceptions/PEAR_ErrorStack warnings + * - callbacks for specific exception classes and their children + * + * 2) Ideas: + * + * - Maybe a way to define a 'template' for the output + * + * 3) Inherited properties from PHP Exception Class: + * + * protected $message + * protected $code + * protected $line + * protected $file + * private $trace + * + * 4) Inherited methods from PHP Exception Class: + * + * __clone + * __construct + * getMessage + * getCode + * getFile + * getLine + * getTraceSafe + * getTraceSafeAsString + * __toString + * + * 5) Usage example + * + * + * require_once 'PEAR/Exception.php'; + * + * class Test { + * function foo() { + * throw new PEAR_Exception('Error Message', ERROR_CODE); + * } + * } + * + * function myLogger($pear_exception) { + * echo $pear_exception->getMessage(); + * } + * // each time a exception is thrown the 'myLogger' will be called + * // (its use is completely optional) + * PEAR_Exception::addObserver('myLogger'); + * $test = new Test; + * try { + * $test->foo(); + * } catch (PEAR_Exception $e) { + * print $e; + * } + * + * + * @category pear + * @package PEAR + * @author Tomas V.V.Cox + * @author Hans Lellelid + * @author Bertrand Mansion + * @author Greg Beaver + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.3.3 + * + */ +class PEAR_Exception extends Exception +{ + const OBSERVER_PRINT = -2; + const OBSERVER_TRIGGER = -4; + const OBSERVER_DIE = -8; + protected $cause; + private static $_observers = array(); + private static $_uniqueid = 0; + private $_trace; + + /** + * Supported signatures: + * - PEAR_Exception(string $message); + * - PEAR_Exception(string $message, int $code); + * - PEAR_Exception(string $message, Exception $cause); + * - PEAR_Exception(string $message, Exception $cause, int $code); + * - PEAR_Exception(string $message, PEAR_Error $cause); + * - PEAR_Exception(string $message, PEAR_Error $cause, int $code); + * - PEAR_Exception(string $message, array $causes); + * - PEAR_Exception(string $message, array $causes, int $code); + * @param string exception message + * @param int|Exception|PEAR_Error|array|null exception cause + * @param int|null exception code or null + */ + public function __construct($message, $p2 = null, $p3 = null) + { + if (is_int($p2)) { + $code = $p2; + $this->cause = null; + } elseif (is_object($p2) || is_array($p2)) { + // using is_object allows both Exception and PEAR_Error + if (is_object($p2) && !($p2 instanceof Exception)) { + if (!class_exists('PEAR_Error') || !($p2 instanceof PEAR_Error)) { + throw new PEAR_Exception('exception cause must be Exception, ' . + 'array, or PEAR_Error'); + } + } + $code = $p3; + if (is_array($p2) && isset($p2['message'])) { + // fix potential problem of passing in a single warning + $p2 = array($p2); + } + $this->cause = $p2; + } else { + $code = null; + $this->cause = null; + } + parent::__construct($message, $code); + $this->signal(); + } + + /** + * @param mixed $callback - A valid php callback, see php func is_callable() + * - A PEAR_Exception::OBSERVER_* constant + * - An array(const PEAR_Exception::OBSERVER_*, + * mixed $options) + * @param string $label The name of the observer. Use this if you want + * to remove it later with removeObserver() + */ + public static function addObserver($callback, $label = 'default') + { + self::$_observers[$label] = $callback; + } + + public static function removeObserver($label = 'default') + { + unset(self::$_observers[$label]); + } + + /** + * @return int unique identifier for an observer + */ + public static function getUniqueId() + { + return self::$_uniqueid++; + } + + private function signal() + { + foreach (self::$_observers as $func) { + if (is_callable($func)) { + call_user_func($func, $this); + continue; + } + settype($func, 'array'); + switch ($func[0]) { + case self::OBSERVER_PRINT : + $f = (isset($func[1])) ? $func[1] : '%s'; + printf($f, $this->getMessage()); + break; + case self::OBSERVER_TRIGGER : + $f = (isset($func[1])) ? $func[1] : E_USER_NOTICE; + trigger_error($this->getMessage(), $f); + break; + case self::OBSERVER_DIE : + $f = (isset($func[1])) ? $func[1] : '%s'; + die(printf($f, $this->getMessage())); + break; + default: + trigger_error('invalid observer type', E_USER_WARNING); + } + } + } + + /** + * Return specific error information that can be used for more detailed + * error messages or translation. + * + * This method may be overridden in child exception classes in order + * to add functionality not present in PEAR_Exception and is a placeholder + * to define API + * + * The returned array must be an associative array of parameter => value like so: + *
+     * array('name' => $name, 'context' => array(...))
+     * 
+ * @return array + */ + public function getErrorData() + { + return array(); + } + + /** + * Returns the exception that caused this exception to be thrown + * @access public + * @return Exception|array The context of the exception + */ + public function getCause() + { + return $this->cause; + } + + /** + * Function must be public to call on caused exceptions + * @param array + */ + public function getCauseMessage(&$causes) + { + $trace = $this->getTraceSafe(); + $cause = array('class' => get_class($this), + 'message' => $this->message, + 'file' => 'unknown', + 'line' => 'unknown'); + if (isset($trace[0])) { + if (isset($trace[0]['file'])) { + $cause['file'] = $trace[0]['file']; + $cause['line'] = $trace[0]['line']; + } + } + $causes[] = $cause; + if ($this->cause instanceof PEAR_Exception) { + $this->cause->getCauseMessage($causes); + } elseif ($this->cause instanceof Exception) { + $causes[] = array('class' => get_class($this->cause), + 'message' => $this->cause->getMessage(), + 'file' => $this->cause->getFile(), + 'line' => $this->cause->getLine()); + } elseif (class_exists('PEAR_Error') && $this->cause instanceof PEAR_Error) { + $causes[] = array('class' => get_class($this->cause), + 'message' => $this->cause->getMessage(), + 'file' => 'unknown', + 'line' => 'unknown'); + } elseif (is_array($this->cause)) { + foreach ($this->cause as $cause) { + if ($cause instanceof PEAR_Exception) { + $cause->getCauseMessage($causes); + } elseif ($cause instanceof Exception) { + $causes[] = array('class' => get_class($cause), + 'message' => $cause->getMessage(), + 'file' => $cause->getFile(), + 'line' => $cause->getLine()); + } elseif (class_exists('PEAR_Error') && $cause instanceof PEAR_Error) { + $causes[] = array('class' => get_class($cause), + 'message' => $cause->getMessage(), + 'file' => 'unknown', + 'line' => 'unknown'); + } elseif (is_array($cause) && isset($cause['message'])) { + // PEAR_ErrorStack warning + $causes[] = array( + 'class' => $cause['package'], + 'message' => $cause['message'], + 'file' => isset($cause['context']['file']) ? + $cause['context']['file'] : + 'unknown', + 'line' => isset($cause['context']['line']) ? + $cause['context']['line'] : + 'unknown', + ); + } + } + } + } + + public function getTraceSafe() + { + if (!isset($this->_trace)) { + $this->_trace = $this->getTrace(); + if (empty($this->_trace)) { + $backtrace = debug_backtrace(); + $this->_trace = array($backtrace[count($backtrace)-1]); + } + } + return $this->_trace; + } + + public function getErrorClass() + { + $trace = $this->getTraceSafe(); + return $trace[0]['class']; + } + + public function getErrorMethod() + { + $trace = $this->getTraceSafe(); + return $trace[0]['function']; + } + + public function __toString() + { + if (isset($_SERVER['REQUEST_URI'])) { + return $this->toHtml(); + } + return $this->toText(); + } + + public function toHtml() + { + $trace = $this->getTraceSafe(); + $causes = array(); + $this->getCauseMessage($causes); + $html = '' . "\n"; + foreach ($causes as $i => $cause) { + $html .= '\n"; + } + $html .= '' . "\n" + . '' + . '' + . '' . "\n"; + + foreach ($trace as $k => $v) { + $html .= '' + . '' + . '' . "\n"; + } + $html .= '' + . '' + . '' . "\n" + . '
' + . str_repeat('-', $i) . ' ' . $cause['class'] . ': ' + . htmlspecialchars($cause['message']) . ' in ' . $cause['file'] . ' ' + . 'on line ' . $cause['line'] . '' + . "
Exception trace
#FunctionLocation
' . $k . ''; + if (!empty($v['class'])) { + $html .= $v['class'] . $v['type']; + } + $html .= $v['function']; + $args = array(); + if (!empty($v['args'])) { + foreach ($v['args'] as $arg) { + if (is_null($arg)) $args[] = 'null'; + elseif (is_array($arg)) $args[] = 'Array'; + elseif (is_object($arg)) $args[] = 'Object('.get_class($arg).')'; + elseif (is_bool($arg)) $args[] = $arg ? 'true' : 'false'; + elseif (is_int($arg) || is_double($arg)) $args[] = $arg; + else { + $arg = (string)$arg; + $str = htmlspecialchars(substr($arg, 0, 16)); + if (strlen($arg) > 16) $str .= '…'; + $args[] = "'" . $str . "'"; + } + } + } + $html .= '(' . implode(', ',$args) . ')' + . '' . (isset($v['file']) ? $v['file'] : 'unknown') + . ':' . (isset($v['line']) ? $v['line'] : 'unknown') + . '
' . ($k+1) . '{main} 
'; + return $html; + } + + public function toText() + { + $causes = array(); + $this->getCauseMessage($causes); + $causeMsg = ''; + foreach ($causes as $i => $cause) { + $causeMsg .= str_repeat(' ', $i) . $cause['class'] . ': ' + . $cause['message'] . ' in ' . $cause['file'] + . ' on line ' . $cause['line'] . "\n"; + } + return $causeMsg . $this->getTraceAsString(); + } +} + +?> \ No newline at end of file From e185c0395a6cd250ccd7c8e385c54830be73f937 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 12 Mar 2009 00:13:28 -0400 Subject: [PATCH 58/58] Revert "trac #201 Add flowplayer to enable multimedia playback capability." This reverts commit 9c9b6790ce78296c0b182f03b5f6f2c035e43a7c. This code wasn't ready for release, so I've reverted it for now. Conflicts: lib/action.php lib/util.php --- bin/flowplayer-3.0.5.swf | Bin 92317 -> 0 bytes bin/flowplayer.audio-3.0.3.swf | Bin 2756 -> 0 bytes bin/flowplayer.controls-3.0.3.swf | Bin 15977 -> 0 bytes js/flowplayer-3.0.5.min.js | 24 ------------------------ js/jquery.simplemodal-1.2.2.pack.js | 8 -------- js/video.js | 9 --------- lib/action.php | 18 ------------------ lib/util.php | 6 ------ theme/base/css/modal.css | 22 ---------------------- theme/base/css/modal_ie.css | 16 ---------------- theme/base/images/x.png | Bin 1066 -> 0 bytes 11 files changed, 103 deletions(-) delete mode 100644 bin/flowplayer-3.0.5.swf delete mode 100644 bin/flowplayer.audio-3.0.3.swf delete mode 100644 bin/flowplayer.controls-3.0.3.swf delete mode 100644 js/flowplayer-3.0.5.min.js delete mode 100644 js/jquery.simplemodal-1.2.2.pack.js delete mode 100644 js/video.js delete mode 100644 theme/base/css/modal.css delete mode 100644 theme/base/css/modal_ie.css delete mode 100644 theme/base/images/x.png diff --git a/bin/flowplayer-3.0.5.swf b/bin/flowplayer-3.0.5.swf deleted file mode 100644 index 05b64a032b96e85ad7fc694495455710e2a1f1b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 92317 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 Ay8r+H diff --git a/bin/flowplayer.audio-3.0.3.swf b/bin/flowplayer.audio-3.0.3.swf deleted file mode 100644 index ef85f1bff0d4f179bc47f9a6404dc8ba75716895..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2756 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 X|LvcrW5=aS{Pk7(YlQzFyXx;XOtq1% diff --git a/js/flowplayer-3.0.5.min.js b/js/flowplayer-3.0.5.min.js deleted file mode 100644 index b1c33150ac..0000000000 --- a/js/flowplayer-3.0.5.min.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * flowplayer.js 3.0.5. The Flowplayer API - * - * Copyright 2009 Flowplayer Oy - * - * This file is part of Flowplayer. - * - * Flowplayer is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Flowplayer 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Flowplayer. If not, see . - * - * Version: 3.0.5 - Tue Feb 03 2009 13:14:17 GMT-0000 (GMT+00:00) - */ -(function(){function log(args){console.log("$f.fireEvent",[].slice.call(args));}function clone(obj){if(!obj||typeof obj!='object'){return obj;}var temp=new obj.constructor();for(var key in obj){if(obj.hasOwnProperty(key)){temp[key]=clone(obj[key]);}}return temp;}function each(obj,fn){if(!obj){return;}var name,i=0,length=obj.length;if(length===undefined){for(name in obj){if(fn.call(obj[name],name,obj[name])===false){break;}}}else{for(var value=obj[0];i1){var swf=arguments[1];var conf=(arguments.length==3)?arguments[2]:{};if(typeof arg=='string'){if(arg.indexOf(".")!=-1){var instances=[];each(select(arg),function(){instances.push(new Player(this,clone(swf),clone(conf)));});return new Iterator(instances);}else{var node=el(arg);return new Player(node!==null?node:arg,swf,conf);}}else if(arg){return new Player(arg,swf,conf);}}return null;};extend(window.$f,{fireEvent:function(id,evt,a0,a1,a2){var p=$f(id);return p?p._fireEvent(evt,a0,a1,a2):null;},addPlugin:function(name,fn){Player.prototype[name]=fn;return $f;},each:each,extend:extend});if(document.all){window.onbeforeunload=function(){$f("*").each(function(){if(this.isLoaded()){this.close();}});};}if(typeof jQuery=='function'){jQuery.prototype.flowplayer=function(params,conf){if(!arguments.length||typeof arguments[0]=='number'){var arr=[];this.each(function(){var p=$f(this);if(p){arr.push(p);}});return arguments.length?arr[arguments[0]]:new Iterator(arr);}return this.each(function(){$f(this,clone(params),conf?clone(conf):{});});};}})();(function(){var jQ=typeof jQuery=='function';function isDomReady(){if(domReady.done){return false;}var d=document;if(d&&d.getElementsByTagName&&d.getElementById&&d.body){clearInterval(domReady.timer);domReady.timer=null;for(var i=0;i';}var e=extend({},p);e.width=e.height=e.id=e.w3c=e.src=null;for(var k in e){if(e[k]!==null){html+='';}}var vars="";if(c){for(var key in c){if(c[key]!==null){vars+=key+'='+(typeof c[key]=='object'?asString(c[key]):c[key])+'&';}}vars=vars.substring(0,vars.length-1);html+='';}html+="";return html;}function Flash(root,opts,flashvars){var version=flashembed.getVersion();extend(this,{getContainer:function(){return root;},getConf:function(){return conf;},getVersion:function(){return version;},getFlashvars:function(){return flashvars;},getApi:function(){return root.firstChild;},getHTML:function(){return getHTML(opts,flashvars);}});var required=opts.version;var express=opts.expressInstall;var ok=!required||flashembed.isSupported(required);if(ok){opts.onFail=opts.version=opts.expressInstall=null;root.innerHTML=getHTML(opts,flashvars);}else if(required&&express&&flashembed.isSupported([6,65])){extend(opts,{src:express});flashvars={MMredirectURL:location.href,MMplayerType:'PlugIn',MMdoctitle:document.title};root.innerHTML=getHTML(opts,flashvars);}else{if(root.innerHTML.replace(/\s/g,'')!==''){}else{root.innerHTML="

Flash version "+required+" or greater is required

"+"

"+(version[0]>0?"Your version is "+version:"You have no flash plugin installed")+"

"+"
";}}if(!ok&&opts.onFail){var ret=opts.onFail.call(this);if(typeof ret=='string'){root.innerHTML=ret;}}}window.flashembed=function(root,conf,flashvars){if(typeof root=='string'){var el=document.getElementById(root);if(el){root=el;}else{domReady(function(){flashembed(root,conf,flashvars);});return;}}if(!root){return;}var opts={width:'100%',height:'100%',allowfullscreen:true,allowscriptaccess:'always',quality:'high',version:null,onFail:null,expressInstall:null,w3c:false};if(typeof conf=='string'){conf={src:conf};}extend(opts,conf);return new Flash(root,opts,flashvars);};extend(window.flashembed,{getVersion:function(){var version=[0,0];if(navigator.plugins&&typeof navigator.plugins["Shockwave Flash"]=="object"){var _d=navigator.plugins["Shockwave Flash"].description;if(typeof _d!="undefined"){_d=_d.replace(/^.*\s+(\S+\s+\S+$)/,"$1");var _m=parseInt(_d.replace(/^(.*)\..*$/,"$1"),10);var _r=/r/.test(_d)?parseInt(_d.replace(/^.*r(.*)$/,"$1"),10):0;version=[_m,_r];}}else if(window.ActiveXObject){try{var _a=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");}catch(e){try{_a=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");version=[6,0];_a.AllowScriptAccess="always";}catch(ee){if(version[0]==6){return;}}try{_a=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");}catch(eee){}}if(typeof _a=="object"){_d=_a.GetVariable("$version");if(typeof _d!="undefined"){_d=_d.replace(/^\S+\s+(.*)$/,"$1").split(",");version=[parseInt(_d[0],10),parseInt(_d[2],10)];}}}return version;},isSupported:function(version){var now=flashembed.getVersion();var ret=(now[0]>version[0])||(now[0]==version[0]&&now[1]>=version[1]);return ret;},domReady:domReady,asString:asString,getHTML:getHTML});if(jQ){jQuery.prototype.flashembed=function(conf,flashvars){return this.each(function(){flashembed(this,conf,flashvars);});};}})(); \ No newline at end of file diff --git a/js/jquery.simplemodal-1.2.2.pack.js b/js/jquery.simplemodal-1.2.2.pack.js deleted file mode 100644 index b5ad5c23a3..0000000000 --- a/js/jquery.simplemodal-1.2.2.pack.js +++ /dev/null @@ -1,8 +0,0 @@ -/* - * SimpleModal 1.2.2 - jQuery Plugin - * http://www.ericmmartin.com/projects/simplemodal/ - * Copyright (c) 2008 Eric Martin - * Dual licensed under the MIT and GPL licenses - * Revision: $Id: jquery.simplemodal.js 181 2008-12-16 16:51:44Z emartin24 $ - */ -eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(g($){m f=$.Q.1Q&&1a($.Q.1D)==6&&!10[\'2g\'],1f=$.Q.1Q&&!$.2a,w=[];$.y=g(a,b){I $.y.12.1n(a,b)};$.y.D=g(){$.y.12.D()};$.1P.y=g(a){I $.y.12.1n(3,a)};$.y.1O={V:29,1J:\'r-H\',1B:{},1z:\'r-n\',20:{},1Z:{},v:2t,D:1o,1T:\'\',X:\'r-D\',l:F,1g:K,1e:F,1d:F,1c:F};$.y.12={7:F,4:{},1n:g(a,b){8(3.4.j){I K}3.7=$.U({},$.y.1O,b);3.v=3.7.v;3.1w=K;8(J a==\'27\'){a=a 25 1A?a:$(a);8(a.1v().1v().23()>0){3.4.T=a.1v();8(!3.7.1g){3.4.21=a.2x(1o)}}}q 8(J a==\'2w\'||J a==\'1r\'){a=$(\'<1q/>\').2s(a)}q{2r(\'2q 2p: 2o j 2l: \'+J a);I K}3.4.j=a.11(\'r-j\').E(3.7.1Z);a=F;3.1S();3.1R();8($.1m(3.7.1d)){3.7.1d.1l(3,[3.4])}I 3},1S:g(){w=3.1k();8(f){3.4.x=$(\'\').E($.U(3.7.2b,{1j:\'1i\',V:0,l:\'1h\',A:w[0],z:w[1],v:3.7.v,L:0,B:0})).O(\'u\')}3.4.H=$(\'<1q/>\').1N(\'1M\',3.7.1J).11(\'r-H\').E($.U(3.7.1B,{1j:\'1i\',V:3.7.V/1b,A:w[0],z:w[1],l:\'1h\',B:0,L:0,v:3.7.v+1})).O(\'u\');3.4.n=$(\'<1q/>\').1N(\'1M\',3.7.1z).11(\'r-n\').E($.U(3.7.20,{1j:\'1i\',l:\'1h\',v:3.7.v+2})).1K(3.7.D?$(3.7.1T).11(3.7.X):\'\').O(\'u\');3.19();8(f||1f){3.18()}3.4.n.1K(3.4.j.1I())},1H:g(){m a=3;$(\'.\'+3.7.X).1G(\'1L.r\',g(e){e.28();a.D()});$(10).1G(\'1F.r\',g(){w=a.1k();a.19();8(f||1f){a.18()}q{a.4.x&&a.4.x.E({A:w[0],z:w[1]});a.4.H.E({A:w[0],z:w[1]})}})},1E:g(){$(\'.\'+3.7.X).1C(\'1L.r\');$(10).1C(\'1F.r\')},18:g(){m p=3.7.l;$.26([3.4.x||F,3.4.H,3.4.n],g(i,e){8(e){m a=\'k.u.17\',N=\'k.u.1W\',16=\'k.u.24\',S=\'k.u.1y\',R=\'k.u.1x\',15=\'k.u.22\',1t=\'k.P.17\',1s=\'k.P.1W\',C=\'k.P.1y\',G=\'k.P.1x\',s=e[0].2v;s.l=\'2u\';8(i<2){s.14(\'A\');s.14(\'z\');s.Z(\'A\',\'\'+16+\' > \'+a+\' ? \'+16+\' : \'+a+\' + "o"\');s.Z(\'z\',\'\'+15+\' > \'+N+\' ? \'+15+\' : \'+N+\' + "o"\')}q{m b,W;8(p&&p.1Y==1X){8(p[0]){m c=J p[0]==\'1r\'?p[0].1V():p[0].13(/o/,\'\');b=c.1U(\'%\')==-1?c+\' + (t = \'+G+\' ? \'+G+\' : \'+R+\') + "o"\':1a(c.13(/%/,\'\'))+\' * ((\'+1t+\' || \'+a+\') / 1b) + (t = \'+G+\' ? \'+G+\' : \'+R+\') + "o"\'}8(p[1]){m d=J p[1]==\'1r\'?p[1].1V():p[1].13(/o/,\'\');W=d.1U(\'%\')==-1?d+\' + (t = \'+C+\' ? \'+C+\' : \'+S+\') + "o"\':1a(d.13(/%/,\'\'))+\' * ((\'+1s+\' || \'+N+\') / 1b) + (t = \'+C+\' ? \'+C+\' : \'+S+\') + "o"\'}}q{b=\'(\'+1t+\' || \'+a+\') / 2 - (3.2n / 2) + (t = \'+G+\' ? \'+G+\' : \'+R+\') + "o"\';W=\'(\'+1s+\' || \'+N+\') / 2 - (3.2m / 2) + (t = \'+C+\' ? \'+C+\' : \'+S+\') + "o"\'}s.14(\'L\');s.14(\'B\');s.Z(\'L\',b);s.Z(\'B\',W)}}})},1k:g(){m a=$(10);m h=$.Q.2k&&$.Q.1D>\'9.5\'&&$.1P.2i<=\'1.2.6\'?k.P[\'17\']:a.A();I[h,a.z()]},19:g(){m a,B,1u=(w[0]/2)-((3.4.n.A()||3.4.j.A())/2),1p=(w[1]/2)-((3.4.n.z()||3.4.j.z())/2);8(3.7.l&&3.7.l.1Y==1X){a=3.7.l[0]||1u;B=3.7.l[1]||1p}q{a=1u;B=1p}3.4.n.E({B:B,L:a})},1R:g(){3.4.x&&3.4.x.Y();8($.1m(3.7.1e)){3.7.1e.1l(3,[3.4])}q{3.4.H.Y();3.4.n.Y();3.4.j.Y()}3.1H()},D:g(){8(!3.4.j){I K}8($.1m(3.7.1c)&&!3.1w){3.1w=1o;3.7.1c.1l(3,[3.4])}q{8(3.4.T){8(3.7.1g){3.4.j.1I().O(3.4.T)}q{3.4.j.M();3.4.21.O(3.4.T)}}q{3.4.j.M()}3.4.n.M();3.4.H.M();3.4.x&&3.4.x.M();3.4={}}3.1E()}}})(1A);',62,158,'|||this|dialog|||opts|if||||||||function|||data|document|position|var|container|px||else|simplemodal|||body|zIndex||iframe|modal|width|height|left|sl|close|css|null|st|overlay|return|typeof|false|top|remove|bcw|appendTo|documentElement|browser|bst|bsl|parentNode|extend|opacity|le|closeClass|show|setExpression|window|addClass|impl|replace|removeExpression|bsw|bsh|clientHeight|fixIE|setPosition|parseInt|100|onClose|onShow|onOpen|ieQuirks|persist|fixed|none|display|getDimensions|apply|isFunction|init|true|vCenter|div|number|cw|ch|hCenter|parent|occb|scrollTop|scrollLeft|containerId|jQuery|overlayCss|unbind|version|unbindEvents|resize|bind|bindEvents|hide|overlayId|append|click|id|attr|defaults|fn|msie|open|create|closeHTML|indexOf|toString|clientWidth|Array|constructor|dataCss|containerCss|orig|scrollWidth|size|scrollHeight|instanceof|each|object|preventDefault|50|boxModel|iframeCss|javascript|src|Close|title|XMLHttpRequest|modalCloseImg|jquery|class|opera|type|offsetWidth|offsetHeight|Unsupported|Error|SimpleModal|alert|html|1000|absolute|style|string|clone'.split('|'),0,{})) \ No newline at end of file diff --git a/js/video.js b/js/video.js deleted file mode 100644 index 936a6312e3..0000000000 --- a/js/video.js +++ /dev/null @@ -1,9 +0,0 @@ -$('document').ready(function() { - $('a.media, a.mediamp3').append(' [PLAY]'); - $('a.mediamp3').html('').css('display', 'block').css('width', '224px').css('height','24px').flowplayer('../bin/flowplayer-3.0.5.swf'); - $('a.media').click(function() { - $('').attr('href', $(this).attr('href')).flowplayer('../bin/flowplayer-3.0.5.swf').modal({'closeHTML':''}); - return false; - }); -}); - diff --git a/lib/action.php b/lib/action.php index 45ce56ac01..975c2bfcb8 100644 --- a/lib/action.php +++ b/lib/action.php @@ -156,15 +156,10 @@ class Action extends HTMLOutputter // lawsuit { if (Event::handle('StartShowStyles', array($this))) { if (Event::handle('StartShowLaconicaStyles', array($this))) { - $this->element('link', array('rel' => 'stylesheet', 'type' => 'text/css', 'href' => theme_path('css/display.css', 'base') . '?version=' . LACONICA_VERSION, 'media' => 'screen, projection, tv')); - $this->element('link', array('rel' => 'stylesheet', - 'type' => 'text/css', - 'href' => theme_path('css/modal.css', 'base') . '?version=' . LACONICA_VERSION, - 'media' => 'screen, projection, tv')); $this->element('link', array('rel' => 'stylesheet', 'type' => 'text/css', 'href' => theme_path('css/display.css', null) . '?version=' . LACONICA_VERSION, @@ -215,11 +210,6 @@ class Action extends HTMLOutputter // lawsuit $this->element('script', array('type' => 'text/javascript', 'src' => common_path('js/jquery.form.js')), ' '); - - $this->element('script', array('type' => 'text/javascript', - 'src' => common_path('js/jquery.simplemodal-1.2.2.pack.js')), - ' '); - Event::handle('EndShowJQueryScripts', array($this)); } if (Event::handle('StartShowLaconicaScripts', array($this))) { @@ -232,14 +222,6 @@ class Action extends HTMLOutputter // lawsuit // Frame-busting code to avoid clickjacking attacks. $this->element('script', array('type' => 'text/javascript'), 'if (window.top !== window.self) { window.top.location.href = window.self.location.href; }'); - - $this->element('script', array('type' => 'text/javascript', - 'src' => common_path('js/flowplayer-3.0.5.min.js')), - ' '); - - $this->element('script', array('type' => 'text/javascript', - 'src' => common_path('js/video.js')), - ' '); Event::handle('EndShowLaconicaScripts', array($this)); } Event::handle('EndShowScripts', array($this)); diff --git a/lib/util.php b/lib/util.php index 6341438cae..a43666fa5c 100644 --- a/lib/util.php +++ b/lib/util.php @@ -480,18 +480,12 @@ function common_replace_urls_callback($text, $callback) { function common_linkify($url) { // It comes in special'd, so we unspecial it before passing to the stringifying // functions - $ext = pathinfo($url, PATHINFO_EXTENSION); $url = htmlspecialchars_decode($url); - $video_ext = array('mp4', 'flv', 'avi', 'mpg', 'mp3', 'ogg'); $display = $url; $url = (!preg_match('#^([a-z]+://|(mailto|aim|tel):)#i', $url)) ? 'http://'.$url : $url; $attrs = array('href' => $url, 'rel' => 'external'); - if (in_array($ext, $video_ext)) { - $attrs['class'] = 'media'; - } - if ($longurl = common_longurl($url)) { $attrs['title'] = $longurl; } diff --git a/theme/base/css/modal.css b/theme/base/css/modal.css deleted file mode 100644 index 985e4adfa5..0000000000 --- a/theme/base/css/modal.css +++ /dev/null @@ -1,22 +0,0 @@ -/* - * SimpleModal Basic Modal Dialog - * http://www.ericmmartin.com/projects/simplemodal/ - * http://code.google.com/p/simplemodal/ - * - * Copyright (c) 2008 Eric Martin - http://ericmmartin.com - * - * Licensed under the MIT license: - * http://www.opensource.org/licenses/mit-license.php - * - * Revision: $Id: basic.css 162 2008-12-01 23:36:58Z emartin24 $ - * - */ - - -/* Overlay */ -#simplemodal-overlay {background-color:#000; cursor:wait;} - -/* Container */ -#simplemodal-container {height:240px; width:320px; background-color:#fff; border:3px solid #ccc;} -#simplemodal-container a.modalCloseImg {background:url(../images/x.png) no-repeat; width:25px; height:29px; display:inline; z-index:3200; position:absolute; top:-15px; right:-18px; cursor:pointer;} -#simplemodal-container #basicModalContent {padding:8px;} diff --git a/theme/base/css/modal_ie.css b/theme/base/css/modal_ie.css deleted file mode 100644 index eab4637c0f..0000000000 --- a/theme/base/css/modal_ie.css +++ /dev/null @@ -1,16 +0,0 @@ -/* - * SimpleModal Basic Modal Dialog - * http://www.ericmmartin.com/projects/simplemodal/ - * http://code.google.com/p/simplemodal/ - * - * Copyright (c) 2008 Eric Martin - http://ericmmartin.com - * - * Licensed under the MIT license: - * http://www.opensource.org/licenses/mit-license.php - * - * Revision: $Id: basic_ie.css 162 2008-12-01 23:36:58Z emartin24 $ - * - */ - -/* IE 6 hacks*/ -#simplemodal-container a.modalCloseImg {background:none; right:-14px; width:22px; height:26px; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../images/x.png',sizingMethod='scale');} diff --git a/theme/base/images/x.png b/theme/base/images/x.png deleted file mode 100644 index c11f7af69fad034c3564a4a455be0d9d569e9878..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1066 zcmV+_1l9YAP)P0012b1^@s6UwFrL0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU#%t=H+RCwB)mP<%fQ5eVP&iH858mu%+ z@(~);$`IRRsFdWQg)j?25H#9E5+YcjgqtV`TnUOGY74=Yv`}0503pyMZ4rozbYe7z z$w%s><2+9PZ}`sb+&d4g1HZX*&*S@_?|k1m_h>>0%PC7PDB-6UEP>TijU~?!h0g26K6CE8L!teL1 zLtn=e$y0l^wY4QQZl=Dz-t5usSR!v^>*VBQl#$xnTElxmL4jCYTr|`V4-cy%A7hEQ zWNUeOxxwJ->T0CEva(W-#m>%7q;7CW+W51oizD>jY>#XZ^Ja5$m{(#C6SY}DW3nc-b6NO}E# zC=@!P4IkO{$dclCF;Rmo6MzcUQCp&zxZUo1x(G;zH*VRe4xXN#HW+PbY0-_)e^mg- zjUl^AOG_OxB=mFEm0D@BE7x657g{w zXlO8G*GW6Ry1Lrn#rXI*Wro8b0bQaN3ahfBgrlv;h@9*mZTU%RSQD1Bp zNe6l04wlWOdPGMBj`WzuDF(Dess{%L2fOX+0&>Vr&h#0WN~nh<*Mt(z<2vC7~2J!3(F;`5pmu9~~Wq;u)Wsn(|;{en9_rPzUIU zzsgIMq1o}P*}Y6~nLFn5^HNn+RbE+H*@fifWE&2?5WbkdCMG6ah{q<{-QYX3 z0k(k;1nAU~A{qxMg_D4UvRN#L|7Y?f$m=lp4R-l@L_$A+2kd|Ya7-r)C5V2JU?Cd| zrE&UYa;!3WW7)Y64W@HxpN(!ad+Y%T1UU

Download latest version from here