diff options
author | Brion Vibber <brion@pobox.com> | 2010-10-06 17:16:13 -0700 |
---|---|---|
committer | Brion Vibber <brion@pobox.com> | 2010-10-06 17:16:13 -0700 |
commit | 99194e03fa50b61f99164674afc949b4bbefd44a (patch) | |
tree | 2d38f6ec4b1e6f314d925233c781315541772a0f /lib | |
parent | 033a7570133d4183c2e162859e9b85fe7df3e40b (diff) | |
parent | 71176b9a98ef5298162f821c621a0e467dd9570b (diff) |
Merge branch '1.0.x' into schema-x
Conflicts:
plugins/OStatus/classes/Ostatus_profile.php
Diffstat (limited to 'lib')
66 files changed, 1167 insertions, 602 deletions
diff --git a/lib/accountsettingsaction.php b/lib/accountsettingsaction.php index 57740f8b8..7991c9002 100644 --- a/lib/accountsettingsaction.php +++ b/lib/accountsettingsaction.php @@ -44,7 +44,6 @@ require_once INSTALLDIR.'/lib/settingsaction.php'; * * @see Widget */ - class AccountSettingsAction extends SettingsAction { /** @@ -54,7 +53,6 @@ class AccountSettingsAction extends SettingsAction * * @return void */ - function showLocalNav() { $menu = new AccountSettingsNav($this); @@ -73,7 +71,6 @@ class AccountSettingsAction extends SettingsAction * * @see HTMLOutputter */ - class AccountSettingsNav extends Widget { var $action = null; @@ -83,7 +80,6 @@ class AccountSettingsNav extends Widget * * @param Action $action current action, used for output */ - function __construct($action=null) { parent::__construct($action); @@ -95,7 +91,6 @@ class AccountSettingsNav extends Widget * * @return void */ - function show() { $action_name = $this->action->trimmed('action'); diff --git a/lib/action.php b/lib/action.php index 2b3b707c5..ddc058d41 100644 --- a/lib/action.php +++ b/lib/action.php @@ -121,7 +121,10 @@ class Action extends HTMLOutputter // lawsuit // XXX: attributes (profile?) $this->elementStart('head'); if (Event::handle('StartShowHeadElements', array($this))) { - $this->showTitle(); + if (Event::handle('StartShowHeadTitle', array($this))) { + $this->showTitle(); + Event::handle('EndShowHeadTitle', array($this)); + } $this->showShortcutIcon(); $this->showStylesheets(); $this->showOpenSearch(); @@ -200,7 +203,7 @@ class Action extends HTMLOutputter // lawsuit if (Event::handle('StartShowStatusNetStyles', array($this)) && Event::handle('StartShowLaconicaStyles', array($this))) { - $this->cssLink('css/display.css',null, 'screen, projection, tv, print'); + $this->primaryCssLink(null, 'screen, projection, tv, print'); Event::handle('EndShowStatusNetStyles', array($this)); Event::handle('EndShowLaconicaStyles', array($this)); } @@ -235,7 +238,7 @@ class Action extends HTMLOutputter // lawsuit Event::handle('EndShowDesign', array($this)); } Event::handle('EndShowStyles', array($this)); - + if (common_config('custom_css', 'enabled')) { $css = common_config('custom_css', 'css'); if (Event::handle('StartShowCustomCss', array($this, &$css))) { @@ -248,6 +251,18 @@ class Action extends HTMLOutputter // lawsuit } } + function primaryCssLink($mainTheme=null, $media=null) + { + // If the currently-selected theme has dependencies on other themes, + // we'll need to load their display.css files as well in order. + $theme = new Theme($mainTheme); + $baseThemes = $theme->getDeps(); + foreach ($baseThemes as $baseTheme) { + $this->cssLink('css/display.css', $baseTheme, $media); + } + $this->cssLink('css/display.css', $mainTheme, $media); + } + /** * Show javascript headers * @@ -266,9 +281,7 @@ class Action extends HTMLOutputter // lawsuit } if (Event::handle('StartShowStatusNetScripts', array($this)) && Event::handle('StartShowLaconicaScripts', array($this))) { - $this->script('xbImportNode.js'); $this->script('util.js'); - $this->script('geometa.js'); // Frame-busting code to avoid clickjacking attacks. $this->inlineScript('if (window.top !== window.self) { window.top.location.href = window.self.location.href; }'); Event::handle('EndShowStatusNetScripts', array($this)); @@ -301,7 +314,6 @@ class Action extends HTMLOutputter // lawsuit * * @return nothing */ - function showFeeds() { $feeds = $this->getFeeds(); @@ -616,7 +628,10 @@ class Action extends HTMLOutputter // lawsuit function showContentBlock() { $this->elementStart('div', array('id' => 'content')); - $this->showPageTitle(); + if (Event::handle('StartShowPageTitle', array($this))) { + $this->showPageTitle(); + Event::handle('EndShowPageTitle', array($this)); + } $this->showPageNoticeBlock(); $this->elementStart('div', array('id' => 'content_inner')); // show the actual content (forms, lists, whatever) @@ -694,19 +709,18 @@ class Action extends HTMLOutputter // lawsuit * * @return nothing */ - function showAside() { $this->elementStart('div', array('id' => 'aside_primary', 'class' => 'aside')); - if (Event::handle('StartShowExportData', array($this))) { - $this->showExportData(); - Event::handle('EndShowExportData', array($this)); - } if (Event::handle('StartShowSections', array($this))) { $this->showSections(); Event::handle('EndShowSections', array($this)); } + if (Event::handle('StartShowExportData', array($this))) { + $this->showExportData(); + Event::handle('EndShowExportData', array($this)); + } $this->elementEnd('div'); } @@ -715,7 +729,6 @@ class Action extends HTMLOutputter // lawsuit * * @return void */ - function showExportData() { $feeds = $this->getFeeds(); @@ -791,6 +804,7 @@ class Action extends HTMLOutputter // lawsuit // TRANS: Secondary navigation menu option leading to contact information on the StatusNet site. _('Contact')); $this->menuItem(common_local_url('doc', array('title' => 'badge')), + // TRANS: Secondary navigation menu option. _('Badge')); Event::handle('EndSecondaryNav', array($this)); } @@ -824,6 +838,9 @@ class Action extends HTMLOutputter // lawsuit $this->elementStart('dd', null); if (common_config('site', 'broughtby')) { // TRANS: First sentence of the StatusNet site license. Used if 'broughtby' is set. + // TRANS: Text between [] is a link description, text between () is the link itself. + // TRANS: Make sure there is no whitespace between "]" and "(". + // TRANS: "%%site.broughtby%%" is the value of the variable site.broughtby $instr = _('**%%site.name%%** is a microblogging service brought to you by [%%site.broughtby%%](%%site.broughtbyurl%%).'); } else { // TRANS: First sentence of the StatusNet site license. Used if 'broughtby' is not set. @@ -831,6 +848,9 @@ class Action extends HTMLOutputter // lawsuit } $instr .= ' '; // TRANS: Second sentence of the StatusNet site license. Mentions the StatusNet source code license. + // TRANS: Make sure there is no whitespace between "]" and "(". + // TRANS: Text between [] is a link description, text between () is the link itself. + // TRANS: %s is the version of StatusNet that is being used. $instr .= sprintf(_('It runs the [StatusNet](http://status.net/) microblogging software, version %s, available under the [GNU Affero General Public License](http://www.fsf.org/licensing/licenses/agpl-3.0.html).'), STATUSNET_VERSION); $output = common_markup_to_html($instr); $this->raw($output); @@ -877,7 +897,8 @@ class Action extends HTMLOutputter // lawsuit 'width' => '80', 'height' => '15')); $this->text(' '); - // TRANS: license message in footer. %1$s is the site name, %2$s is a link to the license URL, with a licence name set in configuration. + // TRANS: license message in footer. + // TRANS: %1$s is the site name, %2$s is a link to the license URL, with a licence name set in configuration. $notice = _('All %1$s content and data are available under the %2$s license.'); $link = "<a class=\"license\" rel=\"external license\" href=\"" . htmlspecialchars(common_config('license', 'url')) . @@ -931,7 +952,6 @@ class Action extends HTMLOutputter // lawsuit * * @return boolean is read only action? */ - function isReadOnly($args) { return false; @@ -978,29 +998,61 @@ class Action extends HTMLOutputter // lawsuit function handle($argarray=null) { header('Vary: Accept-Encoding,Cookie'); + $lm = $this->lastModified(); $etag = $this->etag(); + if ($etag) { header('ETag: ' . $etag); } + if ($lm) { header('Last-Modified: ' . date(DATE_RFC1123, $lm)); - if (array_key_exists('HTTP_IF_MODIFIED_SINCE', $_SERVER)) { - $if_modified_since = $_SERVER['HTTP_IF_MODIFIED_SINCE']; - $ims = strtotime($if_modified_since); - if ($lm <= $ims) { - $if_none_match = (array_key_exists('HTTP_IF_NONE_MATCH', $_SERVER)) ? - $_SERVER['HTTP_IF_NONE_MATCH'] : null; - if (!$if_none_match || - !$etag || - $this->_hasEtag($etag, $if_none_match)) { - header('HTTP/1.1 304 Not Modified'); - // Better way to do this? - exit(0); - } + if ($this->isCacheable()) { + header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' ); + header( "Cache-Control: private, must-revalidate, max-age=0" ); + header( "Pragma:"); + } + } + + $checked = false; + if ($etag) { + $if_none_match = (array_key_exists('HTTP_IF_NONE_MATCH', $_SERVER)) ? + $_SERVER['HTTP_IF_NONE_MATCH'] : null; + if ($if_none_match) { + // If this check fails, ignore the if-modified-since below. + $checked = true; + if ($this->_hasEtag($etag, $if_none_match)) { + header('HTTP/1.1 304 Not Modified'); + // Better way to do this? + exit(0); } } } + + if (!$checked && $lm && array_key_exists('HTTP_IF_MODIFIED_SINCE', $_SERVER)) { + $if_modified_since = $_SERVER['HTTP_IF_MODIFIED_SINCE']; + $ims = strtotime($if_modified_since); + if ($lm <= $ims) { + header('HTTP/1.1 304 Not Modified'); + // Better way to do this? + exit(0); + } + } + } + + /** + * Is this action cacheable? + * + * If the action returns a last-modified + * + * @param array $argarray is ignored since it's now passed in in prepare() + * + * @return boolean is read only action? + */ + function isCacheable() + { + return true; } /** @@ -1011,7 +1063,6 @@ class Action extends HTMLOutputter // lawsuit * * @return boolean */ - function _hasEtag($etag, $if_none_match) { $etags = explode(',', $if_none_match); @@ -1051,7 +1102,6 @@ class Action extends HTMLOutputter // lawsuit * * @return integer integer value */ - function int($key, $defValue=null, $maxValue=null, $minValue=null) { $arg = strtolower($this->trimmed($key)); @@ -1079,7 +1129,6 @@ class Action extends HTMLOutputter // lawsuit * * @return nothing */ - function serverError($msg, $code=500) { $action = $this->trimmed('action'); @@ -1095,7 +1144,6 @@ class Action extends HTMLOutputter // lawsuit * * @return nothing */ - function clientError($msg, $code=400) { $action = $this->trimmed('action'); @@ -1108,7 +1156,6 @@ class Action extends HTMLOutputter // lawsuit * * @return string current URL */ - function selfUrl() { list($action, $args) = $this->returnToArgs(); @@ -1120,7 +1167,6 @@ class Action extends HTMLOutputter // lawsuit * * @return array two elements: action, other args */ - function returnToArgs() { $action = $this->trimmed('action'); @@ -1227,7 +1273,6 @@ class Action extends HTMLOutputter // lawsuit * * @return array Feed object to show in head and links */ - function getFeeds() { return null; @@ -1238,7 +1283,6 @@ class Action extends HTMLOutputter // lawsuit * * @return Design a design object to use */ - function getDesign() { return Design::siteDesign(); @@ -1252,7 +1296,6 @@ class Action extends HTMLOutputter // lawsuit * * @return void */ - // XXX: Finding this type of check with the same message about 50 times. // Possible to refactor? function checkSessionToken() @@ -1260,6 +1303,7 @@ class Action extends HTMLOutputter // lawsuit // CSRF protection $token = $this->trimmed('token'); if (empty($token) || $token != common_session_token()) { + // TRANS: Client error text when there is a problem with the session token. $this->clientError(_('There was a problem with your session token.')); } } diff --git a/lib/activity.php b/lib/activity.php index 8e2da99bb..e974ca991 100644 --- a/lib/activity.php +++ b/lib/activity.php @@ -48,7 +48,6 @@ if (!defined('STATUSNET')) { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 * @link http://status.net/ */ - class Activity { const SPEC = 'http://activitystrea.ms/spec/1.0/'; @@ -108,7 +107,6 @@ class Activity * @param DOMElement $entry Atom entry to poke at * @param DOMElement $feed Atom feed, for context */ - function __construct($entry = null, $feed = null) { if (is_null($entry)) { @@ -133,6 +131,7 @@ class Activity $entry->localName == 'item') { $this->_fromRssItem($entry, $feed); } else { + // Low level exception. No need for i18n. throw new Exception("Unknown DOM element: {$entry->namespaceURI} {$entry->localName}"); } } @@ -313,13 +312,12 @@ class Activity * * @return DOMElement Atom entry */ - function toAtomEntry() { return null; } - function asString($namespace=false) + function asString($namespace=false, $author=true) { $xs = new XMLStringer(true); @@ -338,7 +336,7 @@ class Activity $xs->element('id', null, $this->id); $xs->element('title', null, $this->title); - $xs->element('published', null, common_date_iso8601($this->time)); + $xs->element('published', null, self::iso8601Date($this->time)); $xs->element('content', array('type' => 'html'), $this->content); if (!empty($this->summary)) { @@ -353,13 +351,15 @@ class Activity // XXX: add context - $xs->elementStart('author'); - $xs->element('uri', array(), $this->actor->id); - if ($this->actor->title) { - $xs->element('name', array(), $this->actor->title); + if ($author) { + $xs->elementStart('author'); + $xs->element('uri', array(), $this->actor->id); + if ($this->actor->title) { + $xs->element('name', array(), $this->actor->title); + } + $xs->elementEnd('author'); + $xs->raw($this->actor->asString('activity:actor')); } - $xs->elementEnd('author'); - $xs->raw($this->actor->asString('activity:actor')); $xs->element('activity:verb', null, $this->verb); @@ -386,5 +386,12 @@ class Activity { return ActivityUtils::child($element, $tag, $namespace); } -} + static function iso8601Date($tm) + { + $dateStr = date('d F Y H:i:s', $tm); + $d = new DateTime($dateStr, new DateTimeZone('UTC')); + $d->setTimezone(new DateTimeZone(common_timezone())); + return $d->format('c'); + } +} diff --git a/lib/activitycontext.php b/lib/activitycontext.php index 09a457924..ff3bc9411 100644 --- a/lib/activitycontext.php +++ b/lib/activitycontext.php @@ -54,8 +54,12 @@ class ActivityContext const MENTIONED = 'mentioned'; const CONVERSATION = 'ostatus:conversation'; - function __construct($element) + function __construct($element = null) { + if (empty($element)) { + return; + } + $replyToEl = ActivityUtils::child($element, self::INREPLYTO, self::THR); if (!empty($replyToEl)) { @@ -73,7 +77,6 @@ class ActivityContext $attention = array(); for ($i = 0; $i < $links->length; $i++) { - $link = $links->item($i); $linkRel = $link->getAttribute(ActivityUtils::REL); diff --git a/lib/activityobject.php b/lib/activityobject.php index 677a48197..e89c8db4e 100644 --- a/lib/activityobject.php +++ b/lib/activityobject.php @@ -49,7 +49,6 @@ if (!defined('STATUSNET')) { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 * @link http://status.net/ */ - class ActivityObject { const ARTICLE = 'http://activitystrea.ms/schema/1.0/article'; @@ -116,7 +115,6 @@ class ActivityObject * * @param DOMElement $element DOM thing to turn into an Activity thing */ - function __construct($element = null) { if (empty($element)) { @@ -168,7 +166,6 @@ class ActivityObject ActivityObject::MEDIA_DESCRIPTION, Activity::MEDIA ); - } } @@ -204,7 +201,7 @@ class ActivityObject $title = ActivityUtils::childHtmlContent($element, self::TITLE); - $this->title = html_entity_decode(strip_tags($title)); + $this->title = html_entity_decode(strip_tags($title), ENT_QUOTES, 'UTF-8'); $this->source = $this->_getSource($element); @@ -217,8 +214,7 @@ class ActivityObject } } - // @fixme rationalize with Activity::_fromRssItem() - + // @todo FIXME: rationalize with Activity::_fromRssItem() private function _fromRssItem($item) { $this->title = ActivityUtils::childContent($item, ActivityObject::TITLE, Activity::RSS); @@ -418,7 +414,6 @@ class ActivityObject ); foreach ($sizes as $size) { - $alink = null; $avatar = $profile->getAvatar($size); @@ -430,6 +425,17 @@ class ActivityObject $alink->height = $size; $alink->width = $size; $alink->url = Avatar::defaultImage($size); + + if ($size == AVATAR_PROFILE_SIZE) { + // Hack for Twitter import: we don't have a 96x96 image, + // but we do have a 73x73 image. For now, fake it with that. + $avatar = $profile->getAvatar(73); + if ($avatar) { + $alink = AvatarLink::fromAvatar($avatar); + $alink->height= $size; + $alink->width = $size; + } + } } $object->avatarLinks[] = $alink; diff --git a/lib/activityutils.php b/lib/activityutils.php index dd38d4e14..c462514c4 100644 --- a/lib/activityutils.php +++ b/lib/activityutils.php @@ -46,7 +46,6 @@ if (!defined('STATUSNET')) { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 * @link http://status.net/ */ - class ActivityUtils { const ATOM = 'http://www.w3.org/2005/Atom'; @@ -66,7 +65,6 @@ class ActivityUtils * * @return string related link, if any */ - static function getPermalink($element) { return self::getLink($element, 'alternate', 'text/html'); @@ -79,19 +77,16 @@ class ActivityUtils * * @return string related link, if any */ - static function getLink(DOMNode $element, $rel, $type=null) { $els = $element->childNodes; foreach ($els as $link) { - if (!($link instanceof DOMElement)) { continue; } if ($link->localName == self::LINK && $link->namespaceURI == self::ATOM) { - $linkRel = $link->getAttribute(self::REL); $linkType = $link->getAttribute(self::TYPE); @@ -112,7 +107,6 @@ class ActivityUtils foreach ($els as $link) { if ($link->localName == self::LINK && $link->namespaceURI == self::ATOM) { - $linkRel = $link->getAttribute(self::REL); $linkType = $link->getAttribute(self::TYPE); @@ -135,7 +129,6 @@ class ActivityUtils * * @return DOMElement found element or null */ - static function child(DOMNode $element, $tag, $namespace=self::ATOM) { $els = $element->childNodes; @@ -160,7 +153,6 @@ class ActivityUtils * * @return string content of the child */ - static function childContent(DOMNode $element, $tag, $namespace=self::ATOM) { $el = self::child($element, $tag, $namespace); @@ -194,7 +186,6 @@ class ActivityUtils * @todo handle embedded XML mime types * @todo handle base64-encoded non-XML and non-text mime types */ - static function getContent($element) { return self::childHtmlContent($element, self::CONTENT, self::ATOM); @@ -205,6 +196,7 @@ class ActivityUtils $src = $el->getAttribute(self::SRC); if (!empty($src)) { + // TRANS: Client exception thrown when there is no source attribute. throw new ClientException(_("Can't handle remote content yet.")); } @@ -241,10 +233,12 @@ class ActivityUtils return trim($text); } else if (in_array($type, array('text/xml', 'application/xml')) || preg_match('#(+|/)xml$#', $type)) { + // TRANS: Client exception thrown when there embedded XML content is found that cannot be processed yet. throw new ClientException(_("Can't handle embedded XML content yet.")); } else if (strncasecmp($type, 'text/', 5)) { return $el->textContent; } else { + // TRANS: Client exception thrown when base64 encoded content is found that cannot be processed yet. throw new ClientException(_("Can't handle embedded Base64 content yet.")); } } diff --git a/lib/activityverb.php b/lib/activityverb.php index 76f2b84e9..264351308 100644 --- a/lib/activityverb.php +++ b/lib/activityverb.php @@ -42,7 +42,6 @@ if (!defined('STATUSNET')) { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 * @link http://status.net/ */ - class ActivityVerb { const POST = 'http://activitystrea.ms/schema/1.0/post'; diff --git a/lib/adminform.php b/lib/adminform.php index 3934f6351..1ecb02435 100644 --- a/lib/adminform.php +++ b/lib/adminform.php @@ -45,7 +45,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { * * @see Form */ - class AdminForm extends Form { /** @@ -59,7 +58,6 @@ class AdminForm extends Form * * @return void */ - function input($setting, $title, $instructions, $section='site') { $this->out->input($setting, $title, $this->value($setting, $section), $instructions); @@ -73,7 +71,6 @@ class AdminForm extends Form * * @return string param value if posted, or current config value */ - function value($setting, $main='site') { $value = $this->out->trimmed($setting); @@ -82,5 +79,4 @@ class AdminForm extends Form } return $value; } - } diff --git a/lib/adminpanelaction.php b/lib/adminpanelaction.php index 9e0b2d041..8dd16e9d0 100644 --- a/lib/adminpanelaction.php +++ b/lib/adminpanelaction.php @@ -44,7 +44,6 @@ if (!defined('STATUSNET')) { * * @todo Find some commonalities with SettingsAction and combine */ - class AdminPanelAction extends Action { var $success = true; @@ -61,7 +60,6 @@ class AdminPanelAction extends Action * * @return boolean success flag */ - function prepare($args) { parent::prepare($args); @@ -124,7 +122,6 @@ class AdminPanelAction extends Action * * @return void */ - function handle($args) { if ($_SERVER['REQUEST_METHOD'] == 'POST') { @@ -155,7 +152,6 @@ class AdminPanelAction extends Action * @return void * @see AdminPanelNav */ - function showLocalNav() { $nav = new AdminPanelNav($this); @@ -169,7 +165,6 @@ class AdminPanelAction extends Action * * @return void. */ - function showContent() { $this->showForm(); @@ -199,7 +194,6 @@ class AdminPanelAction extends Action * * @return void */ - function showPageNotice() { if ($this->msg) { @@ -222,7 +216,6 @@ class AdminPanelAction extends Action * * @return void */ - function showForm() { // TRANS: Client error message. @@ -239,7 +232,6 @@ class AdminPanelAction extends Action * * @return void */ - function getInstructions() { return ''; @@ -252,7 +244,6 @@ class AdminPanelAction extends Action * * @return void */ - function saveSettings() { // TRANS: Client error message @@ -267,7 +258,6 @@ class AdminPanelAction extends Action * * @return mixed $result false if something didn't work */ - function deleteSetting($section, $setting) { $config = new Config(); @@ -314,7 +304,6 @@ class AdminPanelAction extends Action * * @see Widget */ - class AdminPanelNav extends Widget { var $action = null; @@ -324,7 +313,6 @@ class AdminPanelNav extends Widget * * @param Action $action current action, used for output */ - function __construct($action=null) { parent::__construct($action); @@ -336,7 +324,6 @@ class AdminPanelNav extends Widget * * @return void */ - function show() { $action_name = $this->action->trimmed('action'); @@ -409,6 +396,14 @@ class AdminPanelNav extends Widget $menu_title, $action_name == 'snapshotadminpanel', 'nav_snapshot_admin_panel'); } + if (AdminPanelAction::canAdmin('license')) { + // TRANS: Menu item title/tooltip + $menu_title = _('Set site license'); + // TRANS: Menu item for site administration + $this->out->menuItem(common_local_url('licenseadminpanel'), _('License'), + $menu_title, $action_name == 'licenseadminpanel', 'nav_license_admin_panel'); + } + if (AdminPanelAction::canAdmin('plugins')) { // TRANS: Menu item title/tooltip $menu_title = _('Plugins configuration'); @@ -421,5 +416,4 @@ class AdminPanelNav extends Widget } $this->action->elementEnd('ul'); } - } diff --git a/lib/apiaction.php b/lib/apiaction.php index 432b32453..d8249055a 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -114,7 +114,6 @@ class ApiValidationException extends Exception { } * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ - class ApiAction extends Action { const READ_ONLY = 1; @@ -141,7 +140,6 @@ class ApiAction extends Action * * @return boolean false if user doesn't exist */ - function prepare($args) { StatusNet::setApi(true); // reduce exception reports to aid in debugging @@ -174,7 +172,6 @@ class ApiAction extends Action * * @return void */ - function handle($args) { header('Access-Control-Allow-Origin: *'); @@ -303,7 +300,7 @@ class ApiAction extends Action // StatusNet-specific - $twitter_user['statusnet:profile_url'] = $profile->profileurl; + $twitter_user['statusnet_profile_url'] = $profile->profileurl; return $twitter_user; } @@ -408,7 +405,7 @@ class ApiAction extends Action // StatusNet-specific - $twitter_status['statusnet:html'] = $notice->rendered; + $twitter_status['statusnet_html'] = $notice->rendered; return $twitter_status; } @@ -464,66 +461,70 @@ class ApiAction extends Action function twitterRssEntryArray($notice) { - $profile = $notice->getProfile(); - $entry = array(); - // We trim() to avoid extraneous whitespace in the output + if (Event::handle('StartRssEntryArray', array($notice, &$entry))) { + $profile = $notice->getProfile(); - $entry['content'] = common_xml_safe_str(trim($notice->rendered)); - $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); + // We trim() to avoid extraneous whitespace in the output - $taguribase = TagURI::base(); - $entry['id'] = "tag:$taguribase:$entry[link]"; + $entry['content'] = common_xml_safe_str(trim($notice->rendered)); + $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['updated'] = $entry['published']; - $entry['author'] = $profile->getBestName(); + $taguribase = TagURI::base(); + $entry['id'] = "tag:$taguribase:$entry[link]"; - // Enclosures - $attachments = $notice->attachments(); - $enclosures = array(); - - foreach ($attachments as $attachment) { - $enclosure_o=$attachment->getEnclosure(); - if ($enclosure_o) { - $enclosure = array(); - $enclosure['url'] = $enclosure_o->url; - $enclosure['mimetype'] = $enclosure_o->mimetype; - $enclosure['size'] = $enclosure_o->size; - $enclosures[] = $enclosure; - } - } + $entry['updated'] = $entry['published']; + $entry['author'] = $profile->getBestName(); - if (!empty($enclosures)) { - $entry['enclosures'] = $enclosures; - } + // Enclosures + $attachments = $notice->attachments(); + $enclosures = array(); - // Tags/Categories - $tag = new Notice_tag(); - $tag->notice_id = $notice->id; - if ($tag->find()) { - $entry['tags']=array(); - while ($tag->fetch()) { - $entry['tags'][]=$tag->tag; + foreach ($attachments as $attachment) { + $enclosure_o=$attachment->getEnclosure(); + if ($enclosure_o) { + $enclosure = array(); + $enclosure['url'] = $enclosure_o->url; + $enclosure['mimetype'] = $enclosure_o->mimetype; + $enclosure['size'] = $enclosure_o->size; + $enclosures[] = $enclosure; + } } - } - $tag->free(); - // RSS Item specific - $entry['description'] = $entry['content']; - $entry['pubDate'] = common_date_rfc2822($notice->created); - $entry['guid'] = $entry['link']; + if (!empty($enclosures)) { + $entry['enclosures'] = $enclosures; + } - if (isset($notice->lat) && isset($notice->lon)) { - // This is the format that GeoJSON expects stuff to be in. - // showGeoRSS() below uses it for XML output, so we reuse it - $entry['geo'] = array('type' => 'Point', - 'coordinates' => array((float) $notice->lat, - (float) $notice->lon)); - } else { - $entry['geo'] = null; + // Tags/Categories + $tag = new Notice_tag(); + $tag->notice_id = $notice->id; + if ($tag->find()) { + $entry['tags']=array(); + while ($tag->fetch()) { + $entry['tags'][]=$tag->tag; + } + } + $tag->free(); + + // RSS Item specific + $entry['description'] = $entry['content']; + $entry['pubDate'] = common_date_rfc2822($notice->created); + $entry['guid'] = $entry['link']; + + if (isset($notice->lat) && isset($notice->lon)) { + // This is the format that GeoJSON expects stuff to be in. + // showGeoRSS() below uses it for XML output, so we reuse it + $entry['geo'] = array('type' => 'Point', + 'coordinates' => array((float) $notice->lat, + (float) $notice->lon)); + } else { + $entry['geo'] = null; + } + + Event::handle('EndRssEntryArray', array($notice, &$entry)); } return $entry; @@ -552,7 +553,6 @@ class ApiAction extends Action $notifications = false; if ($source->isSubscribed($target)) { - $sub = Subscription::pkeyGet(array('subscriber' => $source->id, 'subscribed' => $target->id)); @@ -615,7 +615,11 @@ class ApiAction extends Action $this->showTwitterXmlStatus($value, 'retweeted_status'); break; default: - $this->element($element, null, $value); + if (strncmp($element, 'statusnet_', 10) == 0) { + $this->element('statusnet:'.substr($element, 10), null, $value); + } else { + $this->element($element, null, $value); + } } } $this->elementEnd($tag); @@ -640,6 +644,8 @@ class ApiAction extends Action foreach($twitter_user as $element => $value) { if ($element == 'status') { $this->showTwitterXmlStatus($twitter_user['status']); + } else if (strncmp($element, 'statusnet_', 10) == 0) { + $this->element('statusnet:'.substr($element, 10), null, $value); } else { $this->element($element, null, $value); } @@ -732,7 +738,6 @@ class ApiAction extends Action function showXmlTimeline($notice) { - $this->initDocument('xml'); $this->elementStart('statuses', array('type' => 'array', 'xmlns:statusnet' => 'http://status.net/schema/api/1/')); @@ -757,7 +762,6 @@ class ApiAction extends Action function showRssTimeline($notice, $title, $link, $subtitle, $suplink = null, $logo = null, $self = null) { - $this->initDocument('rss'); $this->element('title', null, $title); @@ -813,7 +817,6 @@ class ApiAction extends Action function showAtomTimeline($notice, $title, $id, $link, $subtitle=null, $suplink=null, $selfuri=null, $logo=null) { - $this->initDocument('atom'); $this->element('title', null, $title); @@ -853,12 +856,10 @@ class ApiAction extends Action } $this->endDocument('atom'); - } function showRssGroups($group, $title, $link, $subtitle) { - $this->initDocument('rss'); $this->element('title', null, $title); @@ -1006,7 +1007,6 @@ class ApiAction extends Action function showAtomGroups($group, $title, $id, $link, $subtitle=null, $selfuri=null) { - $this->initDocument('atom'); $this->element('title', null, common_xml_safe_str($title)); @@ -1037,7 +1037,6 @@ class ApiAction extends Action function showJsonTimeline($notice) { - $this->initDocument('json'); $statuses = array(); @@ -1063,7 +1062,6 @@ class ApiAction extends Action function showJsonGroups($group) { - $this->initDocument('json'); $groups = array(); @@ -1109,7 +1107,6 @@ class ApiAction extends Action function showTwitterXmlUsers($user) { - $this->initDocument('xml'); $this->elementStart('users', array('type' => 'array', 'xmlns:statusnet' => 'http://status.net/schema/api/1/')); @@ -1132,7 +1129,6 @@ class ApiAction extends Action function showJsonUsers($user) { - $this->initDocument('json'); $users = array(); @@ -1217,7 +1213,6 @@ class ApiAction extends Action $this->endXML(); break; case 'json': - // Check for JSONP callback if (isset($this->callback)) { print ')'; @@ -1363,7 +1358,6 @@ class ApiAction extends Action function getTargetUser($id) { if (empty($id)) { - // Twitter supports these other ways of passing the user ID if (is_numeric($this->arg('id'))) { return User::staticGet($this->arg('id')); @@ -1474,7 +1468,6 @@ class ApiAction extends Action */ function arg($key, $def=null) { - // XXX: Do even more input validation/scrubbing? if (array_key_exists($key, $this->args)) { @@ -1541,5 +1534,4 @@ class ApiAction extends Action return $uri; } - } diff --git a/lib/apiauth.php b/lib/apiauth.php index cf7a2692c..8b0a3da17 100644 --- a/lib/apiauth.php +++ b/lib/apiauth.php @@ -68,7 +68,6 @@ require_once INSTALLDIR . '/lib/apioauth.php'; * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ - class ApiAuthAction extends ApiAction { var $auth_user_nickname = null; @@ -83,7 +82,6 @@ class ApiAuthAction extends ApiAction * @return boolean success flag * */ - function prepare($args) { parent::prepare($args); @@ -126,7 +124,6 @@ class ApiAuthAction extends ApiAction * * @return mixed the OAuthRequest or false */ - function getOAuthRequest() { ApiOauthAction::cleanRequest(); @@ -154,7 +151,6 @@ class ApiAuthAction extends ApiAction * * @return nothing */ - function checkOAuthRequest($request) { $datastore = new ApiStatusNetOAuthDataStore(); @@ -164,7 +160,6 @@ class ApiAuthAction extends ApiAction $server->add_signature_method($hmac_method); try { - $server->verify_request($request); $consumer = $request->get_parameter('oauth_consumer_key'); @@ -176,7 +171,8 @@ class ApiAuthAction extends ApiAction common_log(LOG_WARNING, 'Couldn\'t find the OAuth app for consumer key: ' . $consumer); - throw new OAuthException('No application for that consumer key.'); + // TRANS: OAuth exception thrown when no application is found for a given consumer key. + throw new OAuthException(_('No application for that consumer key.')); } // set the source attr @@ -186,19 +182,15 @@ class ApiAuthAction extends ApiAction $appUser = Oauth_application_user::staticGet('token', $access_token); if (!empty($appUser)) { - // If access_type == 0 we have either a request token // or a bad / revoked access token if ($appUser->access_type != 0) { - // Set the access level for the api call - $this->access = ($appUser->access_type & Oauth_application::$writeAccess) ? self::READ_WRITE : self::READ_ONLY; // Set the auth user - if (Event::handle('StartSetApiUser', array(&$user))) { $this->auth_user = User::staticGet('id', $appUser->profile_id); Event::handle('EndSetApiUser', array($user)); @@ -216,13 +208,13 @@ class ApiAuthAction extends ApiAction 'read-write' : 'read-only' )); } else { - throw new OAuthException('Bad access token.'); + // TRANS: OAuth exception given when an incorrect access token was given for a user. + throw new OAuthException(_('Bad access token.')); } } else { - // Also should not happen - - throw new OAuthException('No user for that token.'); + // TRANS: OAuth exception given when no user was found for a given token (no token was found). + throw new OAuthException(_('No user for that token.')); } } catch (OAuthException $e) { @@ -237,7 +229,6 @@ class ApiAuthAction extends ApiAction * * @return boolean true */ - function requiresAuth() { return true; @@ -249,7 +240,6 @@ class ApiAuthAction extends ApiAction * * @return boolean true or false */ - function checkBasicAuthUser($required = true) { $this->basicAuthProcessHeader(); @@ -264,8 +254,8 @@ class ApiAuthAction extends ApiAction header('WWW-Authenticate: Basic realm="' . $realm . '"'); // show error if the user clicks 'cancel' - - $this->clientError("Could not authenticate you.", 401, $this->format); + // TRANS: Client error thrown when authentication fails becaus a user clicked "Cancel". + $this->clientError(_("Could not authenticate you."), 401, $this->format); exit; } else { @@ -283,13 +273,11 @@ class ApiAuthAction extends ApiAction } // By default, basic auth users have rw access - $this->access = self::READ_WRITE; if (empty($this->auth_user) && ($required || isset($_SERVER['PHP_AUTH_USER']))) { // basic authentication failed - list($proxy, $ip) = common_client_ip(); $msg = sprintf( 'Failed API auth attempt, nickname = %1$s, ' . @@ -298,7 +286,8 @@ class ApiAuthAction extends ApiAction $proxy, $ip); common_log(LOG_WARNING, $msg); - $this->clientError("Could not authenticate you.", 401, $this->format); + // TRANS: Client error thrown when authentication fails. + $this->clientError(_("Could not authenticate you."), 401, $this->format); exit; } } @@ -310,7 +299,6 @@ class ApiAuthAction extends ApiAction * * @return void */ - function basicAuthProcessHeader() { $authHeaders = array('AUTHORIZATION', @@ -332,7 +320,6 @@ class ApiAuthAction extends ApiAction // Decode the HTTP_AUTHORIZATION header on php-cgi server self // on fcgid server the header name is AUTHORIZATION - $auth_hash = base64_decode(substr($authorization_header, 6)); list($this->auth_user_nickname, $this->auth_user_password) = explode(':', $auth_hash); diff --git a/lib/apibareauth.php b/lib/apibareauth.php index da7af1261..043181b07 100644 --- a/lib/apibareauth.php +++ b/lib/apibareauth.php @@ -30,7 +30,7 @@ * @author Evan Prodromou <evan@status.net> * @author mEDI <medi@milaro.net> * @author Sarven Capadisli <csarven@status.net> - * @author Zach Copley <zach@status.net> + * @author Zach Copley <zach@status.net> * @copyright 2009 StatusNet, Inc. * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 @@ -60,10 +60,8 @@ require_once INSTALLDIR.'/lib/apiauth.php'; * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ - class ApiBareAuthAction extends ApiAuthAction { - /** * Take arguments for running * @@ -72,7 +70,6 @@ class ApiBareAuthAction extends ApiAuthAction * @return boolean success flag * */ - function prepare($args) { parent::prepare($args); @@ -84,18 +81,15 @@ class ApiBareAuthAction extends ApiAuthAction * * @return boolean true or false */ - function requiresAuth() { // If the site is "private", all API methods except statusnet/config // need authentication - if (common_config('site', 'private')) { return true; } // check whether a user has been specified somehow - $id = $this->arg('id'); $user_id = $this->arg('user_id'); $screen_name = $this->arg('screen_name'); @@ -106,5 +100,4 @@ class ApiBareAuthAction extends ApiAuthAction return false; } - } diff --git a/lib/apioauth.php b/lib/apioauth.php index 4cb8a6775..1c87e4232 100644 --- a/lib/apioauth.php +++ b/lib/apioauth.php @@ -44,7 +44,6 @@ require_once INSTALLDIR . '/lib/apioauthstore.php'; * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ - class ApiOauthAction extends Action { /** @@ -52,7 +51,6 @@ class ApiOauthAction extends Action * * @return boolean false */ - function isReadOnly($args) { return false; @@ -73,7 +71,6 @@ class ApiOauthAction extends Action * * @return void */ - function handle($args) { parent::handle($args); @@ -83,7 +80,6 @@ class ApiOauthAction extends Action static function cleanRequest() { // kill evil effects of magical slashing - if (get_magic_quotes_gpc() == 1) { $_POST = array_map('stripslashes', $_POST); $_GET = array_map('stripslashes', $_GET); @@ -93,7 +89,6 @@ class ApiOauthAction extends Action // XXX: should we strip anything else? Or alternatively // only allow a known list of params? - unset($_GET['p']); unset($_POST['p']); } @@ -118,5 +113,4 @@ class ApiOauthAction extends Action return ($url . '&' . $k . '=' . $v); } } - } diff --git a/lib/apioauthstore.php b/lib/apioauthstore.php index 1bb11cbca..eca93866f 100644 --- a/lib/apioauthstore.php +++ b/lib/apioauthstore.php @@ -23,7 +23,6 @@ require_once INSTALLDIR . '/lib/oauthstore.php'; class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore { - function lookup_consumer($consumer_key) { $con = Consumer::staticGet('consumer_key', $consumer_key); @@ -39,7 +38,6 @@ class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore function getAppByRequestToken($token_key) { // Look up the full req tokenx - $req_token = $this->lookup_token(null, 'request', $token_key); @@ -50,7 +48,6 @@ class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore } // Look up the full Token - $token = new Token(); $token->tok = $req_token->key; $result = $token->find(true); @@ -150,10 +147,8 @@ class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore } // Okay, good - return new OAuthToken($at->tok, $at->secret); } - } else { return null; } @@ -172,19 +167,20 @@ class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore * * @return void */ - public function revoke_token($token_key, $type = 0) { $rt = new Token(); $rt->tok = $token_key; $rt->type = $type; $rt->state = 0; + if (!$rt->find(true)) { - throw new Exception('Tried to revoke unknown token'); + // TRANS: Exception thrown when an attempt is made to revoke an unknown token. + throw new Exception(_('Tried to revoke unknown token.')); } + if (!$rt->delete()) { - throw new Exception('Failed to delete revoked token'); + // TRANS: Exception thrown when an attempt is made to remove a revoked token. + throw new Exception(_('Failed to delete revoked token.')); } } - } - diff --git a/lib/apiprivateauth.php b/lib/apiprivateauth.php index 5e78c65a1..df401c382 100644 --- a/lib/apiprivateauth.php +++ b/lib/apiprivateauth.php @@ -29,7 +29,7 @@ * @author Evan Prodromou <evan@status.net> * @author mEDI <medi@milaro.net> * @author Sarven Capadisli <csarven@status.net> - * @author Zach Copley <zach@status.net> + * @author Zach Copley <zach@status.net> * @copyright 2009 StatusNet, Inc. * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 @@ -58,26 +58,21 @@ require_once INSTALLDIR.'/lib/apiauth.php'; * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ - class ApiPrivateAuthAction extends ApiAuthAction { - /** * Does this API resource require authentication? * * @return boolean true or false */ - function requiresAuth() { // If the site is "private", all API methods except statusnet/config // need authentication - if (common_config('site', 'private')) { return true; } return false; } - } diff --git a/lib/applicationeditform.php b/lib/applicationeditform.php index 81c8fb018..f53c31feb 100644 --- a/lib/applicationeditform.php +++ b/lib/applicationeditform.php @@ -43,13 +43,11 @@ require_once INSTALLDIR . '/lib/form.php'; * @link http://status.net/ * */ - class ApplicationEditForm extends Form { /** * group for user to join */ - var $application = null; /** @@ -58,7 +56,6 @@ class ApplicationEditForm extends Form * @param Action $out output channel * @param User_group $group group to join */ - function __construct($out=null, $application=null) { parent::__construct($out); @@ -71,7 +68,6 @@ class ApplicationEditForm extends Form * * @return string ID of the form */ - function id() { if ($this->application) { @@ -89,7 +85,6 @@ class ApplicationEditForm extends Form * * @return string the method to use for submitting */ - function method() { $this->enctype = 'multipart/form-data'; @@ -101,7 +96,6 @@ class ApplicationEditForm extends Form * * @return string of the form class */ - function formClass() { return 'form_settings'; @@ -112,7 +106,6 @@ class ApplicationEditForm extends Form * * @return string URL of the action */ - function action() { $cur = common_current_user(); @@ -130,7 +123,6 @@ class ApplicationEditForm extends Form * * @return void */ - function formLegend() { // TRANS: Form legend. @@ -142,7 +134,6 @@ class ApplicationEditForm extends Form * * @return void */ - function formData() { if ($this->application) { @@ -206,7 +197,8 @@ class ApplicationEditForm extends Form $maxDesc = Oauth_application::maxDesc(); if ($maxDesc > 0) { // TRANS: Form input field instructions. - $descInstr = sprintf(_('Describe your application in %d characters'), + // TRANS: %d is the number of available characters for the description. + $descInstr = sprintf(ngettext('Describe your application in %d character','Describe your application in %d characters',$maxDesc), $maxDesc); } else { // TRANS: Form input field instructions. @@ -265,8 +257,9 @@ class ApplicationEditForm extends Form // Default to Browser - if ($this->application->type == Oauth_application::$browser - || empty($this->application->type)) { + if (empty($this->application) + || empty($this->application->type) + || $this->application->type == Oauth_application::$browser) { $attrs['checked'] = 'checked'; } @@ -283,7 +276,7 @@ class ApplicationEditForm extends Form 'class' => 'radio', 'value' => Oauth_application::$desktop); - if ($this->application->type == Oauth_application::$desktop) { + if (!empty($this->application) && $this->application->type == Oauth_application::$desktop) { $attrs['checked'] = 'checked'; } @@ -307,8 +300,9 @@ class ApplicationEditForm extends Form // default to read-only access - if ($this->application->access_type & Oauth_application::$readAccess - || empty($this->application->access_type)) { + if (empty($this->application) + || empty($this->application->access_type) + || $this->application->access_type & Oauth_application::$readAccess) { $attrs['checked'] = 'checked'; } @@ -325,7 +319,8 @@ class ApplicationEditForm extends Form 'class' => 'radio', 'value' => 'rw'); - if ($this->application->access_type & Oauth_application::$readAccess + if (!empty($this->application) + && $this->application->access_type & Oauth_application::$readAccess && $this->application->access_type & Oauth_application::$writeAccess ) { $attrs['checked'] = 'checked'; @@ -350,16 +345,15 @@ class ApplicationEditForm extends Form * * @return void */ - function formActions() { - // TRANS: Button label + // TRANS: Button label in the "Edit application" form. $this->out->submit('cancel', _m('BUTTON','Cancel'), 'submit form_action-primary', - // TRANS: Submit button title + // TRANS: Submit button title. 'cancel', _('Cancel')); - // TRANS: Button label + // TRANS: Button label in the "Edit application" form. $this->out->submit('save', _m('BUTTON','Save'), 'submit form_action-secondary', - // TRANS: Submit button title + // TRANS: Submit button title. 'save', _('Save')); } } diff --git a/lib/applicationlist.php b/lib/applicationlist.php index 904f8981d..8b6e3a8ad 100644 --- a/lib/applicationlist.php +++ b/lib/applicationlist.php @@ -1,5 +1,4 @@ <?php - /** * StatusNet, the distributed open-source microblogging tool * @@ -45,7 +44,6 @@ define('APPS_PER_PAGE', 20); * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ - class ApplicationList extends Widget { /** Current application, application query */ @@ -140,7 +138,7 @@ class ApplicationList extends Widget $access = ($this->application->access_type & Oauth_application::$writeAccess) ? $readWriteText : $readOnlyText; $modifiedDate = common_date_string($appUser->modified); - // TRANS: Used in application list. %1$s is a modified date, %2$s is access type (read-write or read-only) + // TRANS: Used in application list. %1$s is a modified date, %2$s is access type ("read-write" or "read-only") $txt = sprintf(_('Approved %1$s - "%2$s" access.'),$modifiedDate,$access); $this->out->raw($txt); @@ -164,10 +162,8 @@ class ApplicationList extends Widget } /* Override this in subclasses. */ - function showOwnerControls() { return; } - } diff --git a/lib/atom10feed.php b/lib/atom10feed.php index a46d49f35..3ae9dc81b 100644 --- a/lib/atom10feed.php +++ b/lib/atom10feed.php @@ -109,7 +109,7 @@ class Atom10Feed extends XMLStringer $xs->element('name', null, $name); } else { throw new Atom10FeedException( - 'author element must contain a name element.' + _('author element must contain a name element.') ); } @@ -323,5 +323,4 @@ class Atom10Feed extends XMLStringer array_push($this->links, $attrs); } - } diff --git a/lib/atomusernoticefeed.php b/lib/atomusernoticefeed.php index 785db4915..ec368f5ca 100644 --- a/lib/atomusernoticefeed.php +++ b/lib/atomusernoticefeed.php @@ -44,7 +44,7 @@ if (!defined('STATUSNET')) */ class AtomUserNoticeFeed extends AtomNoticeFeed { - private $user; + protected $user; /** * Constructor @@ -55,7 +55,6 @@ class AtomUserNoticeFeed extends AtomNoticeFeed * * @return void */ - function __construct($user, $cur = null, $indent = true) { parent::__construct($cur, $indent); $this->user = $user; @@ -90,7 +89,7 @@ class AtomUserNoticeFeed extends AtomNoticeFeed array('nickname' => $user->nickname) ) ); - + $self = common_local_url('ApiTimelineUser', array('id' => $user->id, 'format' => 'atom')); diff --git a/lib/attachmentlist.php b/lib/attachmentlist.php index 59cab9532..f6b09fb49 100644 --- a/lib/attachmentlist.php +++ b/lib/attachmentlist.php @@ -49,7 +49,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { * @see NoticeListItem * @see ProfileNoticeList */ - class AttachmentList extends Widget { /** the current stream of notices being displayed. */ @@ -61,7 +60,6 @@ class AttachmentList extends Widget * * @param Notice $notice stream of notices from DB_DataObject */ - function __construct($notice, $out=null) { parent::__construct($out); @@ -76,7 +74,6 @@ class AttachmentList extends Widget * * @return int count of notices listed. */ - function show() { $atts = new File; @@ -111,7 +108,6 @@ class AttachmentList extends Widget * * @return NoticeListItem a list item for displaying the notice */ - function newListItem($attachment) { return new AttachmentListItem($attachment, $this->out); @@ -135,7 +131,6 @@ class AttachmentList extends Widget * @see NoticeList * @see ProfileNoticeListItem */ - class AttachmentListItem extends Widget { /** The attachment this item will show. */ @@ -151,7 +146,6 @@ class AttachmentListItem extends Widget * * @param Notice $notice The notice we'll display */ - function __construct($attachment, $out=null) { parent::__construct($out); @@ -185,7 +179,6 @@ class AttachmentListItem extends Widget * * @return void */ - function show() { $this->showStart(); @@ -221,7 +214,6 @@ class AttachmentListItem extends Widget * * @return void */ - function showStart() { // XXX: RDFa @@ -236,7 +228,6 @@ class AttachmentListItem extends Widget * * @return void */ - function showEnd() { $this->out->elementEnd('li'); @@ -257,7 +248,7 @@ class Attachment extends AttachmentListItem $this->out->elementEnd('div'); if (!empty($this->oembed->author_name) || !empty($this->oembed->provider)) { - $this->out->elementStart('div', array('id' => 'oembed_info', + $this->out->elementStart('div', array('id' => 'oembed_info', 'class' => 'entry-content')); if (!empty($this->oembed->author_name)) { $this->out->elementStart('dl', 'vcard author'); @@ -438,4 +429,3 @@ class Attachment extends AttachmentListItem $this->out->raw('<script>window.location = ' . json_encode($this->attachment->url) . ';</script>'); } } - diff --git a/lib/attachmentnoticesection.php b/lib/attachmentnoticesection.php index 578c171ff..25e64adf9 100644 --- a/lib/attachmentnoticesection.php +++ b/lib/attachmentnoticesection.php @@ -42,7 +42,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ - class AttachmentNoticeSection extends NoticeSection { function showContent() { @@ -59,11 +58,12 @@ class AttachmentNoticeSection extends NoticeSection $notice->orderBy('created desc'); $notice->selectAdd('post_id as id'); $notice->find(); - return $notice; + return $notice; } function title() { + // TRANS: Title. return _('Notices where this attachment appears'); } @@ -72,4 +72,3 @@ class AttachmentNoticeSection extends NoticeSection return 'popular_notices'; } } - diff --git a/lib/attachmenttagcloudsection.php b/lib/attachmenttagcloudsection.php index e2f85ae02..2c8fc5ee1 100644 --- a/lib/attachmenttagcloudsection.php +++ b/lib/attachmenttagcloudsection.php @@ -40,11 +40,11 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ - class AttachmentTagCloudSection extends TagCloudSection { function title() { + // TRANS: Title. return _('Tags for this attachment'); } @@ -80,4 +80,3 @@ class AttachmentTagCloudSection extends TagCloudSection return $notice_tag; } } - diff --git a/lib/authenticationplugin.php b/lib/authenticationplugin.php index dbdf20629..5e878c155 100644 --- a/lib/authenticationplugin.php +++ b/lib/authenticationplugin.php @@ -40,12 +40,11 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ - abstract class AuthenticationPlugin extends Plugin { //is this plugin authoritative for authentication? public $authoritative = false; - + //should accounts be automatically created after a successful login attempt? public $autoregistration = false; @@ -218,12 +217,14 @@ abstract class AuthenticationPlugin extends Plugin //stop handling of other handlers, because what was requested was done return false; }else{ - throw new Exception(_('Password changing failed')); + // TRANS: Exception thrown when a password change fails. + throw new Exception(_('Password changing failed.')); } }else{ if($this->authoritative){ //since we're authoritative, no other plugin could do this - throw new Exception(_('Password changing failed')); + // TRANS: Exception thrown when a password change fails. + throw new Exception(_('Password changing failed.')); }else{ //let another handler try return null; @@ -233,7 +234,8 @@ abstract class AuthenticationPlugin extends Plugin }else{ if($this->authoritative){ //since we're authoritative, no other plugin could do this - throw new Exception(_('Password changing is not allowed')); + // TRANS: Exception thrown when a password change attempt fails because it is not allowed. + throw new Exception(_('Password changing is not allowed.')); } } } @@ -267,4 +269,3 @@ abstract class AuthenticationPlugin extends Plugin return true; } } - diff --git a/lib/authorizationplugin.php b/lib/authorizationplugin.php index d71f77243..dda604add 100644 --- a/lib/authorizationplugin.php +++ b/lib/authorizationplugin.php @@ -40,7 +40,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ - abstract class AuthorizationPlugin extends Plugin { //is this plugin authoritative for authorization? @@ -103,4 +102,3 @@ abstract class AuthorizationPlugin extends Plugin } } } - diff --git a/lib/blockform.php b/lib/blockform.php index b6652b1f6..1af5e8cfd 100644 --- a/lib/blockform.php +++ b/lib/blockform.php @@ -44,7 +44,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { * * @see UnblockForm */ - class BlockForm extends ProfileActionForm { /** @@ -63,9 +62,9 @@ class BlockForm extends ProfileActionForm * * @return string Title of the form, internationalized */ - function title() { + // TRANS: Title for the form to block a user. return _('Block'); } @@ -74,9 +73,9 @@ class BlockForm extends ProfileActionForm * * @return string description of the form, internationalized */ - function description() { + // TRANS: Description of the form to block a user. return _('Block this user'); } } diff --git a/lib/cache.php b/lib/cache.php index c09a1dd9f..3d78c79ad 100644 --- a/lib/cache.php +++ b/lib/cache.php @@ -41,7 +41,6 @@ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @link http://status.net/ */ - class Cache { var $_items = array(); @@ -56,7 +55,6 @@ class Cache * * @return Cache cache object */ - static function instance() { if (is_null(self::$_inst)) { @@ -77,13 +75,12 @@ class Cache * * @return string full key */ - static function key($extra) { $base_key = common_config('cache', 'base'); if (empty($base_key)) { - $base_key = common_keyize(common_config('site', 'name')); + $base_key = self::keyize(common_config('site', 'name')); } return 'statusnet:' . $base_key . ':' . $extra; @@ -98,7 +95,6 @@ class Cache * * @return string keyized string */ - static function keyize($str) { $str = strtolower($str); @@ -115,7 +111,6 @@ class Cache * * @return string retrieved value or null if unfound */ - function get($key) { $value = false; @@ -140,7 +135,6 @@ class Cache * * @return boolean success flag */ - function set($key, $value, $flag=null, $expiry=null) { $success = false; @@ -192,7 +186,6 @@ class Cache * * @return boolean success flag */ - function delete($key) { $success = false; @@ -214,7 +207,6 @@ class Cache * * @return boolean success flag */ - function reconnect() { $success = false; diff --git a/lib/channel.php b/lib/channel.php index e83960ac5..ae9b2d214 100644 --- a/lib/channel.php +++ b/lib/channel.php @@ -19,6 +19,9 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } +/** + * @todo Needs documentation. + */ class Channel { function on($user) @@ -97,6 +100,7 @@ class WebChannel extends Channel # depending on what command was run $this->out->startHTML(); $this->out->elementStart('head'); + // TRANS: Title for command results. $this->out->element('title', null, _('Command results')); $this->out->elementEnd('head'); $this->out->elementStart('body'); @@ -117,6 +121,7 @@ class AjaxWebChannel extends WebChannel { $this->out->startHTML('text/xml;charset=utf-8'); $this->out->elementStart('head'); + // TRANS: Title for command results. $this->out->element('title', null, _('Command results')); $this->out->elementEnd('head'); $this->out->elementStart('body'); @@ -129,7 +134,8 @@ class AjaxWebChannel extends WebChannel { $this->out->startHTML('text/xml;charset=utf-8'); $this->out->elementStart('head'); - $this->out->element('title', null, _('Ajax Error')); + // TRANS: Title for command results. + $this->out->element('title', null, _('AJAX error')); $this->out->elementEnd('head'); $this->out->elementStart('body'); $this->out->element('p', array('id' => 'error'), $text); @@ -140,7 +146,6 @@ class AjaxWebChannel extends WebChannel class MailChannel extends Channel { - var $addr = null; function source() @@ -155,20 +160,20 @@ class MailChannel extends Channel function on($user) { - return $this->set_notify($user, 1); + return $this->setNotify($user, 1); } function off($user) { - return $this->set_notify($user, 0); + return $this->setNotify($user, 0); } function output($user, $text) { - $headers['From'] = $user->incomingemail; $headers['To'] = $this->addr; + // TRANS: E-mail subject when a command has completed. $headers['Subject'] = _('Command complete'); return mail_send(array($this->addr), $headers, $text); @@ -176,16 +181,16 @@ class MailChannel extends Channel function error($user, $text) { - $headers['From'] = $user->incomingemail; $headers['To'] = $this->addr; + // TRANS: E-mail subject when a command has failed. $headers['Subject'] = _('Command failed'); return mail_send(array($this->addr), $headers, $text); } - function set_notify($user, $value) + function setNotify($user, $value) { $orig = clone($user); $user->smsnotify = $value; diff --git a/lib/clienterroraction.php b/lib/clienterroraction.php index 1b98a1064..08bced5bd 100644 --- a/lib/clienterroraction.php +++ b/lib/clienterroraction.php @@ -1,5 +1,4 @@ <?php - /** * Client error action. * diff --git a/lib/clientexception.php b/lib/clientexception.php index 01c013a01..a74cab4a5 100644 --- a/lib/clientexception.php +++ b/lib/clientexception.php @@ -42,7 +42,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ - class ClientException extends Exception { public function __construct($message = null, $code = 400) { diff --git a/lib/columndef.php b/lib/columndef.php index ac2fcd23e..b21b30e0d 100644 --- a/lib/columndef.php +++ b/lib/columndef.php @@ -40,7 +40,6 @@ if (!defined('STATUSNET')) { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ - class ColumnDef { /** name of the column. */ @@ -76,7 +75,6 @@ class ColumnDef * @param value $extra unused * @param boolean $auto_increment */ - function __construct($name=null, $type=null, $size=null, $nullable=true, $key=null, $default=null, $extra=null, $auto_increment=false) @@ -99,7 +97,6 @@ class ColumnDef * * @return boolean true if equivalent, otherwise false. */ - function equals($other) { return ($this->name == $other->name && @@ -122,7 +119,6 @@ class ColumnDef * * @return boolean true if they're about equivalent */ - private function _typeMatch($other) { switch ($this->type) { @@ -145,7 +141,6 @@ class ColumnDef * * @return boolean true if defaults are effectively the same. */ - private function _defaultMatch($other) { return ((is_null($this->default) && is_null($other->default)) || @@ -160,7 +155,6 @@ class ColumnDef * * @return boolean true if these columns 'null' the same. */ - private function _nullMatch($other) { return ((!is_null($this->default) && !is_null($other->default) && diff --git a/lib/command.php b/lib/command.php index 30db9d069..efe917fb1 100644 --- a/lib/command.php +++ b/lib/command.php @@ -23,7 +23,6 @@ require_once(INSTALLDIR.'/lib/channel.php'); class Command { - var $user = null; function __construct($user=null) @@ -49,7 +48,6 @@ class Command } } - /** * Override this with the meat! * @@ -80,15 +78,16 @@ class Command $notice = Notice::staticGet(substr($arg,1)); if (!$notice) { - throw new CommandException(_('Notice with that id does not exist')); + // TRANS: Command exception text shown when a notice ID is requested that does not exist. + throw new CommandException(_('Notice with that id does not exist.')); } } - + if (Validate::uri($this->other)) { // A specific notice by URI lookup $notice = Notice::staticGet('uri', $arg); } - + if (!$notice) { // Local or remote profile name to get their last notice. // May throw an exception and report 'no such user' @@ -96,13 +95,15 @@ class Command $notice = $recipient->getCurrentNotice(); if (!$notice) { - throw new CommandException(_('User has no last notice')); + // TRANS: Command exception text shown when a last user notice is requested and it does not exist. + throw new CommandException(_('User has no last notice.')); } } } Event::handle('EndCommandGetNotice', array($this, $arg, &$notice)); if (!$notice) { - throw new CommandException(_('Notice with that id does not exist')); + // TRANS: Command exception text shown when a notice ID is requested that does not exist. + throw new CommandException(_('Notice with that id does not exist.')); } return $notice; } @@ -124,7 +125,7 @@ class Command if (!$profile) { // TRANS: Message given requesting a profile for a non-existing user. // TRANS: %s is the nickname of the user for which the profile could not be found. - throw new CommandException(sprintf(_('Could not find a user with nickname %s'), $arg)); + throw new CommandException(sprintf(_('Could not find a user with nickname %s.'), $arg)); } return $profile; } @@ -144,7 +145,7 @@ class Command if (!$user){ // TRANS: Message given getting a non-existing user. // TRANS: %s is the nickname of the user that could not be found. - throw new CommandException(sprintf(_('Could not find a local user with nickname %s'), + throw new CommandException(sprintf(_('Could not find a local user with nickname %s.'), $arg)); } return $user; @@ -163,6 +164,7 @@ class Command } Event::handle('EndCommandGetGroup', array($this, $arg, &$group)); if (!$group) { + // TRANS: Command exception text shown when a group is requested that does not exist. throw new CommandException(_('No such group.')); } return $group; @@ -177,6 +179,7 @@ class UnimplementedCommand extends Command { function handle($channel) { + // TRANS: Error text shown when an unimplemented command is given. $channel->error($this->user, _("Sorry, this command is not yet implemented.")); } } @@ -222,6 +225,7 @@ class NudgeCommand extends Command { $recipient = $this->getUser($this->other); if ($recipient->id == $this->user->id) { + // TRANS: Command exception text shown when a user tries to nudge themselves. throw new CommandException(_('It does not make a lot of sense to nudge yourself!')); } else { if ($recipient->email && $recipient->emailnotifynudge) { @@ -231,7 +235,7 @@ class NudgeCommand extends Command // XXX: notify by SMS // TRANS: Message given having nudged another user. // TRANS: %s is the nickname of the user that was nudged. - $channel->output($this->user, sprintf(_('Nudge sent to %s'), + $channel->output($this->user, sprintf(_('Nudge sent to %s.'), $recipient->nickname)); } } @@ -257,6 +261,10 @@ class StatsCommand extends Command $subbed_count = $profile->subscriberCount(); $notice_count = $profile->noticeCount(); + // TRANS: User statistics text. + // TRANS: %1$s is the number of other user the user is subscribed to. + // TRANS: %2$s is the number of users that are subscribed to the user. + // TRANS: %3$s is the number of notices the user has sent. $channel->output($this->user, sprintf(_("Subscriptions: %1\$s\n". "Subscribers: %2\$s\n". "Notices: %3\$s"), @@ -282,6 +290,7 @@ class FavCommand extends Command $fave = Fave::addNew($this->user->getProfile(), $notice); if (!$fave) { + // TRANS: Error message text shown when a favorite could not be set. $channel->error($this->user, _('Could not create favorite.')); return; } @@ -299,9 +308,9 @@ class FavCommand extends Command $this->user->blowFavesCache(); + // TRANS: Text shown when a notice has been marked as favourite successfully. $channel->output($this->user, _('Notice marked as fave.')); } - } class JoinCommand extends Command @@ -320,10 +329,12 @@ class JoinCommand extends Command $cur = $this->user; if ($cur->isMember($group)) { - $channel->error($cur, _('You are already a member of that group')); + // TRANS: Error text shown a user tries to join a group they already are a member of. + $channel->error($cur, _('You are already a member of that group.')); return; } if (Group_block::isBlocked($group, $cur->getProfile())) { + // TRANS: Error text shown when a user tries to join a group they are blocked from joining. $channel->error($cur, _('You have been blocked from that group by the admin.')); return; } @@ -336,19 +347,19 @@ class JoinCommand extends Command } catch (Exception $e) { // TRANS: Message given having failed to add a user to a group. // TRANS: %1$s is the nickname of the user, %2$s is the nickname of the group. - $channel->error($cur, sprintf(_('Could not join user %1$s to group %2$s'), + $channel->error($cur, sprintf(_('Could not join user %1$s to group %2$s.'), $cur->nickname, $group->nickname)); return; } // TRANS: Message given having added a user to a group. // TRANS: %1$s is the nickname of the user, %2$s is the nickname of the group. - $channel->output($cur, sprintf(_('%1$s joined group %2$s'), + $channel->output($cur, sprintf(_('%1$s joined group %2$s.'), $cur->nickname, $group->nickname)); } - } + class DropCommand extends Command { var $other = null; @@ -365,11 +376,13 @@ class DropCommand extends Command $cur = $this->user; if (!$group) { + // TRANS: Error text shown when trying to leave a group that does not exist. $channel->error($cur, _('No such group.')); return; } if (!$cur->isMember($group)) { + // TRANS: Error text shown when trying to leave an existing group the user is not a member of. $channel->error($cur, _('You are not a member of that group.')); return; } @@ -382,18 +395,17 @@ class DropCommand extends Command } catch (Exception $e) { // TRANS: Message given having failed to remove a user from a group. // TRANS: %1$s is the nickname of the user, %2$s is the nickname of the group. - $channel->error($cur, sprintf(_('Could not remove user %1$s from group %2$s'), + $channel->error($cur, sprintf(_('Could not remove user %1$s from group %2$s.'), $cur->nickname, $group->nickname)); return; } // TRANS: Message given having removed a user from a group. // TRANS: %1$s is the nickname of the user, %2$s is the nickname of the group. - $channel->output($cur, sprintf(_('%1$s left group %2$s'), + $channel->output($cur, sprintf(_('%1$s left group %2$s.'), $cur->nickname, $group->nickname)); } - } class WhoisCommand extends Command @@ -454,12 +466,15 @@ class MessageCommand extends Command } catch (CommandException $f) { throw $e; } + // TRANS: Command exception text shown when trying to send a direct message to a remote user (a user not registered at the current server). + // TRANS: %s is a remote profile. throw new CommandException(sprintf(_('%s is a remote profile; you can only send direct messages to users on the same server.'), $this->other)); } $len = mb_strlen($this->text); if ($len == 0) { + // TRANS: Command exception text shown when trying to send a direct message to another user without content. $channel->error($this->user, _('No content!')); return; } @@ -467,20 +482,24 @@ class MessageCommand extends Command $this->text = common_shorten_links($this->text); if (Message::contentTooLong($this->text)) { + // XXX: i18n. Needs plural support. // TRANS: Message given if content is too long. // TRANS: %1$d is the maximum number of characters, %2$d is the number of submitted characters. - $channel->error($this->user, sprintf(_('Message too long - maximum is %1$d characters, you sent %2$d'), + $channel->error($this->user, sprintf(_('Message too long - maximum is %1$d characters, you sent %2$d.'), Message::maxContent(), mb_strlen($this->text))); return; } if (!$other) { + // TRANS: Error text shown when trying to send a direct message to a user that does not exist. $channel->error($this->user, _('No such user.')); return; } else if (!$this->user->mutuallySubscribed($other)) { + // TRANS: Error text shown when trying to send a direct message to a user without a mutual subscription (each user must be subscribed to the other). $channel->error($this->user, _('You can\'t send a message to this user.')); return; } else if ($this->user->id == $other->id) { + // TRANS: Error text shown when trying to send a direct message to self. $channel->error($this->user, _('Don\'t send a message to yourself; just say it to yourself quietly instead.')); return; } @@ -489,8 +508,9 @@ class MessageCommand extends Command $message->notify(); // TRANS: Message given have sent a direct message to another user. // TRANS: %s is the name of the other user. - $channel->output($this->user, sprintf(_('Direct message to %s sent'), $this->other)); + $channel->output($this->user, sprintf(_('Direct message to %s sent.'), $this->other)); } else { + // TRANS: Error text shown sending a direct message fails with an unknown reason. $channel->error($this->user, _('Error sending direct message.')); } } @@ -511,12 +531,14 @@ class RepeatCommand extends Command if($this->user->id == $notice->profile_id) { - $channel->error($this->user, _('Cannot repeat your own notice')); + // TRANS: Error text shown when trying to repeat an own notice. + $channel->error($this->user, _('Cannot repeat your own notice.')); return; } if ($this->user->getProfile()->hasRepeated($notice->id)) { - $channel->error($this->user, _('Already repeated that notice')); + // TRANS: Error text shown when trying to repeat an notice that was already repeated by the user. + $channel->error($this->user, _('Already repeated that notice.')); return; } @@ -526,8 +548,9 @@ class RepeatCommand extends Command // TRANS: Message given having repeated a notice from another user. // TRANS: %s is the name of the user for which the notice was repeated. - $channel->output($this->user, sprintf(_('Notice from %s repeated'), $recipient->nickname)); + $channel->output($this->user, sprintf(_('Notice from %s repeated.'), $recipient->nickname)); } else { + // TRANS: Error text shown when repeating a notice fails with an unknown reason. $channel->error($this->user, _('Error repeating notice.')); } } @@ -552,6 +575,7 @@ class ReplyCommand extends Command $len = mb_strlen($this->text); if ($len == 0) { + // TRANS: Command exception text shown when trying to reply to a notice without providing content for the reply. $channel->error($this->user, _('No content!')); return; } @@ -559,7 +583,10 @@ class ReplyCommand extends Command $this->text = common_shorten_links($this->text); if (Notice::contentTooLong($this->text)) { - $channel->error($this->user, sprintf(_('Notice too long - maximum is %d characters, you sent %d'), + // XXX: i18n. Needs plural support. + // TRANS: Message given if content of a notice for a reply is too long. + // TRANS: %1$d is the maximum number of characters, %2$d is the number of submitted characters. + $channel->error($this->user, sprintf(_('Notice too long - maximum is %1$d characters, you sent %2$d.'), Notice::maxContent(), mb_strlen($this->text))); return; } @@ -568,8 +595,11 @@ class ReplyCommand extends Command array('reply_to' => $notice->id)); if ($notice) { - $channel->output($this->user, sprintf(_('Reply to %s sent'), $recipient->nickname)); + // TRANS: Text shown having sent a reply to a notice successfully. + // TRANS: %s is the nickname of the user of the notice the reply was sent to. + $channel->output($this->user, sprintf(_('Reply to %s sent.'), $recipient->nickname)); } else { + // TRANS: Error text shown when a reply to a notice fails with an unknown reason. $channel->error($this->user, _('Error saving notice.')); } @@ -578,7 +608,6 @@ class ReplyCommand extends Command class GetCommand extends Command { - var $other = null; function __construct($user, $other) @@ -593,7 +622,8 @@ class GetCommand extends Command $notice = $target->getCurrentNotice(); if (!$notice) { - $channel->error($this->user, _('User has no last notice')); + // TRANS: Error text shown when a last user notice is requested and it does not exist. + $channel->error($this->user, _('User has no last notice.')); return; } $notice_content = $notice->content; @@ -604,7 +634,6 @@ class GetCommand extends Command class SubCommand extends Command { - var $other = null; function __construct($user, $other) @@ -617,7 +646,8 @@ class SubCommand extends Command { if (!$this->other) { - $channel->error($this->user, _('Specify the name of the user to subscribe to')); + // TRANS: Error text shown when no username was provided when issuing a subscribe command. + $channel->error($this->user, _('Specify the name of the user to subscribe to.')); return; } @@ -625,13 +655,16 @@ class SubCommand extends Command $remote = Remote_profile::staticGet('id', $target->id); if ($remote) { + // TRANS: Command exception text shown when trying to subscribe to an OMB profile using the subscribe command. throw new CommandException(_("Can't subscribe to OMB profiles by command.")); } try { Subscription::start($this->user->getProfile(), $target); - $channel->output($this->user, sprintf(_('Subscribed to %s'), $this->other)); + // TRANS: Text shown after having subscribed to another user successfully. + // TRANS: %s is the name of the user the subscription was requested for. + $channel->output($this->user, sprintf(_('Subscribed to %s.'), $this->other)); } catch (Exception $e) { $channel->error($this->user, $e->getMessage()); } @@ -640,7 +673,6 @@ class SubCommand extends Command class UnsubCommand extends Command { - var $other = null; function __construct($user, $other) @@ -652,7 +684,8 @@ class UnsubCommand extends Command function handle($channel) { if(!$this->other) { - $channel->error($this->user, _('Specify the name of the user to unsubscribe from')); + // TRANS: Error text shown when no username was provided when issuing an unsubscribe command. + $channel->error($this->user, _('Specify the name of the user to unsubscribe from.')); return; } @@ -661,7 +694,9 @@ class UnsubCommand extends Command try { Subscription::cancel($this->user->getProfile(), $target); - $channel->output($this->user, sprintf(_('Unsubscribed from %s'), $this->other)); + // TRANS: Text shown after having unsubscribed from another user successfully. + // TRANS: %s is the name of the user the unsubscription was requested for. + $channel->output($this->user, sprintf(_('Unsubscribed from %s.'), $this->other)); } catch (Exception $e) { $channel->error($this->user, $e->getMessage()); } @@ -671,6 +706,7 @@ class UnsubCommand extends Command class OffCommand extends Command { var $other = null; + function __construct($user, $other=null) { parent::__construct($user); @@ -679,11 +715,14 @@ class OffCommand extends Command function handle($channel) { if ($this->other) { + // TRANS: Error text shown when issuing the command "off" with a setting which has not yet been implemented. $channel->error($this->user, _("Command not yet implemented.")); } else { if ($channel->off($this->user)) { + // TRANS: Text shown when issuing the command "off" successfully. $channel->output($this->user, _('Notification off.')); } else { + // TRANS: Error text shown when the command "off" fails for an unknown reason. $channel->error($this->user, _('Can\'t turn off notification.')); } } @@ -702,11 +741,14 @@ class OnCommand extends Command function handle($channel) { if ($this->other) { + // TRANS: Error text shown when issuing the command "on" with a setting which has not yet been implemented. $channel->error($this->user, _("Command not yet implemented.")); } else { if ($channel->on($this->user)) { + // TRANS: Text shown when issuing the command "on" successfully. $channel->output($this->user, _('Notification on.')); } else { + // TRANS: Error text shown when the command "on" fails for an unknown reason. $channel->error($this->user, _('Can\'t turn on notification.')); } } @@ -720,7 +762,8 @@ class LoginCommand extends Command $disabled = common_config('logincommand','disabled'); $disabled = isset($disabled) && $disabled; if($disabled) { - $channel->error($this->user, _('Login command is disabled')); + // TRANS: Error text shown when issuing the login command while login is disabled. + $channel->error($this->user, _('Login command is disabled.')); return; } @@ -731,7 +774,9 @@ class LoginCommand extends Command } $channel->output($this->user, - sprintf(_('This link is useable only once, and is good for only 2 minutes: %s'), + // TRANS: Text shown after issuing the login command successfully. + // TRANS: %s is a logon link.. + sprintf(_('This link is useable only once and is valid for only 2 minutes: %s.'), common_local_url('otp', array('user_id' => $login_token->user_id, 'token' => $login_token->token)))); } @@ -739,7 +784,6 @@ class LoginCommand extends Command class LoseCommand extends Command { - var $other = null; function __construct($user, $other) @@ -751,14 +795,17 @@ class LoseCommand extends Command function execute($channel) { if(!$this->other) { - $channel->error($this->user, _('Specify the name of the user to unsubscribe from')); + // TRANS: Error text shown when no username was provided when issuing the command. + $channel->error($this->user, _('Specify the name of the user to unsubscribe from.')); return; } $result = Subscription::cancel($this->getProfile($this->other), $this->user->getProfile()); if ($result) { - $channel->output($this->user, sprintf(_('Unsubscribed %s'), $this->other)); + // TRANS: Text shown after issuing the lose command successfully (stop another user from following the current user). + // TRANS: %s is the name of the user the unsubscription was requested for. + $channel->output($this->user, sprintf(_('Unsubscribed %s.'), $this->other)); } else { $channel->error($this->user, $result); } @@ -775,8 +822,12 @@ class SubscriptionsCommand extends Command $nicknames[]=$profile->nickname; } if(count($nicknames)==0){ + // TRANS: Text shown after requesting other users a user is subscribed to without having any subscriptions. $out=_('You are not subscribed to anyone.'); }else{ + // TRANS: Text shown after requesting other users a user is subscribed to. + // TRANS: This message supports plural forms. This message is followed by a + // TRANS: hard coded space and a comma separated list of subscribed users. $out = ngettext('You are subscribed to this person:', 'You are subscribed to these people:', count($nicknames)); @@ -797,8 +848,13 @@ class SubscribersCommand extends Command $nicknames[]=$profile->nickname; } if(count($nicknames)==0){ + // TRANS: Text shown after requesting other users that are subscribed to a user + // TRANS: (followers) without having any subscribers. $out=_('No one is subscribed to you.'); }else{ + // TRANS: Text shown after requesting other users that are subscribed to a user (followers). + // TRANS: This message supports plural forms. This message is followed by a + // TRANS: hard coded space and a comma separated list of subscribing users. $out = ngettext('This person is subscribed to you:', 'These people are subscribed to you:', count($nicknames)); @@ -819,8 +875,13 @@ class GroupsCommand extends Command $groups[]=$group->nickname; } if(count($groups)==0){ + // TRANS: Text shown after requesting groups a user is subscribed to without having + // TRANS: any group subscriptions. $out=_('You are not a member of any groups.'); }else{ + // TRANS: Text shown after requesting groups a user is subscribed to. + // TRANS: This message supports plural forms. This message is followed by a + // TRANS: hard coded space and a comma separated list of subscribed groups. $out = ngettext('You are a member of this group:', 'You are a member of these groups:', count($nicknames)); @@ -835,6 +896,7 @@ class HelpCommand extends Command function handle($channel) { $channel->output($this->user, + // TRANS: Help text for commands. Do not translate the command names themselves; they are fixed strings. _("Commands:\n". "on - turn on notifications\n". "off - turn off notifications\n". diff --git a/lib/commandinterpreter.php b/lib/commandinterpreter.php index fbc6174bb..c288c2e5f 100644 --- a/lib/commandinterpreter.php +++ b/lib/commandinterpreter.php @@ -272,7 +272,7 @@ class CommandInterpreter return false; } } - + /** * Split arguments without triggering a PHP notice warning */ @@ -285,4 +285,3 @@ class CommandInterpreter return $pieces; } } - diff --git a/lib/common.php b/lib/common.php index 570666da7..2a11ab722 100644 --- a/lib/common.php +++ b/lib/common.php @@ -22,10 +22,10 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } //exit with 200 response, if this is checking fancy from the installer if (isset($_REQUEST['p']) && $_REQUEST['p'] == 'check-fancy') { exit; } -define('STATUSNET_VERSION', '0.9.4beta2'); +define('STATUSNET_VERSION', '0.9.5'); define('LACONICA_VERSION', STATUSNET_VERSION); // compatibility -define('STATUSNET_CODENAME', 'Orange Crush'); +define('STATUSNET_CODENAME', 'What\'s The Frequency, Kenneth?'); define('AVATAR_PROFILE_SIZE', 96); define('AVATAR_STREAM_SIZE', 48); @@ -150,11 +150,17 @@ try { } catch (NoConfigException $e) { // XXX: Throw a conniption if database not installed // XXX: Find a way to use htmlwriter for this instead of handcoded markup + // TRANS: Error message displayed when no configuration file was found for a StatusNet installation. echo '<p>'. _('No configuration file found. ') .'</p>'; - echo '<p>'. _('I looked for configuration files in the following places: ') .'<br/> '; - echo implode($e->configFiles, '<br/>'); + // TRANS: Error message displayed when no configuration file was found for a StatusNet installation. + // TRANS: Is followed by a list of directories (separated by HTML breaks). + echo '<p>'. _('I looked for configuration files in the following places: ') .'<br /> '; + echo implode($e->configFiles, '<br />'); + // TRANS: Error message displayed when no configuration file was found for a StatusNet installation. echo '<p>'. _('You may wish to run the installer to fix this.') .'</p>'; + // @todo FIXME Link should be in a para? + // TRANS: Error message displayed when no configuration file was found for a StatusNet installation. + // TRANS: The text is link text that leads to the installer page. echo '<a href="install.php">'. _('Go to the installer.') .'</a>'; exit; } - diff --git a/lib/connectsettingsaction.php b/lib/connectsettingsaction.php index 5d62fc56b..c2e759f0f 100644 --- a/lib/connectsettingsaction.php +++ b/lib/connectsettingsaction.php @@ -44,7 +44,6 @@ require_once INSTALLDIR.'/lib/settingsaction.php'; * * @see Widget */ - class ConnectSettingsAction extends SettingsAction { /** @@ -54,7 +53,6 @@ class ConnectSettingsAction extends SettingsAction * * @return void */ - function showLocalNav() { $menu = new ConnectSettingsNav($this); @@ -73,7 +71,6 @@ class ConnectSettingsAction extends SettingsAction * * @see HTMLOutputter */ - class ConnectSettingsNav extends Widget { var $action = null; @@ -83,7 +80,6 @@ class ConnectSettingsNav extends Widget * * @param Action $action current action, used for output */ - function __construct($action=null) { parent::__construct($action); @@ -95,7 +91,6 @@ class ConnectSettingsNav extends Widget * * @return void */ - function show() { $action_name = $this->action->trimmed('action'); @@ -109,17 +104,23 @@ class ConnectSettingsNav extends Widget Event::handle('GetImTransports', array(&$transports)); if ($transports) { $menu['imsettings'] = - array(_('IM'), + // TRANS: Menu item for Instant Messaging settings. + array(_m('MENU','IM'), + // TRANS: Tooltip for Instant Messaging menu item. _('Updates by instant messenger (IM)')); } if (common_config('sms', 'enabled')) { $menu['smssettings'] = - array(_('SMS'), + // TRANS: Menu item for Short Message Service settings. + array(_m('MENU','SMS'), + // TRANS: Tooltip for Short Message Service menu item. _('Updates by SMS')); } - + $menu['oauthconnectionssettings'] = array( - _('Connections'), + // TRANS: Menu item for OAth connection settings. + _m('MENU','Connections'), + // TRANS: Tooltip for connected applications (Connections through OAth) menu item. _('Authorized connected applications') ); @@ -135,6 +136,4 @@ class ConnectSettingsNav extends Widget $this->action->elementEnd('ul'); } - } - diff --git a/lib/currentuserdesignaction.php b/lib/currentuserdesignaction.php index c2f38cd00..490f87d13 100644 --- a/lib/currentuserdesignaction.php +++ b/lib/currentuserdesignaction.php @@ -44,7 +44,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { * @link http://status.net/ * */ - class CurrentUserDesignAction extends Action { /** @@ -54,7 +53,6 @@ class CurrentUserDesignAction extends Action * * @return Design a design object to use */ - function getDesign() { $cur = common_current_user(); diff --git a/lib/dbqueuemanager.php b/lib/dbqueuemanager.php index 3dda9fd1a..51553b899 100644 --- a/lib/dbqueuemanager.php +++ b/lib/dbqueuemanager.php @@ -100,7 +100,7 @@ class DBQueueManager extends QueueManager } } else { $this->_log(LOG_INFO, "[$queue] Got empty/deleted item, discarding"); - $this->_fail($qi); + $this->_done($qi); } return true; } diff --git a/lib/default.php b/lib/default.php index 76e4e44cf..79b54fc3b 100644 --- a/lib/default.php +++ b/lib/default.php @@ -299,10 +299,11 @@ $default = 'RSSCloud' => null, 'ClientSideShorten' => null, 'OpenID' => null), + 'locale_path' => false, // Set to a path to use *instead of* each plugin's own locale subdirectories ), 'pluginlist' => array(), 'admin' => - array('panels' => array('design', 'site', 'user', 'paths', 'access', 'sessions', 'sitenotice', 'plugins')), + array('panels' => array('design', 'site', 'user', 'paths', 'access', 'sessions', 'sitenotice', 'license', 'plugins')), 'singleuser' => array('enabled' => false, 'nickname' => null), diff --git a/lib/disfavorform.php b/lib/disfavorform.php index 5b135b38a..6023766d7 100644 --- a/lib/disfavorform.php +++ b/lib/disfavorform.php @@ -123,9 +123,13 @@ class DisfavorForm extends Form function formData() { - $this->out->hidden('notice-n'.$this->notice->id, - $this->notice->id, - 'notice'); + if (Event::handle('StartDisFavorNoticeForm', array($this, $this->notice))) { + $this->out->hidden('notice-n'.$this->notice->id, + $this->notice->id, + 'notice'); + Event::handle('EndDisFavorNoticeForm', array($this, $this->notice)); + } + } /** diff --git a/lib/distribqueuehandler.php b/lib/distribqueuehandler.php index 8f4b72d5c..a7519c1d5 100644 --- a/lib/distribqueuehandler.php +++ b/lib/distribqueuehandler.php @@ -78,13 +78,19 @@ class DistribQueueHandler } try { + Event::handle('EndNoticeDistribute', array($notice)); + } catch (Exception $e) { + $this->logit($notice, $e); + } + + try { Event::handle('EndNoticeSave', array($notice)); - // Enqueue for other handlers } catch (Exception $e) { $this->logit($notice, $e); } try { + // Enqueue for other handlers common_enqueue_notice($notice); } catch (Exception $e) { $this->logit($notice, $e); diff --git a/lib/favorform.php b/lib/favorform.php index 625df7c8b..4e2891ffd 100644 --- a/lib/favorform.php +++ b/lib/favorform.php @@ -123,9 +123,12 @@ class FavorForm extends Form function formData() { - $this->out->hidden('notice-n'.$this->notice->id, - $this->notice->id, - 'notice'); + if (Event::handle('StartFavorNoticeForm', array($this, $this->notice))) { + $this->out->hidden('notice-n'.$this->notice->id, + $this->notice->id, + 'notice'); + Event::handle('EndFavorNoticeForm', array($this, $this->notice)); + } } /** diff --git a/lib/feedlist.php b/lib/feedlist.php index 9ae83f5e8..4aacf0b3d 100644 --- a/lib/feedlist.php +++ b/lib/feedlist.php @@ -59,42 +59,50 @@ class FeedList extends Widget function show($feeds) { - $this->out->elementStart('div', array('id' => 'export_data', - 'class' => 'section')); - $this->out->element('h2', null, _('Export data')); - $this->out->elementStart('ul', array('class' => 'xoxo')); + if (Event::handle('StartShowFeedLinkList', array($this->action, &$feeds))) { + if (!empty($feeds)) { + $this->out->elementStart('div', array('id' => 'export_data', + 'class' => 'section')); + $this->out->element('h2', null, _('Feeds')); + $this->out->elementStart('ul', array('class' => 'xoxo')); - foreach ($feeds as $feed) { - $this->feedItem($feed); - } + foreach ($feeds as $feed) { + $this->feedItem($feed); + } - $this->out->elementEnd('ul'); - $this->out->elementEnd('div'); + $this->out->elementEnd('ul'); + $this->out->elementEnd('div'); + } + Event::handle('EndShowFeedLinkList', array($this->action, &$feeds)); + } } function feedItem($feed) { - $classname = null; + if (Event::handle('StartShowFeedLink', array($this->action, &$feed))) { + $classname = null; - switch ($feed->type) { - case Feed::RSS1: - case Feed::RSS2: - $classname = 'rss'; - break; - case Feed::ATOM: - $classname = 'atom'; - break; - case Feed::FOAF: - $classname = 'foaf'; - break; - } + switch ($feed->type) { + case Feed::RSS1: + case Feed::RSS2: + $classname = 'rss'; + break; + case Feed::ATOM: + $classname = 'atom'; + break; + case Feed::FOAF: + $classname = 'foaf'; + break; + } - $this->out->elementStart('li'); - $this->out->element('a', array('href' => $feed->url, - 'class' => $classname, - 'type' => $feed->mimeType(), - 'title' => $feed->title), - $feed->typeName()); - $this->out->elementEnd('li'); + $this->out->elementStart('li'); + $this->out->element('a', array('href' => $feed->url, + 'class' => $classname, + 'type' => $feed->mimeType(), + 'title' => $feed->title), + $feed->typeName()); + $this->out->elementEnd('li'); + Event::handle('EndShowFeedLink', array($this->action, $feed)); + } } } diff --git a/lib/groupnav.php b/lib/groupnav.php index 131b38fa2..ee988d0a9 100644 --- a/lib/groupnav.php +++ b/lib/groupnav.php @@ -82,14 +82,20 @@ class GroupNav extends Widget if (Event::handle('StartGroupGroupNav', array($this))) { $this->out->menuItem(common_local_url('showgroup', array('nickname' => $nickname)), - _('Group'), - sprintf(_('%s group'), $nickname), + // TRANS: Menu item in the group navigation page. + _m('MENU','Group'), + // TRANS: Tooltip for menu item in the group navigation page. + // TRANS: %s is the nickname of the group. + sprintf(_m('TOOLTIP','%s group'), $nickname), $action_name == 'showgroup', 'nav_group_group'); $this->out->menuItem(common_local_url('groupmembers', array('nickname' => $nickname)), - _('Members'), - sprintf(_('%s group members'), $nickname), + // TRANS: Menu item in the group navigation page. + _m('MENU','Members'), + // TRANS: Tooltip for menu item in the group navigation page. + // TRANS: %s is the nickname of the group. + sprintf(_m('TOOLTIP','%s group members'), $nickname), $action_name == 'groupmembers', 'nav_group_members'); @@ -98,26 +104,38 @@ class GroupNav extends Widget if ($cur && $cur->isAdmin($this->group)) { $this->out->menuItem(common_local_url('blockedfromgroup', array('nickname' => $nickname)), - _('Blocked'), - sprintf(_('%s blocked users'), $nickname), + // TRANS: Menu item in the group navigation page. Only shown for group administrators. + _m('MENU','Blocked'), + // TRANS: Tooltip for menu item in the group navigation page. Only shown for group administrators. + // TRANS: %s is the nickname of the group. + sprintf(_m('TOOLTIP','%s blocked users'), $nickname), $action_name == 'blockedfromgroup', 'nav_group_blocked'); $this->out->menuItem(common_local_url('editgroup', array('nickname' => $nickname)), - _('Admin'), - sprintf(_('Edit %s group properties'), $nickname), + // TRANS: Menu item in the group navigation page. Only shown for group administrators. + _m('MENU','Admin'), + // TRANS: Tooltip for menu item in the group navigation page. Only shown for group administrators. + // TRANS: %s is the nickname of the group. + sprintf(_m('TOOLTIP','Edit %s group properties'), $nickname), $action_name == 'editgroup', 'nav_group_admin'); $this->out->menuItem(common_local_url('grouplogo', array('nickname' => $nickname)), - _('Logo'), - sprintf(_('Add or edit %s logo'), $nickname), + // TRANS: Menu item in the group navigation page. Only shown for group administrators. + _m('MENU','Logo'), + // TRANS: Tooltip for menu item in the group navigation page. Only shown for group administrators. + // TRANS: %s is the nickname of the group. + sprintf(_m('TOOLTIP','Add or edit %s logo'), $nickname), $action_name == 'grouplogo', 'nav_group_logo'); $this->out->menuItem(common_local_url('groupdesignsettings', array('nickname' => $nickname)), - _('Design'), - sprintf(_('Add or edit %s design'), $nickname), + // TRANS: Menu item in the group navigation page. Only shown for group administrators. + _m('MENU','Design'), + // TRANS: Tooltip for menu item in the group navigation page. Only shown for group administrators. + // TRANS: %s is the nickname of the group. + sprintf(_m('TOOLTIP','Add or edit %s design'), $nickname), $action_name == 'groupdesignsettings', 'nav_group_design'); } diff --git a/lib/htmloutputter.php b/lib/htmloutputter.php index 7eccd6cc0..9780dc424 100644 --- a/lib/htmloutputter.php +++ b/lib/htmloutputter.php @@ -325,6 +325,7 @@ class HTMLOutputter extends XMLOutputter * @param string $label text of the button * @param string $cls class of the button, default 'submit' * @param string $name name, if different than ID + * @param string $title title text for the submit button * * @return void * diff --git a/lib/imchannel.php b/lib/imchannel.php index 12354ce4b..61355a429 100644 --- a/lib/imchannel.php +++ b/lib/imchannel.php @@ -36,27 +36,27 @@ class IMChannel extends Channel function on($user) { - return $this->set_notify($user, 1); + return $this->setNotify($user, 1); } function off($user) { - return $this->set_notify($user, 0); + return $this->setNotify($user, 0); } function output($user, $text) { $text = '['.common_config('site', 'name') . '] ' . $text; - $this->imPlugin->send_message($this->imPlugin->get_screenname($user), $text); + $this->imPlugin->sendMessage($this->imPlugin->getScreenname($user), $text); } function error($user, $text) { $text = '['.common_config('site', 'name') . '] ' . $text; - $screenname = $this->imPlugin->get_screenname($user); + $screenname = $this->imPlugin->getScreenname($user); if($screenname){ - $this->imPlugin->send_message($screenname, $text); + $this->imPlugin->sendMessage($screenname, $text); return true; }else{ common_log(LOG_ERR, @@ -66,7 +66,7 @@ class IMChannel extends Channel } } - function set_notify($user, $notify) + function setNotify($user, $notify) { $user_im_prefs = new User_im_prefs(); $user_im_prefs->transport = $this->imPlugin->transport; diff --git a/lib/immanager.php b/lib/immanager.php index da80b74b7..9563a5326 100644 --- a/lib/immanager.php +++ b/lib/immanager.php @@ -31,7 +31,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } * 2) override handleInput() with what to do when data is waiting on * one of the sockets * 3) override idle($timeout) to do keepalives (if necessary) - * 4) implement send_raw_message() to send raw data that ImPlugin::enqueue_outgoing_raw + * 4) implement send_raw_message() to send raw data that ImPlugin::enqueueOutgoingRaw * enqueued */ diff --git a/lib/implugin.php b/lib/implugin.php index dafb8a416..2811e7d64 100644 --- a/lib/implugin.php +++ b/lib/implugin.php @@ -59,7 +59,6 @@ abstract class ImPlugin extends Plugin */ abstract function normalize($screenname); - /** * validate (ensure the validity of) a screenname * @@ -79,35 +78,35 @@ abstract class ImPlugin extends Plugin /** * send a single notice to a given screenname * The implementation should put raw data, ready to send, into the outgoing - * queue using enqueue_outgoing_raw() + * queue using enqueueOutgoingRaw() * * @param string $screenname screenname to send to * @param Notice $notice notice to send * * @return boolean success value */ - function send_notice($screenname, $notice) + function sendNotice($screenname, $notice) { - return $this->send_message($screenname, $this->format_notice($notice)); + return $this->sendMessage($screenname, $this->formatNotice($notice)); } /** * send a message (text) to a given screenname * The implementation should put raw data, ready to send, into the outgoing - * queue using enqueue_outgoing_raw() + * queue using enqueueOutgoingRaw() * * @param string $screenname screenname to send to * @param Notice $body text to send * * @return boolean success value */ - abstract function send_message($screenname, $body); + abstract function sendMessage($screenname, $body); /** * receive a raw message * Raw IM data is taken from the incoming queue, and passed to this function. - * It should parse the raw message and call handle_incoming() - * + * It should parse the raw message and call handleIncoming() + * * Returning false may CAUSE REPROCESSING OF THE QUEUE ITEM, and should * be used for temporary failures only. For permanent failures such as * unrecognized addresses, return true to indicate your processing has @@ -117,14 +116,14 @@ abstract class ImPlugin extends Plugin * * @return boolean true if processing completed, false for temporary failures */ - abstract function receive_raw_message($data); + abstract function receiveRawMessage($data); /** * get the screenname of the daemon that sends and receives message for this service * * @return string screenname of this plugin */ - abstract function daemon_screenname(); + abstract function daemonScreenname(); /** * get the microid uri of a given screenname @@ -135,7 +134,7 @@ abstract class ImPlugin extends Plugin */ function microiduri($screenname) { - return $this->transport . ':' . $screenname; + return $this->transport . ':' . $screenname; } //========================UTILITY FUNCTIONS USEFUL TO IMPLEMENTATIONS - MISC ========================\ @@ -144,7 +143,7 @@ abstract class ImPlugin extends Plugin * * @param object $data */ - function enqueue_outgoing_raw($data) + function enqueueOutgoingRaw($data) { $qm = QueueManager::get(); $qm->enqueue($data, $this->transport . '-out'); @@ -155,7 +154,7 @@ abstract class ImPlugin extends Plugin * * @param object $data */ - function enqueue_incoming_raw($data) + function enqueueIncomingRaw($data) { $qm = QueueManager::get(); $qm->enqueue($data, $this->transport . '-in'); @@ -168,9 +167,9 @@ abstract class ImPlugin extends Plugin * * @return User user */ - function get_user($screenname) + function getUser($screenname) { - $user_im_prefs = $this->get_user_im_prefs_from_screenname($screenname); + $user_im_prefs = $this->getUserImPrefsFromScreenname($screenname); if($user_im_prefs){ $user = User::staticGet('id', $user_im_prefs->user_id); $user_im_prefs->free(); @@ -180,7 +179,6 @@ abstract class ImPlugin extends Plugin } } - /** * given a screenname, get the User_im_prefs object for this transport * @@ -188,7 +186,7 @@ abstract class ImPlugin extends Plugin * * @return User_im_prefs user_im_prefs */ - function get_user_im_prefs_from_screenname($screenname) + function getUserImPrefsFromScreenname($screenname) { $user_im_prefs = User_im_prefs::pkeyGet( array('transport' => $this->transport, @@ -200,7 +198,6 @@ abstract class ImPlugin extends Plugin } } - /** * given a User, get their screenname * @@ -208,9 +205,9 @@ abstract class ImPlugin extends Plugin * * @return string screenname of that user */ - function get_screenname($user) + function getScreenname($user) { - $user_im_prefs = $this->get_user_im_prefs_from_user($user); + $user_im_prefs = $this->getUserImPrefsFromUser($user); if ($user_im_prefs) { return $user_im_prefs->screenname; } else { @@ -218,7 +215,6 @@ abstract class ImPlugin extends Plugin } } - /** * given a User, get their User_im_prefs * @@ -226,7 +222,7 @@ abstract class ImPlugin extends Plugin * * @return User_im_prefs user_im_prefs of that user */ - function get_user_im_prefs_from_user($user) + function getUserImPrefsFromUser($user) { $user_im_prefs = User_im_prefs::pkeyGet( array('transport' => $this->transport, @@ -246,10 +242,10 @@ abstract class ImPlugin extends Plugin * * @param boolean success */ - protected function send_from_site($screenname, $msg) + protected function sendFromSite($screenname, $msg) { $text = '['.common_config('site', 'name') . '] ' . $msg; - $this->send_message($screenname, $text); + $this->sendMessage($screenname, $text); } /** @@ -261,7 +257,7 @@ abstract class ImPlugin extends Plugin * * @return boolean success value */ - function send_confirmation_code($screenname, $code, $user) + function sendConfirmationCode($screenname, $code, $user) { $body = sprintf(_('User "%s" on %s has said that your %s screenname belongs to them. ' . 'If that\'s true, you can confirm by clicking on this URL: ' . @@ -271,7 +267,7 @@ abstract class ImPlugin extends Plugin 'or if you didn\'t request this confirmation, just ignore this message.'), $user->nickname, common_config('site', 'name'), $this->getDisplayName(), common_local_url('confirmaddress', array('code' => $code))); - return $this->send_message($screenname, $body); + return $this->sendMessage($screenname, $body); } /** @@ -285,7 +281,7 @@ abstract class ImPlugin extends Plugin * @return boolean success flag */ - function public_notice($notice) + function publicNotice($notice) { // Now, users who want everything @@ -298,7 +294,7 @@ abstract class ImPlugin extends Plugin 'Sending notice ' . $notice->id . ' to public listener ' . $screenname, __FILE__); - $this->send_notice($screenname, $notice); + $this->sendNotice($screenname, $notice); } return true; @@ -318,7 +314,7 @@ abstract class ImPlugin extends Plugin * @return boolean success flag */ - function broadcast_notice($notice) + function broadcastNotice($notice) { $ni = $notice->whoGets(); @@ -329,7 +325,7 @@ abstract class ImPlugin extends Plugin // either not a local user, or just not found continue; } - $user_im_prefs = $this->get_user_im_prefs_from_user($user); + $user_im_prefs = $this->getUserImPrefsFromUser($user); if(!$user_im_prefs || !$user_im_prefs->notify){ continue; } @@ -356,7 +352,7 @@ abstract class ImPlugin extends Plugin common_log(LOG_INFO, 'Sending notice ' . $notice->id . ' to ' . $user_im_prefs->screenname, __FILE__); - $this->send_notice($user_im_prefs->screenname, $notice); + $this->sendNotice($user_im_prefs->screenname, $notice); $user_im_prefs->free(); } @@ -371,7 +367,7 @@ abstract class ImPlugin extends Plugin * @return string plain-text version of the notice, with user nickname prefixed */ - function format_notice($notice) + function formatNotice($notice) { $profile = $notice->getProfile(); return $profile->nickname . ': ' . $notice->content . ' [' . $notice->id . ']'; @@ -384,7 +380,7 @@ abstract class ImPlugin extends Plugin * @param string $body message text * @return boolean true if the message was a command and was executed, false if it was not a command */ - protected function handle_command($user, $body) + protected function handleCommand($user, $body) { $inter = new CommandInterpreter(); $cmd = $inter->handle_command($user, $body); @@ -402,7 +398,7 @@ abstract class ImPlugin extends Plugin * @param string $txt message text * @return boolean true if autoreply */ - protected function is_autoreply($txt) + protected function isAutoreply($txt) { if (preg_match('/[\[\(]?[Aa]uto[-\s]?[Rr]e(ply|sponse)[\]\)]/', $txt)) { return true; @@ -418,7 +414,7 @@ abstract class ImPlugin extends Plugin * @param string $txt message text * @return boolean true if OTR */ - protected function is_otr($txt) + protected function isOtr($txt) { if (preg_match('/^\?OTR/', $txt)) { return true; @@ -436,34 +432,34 @@ abstract class ImPlugin extends Plugin * * @param boolean success */ - protected function handle_incoming($from, $notice_text) + protected function handleIncoming($from, $notice_text) { - $user = $this->get_user($from); + $user = $this->getUser($from); // For common_current_user to work global $_cur; $_cur = $user; if (!$user) { - $this->send_from_site($from, 'Unknown user; go to ' . + $this->sendFromSite($from, 'Unknown user; go to ' . common_local_url('imsettings') . ' to add your address to your account'); common_log(LOG_WARNING, 'Message from unknown user ' . $from); return; } - if ($this->handle_command($user, $notice_text)) { + if ($this->handleCommand($user, $notice_text)) { common_log(LOG_INFO, "Command message by $from handled."); return; - } else if ($this->is_autoreply($notice_text)) { + } else if ($this->isAutoreply($notice_text)) { common_log(LOG_INFO, 'Ignoring auto reply from ' . $from); return; - } else if ($this->is_otr($notice_text)) { + } else if ($this->isOtr($notice_text)) { common_log(LOG_INFO, 'Ignoring OTR from ' . $from); return; } else { common_log(LOG_INFO, 'Posting a notice from ' . $user->nickname); - $this->add_notice($from, $user, $notice_text); + $this->addNotice($from, $user, $notice_text); } $user->free(); @@ -481,12 +477,12 @@ abstract class ImPlugin extends Plugin * * @param boolean success */ - protected function add_notice($screenname, $user, $body) + protected function addNotice($screenname, $user, $body) { $body = trim(strip_tags($body)); $content_shortened = common_shorten_links($body); if (Notice::contentTooLong($content_shortened)) { - $this->send_from_site($screenname, sprintf(_('Message too long - maximum is %1$d characters, you sent %2$d.'), + $this->sendFromSite($screenname, sprintf(_('Message too long - maximum is %1$d characters, you sent %2$d.'), Notice::maxContent(), mb_strlen($content_shortened))); return; @@ -496,11 +492,10 @@ abstract class ImPlugin extends Plugin $notice = Notice::saveNew($user->id, $content_shortened, $this->transport); } catch (Exception $e) { common_log(LOG_ERR, $e->getMessage()); - $this->send_from_site($from, $e->getMessage()); + $this->sendFromSite($from, $e->getMessage()); return; } - common_broadcast_notice($notice); common_log(LOG_INFO, 'Added notice ' . $notice->id . ' from user ' . $user->nickname); $notice->free(); @@ -508,7 +503,7 @@ abstract class ImPlugin extends Plugin } //========================EVENT HANDLERS========================\ - + /** * Register notice queue handler * @@ -599,14 +594,14 @@ abstract class ImPlugin extends Plugin { $transports[$this->transport] = array( 'display' => $this->getDisplayName(), - 'daemon_screenname' => $this->daemon_screenname()); + 'daemonScreenname' => $this->daemonScreenname()); } function onSendImConfirmationCode($transport, $screenname, $code, $user) { if($transport == $this->transport) { - $this->send_confirmation_code($screenname, $code, $user); + $this->sendConfirmationCode($screenname, $code, $user); return false; } } diff --git a/lib/imqueuehandler.php b/lib/imqueuehandler.php index b42d8e7c0..9c35890c6 100644 --- a/lib/imqueuehandler.php +++ b/lib/imqueuehandler.php @@ -37,10 +37,10 @@ class ImQueueHandler extends QueueHandler */ function handle($notice) { - $this->plugin->broadcast_notice($notice); + $this->plugin->broadcastNotice($notice); if ($notice->is_local == Notice::LOCAL_PUBLIC || $notice->is_local == Notice::LOCAL_NONPUBLIC) { - $this->plugin->public_notice($notice); + $this->plugin->publicNotice($notice); } return true; } diff --git a/lib/imreceiverqueuehandler.php b/lib/imreceiverqueuehandler.php index 269c7db91..aa4a663b7 100644 --- a/lib/imreceiverqueuehandler.php +++ b/lib/imreceiverqueuehandler.php @@ -37,6 +37,6 @@ class ImReceiverQueueHandler extends QueueHandler */ function handle($data) { - return $this->plugin->receive_raw_message($data); + return $this->plugin->receiveRawMessage($data); } } diff --git a/lib/installer.php b/lib/installer.php index ff2bed140..2eff2d85a 100644 --- a/lib/installer.php +++ b/lib/installer.php @@ -319,7 +319,7 @@ abstract class Installer $this->updateStatus(sprintf("Adding %s data to database...", $name)); $res = $this->runDbScript($scr.'.sql', $conn, 'pgsql'); if ($res === false) { - $this->updateStatus(sprintf("Can't run %d script.", $name), true); + $this->updateStatus(sprintf("Can't run %s script.", $name), true); return false; } } diff --git a/lib/language.php b/lib/language.php index 80d256807..86896cff9 100644 --- a/lib/language.php +++ b/lib/language.php @@ -322,10 +322,12 @@ function get_all_languages() { 'gl' => array('q' => 0.8, 'lang' => 'gl', 'name' => 'Galician', 'direction' => 'ltr'), 'he' => array('q' => 0.5, 'lang' => 'he', 'name' => 'Hebrew', 'direction' => 'rtl'), 'hsb' => array('q' => 0.8, 'lang' => 'hsb', 'name' => 'Upper Sorbian', 'direction' => 'ltr'), + 'hu' => array('q' => 0.8, 'lang' => 'hu', 'name' => 'Hungarian', 'direction' => 'ltr'), 'ia' => array('q' => 0.8, 'lang' => 'ia', 'name' => 'Interlingua', 'direction' => 'ltr'), 'is' => array('q' => 0.1, 'lang' => 'is', 'name' => 'Icelandic', 'direction' => 'ltr'), 'it' => array('q' => 1, 'lang' => 'it', 'name' => 'Italian', 'direction' => 'ltr'), 'jp' => array('q' => 0.5, 'lang' => 'ja', 'name' => 'Japanese', 'direction' => 'ltr'), + 'ka' => array('q' => 0.8, 'lang' => 'ka', 'name' => 'Georgian', 'direction' => 'ltr'), 'ko' => array('q' => 0.9, 'lang' => 'ko', 'name' => 'Korean', 'direction' => 'ltr'), 'mk' => array('q' => 0.5, 'lang' => 'mk', 'name' => 'Macedonian', 'direction' => 'ltr'), 'nb' => array('q' => 0.1, 'lang' => 'nb', 'name' => 'Norwegian (Bokmål)', 'direction' => 'ltr'), diff --git a/lib/mediafile.php b/lib/mediafile.php index c96c78ab5..23338cc0e 100644 --- a/lib/mediafile.php +++ b/lib/mediafile.php @@ -95,6 +95,7 @@ class MediaFile if (!$file_id) { common_log_db_error($file, "INSERT", __FILE__); + // TRANS: Client exception thrown when a database error was thrown during a file upload operation. throw new ClientException(_('There was a database error while saving your file. Please try again.')); } @@ -120,6 +121,7 @@ class MediaFile if (!$result) { common_log_db_error($file_redir, "INSERT", __FILE__); + // TRANS: Client exception thrown when a database error was thrown during a file upload operation. throw new ClientException(_('There was a database error while saving your file. Please try again.')); } } @@ -139,16 +141,19 @@ class MediaFile case UPLOAD_ERR_OK: // success, jump out break; case UPLOAD_ERR_INI_SIZE: + // TRANS: Client exception thrown when an uploaded file is larger than set in php.ini. throw new ClientException(_('The uploaded file exceeds the ' . 'upload_max_filesize directive in php.ini.')); return; case UPLOAD_ERR_FORM_SIZE: throw new ClientException( + // TRANS: Client exception. _('The uploaded file exceeds the MAX_FILE_SIZE directive' . ' that was specified in the HTML form.')); return; case UPLOAD_ERR_PARTIAL: @unlink($_FILES[$param]['tmp_name']); + // TRANS: Client exception. throw new ClientException(_('The uploaded file was only' . ' partially uploaded.')); return; @@ -156,17 +161,21 @@ class MediaFile // No file; probably just a non-AJAX submission. return; case UPLOAD_ERR_NO_TMP_DIR: + // TRANS: Client exception thrown when a temporary folder is not present to store a file upload. throw new ClientException(_('Missing a temporary folder.')); return; case UPLOAD_ERR_CANT_WRITE: + // TRANS: Client exception thrown when writing to disk is not possible during a file upload operation. throw new ClientException(_('Failed to write file to disk.')); return; case UPLOAD_ERR_EXTENSION: + // TRANS: Client exception thrown when a file upload operation has been stopped by an extension. throw new ClientException(_('File upload stopped by extension.')); return; default: common_log(LOG_ERR, __METHOD__ . ": Unknown upload error " . $_FILES[$param]['error']); + // TRANS: Client exception thrown when a file upload operation has failed with an unknown reason. throw new ClientException(_('System error uploading file.')); return; } @@ -176,6 +185,7 @@ class MediaFile // Should never actually get here @unlink($_FILES[$param]['tmp_name']); + // TRANS: Client exception thrown when a file upload operation would cause a user to exceed a set quota. throw new ClientException(_('File exceeds user\'s quota.')); return; } @@ -194,11 +204,15 @@ class MediaFile $result = move_uploaded_file($_FILES[$param]['tmp_name'], $filepath); if (!$result) { + // TRANS: Client exception thrown when a file upload operation fails because the file could + // TRANS: not be moved from the temporary folder to the permanent file location. throw new ClientException(_('File could not be moved to destination directory.')); return; } } else { + // TRANS: Client exception thrown when a file upload operation has been stopped because the MIME + // TRANS: type of the uploaded file could not be determined. throw new ClientException(_('Could not determine file\'s MIME type.')); return; } @@ -214,6 +228,7 @@ class MediaFile // Should never actually get here + // TRANS: Client exception thrown when a file upload operation would cause a user to exceed a set quota. throw new ClientException(_('File exceeds user\'s quota.')); return; } @@ -231,10 +246,14 @@ class MediaFile $result = copy($stream['uri'], $filepath) && chmod($filepath, 0664); if (!$result) { + // TRANS: Client exception thrown when a file upload operation fails because the file could + // TRANS: not be moved from the temporary folder to the permanent file location. throw new ClientException(_('File could not be moved to destination directory.' . $stream['uri'] . ' ' . $filepath)); } } else { + // TRANS: Client exception thrown when a file upload operation has been stopped because the MIME + // TRANS: type of the uploaded file could not be determined. throw new ClientException(_('Could not determine file\'s MIME type.')); return; } @@ -315,12 +334,17 @@ class MediaFile } $media = MIME_Type::getMedia($filetype); if ('application' !== $media) { - $hint = sprintf(_(' Try using another %s format.'), $media); + // TRANS: Client exception thrown trying to upload a forbidden MIME type. + // TRANS: %1$s is the file type that was denied, %2$s is the application part of + // TRANS: the MIME type that was denied. + $hint = sprintf(_('"%1$s" is not a supported file type on this server. ' . + 'Try using another %2$s format.'), $filetype, $media); } else { - $hint = ''; + // TRANS: Client exception thrown trying to upload a forbidden MIME type. + // TRANS: %s is the file type that was denied. + $hint = sprintf(_('"%s" is not a supported file type on this server.'), $filetype); } - throw new ClientException(sprintf( - _('%s is not a supported file type on this server.'), $filetype) . $hint); + throw new ClientException($hint); } static function respectsQuota($user, $filesize) diff --git a/lib/noticeform.php b/lib/noticeform.php index 84c20a5b3..514066356 100644 --- a/lib/noticeform.php +++ b/lib/noticeform.php @@ -169,7 +169,8 @@ class NoticeForm extends Form function formData() { if (Event::handle('StartShowNoticeFormData', array($this))) { - $this->out->element('label', array('for' => 'notice_data-text'), + $this->out->element('label', array('for' => 'notice_data-text', + 'id' => 'notice_data-text-label'), sprintf(_('What\'s up, %s?'), $this->user->nickname)); // XXX: vary by defined max size $this->out->element('textarea', array('id' => 'notice_data-text', diff --git a/lib/noticelist.php b/lib/noticelist.php index 529d6a3f9..df1533980 100644 --- a/lib/noticelist.php +++ b/lib/noticelist.php @@ -226,24 +226,31 @@ class NoticeListItem extends Widget function showNoticeInfo() { $this->out->elementStart('div', 'entry-content'); - $this->showNoticeLink(); - $this->showNoticeSource(); - $this->showNoticeLocation(); - $this->showContext(); - $this->showRepeat(); + if (Event::handle('StartShowNoticeInfo', array($this))) { + $this->showNoticeLink(); + $this->showNoticeSource(); + $this->showNoticeLocation(); + $this->showContext(); + $this->showRepeat(); + Event::handle('EndShowNoticeInfo', array($this)); + } + $this->out->elementEnd('div'); } function showNoticeOptions() { - $user = common_current_user(); - if ($user) { - $this->out->elementStart('div', 'notice-options'); - $this->showFaveForm(); - $this->showReplyLink(); - $this->showRepeatForm(); - $this->showDeleteLink(); - $this->out->elementEnd('div'); + if (Event::handle('StartShowNoticeOptions', array($this))) { + $user = common_current_user(); + if ($user) { + $this->out->elementStart('div', 'notice-options'); + $this->showFaveForm(); + $this->showReplyLink(); + $this->showRepeatForm(); + $this->showDeleteLink(); + $this->out->elementEnd('div'); + } + Event::handle('EndShowNoticeOptions', array($this)); } } @@ -270,15 +277,18 @@ class NoticeListItem extends Widget function showFaveForm() { - $user = common_current_user(); - if ($user) { - if ($user->hasFave($this->notice)) { - $disfavor = new DisfavorForm($this->out, $this->notice); - $disfavor->show(); - } else { - $favor = new FavorForm($this->out, $this->notice); - $favor->show(); + if (Event::handle('StartShowFaveForm', array($this))) { + $user = common_current_user(); + if ($user) { + if ($user->hasFave($this->notice)) { + $disfavor = new DisfavorForm($this->out, $this->notice); + $disfavor->show(); + } else { + $favor = new FavorForm($this->out, $this->notice); + $favor->show(); + } } + Event::handle('EndShowFaveForm', array($this)); } } diff --git a/lib/oauthstore.php b/lib/oauthstore.php index a6a6de750..f3ee629fd 100644 --- a/lib/oauthstore.php +++ b/lib/oauthstore.php @@ -280,7 +280,7 @@ class StatusNetOAuthDataStore extends OAuthDataStore $profile->created = DB_DataObject_Cast::dateTime(); # current time $id = $profile->insert(); if (!$id) { - throw new Exception(_('Error inserting new profile')); + throw new Exception(_('Error inserting new profile.')); } $remote->id = $id; } @@ -288,7 +288,7 @@ class StatusNetOAuthDataStore extends OAuthDataStore $avatar_url = $omb_profile->getAvatarURL(); if ($avatar_url) { if (!$this->add_avatar($profile, $avatar_url)) { - throw new Exception(_('Error inserting avatar')); + throw new Exception(_('Error inserting avatar.')); } } else { $avatar = $profile->getOriginalAvatar(); @@ -303,12 +303,12 @@ class StatusNetOAuthDataStore extends OAuthDataStore if ($exists) { if (!$remote->update($orig_remote)) { - throw new Exception(_('Error updating remote profile')); + throw new Exception(_('Error updating remote profile.')); } } else { $remote->created = DB_DataObject_Cast::dateTime(); # current time if (!$remote->insert()) { - throw new Exception(_('Error inserting remote profile')); + throw new Exception(_('Error inserting remote profile.')); } } } @@ -342,7 +342,8 @@ class StatusNetOAuthDataStore extends OAuthDataStore **/ public function saveNotice(&$omb_notice) { if (Notice::staticGet('uri', $omb_notice->getIdentifierURI())) { - throw new Exception(_('Duplicate notice')); + // TRANS: Exception thrown when a notice is denied because it has been sent before. + throw new Exception(_('Duplicate notice.')); } $author_uri = $omb_notice->getAuthor()->getIdentifierURI(); common_log(LOG_DEBUG, $author_uri, __FILE__); diff --git a/lib/plugin.php b/lib/plugin.php index f63bdf309..3f84afa27 100644 --- a/lib/plugin.php +++ b/lib/plugin.php @@ -88,7 +88,12 @@ class Plugin $class = get_class($this); if (substr($class, -6) == 'Plugin') { $name = substr($class, 0, -6); - $path = INSTALLDIR . "/plugins/$name/locale"; + $path = common_config('plugins', 'locale_path'); + if (!$path) { + // @fixme this will fail for things installed in local/plugins + // ... but then so will web links so far. + $path = INSTALLDIR . "/plugins/$name/locale"; + } if (file_exists($path) && is_dir($path)) { bindtextdomain($name, $path); bind_textdomain_codeset($name, 'UTF-8'); @@ -112,9 +117,9 @@ class Plugin $name = mb_substr($cls, 0, -6); $versions[] = array('name' => $name, + // TRANS: Displayed as version information for a plugin if no version information was found. 'version' => _('Unknown')); return true; } } - diff --git a/lib/router.php b/lib/router.php index ca3c2e880..3bbb4a044 100644 --- a/lib/router.php +++ b/lib/router.php @@ -151,6 +151,8 @@ class Router $m->connect('main/xrds', array('action' => 'publicxrds')); + $m->connect('.well-known/host-meta', + array('action' => 'hostmeta')); // these take a code @@ -488,19 +490,19 @@ class Router // Social graph $m->connect('api/friends/ids/:id.:format', - array('action' => 'apiuserfriends', + array('action' => 'ApiUserFriends', 'ids_only' => true)); $m->connect('api/followers/ids/:id.:format', - array('action' => 'apiuserfollowers', + array('action' => 'ApiUserFollowers', 'ids_only' => true)); $m->connect('api/friends/ids.:format', - array('action' => 'apiuserfriends', + array('action' => 'ApiUserFriends', 'ids_only' => true)); $m->connect('api/followers/ids.:format', - array('action' => 'apiuserfollowers', + array('action' => 'ApiUserFollowers', 'ids_only' => true)); // account @@ -678,13 +680,13 @@ class Router $m->connect('api/trends.json', array('action' => 'ApiTrends')); $m->connect('api/oauth/request_token', - array('action' => 'apioauthrequesttoken')); + array('action' => 'ApiOauthRequestToken')); $m->connect('api/oauth/access_token', - array('action' => 'apioauthaccesstoken')); + array('action' => 'ApiOauthAccessToken')); $m->connect('api/oauth/authorize', - array('action' => 'apioauthauthorize')); + array('action' => 'ApiOauthAuthorize')); // Admin @@ -696,6 +698,7 @@ class Router $m->connect('admin/sessions', array('action' => 'sessionsadminpanel')); $m->connect('admin/sitenotice', array('action' => 'sitenoticeadminpanel')); $m->connect('admin/snapshot', array('action' => 'snapshotadminpanel')); + $m->connect('admin/license', array('action' => 'licenseadminpanel')); $m->connect('admin/plugins', array('action' => 'pluginsadminpanel')); $m->connect('admin/plugins/enable/:plugin', array('action' => 'pluginenable'), diff --git a/lib/searchaction.php b/lib/searchaction.php index bb71a2ba1..14c3ed016 100644 --- a/lib/searchaction.php +++ b/lib/searchaction.php @@ -117,14 +117,17 @@ class SearchAction extends Action 'class' => 'form_settings', 'action' => common_local_url($this->trimmed('action')))); $this->elementStart('fieldset'); + // TRANS: Fieldset legend for the search form. $this->element('legend', null, _('Search site')); $this->elementStart('ul', 'form_data'); $this->elementStart('li'); if (!common_config('site', 'fancy')) { $this->hidden('action', $this->trimmed('action')); } + // TRANS: Used as a field label for the field where one or more keywords + // TRANS: for searching can be entered. $this->input('q', _('Keyword(s)'), $q); - $this->submit('search', _('Search')); + $this->submit('search', _m('BUTTON','Search')); $this->elementEnd('li'); $this->elementEnd('ul'); $this->elementEnd('fieldset'); @@ -135,6 +138,8 @@ class SearchAction extends Action } function searchSuggestions($q) { + // @todo FIXME: This formatting does not make this string get picked up by gettext. + // TRANS: Standard search suggestions shown when a search does not give any results. $message = _(<<<E_O_T * Make sure all words are spelled correctly. * Try different keywords. @@ -145,6 +150,8 @@ E_O_T ); if (!common_config('site', 'private')) { $qe = urlencode($q); + // @todo FIXME: This formatting does not make this string get picked up by gettext. + // TRANS: Standard search suggestions shown when a search does not give any results. $message .= sprintf(_(<<<E_O_T You can also try your search on other engines: @@ -159,6 +166,7 @@ E_O_T ), $qe, $qe, $qe, $qe, $qe); } $this->elementStart('dl', array('id' => 'help_search', 'class' => 'help')); + // TRANS: Definition list item with instructions on how to get (better) search results. $this->element('dt', null, _('Search help')); $this->elementStart('dd', 'instructions'); $this->raw(common_markup_to_html($message)); @@ -166,4 +174,3 @@ E_O_T $this->elementEnd('div'); } } - diff --git a/lib/spawningdaemon.php b/lib/spawningdaemon.php index 2f9f6e32e..ea09b6fb2 100644 --- a/lib/spawningdaemon.php +++ b/lib/spawningdaemon.php @@ -204,7 +204,7 @@ abstract class SpawningDaemon extends Daemon // Reconnect main memcached, or threads will stomp on // each other and corrupt their requests. - $cache = common_memcache(); + $cache = Cache::instance(); if ($cache) { $cache->reconnect(); } diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php index fc98c77d4..1d9a5ad20 100644 --- a/lib/stompqueuemanager.php +++ b/lib/stompqueuemanager.php @@ -578,7 +578,7 @@ class StompQueueManager extends QueueManager function incDeliveryCount($msgId) { $count = 0; - $cache = common_memcache(); + $cache = Cache::instance(); if ($cache) { $key = 'statusnet:stomp:message-retries:' . $msgId; $count = $cache->increment($key); diff --git a/lib/theme.php b/lib/theme.php index a9d0cbc84..992fce870 100644 --- a/lib/theme.php +++ b/lib/theme.php @@ -54,6 +54,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { class Theme { + var $name = null; var $dir = null; var $path = null; @@ -70,6 +71,10 @@ class Theme if (empty($name)) { $name = common_config('site', 'theme'); } + if (!self::validName($name)) { + throw new ServerException("Invalid theme name."); + } + $this->name = $name; // Check to see if it's in the local dir @@ -178,6 +183,58 @@ class Theme } /** + * Fetch a list of other themes whose CSS needs to be pulled in before + * this theme's, based on following the theme.ini 'include' settings. + * (May be empty if this theme has no include dependencies.) + * + * @return array of strings with theme names + */ + function getDeps() + { + $chain = $this->doGetDeps(array($this->name)); + array_pop($chain); // Drop us back off + return $chain; + } + + protected function doGetDeps($chain) + { + $data = $this->getMetadata(); + if (!empty($data['include'])) { + $include = $data['include']; + + // Protect against cycles! + if (!in_array($include, $chain)) { + try { + $theme = new Theme($include); + array_unshift($chain, $include); + return $theme->doGetDeps($chain); + } catch (Exception $e) { + common_log(LOG_ERR, + "Exception while fetching theme dependencies " . + "for $this->name: " . $e->getMessage()); + } + } + } + return $chain; + } + + /** + * Pull data from the theme's theme.ini file. + * @fixme calling getFile will fall back to default theme, this may be unsafe. + * + * @return associative array of strings + */ + function getMetadata() + { + $iniFile = $this->getFile('theme.ini'); + if (file_exists($iniFile)) { + return parse_ini_file($iniFile); + } else { + return array(); + } + } + + /** * Gets the full path of a file in a theme dir based on its relative name * * @param string $relative relative path within the theme directory @@ -285,4 +342,9 @@ class Theme return $instroot; } + + static function validName($name) + { + return preg_match('/^[a-z0-9][a-z0-9_-]*$/i', $name); + } } diff --git a/lib/themeuploader.php b/lib/themeuploader.php index 370965db0..5a48e884e 100644 --- a/lib/themeuploader.php +++ b/lib/themeuploader.php @@ -128,8 +128,16 @@ class ThemeUploader continue; } - // Check the directory structure... + // Is this a safe or skippable file? $path = pathinfo($name); + if ($this->skippable($path['filename'], $path['extension'])) { + // Documentation and such... booooring + continue; + } else { + $this->validateFile($path['filename'], $path['extension']); + } + + // Check the directory structure... $dirs = explode('/', $path['dirname']); $baseDir = array_shift($dirs); if ($commonBaseDir === false) { @@ -144,14 +152,6 @@ class ThemeUploader $this->validateFileOrFolder($dir); } - // Is this a safe or skippable file? - if ($this->skippable($path['filename'], $path['extension'])) { - // Documentation and such... booooring - continue; - } else { - $this->validateFile($path['filename'], $path['extension']); - } - $fullPath = $dirs; $fullPath[] = $path['basename']; $localFile = implode('/', $fullPath); @@ -180,39 +180,64 @@ class ThemeUploader } } + /** + * @fixme Probably most unrecognized files should just be skipped... + */ protected function skippable($filename, $ext) { - $skip = array('txt', 'rtf', 'doc', 'docx', 'odt'); + $skip = array('txt', 'html', 'rtf', 'doc', 'docx', 'odt', 'xcf'); if (strtolower($filename) == 'readme') { return true; } if (in_array(strtolower($ext), $skip)) { return true; } + if ($filename == '' || substr($filename, 0, 1) == '.') { + // Skip Unix-style hidden files + return true; + } + if ($filename == '__MACOSX') { + // Skip awful metadata files Mac OS X slips in for you. + // Thanks Apple! + return true; + } return false; } protected function validateFile($filename, $ext) { $this->validateFileOrFolder($filename); - $this->validateExtension($ext); + $this->validateExtension($filename, $ext); // @fixme validate content } protected function validateFileOrFolder($name) { - if (!preg_match('/^[a-z0-9_-]+$/i', $name)) { + if (!preg_match('/^[a-z0-9_\.-]+$/i', $name)) { + common_log(LOG_ERR, "Bad theme filename: $name"); $msg = _("Theme contains invalid file or folder name. " . "Stick with ASCII letters, digits, underscore, and minus sign."); throw new ClientException($msg); } + if (preg_match('/\.(php|cgi|asp|aspx|js|vb)\w/i', $name)) { + common_log(LOG_ERR, "Unsafe theme filename: $name"); + $msg = _("Theme contains unsafe file extension names; may be unsafe."); + throw new ClientException($msg); + } return true; } - protected function validateExtension($ext) + protected function validateExtension($base, $ext) { - $allowed = array('css', 'png', 'gif', 'jpg', 'jpeg'); + $allowed = array('css', // CSS may need validation + 'png', 'gif', 'jpg', 'jpeg', + 'svg', // SVG images/fonts may need validation + 'ttf', 'eot', 'woff'); if (!in_array(strtolower($ext), $allowed)) { + if ($ext == 'ini' && $base == 'theme') { + // theme.ini exception + return true; + } $msg = sprintf(_("Theme contains file of type '.%s', " . "which is not allowed."), $ext); diff --git a/lib/unblockform.php b/lib/unblockform.php index 2a444f7cd..b89d7ff78 100644 --- a/lib/unblockform.php +++ b/lib/unblockform.php @@ -66,6 +66,7 @@ class UnblockForm extends ProfileActionForm function title() { + // TRANS: Title for the form to unblock a user. return _('Unblock'); } @@ -77,6 +78,7 @@ class UnblockForm extends ProfileActionForm function description() { + // TRANS: Description of the form to unblock a user. return _('Unblock this user'); } } diff --git a/lib/useractivitystream.php b/lib/useractivitystream.php new file mode 100644 index 000000000..0fc315e26 --- /dev/null +++ b/lib/useractivitystream.php @@ -0,0 +1,151 @@ +<?php +/* + * StatusNet - the distributed open-source microblogging tool + * Copyright (C) 2010 StatusNet, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * Class for activity streams + * + * Includes faves, notices, and subscriptions. + * + * We extend atomusernoticefeed since it does some nice setup for us. + * + */ + +class UserActivityStream extends AtomUserNoticeFeed +{ + function __construct($user, $indent = true) + { + parent::__construct($user, null, $indent); + + $subscriptions = $this->getSubscriptions(); + $subscribers = $this->getSubscribers(); + $groups = $this->getGroups(); + $faves = $this->getFaves(); + $notices = $this->getNotices(); + + $objs = array_merge($subscriptions, $subscribers, $groups, $faves, $notices); + + // Sort by create date + + usort($objs, 'UserActivityStream::compareObject'); + + foreach ($objs as $obj) { + $act = $obj->asActivity(); + // Only show the author sub-element if it's different from default user + $str = $act->asString(false, ($act->actor->id != $this->user->uri)); + $this->addEntryRaw($str); + } + } + + function compareObject($a, $b) + { + $ac = strtotime((empty($a->created)) ? $a->modified : $a->created); + $bc = strtotime((empty($b->created)) ? $b->modified : $b->created); + + return (($ac == $bc) ? 0 : (($ac < $bc) ? 1 : -1)); + } + + function getSubscriptions() + { + $subs = array(); + + $sub = new Subscription(); + + $sub->subscriber = $this->user->id; + + if ($sub->find()) { + while ($sub->fetch()) { + if ($sub->subscribed != $this->user->id) { + $subs[] = clone($sub); + } + } + } + + return $subs; + } + + function getSubscribers() + { + $subs = array(); + + $sub = new Subscription(); + + $sub->subscribed = $this->user->id; + + if ($sub->find()) { + while ($sub->fetch()) { + if ($sub->subscriber != $this->user->id) { + $subs[] = clone($sub); + } + } + } + + return $subs; + } + + function getFaves() + { + $faves = array(); + + $fave = new Fave(); + + $fave->user_id = $this->user->id; + + if ($fave->find()) { + while ($fave->fetch()) { + $faves[] = clone($fave); + } + } + + return $faves; + } + + function getNotices() + { + $notices = array(); + + $notice = new Notice(); + + $notice->profile_id = $this->user->id; + + if ($notice->find()) { + while ($notice->fetch()) { + $notices[] = clone($notice); + } + } + + return $notices; + } + + function getGroups() + { + $groups = array(); + + $gm = new Group_member(); + + $gm->profile_id = $this->user->id; + + if ($gm->find()) { + while ($gm->fetch()) { + $groups[] = clone($gm); + } + } + + return $groups; + } +} diff --git a/lib/usernoprofileexception.php b/lib/usernoprofileexception.php index 6744d2529..954d31b0d 100644 --- a/lib/usernoprofileexception.php +++ b/lib/usernoprofileexception.php @@ -55,7 +55,9 @@ class UserNoProfileException extends ServerException { $this->user = $user; - $message = sprintf(_("User %s (%d) has no profile record."), + // TRANS: Exception text shown when no profile can be found for a user. + // TRANS: %1$s is a user nickname, $2$d is a user ID (number). + $message = sprintf(_('User %1$s (%2$d) has no profile record.'), $user->nickname, $user->id); parent::__construct($message); diff --git a/lib/util.php b/lib/util.php index 8eff4e568..df339d4b1 100644 --- a/lib/util.php +++ b/lib/util.php @@ -19,15 +19,18 @@ /* XXX: break up into separate modules (HTTP, user, files) */ -// Show a server error - +/** + * Show a server error. + */ function common_server_error($msg, $code=500) { $err = new ServerErrorAction($msg, $code); $err->showPage(); } -// Show a user error +/** + * Show a user error. + */ function common_user_error($msg, $code=400) { $err = new ClientErrorAction($msg, $code); @@ -37,7 +40,7 @@ function common_user_error($msg, $code=400) /** * This should only be used at setup; processes switching languages * to send text to other users should use common_switch_locale(). - * + * * @param string $language Locale language code (optional; empty uses * current user's preference or site default) * @return mixed success @@ -61,10 +64,10 @@ function common_init_locale($language=null) /** * Initialize locale and charset settings and gettext with our message catalog, * using the current user's language preference or the site default. - * + * * This should generally only be run at framework initialization; code switching * languages at runtime should call common_switch_language(). - * + * * @access private */ function common_init_language() @@ -142,7 +145,6 @@ function common_switch_locale($language=null) textdomain("statusnet"); } - function common_timezone() { if (common_logged_in()) { @@ -204,8 +206,10 @@ function common_language() // Finally, if none of the above worked, use the site's default... return common_config('site', 'language'); } -// salted, hashed passwords are stored in the DB +/** + * Salted, hashed passwords are stored in the DB. + */ function common_munge_password($password, $id) { if (is_object($id) || is_object($password)) { @@ -216,8 +220,9 @@ function common_munge_password($password, $id) return md5($password . $id); } -// check if a username exists and has matching password - +/** + * Check if a username exists and has matching password. + */ function common_check_user($nickname, $password) { // empty nickname always unacceptable @@ -244,7 +249,9 @@ function common_check_user($nickname, $password) return $authenticatedUser; } -// is the current user logged in? +/** + * Is the current user logged in? + */ function common_logged_in() { return (!is_null(common_current_user())); @@ -290,12 +297,10 @@ function common_ensure_session() // 3) null to clear // Initialize to false; set to null if none found - $_cur = false; function common_set_user($user) { - global $_cur; if (is_null($user) && common_have_session()) { @@ -381,7 +386,6 @@ function common_rememberme($user=null) function common_remembered_user() { - $user = null; $packed = isset($_COOKIE[REMEMBERME]) ? $_COOKIE[REMEMBERME] : null; @@ -443,14 +447,17 @@ function common_remembered_user() return $user; } -// must be called with a valid user! - +/** + * must be called with a valid user! + */ function common_forgetme() { common_set_cookie(REMEMBERME, '', 0); } -// who is the current user? +/** + * Who is the current user? + */ function common_current_user() { global $_cur; @@ -486,10 +493,11 @@ function common_current_user() return $_cur; } -// Logins that are 'remembered' aren't 'real' -- they're subject to -// cookie-stealing. So, we don't let them do certain things. New reg, -// OpenID, and password logins _are_ real. - +/** + * Logins that are 'remembered' aren't 'real' -- they're subject to + * cookie-stealing. So, we don't let them do certain things. New reg, + * OpenID, and password logins _are_ real. + */ function common_real_login($real=true) { common_ensure_session(); @@ -501,6 +509,29 @@ function common_is_real_login() return common_logged_in() && $_SESSION['real_login']; } +/** + * Get a hash portion for HTTP caching Etags and such including + * info on the current user's session. If login/logout state changes, + * or we've changed accounts, or we've renamed the current user, + * we'll get a new hash value. + * + * This should not be considered secure information. + * + * @param User $user (optional; uses common_current_user() if left out) + * @return string + */ +function common_user_cache_hash($user=false) +{ + if ($user === false) { + $user = common_current_user(); + } + if ($user) { + return crc32($user->id . ':' . $user->nickname); + } else { + return '0'; + } +} + // get canonical version of nickname for comparison function common_canonical_nickname($nickname) { @@ -592,9 +623,7 @@ function common_find_mentions($text, $notice) } if (Event::handle('StartFindMentions', array($sender, $text, &$mentions))) { - // Get the context of the original notice, if any - $originalAuthor = null; $originalNotice = null; $originalMentions = array(); @@ -630,7 +659,6 @@ function common_find_mentions($text, $notice) $matches = array_merge($tmatches[1], $atmatches[1]); foreach ($matches as $match) { - $nickname = common_canonical_nickname($match[0]); // Try to get a profile for this nickname. @@ -638,19 +666,15 @@ function common_find_mentions($text, $notice) // sender context. if (!empty($originalAuthor) && $originalAuthor->nickname == $nickname) { - $mentioned = $originalAuthor; - } else if (!empty($originalMentions) && array_key_exists($nickname, $originalMentions)) { - $mentioned = $originalMentions[$nickname]; } else { $mentioned = common_relative_profile($sender, $nickname); } if (!empty($mentioned)) { - $user = User::staticGet('id', $mentioned->id); if ($user) { @@ -845,7 +869,10 @@ function common_linkify($url) { } elseif (is_string($longurl_data)) { $longurl = $longurl_data; } else { - throw new ServerException("Can't linkify url '$url'"); + // Unable to reach the server to verify contents, etc + // Just pass the link on through for now. + common_log(LOG_ERR, "Can't linkify url '$url'"); + $longurl = $url; } } $attrs = array('href' => $canon, 'title' => $longurl, 'rel' => 'external'); @@ -906,6 +933,28 @@ function common_shorten_links($text, $always = false) } } +/** + * Very basic stripping of invalid UTF-8 input text. + * + * @param string $str + * @return mixed string or null if invalid input + * + * @todo ideally we should drop bad chars, and maybe do some of the checks + * from common_xml_safe_str. But we can't strip newlines, etc. + * @todo Unicode normalization might also be useful, but not needed now. + */ +function common_validate_utf8($str) +{ + // preg_replace will return NULL on invalid UTF-8 input. + return preg_replace('//u', '', $str); +} + +/** + * Make sure an arbitrary string is safe for output in XML as a single line. + * + * @param string $str + * @return string + */ function common_xml_safe_str($str) { // Replace common eol and extra whitespace input chars @@ -1042,8 +1091,7 @@ function common_local_url($action, $args=null, $params=null, $fragment=null, $ad function common_is_sensitive($action) { - static $sensitive = array('login', 'register', 'passwordsettings', - 'twittersettings', 'api'); + static $sensitive = array('login', 'register', 'passwordsettings', 'api'); $ssl = null; if (Event::handle('SensitiveAction', array($action, &$ssl))) { @@ -1129,30 +1177,30 @@ function common_date_string($dt) // TRANS: Used in notices to indicate when the notice was made compared to now. return _('about a minute ago'); } else if ($diff < 3300) { - // XXX: should support plural. + $minutes = round($diff/60); // TRANS: Used in notices to indicate when the notice was made compared to now. - return sprintf(_('about %d minutes ago'), round($diff/60)); + return sprintf( ngettext('about one minute ago', 'about %d minutes ago', $minutes), $minutes); } else if ($diff < 5400) { // TRANS: Used in notices to indicate when the notice was made compared to now. return _('about an hour ago'); } else if ($diff < 22 * 3600) { - // XXX: should support plural. + $hours = round($diff/3600); // TRANS: Used in notices to indicate when the notice was made compared to now. - return sprintf(_('about %d hours ago'), round($diff/3600)); + return sprintf( ngettext('about one hour ago', 'about %d hours ago', $hours), $hours); } else if ($diff < 37 * 3600) { // TRANS: Used in notices to indicate when the notice was made compared to now. return _('about a day ago'); } else if ($diff < 24 * 24 * 3600) { - // XXX: should support plural. + $days = round($diff/(24*3600)); // TRANS: Used in notices to indicate when the notice was made compared to now. - return sprintf(_('about %d days ago'), round($diff/(24*3600))); + return sprintf( ngettext('about one day ago', 'about %d days ago', $days), $days); } else if ($diff < 46 * 24 * 3600) { // TRANS: Used in notices to indicate when the notice was made compared to now. return _('about a month ago'); } else if ($diff < 330 * 24 * 3600) { - // XXX: should support plural. + $months = round($diff/(30*24*3600)); // TRANS: Used in notices to indicate when the notice was made compared to now. - return sprintf(_('about %d months ago'), round($diff/(30*24*3600))); + return sprintf( ngettext('about one month ago', 'about %d months ago',$months), $months); } else if ($diff < 480 * 24 * 3600) { // TRANS: Used in notices to indicate when the notice was made compared to now. return _('about a year ago'); @@ -1250,11 +1298,6 @@ function common_redirect($url, $code=307) exit; } -function common_broadcast_notice($notice, $remote=false) -{ - // DO NOTHING! -} - // Stick the notice on the queue function common_enqueue_notice($notice) @@ -1309,8 +1352,9 @@ function common_profile_url($nickname) null, null, false); } -// Should make up a reasonable root URL - +/** + * Should make up a reasonable root URL + */ function common_root_url($ssl=false) { $url = common_path('', $ssl, false); @@ -1321,9 +1365,10 @@ function common_root_url($ssl=false) return $url; } -// returns $bytes bytes of random data as a hexadecimal string -// "good" here is a goal and not a guarantee - +/** + * returns $bytes bytes of random data as a hexadecimal string + * "good" here is a goal and not a guarantee + */ function common_good_rand($bytes) { // XXX: use random.org...? @@ -1359,13 +1404,13 @@ function common_mtrand($bytes) /** * Record the given URL as the return destination for a future * form submission, to be read by common_get_returnto(). - * + * * @param string $url - * + * * @fixme as a session-global setting, this can allow multiple forms * to conflict and overwrite each others' returnto destinations if * the user has multiple tabs or windows open. - * + * * Should refactor to index with a token or otherwise only pass the * data along its intended path. */ @@ -1378,13 +1423,13 @@ function common_set_returnto($url) /** * Fetch a return-destination URL previously recorded by * common_set_returnto(). - * + * * @return mixed URL string or null - * + * * @fixme as a session-global setting, this can allow multiple forms * to conflict and overwrite each others' returnto destinations if * the user has multiple tabs or windows open. - * + * * Should refactor to index with a token or otherwise only pass the * data along its intended path. */ @@ -1469,7 +1514,12 @@ function common_log_db_error(&$object, $verb, $filename=null) { $objstr = common_log_objstring($object); $last_error = &PEAR::getStaticProperty('DB_DataObject','lastError'); - common_log(LOG_ERR, $last_error->message . '(' . $verb . ' on ' . $objstr . ')', $filename); + if (is_object($last_error)) { + $msg = $last_error->message; + } else { + $msg = 'Unknown error (' . var_export($last_error, true) . ')'; + } + common_log(LOG_ERR, $msg . '(' . $verb . ' on ' . $objstr . ')', $filename); } function common_log_objstring(&$object) @@ -1647,19 +1697,25 @@ function common_config($main, $sub) array_key_exists($sub, $config[$main])) ? $config[$main][$sub] : false; } +/** + * Pull arguments from a GET/POST/REQUEST array with first-level input checks: + * strips "magic quotes" slashes if necessary, and kills invalid UTF-8 strings. + * + * @param array $from + * @return array + */ function common_copy_args($from) { $to = array(); $strip = get_magic_quotes_gpc(); foreach ($from as $k => $v) { - if($strip) { - if(is_array($v)) { - $to[$k] = common_copy_args($v); - } else { - $to[$k] = stripslashes($v); - } + if(is_array($v)) { + $to[$k] = common_copy_args($v); } else { - $to[$k] = $v; + if ($strip) { + $v = stripslashes($v); + } + $to[$k] = strval(common_validate_utf8($v)); } } return $to; @@ -1797,21 +1853,6 @@ function common_session_token() return $_SESSION['token']; } -function common_cache_key($extra) -{ - return Cache::key($extra); -} - -function common_keyize($str) -{ - return Cache::keyize($str); -} - -function common_memcache() -{ - return Cache::instance(); -} - function common_license_terms($uri) { if(preg_match('/creativecommons.org\/licenses\/([^\/]+)/', $uri, $matches)) { @@ -1842,7 +1883,6 @@ function common_compatible_license($from, $to) */ function common_database_tablename($tablename) { - if(common_config('db','quote_identifiers')) { $tablename = '"'. $tablename .'"'; } diff --git a/lib/xrd.php b/lib/xrd.php new file mode 100644 index 000000000..c8cffed9c --- /dev/null +++ b/lib/xrd.php @@ -0,0 +1,172 @@ +<?php +/** + * StatusNet - the distributed open-source microblogging tool + * Copyright (C) 2010, StatusNet, Inc. + * + * A sample module to show best practices for StatusNet plugins + * + * PHP version 5 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @package StatusNet + * @author James Walker <james@status.net> + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ + +class XRD +{ + const XML_NS = 'http://www.w3.org/2000/xmlns/'; + + const XRD_NS = 'http://docs.oasis-open.org/ns/xri/xrd-1.0'; + + const HOST_META_NS = 'http://host-meta.net/xrd/1.0'; + + public $expires; + + public $subject; + + public $host; + + public $alias = array(); + + public $types = array(); + + public $links = array(); + + public static function parse($xml) + { + $xrd = new XRD(); + + $dom = new DOMDocument(); + + // Don't spew XML warnings to output + $old = error_reporting(); + error_reporting($old & ~E_WARNING); + $ok = $dom->loadXML($xml); + error_reporting($old); + + if (!$ok) { + // TRANS: Exception. + throw new Exception(_m('Invalid XML.')); + } + $xrd_element = $dom->getElementsByTagName('XRD')->item(0); + if (!$xrd_element) { + // TRANS: Exception. + throw new Exception(_m('Invalid XML, missing XRD root.')); + } + + // Check for host-meta host + $host = $xrd_element->getElementsByTagName('Host')->item(0); + if ($host) { + $xrd->host = $host->nodeValue; + } + + // Loop through other elements + foreach ($xrd_element->childNodes as $node) { + if (!($node instanceof DOMElement)) { + continue; + } + switch ($node->tagName) { + case 'Expires': + $xrd->expires = $node->nodeValue; + break; + case 'Subject': + $xrd->subject = $node->nodeValue; + break; + + case 'Alias': + $xrd->alias[] = $node->nodeValue; + break; + + case 'Link': + $xrd->links[] = $xrd->parseLink($node); + break; + + case 'Type': + $xrd->types[] = $xrd->parseType($node); + break; + + } + } + return $xrd; + } + + public function toXML() + { + $xs = new XMLStringer(); + + $xs->startXML(); + $xs->elementStart('XRD', array('xmlns' => XRD::XRD_NS)); + + if ($this->host) { + $xs->element('hm:Host', array('xmlns:hm' => XRD::HOST_META_NS), $this->host); + } + + if ($this->expires) { + $xs->element('Expires', null, $this->expires); + } + + if ($this->subject) { + $xs->element('Subject', null, $this->subject); + } + + foreach ($this->alias as $alias) { + $xs->element('Alias', null, $alias); + } + + foreach ($this->links as $link) { + $titles = array(); + if (isset($link['title'])) { + $titles = $link['title']; + unset($link['title']); + } + $xs->elementStart('Link', $link); + foreach ($titles as $title) { + $xs->element('Title', null, $title); + } + $xs->elementEnd('Link'); + } + + $xs->elementEnd('XRD'); + + return $xs->getString(); + } + + function parseType($element) + { + return array(); + } + + function parseLink($element) + { + $link = array(); + $link['rel'] = $element->getAttribute('rel'); + $link['type'] = $element->getAttribute('type'); + $link['href'] = $element->getAttribute('href'); + $link['template'] = $element->getAttribute('template'); + foreach ($element->childNodes as $node) { + if ($node instanceof DOMElement) { + switch($node->tagName) { + case 'Title': + $link['title'][] = $node->nodeValue; + } + } + } + + return $link; + } +} |