diff --git a/.gitignore b/.gitignore index 1cde3a6254..217622c84d 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,4 @@ config-*.php good-config.php lac08.log php.log - +.DS_Store diff --git a/EVENTS.txt b/EVENTS.txt index 9de2f8bc6b..a8a77390f6 100644 --- a/EVENTS.txt +++ b/EVENTS.txt @@ -129,6 +129,9 @@ StartSubGroupNav: Showing the subscriptions group nav menu EndSubGroupNav: At the end of the subscriptions group nav menu - $action: the current action +StartInitializeRouter: Before the router instance has been initialized; good place to add routes +- $m: the Net_URL_Mapper that has just been set up + RouterInitialized: After the router instance has been initialized - $m: the Net_URL_Mapper that has just been set up @@ -390,3 +393,84 @@ EndProfilePageProfileTags: after showing the tags on the profile page - $action: the current action - &$profile: the profile being shown +StartProfileList: when starting a list of profiles (before ) +- $profilelist: ProfileList widget + +StartProfileListItem: when starting to show a profile list item +- $item: ProfileListItem widget + +EndProfileListItem: after showing a profile list item +- $item: ProfileListItem widget + +StartProfileListItemProfile: the profile data part of the item +- $item: ProfileListItem widget + +EndProfileListItemProfile: the profile data part of the item +- $item: ProfileListItem widget + +StartProfileListItemActions: the actions (buttons) for an item +- $item: ProfileListItem widget + +EndProfileListItemActions: the actions (buttons) for an item +- $item: ProfileListItem widget + +StartProfileListItemProfileElements: inside the
+- $item: ProfileListItem widget + +EndProfileListItemProfileElements: inside the
+- $item: ProfileListItem widget + +StartProfileListItemAvatar: Showing a profile list avatar +- $item: ProfileListItem widget + +EndProfileListItemAvatar: Showing a profile list avatar +- $item: ProfileListItem widget + +StartProfileListItemFullName: Showing the profile list full name +- $item: ProfileListItem widget + +EndProfileListItemFullName: Showing the profile list full name +- $item: ProfileListItem widget + +StartProfileListItemLocation: Showing the profile list location +- $item: ProfileListItem widget + +EndProfileListItemLocation: Showing the profile list location +- $item: ProfileListItem widget + +StartProfileListItemHomepage: Showing the profile list homepage +- $item: ProfileListItem widget + +EndProfileListItemHomepage: Showing the profile list homepage +- $item: ProfileListItem widget + +StartProfileListItemBio: Showing the profile list bio +- $item: ProfileListItem widget + +EndProfileListItemBio: Showing the profile list bio +- $item: ProfileListItem widget + +StartProfileListItemActionElements: Showing the profile list actions (prepend a button here, or replace all buttons) +- $item: ProfileListItem widget + +EndProfileListItemActionElements: Showing profile list actions (append a button here) +- $item: ProfileListItem widget + +StartUserXRDS: Start XRDS output (right after the opening XRDS tag) +- $action: the current action +- &$xrdsoutputter - XRDSOutputter object to write to + +EndUserXRDS: End XRDS output (right before the closing XRDS tag) +- $action: the current action +- &$xrdsoutputter - XRDSOutputter object to write to + +StartPublicXRDS: Start XRDS output (right after the opening XRDS tag) +- $action: the current action +- &$xrdsoutputter - XRDSOutputter object to write to + +EndPublicXRDS: End XRDS output (right before the closing XRDS tag) +- $action: the current action +- &$xrdsoutputter - XRDSOutputter object to write to diff --git a/README b/README index 037027d431..952c914fec 100644 --- a/README +++ b/README @@ -2,8 +2,8 @@ README ------ -StatusNet 0.8.1 ("Second Guessing") -26 Aug 2009 +StatusNet 0.8.2 ("Life and How to Live It") +1 Nov 2009 This is the README file for StatusNet (formerly Laconica), the Open Source microblogging platform. It includes installation instructions, @@ -77,49 +77,80 @@ for additional terms. New this version ================ -This is a minor feature and bugfix release since version 0.8.0, -released Jul 15 2009. Notable changes this version: +This is a minor feature and bugfix release since version 0.8.1, +released Aug 26 2009. Notable changes this version: -- Laconica has been renamed StatusNet. With a few minor compatibility - exceptions, all references to "Laconica" in code, documentation - and comments were changed to "StatusNet". -- A new plugin to support "infinite scroll". -- A new plugin to support reCaptcha . -- Better logging of server errors. -- Add an Openid-only mode for authentication. -- 'lite' parameter for some Twitter API methods. -- A new plugin to auto-complete nicknames for @-replies. -- Configuration options to disable OpenID, SMS, Twitter, post-by-email, and IM. -- Support for lighttpd using 404-based - rewrites. -- Support for using Twitter's OAuth authentication as a client. -- First version of the groups API. -- Can configure a site-wide design, including background image and - colors. -- Improved algorithm for replies and conversations, making - conversation trees more accurate and useful. -- Add a script to create a simulation database for testing/debugging. -- Sanitize HTML for OEmbed. -- Improved queue management for DB-based queuing. -- More complete URL detection. -- Hashtags now support full Unicode character set. -- Notice inboxes are now garbage-collected on a regular basis - at notice-write time. -- PiwikAnalyticsPlugin updated for latest Piwik interface. -- Attachment and notice pages can be embedded with OEmbed - . -- Failed authentication is logged. -- PostgreSQL schema and support brought up-to-date with 0.8.x features. -- The installer works with PostgreSQL as well as MySQL. -- RSS 1.0 feeds use HTTP Basic authentication in private mode. -- Many, many bug fixes, particularly with performance. -- Better (=working) garbage collection for old sessions. -- Better (=working) search queries. -- Some cleanup of HTML output. -- Better error handling when updating Facebook. -- Considerably better performance when using replication for API - calls. -- Initial unit tests. +- New script for deleting user accounts. Not particularly safe or + community-friendly. Better for deleting abusive accounts than for + users who are 'retiring'. +- Improved detection of URLs in notices, specifically for punctuation + chars like ~, :, $, _, -, +, !, @, and %. +- Removed some extra
semantic HTML code. +- Correct error in status-network database ini file (having multiple + statusnet sites with a single codebase) +- Fixed error output for Twitter posting failures. +- Fixed bug in Twitter queue handler that requeued inapplicable + notices ad infinitum. +- Improve FOAF output for remote users. +- new commands to join and leave groups. +- Fixed bug in which you cannot turn off importing friends timelines + flag. +- Better error handling in Twitter posting. +- Show oEmbed data for XHTML files as well as plain HTML. +- Updated bug database link in README. +- require HTML tidy extension. +- add support for HTTP Basic Auth in PHP CGI or FastCGI (e.g. GoDaddy). +- autofocus input to selected entry elements depending on page. +- updated layout for filter-by-tag form. +- better layout for inbox and outbox pages. +- fix highlighting search terms in attributes of notice list elements. +- Correctly handle errors in linkback plugin. +- Updated biz theme. +- Updated cloudy theme. +- Don't match '::' as an IPv6 address. +- Use the same decision logic for deciding whether to mark an + attachment as an enclosure in RSS or as a paperclip item in Web + output. +- Fixed a bug in the Piwik plugin that hard-coded the site ID. +- Add a param, inreplyto, to notice/new to allow an explicit response + to another notice. +- Show username in subject of emails. +- Check if avatar exists before trying to delete it. +- Correctly add omb_version to response for request token in OMB. +- Add a few more SMS carriers. +- Add a few more notice sources. +- Vary: header. +- Improvements to the AutoCompletePlugin. +- Check for 'dl' before using it. +- Make it impossible to delete self-subscriptions via the API. +- Fix pagination of tagged user pages. +- Make PiwikAnalyticsPlugin work with addPlugin(). +- Removed trailing single space in user nicknames in notice lists. +- Show context link if a notice starts a conversation. +- blacklist all files and directories in install dir. +- handle GoDaddy-style PATH_INFO, including script name. +- add home_timeline synonym for friends_timeline. +- Add a popup window for the realtime plugin. +- Add some more streams for the realtime plugin. +- Fix a bug that overwrote group creation timestamp on every edit. +- Moved HTTP error code strings to a class variable. +- The Twitter API now returns server errors in the correct format. +- Reset the doctype for HTML output. +- Fixed a number of notices. +- Don't show search suggestions for private sites. +- Some corrections to FBConnect nav overrides. +- Slightly less database-intensive session management. +- Updated name of software in installer script. +- Include long-form attachment URLs if url-shortener is disabled. +- Include updated localisations for Polish, Greek, Hebrew, Icelandic, + Norwegian, and Chinese. +- Include upstream fixes to gettext.php. +- Correct for regression in Facebook API for updates. +- Ignore "Sent from my iPhone" (and similar) in mail updates. +- Use the NICKNAME_FMT constant for detecting nicknames. +- Check for site servername config'd. +- Compatibility fix for empty status updates with Twitter API. +- Option to show files privately (EXPERIMENTAL! Use with caution.) Prerequisites ============= @@ -225,9 +256,9 @@ especially if you've previously installed PHP/MySQL packages. 1. Unpack the tarball you downloaded on your Web server. Usually a command like this will work: - tar zxf statusnet-0.8.1.tar.gz + tar zxf statusnet-0.8.2.tar.gz - ...which will make a statusnet-0.8.1 subdirectory in your current + ...which will make a statusnet-0.8.2 subdirectory in your current directory. (If you don't have shell access on your Web server, you may have to unpack the tarball on your local computer and FTP the files to the server.) @@ -235,7 +266,7 @@ especially if you've previously installed PHP/MySQL packages. 2. Move the tarball to a directory of your choosing in your Web root directory. Usually something like this will work: - mv statusnet-0.8.1 /var/www/mublog + mv statusnet-0.8.2 /var/www/mublog This will make your StatusNet instance available in the mublog path of your server, like "http://example.net/mublog". "microblog" or @@ -526,10 +557,6 @@ This will run eight (for now) queue handlers: of registered users. * xmppconfirmhandler.php - sends confirmation messages to registered users. -* twitterqueuehandler.php - sends queued notices to Twitter for user - who have opted to set up Twitter bridging. -* facebookqueuehandler.php - sends queued notices to Facebook for users - of the built-in Facebook application. Note that these queue daemons are pretty raw, and need your care. In particular, they leak memory, and you may want to restart them on a @@ -547,101 +574,6 @@ our kind of hacky home-grown DB-based queue solution. See the "queues" config section below for how to configure to use STOMP. As of this writing, the software has been tested with ActiveMQ ( -Twitter Bridge --------------- - -* OAuth - -As of 0.8.1, OAuth is used to to access protected resources on Twitter -instead of HTTP Basic Auth. To use Twitter bridging you will need -to register your instance of StatusNet as an application on Twitter -(http://twitter.com/apps), and update the following variables in your -config.php with the consumer key and secret Twitter generates for you: - - $config['twitter']['consumer_key'] = 'YOURKEY'; - $config['twitter']['consumer_secret'] = 'YOURSECRET'; - -When registering your application with Twitter set the type to "Browser" -and your Callback URL to: - - http://example.org/mublog/twitter/authorization - -The default access type should be, "Read & Write". - -* Importing statuses from Twitter - -To allow your users to import their friends' Twitter statuses, you will -need to enable the bidirectional Twitter bridge in config.php: - - $config['twitterbridge']['enabled'] = true; - -and run the TwitterStatusFetcher daemon (scripts/twitterstatusfetcher.php). -Additionally, you will want to set the integration source variable, -which will keep notices posted to Twitter via StatusNet from looping -back. The integration source should be set to the name of your -application, exactly as you specified it on the settings page for your -StatusNet application on Twitter, e.g.: - - $config['integration']['source'] = 'YourApp'; - -* Twitter Friends Syncing - -Users may set a flag in their settings ("Subscribe to my Twitter friends -here" under the Twitter tab) to have StatusNet attempt to locate and -subscribe to "friends" (people they "follow") on Twitter who also have -accounts on your StatusNet system, and who have previously set up a link -for automatically posting notices to Twitter. - -As of 0.8.0, this is no longer accomplished via a cron job. Instead you -must run the SyncTwitterFriends daemon (scripts/synctwitterfreinds.php). - -Built-in Facebook Application ------------------------------ - -StatusNet's Facebook application allows your users to automatically -update their Facebook statuses with their latest notices, invite -their friends to use the app (and thus your site), view their notice -timelines, and post notices -- all from within Facebook. The application -is built into StatusNet and runs on your host. For automatic Facebook -status updating to work you will need to enable queuing and run the -facebookqueuehandler.php daemon (see the "Queues and daemons" section -above). - -Quick setup instructions*: - -Install the Facebook Developer application on Facebook: - - http://www.facebook.com/developers/ - -Use it to create a new application and generate an API key and secret. -Uncomment the Facebook app section of your config.php and copy in the -key and secret, e.g.: - - # Config section for the built-in Facebook application - $config['facebook']['apikey'] = 'APIKEY'; - $config['facebook']['secret'] = 'SECRET'; - -In Facebook's application editor, specify the following URLs for your app: - -- Canvas Callback URL: http://example.net/mublog/facebook/ -- Post-Remove Callback URL: http://example.net/mublog/facebook/remove -- Post-Add Redirect URL: http://apps.facebook.com/yourapp/ -- Canvas Page URL: http://apps.facebook.com/yourapp/ - -(Replace 'example.net' with your host's URL, 'mublog' with the path -to your StatusNet installation, and 'yourapp' with the name of the -Facebook application you created.) - -Additionally, Choose "Web" for Application type in the Advanced tab. -In the "Canvas setting" section, choose the "FBML" for Render Method, -"Smart Size" for IFrame size, and "Full width (760px)" for Canvas Width. -Everything else can be left with default values. - -*For more detailed instructions please see the installation guide on the -StatusNet wiki: - - http://status.net/trac/wiki/FacebookApplication - Sitemaps -------- @@ -755,6 +687,16 @@ private site, but users of the private site may be able to subscribe to users on a remote site. (Or not... it's not well tested.) The "proper behaviour" hasn't been defined here, so handle with care. +If fancy URLs is enabled, access to file attachments can also be +restricted to logged-in users only. Uncomment the appropriate rewrite +<<<<<<< HEAD:README +rule in .htaccess or your server's httpd.conf. (This most likely will +not work if you are using a virtual server for attachments, so consider +the performance/security tradeoff.) +======= +rule in .htaccess or your server's httpd.conf. +>>>>>>> 446de62... Revert "Added some explanatory text to README":README + Upgrading ========= @@ -768,7 +710,7 @@ with this situation. If you've been using StatusNet 0.7, 0.6, 0.5 or lower, or if you've been tracking the "git" version of the software, you will probably want to upgrade and keep your existing data. There is no automated -upgrade procedure in StatusNet 0.8.1. Try these step-by-step +upgrade procedure in StatusNet 0.8.2. Try these step-by-step instructions; read to the end first before trying them. 0. Download StatusNet and set up all the prerequisites as if you were @@ -789,7 +731,7 @@ instructions; read to the end first before trying them. 5. Once all writing processes to your site are turned off, make a final backup of the Web directory and database. 6. Move your StatusNet directory to a backup spot, like "mublog.bak". -7. Unpack your StatusNet 0.8.1 tarball and move it to "mublog" or +7. Unpack your StatusNet 0.8.2 tarball and move it to "mublog" or wherever your code used to be. 8. Copy the config.php file and avatar directory from your old directory to your new directory. @@ -1251,24 +1193,11 @@ For SMS integration. enabled: Whether to enable SMS integration. Defaults to true. Queues should also be enabled. -twitter -------- - -For Twitter integration - -enabled: Whether to enable Twitter integration. Defaults to true. - Queues should also be enabled. - integration ----------- A catch-all for integration with other systems. -source: The name to use for the source of posts to Twitter. Defaults - to 'statusnet', but if you request your own source name from - Twitter , you can use - that here instead. Status updates on Twitter will then have - links to your site. taguri: base for tag:// URIs. Defaults to site-server + ',2009'. inboxes @@ -1446,15 +1375,6 @@ dir: directory to write backgrounds too. Default is '/background/' path: path to backgrounds. Default is sub-path of install path; note that you may need to change this if you change site-path too. -twitterbridge -------------- - -A bi-direction bridge to Twitter (http://twitter.com/). - -enabled: default false. If true, will show user's Twitter friends' - notices in their inbox and faves pages, only to the user. You - must also run the twitterstatusfetcher.php script. - ping ---- @@ -1553,7 +1473,7 @@ repository (see below), and you get a compilation error ("unexpected T_STRING") in the browser, check to see that you don't have any conflicts in your code. -If you upgraded to StatusNet 0.8.1 without reading the "Notice +If you upgraded to StatusNet 0.8.2 without reading the "Notice inboxes" section above, and all your users' 'Personal' tabs are empty, read the "Notice inboxes" section above. @@ -1661,6 +1581,7 @@ if anyone's been overlooked in error. * Jeffery To * Federico Marani * Craig Andrews +* mEDI Thanks also to the developers of our upstream library code and to the thousands of people who have tried out Identi.ca, installed StatusNet, diff --git a/actions/all.php b/actions/all.php index f1786462e1..61cedce749 100644 --- a/actions/all.php +++ b/actions/all.php @@ -99,19 +99,17 @@ class AllAction extends ProfileAction sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->user->nickname)), new Feed(Feed::RSS2, common_local_url( - 'api', array( - 'apiaction' => 'statuses', - 'method' => 'friends_timeline', - 'argument' => $this->user->nickname.'.rss' + 'ApiTimelineFriends', array( + 'format' => 'rss', + 'id' => $this->user->nickname ) ), sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->user->nickname)), new Feed(Feed::ATOM, common_local_url( - 'api', array( - 'apiaction' => 'statuses', - 'method' => 'friends_timeline', - 'argument' => $this->user->nickname.'.atom' + 'ApiTimelineFriends', array( + 'format' => 'atom', + 'id' => $this->user->nickname ) ), sprintf(_('Feed for friends of %s (Atom)'), $this->user->nickname)) diff --git a/actions/apidirectmessagenew.php b/actions/apidirectmessagenew.php index fa6cafbe8d..ca1ee70dde 100644 --- a/actions/apidirectmessagenew.php +++ b/actions/apidirectmessagenew.php @@ -157,7 +157,7 @@ class ApiDirectMessageNewAction extends ApiAuthAction // Note: sending msgs to yourself is allowed by Twitter $errmsg = 'Don\'t send a message to yourself; ' . - 'just say it to yourself quietly instead.' + 'just say it to yourself quietly instead.'; $this->clientError(_($errmsg), 403, $this->format); return; diff --git a/actions/apifavoritecreate.php b/actions/apifavoritecreate.php index a80a6492e9..4367397707 100644 --- a/actions/apifavoritecreate.php +++ b/actions/apifavoritecreate.php @@ -127,7 +127,7 @@ class ApiFavoriteCreateAction extends ApiAuthAction if (empty($fave)) { $this->clientError( - _('Could not create favorite.') + _('Could not create favorite.'), 403, $this->format ); diff --git a/actions/apistatusesupdate.php b/actions/apistatusesupdate.php index 0d71e15128..898a4bd723 100644 --- a/actions/apistatusesupdate.php +++ b/actions/apistatusesupdate.php @@ -38,6 +38,7 @@ if (!defined('STATUSNET')) { } require_once INSTALLDIR . '/lib/apiauth.php'; +require_once INSTALLDIR . '/lib/mediafile.php'; /** * Updates the authenticating user's status (posts a notice). @@ -60,7 +61,6 @@ class ApiStatusesUpdateAction extends ApiAuthAction var $source = null; var $status = null; var $in_reply_to_status_id = null; - static $reserved_sources = array('web', 'omb', 'mail', 'xmpp', 'api'); /** @@ -76,25 +76,8 @@ class ApiStatusesUpdateAction extends ApiAuthAction { parent::prepare($args); - $this->user = $this->auth_user; - - if (empty($this->user)) { - $this->clientError(_('No such user!'), 404, $this->format); - return false; - } - + $this->user = $this->auth_user; $this->status = $this->trimmed('status'); - - if (empty($this->status)) { - $this->clientError( - 'Client must provide a \'status\' parameter with a value.', - 400, - $this->format - ); - - return false; - } - $this->source = $this->trimmed('source'); if (empty($this->source) || in_array($source, $this->reserved_sources)) { @@ -129,6 +112,27 @@ class ApiStatusesUpdateAction extends ApiAuthAction return; } + if (empty($this->status)) { + $this->clientError( + 'Client must provide a \'status\' parameter with a value.', + 400, + $this->format + ); + return; + } + + if (empty($this->user)) { + $this->clientError(_('No such user!'), 404, $this->format); + return; + } + + // Workaround for PHP returning empty $_FILES when POST length > PHP settings + + if (empty($_POST) && ($_SERVER['CONTENT_LENGTH'] > 0)) { + $this->clientError(_('Unable to handle that much POST data!')); + return; + } + $status_shortened = common_shorten_links($this->status); if (Notice::contentTooLong($status_shortened)) { @@ -187,14 +191,40 @@ class ApiStatusesUpdateAction extends ApiAuthAction } } + $upload = null; + + try { + $upload = MediaFile::fromUpload('media', $this->user); + } catch (ClientException $ce) { + $this->clientError($ce->getMessage()); + return; + } + + if (isset($upload)) { + $status_shortened .= ' ' . $upload->shortUrl(); + + if (Notice::contentTooLong($status_shortened)) { + $upload->delete(); + $msg = _( + 'Max notice size is %d chars, ' . + 'including attachment URL.' + ); + $this->clientError(sprintf($msg, Notice::maxContent())); + } + } + $this->notice = Notice::saveNew( $this->user->id, - html_entity_decode($this->status, ENT_NOQUOTES, 'UTF-8'), + html_entity_decode($status_shortened, ENT_NOQUOTES, 'UTF-8'), $this->source, 1, $reply_to ); + if (isset($upload)) { + $upload->attachToNotice($this->notice); + } + common_broadcast_notice($this->notice); } diff --git a/actions/bookmarklet.php b/actions/bookmarklet.php new file mode 100644 index 0000000000..0603a74561 --- /dev/null +++ b/actions/bookmarklet.php @@ -0,0 +1,75 @@ +. + * + * @category Bookmarklet + * @package StatusNet + * @author Sarven Capadisli + * @copyright 2008-2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR . '/actions/newnotice.php'; + +/** + * Action for posting a notice + * + * @category Bookmarklet + * @package StatusNet + * @author Sarven Capadisli + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +class BookmarkletAction extends NewnoticeAction +{ + function showTitle() + { + $this->element('title', null, _('Post to ').common_config('site', 'name')); + } + + function showHeader() + { + $this->elementStart('div', array('id' => 'header')); + $this->elementStart('address'); + $this->element('a', array('class' => 'url', + 'href' => common_local_url('public')), + ''); + $this->elementEnd('address'); + if (common_logged_in()) { + $this->showNoticeForm(); + } + $this->elementEnd('div'); + } + + function showCore() + { + } + + function showFooter() + { + } +} + diff --git a/actions/emailsettings.php b/actions/emailsettings.php index 6eff06c0d6..67b991cdc8 100644 --- a/actions/emailsettings.php +++ b/actions/emailsettings.php @@ -326,7 +326,7 @@ class EmailsettingsAction extends AccountSettingsAction $this->showForm(_('Cannot normalize that email address')); return; } - if (!Validate::email($email, true)) { + if (!Validate::email($email, common_config('email', 'check_domain'))) { $this->showForm(_('Not a valid email address')); return; } else if ($user->email == $email) { diff --git a/actions/getfile.php b/actions/getfile.php new file mode 100644 index 0000000000..ecda34c0f6 --- /dev/null +++ b/actions/getfile.php @@ -0,0 +1,145 @@ +. + * + * @category Personal + * @package StatusNet + * @author Jeffery To + * @copyright 2008-2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +require_once 'MIME/Type.php'; + +/** + * Action for getting a file attachment + * + * @category Personal + * @package StatusNet + * @author Jeffery To + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +class GetfileAction extends Action +{ + /** + * Path of file to return + */ + + var $path = null; + + /** + * Get file name + * + * @param array $args $_REQUEST array + * + * @return success flag + */ + + function prepare($args) + { + parent::prepare($args); + + $filename = $this->trimmed('filename'); + $path = null; + + if ($filename) { + $path = common_config('attachments', 'dir') . $filename; + } + + if (empty($path) or !file_exists($path)) { + $this->clientError(_('No such file.'), 404); + return false; + } + if (!is_readable($path)) { + $this->clientError(_('Cannot read file.'), 403); + return false; + } + + $this->path = $path; + return true; + } + + /** + * Is this page read-only? + * + * @return boolean true + */ + + function isReadOnly($args) + { + return true; + } + + /** + * Last-modified date for file + * + * @return int last-modified date as unix timestamp + */ + + function lastModified() + { + return filemtime($this->path); + } + + /** + * etag for file + * + * This returns the same data (inode, size, mtime) as Apache would, + * but in decimal instead of hex. + * + * @return string etag http header + */ + function etag() + { + $stat = stat($this->path); + return '"' . $stat['ino'] . '-' . $stat['size'] . '-' . $stat['mtime'] . '"'; + } + + /** + * Handle input, produce output + * + * @param array $args $_REQUEST contents + * + * @return void + */ + + function handle($args) + { + // undo headers set by PHP sessions + $sec = session_cache_expire() * 60; + header('Expires: ' . date(DATE_RFC1123, time() + $sec)); + header('Cache-Control: public, max-age=' . $sec); + header('Pragma: public'); + + parent::handle($args); + + $path = $this->path; + header('Content-Type: ' . MIME_Type::autoDetect($path)); + readfile($path); + } +} diff --git a/actions/groupmembers.php b/actions/groupmembers.php index dcbdd37597..b326a0df75 100644 --- a/actions/groupmembers.php +++ b/actions/groupmembers.php @@ -179,9 +179,12 @@ class GroupMemberListItem extends ProfileListItem function showActions() { $this->startActions(); - $this->showSubscribeButton(); - $this->showMakeAdminForm(); - $this->showGroupBlockForm(); + if (Event::handle('StartProfileListItemActionElements', array($this))) { + $this->showSubscribeButton(); + $this->showMakeAdminForm(); + $this->showGroupBlockForm(); + Event::handle('EndProfileListItemActionElements', array($this)); + } $this->endActions(); } diff --git a/actions/invite.php b/actions/invite.php index 788130c582..3015202e9e 100644 --- a/actions/invite.php +++ b/actions/invite.php @@ -68,7 +68,7 @@ class InviteAction extends CurrentUserDesignAction foreach ($addresses as $email) { $email = trim($email); - if (!Validate::email($email, true)) { + if (!Validate::email($email, common_config('email', 'check_domain'))) { $this->showForm(sprintf(_('Invalid email address: %s'), $email)); return; } diff --git a/actions/newmessage.php b/actions/newmessage.php index a0b17fc18a..37fca1ca2b 100644 --- a/actions/newmessage.php +++ b/actions/newmessage.php @@ -99,7 +99,9 @@ class NewmessageAction extends Action $user = common_current_user(); if (!$user) { - $this->clientError(_('Only logged-in users can send direct messages.'), 403); + /* Go log in, and then come back. */ + common_set_returnto($_SERVER['REQUEST_URI']); + common_redirect(common_local_url('login')); return false; } @@ -221,7 +223,22 @@ class NewmessageAction extends Action } $this->msg = $msg; - $this->showPage(); + if ($this->trimmed('ajax')) { + $this->startHTML('text/xml;charset=UTF-8'); + $this->elementStart('head'); + $this->element('title', null, _('New message')); + $this->elementEnd('head'); + $this->elementStart('body'); + if (common_logged_in()) { + $this->showNoticeForm(); + } + $this->elementEnd('div'); + $this->elementEnd('body'); + $this->endHTML(); + } + else { + $this->showPage(); + } } function showPageNotice() diff --git a/actions/newnotice.php b/actions/newnotice.php index 9ee031f936..fbd7ab6bce 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -33,7 +33,8 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -require_once INSTALLDIR.'/lib/noticelist.php'; +require_once INSTALLDIR . '/lib/noticelist.php'; +require_once INSTALLDIR . '/lib/mediafile.php'; /** * Action for posting new notices @@ -113,33 +114,6 @@ class NewnoticeAction extends Action } } - function getUploadedFileType() { - require_once 'MIME/Type.php'; - - $cmd = &PEAR::getStaticProperty('MIME_Type', 'fileCmd'); - $cmd = common_config('attachments', 'filecommand'); - - $filetype = MIME_Type::autoDetect($_FILES['attach']['tmp_name']); - if (in_array($filetype, common_config('attachments', 'supported'))) { - return $filetype; - } - $media = MIME_Type::getMedia($filetype); - if ('application' !== $media) { - $hint = sprintf(_(' Try using another %s format.'), $media); - } else { - $hint = ''; - } - $this->clientError(sprintf( - _('%s is not a supported filetype on this server.'), $filetype) . $hint); - } - - function isRespectsQuota($user) { - $file = new File; - $ret = $file->isRespectsQuota($user,$_FILES['attach']['size']); - if (true === $ret) return true; - $this->clientError($ret); - } - /** * Save a new notice, based on arguments * @@ -160,18 +134,12 @@ class NewnoticeAction extends Action if (!$content) { $this->clientError(_('No content!')); - } else { - $content_shortened = common_shorten_links($content); - if (Notice::contentTooLong($content_shortened)) { - $this->clientError(sprintf(_('That\'s too long. '. - 'Max notice size is %d chars.'), - Notice::maxContent())); - } + return; } $inter = new CommandInterpreter(); - $cmd = $inter->handle_command($user, $content_shortened); + $cmd = $inter->handle_command($user, $content); if ($cmd) { if ($this->boolean('ajax')) { @@ -182,6 +150,13 @@ class NewnoticeAction extends Action return; } + $content_shortened = common_shorten_links($content); + if (Notice::contentTooLong($content_shortened)) { + $this->clientError(sprintf(_('That\'s too long. '. + 'Max notice size is %d chars.'), + Notice::maxContent())); + } + $replyto = $this->trimmed('inreplyto'); #If an ID of 0 is wrongly passed here, it will cause a database error, #so override it... @@ -189,84 +164,37 @@ class NewnoticeAction extends Action $replyto = 'false'; } - if (isset($_FILES['attach']['error'])) { - switch ($_FILES['attach']['error']) { - case UPLOAD_ERR_NO_FILE: - // no file uploaded, nothing to do - break; + $upload = null; + $upload = MediaFile::fromUpload('attach'); - case UPLOAD_ERR_OK: - $mimetype = $this->getUploadedFileType(); - if (!$this->isRespectsQuota($user)) { - die('clientError() should trigger an exception before reaching here.'); - } - break; + if (isset($upload)) { - case UPLOAD_ERR_INI_SIZE: - $this->clientError(_('The uploaded file exceeds the upload_max_filesize directive in php.ini.')); - - case UPLOAD_ERR_FORM_SIZE: - $this->clientError(_('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.')); - - case UPLOAD_ERR_PARTIAL: - $this->clientError(_('The uploaded file was only partially uploaded.')); - - case UPLOAD_ERR_NO_TMP_DIR: - $this->clientError(_('Missing a temporary folder.')); - - case UPLOAD_ERR_CANT_WRITE: - $this->clientError(_('Failed to write file to disk.')); - - case UPLOAD_ERR_EXTENSION: - $this->clientError(_('File upload stopped by extension.')); - - default: - die('Should never reach here.'); - } - } - - if (isset($mimetype)) { - $filename = $this->saveFile($mimetype); - if (empty($filename)) { - $this->clientError(_('Couldn\'t save file.')); - } - - $fileRecord = $this->storeFile($filename, $mimetype); - - $fileurl = common_local_url('attachment', - array('attachment' => $fileRecord->id)); - - // not sure this is necessary -- Zach - $this->maybeAddRedir($fileRecord->id, $fileurl); - - $short_fileurl = common_shorten_url($fileurl); - if (!$short_fileurl) { - // todo -- Consider forcing default shortener if none selected? - $short_fileurl = $fileurl; - } - $content_shortened .= ' ' . $short_fileurl; + $content_shortened .= ' ' . $upload->shortUrl(); if (Notice::contentTooLong($content_shortened)) { - $this->deleteFile($filename); - $this->clientError(sprintf(_('Max notice size is %d chars, including attachment URL.'), - Notice::maxContent())); + $upload->delete(); + $this->clientError( + sprintf( + _('Max notice size is %d chars, including attachment URL.'), + Notice::maxContent() + ) + ); } - - // Also, not sure this is necessary -- Zach - $this->maybeAddRedir($fileRecord->id, $short_fileurl); } $notice = Notice::saveNew($user->id, $content_shortened, 'web', 1, ($replyto == 'false') ? null : $replyto); - if (isset($mimetype)) { - $this->attachFile($notice, $fileRecord); + if (isset($upload)) { + $upload->attachToNotice($notice); } common_broadcast_notice($notice); if ($this->boolean('ajax')) { - $this->startHTML('text/xml;charset=utf-8'); + header('Content-Type: text/xml;charset=utf-8'); + $this->xw->startDocument('1.0', 'UTF-8'); + $this->elementStart('html'); $this->elementStart('head'); $this->element('title', null, _('Notice posted')); $this->elementEnd('head'); @@ -288,87 +216,6 @@ class NewnoticeAction extends Action } } - function saveFile($mimetype) { - - $cur = common_current_user(); - - if (empty($cur)) { - $this->serverError(_('Somehow lost the login in saveFile')); - } - - $basename = basename($_FILES['attach']['name']); - - $filename = File::filename($cur->getProfile(), $basename, $mimetype); - - $filepath = File::path($filename); - - if (move_uploaded_file($_FILES['attach']['tmp_name'], $filepath)) { - return $filename; - } else { - $this->clientError(_('File could not be moved to destination directory.')); - } - } - - function deleteFile($filename) - { - $filepath = File::path($filename); - @unlink($filepath); - } - - function storeFile($filename, $mimetype) { - - $file = new File; - $file->filename = $filename; - - $file->url = File::url($filename); - - $filepath = File::path($filename); - - $file->size = filesize($filepath); - $file->date = time(); - $file->mimetype = $mimetype; - - $file_id = $file->insert(); - - if (!$file_id) { - common_log_db_error($file, "INSERT", __FILE__); - $this->clientError(_('There was a database error while saving your file. Please try again.')); - } - - return $file; - } - - function rememberFile($file, $short) - { - $this->maybeAddRedir($file->id, $short); - } - - function maybeAddRedir($file_id, $url) - { - $file_redir = File_redirection::staticGet('url', $url); - - if (empty($file_redir)) { - $file_redir = new File_redirection; - $file_redir->url = $url; - $file_redir->file_id = $file_id; - - $result = $file_redir->insert(); - - if (!$result) { - common_log_db_error($file_redir, "INSERT", __FILE__); - $this->clientError(_('There was a database error while saving your file. Please try again.')); - } - } - } - - function attachFile($notice, $filerec) - { - File_to_post::processNew($filerec->id, $notice->id); - - $this->maybeAddRedir($filerec->id, - common_local_url('file', array('notice' => $notice->id))); - } - /** * Show an Ajax-y error message * diff --git a/actions/othersettings.php b/actions/othersettings.php index 011b4fc838..d32a2d651c 100644 --- a/actions/othersettings.php +++ b/actions/othersettings.php @@ -103,7 +103,7 @@ class OthersettingsAction extends AccountSettingsAction foreach($_shorteners as $name=>$value) { $services[$name]=$name; - if($value['info']['freeService']){ + if(!empty($value['info']['freeService'])){ // I18N $services[$name].=' (free service)'; } diff --git a/actions/profilesettings.php b/actions/profilesettings.php index 5445d9bb25..0a0cc59973 100644 --- a/actions/profilesettings.php +++ b/actions/profilesettings.php @@ -306,6 +306,16 @@ class ProfilesettingsAction extends AccountSettingsAction $profile->homepage = $homepage; $profile->bio = $bio; $profile->location = $location; + + $loc = Location::fromName($location); + + if (!empty($loc)) { + $profile->lat = $loc->lat; + $profile->lon = $loc->lon; + $profile->location_id = $loc->location_id; + $profile->location_ns = $loc->location_ns; + } + $profile->profileurl = common_profile_url($nickname); common_debug('Old profile: ' . common_log_objstring($orig_profile), __FILE__); diff --git a/actions/public.php b/actions/public.php index 73fad182a3..982dfde157 100644 --- a/actions/public.php +++ b/actions/public.php @@ -131,6 +131,13 @@ class PublicAction extends Action return _('Public timeline'); } } + + function extraHead() + { + parent::extraHead(); + $this->element('meta', array('http-equiv' => 'X-XRDS-Location', + 'content' => common_local_url('publicxrds'))); + } /** * Output elements for RSS and Atom feeds @@ -143,14 +150,12 @@ class PublicAction extends Action return array(new Feed(Feed::RSS1, common_local_url('publicrss'), _('Public Stream Feed (RSS 1.0)')), new Feed(Feed::RSS2, - common_local_url('api', - array('apiaction' => 'statuses', - 'method' => 'public_timeline.rss')), + common_local_url('ApiTimelinePublic', + array('format' => 'rss')), _('Public Stream Feed (RSS 2.0)')), new Feed(Feed::ATOM, - common_local_url('api', - array('apiaction' => 'statuses', - 'method' => 'public_timeline.atom')), + common_local_url('ApiTimelinePublic', + array('format' => 'atom')), _('Public Stream Feed (Atom)'))); } diff --git a/actions/publicxrds.php b/actions/publicxrds.php new file mode 100644 index 0000000000..5fd4eead7d --- /dev/null +++ b/actions/publicxrds.php @@ -0,0 +1,81 @@ + + * @author Robin Millette + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + * + * StatusNet - the distributed open-source microblogging tool + * Copyright (C) 2008, 2009, StatusNet, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR.'/plugins/OpenID/openid.php'; +require_once INSTALLDIR.'/lib/xrdsoutputter.php'; + +/** + * Public XRDS + * + * @category Action + * @package StatusNet + * @author Evan Prodromou + * @author Robin Millette + * @author Craig Andrews + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + * + * @todo factor out similarities with XrdsAction + */ +class PublicxrdsAction extends Action +{ + /** + * Is read only? + * + * @return boolean true + */ + function isReadOnly($args) + { + return true; + } + + /** + * Class handler. + * + * @param array $args array of arguments + * + * @return nothing + */ + function handle($args) + { + parent::handle($args); + $xrdsOutputter = new XRDSOutputter(); + $xrdsOutputter->startXRDS(); + Event::handle('StartPublicXRDS', array($this,&$xrdsOutputter)); + Event::handle('EndPublicXRDS', array($this,&$xrdsOutputter)); + $xrdsOutputter->endXRDS(); + } +} + diff --git a/actions/register.php b/actions/register.php index 100ab74242..a6c1a903aa 100644 --- a/actions/register.php +++ b/actions/register.php @@ -191,7 +191,7 @@ class RegisterAction extends Action if (!$this->boolean('license')) { $this->showForm(_('You can\'t register if you don\'t '. 'agree to the license.')); - } else if ($email && !Validate::email($email, true)) { + } else if ($email && !Validate::email($email, common_config('email', 'check_domain'))) { $this->showForm(_('Not a valid email address.')); } else if (!Validate::string($nickname, array('min_length' => 1, 'max_length' => 64, diff --git a/actions/replies.php b/actions/replies.php index 6003ad30bd..a13b5a2273 100644 --- a/actions/replies.php +++ b/actions/replies.php @@ -138,11 +138,25 @@ class RepliesAction extends OwnerDesignAction function getFeeds() { - $rssurl = common_local_url('repliesrss', - array('nickname' => $this->user->nickname)); - $rsstitle = sprintf(_('Feed for replies to %s'), $this->user->nickname); - - return array(new Feed(Feed::RSS1, $rssurl, $rsstitle)); + return array(new Feed(Feed::RSS1, + common_local_url('repliesrss', + array('nickname' => $this->user->nickname)), + sprintf(_('Replies feed for %s (RSS 1.0)'), + $this->user->nickname)), + new Feed(Feed::RSS2, + common_local_url('ApiTimelineMentions', + array( + 'id' => $this->user->nickname, + 'format' => 'rss')), + sprintf(_('Replies feed for %s (RSS 2.0)'), + $this->user->nickname)), + new Feed(Feed::ATOM, + common_local_url('ApiTimelineMentions', + array( + 'id' => $this->user->nickname, + 'format' => 'atom')), + sprintf(_('Replies feed for %s (Atom)'), + $this->user->nickname))); } /** diff --git a/actions/showfavorites.php b/actions/showfavorites.php index b96d2af37f..b12fcdd9a0 100644 --- a/actions/showfavorites.php +++ b/actions/showfavorites.php @@ -164,13 +164,25 @@ class ShowfavoritesAction extends OwnerDesignAction function getFeeds() { - $feedurl = common_local_url('favoritesrss', - array('nickname' => - $this->user->nickname)); - $feedtitle = sprintf(_('Feed for favorites of %s'), - $this->user->nickname); - - return array(new Feed(Feed::RSS1, $feedurl, $feedtitle)); + return array(new Feed(Feed::RSS1, + common_local_url('favoritesrss', + array('nickname' => $this->user->nickname)), + sprintf(_('Feed for favorites of %s (RSS 1.0)'), + $this->user->nickname)), + new Feed(Feed::RSS2, + common_local_url('ApiTimelineFavorites', + array( + 'id' => $this->user->nickname, + 'format' => 'rss')), + sprintf(_('Feed for favorites of %s (RSS 2.0)'), + $this->user->nickname)), + new Feed(Feed::ATOM, + common_local_url('ApiTimelineFavorites', + array( + 'id' => $this->user->nickname, + 'format' => 'atom')), + sprintf(_('Feed for favorites of %s (Atom)'), + $this->user->nickname))); } /** diff --git a/actions/showgroup.php b/actions/showgroup.php index bfe45ddad7..a4af29391d 100644 --- a/actions/showgroup.php +++ b/actions/showgroup.php @@ -328,17 +328,15 @@ class ShowgroupAction extends GroupDesignAction sprintf(_('Notice feed for %s group (RSS 1.0)'), $this->group->nickname)), new Feed(Feed::RSS2, - common_local_url('api', - array('apiaction' => 'groups', - 'method' => 'timeline', - 'argument' => $this->group->nickname.'.rss')), + common_local_url('ApiTimelineGroup', + array('format' => 'rss', + 'id' => $this->group->nickname)), sprintf(_('Notice feed for %s group (RSS 2.0)'), $this->group->nickname)), new Feed(Feed::ATOM, - common_local_url('api', - array('apiaction' => 'groups', - 'method' => 'timeline', - 'argument' => $this->group->nickname.'.atom')), + common_local_url('ApiTimelineGroup', + array('format' => 'atom', + 'id' => $this->group->nickname)), sprintf(_('Notice feed for %s group (Atom)'), $this->group->nickname)), new Feed(Feed::FOAF, diff --git a/actions/shownotice.php b/actions/shownotice.php index 41408c23cc..5d16fdad9e 100644 --- a/actions/shownotice.php +++ b/actions/shownotice.php @@ -172,9 +172,9 @@ class ShownoticeAction extends OwnerDesignAction function title() { if (!empty($this->profile->fullname)) { - $base = $this->profile->fullname . ' (' . $this->user->nickname . ') '; + $base = $this->profile->fullname . ' (' . $this->profile->nickname . ') '; } else { - $base = $this->user->nickname; + $base = $this->profile->nickname; } return sprintf(_('%1$s\'s status on %2$s'), diff --git a/actions/showstream.php b/actions/showstream.php index b3a9b1f05c..4f48060378 100644 --- a/actions/showstream.php +++ b/actions/showstream.php @@ -128,17 +128,17 @@ class ShowstreamAction extends ProfileAction sprintf(_('Notice feed for %s (RSS 1.0)'), $this->user->nickname)), new Feed(Feed::RSS2, - common_local_url('api', - array('apiaction' => 'statuses', - 'method' => 'user_timeline', - 'argument' => $this->user->nickname.'.rss')), + common_local_url('ApiTimelineUser', + array( + 'id' => $this->user->nickname, + 'format' => 'rss')), sprintf(_('Notice feed for %s (RSS 2.0)'), $this->user->nickname)), new Feed(Feed::ATOM, - common_local_url('api', - array('apiaction' => 'statuses', - 'method' => 'user_timeline', - 'argument' => $this->user->nickname.'.atom')), + common_local_url('ApiTimelineUser', + array( + 'id' => $this->user->nickname, + 'format' => 'atom')), sprintf(_('Notice feed for %s (Atom)'), $this->user->nickname)), new Feed(Feed::FOAF, @@ -348,6 +348,8 @@ class ShowstreamAction extends ProfileAction { if (Event::handle('StartProfilePageActionsSection', array(&$this, $this->profile))) { + $cur = common_current_user(); + $this->elementStart('div', 'entity_actions'); $this->element('h2', null, _('User actions')); $this->elementStart('ul'); @@ -379,21 +381,21 @@ class ShowstreamAction extends ProfileAction } $this->elementEnd('li'); - if ($cur->mutuallySubscribed($user)) { + if ($cur->mutuallySubscribed($this->user)) { // message $this->elementStart('li', 'entity_send-a-message'); - $this->element('a', array('href' => common_local_url('newmessage', array('to' => $user->id)), + $this->element('a', array('href' => common_local_url('newmessage', array('to' => $this->user->id)), 'title' => _('Send a direct message to this user')), _('Message')); $this->elementEnd('li'); // nudge - if ($user->email && $user->emailnotifynudge) { + if ($this->user->email && $this->user->emailnotifynudge) { $this->elementStart('li', 'entity_nudge'); - $nf = new NudgeForm($this, $user); + $nf = new NudgeForm($this, $this->user); $nf->show(); $this->elementEnd('li'); } diff --git a/actions/tag.php b/actions/tag.php index f0ab30308c..3a88c1229d 100644 --- a/actions/tag.php +++ b/actions/tag.php @@ -86,17 +86,15 @@ class TagAction extends Action sprintf(_('Notice feed for tag %s (RSS 1.0)'), $this->tag)), new Feed(Feed::RSS2, - common_local_url('api', - array('apiaction' => 'tags', - 'method' => 'timeline', - 'argument' => $this->tag.'.rss')), - sprintf(_('Notice feed for %s group (RSS 2.0)'), + common_local_url('ApiTimelineTag', + array('format' => 'rss', + 'tag' => $this->tag)), + sprintf(_('Notice feed for tag %s (RSS 2.0)'), $this->tag)), new Feed(Feed::ATOM, - common_local_url('api', - array('apiaction' => 'tags', - 'method' => 'timeline', - 'argument' => $this->tag.'.atom')), + common_local_url('ApiTimelineTag', + array('format' => 'atom', + 'tag' => $this->tag)), sprintf(_('Notice feed for tag %s (Atom)'), $this->tag))); } diff --git a/actions/xrds.php b/actions/xrds.php index 8ba89fec0f..8f09557d18 100644 --- a/actions/xrds.php +++ b/actions/xrds.php @@ -36,6 +36,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { require_once INSTALLDIR.'/lib/omb.php'; require_once INSTALLDIR.'/extlib/libomb/service_provider.php'; require_once INSTALLDIR.'/extlib/libomb/xrds_mapper.php'; +require_once INSTALLDIR.'/lib/xrdsoutputter.php'; /** * XRDS for OpenMicroBlogging @@ -49,6 +50,8 @@ require_once INSTALLDIR.'/extlib/libomb/xrds_mapper.php'; */ class XrdsAction extends Action { + var $user; + /** * Is read only? * @@ -58,6 +61,18 @@ class XrdsAction extends Action { return true; } + + function prepare($args) + { + parent::prepare($args); + $nickname = $this->trimmed('nickname'); + $this->user = User::staticGet('nickname', $nickname); + if (!$this->user) { + $this->clientError(_('No such user.')); + return; + } + return true; + } /** * Class handler. @@ -69,49 +84,64 @@ class XrdsAction extends Action function handle($args) { parent::handle($args); - $nickname = $this->trimmed('nickname'); - $user = User::staticGet('nickname', $nickname); - if (!$user) { - $this->clientError(_('No such user.')); - return; - } - $this->showXrds($user); - } + $xrdsOutputter = new XRDSOutputter(); + $xrdsOutputter->startXRDS(); - /** - * Show XRDS for a user. - * - * @param class $user XRDS for this user. - * - * @return void - */ - function showXrds($user) - { - $srv = new OMB_Service_Provider(profile_to_omb_profile($user->uri, - $user->getProfile())); - /* Use libomb’s default XRDS Writer. */ - $xrds_writer = null; - $srv->writeXRDS(new Laconica_XRDS_Mapper(), $xrds_writer); - } -} + Event::handle('StartUserXRDS', array($this,&$xrdsOutputter)); -class Laconica_XRDS_Mapper implements OMB_XRDS_Mapper -{ - protected $urls; + //oauth + $xrdsOutputter->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)', + 'xml:id' => 'oauth', + 'xmlns:simple' => 'http://xrds-simple.net/core/1.0', + 'version' => '2.0')); + $xrdsOutputter->element('Type', null, 'xri://$xrds*simple'); + $xrdsOutputter->showXrdsService(OAUTH_ENDPOINT_REQUEST, + common_local_url('requesttoken'), + array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY, OAUTH_HMAC_SHA1)); + $xrdsOutputter->showXrdsService( OAUTH_ENDPOINT_AUTHORIZE, + common_local_url('userauthorization'), + array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY, OAUTH_HMAC_SHA1), + null, + $this->user->getIdentifierURI()); + $xrdsOutputter->showXrdsService(OAUTH_ENDPOINT_ACCESS, + common_local_url('accesstoken'), + array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY, OAUTH_HMAC_SHA1), + null, + $this->user->getIdentifierURI()); + $xrdsOutputter->showXrdsService(OAUTH_ENDPOINT_RESOURCE, + null, + array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY, OAUTH_HMAC_SHA1), + null, + $this->user->getIdentifierURI()); + $xrdsOutputter->elementEnd('XRD'); + + //omb + $xrdsOutputter->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)', + 'xml:id' => 'oauth', + 'xmlns:simple' => 'http://xrds-simple.net/core/1.0', + 'version' => '2.0')); + $xrdsOutputter->element('Type', null, 'xri://$xrds*simple'); + $xrdsOutputter->showXrdsService(OMB_ENDPOINT_POSTNOTICE, + common_local_url('postnotice')); + $xrdsOutputter->showXrdsService(OMB_ENDPOINT_UPDATEPROFILE, + common_local_url('updateprofile')); + $xrdsOutputter->elementEnd('XRD'); + + //misc + $xrdsOutputter->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)', + 'xml:id' => 'oauth', + 'xmlns:simple' => 'http://xrds-simple.net/core/1.0', + 'version' => '2.0')); + $xrdsOutputter->showXrdsService(OAUTH_DISCOVERY, + '#oauth'); + $xrdsOutputter->showXrdsService(OMB_VERSION, + '#omb'); + $xrdsOutputter->elementEnd('XRD'); - public function __construct() - { - $this->urls = array( - OAUTH_ENDPOINT_REQUEST => 'requesttoken', - OAUTH_ENDPOINT_AUTHORIZE => 'userauthorization', - OAUTH_ENDPOINT_ACCESS => 'accesstoken', - OMB_ENDPOINT_POSTNOTICE => 'postnotice', - OMB_ENDPOINT_UPDATEPROFILE => 'updateprofile'); - } + Event::handle('EndUserXRDS', array($this,&$xrdsOutputter)); - public function getURL($action) - { - return common_local_url($this->urls[$action]); + $xrdsOutputter->endXRDS(); + } } ?> diff --git a/classes/Avatar.php b/classes/Avatar.php index 5e8b315fe6..64f105179c 100644 --- a/classes/Avatar.php +++ b/classes/Avatar.php @@ -81,7 +81,7 @@ class Avatar extends Memcached_DataObject if (empty($server)) { $server = common_config('site', 'server'); } - + common_debug('path = ' . $path); // XXX: protocol return 'http://'.$server.$path.$filename; diff --git a/classes/Location_namespace.php b/classes/Location_namespace.php new file mode 100644 index 0000000000..5ab95d9ef2 --- /dev/null +++ b/classes/Location_namespace.php @@ -0,0 +1,46 @@ +. + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } + +/** + * Table Definition for location_namespace + */ + +require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; + +class Location_namespace extends Memcached_DataObject +{ + ###START_AUTOCODE + /* the code below is auto generated do not remove the above tag */ + + public $__table = 'location_namespace'; // table name + public $id; // int(4) primary_key not_null + public $description; // varchar(255) + public $created; // datetime() not_null + public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP + + /* Static get */ + function staticGet($k,$v=NULL) { + return Memcached_DataObject::staticGet('Location_namespace',$k,$v); + } + + /* the code above is auto generated do not remove the tag below */ + ###END_AUTOCODE +} diff --git a/classes/Notice.php b/classes/Notice.php index cd3906ca17..a9dbaa461b 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -66,9 +66,15 @@ class Notice extends Memcached_DataObject public $is_local; // tinyint(1) public $source; // varchar(32) public $conversation; // int(4) + public $lat; // decimal(10,7) + public $lon; // decimal(10,7) + public $location_id; // int(4) + public $location_ns; // int(4) /* Static get */ - function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Notice',$k,$v); } + function staticGet($k,$v=NULL) { + return Memcached_DataObject::staticGet('Notice',$k,$v); + } /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE @@ -162,7 +168,8 @@ class Notice extends Memcached_DataObject } static function saveNew($profile_id, $content, $source=null, - $is_local=Notice::LOCAL_PUBLIC, $reply_to=null, $uri=null, $created=null) { + $is_local=Notice::LOCAL_PUBLIC, $reply_to=null, $uri=null, $created=null, + $lat=null, $lon=null, $location_id=null, $location_ns=null) { $profile = Profile::staticGet($profile_id); @@ -172,7 +179,7 @@ class Notice extends Memcached_DataObject throw new ClientException(_('Problem saving notice. Too long.')); } - if (!$profile) { + if (empty($profile)) { throw new ClientException(_('Problem saving notice. Unknown user.')); } @@ -228,6 +235,26 @@ class Notice extends Memcached_DataObject $notice->conversation = $reply->conversation; } + if (!empty($lat) && !empty($lon)) { + $notice->lat = $lat; + $notice->lon = $lon; + $notice->location_id = $location_id; + $notice->location_ns = $location_ns; + } else if (!empty($location_ns) && !empty($location_id)) { + $location = Location::fromId($location_id, $location_ns); + if (!empty($location)) { + $notice->lat = $location->lat; + $notice->lon = $location->lon; + $notice->location_id = $location_id; + $notice->location_ns = $location_ns; + } + } else { + $notice->lat = $profile->lat; + $notice->lon = $profile->lon; + $notice->location_id = $profile->location_id; + $notice->location_ns = $profile->location_ns; + } + if (Event::handle('StartNoticeSave', array(&$notice))) { // XXX: some of these functions write to the DB @@ -269,7 +296,6 @@ class Notice extends Memcached_DataObject // XXX: do we need to change this for remote users? - $notice->saveReplies(); $notice->saveTags(); $notice->addToInboxes(); @@ -307,11 +333,11 @@ class Notice extends Memcached_DataObject static function checkDupes($profile_id, $content) { $profile = Profile::staticGet($profile_id); - if (!$profile) { + if (empty($profile)) { return false; } $notice = $profile->getNotices(0, NOTICE_CACHE_WINDOW); - if ($notice) { + if (!empty($notice)) { $last = 0; while ($notice->fetch()) { if (time() - strtotime($notice->created) >= common_config('site', 'dupelimit')) { @@ -337,7 +363,7 @@ class Notice extends Memcached_DataObject static function checkEditThrottle($profile_id) { $profile = Profile::staticGet($profile_id); - if (!$profile) { + if (empty($profile)) { return false; } # Get the Nth notice @@ -658,7 +684,7 @@ class Notice extends Memcached_DataObject $cache = common_memcache(); - if (!$cache) { + if (empty($cache)) { return Notice::getStreamDirect($qry, $offset, $limit, null, null, $order, null); } @@ -719,7 +745,7 @@ class Notice extends Memcached_DataObject # If there are no hits, just return the value - if (!$notice) { + if (empty($notice)) { return $notice; } @@ -909,6 +935,18 @@ class Notice extends Memcached_DataObject } } + $recipients = $this->saveReplies(); + + foreach ($recipients as $recipient) { + + if (!array_key_exists($recipient, $ni)) { + $recipientUser = User::staticGet('id', $recipient); + if (!empty($recipientUser)) { + $ni[$recipient] = NOTICE_INBOX_SOURCE_REPLY; + } + } + } + $cnt = 0; $qryhdr = 'INSERT INTO notice_inbox (user_id, notice_id, source, created) VALUES '; @@ -1061,12 +1099,12 @@ class Notice extends Memcached_DataObject for ($i=0; $icreated); - if (!$recipient) { + if (empty($recipient)) { continue; } // Don't save replies from blocked profile to local user $recipient_user = User::staticGet('id', $recipient->id); - if ($recipient_user && $recipient_user->hasBlocked($sender)) { + if (!empty($recipient_user) && $recipient_user->hasBlocked($sender)) { continue; } $reply = new Reply(); @@ -1077,7 +1115,7 @@ class Notice extends Memcached_DataObject $last_error = &PEAR::getStaticProperty('DB_DataObject','lastError'); common_log(LOG_ERR, 'DB error inserting reply: ' . $last_error->message); common_server_error(sprintf(_('DB error inserting reply: %s'), $last_error->message)); - return; + return array(); } else { $replied[$recipient->id] = 1; } @@ -1101,7 +1139,7 @@ class Notice extends Memcached_DataObject $id = $reply->insert(); if (!$id) { common_log_db_error($reply, 'INSERT', __FILE__); - return; + return array(); } else { $replied[$recipient->id] = 1; } @@ -1110,12 +1148,16 @@ class Notice extends Memcached_DataObject } } - foreach (array_keys($replied) as $recipient) { + $recipientIds = array_keys($replied); + + foreach ($recipientIds as $recipient) { $user = User::staticGet('id', $recipient); if ($user) { mail_notify_attn($user, $this); } } + + return $recipientIds; } function asAtomEntry($namespace=false, $source=false) @@ -1139,10 +1181,9 @@ class Notice extends Memcached_DataObject $xs->element('link', array('href' => $profile->profileurl)); $user = User::staticGet('id', $profile->id); if (!empty($user)) { - $atom_feed = common_local_url('api', - array('apiaction' => 'statuses', - 'method' => 'user_timeline', - 'argument' => $profile->nickname.'.atom')); + $atom_feed = common_local_url('ApiTimelineUser', + array('format' => 'atom', + 'id' => $profile->nickname)); $xs->element('link', array('rel' => 'self', 'type' => 'application/atom+xml', 'href' => $profile->profileurl)); @@ -1370,4 +1411,21 @@ class Notice extends Memcached_DataObject $contentlimit = self::maxContent(); return ($contentlimit > 0 && !empty($content) && (mb_strlen($content) > $contentlimit)); } + + function getLocation() + { + $location = null; + + if (!empty($this->location_id) && !empty($this->location_ns)) { + $location = Location::fromId($this->location_id, $this->location_ns); + } + + if (is_null($location)) { // no ID, or Location::fromId() failed + if (!empty($this->lat) && !empty($this->lon)) { + $location = Location::fromLatLon($this->lat, $this->lon); + } + } + + return $location; + } } diff --git a/classes/Profile.php b/classes/Profile.php index 4a069ee84e..7c1e9db332 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -37,15 +37,26 @@ class Profile extends Memcached_DataObject public $homepage; // varchar(255) multiple_key public $bio; // text() multiple_key public $location; // varchar(255) multiple_key + public $lat; // decimal(10,7) + public $lon; // decimal(10,7) + public $location_id; // int(4) + public $location_ns; // int(4) public $created; // datetime() not_null public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP /* Static get */ - function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Profile',$k,$v); } + function staticGet($k,$v=NULL) { + return Memcached_DataObject::staticGet('Profile',$k,$v); + } /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE + function getUser() + { + return User::staticGet('id', $this->id); + } + function getAvatar($width, $height=null) { if (is_null($height)) { @@ -551,4 +562,29 @@ class Profile extends Memcached_DataObject $block->blocked = $this->id; $block->delete(); } + + // XXX: identical to Notice::getLocation. + + function getLocation() + { + $location = null; + + if (!empty($this->location_id) && !empty($this->location_ns)) { + $location = Location::fromId($this->location_id, $this->location_ns); + } + + if (is_null($location)) { // no ID, or Location::fromId() failed + if (!empty($this->lat) && !empty($this->lon)) { + $location = Location::fromLatLon($this->lat, $this->lon); + } + } + + if (is_null($location)) { // still haven't found it! + if (!empty($this->location)) { + $location = Location::fromName($this->location); + } + } + + return $location; + } } diff --git a/classes/User.php b/classes/User.php index 0a70c98014..3fa9cc1526 100644 --- a/classes/User.php +++ b/classes/User.php @@ -198,6 +198,15 @@ class User extends Memcached_DataObject } if (!empty($location)) { $profile->location = $location; + + $loc = Location::fromName($location); + + if (!empty($loc)) { + $profile->lat = $loc->lat; + $profile->lon = $loc->lon; + $profile->location_id = $loc->location_id; + $profile->location_ns = $loc->location_ns; + } } $profile->created = common_sql_now(); @@ -319,6 +328,7 @@ class User extends Memcached_DataObject common_config('site', 'name'), $user->nickname), 'system'); + common_broadcast_notice($notice); } } diff --git a/classes/statusnet.ini b/classes/statusnet.ini index 453981cd64..623790b100 100644 --- a/classes/statusnet.ini +++ b/classes/statusnet.ini @@ -1,3 +1,4 @@ + [avatar] profile_id = 129 original = 17 @@ -243,6 +244,15 @@ created = 142 [invitation__keys] code = K +[location_namespace] +id = 129 +description = 2 +created = 142 +modified = 384 + +[location_namespace__keys] +id = K + [message] id = 129 uri = 2 @@ -284,6 +294,10 @@ reply_to = 1 is_local = 17 source = 2 conversation = 1 +lat = 1 +lon = 1 +location_id = 1 +location_ns = 1 [notice__keys] id = N @@ -325,6 +339,10 @@ profileurl = 2 homepage = 2 bio = 34 location = 2 +lat = 1 +lon = 1 +location_id = 1 +location_ns = 1 created = 142 modified = 384 @@ -519,6 +537,16 @@ modified = 384 canonical = K display = U +[user_openid_trustroot] +trustroot = 130 +user_id = 129 +created = 142 +modified = 384 + +[user_openid__keys] +trustroot = K +user_id = K + [user_role] user_id = 129 role = 130 diff --git a/config.php.sample b/config.php.sample index 997c9d6b0b..9fccb84f3b 100644 --- a/config.php.sample +++ b/config.php.sample @@ -104,6 +104,10 @@ $config['sphinx']['port'] = 3312; // $config['site']['timezone'] = 'Pacific/Auckland'; // $config['site']['language'] = 'en_NZ'; +// When validating user supplied email addresses, validate if the domain +// is running an SMTP server. +// $config['mail']['check_domain'] = true; + // Email info, used for all outbound email // $config['mail']['notifyfrom'] = 'microblog@example.net'; // $config['mail']['domain'] = 'microblog.example.net'; diff --git a/db/location_namespace.sql b/db/location_namespace.sql new file mode 100644 index 0000000000..59b2ce67c3 --- /dev/null +++ b/db/location_namespace.sql @@ -0,0 +1,5 @@ +insert into location_namespace + (id, description, created) +values + (1, 'Geonames', now()), + (2, 'Where on Earth', now()); diff --git a/db/statusnet.sql b/db/statusnet.sql index dfcddb643c..1524d83957 100644 --- a/db/statusnet.sql +++ b/db/statusnet.sql @@ -1,6 +1,7 @@ /* local and remote users have profiles */ create table profile ( + id integer auto_increment primary key comment 'unique identifier', nickname varchar(64) not null comment 'nickname or username', fullname varchar(255) comment 'display name', @@ -8,6 +9,11 @@ create table profile ( homepage varchar(255) comment 'identifying URL', bio text comment 'descriptive biography', location varchar(255) comment 'physical location', + lat decimal(10,7) comment 'latitude', + lon decimal(10,7) comment 'longitude', + location_id integer comment 'location id if possible', + location_ns integer comment 'namespace for location', + created datetime not null comment 'date this record was created', modified timestamp comment 'date this record was modified', @@ -119,6 +125,10 @@ create table notice ( is_local tinyint default 0 comment 'notice was generated by a user', source varchar(32) comment 'source of comment, like "web", "im", or "clientname"', conversation integer comment 'id of root notice in this conversation' references notice (id), + lat decimal(10,7) comment 'latitude', + lon decimal(10,7) comment 'longitude', + location_id integer comment 'location id if possible', + location_ns integer comment 'namespace for location', index notice_profile_id_idx (profile_id), index notice_conversation_idx (conversation), @@ -556,3 +566,12 @@ create table user_role ( constraint primary key (user_id, role) ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; + +create table location_namespace ( + + id integer primary key comment 'identity for this namespace', + description varchar(255) comment 'description of the namespace', + created datetime not null comment 'date the record was created', + modified timestamp comment 'date this record was modified' + +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; diff --git a/doc-src/bookmarklet b/doc-src/bookmarklet index e5ded77023..6ce23bd0b6 100644 --- a/doc-src/bookmarklet +++ b/doc-src/bookmarklet @@ -2,4 +2,4 @@ A bookmarklet is a small piece of javascript code used as a bookmark. This one w Drag-and-drop the following link to your bookmarks bar or right-click it and add it to your browser favorites to keep it handy. -Post to %%site.name%% +Post to %%site.name%% diff --git a/extlib/Auth/OpenID.php b/extlib/Auth/OpenID.php index 6556b5b01e..db6164256f 100644 --- a/extlib/Auth/OpenID.php +++ b/extlib/Auth/OpenID.php @@ -20,7 +20,7 @@ /** * The library version string */ -define('Auth_OpenID_VERSION', '2.1.2'); +define('Auth_OpenID_VERSION', '2.1.3'); /** * Require the fetcher code. diff --git a/extlib/Auth/OpenID/BigMath.php b/extlib/Auth/OpenID/BigMath.php index b5fc627a09..45104947d6 100644 --- a/extlib/Auth/OpenID/BigMath.php +++ b/extlib/Auth/OpenID/BigMath.php @@ -376,7 +376,7 @@ function Auth_OpenID_detectMathLibrary($exts) // Try to load dynamic modules. if (!$loaded) { foreach ($extension['modules'] as $module) { - if (function_exists('dl') && ini_get('enable_dl') && !ini_get('safe_mode') && @dl($module . "." . PHP_SHLIB_SUFFIX)) { + if (@dl($module . "." . PHP_SHLIB_SUFFIX)) { $loaded = true; break; } diff --git a/extlib/Auth/OpenID/Consumer.php b/extlib/Auth/OpenID/Consumer.php index a72684c6b8..500890b656 100644 --- a/extlib/Auth/OpenID/Consumer.php +++ b/extlib/Auth/OpenID/Consumer.php @@ -1295,7 +1295,8 @@ class Auth_OpenID_GenericConsumer { Auth_OpenID_OPENID2_NS => array_merge($basic_sig_fields, array('response_nonce', 'claimed_id', - 'assoc_handle')), + 'assoc_handle', + 'op_endpoint')), Auth_OpenID_OPENID1_NS => array_merge($basic_sig_fields, array('nonce')) ); diff --git a/extlib/Auth/OpenID/Message.php b/extlib/Auth/OpenID/Message.php index fd23e67a3c..5ab115a86e 100644 --- a/extlib/Auth/OpenID/Message.php +++ b/extlib/Auth/OpenID/Message.php @@ -887,6 +887,11 @@ class Auth_OpenID_Message { function getAliasedArg($aliased_key, $default = null) { + if ($aliased_key == 'ns') { + // Return the namespace URI for the OpenID namespace + return $this->getOpenIDNamespace(); + } + $parts = explode('.', $aliased_key, 2); if (count($parts) != 2) { diff --git a/extlib/Auth/Yadis/HTTPFetcher.php b/extlib/Auth/Yadis/HTTPFetcher.php index a1825403d6..963b9a49a4 100644 --- a/extlib/Auth/Yadis/HTTPFetcher.php +++ b/extlib/Auth/Yadis/HTTPFetcher.php @@ -138,7 +138,7 @@ class Auth_Yadis_HTTPFetcher { * pass the URLHasAllowedScheme check or if the server's response * is malformed. */ - function get($url, $headers) + function get($url, $headers = null) { trigger_error("not implemented", E_USER_ERROR); } diff --git a/extlib/Auth/Yadis/ParanoidHTTPFetcher.php b/extlib/Auth/Yadis/ParanoidHTTPFetcher.php index 8975d7f89e..6a418260ee 100644 --- a/extlib/Auth/Yadis/ParanoidHTTPFetcher.php +++ b/extlib/Auth/Yadis/ParanoidHTTPFetcher.php @@ -127,8 +127,6 @@ class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher { Auth_OpenID_USER_AGENT.' '.$curl_user_agent); curl_setopt($c, CURLOPT_TIMEOUT, $off); curl_setopt($c, CURLOPT_URL, $url); - curl_setopt($c, CURLOPT_RANGE, - "0-".(1024 * Auth_OpenID_FETCHER_MAX_RESPONSE_KB)); curl_exec($c); diff --git a/extlib/Auth/Yadis/PlainHTTPFetcher.php b/extlib/Auth/Yadis/PlainHTTPFetcher.php index 8882e3cef7..3e0ca2bb0c 100644 --- a/extlib/Auth/Yadis/PlainHTTPFetcher.php +++ b/extlib/Auth/Yadis/PlainHTTPFetcher.php @@ -83,8 +83,6 @@ class Auth_Yadis_PlainHTTPFetcher extends Auth_Yadis_HTTPFetcher { "User-Agent: $user_agent", "Host: ".$parts['host']. ($specify_port ? ":".$parts['port'] : ""), - "Range: 0-". - (1024*Auth_OpenID_FETCHER_MAX_RESPONSE_KB), "Port: ".$parts['port']); $errno = 0; diff --git a/extlib/Auth/Yadis/XML.php b/extlib/Auth/Yadis/XML.php index 7232d6cbdd..81b2ce2210 100644 --- a/extlib/Auth/Yadis/XML.php +++ b/extlib/Auth/Yadis/XML.php @@ -91,7 +91,7 @@ class Auth_Yadis_XMLParser { * @return array $node_list An array of matching opaque node * objects to be used with other methods of this parser class. */ - function evalXPath($xpath, $node = null) + function &evalXPath($xpath, $node = null) { // Not implemented. } @@ -349,7 +349,7 @@ function &Auth_Yadis_getXMLParser() foreach ($extensions as $name => $params) { if (!extension_loaded($name)) { foreach ($params['libname'] as $libname) { - if (function_exists('dl') && ini_get('enable_dl') && !ini_get('safe_mode') && @dl($libname)) { + if (@dl($libname)) { $classname = $params['classname']; } } diff --git a/extlib/DB/DataObject.php b/extlib/DB/DataObject.php index 8e226b8fa9..60ff1441b5 100644 --- a/extlib/DB/DataObject.php +++ b/extlib/DB/DataObject.php @@ -235,7 +235,7 @@ class DB_DataObject extends DB_DataObject_Overload * @access private * @var string */ - var $_DB_DataObject_version = "1.8.11"; + var $_DB_DataObject_version = "1.8.12"; /** * The Database table (used by table extends) diff --git a/extlib/DB/DataObject/Cast.php b/extlib/DB/DataObject/Cast.php index 095d2a4d25..2049beb581 100644 --- a/extlib/DB/DataObject/Cast.php +++ b/extlib/DB/DataObject/Cast.php @@ -6,9 +6,9 @@ * * PHP versions 4 and 5 * - * LICENSE: This source file is subject to version 3.0 of the PHP license + * LICENSE: This source file is subject to version 3.01 of the PHP license * that is available through the world-wide-web at the following URI: - * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * http://www.php.net/license/3_01.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * @@ -16,8 +16,8 @@ * @package DB_DataObject * @author Alan Knowles * @copyright 1997-2008 The PHP Group - * @license http://www.php.net/license/3_0.txt PHP License 3.0 - * @version CVS: $Id: Cast.php 264148 2008-08-04 03:44:59Z alan_k $ + * @license http://www.php.net/license/3_01.txt PHP License 3.01 + * @version CVS: $Id: Cast.php 287158 2009-08-12 13:58:31Z alan_k $ * @link http://pear.php.net/package/DB_DataObject */ diff --git a/extlib/DB/DataObject/Error.php b/extlib/DB/DataObject/Error.php index 3821154537..cdb863d83c 100644 --- a/extlib/DB/DataObject/Error.php +++ b/extlib/DB/DataObject/Error.php @@ -7,9 +7,9 @@ * * PHP versions 4 and 5 * - * LICENSE: This source file is subject to version 3.0 of the PHP license + * LICENSE: This source file is subject to version 3.01 of the PHP license * that is available through the world-wide-web at the following URI: - * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * http://www.php.net/license/3_01.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * @@ -17,8 +17,8 @@ * @package DB_DataObject * @author Alan Knowles * @copyright 1997-2006 The PHP Group - * @license http://www.php.net/license/3_0.txt PHP License 3.0 - * @version CVS: $Id: Error.php 277015 2009-03-12 05:51:03Z alan_k $ + * @license http://www.php.net/license/3_01.txt PHP License 3.01 + * @version CVS: $Id: Error.php 287158 2009-08-12 13:58:31Z alan_k $ * @link http://pear.php.net/package/DB_DataObject */ diff --git a/extlib/README b/extlib/README new file mode 100644 index 0000000000..cfc2f9c8c4 --- /dev/null +++ b/extlib/README @@ -0,0 +1,58 @@ +DO NOT "FIX" CODE IN THIS DIRECTORY. + +ONLY UPSTREAM VERSIONS OF SOFTWARE GO IN THIS DIRECTORY. + +This directory is provided as a courtesy to our users who might be +unable or unwilling to find and install libraries we depend on. + +If we "fix" software in this directory, we hamstring users who do the +right thing and keep a single version of upstream libraries in a +system-wide library. We introduce subtle and maddening bugs where +our code is "accidentally" using the "wrong" library version. We may +unwittingly interfere with other software that depends on the +canonical release versions of those same libraries! + +Forking upstream software for trivial reasons makes us bad citizens in +the Open Source community and adds unnecessary heartache for our +users. Don't make us "that" project. + +FAQ: + +Q: What should we do when we find a bug in upstream software? + +A: First and foremost, REPORT THE BUG, and if possible send in a patch. + + Watch for a release of the upstream software and integrate with it + when it's released. + + In the meantime, work around the bug, if at all possible. Usually, + it's quite possible, if slightly harder or less efficient. + +Q: What if the bug can't be worked around? + +A: If the upstream developers have accepted a bug patch, it's + undesirable but acceptable to apply that patch to the library in + the extlib dir. Ideally, use a release version for upstream or a + version control system snapshot. + + Note that this is a last resort. + +Q: What if upstream is unresponsive or won't accept a patch? + +A: Try again. + +Q: I tried again, and upstream is still unresponsive and nobody's + checked on my patch. Now what? + +A: If the upstream project is moribund and there's a way to adopt it, + propose having the StatusNet dev team adopt the project. Or, adopt + it yourself. + +Q: What if there's no upstream authority and it can't be adopted? + +A: Then we fork it. Make a new name and a new version. Include it in + lib/ instead of extlib/, and use the StatusNet_* prefix to change + the namespace to avoid collisions. + + This is a last resort; consult with the rest of the dev group + before taking this radical step. diff --git a/extlib/php-gettext/ChangeLog b/extlib/php-gettext/ChangeLog index 5e0949dfd7..ab77d80810 100644 --- a/extlib/php-gettext/ChangeLog +++ b/extlib/php-gettext/ChangeLog @@ -1,3 +1,19 @@ +2006-02-28 Danilo Šegan + + * gettext.php: Added some comments about these workarounds for + different PHP versions and architectures. + +2006-02-28 Danilo Šegan + + Fixes bug #15923. + + * gettext.php (gettext_reader): make magic check work on 64-bit + platforms as well (by Steffen Pingel). + +2006-02-20 Danilo Šegan + + * gettext.inc (_bindtextdomain): Use php_uname to detect Windows. + 2006-02-07 Danilo Šegan * examples/pigs_dropin.php: comment-out bind_textdomain_codeset diff --git a/extlib/php-gettext/gettext.inc b/extlib/php-gettext/gettext.inc index eb94b256a6..7c95e40ec2 100644 --- a/extlib/php-gettext/gettext.inc +++ b/extlib/php-gettext/gettext.inc @@ -129,7 +129,7 @@ function _setlocale($category, $locale) { $ret = 0; if (function_exists('setlocale')) // I don't know if this ever happens ;) $ret = setlocale($category, $locale); - if (($ret and $locale == '') or ($ret == $locale)) { + if ($ret and ($locale == '' or $ret == $locale)) { $EMULATEGETTEXT = 0; $CURRENTLOCALE = $ret; } else { @@ -148,9 +148,9 @@ function _setlocale($category, $locale) { */ function _bindtextdomain($domain, $path) { global $text_domains; - // ensure $path ends with a slash - if ($path[strlen($path) - 1] != '/') $path .= '/'; - elseif ($path[strlen($path) - 1] != '\\') $path .= '\\'; + // ensure $path ends with a slash + if ($path[strlen($path) - 1] != '/') $path .= '/'; + elseif ($path[strlen($path) - 1] != '\\') $path .= '\\'; $text_domains[$domain]->path = $path; } diff --git a/extlib/php-gettext/gettext.php b/extlib/php-gettext/gettext.php index ad94a987b7..cd080444ca 100644 --- a/extlib/php-gettext/gettext.php +++ b/extlib/php-gettext/gettext.php @@ -102,16 +102,16 @@ class gettext_reader { // Caching can be turned off $this->enable_cache = $enable_cache; - // $MAGIC1 = (int)0x950412de; //bug in PHP 5 + // $MAGIC1 = (int)0x950412de; //bug in PHP 5.0.2, see https://savannah.nongnu.org/bugs/?func=detailitem&item_id=10565 $MAGIC1 = (int) - 1794895138; // $MAGIC2 = (int)0xde120495; //bug $MAGIC2 = (int) - 569244523; $this->STREAM = $Reader; $magic = $this->readint(); - if ($magic == $MAGIC1) { + if ($magic == ($MAGIC1 & 0xFFFFFFFF)) { // to make sure it works for 64-bit platforms $this->BYTEORDER = 0; - } elseif ($magic == $MAGIC2) { + } elseif ($magic == ($MAGIC2 & 0xFFFFFFFF)) { $this->BYTEORDER = 1; } else { $this->error = 1; // not MO file diff --git a/htaccess.sample b/htaccess.sample index 37eb8e01ec..91ae9da9be 100644 --- a/htaccess.sample +++ b/htaccess.sample @@ -5,6 +5,14 @@ RewriteBase /mublog/ + # If your site is private and want to only allow logged-in users to + # be able to download file attachments, uncomment this rule. + # + # If you have a custom attachment path + # ($config['attachments']['path']), change "file/" to match. + # + #RewriteRule ^file/(.*) getfile/$1 + RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule (.*) index.php?p=$1 [L,QSA] diff --git a/index.php b/index.php index 644812bd55..3acdba3754 100644 --- a/index.php +++ b/index.php @@ -143,7 +143,7 @@ function checkMirror($action_obj, $args) function isLoginAction($action) { - static $loginActions = array('login', 'recoverpassword', 'api', 'doc', 'register'); + static $loginActions = array('login', 'recoverpassword', 'api', 'doc', 'register', 'publicxrds'); $login = null; diff --git a/install.php b/install.php index 319c261e41..6bfc4c2e21 100644 --- a/install.php +++ b/install.php @@ -692,9 +692,7 @@ function writeConf($sitename, $server, $path, $fancy, $db) // database "\$config['db']['database'] = '{$db['database']}';\n\n". ($db['type'] == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n":''). - "\$config['db']['type'] = '{$db['type']}';\n\n". - - "?>"; + "\$config['db']['type'] = '{$db['type']}';\n\n"; // write configuration file out to install directory $res = file_put_contents(INSTALLDIR.'/config.php', $cfg); diff --git a/js/util.js b/js/util.js index 0a943512f2..663ec89863 100644 --- a/js/util.js +++ b/js/util.js @@ -14,370 +14,377 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . + * + * @category UI interaction + * @package StatusNet + * @author Sarven Capadisli + * @author Evan Prodromou + * @copyright 2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ */ $(document).ready(function(){ - var counterBlackout = false; - - // count character on keyup - function counter(event){ - if (maxLength <= 0) { - return; - } - var currentLength = $("#notice_data-text").val().length; - var remaining = maxLength - currentLength; - var counter = $("#notice_text-count"); - - if (remaining.toString() != counter.text()) { - if (!counterBlackout || remaining == 0) { - if (counter.text() != String(remaining)) { - counter.text(remaining); - } + if ($('body.user_in').length > 0) { + $('.'+SN.C.S.FormNotice).each(function() { SN.U.FormNoticeEnhancements($(this)); }); - if (remaining < 0) { - $("#form_notice").addClass("warning"); - } else { - $("#form_notice").removeClass("warning"); - } - // Skip updates for the next 500ms. - // On slower hardware, updating on every keypress is unpleasant. - if (!counterBlackout) { - counterBlackout = true; - window.setTimeout(clearCounterBlackout, 500); - } - } - } - } - - function clearCounterBlackout() { - // Allow keyup events to poke the counter again - counterBlackout = false; - // Check if the string changed since we last looked - counter(null); - } + $('.form_user_subscribe').each(function() { SN.U.FormXHR($(this)); }); + $('.form_user_unsubscribe').each(function() { SN.U.FormXHR($(this)); }); + $('.form_favor').each(function() { SN.U.FormXHR($(this)); }); + $('.form_disfavor').each(function() { SN.U.FormXHR($(this)); }); + $('.form_group_join').each(function() { SN.U.FormXHR($(this)); }); + $('.form_group_leave').each(function() { SN.U.FormXHR($(this)); }); + $('.form_user_nudge').each(function() { SN.U.FormXHR($(this)); }); - function submitonreturn(event) { - if (event.keyCode == 13 || event.keyCode == 10) { - // iPhone sends \n not \r for 'return' - $("#form_notice").submit(); - event.preventDefault(); - event.stopPropagation(); - $("#notice_data-text").blur(); - $("body").focus(); - return false; - } - return true; - } + SN.U.NoticeReply(); - // define maxLength if it wasn't defined already + SN.U.NoticeDataAttach(); - if (typeof(maxLength) == "undefined") { - maxLength = 140; + SN.U.NewDirectMessage(); } - if ($("#notice_data-text").length) { - if (maxLength > 0) { - $("#notice_data-text").bind("keyup", counter); - // run once in case there's something in there - counter(); - } - - $("#notice_data-text").bind("keydown", submitonreturn); - - if($('body')[0].id != 'conversation') { - $("#notice_data-text").focus(); - } - } - - // XXX: refactor this code - - var favoptions = { dataType: 'xml', - beforeSubmit: function(data, target, options) { - $(target).addClass('processing'); - return true; - }, - success: function(xml) { var new_form = document._importNode($('form', xml).get(0), true); - var dis = new_form.id; - var fav = dis.replace('disfavor', 'favor'); - $('form#'+fav).replaceWith(new_form); - $('form#'+dis).ajaxForm(disoptions).each(addAjaxHidden); - } - }; - - var disoptions = { dataType: 'xml', - beforeSubmit: function(data, target, options) { - $(target).addClass('processing'); - return true; - }, - success: function(xml) { var new_form = document._importNode($('form', xml).get(0), true); - var fav = new_form.id; - var dis = fav.replace('favor', 'disfavor'); - $('form#'+dis).replaceWith(new_form); - $('form#'+fav).ajaxForm(favoptions).each(addAjaxHidden); - } - }; - - var joinoptions = { dataType: 'xml', - success: function(xml) { var new_form = document._importNode($('form', xml).get(0), true); - var leave = new_form.id; - var join = leave.replace('leave', 'join'); - $('form#'+join).replaceWith(new_form); - $('form#'+leave).ajaxForm(leaveoptions).each(addAjaxHidden); - } - }; - - var leaveoptions = { dataType: 'xml', - success: function(xml) { var new_form = document._importNode($('form', xml).get(0), true); - var join = new_form.id; - var leave = join.replace('join', 'leave'); - $('form#'+leave).replaceWith(new_form); - $('form#'+join).ajaxForm(joinoptions).each(addAjaxHidden); - } - }; - - function addAjaxHidden() { - var ajax = document.createElement('input'); - ajax.setAttribute('type', 'hidden'); - ajax.setAttribute('name', 'ajax'); - ajax.setAttribute('value', 1); - this.appendChild(ajax); - } - - $("form.form_favor").ajaxForm(favoptions); - $("form.form_disfavor").ajaxForm(disoptions); - $("form.form_group_join").ajaxForm(joinoptions); - $("form.form_group_leave").ajaxForm(leaveoptions); - $("form.form_favor").each(addAjaxHidden); - $("form.form_disfavor").each(addAjaxHidden); - $("form.form_group_join").each(addAjaxHidden); - $("form.form_group_leave").each(addAjaxHidden); - - $("#form_user_nudge").ajaxForm ({ dataType: 'xml', - beforeSubmit: function(xml) { $("#form_user_nudge input[type=submit]").attr("disabled", "disabled"); - $("#form_user_nudge input[type=submit]").addClass("disabled"); - }, - success: function(xml) { $("#form_user_nudge").replaceWith(document._importNode($("#nudge_response", xml).get(0),true)); - $("#form_user_nudge input[type=submit]").removeAttr("disabled"); - $("#form_user_nudge input[type=submit]").removeClass("disabled"); - } - }); - $("#form_user_nudge").each(addAjaxHidden); - - var Subscribe = { dataType: 'xml', - beforeSubmit: function(formData, jqForm, options) { $(".form_user_subscribe input[type=submit]").attr("disabled", "disabled"); - $(".form_user_subscribe input[type=submit]").addClass("disabled"); - }, - success: function(xml) { var form_unsubscribe = document._importNode($('form', xml).get(0), true); - var form_unsubscribe_id = form_unsubscribe.id; - var form_subscribe_id = form_unsubscribe_id.replace('unsubscribe', 'subscribe'); - $("form#"+form_subscribe_id).replaceWith(form_unsubscribe); - $("form#"+form_unsubscribe_id).ajaxForm(UnSubscribe).each(addAjaxHidden); - $("dd.subscribers").text(parseInt($("dd.subscribers").text())+1); - $(".form_user_subscribe input[type=submit]").removeAttr("disabled"); - $(".form_user_subscribe input[type=submit]").removeClass("disabled"); - } - }; - - var UnSubscribe = { dataType: 'xml', - beforeSubmit: function(formData, jqForm, options) { $(".form_user_unsubscribe input[type=submit]").attr("disabled", "disabled"); - $(".form_user_unsubscribe input[type=submit]").addClass("disabled"); - }, - success: function(xml) { var form_subscribe = document._importNode($('form', xml).get(0), true); - var form_subscribe_id = form_subscribe.id; - var form_unsubscribe_id = form_subscribe_id.replace('subscribe', 'unsubscribe'); - $("form#"+form_unsubscribe_id).replaceWith(form_subscribe); - $("form#"+form_subscribe_id).ajaxForm(Subscribe).each(addAjaxHidden); - $("#profile_send_a_new_message").remove(); - $("#profile_nudge").remove(); - $("dd.subscribers").text(parseInt($("dd.subscribers").text())-1); - $(".form_user_unsubscribe input[type=submit]").removeAttr("disabled"); - $(".form_user_unsubscribe input[type=submit]").removeClass("disabled"); - } - }; - - $(".form_user_subscribe").ajaxForm(Subscribe); - $(".form_user_unsubscribe").ajaxForm(UnSubscribe); - $(".form_user_subscribe").each(addAjaxHidden); - $(".form_user_unsubscribe").each(addAjaxHidden); - - var PostNotice = { dataType: 'xml', - beforeSubmit: function(formData, jqForm, options) { if ($("#notice_data-text").get(0).value.length == 0) { - $("#form_notice").addClass("warning"); - return false; - } - $("#form_notice").addClass("processing"); - $("#notice_action-submit").attr("disabled", "disabled"); - $("#notice_action-submit").addClass("disabled"); - return true; - }, - timeout: '60000', - error: function (xhr, textStatus, errorThrown) { $("#form_notice").removeClass("processing"); - $("#notice_action-submit").removeAttr("disabled"); - $("#notice_action-submit").removeClass("disabled"); - if (textStatus == "timeout") { - alert ("Sorry! We had trouble sending your notice. The servers are overloaded. Please try again, and contact the site administrator if this problem persists"); - } - else { - if ($(".error", xhr.responseXML).length > 0) { - $('#form_notice').append(document._importNode($(".error", xhr.responseXML).get(0), true)); - } - else { - var HTTP20x30x = [200, 201, 202, 203, 204, 205, 206, 300, 301, 302, 303, 304, 305, 306, 307]; - if(jQuery.inArray(parseInt(xhr.status), HTTP20x30x) < 0) { - alert("Sorry! We had trouble sending your notice ("+xhr.status+" "+xhr.statusText+"). Please report the problem to the site administrator if this happens again."); - } - else { - $("#notice_data-text").val(""); - if (maxLength > 0) { - counter(); - } - } - } - } - }, - success: function(xml) { if ($("#error", xml).length > 0) { - var result = document._importNode($("p", xml).get(0), true); - result = result.textContent || result.innerHTML; - alert(result); - } - else { - if ($("#command_result", xml).length > 0) { - var result = document._importNode($("p", xml).get(0), true); - result = result.textContent || result.innerHTML; - alert(result); - } - else { - li = $("li", xml).get(0); - if ($("#"+li.id).length == 0) { - var notice_irt_value = $('#notice_in-reply-to').val(); - var notice_irt = '#notices_primary #notice-'+notice_irt_value; - if($('body')[0].id == 'conversation') { - if(notice_irt_value.length > 0 && $(notice_irt+' .notices').length < 1) { - $(notice_irt).append('
    '); - } - $($(notice_irt+' .notices')[0]).append(document._importNode(li, true)); - } - else { - $("#notices_primary .notices").prepend(document._importNode(li, true)); - } - $('#'+li.id).css({display:'none'}); - $('#'+li.id).fadeIn(2500); - NoticeReply(); - NoticeAttachments(); - } - } - $("#notice_data-text").val(""); - $("#notice_data-attach").val(""); - $("#notice_in-reply-to").val(""); - $('#notice_data-attach_selected').remove(); - if (maxLength > 0) { - counter(); - } - } - $("#form_notice").removeClass("processing"); - $("#notice_action-submit").removeAttr("disabled"); - $("#notice_action-submit").removeClass("disabled"); - } - }; - $("#form_notice").ajaxForm(PostNotice); - $("#form_notice").each(addAjaxHidden); - NoticeReply(); - NoticeAttachments(); - NoticeDataAttach(); + SN.U.NoticeAttachments(); }); -function NoticeReply() { - if ($('#notice_data-text').length > 0 && $('#content .notice_reply').length > 0) { - $('#content .notice').each(function() { - var notice = $(this)[0]; - $($('.notice_reply', notice)[0]).click(function() { - var nickname = ($('.author .nickname', notice).length > 0) ? $($('.author .nickname', notice)[0]) : $('.author .nickname.uid'); - NoticeReplySet(nickname.text(), $($('.notice_id', notice)[0]).text()); + +var SN = { // StatusNet + C: { // Config + I: { // Init + CounterBlackout: false, + MaxLength: 140, + PatternUsername: /^[0-9a-zA-Z\-_.]*$/, + HTTP20x30x: [200, 201, 202, 203, 204, 205, 206, 300, 301, 302, 303, 304, 305, 306, 307] + }, + + S: { // Selector + Disabled: 'disabled', + Warning: 'warning', + Error: 'error', + Success: 'success', + Processing: 'processing', + CommandResult: 'command_result', + FormNotice: 'form_notice', + NoticeDataText: 'notice_data-text', + NoticeTextCount: 'notice_text-count', + NoticeInReplyTo: 'notice_in-reply-to', + NoticeDataAttach: 'notice_data-attach', + NoticeDataAttachSelected: 'notice_data-attach_selected', + NoticeActionSubmit: 'notice_action-submit' + } + }, + + U: { // Utils + FormNoticeEnhancements: function(form) { + form_id = form.attr('id'); + if (maxLength > 0) { + $('#'+form_id+' #'+SN.C.S.NoticeDataText).bind('keyup', function(e) { + SN.U.Counter(form); + }); + // run once in case there's something in there + SN.U.Counter(form); + } + + $('#'+form_id+' #'+SN.C.S.NoticeDataText).bind('keydown', function(e) { + SN.U.SubmitOnReturn(e, form); + }); + + if($('body')[0].id != 'conversation') { + $('#'+form_id+' textarea').focus(); + } + + SN.U.FormNoticeXHR(form); + }, + + SubmitOnReturn: function(event, el) { + if (event.keyCode == 13 || event.keyCode == 10) { + el.submit(); + event.preventDefault(); + event.stopPropagation(); + $('#'+el[0].id+' #'+SN.U.NoticeDataText).blur(); + $('body').focus(); + return false; + } + return true; + }, + + Counter: function(form) { + SN.C.I.FormNoticeCurrent = form; + form_id = form.attr('id'); + if (typeof(maxLength) == "undefined") { + maxLength = SN.C.I.MaxLength; + } + + if (maxLength <= 0) { + return; + } + + var remaining = maxLength - $('#'+form_id+' #'+SN.C.S.NoticeDataText).val().length; + var counter = $('#'+form_id+' #'+SN.C.S.NoticeTextCount); + + if (remaining.toString() != counter.text()) { + if (!SN.C.I.CounterBlackout || remaining == 0) { + if (counter.text() != String(remaining)) { + counter.text(remaining); + } + if (remaining < 0) { + form.addClass(SN.C.S.Warning); + } else { + form.removeClass(SN.C.S.Warning); + } + // Skip updates for the next 500ms. + // On slower hardware, updating on every keypress is unpleasant. + if (!SN.C.I.CounterBlackout) { + SN.C.I.CounterBlackout = true; + SN.C.I.FormNoticeCurrent = form; + window.setTimeout("SN.U.ClearCounterBlackout(SN.C.I.FormNoticeCurrent);", 500); + } + } + } + }, + + ClearCounterBlackout: function(form) { + // Allow keyup events to poke the counter again + SN.C.I.CounterBlackout = false; + // Check if the string changed since we last looked + SN.U.Counter(form); + }, + + FormXHR: function(f) { + f.bind('submit', function(e) { + form_id = $(this)[0].id; + $.ajax({ + type: 'POST', + dataType: 'xml', + url: $(this)[0].action, + data: $(this).serialize() + '&ajax=1', + beforeSend: function(xhr) { + $('#'+form_id).addClass(SN.C.S.Processing); + $('#'+form_id+' .submit').addClass(SN.C.S.Disabled); + $('#'+form_id+' .submit').attr(SN.C.S.Disabled, SN.C.S.Disabled); + }, + error: function (xhr, textStatus, errorThrown) { + alert(errorThrown || textStatus); + }, + success: function(data, textStatus) { + if (typeof($('form', data)[0]) != 'undefined') { + form_new = document._importNode($('form', data)[0], true); + $('#'+form_id).replaceWith(form_new); + $('#'+form_new.id).each(function() { SN.U.FormXHR($(this)); }); + } + else { + $('#'+form_id).replaceWith(document._importNode($('p', data)[0], true)); + } + } + }); return false; }); - }); + }, + + FormNoticeXHR: function(form) { + form_id = form.attr('id'); + form.append(''); + form.ajaxForm({ + dataType: 'xml', + timeout: '60000', + beforeSend: function(xhr) { + if ($('#'+form_id+' #'+SN.C.S.NoticeDataText)[0].value.length === 0) { + form.addClass(SN.C.S.Warning); + return false; + } + form.addClass(SN.C.S.Processing); + $('#'+form_id+' #'+SN.C.S.NoticeActionSubmit).addClass(SN.C.S.Disabled); + $('#'+form_id+' #'+SN.C.S.NoticeActionSubmit).attr(SN.C.S.Disabled, SN.C.S.Disabled); + return true; + }, + error: function (xhr, textStatus, errorThrown) { + form.removeClass(SN.C.S.Processing); + $('#'+form_id+' #'+SN.C.S.NoticeActionSubmit).removeClass(SN.C.S.Disabled); + $('#'+form_id+' #'+SN.C.S.NoticeActionSubmit).removeAttr(SN.C.S.Disabled, SN.C.S.Disabled); + if (textStatus == 'timeout') { + alert ('Sorry! We had trouble sending your notice. The servers are overloaded. Please try again, and contact the site administrator if this problem persists'); + } + else { + if ($('.'+SN.C.S.Error, xhr.responseXML).length > 0) { + form.append(document._importNode($('.'+SN.C.S.Error, xhr.responseXML)[0], true)); + } + else { + if(jQuery.inArray(parseInt(xhr.status), SN.C.I.HTTP20x30x) < 0) { + alert('Sorry! We had trouble sending your notice ('+xhr.status+' '+xhr.statusText+'). Please report the problem to the site administrator if this happens again.'); + } + else { + $('#'+form_id+' #'+SN.C.S.NoticeDataText).val(''); + SN.U.Counter($('#'+SN.C.S.FormNotice)); + } + } + } + }, + success: function(data, textStatus) { + if ($('#'+SN.C.S.Error, data).length > 0) { + var result = document._importNode($('p', data)[0], true); + alert(result.textContent || result.innerHTML); + } + else { + if($('body')[0].id == 'bookmarklet') { + self.close(); + } + + if ($('#'+SN.C.S.CommandResult, data).length > 0) { + var result = document._importNode($('p', data)[0], true); + alert(result.textContent || result.innerHTML); + } + else { + notice = document._importNode($('li', data)[0], true); + if ($('#'+notice.id).length == 0) { + var notice_irt_value = $('#'+SN.C.S.NoticeInReplyTo).val(); + var notice_irt = '#notices_primary #notice-'+notice_irt_value; + if($('body')[0].id == 'conversation') { + if(notice_irt_value.length > 0 && $(notice_irt+' .notices').length < 1) { + $(notice_irt).append('
      '); + } + $($(notice_irt+' .notices')[0]).append(notice); + } + else { + $("#notices_primary .notices").prepend(notice); + } + $('#'+notice.id).css({display:'none'}); + $('#'+notice.id).fadeIn(2500); + SN.U.NoticeAttachments(); + SN.U.NoticeReply(); + } + } + $('#'+form_id+' #'+SN.C.S.NoticeDataText).val(''); + $('#'+form_id+' #'+SN.C.S.NoticeDataAttach).val(''); + $('#'+form_id+' #'+SN.C.S.NoticeInReplyTo).val(''); + $('#'+form_id+' #'+SN.C.S.NoticeDataAttachSelected).remove(); + SN.U.Counter($('#'+SN.C.S.FormNotice)); + } + }, + complete: function(xhr, textStatus) { + form.removeClass(SN.C.S.Processing); + $('#'+form_id+' #'+SN.C.S.NoticeActionSubmit).removeAttr(SN.C.S.Disabled); + $('#'+form_id+' #'+SN.C.S.NoticeActionSubmit).removeClass(SN.C.S.Disabled); + } + }); + }, + + NoticeReply: function() { + if ($('#'+SN.C.S.NoticeDataText).length > 0 && $('#content .notice_reply').length > 0) { + $('#content .notice').each(function() { + var notice = $(this)[0]; + $($('.notice_reply', notice)[0]).click(function() { + var nickname = ($('.author .nickname', notice).length > 0) ? $($('.author .nickname', notice)[0]) : $('.author .nickname.uid'); + SN.U.NoticeReplySet(nickname.text(), $($('.notice_id', notice)[0]).text()); + return false; + }); + }); + } + }, + + NoticeReplySet: function(nick,id) { + if (nick.match(SN.C.I.PatternUsername)) { + var text = $('#'+SN.C.S.NoticeDataText); + if (text.length) { + replyto = '@' + nick + ' '; + text.val(replyto + text.val().replace(RegExp(replyto, 'i'), '')); + $('#'+SN.C.S.FormNotice+' input#'+SN.C.S.NoticeInReplyTo).val(id); + if (text.get(0).setSelectionRange) { + var len = text.val().length; + text.get(0).setSelectionRange(len,len); + text.get(0).focus(); + } + return false; + } + } + return true; + }, + + NoticeAttachments: function() { + $.fn.jOverlay.options = { + method : 'GET', + data : '', + url : '', + color : '#000', + opacity : '0.6', + zIndex : 99, + center : false, + imgLoading : $('address .url')[0].href+'theme/base/images/illustrations/illu_progress_loading-01.gif', + bgClickToClose : true, + success : function() { + $('#jOverlayContent').append(''); + $('#jOverlayContent button').click($.closeOverlay); + }, + timeout : 0, + autoHide : true, + css : {'max-width':'542px', 'top':'5%', 'left':'32.5%'} + }; + + $('#content .notice a.attachment').click(function() { + $().jOverlay({url: $('address .url')[0].href+'attachment/' + ($(this).attr('id').substring('attachment'.length + 1)) + '/ajax'}); + return false; + }); + + var t; + $("body:not(#shownotice) #content .notice a.thumbnail").hover( + function() { + var anchor = $(this); + $("a.thumbnail").children('img').hide(); + anchor.closest(".entry-title").addClass('ov'); + + if (anchor.children('img').length == 0) { + t = setTimeout(function() { + $.get($('address .url')[0].href+'attachment/' + (anchor.attr('id').substring('attachment'.length + 1)) + '/thumbnail', null, function(data) { + anchor.append(data); + }); + }, 500); + } + else { + anchor.children('img').show(); + } + }, + function() { + clearTimeout(t); + $("a.thumbnail").children('img').hide(); + $(this).closest(".entry-title").removeClass('ov'); + } + ); + }, + + NoticeDataAttach: function() { + NDA = $('#'+SN.C.S.NoticeDataAttach); + NDA.change(function() { + S = '
      '+$(this).val()+'
      '; + NDAS = $('#'+SN.C.S.NoticeDataAttachSelected); + (NDAS.length > 0) ? NDAS.replaceWith(S) : $('#'+SN.C.S.FormNotice).append(S); + $('#'+SN.C.S.NoticeDataAttachSelected+' button').click(function(){ + $('#'+SN.C.S.NoticeDataAttachSelected).remove(); + NDA.val(''); + }); + }); + }, + + NewDirectMessage: function() { + NDM = $('.entity_send-a-message a'); + NDM.attr({'href':NDM.attr('href')+'&ajax=1'}); + NDM.click(function() { + var NDMF = $('.entity_send-a-message form'); + if (NDMF.length == 0) { + $.get(NDM.attr('href'), null, function(data) { + $('.entity_send-a-message').append(document._importNode($('form', data).get(0), true)); + NDMF = $('.entity_send-a-message .form_notice'); + SN.U.FormNoticeEnhancements(NDMF); + NDMF.append(''); + $('.entity_send-a-message button').click(function(){ + NDMF.hide(); + return false; + }); + }); + } + else { + NDMF.show(); + $('.entity_send-a-message textarea').focus(); + } + return false; + }); + } } } - -function NoticeReplySet(nick,id) { - rgx_username = /^[0-9a-zA-Z\-_.]*$/; - if (nick.match(rgx_username)) { - var text = $("#notice_data-text"); - if (text.length) { - replyto = "@" + nick + " "; - text.val(replyto + text.val().replace(RegExp(replyto, 'i'), '')); - $("#form_notice input#notice_in-reply-to").val(id); - if (text.get(0).setSelectionRange) { - var len = text.val().length; - text.get(0).setSelectionRange(len,len); - text.get(0).focus(); - } - return false; - } - } - return true; -} - -function NoticeAttachments() { - $.fn.jOverlay.options = { - method : 'GET', - data : '', - url : '', - color : '#000', - opacity : '0.6', - zIndex : 99, - center : false, - imgLoading : $('address .url')[0].href+'theme/base/images/illustrations/illu_progress_loading-01.gif', - bgClickToClose : true, - success : function() { - $('#jOverlayContent').append(''); - $('#jOverlayContent button').click($.closeOverlay); - }, - timeout : 0, - autoHide : true, - css : {'max-width':'542px', 'top':'5%', 'left':'32.5%'} - }; - - $('#content .notice a.attachment').click(function() { - $().jOverlay({url: $('address .url')[0].href+'attachment/' + ($(this).attr('id').substring('attachment'.length + 1)) + '/ajax'}); - return false; - }); - - var t; - $("body:not(#shownotice) #content .notice a.thumbnail").hover( - function() { - var anchor = $(this); - $("a.thumbnail").children('img').hide(); - anchor.closest(".entry-title").addClass('ov'); - - if (anchor.children('img').length == 0) { - t = setTimeout(function() { - $.get($('address .url')[0].href+'attachment/' + (anchor.attr('id').substring('attachment'.length + 1)) + '/thumbnail', null, function(data) { - anchor.append(data); - }); - }, 500); - } - else { - anchor.children('img').show(); - } - }, - function() { - clearTimeout(t); - $("a.thumbnail").children('img').hide(); - $(this).closest(".entry-title").removeClass('ov'); - } - ); -} - -function NoticeDataAttach() { - NDA = $('#notice_data-attach'); - NDA.change(function() { - S = '
      '+$(this).val()+'
      '; - NDAS = $('#notice_data-attach_selected'); - (NDAS.length > 0) ? NDAS.replaceWith(S) : $('#form_notice').append(S); - $('#notice_data-attach_selected button').click(function(){ - $('#notice_data-attach_selected').remove(); - NDA.val(''); - }); - }); -} diff --git a/lib/api.php b/lib/api.php index 7a63a4a785..9bd2083deb 100644 --- a/lib/api.php +++ b/lib/api.php @@ -134,11 +134,19 @@ class ApiAction extends Action $twitter_user['protected'] = false; # not supported by StatusNet yet $twitter_user['followers_count'] = $profile->subscriberCount(); - // To be supported soon... - $twitter_user['profile_background_color'] = ''; - $twitter_user['profile_text_color'] = ''; - $twitter_user['profile_link_color'] = ''; - $twitter_user['profile_sidebar_fill_color'] = ''; + // Need to pull up the user for some of this + $user = $profile->getUser(); + $design = $user->getDesign(); + $defaultDesign = Design::siteDesign(); + if (!$design) $design = $defaultDesign; + $color = Design::toWebColor(empty($design->backgroundcolor) ? $defaultDesign->backgroundcolor : $design->backgroundcolor); + $twitter_user['profile_background_color'] = ($color == null) ? '' : '#'.$color->hexValue(); + $color = Design::toWebColor(empty($design->textcolor) ? $defaultDesign->textcolor : $design->textcolor); + $twitter_user['profile_text_color'] = ($color == null) ? '' : '#'.$color->hexValue(); + $color = Design::toWebColor(empty($design->linkcolor) ? $defaultDesign->linkcolor : $design->linkcolor); + $twitter_user['profile_link_color'] = ($color == null) ? '' : '#'.$color->hexValue(); + $color = Design::toWebColor(empty($design->sidebarcolor) ? $defaultDesign->sidebarcolor : $design->sidebarcolor); + $twitter_user['profile_sidebar_fill_color'] = ($color == null) ? '' : '#'.$color->hexValue(); $twitter_user['profile_sidebar_border_color'] = ''; $twitter_user['friends_count'] = $profile->subscriptionCount(); @@ -147,8 +155,6 @@ class ApiAction extends Action $twitter_user['favourites_count'] = $profile->faveCount(); // British spelling! - // Need to pull up the user for some of this - $user = User::staticGet($profile->id); $timezone = 'UTC'; diff --git a/lib/command.php b/lib/command.php index 11d40b8e15..9efa406964 100644 --- a/lib/command.php +++ b/lib/command.php @@ -73,7 +73,7 @@ class UntrackCommand extends UnimplementedCommand } } -class NudgeCommand extends UnimplementedCommand +class NudgeCommand extends Command { var $other = null; function __construct($user, $other) @@ -81,6 +81,26 @@ class NudgeCommand extends UnimplementedCommand parent::__construct($user); $this->other = $other; } + function execute($channel) + { + $recipient = User::staticGet('nickname', $this->other); + if(! $recipient){ + $channel->error($this->user, sprintf(_('Could not find a user with nickname %s'), + $this->other)); + }else{ + if ($recipient->id == $this->user->id) { + $channel->error($this->user, _('It does not make a lot of sense to nudge yourself!')); + }else{ + if ($recipient->email && $recipient->emailnotifynudge) { + mail_notify_nudge($this->user, $recipient); + } + // XXX: notify by IM + // XXX: notify by SMS + $channel->output($this->user, sprintf(_('Nudge sent to %s'), + $recipient->nickname)); + } + } + } } class InviteCommand extends UnimplementedCommand @@ -124,18 +144,30 @@ class FavCommand extends Command function execute($channel) { + if(substr($this->other,0,1)=='#'){ + //favoriting a specific notice_id - $recipient = - common_relative_profile($this->user, common_canonical_nickname($this->other)); + $notice = Notice::staticGet(substr($this->other,1)); + if (!$notice) { + $channel->error($this->user, _('Notice with that id does not exist')); + return; + } + $recipient = $notice->getProfile(); + }else{ + //favoriting a given user's last notice - if (!$recipient) { - $channel->error($this->user, _('No such user.')); - return; - } - $notice = $recipient->getCurrentNotice(); - if (!$notice) { - $channel->error($this->user, _('User has no last notice')); - return; + $recipient = + common_relative_profile($this->user, common_canonical_nickname($this->other)); + + if (!$recipient) { + $channel->error($this->user, _('No such user.')); + return; + } + $notice = $recipient->getCurrentNotice(); + if (!$notice) { + $channel->error($this->user, _('User has no last notice')); + return; + } } $fave = Fave::addNew($this->user, $notice); @@ -347,6 +379,71 @@ class MessageCommand extends Command } } +class ReplyCommand extends Command +{ + var $other = null; + var $text = null; + function __construct($user, $other, $text) + { + parent::__construct($user); + $this->other = $other; + $this->text = $text; + } + + function execute($channel) + { + if(substr($this->other,0,1)=='#'){ + //replying to a specific notice_id + + $notice = Notice::staticGet(substr($this->other,1)); + if (!$notice) { + $channel->error($this->user, _('Notice with that id does not exist')); + return; + } + $recipient = $notice->getProfile(); + }else{ + //replying to a given user's last notice + + $recipient = + common_relative_profile($this->user, common_canonical_nickname($this->other)); + + if (!$recipient) { + $channel->error($this->user, _('No such user.')); + return; + } + $notice = $recipient->getCurrentNotice(); + if (!$notice) { + $channel->error($this->user, _('User has no last notice')); + return; + } + } + + $len = mb_strlen($this->text); + + if ($len == 0) { + $channel->error($this->user, _('No content!')); + return; + } + + $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'), + Notice::maxContent(), mb_strlen($this->text))); + return; + } + + $notice = Notice::saveNew($this->user->id, $this->text, $channel->source(), 1, + $notice->id); + if ($notice) { + $channel->output($this->user, sprintf(_('Reply to %s sent'), $recipient->nickname)); + } else { + $channel->error($this->user, _('Error saving notice.')); + } + common_broadcast_notice($notice); + } +} + class GetCommand extends Command { @@ -497,6 +594,9 @@ class HelpCommand extends Command "get - get last notice from user\n". "whois - get profile info on user\n". "fav - add user's last notice as a 'fave'\n". + "fav # - add notice with the given id as a 'fave'\n". + "reply # - reply to notice with a given id\n". + "reply - reply to the last notice from user\n". "join - join group\n". "drop - leave group\n". "stats - get your stats\n". @@ -507,7 +607,7 @@ class HelpCommand extends Command "last - same as 'get'\n". "on - not yet implemented.\n". "off - not yet implemented.\n". - "nudge - not yet implemented.\n". + "nudge - remind a user to update.\n". "invite - not yet implemented.\n". "track - not yet implemented.\n". "untrack - not yet implemented.\n". diff --git a/lib/commandinterpreter.php b/lib/commandinterpreter.php index 60fc4c3c44..b921a17cc2 100644 --- a/lib/commandinterpreter.php +++ b/lib/commandinterpreter.php @@ -134,6 +134,17 @@ class CommandInterpreter } else { return new MessageCommand($user, $other, $extra); } + case 'r': + case 'reply': + if (!$arg) { + return null; + } + list($other, $extra) = $this->split_arg($arg); + if (!$extra) { + return null; + } else { + return new ReplyCommand($user, $other, $extra); + } case 'whois': if (!$arg) { return null; diff --git a/lib/common.php b/lib/common.php index ce33c871bf..2c2f6869ee 100644 --- a/lib/common.php +++ b/lib/common.php @@ -185,7 +185,14 @@ function _have_config() } // XXX: Throw a conniption if database not installed - +// XXX: Find a way to use htmlwriter for this instead of handcoded markup +if (!_have_config()) { + echo '

      '. _('No configuation file found. ') .'

      '; + echo '

      '. _('I looked for configuration files in the following places: ') .'
      '. implode($_config_files, '
      '); + echo '

      '. _('You may wish to run the installer to fix this.') .'

      '; + echo ''. _('Go to the installer.') .''; + exit; +} // Fixup for statusnet.ini $_db_name = substr($config['db']['database'], strrpos($config['db']['database'], '/') + 1); @@ -223,7 +230,6 @@ require_once INSTALLDIR.'/lib/theme.php'; require_once INSTALLDIR.'/lib/mail.php'; require_once INSTALLDIR.'/lib/subs.php'; require_once INSTALLDIR.'/lib/Shorturl_api.php'; -require_once INSTALLDIR.'/lib/twitter.php'; require_once INSTALLDIR.'/lib/clientexception.php'; require_once INSTALLDIR.'/lib/serverexception.php'; diff --git a/lib/connectsettingsaction.php b/lib/connectsettingsaction.php index 2095a7cebf..e5fb8727ba 100644 --- a/lib/connectsettingsaction.php +++ b/lib/connectsettingsaction.php @@ -98,34 +98,37 @@ class ConnectSettingsNav extends Widget function show() { - # action => array('prompt', 'title') - $menu = array(); - if (common_config('xmpp', 'enabled')) { - $menu['imsettings'] = - array(_('IM'), - _('Updates by instant messenger (IM)')); - } - if (common_config('sms', 'enabled')) { - $menu['smssettings'] = - array(_('SMS'), - _('Updates by SMS')); - } - if (common_config('twitter', 'enabled')) { - $menu['twittersettings'] = - array(_('Twitter'), - _('Twitter integration options')); - } - $action_name = $this->action->trimmed('action'); $this->action->elementStart('ul', array('class' => 'nav')); - foreach ($menu as $menuaction => $menudesc) { - $this->action->menuItem(common_local_url($menuaction), - $menudesc[0], - $menudesc[1], - $action_name === $menuaction); + if (Event::handle('StartConnectSettingsNav', array(&$this->action))) { + + # action => array('prompt', 'title') + $menu = array(); + if (common_config('xmpp', 'enabled')) { + $menu['imsettings'] = + array(_('IM'), + _('Updates by instant messenger (IM)')); + } + if (common_config('sms', 'enabled')) { + $menu['smssettings'] = + array(_('SMS'), + _('Updates by SMS')); + } + + foreach ($menu as $menuaction => $menudesc) { + $this->action->menuItem(common_local_url($menuaction), + $menudesc[0], + $menudesc[1], + $action_name === $menuaction); + } + + Event::handle('EndConnectSettingsNav', array(&$this->action)); } $this->action->elementEnd('ul'); } + } + + diff --git a/lib/curlclient.php b/lib/curlclient.php index 36fc7d157e..c307c29844 100644 --- a/lib/curlclient.php +++ b/lib/curlclient.php @@ -1,4 +1,4 @@ -n 'http://i.creativecommons.org/l/by/3.0/80x15.png'), 'mail' => array('backend' => 'mail', - 'params' => null), + 'params' => null, + 'domain_check' => true), 'nickname' => array('blacklist' => array(), 'featured' => array()), @@ -140,21 +141,21 @@ $default = array('enabled' => true), 'sms' => array('enabled' => true), - 'twitterbridge' => + 'twitterimport' => array('enabled' => false), 'integration' => array('source' => 'StatusNet', # source attribute for Twitter 'taguri' => $_server.',2009'), # base for tag URIs - 'twitter' => - array('enabled' => true, - 'consumer_key' => null, - 'consumer_secret' => null), + 'twitter' => + array('enabled' => true, + 'consumer_key' => null, + 'consumer_secret' => null), 'memcached' => array('enabled' => false, 'server' => 'localhost', 'base' => null, 'port' => 11211), - 'ping' => + 'ping' => array('notify' => array()), 'inboxes' => array('enabled' => true), # ignored after 0.9.x @@ -200,12 +201,12 @@ $default = 'video/mp4', 'video/quicktime', 'video/mpeg'), - 'file_quota' => 5000000, - 'user_quota' => 50000000, - 'monthly_quota' => 15000000, - 'uploads' => true, - 'filecommand' => '/usr/bin/file', - ), + 'file_quota' => 5000000, + 'user_quota' => 50000000, + 'monthly_quota' => 15000000, + 'uploads' => true, + 'filecommand' => '/usr/bin/file', + ), 'group' => array('maxaliases' => 3, 'desclimit' => null), @@ -229,4 +230,6 @@ $default = array('contentlimit' => null), 'http' => array('client' => 'curl'), // XXX: should this be the default? + 'location' => + array('namespace' => 1), // 1 = geonames, 2 = Yahoo Where on Earth ); diff --git a/lib/httpclient.php b/lib/httpclient.php index c8c8ae5b26..f16e31e103 100644 --- a/lib/httpclient.php +++ b/lib/httpclient.php @@ -48,7 +48,7 @@ if (!defined('STATUSNET')) { class HTTPResponse { public $code = null; - public $headers = null; + public $headers = array(); public $body = null; } diff --git a/lib/jabber.php b/lib/jabber.php index 3dcdce5dbf..73f2ec6605 100644 --- a/lib/jabber.php +++ b/lib/jabber.php @@ -176,6 +176,7 @@ function jabber_format_entry($profile, $notice) $xs = new XMLStringer(); $xs->elementStart('html', array('xmlns' => 'http://jabber.org/protocol/xhtml-im')); $xs->elementStart('body', array('xmlns' => 'http://www.w3.org/1999/xhtml')); + $xs->element("img", array('src'=> $profile->avatarUrl(AVATAR_MINI_SIZE) , 'alt' => $profile->nickname)); $xs->element('a', array('href' => $profile->profileurl), $profile->nickname); $xs->text(": "); @@ -184,6 +185,11 @@ function jabber_format_entry($profile, $notice) } else { $xs->raw(common_render_content($notice->content, $notice)); } + $xs->raw(" "); + $xs->element('a', array( + 'href'=>common_local_url('conversation', + array('id' => $notice->conversation)).'#notice-'.$notice->id + ),sprintf(_('notice id: %s'),$notice->id)); $xs->elementEnd('body'); $xs->elementEnd('html'); diff --git a/lib/language.php b/lib/language.php index 561a4ddb82..7dcb808c96 100644 --- a/lib/language.php +++ b/lib/language.php @@ -101,35 +101,36 @@ function get_nice_language_list() */ function get_all_languages() { return array( - 'bg' => array('q' => 0.8, 'lang' => 'bg_BG', 'name' => 'Bulgarian', 'direction' => 'ltr'), - 'ca' => array('q' => 0.5, 'lang' => 'ca_ES', 'name' => 'Catalan', 'direction' => 'ltr'), - 'cs' => array('q' => 0.5, 'lang' => 'cs_CZ', 'name' => 'Czech', 'direction' => 'ltr'), - 'de' => array('q' => 0.8, 'lang' => 'de_DE', 'name' => 'German', 'direction' => 'ltr'), + 'bg' => array('q' => 0.8, 'lang' => 'bg', 'name' => 'Bulgarian', 'direction' => 'ltr'), + 'ca' => array('q' => 0.5, 'lang' => 'ca', 'name' => 'Catalan', 'direction' => 'ltr'), + 'cs' => array('q' => 0.5, 'lang' => 'cs', 'name' => 'Czech', 'direction' => 'ltr'), + 'de' => array('q' => 0.8, 'lang' => 'de', 'name' => 'German', 'direction' => 'ltr'), 'el' => array('q' => 0.1, 'lang' => 'el', 'name' => 'Greek', 'direction' => 'ltr'), - 'en-us' => array('q' => 1, 'lang' => 'en_US', 'name' => 'English (US)', 'direction' => 'ltr'), + 'en-us' => array('q' => 1, 'lang' => 'en', 'name' => 'English (US)', 'direction' => 'ltr'), 'en-gb' => array('q' => 1, 'lang' => 'en_GB', 'name' => 'English (British)', 'direction' => 'ltr'), - 'en' => array('q' => 1, 'lang' => 'en_US', 'name' => 'English (US)', 'direction' => 'ltr'), + 'en' => array('q' => 1, 'lang' => 'en', 'name' => 'English (US)', 'direction' => 'ltr'), 'es' => array('q' => 1, 'lang' => 'es', 'name' => 'Spanish', 'direction' => 'ltr'), 'fi' => array('q' => 1, 'lang' => 'fi', 'name' => 'Finnish', 'direction' => 'ltr'), - 'fr-fr' => array('q' => 1, 'lang' => 'fr_FR', 'name' => 'French', 'direction' => 'ltr'), - 'he' => array('q' => 0.5, 'lang' => 'he_IL', 'name' => 'Hebrew', 'direction' => 'rtl'), - 'it' => array('q' => 1, 'lang' => 'it_IT', 'name' => 'Italian', 'direction' => 'ltr'), - 'jp' => array('q' => 0.5, 'lang' => 'ja_JP', 'name' => 'Japanese', 'direction' => 'ltr'), - 'ko' => array('q' => 0.9, 'lang' => 'ko_KR', 'name' => 'Korean', 'direction' => 'ltr'), - 'mk' => array('q' => 0.5, 'lang' => 'mk_MK', 'name' => 'Macedonian', 'direction' => 'ltr'), - 'nb' => array('q' => 0.1, 'lang' => 'nb_NO', 'name' => 'Norwegian (Bokmål)', 'direction' => 'ltr'), - 'no' => array('q' => 0.1, 'lang' => 'nb_NO', 'name' => 'Norwegian (Bokmål)', 'direction' => 'ltr'), - 'nn' => array('q' => 1, 'lang' => 'nn_NO', 'name' => 'Norwegian (Nynorsk)', 'direction' => 'ltr'), - 'nl' => array('q' => 0.5, 'lang' => 'nl_NL', 'name' => 'Dutch', 'direction' => 'ltr'), - 'pl' => array('q' => 0.5, 'lang' => 'pl_PL', 'name' => 'Polish', 'direction' => 'ltr'), + 'fr-fr' => array('q' => 1, 'lang' => 'fr', 'name' => 'French', 'direction' => 'ltr'), + 'ga' => array('q' => 0.5, 'lang' => 'ga', 'name' => 'Galician', 'direction' => 'ltr'), + 'he' => array('q' => 0.5, 'lang' => 'he', 'name' => 'Hebrew', 'direction' => 'rtl'), + 'it' => array('q' => 1, 'lang' => 'it', 'name' => 'Italian', 'direction' => 'ltr'), + 'jp' => array('q' => 0.5, 'lang' => 'ja', 'name' => 'Japanese', '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'), + 'no' => array('q' => 0.1, 'lang' => 'nb', 'name' => 'Norwegian (Bokmål)', 'direction' => 'ltr'), + 'nn' => array('q' => 1, 'lang' => 'nn', 'name' => 'Norwegian (Nynorsk)', 'direction' => 'ltr'), + 'nl' => array('q' => 0.5, 'lang' => 'nl', 'name' => 'Dutch', 'direction' => 'ltr'), + 'pl' => array('q' => 0.5, 'lang' => 'pl', 'name' => 'Polish', 'direction' => 'ltr'), 'pt' => array('q' => 0.1, 'lang' => 'pt', 'name' => 'Portuguese', 'direction' => 'ltr'), 'pt-br' => array('q' => 0.9, 'lang' => 'pt_BR', 'name' => 'Portuguese Brazil', 'direction' => 'ltr'), - 'ru' => array('q' => 0.9, 'lang' => 'ru_RU', 'name' => 'Russian', 'direction' => 'ltr'), - 'sv' => array('q' => 0.8, 'lang' => 'sv_SE', 'name' => 'Swedish', 'direction' => 'ltr'), - 'te' => array('q' => 0.3, 'lang' => 'te_IN', 'name' => 'Telugu', 'direction' => 'ltr'), - 'tr' => array('q' => 0.5, 'lang' => 'tr_TR', 'name' => 'Turkish', 'direction' => 'ltr'), - 'uk' => array('q' => 1, 'lang' => 'uk_UA', 'name' => 'Ukrainian', 'direction' => 'ltr'), - 'vi' => array('q' => 0.8, 'lang' => 'vi_VN', 'name' => 'Vietnamese', 'direction' => 'ltr'), + 'ru' => array('q' => 0.9, 'lang' => 'ru', 'name' => 'Russian', 'direction' => 'ltr'), + 'sv' => array('q' => 0.8, 'lang' => 'sv', 'name' => 'Swedish', 'direction' => 'ltr'), + 'te' => array('q' => 0.3, 'lang' => 'te', 'name' => 'Telugu', 'direction' => 'ltr'), + 'tr' => array('q' => 0.5, 'lang' => 'tr', 'name' => 'Turkish', 'direction' => 'ltr'), + 'uk' => array('q' => 1, 'lang' => 'uk', 'name' => 'Ukrainian', 'direction' => 'ltr'), + 'vi' => array('q' => 0.8, 'lang' => 'vi', 'name' => 'Vietnamese', 'direction' => 'ltr'), 'zh-cn' => array('q' => 0.9, 'lang' => 'zh_CN', 'name' => 'Chinese (Simplified)', 'direction' => 'ltr'), 'zh-hant' => array('q' => 0.2, 'lang' => 'zh_TW', 'name' => 'Chinese (Taiwanese)', 'direction' => 'ltr'), ); diff --git a/lib/location.php b/lib/location.php new file mode 100644 index 0000000000..bbfc15a36d --- /dev/null +++ b/lib/location.php @@ -0,0 +1,188 @@ +. + * + * @category Location + * @package StatusNet + * @author Evan Prodromou + * @copyright 2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +/** + * class for locations + * + * These are stored in the DB as part of notice and profile records, + * but since they're about the same in both, we have a separate class + * for them. + * + * @category Location + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +class Location +{ + public $lat; + public $lon; + public $location_id; + public $location_ns; + private $_url; + + var $names = array(); + + /** + * Constructor that makes a Location from a string name + * + * @param string $name Human-readable name (any kind) + * @param string $language Language, default = common_language() + * + * @return Location Location with that name (or null if not found) + */ + + static function fromName($name, $language=null) + { + if (is_null($language)) { + $language = common_language(); + } + + $location = null; + + // Let a third-party handle it + + Event::handle('LocationFromName', array($name, $language, &$location)); + + return $location; + } + + /** + * Constructor that makes a Location from an ID + * + * @param integer $id Identifier ID + * @param integer $ns Namespace of the identifier + * @param string $language Language to return name in (default is common) + * + * @return Location The location with this ID (or null if none) + */ + + static function fromId($id, $ns, $language=null) + { + if (is_null($language)) { + $language = common_language(); + } + + $location = null; + + // Let a third-party handle it + + Event::handle('LocationFromId', array($id, $ns, $language, &$location)); + + return $location; + } + + /** + * Constructor that finds the nearest location to a lat/lon pair + * + * @param float $lat Latitude + * @param float $lon Longitude + * @param string $language Language for results, default = current + * + * @return Location the location found, or null if none found + */ + + static function fromLatLon($lat, $lon, $language=null) + { + if (is_null($language)) { + $language = common_language(); + } + + $location = null; + + // Let a third-party handle it + + if (Event::handle('LocationFromLatLon', + array($lat, $lon, $language, &$location))) { + // Default is just the lat/lon pair + + $location = new Location(); + + $location->lat = $lat; + $location->lon = $lon; + } + + return $location; + } + + /** + * Get the name for this location in the given language + * + * @param string $language language to use, default = current + * + * @return string location name or null if not found + */ + + function getName($language=null) + { + if (is_null($language)) { + $language = common_language(); + } + + if (array_key_exists($language, $this->names)) { + return $this->names[$language]; + } else { + $name = null; + Event::handle('LocationNameLanguage', array($this, $language, &$name)); + if (!empty($name)) { + $this->names[$language] = $name; + return $name; + } + } + } + + /** + * Get an URL suitable for this location + * + * @return string URL for this location or NULL + */ + + function getURL() + { + // Keep one cached + + if (is_string($this->_url)) { + return $this->_url; + } + + $url = null; + + Event::handle('LocationUrl', array($this, &$url)); + + $this->_url = $url; + + return $url; + } +} diff --git a/lib/mail.php b/lib/mail.php index 5bf4d74256..5218059e9d 100644 --- a/lib/mail.php +++ b/lib/mail.php @@ -640,75 +640,3 @@ function mail_notify_attn($user, $notice) mail_to_user($user, $subject, $body); } -/** - * Send a mail message to notify a user that her Twitter bridge link - * has stopped working, and therefore has been removed. This can - * happen when the user changes her Twitter password, or otherwise - * revokes access. - * - * @param User $user user whose Twitter bridge link has been removed - * - * @return boolean success flag - */ - -function mail_twitter_bridge_removed($user) -{ - common_init_locale($user->language); - - $profile = $user->getProfile(); - - $subject = sprintf(_('Your Twitter bridge has been disabled.')); - - $site_name = common_config('site', 'name'); - - $body = sprintf(_('Hi, %1$s. We\'re sorry to inform you that your ' . - 'link to Twitter has been disabled. We no longer seem to have ' . - 'permission to update your Twitter status. (Did you revoke ' . - '%3$s\'s access?)' . "\n\n" . - 'You can re-enable your Twitter bridge by visiting your ' . - "Twitter settings page:\n\n\t%2\$s\n\n" . - "Regards,\n%3\$s\n"), - $profile->getBestName(), - common_local_url('twittersettings'), - common_config('site', 'name')); - - common_init_locale(); - return mail_to_user($user, $subject, $body); -} - -/** - * Send a mail message to notify a user that her Facebook Application - * access has been removed. - * - * @param User $user user whose Facebook app link has been removed - * - * @return boolean success flag - */ - -function mail_facebook_app_removed($user) -{ - common_init_locale($user->language); - - $profile = $user->getProfile(); - - $site_name = common_config('site', 'name'); - - $subject = sprintf( - _('Your %1$s Facebook application access has been disabled.', - $site_name)); - - $body = sprintf(_("Hi, %1\$s. We're sorry to inform you that we are " . - 'unable to update your Facebook status from %2$s, and have disabled ' . - 'the Facebook application for your account. This may be because ' . - 'you have removed the Facebook application\'s authorization, or ' . - 'have deleted your Facebook account. You can re-enable the ' . - 'Facebook application and automatic status updating by ' . - "re-installing the %2\$s Facebook application.\n\nRegards,\n\n%2\$s"), - $user->nickname, $site_name); - - common_init_locale(); - return mail_to_user($user, $subject, $body); - -} - - diff --git a/lib/mediafile.php b/lib/mediafile.php new file mode 100644 index 0000000000..d4d184dd0f --- /dev/null +++ b/lib/mediafile.php @@ -0,0 +1,284 @@ +. + * + * @category Media + * @package StatusNet + * @author Robin Millette + * @author Zach Copley + * @copyright 2008-2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +class MediaFile +{ + + var $filename = null; + var $fileRecord = null; + var $user = null; + var $fileurl = null; + var $short_fileurl = null; + var $mimetype = null; + + function __construct($user = null, $filename = null, $mimetype = null) + { + if ($user == null) { + $this->user = common_current_user(); + } + + $this->filename = $filename; + $this->mimetype = $mimetype; + $this->fileRecord = $this->storeFile(); + + $this->fileurl = common_local_url('attachment', + array('attachment' => $this->fileRecord->id)); + + $this->maybeAddRedir($this->fileRecord->id, $this->fileurl); + $this->short_fileurl = common_shorten_url($this->fileurl); + $this->maybeAddRedir($this->fileRecord->id, $this->short_fileurl); + } + + function attachToNotice($notice) + { + File_to_post::processNew($this->fileRecord->id, $notice->id); + $this->maybeAddRedir($this->fileRecord->id, + common_local_url('file', array('notice' => $notice->id))); + } + + function shortUrl() + { + return $this->short_fileurl; + } + + function delete() + { + $filepath = File::path($this->filename); + @unlink($filepath); + } + + function storeFile() { + + $file = new File; + + $file->filename = $this->filename; + $file->url = File::url($this->filename); + $filepath = File::path($this->filename); + $file->size = filesize($filepath); + $file->date = time(); + $file->mimetype = $this->mimetype; + + $file_id = $file->insert(); + + if (!$file_id) { + common_log_db_error($file, "INSERT", __FILE__); + throw new ClientException(_('There was a database error while saving your file. Please try again.')); + } + + return $file; + } + + function rememberFile($file, $short) + { + $this->maybeAddRedir($file->id, $short); + } + + function maybeAddRedir($file_id, $url) + { + $file_redir = File_redirection::staticGet('url', $url); + + if (empty($file_redir)) { + + $file_redir = new File_redirection; + $file_redir->url = $url; + $file_redir->file_id = $file_id; + + $result = $file_redir->insert(); + + if (!$result) { + common_log_db_error($file_redir, "INSERT", __FILE__); + throw new ClientException(_('There was a database error while saving your file. Please try again.')); + } + } + } + + static function fromUpload($param = 'media', $user = null) + { + if (empty($user)) { + $user = common_current_user(); + } + + if (!isset($_FILES[$param]['error'])){ + return; + } + + switch ($_FILES[$param]['error']) { + case UPLOAD_ERR_OK: // success, jump out + break; + case UPLOAD_ERR_INI_SIZE: + throw new ClientException(_('The uploaded file exceeds the ' . + 'upload_max_filesize directive in php.ini.')); + return; + case UPLOAD_ERR_FORM_SIZE: + throw new ClientException( + _('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']); + throw new ClientException(_('The uploaded file was only' . + ' partially uploaded.')); + return; + case UPLOAD_ERR_NO_TMP_DIR: + throw new ClientException(_('Missing a temporary folder.')); + return; + case UPLOAD_ERR_CANT_WRITE: + throw new ClientException(_('Failed to write file to disk.')); + return; + case UPLOAD_ERR_EXTENSION: + throw new ClientException(_('File upload stopped by extension.')); + return; + default: + throw new ClientException(_('System error uploading file.')); + return; + } + + if (!MediaFile::respectsQuota($user, $_FILES['attach']['size'])) { + + // Should never actually get here + + @unlink($_FILES[$param]['tmp_name']); + throw new ClientException(_('File exceeds user\'s quota!')); + return; + } + + $mimetype = MediaFile::getUploadedFileType($_FILES[$param]['tmp_name']); + + $filename = null; + + if (isset($mimetype)) { + + $basename = basename($_FILES[$param]['name']); + $filename = File::filename($user->getProfile(), $basename, $mimetype); + $filepath = File::path($filename); + + $result = move_uploaded_file($_FILES[$param]['tmp_name'], $filepath); + + if (!$result) { + throw new ClientException(_('File could not be moved to destination directory.')); + return; + } + + } else { + throw new ClientException(_('Could not determine file\'s mime-type!')); + return; + } + + return new MediaFile($user, $filename, $mimetype); + } + + static function fromFilehandle($fh, $user) { + + $stream = stream_get_meta_data($fh); + + if (!MediaFile::respectsQuota($user, filesize($stream['uri']))) { + + // Should never actually get here + + throw new ClientException(_('File exceeds user\'s quota!')); + return; + } + + $mimetype = MediaFile::getUploadedFileType($fh); + + $filename = null; + + if (isset($mimetype)) { + + $filename = File::filename($user->getProfile(), "email", $mimetype); + + $filepath = File::path($filename); + + $result = copy($stream['uri'], $filepath) && chmod($filepath, 0664); + + if (!$result) { + throw new ClientException(_('File could not be moved to destination directory.' . + $stream['uri'] . ' ' . $filepath)); + } + } else { + throw new ClientException(_('Could not determine file\'s mime-type!')); + return; + } + + return new MediaFile($user, $filename, $mimetype); + } + + static function getUploadedFileType($f) { + require_once 'MIME/Type.php'; + + $cmd = &PEAR::getStaticProperty('MIME_Type', 'fileCmd'); + $cmd = common_config('attachments', 'filecommand'); + + $filetype = null; + + if (is_string($f)) { + + // assuming a filename + + $filetype = MIME_Type::autoDetect($f); + } else { + + // assuming a filehandle + + $stream = stream_get_meta_data($f); + $filetype = MIME_Type::autoDetect($stream['uri']); + } + + if (in_array($filetype, common_config('attachments', 'supported'))) { + return $filetype; + } + $media = MIME_Type::getMedia($filetype); + if ('application' !== $media) { + $hint = sprintf(_(' Try using another %s format.'), $media); + } else { + $hint = ''; + } + throw new ClientException(sprintf( + _('%s is not a supported filetype on this server.'), $filetype) . $hint); + } + + static function respectsQuota($user, $filesize) + { + $file = new File; + $result = $file->isRespectsQuota($user, $filesize); + if ($result === true) { + return true; + } else { + throw new ClientException($result); + } + } + +} \ No newline at end of file diff --git a/lib/messageform.php b/lib/messageform.php index e25ebfa08f..b034be3122 100644 --- a/lib/messageform.php +++ b/lib/messageform.php @@ -80,10 +80,21 @@ class MessageForm extends Form /** * ID of the form * - * @return int ID of the form + * @return string ID of the form */ function id() + { + return 'form_notice-direct'; + } + + /** + * Class of the form + * + * @return string class of the form + */ + + function formClass() { return 'form_notice'; } diff --git a/lib/noticeform.php b/lib/noticeform.php index 9864d15eb0..1be011c182 100644 --- a/lib/noticeform.php +++ b/lib/noticeform.php @@ -105,7 +105,7 @@ class NoticeForm extends Form /** * ID of the form * - * @return int ID of the form + * @return string ID of the form */ function id() @@ -113,6 +113,17 @@ class NoticeForm extends Form return 'form_notice'; } + /** + * Class of the form + * + * @return string class of the form + */ + + function formClass() + { + return 'form_notice'; + } + /** * Action of the form * diff --git a/lib/noticelist.php b/lib/noticelist.php index 6c296f82a7..8b3015cc3e 100644 --- a/lib/noticelist.php +++ b/lib/noticelist.php @@ -199,6 +199,7 @@ class NoticeListItem extends Widget { $this->out->elementStart('div', 'entry-content'); $this->showNoticeLink(); + $this->showNoticeLocation(); $this->showNoticeSource(); $this->showContext(); $this->out->elementEnd('div'); @@ -369,6 +370,44 @@ class NoticeListItem extends Widget $this->out->elementEnd('a'); } + /** + * show the notice location + * + * shows the notice location in the correct language. + * + * If an URL is available, makes a link. Otherwise, just a span. + * + * @return void + */ + + function showNoticeLocation() + { + $id = $this->notice->id; + + $location = $this->notice->getLocation(); + + if (empty($location)) { + return; + } + + $name = $location->getName(); + + if (empty($name)) { + // XXX: Could be a translation issue. Fall back to... something? + return; + } + + $url = $location->getUrl(); + + if (empty($url)) { + $this->out->element('span', array('class' => 'location'), $name); + } else { + $this->out->element('a', array('class' => 'location', + 'href' => $url), + $name); + } + } + /** * Show the source of the notice * diff --git a/lib/omb.php b/lib/omb.php index 0566701ff1..cd6d6e1b25 100644 --- a/lib/omb.php +++ b/lib/omb.php @@ -87,7 +87,7 @@ function omb_broadcast_notice($notice) common_debug('Posting to ' . $rp->postnoticeurl, __FILE__); /* Post notice. */ - $service = new Laconica_OMB_Service_Consumer( + $service = new StatusNet_OMB_Service_Consumer( array(OMB_ENDPOINT_POSTNOTICE => $rp->postnoticeurl)); try { $service->setToken($rp->token, $rp->secret); diff --git a/lib/profilelist.php b/lib/profilelist.php index 331430b3ef..5cc211e362 100644 --- a/lib/profilelist.php +++ b/lib/profilelist.php @@ -62,9 +62,15 @@ class ProfileList extends Widget function show() { - $this->startList(); - $cnt = $this->showProfiles(); - $this->endList(); + $cnt = 0; + + if (Event::handle('StartProfileList', array($this))) { + $this->startList(); + $cnt = $this->showProfiles(); + $this->endList(); + Event::handle('EndProfileList', array($this)); + } + return $cnt; } @@ -117,10 +123,19 @@ class ProfileListItem extends Widget function show() { - $this->startItem(); - $this->showProfile(); - $this->showActions(); - $this->endItem(); + if (Event::handle('StartProfileListItem', array($this))) { + $this->startItem(); + if (Event::handle('StartProfileListItemProfile', array($this))) { + $this->showProfile(); + Event::handle('EndProfileListItemProfile', array($this)); + } + if (Event::handle('StartProfileListItemActions', array($this))) { + $this->showActions(); + Event::handle('EndProfileListItemActions', array($this)); + } + $this->endItem(); + Event::handle('EndProfileListItem', array($this)); + } } function startItem() @@ -132,11 +147,29 @@ class ProfileListItem extends Widget function showProfile() { $this->startProfile(); - $this->showAvatar(); - $this->showFullName(); - $this->showLocation(); - $this->showHomepage(); - $this->showBio(); + if (Event::handle('StartProfileListItemProfileElements', array($this))) { + if (Event::handle('StartProfileListItemAvatar', array($this))) { + $this->showAvatar(); + Event::handle('EndProfileListItemAvatar', array($this)); + } + if (Event::handle('StartProfileListItemFullName', array($this))) { + $this->showFullName(); + Event::handle('EndProfileListItemFullName', array($this)); + } + if (Event::handle('StartProfileListItemLocation', array($this))) { + $this->showLocation(); + Event::handle('EndProfileListItemLocation', array($this)); + } + if (Event::handle('StartProfileListItemHomepage', array($this))) { + $this->showHomepage(); + Event::handle('EndProfileListItemHomepage', array($this)); + } + if (Event::handle('StartProfileListItemBio', array($this))) { + $this->showBio(); + Event::handle('EndProfileListItemBio', array($this)); + } + Event::handle('EndProfileListItemProfileElements', array($this)); + } $this->endProfile(); } @@ -225,7 +258,10 @@ class ProfileListItem extends Widget function showActions() { $this->startActions(); - $this->showSubscribeButton(); + if (Event::handle('StartProfileListItemActionElements', array($this))) { + $this->showSubscribeButton(); + Event::handle('EndProfileListItemActionElements', array($this)); + } $this->endActions(); } diff --git a/lib/queuehandler.php b/lib/queuehandler.php index 8c65a97c66..cd43b1e09a 100644 --- a/lib/queuehandler.php +++ b/lib/queuehandler.php @@ -27,6 +27,22 @@ define('CLAIM_TIMEOUT', 1200); define('QUEUE_HANDLER_MISS_IDLE', 10); define('QUEUE_HANDLER_HIT_IDLE', 0); +/** + * Base class for queue handlers. + * + * As extensions of the Daemon class, each queue handler has the ability + * to launch itself in the background, at which point it'll pass control + * to the configured QueueManager class to poll for updates. + * + * Subclasses must override at least the following methods: + * - transport + * - start + * - finish + * - handle_notice + * + * Some subclasses will also want to override the idle handler: + * - idle + */ class QueueHandler extends Daemon { @@ -39,6 +55,14 @@ class QueueHandler extends Daemon } } + /** + * How many seconds a polling-based queue manager should wait between + * checks for new items to handle. + * + * Defaults to 60 seconds; override to speed up or slow down. + * + * @return int timeout in seconds + */ function timeout() { return 60; @@ -54,24 +78,69 @@ class QueueHandler extends Daemon return strtolower($this->class_name().'.'.$this->get_id()); } + /** + * Return transport keyword which identifies items this queue handler + * services; must be defined for all subclasses. + * + * Must be 8 characters or less to fit in the queue_item database. + * ex "email", "jabber", "sms", "irc", ... + * + * @return string + */ function transport() { return null; } + /** + * Initialization, run when the queue handler starts. + * If this function indicates failure, the handler run will be aborted. + * + * @fixme run() will abort if this doesn't return true, + * but some subclasses don't bother. + * @return boolean true on success, false on failure + */ function start() { } + /** + * Cleanup, run when the queue handler ends. + * If this function indicates failure, a warning will be logged. + * + * @fixme run() will throw warnings if this doesn't return true, + * but many subclasses don't bother. + * @return boolean true on success, false on failure + */ function finish() { } + /** + * Here's the meat of your queue handler -- you're handed a Notice + * object, which you may do as you will with. + * + * If this function indicates failure, a warning will be logged + * and the item is placed back in the queue to be re-run. + * + * @param Notice $notice + * @return boolean true on success, false on failure + */ function handle_notice($notice) { return true; } + /** + * Setup and start of run loop for this queue handler as a daemon. + * Most of the heavy lifting is passed on to the QueueManager's service() + * method, which passes control back to our handle_notice() method for + * each notice that comes in on the queue. + * + * Most of the time this won't need to be overridden in a subclass. + * + * @return boolean true on success, false on failure + */ function run() { if (!$this->start()) { @@ -100,6 +169,14 @@ class QueueHandler extends Daemon return true; } + /** + * Called by QueueHandler after each handled item or empty polling cycle. + * This is a good time to e.g. service your XMPP connection. + * + * Doesn't need to be overridden if there's no maintenance to do. + * + * @param int $timeout seconds to sleep if there's nothing to do + */ function idle($timeout=0) { if ($timeout > 0) { diff --git a/lib/router.php b/lib/router.php index b9a45d867f..64853e4198 100644 --- a/lib/router.php +++ b/lib/router.php @@ -71,575 +71,574 @@ class Router { $m = Net_URL_Mapper::getInstance(); - // In the "root" + if (Event::handle('StartInitializeRouter', array(&$m))) { - $m->connect('', array('action' => 'public')); - $m->connect('rss', array('action' => 'publicrss')); - $m->connect('featuredrss', array('action' => 'featuredrss')); - $m->connect('favoritedrss', array('action' => 'favoritedrss')); - $m->connect('opensearch/people', array('action' => 'opensearch', - 'type' => 'people')); - $m->connect('opensearch/notice', array('action' => 'opensearch', - 'type' => 'notice')); + // In the "root" - // docs + $m->connect('', array('action' => 'public')); + $m->connect('rss', array('action' => 'publicrss')); + $m->connect('featuredrss', array('action' => 'featuredrss')); + $m->connect('favoritedrss', array('action' => 'favoritedrss')); + $m->connect('opensearch/people', array('action' => 'opensearch', + 'type' => 'people')); + $m->connect('opensearch/notice', array('action' => 'opensearch', + 'type' => 'notice')); - $m->connect('doc/:title', array('action' => 'doc')); + // docs - // Twitter + $m->connect('doc/:title', array('action' => 'doc')); - $m->connect('twitter/authorization', array('action' => 'twitterauthorization')); + // main stuff is repetitive - // facebook + $main = array('login', 'logout', 'register', 'subscribe', + 'unsubscribe', 'confirmaddress', 'recoverpassword', + 'invite', 'favor', 'disfavor', 'sup', + 'block', 'unblock', 'subedit', + 'groupblock', 'groupunblock'); - $m->connect('facebook', array('action' => 'facebookhome')); - $m->connect('facebook/index.php', array('action' => 'facebookhome')); - $m->connect('facebook/settings.php', array('action' => 'facebooksettings')); - $m->connect('facebook/invite.php', array('action' => 'facebookinvite')); - $m->connect('facebook/remove', array('action' => 'facebookremove')); + foreach ($main as $a) { + $m->connect('main/'.$a, array('action' => $a)); + } - // main stuff is repetitive + $m->connect('main/sup/:seconds', array('action' => 'sup'), + array('seconds' => '[0-9]+')); - $main = array('login', 'logout', 'register', 'subscribe', - 'unsubscribe', 'confirmaddress', 'recoverpassword', - 'invite', 'favor', 'disfavor', 'sup', - 'block', 'unblock', 'subedit', - 'groupblock', 'groupunblock'); + $m->connect('main/tagother/:id', array('action' => 'tagother')); - foreach ($main as $a) { - $m->connect('main/'.$a, array('action' => $a)); - } + $m->connect('main/oembed', + array('action' => 'oembed')); - $m->connect('main/sup/:seconds', array('action' => 'sup'), - array('seconds' => '[0-9]+')); + $m->connect('main/xrds', + array('action' => 'publicxrds')); - $m->connect('main/tagother/:id', array('action' => 'tagother')); + // these take a code - $m->connect('main/oembed', - array('action' => 'oembed')); + foreach (array('register', 'confirmaddress', 'recoverpassword') as $c) { + $m->connect('main/'.$c.'/:code', array('action' => $c)); + } - // these take a code + // exceptional - foreach (array('register', 'confirmaddress', 'recoverpassword') as $c) { - $m->connect('main/'.$c.'/:code', array('action' => $c)); - } + $m->connect('main/remote', array('action' => 'remotesubscribe')); + $m->connect('main/remote?nickname=:nickname', array('action' => 'remotesubscribe'), array('nickname' => '[A-Za-z0-9_-]+')); - // exceptional + foreach (Router::$bare as $action) { + $m->connect('index.php?action=' . $action, array('action' => $action)); + } - $m->connect('main/remote', array('action' => 'remotesubscribe')); - $m->connect('main/remote?nickname=:nickname', array('action' => 'remotesubscribe'), array('nickname' => '[A-Za-z0-9_-]+')); + // settings - foreach (Router::$bare as $action) { - $m->connect('index.php?action=' . $action, array('action' => $action)); - } + foreach (array('profile', 'avatar', 'password', 'im', + 'email', 'sms', 'userdesign', 'other') as $s) { + $m->connect('settings/'.$s, array('action' => $s.'settings')); + } - // settings + // search - foreach (array('profile', 'avatar', 'password', 'im', - 'email', 'sms', 'twitter', 'userdesign', 'other') as $s) { - $m->connect('settings/'.$s, array('action' => $s.'settings')); - } + foreach (array('group', 'people', 'notice') as $s) { + $m->connect('search/'.$s, array('action' => $s.'search')); + $m->connect('search/'.$s.'?q=:q', + array('action' => $s.'search'), + array('q' => '.+')); + } - // search - - foreach (array('group', 'people', 'notice') as $s) { - $m->connect('search/'.$s, array('action' => $s.'search')); - $m->connect('search/'.$s.'?q=:q', - array('action' => $s.'search'), + // The second of these is needed to make the link work correctly + // when inserted into the page. The first is needed to match the + // route on the way in. Seems to be another Net_URL_Mapper bug to me. + $m->connect('search/notice/rss', array('action' => 'noticesearchrss')); + $m->connect('search/notice/rss?q=:q', array('action' => 'noticesearchrss'), array('q' => '.+')); - } - // The second of these is needed to make the link work correctly - // when inserted into the page. The first is needed to match the - // route on the way in. Seems to be another Net_URL_Mapper bug to me. - $m->connect('search/notice/rss', array('action' => 'noticesearchrss')); - $m->connect('search/notice/rss?q=:q', array('action' => 'noticesearchrss'), - array('q' => '.+')); + $m->connect('attachment/:attachment', + array('action' => 'attachment'), + array('attachment' => '[0-9]+')); - $m->connect('attachment/:attachment', - array('action' => 'attachment'), - array('attachment' => '[0-9]+')); + $m->connect('attachment/:attachment/ajax', + array('action' => 'attachment_ajax'), + array('attachment' => '[0-9]+')); - $m->connect('attachment/:attachment/ajax', - array('action' => 'attachment_ajax'), - array('attachment' => '[0-9]+')); + $m->connect('attachment/:attachment/thumbnail', + array('action' => 'attachment_thumbnail'), + array('attachment' => '[0-9]+')); - $m->connect('attachment/:attachment/thumbnail', - array('action' => 'attachment_thumbnail'), - array('attachment' => '[0-9]+')); + $m->connect('notice/new', array('action' => 'newnotice')); + $m->connect('notice/new?replyto=:replyto', + array('action' => 'newnotice'), + array('replyto' => '[A-Za-z0-9_-]+')); + $m->connect('notice/new?replyto=:replyto&inreplyto=:inreplyto', + array('action' => 'newnotice'), + array('replyto' => '[A-Za-z0-9_-]+'), + array('inreplyto' => '[0-9]+')); - $m->connect('notice/new', array('action' => 'newnotice')); - $m->connect('notice/new?replyto=:replyto', - array('action' => 'newnotice'), - array('replyto' => '[A-Za-z0-9_-]+')); - $m->connect('notice/new?replyto=:replyto&inreplyto=:inreplyto', - array('action' => 'newnotice'), - array('replyto' => '[A-Za-z0-9_-]+'), - array('inreplyto' => '[0-9]+')); + $m->connect('notice/:notice/file', + array('action' => 'file'), + array('notice' => '[0-9]+')); - $m->connect('notice/:notice/file', - array('action' => 'file'), - array('notice' => '[0-9]+')); + $m->connect('notice/:notice', + array('action' => 'shownotice'), + array('notice' => '[0-9]+')); + $m->connect('notice/delete', array('action' => 'deletenotice')); + $m->connect('notice/delete/:notice', + array('action' => 'deletenotice'), + array('notice' => '[0-9]+')); - $m->connect('notice/:notice', - array('action' => 'shownotice'), - array('notice' => '[0-9]+')); - $m->connect('notice/delete', array('action' => 'deletenotice')); - $m->connect('notice/delete/:notice', - array('action' => 'deletenotice'), - array('notice' => '[0-9]+')); + $m->connect('bookmarklet/new', array('action' => 'bookmarklet')); - // conversation + // conversation - $m->connect('conversation/:id', - array('action' => 'conversation'), - array('id' => '[0-9]+')); + $m->connect('conversation/:id', + array('action' => 'conversation'), + array('id' => '[0-9]+')); - $m->connect('message/new', array('action' => 'newmessage')); - $m->connect('message/new?to=:to', array('action' => 'newmessage'), array('to' => '[A-Za-z0-9_-]+')); - $m->connect('message/:message', - array('action' => 'showmessage'), - array('message' => '[0-9]+')); + $m->connect('message/new', array('action' => 'newmessage')); + $m->connect('message/new?to=:to', array('action' => 'newmessage'), array('to' => '[A-Za-z0-9_-]+')); + $m->connect('message/:message', + array('action' => 'showmessage'), + array('message' => '[0-9]+')); - $m->connect('user/:id', - array('action' => 'userbyid'), - array('id' => '[0-9]+')); + $m->connect('user/:id', + array('action' => 'userbyid'), + array('id' => '[0-9]+')); - $m->connect('tags/', array('action' => 'publictagcloud')); - $m->connect('tag/', array('action' => 'publictagcloud')); - $m->connect('tags', array('action' => 'publictagcloud')); - $m->connect('tag', array('action' => 'publictagcloud')); - $m->connect('tag/:tag/rss', - array('action' => 'tagrss'), - array('tag' => '[a-zA-Z0-9]+')); - $m->connect('tag/:tag', - array('action' => 'tag'), - array('tag' => '[\pL\pN_\-\.]{1,64}')); + $m->connect('tags/', array('action' => 'publictagcloud')); + $m->connect('tag/', array('action' => 'publictagcloud')); + $m->connect('tags', array('action' => 'publictagcloud')); + $m->connect('tag', array('action' => 'publictagcloud')); + $m->connect('tag/:tag/rss', + array('action' => 'tagrss'), + array('tag' => '[a-zA-Z0-9]+')); + $m->connect('tag/:tag', + array('action' => 'tag'), + array('tag' => '[\pL\pN_\-\.]{1,64}')); - $m->connect('peopletag/:tag', - array('action' => 'peopletag'), - array('tag' => '[a-zA-Z0-9]+')); + $m->connect('peopletag/:tag', + array('action' => 'peopletag'), + array('tag' => '[a-zA-Z0-9]+')); - $m->connect('featured/', array('action' => 'featured')); - $m->connect('featured', array('action' => 'featured')); - $m->connect('favorited/', array('action' => 'favorited')); - $m->connect('favorited', array('action' => 'favorited')); + $m->connect('featured/', array('action' => 'featured')); + $m->connect('featured', array('action' => 'featured')); + $m->connect('favorited/', array('action' => 'favorited')); + $m->connect('favorited', array('action' => 'favorited')); - // groups + // groups - $m->connect('group/new', array('action' => 'newgroup')); + $m->connect('group/new', array('action' => 'newgroup')); - foreach (array('edit', 'join', 'leave') as $v) { - $m->connect('group/:nickname/'.$v, - array('action' => $v.'group'), + foreach (array('edit', 'join', 'leave') as $v) { + $m->connect('group/:nickname/'.$v, + array('action' => $v.'group'), + array('nickname' => '[a-zA-Z0-9]+')); + } + + foreach (array('members', 'logo', 'rss', 'designsettings') as $n) { + $m->connect('group/:nickname/'.$n, + array('action' => 'group'.$n), + array('nickname' => '[a-zA-Z0-9]+')); + } + + $m->connect('group/:nickname/foaf', + array('action' => 'foafgroup'), array('nickname' => '[a-zA-Z0-9]+')); - } - foreach (array('members', 'logo', 'rss', 'designsettings') as $n) { - $m->connect('group/:nickname/'.$n, - array('action' => 'group'.$n), + $m->connect('group/:nickname/blocked', + array('action' => 'blockedfromgroup'), array('nickname' => '[a-zA-Z0-9]+')); - } - - $m->connect('group/:nickname/foaf', - array('action' => 'foafgroup'), - array('nickname' => '[a-zA-Z0-9]+')); - - $m->connect('group/:nickname/blocked', - array('action' => 'blockedfromgroup'), - array('nickname' => '[a-zA-Z0-9]+')); - - $m->connect('group/:nickname/makeadmin', - array('action' => 'makeadmin'), - array('nickname' => '[a-zA-Z0-9]+')); - - $m->connect('group/:id/id', - array('action' => 'groupbyid'), - array('id' => '[0-9]+')); - - $m->connect('group/:nickname', - array('action' => 'showgroup'), - array('nickname' => '[a-zA-Z0-9]+')); - - $m->connect('group/', array('action' => 'groups')); - $m->connect('group', array('action' => 'groups')); - $m->connect('groups/', array('action' => 'groups')); - $m->connect('groups', array('action' => 'groups')); - - // Twitter-compatible API - - // statuses API - - $m->connect('api/statuses/public_timeline.:format', - array('action' => 'ApiTimelinePublic', - 'format' => '(xml|json|rss|atom)')); - $m->connect('api/statuses/friends_timeline.:format', - array('action' => 'ApiTimelineFriends', - 'format' => '(xml|json|rss|atom)')); + $m->connect('group/:nickname/makeadmin', + array('action' => 'makeadmin'), + array('nickname' => '[a-zA-Z0-9]+')); + + $m->connect('group/:id/id', + array('action' => 'groupbyid'), + array('id' => '[0-9]+')); + + $m->connect('group/:nickname', + array('action' => 'showgroup'), + array('nickname' => '[a-zA-Z0-9]+')); + + $m->connect('group/', array('action' => 'groups')); + $m->connect('group', array('action' => 'groups')); + $m->connect('groups/', array('action' => 'groups')); + $m->connect('groups', array('action' => 'groups')); + + // Twitter-compatible API + + // statuses API + + $m->connect('api/statuses/public_timeline.:format', + array('action' => 'ApiTimelinePublic', + 'format' => '(xml|json|rss|atom)')); + + $m->connect('api/statuses/friends_timeline.:format', + array('action' => 'ApiTimelineFriends', + 'format' => '(xml|json|rss|atom)')); + + $m->connect('api/statuses/friends_timeline/:id.:format', + array('action' => 'ApiTimelineFriends', + 'id' => '[a-zA-Z0-9]+', + 'format' => '(xml|json|rss|atom)')); + $m->connect('api/statuses/home_timeline.:format', + array('action' => 'ApiTimelineFriends', + 'format' => '(xml|json|rss|atom)')); + + $m->connect('api/statuses/home_timeline/:id.:format', + array('action' => 'ApiTimelineFriends', + 'id' => '[a-zA-Z0-9]+', + 'format' => '(xml|json|rss|atom)')); - $m->connect('api/statuses/friends_timeline/:id.:format', - array('action' => 'ApiTimelineFriends', - 'id' => '[a-zA-Z0-9]+', - 'format' => '(xml|json|rss|atom)')); - $m->connect('api/statuses/home_timeline.:format', - array('action' => 'ApiTimelineFriends', - 'format' => '(xml|json|rss|atom)')); + $m->connect('api/statuses/user_timeline.:format', + array('action' => 'ApiTimelineUser', + 'format' => '(xml|json|rss|atom)')); - $m->connect('api/statuses/home_timeline/:id.:format', - array('action' => 'ApiTimelineFriends', - 'id' => '[a-zA-Z0-9]+', - 'format' => '(xml|json|rss|atom)')); - - $m->connect('api/statuses/user_timeline.:format', - array('action' => 'ApiTimelineUser', - 'format' => '(xml|json|rss|atom)')); - - $m->connect('api/statuses/user_timeline/:id.:format', - array('action' => 'ApiTimelineUser', - 'id' => '[a-zA-Z0-9]+', - 'format' => '(xml|json|rss|atom)')); + $m->connect('api/statuses/user_timeline/:id.:format', + array('action' => 'ApiTimelineUser', + 'id' => '[a-zA-Z0-9]+', + 'format' => '(xml|json|rss|atom)')); + + $m->connect('api/statuses/mentions.:format', + array('action' => 'ApiTimelineMentions', + 'format' => '(xml|json|rss|atom)')); + + $m->connect('api/statuses/mentions/:id.:format', + array('action' => 'ApiTimelineMentions', + 'id' => '[a-zA-Z0-9]+', + 'format' => '(xml|json|rss|atom)')); + + $m->connect('api/statuses/replies.:format', + array('action' => 'ApiTimelineMentions', + 'format' => '(xml|json|rss|atom)')); + + $m->connect('api/statuses/replies/:id.:format', + array('action' => 'ApiTimelineMentions', + 'id' => '[a-zA-Z0-9]+', + 'format' => '(xml|json|rss|atom)')); + + $m->connect('api/statuses/friends.:format', + array('action' => 'ApiUserFriends', + 'format' => '(xml|json)')); + + $m->connect('api/statuses/friends/:id.:format', + array('action' => 'ApiUserFriends', + 'id' => '[a-zA-Z0-9]+', + 'format' => '(xml|json)')); - $m->connect('api/statuses/mentions.:format', - array('action' => 'ApiTimelineMentions', - 'format' => '(xml|json|rss|atom)')); + $m->connect('api/statuses/followers.:format', + array('action' => 'ApiUserFollowers', + 'format' => '(xml|json)')); - $m->connect('api/statuses/mentions/:id.:format', - array('action' => 'ApiTimelineMentions', - 'id' => '[a-zA-Z0-9]+', - 'format' => '(xml|json|rss|atom)')); + $m->connect('api/statuses/followers/:id.:format', + array('action' => 'ApiUserFollowers', + 'id' => '[a-zA-Z0-9]+', + 'format' => '(xml|json)')); - $m->connect('api/statuses/replies.:format', - array('action' => 'ApiTimelineMentions', - 'format' => '(xml|json|rss|atom)')); - - $m->connect('api/statuses/replies/:id.:format', - array('action' => 'ApiTimelineMentions', - 'id' => '[a-zA-Z0-9]+', - 'format' => '(xml|json|rss|atom)')); + $m->connect('api/statuses/show.:format', + array('action' => 'ApiStatusesShow', + 'format' => '(xml|json)')); - $m->connect('api/statuses/friends.:format', - array('action' => 'ApiUserFriends', - 'format' => '(xml|json)')); + $m->connect('api/statuses/show/:id.:format', + array('action' => 'ApiStatusesShow', + 'id' => '[0-9]+', + 'format' => '(xml|json)')); - $m->connect('api/statuses/friends/:id.:format', - array('action' => 'ApiUserFriends', - 'id' => '[a-zA-Z0-9]+', - 'format' => '(xml|json)')); - - $m->connect('api/statuses/followers.:format', - array('action' => 'ApiUserFollowers', - 'format' => '(xml|json)')); - - $m->connect('api/statuses/followers/:id.:format', - array('action' => 'ApiUserFollowers', - 'id' => '[a-zA-Z0-9]+', - 'format' => '(xml|json)')); + $m->connect('api/statuses/update.:format', + array('action' => 'ApiStatusesUpdate', + 'format' => '(xml|json)')); - $m->connect('api/statuses/show.:format', - array('action' => 'ApiStatusesShow', - 'format' => '(xml|json)')); + $m->connect('api/statuses/destroy.:format', + array('action' => 'ApiStatusesDestroy', + 'format' => '(xml|json)')); - $m->connect('api/statuses/show/:id.:format', - array('action' => 'ApiStatusesShow', - 'id' => '[0-9]+', - 'format' => '(xml|json)')); + $m->connect('api/statuses/destroy/:id.:format', + array('action' => 'ApiStatusesDestroy', + 'id' => '[0-9]+', + 'format' => '(xml|json)')); - $m->connect('api/statuses/update.:format', - array('action' => 'ApiStatusesUpdate', - 'format' => '(xml|json)')); + // users - $m->connect('api/statuses/destroy.:format', - array('action' => 'ApiStatusesDestroy', - 'format' => '(xml|json)')); + $m->connect('api/users/show/:id.:format', + array('action' => 'ApiUserShow', + 'id' => '[a-zA-Z0-9]+', + 'format' => '(xml|json)')); - $m->connect('api/statuses/destroy/:id.:format', - array('action' => 'ApiStatusesDestroy', - 'id' => '[0-9]+', - 'format' => '(xml|json)')); + $m->connect('api/users/:method', + array('action' => 'api', + 'apiaction' => 'users'), + array('method' => 'show(\.(xml|json))?')); - // users + // direct messages - $m->connect('api/users/show/:id.:format', - array('action' => 'ApiUserShow', - 'id' => '[a-zA-Z0-9]+', - 'format' => '(xml|json)')); + $m->connect('api/direct_messages.:format', + array('action' => 'ApiDirectMessage', + 'format' => '(xml|json|rss|atom)')); - $m->connect('api/users/:method', - array('action' => 'api', - 'apiaction' => 'users'), - array('method' => 'show(\.(xml|json))?')); + $m->connect('api/direct_messages/sent.:format', + array('action' => 'ApiDirectMessage', + 'format' => '(xml|json|rss|atom)', + 'sent' => true)); - // direct messages + $m->connect('api/direct_messages/new.:format', + array('action' => 'ApiDirectMessageNew', + 'format' => '(xml|json)')); + // friendships - $m->connect('api/direct_messages.:format', - array('action' => 'ApiDirectMessage', - 'format' => '(xml|json|rss|atom)')); + $m->connect('api/friendships/show.:format', + array('action' => 'ApiFriendshipsShow', + 'format' => '(xml|json)')); - $m->connect('api/direct_messages/sent.:format', - array('action' => 'ApiDirectMessage', - 'format' => '(xml|json|rss|atom)', - 'sent' => true)); + $m->connect('api/friendships/exists.:format', + array('action' => 'ApiFriendshipsExists', + 'format' => '(xml|json)')); - $m->connect('api/direct_messages/new.:format', - array('action' => 'ApiDirectMessageNew', - 'format' => '(xml|json)')); + $m->connect('api/friendships/create.:format', + array('action' => 'ApiFriendshipsCreate', + 'format' => '(xml|json)')); - // friendships + $m->connect('api/friendships/destroy.:format', + array('action' => 'ApiFriendshipsDestroy', + 'format' => '(xml|json)')); - $m->connect('api/friendships/show.:format', - array('action' => 'ApiFriendshipsShow', - 'format' => '(xml|json)')); + $m->connect('api/friendships/create/:id.:format', + array('action' => 'ApiFriendshipsCreate', + 'id' => '[a-zA-Z0-9]+', + 'format' => '(xml|json)')); - $m->connect('api/friendships/exists.:format', - array('action' => 'ApiFriendshipsExists', - 'format' => '(xml|json)')); + $m->connect('api/friendships/destroy/:id.:format', + array('action' => 'ApiFriendshipsDestroy', + 'id' => '[a-zA-Z0-9]+', + 'format' => '(xml|json)')); - $m->connect('api/friendships/create.:format', - array('action' => 'ApiFriendshipsCreate', - 'format' => '(xml|json)')); + // Social graph - $m->connect('api/friendships/destroy.:format', - array('action' => 'ApiFriendshipsDestroy', - 'format' => '(xml|json)')); + $m->connect('api/friends/ids/:id.:format', + array('action' => 'apiFriends', + 'ids_only' => true)); - $m->connect('api/friendships/create/:id.:format', - array('action' => 'ApiFriendshipsCreate', - 'id' => '[a-zA-Z0-9]+', - 'format' => '(xml|json)')); + $m->connect('api/followers/ids/:id.:format', + array('action' => 'apiFollowers', + 'ids_only' => true)); - $m->connect('api/friendships/destroy/:id.:format', - array('action' => 'ApiFriendshipsDestroy', - 'id' => '[a-zA-Z0-9]+', - 'format' => '(xml|json)')); + $m->connect('api/friends/ids.:format', + array('action' => 'apiFriends', + 'ids_only' => true)); - // Social graph + $m->connect('api/followers/ids.:format', + array('action' => 'apiFollowers', + 'ids_only' => true)); - $m->connect('api/friends/ids/:id.:format', - array('action' => 'apiFriends', - 'ids_only' => true)); + // account - $m->connect('api/followers/ids/:id.:format', - array('action' => 'apiFollowers', - 'ids_only' => true)); + $m->connect('api/account/verify_credentials.:format', + array('action' => 'ApiAccountVerifyCredentials')); - $m->connect('api/friends/ids.:format', - array('action' => 'apiFriends', - 'ids_only' => true)); + // special case where verify_credentials is called w/out a format - $m->connect('api/followers/ids.:format', - array('action' => 'apiFollowers', - 'ids_only' => true)); + $m->connect('api/account/verify_credentials', + array('action' => 'ApiAccountVerifyCredentials')); - // account + $m->connect('api/account/rate_limit_status.:format', + array('action' => 'ApiAccountRateLimitStatus')); - $m->connect('api/account/verify_credentials.:format', - array('action' => 'ApiAccountVerifyCredentials')); + // favorites - // special case where verify_credentials is called w/out a format + $m->connect('api/favorites.:format', + array('action' => 'ApiTimelineFavorites', + 'format' => '(xml|json|rss|atom)')); - $m->connect('api/account/verify_credentials', - array('action' => 'ApiAccountVerifyCredentials')); + $m->connect('api/favorites/:id.:format', + array('action' => 'ApiTimelineFavorites', + 'id' => '[a-zA-Z0-9]+', + 'format' => '(xmljson|rss|atom)')); - $m->connect('api/account/rate_limit_status.:format', - array('action' => 'ApiAccountRateLimitStatus')); + $m->connect('api/favorites/create/:id.:format', + array('action' => 'ApiFavoriteCreate', + 'id' => '[a-zA-Z0-9]+', + 'format' => '(xml|json)')); - // favorites + $m->connect('api/favorites/destroy/:id.:format', + array('action' => 'ApiFavoriteDestroy', + 'id' => '[a-zA-Z0-9]+', + 'format' => '(xml|json)')); - $m->connect('api/favorites.:format', - array('action' => 'ApiTimelineFavorites', - 'format' => '(xml|json|rss|atom)')); + // notifications - $m->connect('api/favorites/:id.:format', - array('action' => 'ApiTimelineFavorites', - 'id' => '[a-zA-Z0-9]+', - 'format' => '(xmljson|rss|atom)')); + $m->connect('api/notifications/:method/:argument', + array('action' => 'api', + 'apiaction' => 'favorites')); - $m->connect('api/favorites/create/:id.:format', - array('action' => 'ApiFavoriteCreate', - 'id' => '[a-zA-Z0-9]+', - 'format' => '(xml|json)')); + // blocks - $m->connect('api/favorites/destroy/:id.:format', - array('action' => 'ApiFavoriteDestroy', - 'id' => '[a-zA-Z0-9]+', - 'format' => '(xml|json)')); + $m->connect('api/blocks/create/:id.:format', + array('action' => 'ApiBlockCreate', + 'id' => '[a-zA-Z0-9]+', + 'format' => '(xml|json)')); - // notifications + $m->connect('api/blocks/destroy/:id.:format', + array('action' => 'ApiBlockDestroy', + 'id' => '[a-zA-Z0-9]+', + 'format' => '(xml|json)')); + // help - $m->connect('api/notifications/:method/:argument', - array('action' => 'api', - 'apiaction' => 'favorites')); + $m->connect('api/help/test.:format', + array('action' => 'ApiHelpTest', + 'format' => '(xml|json)')); - // blocks + // statusnet - $m->connect('api/blocks/create/:id.:format', - array('action' => 'ApiBlockCreate', - 'id' => '[a-zA-Z0-9]+', - 'format' => '(xml|json)')); + $m->connect('api/statusnet/version.:format', + array('action' => 'ApiStatusnetVersion', + 'format' => '(xml|json)')); - $m->connect('api/blocks/destroy/:id.:format', - array('action' => 'ApiBlockDestroy', - 'id' => '[a-zA-Z0-9]+', - 'format' => '(xml|json)')); - // help + $m->connect('api/statusnet/config.:format', + array('action' => 'ApiStatusnetConfig', + 'format' => '(xml|json)')); - $m->connect('api/help/test.:format', - array('action' => 'ApiHelpTest', - 'format' => '(xml|json)')); + // For older methods, we provide "laconica" base action - // statusnet + $m->connect('api/laconica/version.:format', + array('action' => 'ApiStatusnetVersion', + 'format' => '(xml|json)')); + + $m->connect('api/laconica/config.:format', + array('action' => 'ApiStatusnetConfig', + 'format' => '(xml|json)')); - $m->connect('api/statusnet/version.:format', - array('action' => 'ApiStatusnetVersion', - 'format' => '(xml|json)')); - - $m->connect('api/statusnet/config.:format', - array('action' => 'ApiStatusnetConfig', - 'format' => '(xml|json)')); - - // For older methods, we provide "laconica" base action - - $m->connect('api/laconica/version.:format', - array('action' => 'ApiStatusnetVersion', - 'format' => '(xml|json)')); - - $m->connect('api/laconica/config.:format', - array('action' => 'ApiStatusnetConfig', - 'format' => '(xml|json)')); - - // Groups and tags are newer than 0.8.1 so no backward-compatibility - // necessary - - // Groups - //'list' has to be handled differently, as php will not allow a method to be named 'list' - - $m->connect('api/statusnet/groups/timeline/:id.:format', - array('action' => 'ApiTimelineGroup', - 'id' => '[a-zA-Z0-9]+', - 'format' => '(xmljson|rss|atom)')); - - $m->connect('api/statusnet/groups/show.:format', - array('action' => 'ApiGroupShow', - 'format' => '(xml|json)')); - - $m->connect('api/statusnet/groups/show/:id.:format', - array('action' => 'ApiGroupShow', - 'id' => '[a-zA-Z0-9]+', - 'format' => '(xml|json)')); - - $m->connect('api/statusnet/groups/join.:format', - array('action' => 'ApiGroupJoin', - 'id' => '[a-zA-Z0-9]+', - 'format' => '(xml|json)')); - - $m->connect('api/statusnet/groups/join/:id.:format', - array('action' => 'ApiGroupJoin', - 'format' => '(xml|json)')); - - $m->connect('api/statusnet/groups/leave.:format', - array('action' => 'ApiGroupLeave', - 'id' => '[a-zA-Z0-9]+', - 'format' => '(xml|json)')); - - $m->connect('api/statusnet/groups/leave/:id.:format', - array('action' => 'ApiGroupLeave', - 'format' => '(xml|json)')); - - $m->connect('api/statusnet/groups/is_member.:format', - array('action' => 'ApiGroupIsMember', - 'format' => '(xml|json)')); - - $m->connect('api/statusnet/groups/list.:format', - array('action' => 'ApiGroupList', - 'format' => '(xml|json|rss|atom)')); - - $m->connect('api/statusnet/groups/list/:id.:format', - array('action' => 'ApiGroupList', - 'id' => '[a-zA-Z0-9]+', - 'format' => '(xml|json|rss|atom)')); - - $m->connect('api/statusnet/groups/list_all.:format', - array('action' => 'ApiGroupListAll', - 'format' => '(xml|json|rss|atom)')); - - $m->connect('api/statusnet/groups/membership.:format', - array('action' => 'ApiGroupMembership', - 'format' => '(xml|json)')); - - $m->connect('api/statusnet/groups/membership/:id.:format', - array('action' => 'ApiGroupMembership', - 'id' => '[a-zA-Z0-9]+', - 'format' => '(xml|json)')); - - $m->connect('api/statusnet/groups/create.:format', - array('action' => 'ApiGroupCreate', - 'format' => '(xml|json)')); - // Tags - $m->connect('api/statusnet/tags/timeline/:tag.:format', - array('action' => 'ApiTimelineTag', - 'format' => '(xmljson|rss|atom)')); - - // search - $m->connect('api/search.atom', array('action' => 'twitapisearchatom')); - $m->connect('api/search.json', array('action' => 'twitapisearchjson')); - $m->connect('api/trends.json', array('action' => 'twitapitrends')); - - // user stuff - - foreach (array('subscriptions', 'subscribers', - 'nudge', 'all', 'foaf', 'xrds', - 'replies', 'inbox', 'outbox', 'microsummary') as $a) { - $m->connect(':nickname/'.$a, - array('action' => $a), + // Groups and tags are newer than 0.8.1 so no backward-compatibility + // necessary + + // Groups + //'list' has to be handled differently, as php will not allow a method to be named 'list' + + $m->connect('api/statusnet/groups/timeline/:id.:format', + array('action' => 'ApiTimelineGroup', + 'id' => '[a-zA-Z0-9]+', + 'format' => '(xmljson|rss|atom)')); + + $m->connect('api/statusnet/groups/show.:format', + array('action' => 'ApiGroupShow', + 'format' => '(xml|json)')); + + $m->connect('api/statusnet/groups/show/:id.:format', + array('action' => 'ApiGroupShow', + 'id' => '[a-zA-Z0-9]+', + 'format' => '(xml|json)')); + + $m->connect('api/statusnet/groups/join.:format', + array('action' => 'ApiGroupJoin', + 'id' => '[a-zA-Z0-9]+', + 'format' => '(xml|json)')); + + $m->connect('api/statusnet/groups/join/:id.:format', + array('action' => 'ApiGroupJoin', + 'format' => '(xml|json)')); + + $m->connect('api/statusnet/groups/leave.:format', + array('action' => 'ApiGroupLeave', + 'id' => '[a-zA-Z0-9]+', + 'format' => '(xml|json)')); + + $m->connect('api/statusnet/groups/leave/:id.:format', + array('action' => 'ApiGroupLeave', + 'format' => '(xml|json)')); + + $m->connect('api/statusnet/groups/is_member.:format', + array('action' => 'ApiGroupIsMember', + 'format' => '(xml|json)')); + + $m->connect('api/statusnet/groups/list.:format', + array('action' => 'ApiGroupList', + 'format' => '(xml|json|rss|atom)')); + + $m->connect('api/statusnet/groups/list/:id.:format', + array('action' => 'ApiGroupList', + 'id' => '[a-zA-Z0-9]+', + 'format' => '(xml|json|rss|atom)')); + + $m->connect('api/statusnet/groups/list_all.:format', + array('action' => 'ApiGroupListAll', + 'format' => '(xml|json|rss|atom)')); + + $m->connect('api/statusnet/groups/membership.:format', + array('action' => 'ApiGroupMembership', + 'format' => '(xml|json)')); + + $m->connect('api/statusnet/groups/membership/:id.:format', + array('action' => 'ApiGroupMembership', + 'id' => '[a-zA-Z0-9]+', + 'format' => '(xml|json)')); + + $m->connect('api/statusnet/groups/create.:format', + array('action' => 'ApiGroupCreate', + 'format' => '(xml|json)')); + // Tags + $m->connect('api/statusnet/tags/timeline/:tag.:format', + array('action' => 'ApiTimelineTag', + 'format' => '(xmljson|rss|atom)')); + + // search + $m->connect('api/search.atom', array('action' => 'twitapisearchatom')); + $m->connect('api/search.json', array('action' => 'twitapisearchjson')); + $m->connect('api/trends.json', array('action' => 'twitapitrends')); + + $m->connect('getfile/:filename', + array('action' => 'getfile'), + array('filename' => '[A-Za-z0-9._-]+')); + + // user stuff + + foreach (array('subscriptions', 'subscribers', + 'nudge', 'all', 'foaf', 'xrds', + 'replies', 'inbox', 'outbox', 'microsummary') as $a) { + $m->connect(':nickname/'.$a, + array('action' => $a), + array('nickname' => '[a-zA-Z0-9]{1,64}')); + } + + foreach (array('subscriptions', 'subscribers') as $a) { + $m->connect(':nickname/'.$a.'/:tag', + array('action' => $a), + array('tag' => '[a-zA-Z0-9]+', + 'nickname' => '[a-zA-Z0-9]{1,64}')); + } + + foreach (array('rss', 'groups') as $a) { + $m->connect(':nickname/'.$a, + array('action' => 'user'.$a), + array('nickname' => '[a-zA-Z0-9]{1,64}')); + } + + foreach (array('all', 'replies', 'favorites') as $a) { + $m->connect(':nickname/'.$a.'/rss', + array('action' => $a.'rss'), + array('nickname' => '[a-zA-Z0-9]{1,64}')); + } + + $m->connect(':nickname/favorites', + array('action' => 'showfavorites'), array('nickname' => '[a-zA-Z0-9]{1,64}')); - } - foreach (array('subscriptions', 'subscribers') as $a) { - $m->connect(':nickname/'.$a.'/:tag', - array('action' => $a), - array('tag' => '[a-zA-Z0-9]+', + $m->connect(':nickname/avatar/:size', + array('action' => 'avatarbynickname'), + array('size' => '(original|96|48|24)', 'nickname' => '[a-zA-Z0-9]{1,64}')); - } - foreach (array('rss', 'groups') as $a) { - $m->connect(':nickname/'.$a, - array('action' => 'user'.$a), + $m->connect(':nickname/tag/:tag/rss', + array('action' => 'userrss'), + array('nickname' => '[a-zA-Z0-9]{1,64}'), + array('tag' => '[a-zA-Z0-9]+')); + + $m->connect(':nickname/tag/:tag', + array('action' => 'showstream'), + array('nickname' => '[a-zA-Z0-9]{1,64}'), + array('tag' => '[a-zA-Z0-9]+')); + + $m->connect(':nickname', + array('action' => 'showstream'), array('nickname' => '[a-zA-Z0-9]{1,64}')); + + Event::handle('RouterInitialized', array($m)); } - foreach (array('all', 'replies', 'favorites') as $a) { - $m->connect(':nickname/'.$a.'/rss', - array('action' => $a.'rss'), - array('nickname' => '[a-zA-Z0-9]{1,64}')); - } - - $m->connect(':nickname/favorites', - array('action' => 'showfavorites'), - array('nickname' => '[a-zA-Z0-9]{1,64}')); - - $m->connect(':nickname/avatar/:size', - array('action' => 'avatarbynickname'), - array('size' => '(original|96|48|24)', - 'nickname' => '[a-zA-Z0-9]{1,64}')); - - $m->connect(':nickname/tag/:tag/rss', - array('action' => 'userrss'), - array('nickname' => '[a-zA-Z0-9]{1,64}'), - array('tag' => '[a-zA-Z0-9]+')); - - $m->connect(':nickname/tag/:tag', - array('action' => 'showstream'), - array('nickname' => '[a-zA-Z0-9]{1,64}'), - array('tag' => '[a-zA-Z0-9]+')); - - $m->connect(':nickname', - array('action' => 'showstream'), - array('nickname' => '[a-zA-Z0-9]{1,64}')); - - Event::handle('RouterInitialized', array($m)); - return $m; } diff --git a/lib/unqueuemanager.php b/lib/unqueuemanager.php index 6cfe5bcbd3..72dbc4eede 100644 --- a/lib/unqueuemanager.php +++ b/lib/unqueuemanager.php @@ -48,17 +48,6 @@ class UnQueueManager jabber_public_notice($notice); } break; - case 'twitter': - if ($this->_isLocal($notice)) { - broadcast_twitter($notice); - } - break; - case 'facebook': - if ($this->_isLocal($notice)) { - require_once INSTALLDIR . '/lib/facebookutil.php'; - return facebookBroadcastNotice($notice); - } - break; case 'ping': if ($this->_isLocal($notice)) { require_once INSTALLDIR . '/lib/ping.php'; @@ -77,7 +66,7 @@ class UnQueueManager break; default: if (Event::handle('UnqueueHandleNotice', array(&$notice, $queue))) { - throw ServerException("UnQueueManager: Unknown queue: $queue"); + throw new ServerException("UnQueueManager: Unknown queue: $queue"); } } } diff --git a/lib/util.php b/lib/util.php index be10647fcb..d159c583ec 100644 --- a/lib/util.php +++ b/lib/util.php @@ -51,13 +51,23 @@ function common_init_locale($language=null) function common_init_language() { mb_internal_encoding('UTF-8'); + + // gettext seems very picky... We first need to setlocale() + // to a locale which _does_ exist on the system, and _then_ + // we can set in another locale that may not be set up + // (say, ga_ES for Galego/Galician) it seems to take it. + common_init_locale("en_US"); + $language = common_language(); - // So we don't have to make people install the gettext locales $locale_set = common_init_locale($language); - bindtextdomain("statusnet", common_config('site','locale_path')); + setlocale(LC_CTYPE, 'C'); + + // So we don't have to make people install the gettext locales + $path = common_config('site','locale_path'); + bindtextdomain("statusnet", $path); bind_textdomain_codeset("statusnet", "UTF-8"); textdomain("statusnet"); - setlocale(LC_CTYPE, 'C'); + if(!$locale_set) { common_log(LOG_INFO, 'Language requested:' . $language . ' - locale could not be set. Perhaps that system locale is not installed.', __FILE__); } @@ -391,7 +401,7 @@ function common_render_content($text, $notice) { $r = common_render_text($text); $id = $notice->profile_id; - $r = preg_replace('/(^|[\s\.\,\:\;]+)@([A-Za-z0-9]{1,64})/e', "'\\1@'.common_at_link($id, '\\2')", $r); + $r = preg_replace('/(^|\s+)@(['.NICKNAME_FMT.']{1,64})/e', "'\\1@'.common_at_link($id, '\\2')", $r); $r = preg_replace('/^T ([A-Z0-9]{1,64}) /e', "'T '.common_at_link($id, '\\1').' '", $r); $r = preg_replace('/(^|[\s\.\,\:\;]+)@#([A-Za-z0-9]{1,64})/e', "'\\1@#'.common_at_hash_link($id, '\\2')", $r); $r = preg_replace('/(^|[\s\.\,\:\;]+)!([A-Za-z0-9]{1,64})/e', "'\\1!'.common_group_link($id, '\\2')", $r); @@ -771,12 +781,18 @@ function common_path($relative, $ssl=false) if (is_string(common_config('site', 'sslserver')) && mb_strlen(common_config('site', 'sslserver')) > 0) { $serverpart = common_config('site', 'sslserver'); - } else { + } else if (common_config('site', 'server')) { $serverpart = common_config('site', 'server'); + } else { + common_log(LOG_ERR, 'Site Sever not configured, unable to determine site name.'); } } else { $proto = 'http'; - $serverpart = common_config('site', 'server'); + if (common_config('site', 'server')) { + $serverpart = common_config('site', 'server'); + } else { + common_log(LOG_ERR, 'Site Sever not configured, unable to determine site name.'); + } } return $proto.'://'.$serverpart.'/'.$pathpart.$relative; @@ -896,8 +912,6 @@ function common_broadcast_notice($notice, $remote=false) function common_enqueue_notice($notice) { static $localTransports = array('omb', - 'twitter', - 'facebook', 'ping'); static $allTransports = array('sms', 'plugin'); diff --git a/plugins/OpenID/publicxrds.php b/lib/xrdsoutputter.php similarity index 52% rename from plugins/OpenID/publicxrds.php rename to lib/xrdsoutputter.php index 1b2b359caa..4b77ed5a3a 100644 --- a/plugins/OpenID/publicxrds.php +++ b/lib/xrdsoutputter.php @@ -1,21 +1,12 @@ - * @author Robin Millette - * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 - * @link http://status.net/ - * - * StatusNet - the distributed open-source microblogging tool - * Copyright (C) 2008, 2009, StatusNet, Inc. - * - * This program is free software: you can redistribute it and/or modify + * LICENCE: This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -27,60 +18,44 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . + * + * @category Output + * @package StatusNet + * @author Craig Andrews + * @copyright 2008 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ */ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -require_once INSTALLDIR.'/plugins/OpenID/openid.php'; +require_once INSTALLDIR.'/lib/xmloutputter.php'; /** - * Public XRDS for OpenID + * Low-level generator for XRDS XML * - * @category Action + * @category Output * @package StatusNet - * @author Evan Prodromou - * @author Robin Millette - * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @author Craig Andrews + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ * - * @todo factor out similarities with XrdsAction + * @see Action + * @see XMLOutputter */ -class PublicxrdsAction extends Action +class XRDSOutputter extends XMLOutputter { - /** - * Is read only? - * - * @return boolean true - */ - function isReadOnly($args) + public function startXRDS() { - return true; - } - - /** - * Class handler. - * - * @param array $args array of arguments - * - * @return nothing - */ - function handle($args) - { - parent::handle($args); header('Content-Type: application/xrds+xml'); $this->startXML(); $this->elementStart('XRDS', array('xmlns' => 'xri://$xrds')); - $this->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)', - 'xmlns:simple' => 'http://xrds-simple.net/core/1.0', - 'version' => '2.0')); - $this->element('Type', null, 'xri://$xrds*simple'); - foreach (array('finishopenidlogin', 'finishaddopenid') as $finish) { - $this->showService(Auth_OpenID_RP_RETURN_TO_URL_TYPE, - common_local_url($finish)); - } - $this->elementEnd('XRD'); + } + + public function endXRDS() + { $this->elementEnd('XRDS'); $this->endXML(); } @@ -96,7 +71,7 @@ class PublicxrdsAction extends Action * * @return void */ - function showService($type, $uri, $params=null, $sigs=null, $localId=null) + function showXrdsService($type, $uri, $params=null, $sigs=null, $localId=null) { $this->elementStart('Service'); if ($uri) { @@ -119,4 +94,3 @@ class PublicxrdsAction extends Action $this->elementEnd('Service'); } } - diff --git a/locale/bg/LC_MESSAGES/statusnet.mo b/locale/bg/LC_MESSAGES/statusnet.mo new file mode 100644 index 0000000000..335fe0b92b Binary files /dev/null and b/locale/bg/LC_MESSAGES/statusnet.mo differ diff --git a/locale/bg_BG/LC_MESSAGES/statusnet.po b/locale/bg/LC_MESSAGES/statusnet.po similarity index 100% rename from locale/bg_BG/LC_MESSAGES/statusnet.po rename to locale/bg/LC_MESSAGES/statusnet.po diff --git a/locale/bg_BG/LC_MESSAGES/statusnet.mo b/locale/bg_BG/LC_MESSAGES/statusnet.mo deleted file mode 100644 index 8cfa1523d2..0000000000 Binary files a/locale/bg_BG/LC_MESSAGES/statusnet.mo and /dev/null differ diff --git a/locale/ca_ES/LC_MESSAGES/statusnet.mo b/locale/ca/LC_MESSAGES/statusnet.mo similarity index 100% rename from locale/ca_ES/LC_MESSAGES/statusnet.mo rename to locale/ca/LC_MESSAGES/statusnet.mo diff --git a/locale/ca_ES/LC_MESSAGES/statusnet.po b/locale/ca/LC_MESSAGES/statusnet.po similarity index 100% rename from locale/ca_ES/LC_MESSAGES/statusnet.po rename to locale/ca/LC_MESSAGES/statusnet.po diff --git a/locale/cs/LC_MESSAGES/statusnet.mo b/locale/cs/LC_MESSAGES/statusnet.mo new file mode 100644 index 0000000000..4618fd73d7 Binary files /dev/null and b/locale/cs/LC_MESSAGES/statusnet.mo differ diff --git a/locale/cs_CZ/LC_MESSAGES/statusnet.po b/locale/cs/LC_MESSAGES/statusnet.po similarity index 100% rename from locale/cs_CZ/LC_MESSAGES/statusnet.po rename to locale/cs/LC_MESSAGES/statusnet.po diff --git a/locale/cs_CZ/LC_MESSAGES/statusnet.mo b/locale/cs_CZ/LC_MESSAGES/statusnet.mo deleted file mode 100644 index e126daaf09..0000000000 Binary files a/locale/cs_CZ/LC_MESSAGES/statusnet.mo and /dev/null differ diff --git a/locale/de/LC_MESSAGES/statusnet.mo b/locale/de/LC_MESSAGES/statusnet.mo new file mode 100644 index 0000000000..335b267155 Binary files /dev/null and b/locale/de/LC_MESSAGES/statusnet.mo differ diff --git a/locale/de_DE/LC_MESSAGES/statusnet.po b/locale/de/LC_MESSAGES/statusnet.po similarity index 100% rename from locale/de_DE/LC_MESSAGES/statusnet.po rename to locale/de/LC_MESSAGES/statusnet.po diff --git a/locale/de_DE/LC_MESSAGES/statusnet.mo b/locale/de_DE/LC_MESSAGES/statusnet.mo deleted file mode 100644 index fe6072c1b1..0000000000 Binary files a/locale/de_DE/LC_MESSAGES/statusnet.mo and /dev/null differ diff --git a/locale/el_GR/LC_MESSAGES/statusnet.mo b/locale/el/LC_MESSAGES/statusnet.mo similarity index 100% rename from locale/el_GR/LC_MESSAGES/statusnet.mo rename to locale/el/LC_MESSAGES/statusnet.mo diff --git a/locale/el_GR/LC_MESSAGES/statusnet.po b/locale/el/LC_MESSAGES/statusnet.po similarity index 100% rename from locale/el_GR/LC_MESSAGES/statusnet.po rename to locale/el/LC_MESSAGES/statusnet.po diff --git a/locale/en_GB/LC_MESSAGES/statusnet.mo b/locale/en_GB/LC_MESSAGES/statusnet.mo index 11eacc9ac1..4eeac7304f 100644 Binary files a/locale/en_GB/LC_MESSAGES/statusnet.mo and b/locale/en_GB/LC_MESSAGES/statusnet.mo differ diff --git a/locale/es/LC_MESSAGES/statusnet.mo b/locale/es/LC_MESSAGES/statusnet.mo index ab03d12e0b..05eabcc750 100644 Binary files a/locale/es/LC_MESSAGES/statusnet.mo and b/locale/es/LC_MESSAGES/statusnet.mo differ diff --git a/locale/fr/LC_MESSAGES/statusnet.mo b/locale/fr/LC_MESSAGES/statusnet.mo new file mode 100644 index 0000000000..1d3509af15 Binary files /dev/null and b/locale/fr/LC_MESSAGES/statusnet.mo differ diff --git a/locale/fr_FR/LC_MESSAGES/statusnet.po b/locale/fr/LC_MESSAGES/statusnet.po similarity index 100% rename from locale/fr_FR/LC_MESSAGES/statusnet.po rename to locale/fr/LC_MESSAGES/statusnet.po diff --git a/locale/fr_FR/LC_MESSAGES/statusnet.mo b/locale/fr_FR/LC_MESSAGES/statusnet.mo deleted file mode 100644 index f26b8708d6..0000000000 Binary files a/locale/fr_FR/LC_MESSAGES/statusnet.mo and /dev/null differ diff --git a/locale/ga/LC_MESSAGES/statusnet.mo b/locale/ga/LC_MESSAGES/statusnet.mo new file mode 100644 index 0000000000..c13acd1a80 Binary files /dev/null and b/locale/ga/LC_MESSAGES/statusnet.mo differ diff --git a/locale/ga/LC_MESSAGES/statusnet.po b/locale/ga/LC_MESSAGES/statusnet.po new file mode 100644 index 0000000000..3815e48532 --- /dev/null +++ b/locale/ga/LC_MESSAGES/statusnet.po @@ -0,0 +1,4713 @@ +# translation of statusnet.po to Galician +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Francisco Diéguez , 2008. +msgid "" +msgstr "" +"Project-Id-Version: laconica-new\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2008-12-17 20:08+0100\n" +"PO-Revision-Date: 2008-12-17 20:10+0100\n" +"Last-Translator: Martín Vázquez Cabanas \n" +"Language-Team: Galician \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" + +#: ../actions/noticesearchrss.php:64 +#: actions/noticesearchrss.php:68 +#: actions/noticesearchrss.php:61 +#, php-format +msgid " Search Stream for \"%s\"" +msgstr "Buscar \"%s\" na Liña de tempo" + +#: ../actions/finishopenidlogin.php:82 +#: ../actions/register.php:191 +#: actions/finishopenidlogin.php:88 +#: actions/register.php:205 +#: actions/register.php:232 +msgid " except this private data: password, email address, IM address, phone number." +msgstr " agás esta informción privada: contrasinal, dirección de correo electrónico, dirección IM, número de teléfono." + +#: ../actions/showstream.php:400 +#: ../lib/stream.php:109 +#: actions/showstream.php:418 +#: lib/mailbox.php:164 +#: lib/stream.php:76 +#: lib/facebookaction.php:195 +#: lib/noticelist.php:160 +msgid " from " +msgstr " dende " + +#: ../actions/twitapistatuses.php:478 +#: actions/twitapistatuses.php:412 +#: actions/twitapistatuses.php:341 +#, php-format +msgid "%1$s / Updates replying to %2$s" +msgstr "%1$s / Chíos que respostan a %2$s" + +#: ../actions/invite.php:168 +#: actions/invite.php:176 +#, php-format +msgid "%1$s has invited you to join them on %2$s" +msgstr "%1$s invitoute a unirse a él en %2$s." + +#: ../actions/invite.php:170 +#: actions/invite.php:178 +#, php-format +msgid "" +"%1$s has invited you to join them on %2$s (%3$s).\n" +"\n" +"%2$s is a micro-blogging service that lets you keep up-to-date with people you know and people who interest you.\n" +"\n" +"You can also share news about yourself, your thoughts, or your life online with people who know about you. It's also great for meeting new people who share your interests.\n" +"\n" +"%1$s said:\n" +"\n" +"%4$s\n" +"\n" +"You can see %1$s's profile page on %2$s here:\n" +"\n" +"%5$s\n" +"\n" +"If you'd like to try the service, click on the link below to accept the invitation.\n" +"\n" +"%6$s\n" +"\n" +"If not, you can ignore this message. Thanks for your patience and your time.\n" +"\n" +"Sincerely, %2$s\n" +msgstr "" +"%1$s invitoute a unirte a el en %2$s (%3$s).\n" +"\n" +"%2$s é un servizo de microbloguexo que che permite manterte actualizado coa xente que coñeces e xente na que tes interese.\n" +"\n" +"Tamén podes compartir novas contigo mesmo, ou pensamentos, ou vivir en liña con xente que te coñece. Tamén está moi ben para coñecer xente que comparte os mesmos intereses..\n" +"\n" +"%1$s dixo:\n" +"\n" +"%4$s\n" +"\n" +"Podes ollar a súa páxina de perfil %1$s's en %2$s here:\n" +"\n" +"%5$s\n" +"\n" +"Se queres probar, fai clic na ligazón de abaixo para aceptar a invitación..\n" +"\n" +"%6$s\n" +"\n" +"Se non, pois ignora esta mensaxe. Pero aló ti, aquí se pasa moi ben.\n" +"\n" +"Saudiños, %2$s\n" + +#: ../lib/mail.php:124 +#: lib/mail.php:124 +#: lib/mail.php:126 +#: lib/mail.php:115 +#, php-format +msgid "%1$s is now listening to your notices on %2$s." +msgstr "%1$s está a escoitar os teus chíos %2$s." + +#: ../lib/mail.php:126 +#: lib/mail.php:117 +#, php-format +msgid "" +"%1$s is now listening to your notices on %2$s.\n" +"\n" +"\t%3$s\n" +"\n" +"Faithfully yours,\n" +"%4$s.\n" +msgstr "" +"%1$s está a escoitar os teus chíos en %2$s.\n" +"\n" +"\t%3$s\n" +"\n" +"Atentamente todo seu,\n" +"%4$s.\n" + +#: ../actions/twitapistatuses.php:482 +#: actions/twitapistatuses.php:415 +#: actions/twitapistatuses.php:344 +#, php-format +msgid "%1$s updates that reply to updates from %2$s / %3$s." +msgstr "Hai %1$s chíos en resposta a chíos dende %2$s / %3$s." + +#: ../actions/shownotice.php:45 +#: actions/shownotice.php:45 +#: actions/shownotice.php:73 +#, php-format +msgid "%1$s's status on %2$s" +msgstr "Estado de %1$s en %2$s" + +#: ../actions/invite.php:84 +#: ../actions/invite.php:92 +#: actions/invite.php:91 +#: actions/invite.php:99 +#, php-format +msgid "%s (%s)" +msgstr "%s (%s)" + +#: ../actions/publicrss.php:62 +#: actions/publicrss.php:48 +#, php-format +msgid "%s Public Stream" +msgstr "%s Fio Público" + +#: ../actions/all.php:47 +#: ../actions/allrss.php:60 +#: ../actions/twitapistatuses.php:238 +#: ../lib/stream.php:51 +#: actions/all.php:47 +#: actions/allrss.php:60 +#: actions/twitapistatuses.php:155 +#: lib/personal.php:51 +#: actions/twitapistatuses.php:123 +#, php-format +msgid "%s and friends" +msgstr "%s e amigos" + +#: ../actions/twitapistatuses.php:49 +#: actions/twitapistatuses.php:49 +#: actions/twitapistatuses.php:31 +#, php-format +msgid "%s public timeline" +msgstr "Liña de tempo pública de %s" + +#: ../lib/mail.php:206 +#: lib/mail.php:212 +#: lib/mail.php:207 +#, php-format +msgid "%s status" +msgstr "Estado de %s" + +#: ../actions/twitapistatuses.php:338 +#: actions/twitapistatuses.php:265 +#: actions/twitapistatuses.php:195 +#, php-format +msgid "%s timeline" +msgstr "Liña de tempo de %s" + +#: ../actions/twitapistatuses.php:52 +#: actions/twitapistatuses.php:52 +#: actions/twitapistatuses.php:34 +#, php-format +msgid "%s updates from everyone!" +msgstr "%s chíos de calquera!" + +#: ../actions/register.php:213 +#: actions/register.php:254 +msgid "(You should receive a message by email momentarily, with instructions on how to confirm your email address.)" +msgstr "(Deberías recibir unha mensaxe no teu email nun intre, coas instrucións de como confirmar a túa dirección de correo.)" + +#: ../lib/util.php:257 +#: lib/util.php:273 +#: lib/util.php:290 +#, php-format +msgid "**%%site.name%%** is a microblogging service brought to you by [%%site.broughtby%%](%%site.broughtbyurl%%). " +msgstr "**%%site.name%%** é un servizo de microbloguexo que che proporciona [%%site.broughtby%%](%%site.broughtbyurl%%). " + +#: ../lib/util.php:259 +#: lib/util.php:275 +#: lib/util.php:292 +#, php-format +msgid "**%%site.name%%** is a microblogging service. " +msgstr "**%%site.name%%** é un servizo de microbloguexo." + +#: ../lib/util.php:274 +#: lib/util.php:290 +#: lib/util.php:307 +msgid ". Contributors should be attributed by full name or nickname." +msgstr ". Os contribuíntes deben atribuiselles polo nome completo ou apodo." + +#: ../actions/finishopenidlogin.php:73 +#: ../actions/profilesettings.php:43 +#: actions/finishopenidlogin.php:79 +#: actions/profilesettings.php:76 +#: actions/profilesettings.php:78 +msgid "1-64 lowercase letters or numbers, no punctuation or spaces" +msgstr "De 1 a 64 letras minúsculas ou númeors, nin espazos nin signos de puntuación" + +#: ../actions/register.php:152 +#: actions/register.php:166 +#: actions/register.php:193 +msgid "1-64 lowercase letters or numbers, no punctuation or spaces. Required." +msgstr "De 1 a 64 letras minúsculas ou números, nin espazos nin signos de puntuación. Requerido." + +#: ../actions/password.php:42 +#: actions/profilesettings.php:181 +#: actions/profilesettings.php:198 +msgid "6 or more characters" +msgstr "6 ou máis caracteres" + +#: ../actions/recoverpassword.php:180 +#: actions/recoverpassword.php:186 +msgid "6 or more characters, and don't forget it!" +msgstr "6 ou máis caracteres, non o esquenzas!" + +#: ../actions/register.php:154 +#: actions/register.php:168 +#: actions/register.php:195 +msgid "6 or more characters. Required." +msgstr "6 ou máis caracteres. Requerido." + +#: ../actions/imsettings.php:197 +#: actions/imsettings.php:205 +#: actions/imsettings.php:210 +#, php-format +msgid "A confirmation code was sent to the IM address you added. You must approve %s for sending messages to you." +msgstr "O código de confirmación foi embiado á dirección IM que engadiches. Deberías engadir a %s como contacto para que che poida enviar mensaxes." + +#: ../actions/emailsettings.php:213 +#: actions/emailsettings.php:231 +#: actions/emailsettings.php:235 +msgid "A confirmation code was sent to the email address you added. Check your inbox (and spam box!) for the code and instructions on how to use it." +msgstr "Enviouseche un código de confirmación á dirección de correo que engadiches. Comproba a túa bandexa de entrada (ou spam!) polo código e instrucións que debes seguir." + +#: ../actions/smssettings.php:216 +#: actions/smssettings.php:224 +#: actions/smssettings.php:226 +msgid "A confirmation code was sent to the phone number you added. Check your inbox (and spam box!) for the code and instructions on how to use it." +msgstr "Enviouseche o código de confirmación ó número de teléfono que engadiches. Comproba a túa bandexa de entrada (ou spam!) polo código e instrucións que debes seguir." + +#: ../actions/twitapiaccount.php:49 +#: ../actions/twitapihelp.php:45 +#: ../actions/twitapistatuses.php:88 +#: ../actions/twitapistatuses.php:259 +#: ../actions/twitapistatuses.php:370 +#: ../actions/twitapistatuses.php:532 +#: ../actions/twitapiusers.php:122 +#: actions/twitapiaccount.php:49 +#: actions/twitapidirect_messages.php:104 +#: actions/twitapifavorites.php:111 +#: actions/twitapifavorites.php:120 +#: actions/twitapifriendships.php:156 +#: actions/twitapihelp.php:46 +#: actions/twitapistatuses.php:93 +#: actions/twitapistatuses.php:176 +#: actions/twitapistatuses.php:288 +#: actions/twitapistatuses.php:298 +#: actions/twitapistatuses.php:454 +#: actions/twitapistatuses.php:463 +#: actions/twitapistatuses.php:504 +#: actions/twitapiusers.php:55 +#: actions/twitapiaccount.php:35 +#: actions/twitapidirect_messages.php:107 +#: actions/twitapifavorites.php:83 +#: actions/twitapifavorites.php:99 +#: actions/twitapifriendships.php:117 +#: actions/twitapihelp.php:42 +#: actions/twitapistatuses.php:77 +#: actions/twitapistatuses.php:144 +#: actions/twitapistatuses.php:224 +#: actions/twitapistatuses.php:234 +#: actions/twitapistatuses.php:386 +#: actions/twitapistatuses.php:395 +#: actions/twitapistatuses.php:421 +#: actions/twitapiusers.php:30 +msgid "API method not found!" +msgstr "Método da API non atopado" + +#: ../actions/twitapiaccount.php:57 +#: ../actions/twitapiaccount.php:113 +#: ../actions/twitapiaccount.php:119 +#: ../actions/twitapiblocks.php:28 +#: ../actions/twitapiblocks.php:34 +#: ../actions/twitapidirect_messages.php:43 +#: ../actions/twitapidirect_messages.php:49 +#: ../actions/twitapidirect_messages.php:56 +#: ../actions/twitapidirect_messages.php:62 +#: ../actions/twitapifavorites.php:41 +#: ../actions/twitapifavorites.php:47 +#: ../actions/twitapifavorites.php:53 +#: ../actions/twitapihelp.php:52 +#: ../actions/twitapinotifications.php:29 +#: ../actions/twitapinotifications.php:35 +#: ../actions/twitapistatuses.php:768 +#: actions/twitapiaccount.php:56 +#: actions/twitapiaccount.php:109 +#: actions/twitapiaccount.php:114 +#: actions/twitapiblocks.php:28 +#: actions/twitapiblocks.php:33 +#: actions/twitapidirect_messages.php:170 +#: actions/twitapifavorites.php:168 +#: actions/twitapihelp.php:53 +#: actions/twitapinotifications.php:29 +#: actions/twitapinotifications.php:34 +#: actions/twitapistatuses.php:690 +#: actions/twitapiaccount.php:42 +#: actions/twitapiaccount.php:92 +#: actions/twitapiaccount.php:97 +#: actions/twitapidirect_messages.php:178 +#: actions/twitapifavorites.php:139 +#: actions/twitapihelp.php:49 +#: actions/twitapistatuses.php:549 +msgid "API method under construction." +msgstr "Método da API en contrución." + +#: ../lib/util.php:324 +#: lib/util.php:340 +#: lib/util.php:369 +msgid "About" +msgstr "Sobre" + +#: ../actions/userauthorization.php:119 +#: actions/userauthorization.php:126 +msgid "Accept" +msgstr "Aceptar" + +#: ../actions/emailsettings.php:62 +#: ../actions/imsettings.php:63 +#: ../actions/openidsettings.php:57 +#: ../actions/smssettings.php:71 +#: actions/emailsettings.php:63 +#: actions/imsettings.php:64 +#: actions/openidsettings.php:58 +#: actions/smssettings.php:71 +#: actions/twittersettings.php:85 +#: actions/smspostsettings.php:50 +#: actions/twittersettings.php:84 +#: actions/smspostsettings.php:51 +msgid "Add" +msgstr "Engadir" + +#: ../actions/openidsettings.php:43 +#: actions/openidsettings.php:44 +msgid "Add OpenID" +msgstr "Engadir dirección OpenID" + +#: ../lib/settingsaction.php:97 +#: lib/settingsaction.php:91 +#: actions/deleteprofile.php:248 +msgid "Add or remove OpenIDs" +msgstr "Engadir ou eliminar OpenID" + +#: ../actions/emailsettings.php:38 +#: ../actions/imsettings.php:39 +#: ../actions/smssettings.php:39 +#: actions/emailsettings.php:39 +#: actions/imsettings.php:40 +#: actions/smssettings.php:39 +msgid "Address" +msgstr "Enderezo" + +#: ../actions/invite.php:131 +#: actions/invite.php:139 +msgid "Addresses of friends to invite (one per line)" +msgstr "Direccións dos amigos que queres invitar (unha por liña)" + +#: ../actions/showstream.php:273 +#: actions/showstream.php:288 +#: actions/showstream.php:336 +msgid "All subscriptions" +msgstr "Tódalas subscricións" + +#: ../actions/publicrss.php:64 +#: actions/publicrss.php:50 +#, php-format +msgid "All updates for %s" +msgstr "Tódalas actualizacións de %s" + +#: ../actions/noticesearchrss.php:66 +#: actions/noticesearchrss.php:70 +#: actions/noticesearchrss.php:63 +#, php-format +msgid "All updates matching search term \"%s\"" +msgstr "Tódalas actualizacións que coinciden co termo de procura \"%s\"" + +#: ../actions/finishopenidlogin.php:29 +#: ../actions/login.php:31 +#: ../actions/openidlogin.php:29 +#: ../actions/register.php:30 +#: actions/finishopenidlogin.php:29 +#: actions/login.php:31 +#: actions/openidlogin.php:29 +#: actions/register.php:30 +msgid "Already logged in." +msgstr "Sesión xa iniciada" + +#: ../lib/subs.php:42 +#: lib/subs.php:42 +#: lib/subs.php:47 +msgid "Already subscribed!." +msgstr "¡Xa está subscrito!." + +#: ../actions/deletenotice.php:54 +#: actions/deletenotice.php:55 +msgid "Are you sure you want to delete this notice?" +msgstr "Estas seguro que queres eliminar este chío?" + +#: ../actions/userauthorization.php:77 +#: actions/userauthorization.php:83 +msgid "Authorize subscription" +msgstr "Subscrición de autorización." + +#: ../actions/login.php:104 +#: ../actions/register.php:178 +#: actions/register.php:192 +#: actions/login.php:111 +#: actions/openidlogin.php:86 +#: actions/register.php:219 +msgid "Automatically login in the future; not for shared computers!" +msgstr "Endiante acceder automáticamente, coidado en equipos compartidos!" + +#: ../actions/profilesettings.php:65 +#: actions/profilesettings.php:98 +#: actions/profilesettings.php:112 +msgid "Automatically subscribe to whoever subscribes to me (best for non-humans)" +msgstr "Suscribirse automáticamente a calquera que se suscriba a min (o mellor para non humáns)" + +#: ../actions/avatar.php:32 +#: ../lib/settingsaction.php:90 +#: actions/profilesettings.php:34 +msgid "Avatar" +msgstr "Avatar" + +#: ../actions/avatar.php:113 +#: actions/profilesettings.php:350 +#: actions/profilesettings.php:396 +msgid "Avatar updated." +msgstr "Avatar actualizado." + +#: ../actions/imsettings.php:55 +#: actions/imsettings.php:56 +#, php-format +msgid "Awaiting confirmation on this address. Check your Jabber/GTalk account for a message with further instructions. (Did you add %s to your buddy list?)" +msgstr "Awaiting confirmation on this address. Check your Jabber/GTalk account for a message with further instructions. (Did you add %s to your buddy list?)" + +#: ../actions/emailsettings.php:54 +#: actions/emailsettings.php:55 +msgid "Awaiting confirmation on this address. Check your inbox (and spam box!) for a message with further instructions." +msgstr "Agardando confirmación para esta dirección. Comproba a túa conta de Jabber/GTalk que ten que haber unha mensaxe coas seguintes instrucións. (Engadiches a %s á túa lista de contactos?)" + +#: ../actions/smssettings.php:58 +#: actions/smssettings.php:58 +msgid "Awaiting confirmation on this phone number." +msgstr "Agardando a confirmación neste número de teléfono." + +#: ../lib/util.php:1318 +#: lib/util.php:1452 +#: lib/facebookaction.php:259 +#: lib/util.php:1851 +msgid "Before »" +msgstr "Antes »" + +#: ../actions/profilesettings.php:49 +#: ../actions/register.php:170 +#: actions/profilesettings.php:82 +#: actions/register.php:184 +#: actions/profilesettings.php:84 +#: actions/register.php:211 +msgid "Bio" +msgstr "Bio" + +#: ../actions/profilesettings.php:101 +#: ../actions/register.php:82 +#: ../actions/updateprofile.php:103 +#: actions/profilesettings.php:216 +#: actions/register.php:89 +#: actions/updateprofile.php:104 +#: actions/profilesettings.php:235 +#: actions/register.php:98 +msgid "Bio is too long (max 140 chars)." +msgstr "O teu Bio é demasiado longo (max 140 car.)." + +#: ../lib/deleteaction.php:41 +#: lib/deleteaction.php:41 +msgid "Can't delete this notice." +msgstr "Non se pode eliminar este chíos." + +#: ../actions/updateprofile.php:119 +#: actions/updateprofile.php:120 +#, php-format +msgid "Can't read avatar URL '%s'" +msgstr "Non se pode ler a URL do avatar de '%s'" + +#: ../actions/password.php:85 +#: ../actions/recoverpassword.php:300 +#: actions/profilesettings.php:404 +#: actions/recoverpassword.php:313 +#: actions/profilesettings.php:450 +msgid "Can't save new password." +msgstr "Non se pode gardar a contrasinal." + +#: ../actions/emailsettings.php:57 +#: ../actions/imsettings.php:58 +#: ../actions/smssettings.php:62 +#: actions/emailsettings.php:58 +#: actions/imsettings.php:59 +#: actions/smssettings.php:62 +msgid "Cancel" +msgstr "Cancelar" + +#: ../lib/openid.php:121 +#: lib/openid.php:121 +msgid "Cannot instantiate OpenID consumer object." +msgstr "Non se pode instanciar o obxecto consumidor de OpenID." + +#: ../actions/imsettings.php:163 +#: actions/imsettings.php:171 +#: actions/imsettings.php:176 +msgid "Cannot normalize that Jabber ID" +msgstr "Non se pode normalizar ese identificador de Jabber" + +#: ../actions/emailsettings.php:181 +#: actions/emailsettings.php:199 +#: actions/emailsettings.php:205 +msgid "Cannot normalize that email address" +msgstr "Esa dirección de correo non se pode normalizar " + +#: ../actions/password.php:45 +#: actions/profilesettings.php:184 +#: actions/profilesettings.php:201 +msgid "Change" +msgstr "Modificado" + +#: ../lib/settingsaction.php:88 +#: lib/settingsaction.php:88 +#: actions/deleteprofile.php:245 +msgid "Change email handling" +msgstr "Cambiar a xestión de email" + +#: ../actions/password.php:32 +#: actions/profilesettings.php:36 +msgid "Change password" +msgstr "Cambiar contrasinal" + +#: ../lib/settingsaction.php:94 +msgid "Change your password" +msgstr "Cambiar contrasinal" + +#: ../lib/settingsaction.php:85 +#: lib/settingsaction.php:85 +#: actions/deleteprofile.php:242 +msgid "Change your profile settings" +msgstr "Configuración de perfil" + +#: ../actions/password.php:43 +#: ../actions/recoverpassword.php:181 +#: ../actions/register.php:155 +#: ../actions/smssettings.php:65 +#: actions/profilesettings.php:182 +#: actions/recoverpassword.php:187 +#: actions/register.php:169 +#: actions/smssettings.php:65 +#: actions/profilesettings.php:199 +#: actions/register.php:196 +msgid "Confirm" +msgstr "Confirmar" + +#: ../actions/confirmaddress.php:90 +#: actions/confirmaddress.php:90 +msgid "Confirm Address" +msgstr "Confirmar enderezo" + +#: ../actions/emailsettings.php:238 +#: ../actions/imsettings.php:222 +#: ../actions/smssettings.php:245 +#: actions/emailsettings.php:256 +#: actions/imsettings.php:230 +#: actions/smssettings.php:253 +#: actions/emailsettings.php:260 +#: actions/imsettings.php:235 +#: actions/smssettings.php:255 +msgid "Confirmation cancelled." +msgstr "Confirmación cancealada." + +#: ../actions/smssettings.php:63 +#: actions/smssettings.php:63 +msgid "Confirmation code" +msgstr "Código de confirmación." + +#: ../actions/confirmaddress.php:38 +#: actions/confirmaddress.php:38 +msgid "Confirmation code not found." +msgstr "Confirmation code not found." + +#: ../actions/register.php:202 +#: actions/register.php:243 +#, php-format +msgid "" +"Congratulations, %s! And welcome to %%%%site.name%%%%. From here, you may want to...\n" +"\n" +"* Go to [your profile](%s) and post your first message.\n" +"* Add a [Jabber/GTalk address](%%%%action.imsettings%%%%) so you can send notices through instant messages.\n" +"* [Search for people](%%%%action.peoplesearch%%%%) that you may know or that share your interests. \n" +"* Update your [profile settings](%%%%action.profilesettings%%%%) to tell others more about you. \n" +"* Read over the [online docs](%%%%doc.help%%%%) for features you may have missed. \n" +"\n" +"Thanks for signing up and we hope you enjoy using this service." +msgstr "" +"Noraboa, %s! e benvido a %%%%site.name%%%%. Dende aquí, podes...\n" +"\n" +"* Ír ó [teu perfil](%s) e enviar o teu primeiro chío.\n" +"* Engadir unha [conta de Jabber/Gtalk](%%%%action.imsettings%%%%) para enviar os teus chíos a través de mensaxería instantánea.\n" +"* [Buscar xente ](%%%%action.peoplesearch%%%%) que poidas coñecer ou que comparta os teus intereses. \n" +"* Actualizar as túas [preferencias no perfil](%%%%action.profilesettings%%%%) para decirlle a outros máis sobre ti. \n" +"* Ler os [manuais en liña](%%%%doc.help%%%%) para ollar máis cousas que podes facer aquí. \n" +"\n" +"Grazas por rexistrarte e esperamos que laretexes moito." + +#: ../actions/finishopenidlogin.php:91 +#: actions/finishopenidlogin.php:97 +msgid "Connect" +msgstr "Conectar" + +#: ../actions/finishopenidlogin.php:86 +#: actions/finishopenidlogin.php:92 +msgid "Connect existing account" +msgstr "Conectar con unha conta existente" + +#: ../lib/util.php:332 +#: lib/util.php:348 +#: lib/util.php:377 +msgid "Contact" +msgstr "Contacto" + +#: ../lib/openid.php:178 +#: lib/openid.php:178 +#, php-format +msgid "Could not create OpenID form: %s" +msgstr "Non se pode crear o formulario OpenID: %s" + +#: ../actions/twitapifriendships.php:60 +#: ../actions/twitapifriendships.php:76 +#: actions/twitapifriendships.php:60 +#: actions/twitapifriendships.php:76 +#: actions/twitapifriendships.php:46 +#: actions/twitapifriendships.php:62 +#, php-format +msgid "Could not follow user: %s is already on your list." +msgstr "Non podes seguir a este usuario: %s xa está na túa lista." + +#: ../actions/twitapifriendships.php:53 +#: actions/twitapifriendships.php:53 +#: actions/twitapifriendships.php:39 +msgid "Could not follow user: User not found." +msgstr "Non podes seguir a este usuario: o Usuario non se atopa." + +#: ../lib/openid.php:160 +#: lib/openid.php:160 +#, php-format +msgid "Could not redirect to server: %s" +msgstr "Non se pode redireccionar ao servidor: %s" + +#: ../actions/updateprofile.php:162 +#: actions/updateprofile.php:163 +msgid "Could not save avatar info" +msgstr "Non se pode gardar a información do avatar" + +#: ../actions/updateprofile.php:155 +#: actions/updateprofile.php:156 +msgid "Could not save new profile info" +msgstr "Non se pode gardar a nova información do perfil" + +#: ../lib/subs.php:54 +#: lib/subs.php:61 +#: lib/subs.php:70 +msgid "Could not subscribe other to you." +msgstr "Outro usuario non se puido suscribir a ti." + +#: ../lib/subs.php:46 +#: lib/subs.php:46 +#: lib/subs.php:55 +msgid "Could not subscribe." +msgstr "No se pode suscribir." + +#: ../actions/recoverpassword.php:102 +#: actions/recoverpassword.php:105 +msgid "Could not update user with confirmed email address." +msgstr "Non se puido actualizar o usuario coa dirección de correo electrónico." + +#: ../actions/finishremotesubscribe.php:99 +#: actions/finishremotesubscribe.php:101 +#: actions/finishremotesubscribe.php:112 +msgid "Couldn't convert request tokens to access tokens." +msgstr "Non se pode convertir o token da petición a tokens de acceso." + +#: ../actions/confirmaddress.php:84 +#: ../actions/emailsettings.php:234 +#: ../actions/imsettings.php:218 +#: ../actions/smssettings.php:241 +#: actions/confirmaddress.php:84 +#: actions/emailsettings.php:252 +#: actions/imsettings.php:226 +#: actions/smssettings.php:249 +#: actions/emailsettings.php:256 +#: actions/imsettings.php:231 +#: actions/smssettings.php:251 +msgid "Couldn't delete email confirmation." +msgstr "Non se pode eliminar a confirmación de email." + +#: ../lib/subs.php:103 +#: lib/subs.php:116 +#: lib/subs.php:129 +msgid "Couldn't delete subscription." +msgstr "Non se pode eliminar a subscrición." + +#: ../actions/twitapistatuses.php:93 +#: actions/twitapistatuses.php:98 +#: actions/twitapistatuses.php:82 +msgid "Couldn't find any statuses." +msgstr "Non se puido atopar ningún estado" + +#: ../actions/remotesubscribe.php:127 +#: actions/remotesubscribe.php:136 +#: actions/remotesubscribe.php:148 +msgid "Couldn't get a request token." +msgstr "Non se puido recoller o token de petición." + +#: ../actions/emailsettings.php:205 +#: ../actions/imsettings.php:187 +#: ../actions/smssettings.php:206 +#: actions/emailsettings.php:223 +#: actions/imsettings.php:195 +#: actions/smssettings.php:214 +#: actions/emailsettings.php:229 +#: actions/imsettings.php:200 +#: actions/smssettings.php:216 +msgid "Couldn't insert confirmation code." +msgstr "Non se puido inserir o código de confirmación." + +#: ../actions/finishremotesubscribe.php:180 +#: actions/finishremotesubscribe.php:182 +#: actions/finishremotesubscribe.php:198 +#: actions/finishremotesubscribe.php:216 +msgid "Couldn't insert new subscription." +msgstr "Non se puido inserir a nova subscrición." + +#: ../actions/profilesettings.php:184 +#: ../actions/twitapiaccount.php:96 +#: actions/profilesettings.php:299 +#: actions/twitapiaccount.php:94 +#: actions/profilesettings.php:336 +#: actions/twitapiaccount.php:77 +msgid "Couldn't save profile." +msgstr "Non se puido gardar o perfil." + +#: ../actions/profilesettings.php:161 +#: actions/profilesettings.php:276 +#: actions/profilesettings.php:313 +msgid "Couldn't update user for autosubscribe." +msgstr "Non se puido actualizar o usuario para autosuscrición." + +#: ../actions/emailsettings.php:280 +#: ../actions/emailsettings.php:294 +#: actions/emailsettings.php:298 +#: actions/emailsettings.php:312 +#: actions/emailsettings.php:302 +#: actions/emailsettings.php:316 +msgid "Couldn't update user record." +msgstr "Non se puido actualizar o rexistro de usuario." + +#: ../actions/confirmaddress.php:72 +#: ../actions/emailsettings.php:156 +#: ../actions/emailsettings.php:259 +#: ../actions/imsettings.php:138 +#: ../actions/imsettings.php:243 +#: ../actions/profilesettings.php:141 +#: ../actions/smssettings.php:157 +#: ../actions/smssettings.php:269 +#: actions/confirmaddress.php:72 +#: actions/emailsettings.php:174 +#: actions/emailsettings.php:277 +#: actions/imsettings.php:146 +#: actions/imsettings.php:251 +#: actions/profilesettings.php:256 +#: actions/smssettings.php:165 +#: actions/smssettings.php:277 +#: actions/emailsettings.php:180 +#: actions/emailsettings.php:281 +#: actions/imsettings.php:151 +#: actions/imsettings.php:256 +#: actions/othersettings.php:173 +#: actions/profilesettings.php:293 +#: actions/smspostsettings.php:96 +#: actions/smspostsettings.php:123 +#: actions/smssettings.php:167 +#: actions/smssettings.php:279 +#: actions/smspostsettings.php:101 +#: actions/smspostsettings.php:128 +msgid "Couldn't update user." +msgstr "Non se puido actualizar o usuario." + +#: ../actions/finishopenidlogin.php:84 +#: actions/finishopenidlogin.php:90 +msgid "Create" +msgstr "Crear" + +#: ../actions/finishopenidlogin.php:70 +#: actions/finishopenidlogin.php:76 +msgid "Create a new user with this nickname." +msgstr "Crear un novo usuario con este alcume." + +#: ../actions/finishopenidlogin.php:68 +#: actions/finishopenidlogin.php:74 +msgid "Create new account" +msgstr "Crear nova conta" + +#: ../actions/finishopenidlogin.php:191 +#: actions/finishopenidlogin.php:197 +#: actions/finishopenidlogin.php:208 +msgid "Creating new account for OpenID that already has a user." +msgstr "Creando nova conta para OpenID que xa ten un usuario." + +#: ../actions/imsettings.php:45 +#: actions/imsettings.php:46 +msgid "Current confirmed Jabber/GTalk address." +msgstr "Direccións Jabber/GTalk confirmadas." + +#: ../actions/smssettings.php:46 +#: actions/smssettings.php:46 +msgid "Current confirmed SMS-enabled phone number." +msgstr "Número de teléfono actual confirmado mediante SMS." + +#: ../actions/emailsettings.php:44 +#: actions/emailsettings.php:45 +msgid "Current confirmed email address." +msgstr "Direccións de correo confirmadas actualmente." + +#: ../actions/showstream.php:356 +#: actions/showstream.php:367 +#: actions/showstream.php:418 +msgid "Currently" +msgstr "Actual" + +#: ../classes/Notice.php:72 +#: classes/Notice.php:86 +#: classes/Notice.php:87 +#, php-format +msgid "DB error inserting hashtag: %s" +msgstr "Erro ó inserir o hashtag na BD: %s" + +#: ../lib/util.php:1061 +#: lib/util.php:1110 +#: lib/util.php:1479 +#, php-format +msgid "DB error inserting reply: %s" +msgstr "Erro ó inserir a contestación na BD: %s" + +#: ../actions/deletenotice.php:41 +#: actions/deletenotice.php:41 +msgid "Delete notice" +msgstr "Eliminar chío" + +#: ../actions/profilesettings.php:51 +#: ../actions/register.php:172 +#: actions/profilesettings.php:84 +#: actions/register.php:186 +#: actions/profilesettings.php:86 +#: actions/register.php:213 +msgid "Describe yourself and your interests in 140 chars" +msgstr "Contanos un pouco de ti e dos teus intereses en 140 caractéres." + +#: ../actions/register.php:158 +#: ../actions/register.php:161 +#: ../lib/settingsaction.php:87 +#: actions/register.php:172 +#: actions/register.php:175 +#: lib/settingsaction.php:87 +#: actions/deleteprofile.php:244 +#: actions/register.php:199 +#: actions/register.php:202 +msgid "Email" +msgstr "Correo Electrónico" + +#: ../actions/emailsettings.php:59 +#: actions/emailsettings.php:60 +msgid "Email Address" +msgstr "Enderezo de correo" + +#: ../actions/emailsettings.php:32 +#: actions/emailsettings.php:32 +msgid "Email Settings" +msgstr "Configuración de Correo" + +#: ../actions/register.php:73 +#: actions/register.php:80 +#: actions/register.php:89 +msgid "Email address already exists." +msgstr "O enderezo de correo xa existe." + +#: ../lib/mail.php:90 +#: lib/mail.php:90 +msgid "Email address confirmation" +msgstr "Confirmar correo electrónico" + +#: ../actions/emailsettings.php:61 +#: actions/emailsettings.php:62 +msgid "Email address, like \"UserName@example.org\"" +msgstr "Dirección de correo, coma \"Nomede Usuario@exemplo.org\"" + +#: ../actions/invite.php:129 +#: actions/invite.php:137 +msgid "Email addresses" +msgstr "Enderezos de correo" + +#: ../actions/recoverpassword.php:191 +#: actions/recoverpassword.php:197 +msgid "Enter a nickname or email address." +msgstr "Insire o teu alcume ou enderezo de correo." + +#: ../actions/smssettings.php:64 +#: actions/smssettings.php:64 +msgid "Enter the code you received on your phone." +msgstr "Insire o código que recibiches no teu teléfono." + +#: ../actions/userauthorization.php:137 +#: actions/userauthorization.php:144 +msgid "Error authorizing token" +msgstr "Erro no token de autorización." + +#: ../actions/finishopenidlogin.php:253 +#: actions/finishopenidlogin.php:259 +#: actions/finishopenidlogin.php:274 +msgid "Error connecting user to OpenID." +msgstr "Acounteceu un erro conectando o usuario ó OpenID." + +#: ../actions/finishaddopenid.php:78 +#: actions/finishaddopenid.php:78 +msgid "Error connecting user." +msgstr "Acounteceu un erro ó conectar co usuario" + +#: ../actions/finishremotesubscribe.php:151 +#: actions/finishremotesubscribe.php:153 +#: actions/finishremotesubscribe.php:164 +msgid "Error inserting avatar" +msgstr "Acounteceu un erro ó inserir o avatar" + +#: ../actions/finishremotesubscribe.php:143 +#: actions/finishremotesubscribe.php:145 +#: actions/finishremotesubscribe.php:156 +msgid "Error inserting new profile" +msgstr "Acounteceu un erro ó inserir o novo perfil" + +#: ../actions/finishremotesubscribe.php:167 +#: actions/finishremotesubscribe.php:169 +#: actions/finishremotesubscribe.php:180 +msgid "Error inserting remote profile" +msgstr "Aconteceu un erro ó inserir o perfil remoto" + +#: ../actions/recoverpassword.php:240 +#: actions/recoverpassword.php:246 +msgid "Error saving address confirmation." +msgstr "Acounteceu un erro gardando a confirmación de enderezo." + +#: ../actions/userauthorization.php:140 +#: actions/userauthorization.php:147 +msgid "Error saving remote profile" +msgstr "Acounteceu un erro gardando o perfil remoto." + +#: ../lib/openid.php:226 +#: lib/openid.php:226 +msgid "Error saving the profile." +msgstr "Acounteceu un erro ó gardar o perfil." + +#: ../lib/openid.php:237 +#: lib/openid.php:237 +msgid "Error saving the user." +msgstr "Acounteceu un erro gardando o usuario." + +#: ../actions/password.php:80 +#: actions/profilesettings.php:399 +#: actions/profilesettings.php:445 +msgid "Error saving user; invalid." +msgstr "Acounteceu un erro gardando o usuario: é inválido." + +#: ../actions/login.php:47 +#: ../actions/login.php:73 +#: ../actions/recoverpassword.php:307 +#: ../actions/register.php:98 +#: actions/login.php:47 +#: actions/login.php:73 +#: actions/recoverpassword.php:320 +#: actions/register.php:108 +#: actions/login.php:54 +#: actions/login.php:80 +#: actions/register.php:117 +msgid "Error setting user." +msgstr "Acounteceu un erro configurando o usuario." + +#: ../actions/finishaddopenid.php:83 +#: actions/finishaddopenid.php:83 +msgid "Error updating profile" +msgstr "Acounteceu un erro actualizando o usuario" + +#: ../actions/finishremotesubscribe.php:161 +#: actions/finishremotesubscribe.php:163 +#: actions/finishremotesubscribe.php:174 +msgid "Error updating remote profile" +msgstr "Acounteceu un erro actualizando o perfil remoto" + +#: ../actions/recoverpassword.php:80 +#: actions/recoverpassword.php:80 +msgid "Error with confirmation code." +msgstr "Acounteceu un erro co código de confirmación." + +#: ../actions/finishopenidlogin.php:89 +#: actions/finishopenidlogin.php:95 +msgid "Existing nickname" +msgstr "Alcume existente" + +#: ../lib/util.php:326 +#: lib/util.php:342 +#: lib/util.php:371 +msgid "FAQ" +msgstr "Preguntas frecuentes" + +#: ../actions/avatar.php:115 +#: actions/profilesettings.php:352 +#: actions/profilesettings.php:398 +msgid "Failed updating avatar." +msgstr "Acounteceu un fallo ó actualizar o avatar." + +#: ../actions/all.php:61 +#: ../actions/allrss.php:64 +#: actions/all.php:61 +#: actions/allrss.php:64 +#, php-format +msgid "Feed for friends of %s" +msgstr "Fonte para os amigos de %s" + +#: ../actions/replies.php:65 +#: ../actions/repliesrss.php:80 +#: actions/replies.php:65 +#: actions/repliesrss.php:66 +#, php-format +msgid "Feed for replies to %s" +msgstr "Fonte para as contestacións de %s" + +#: ../actions/tag.php:55 +#: actions/tag.php:55 +#: actions/tag.php:61 +#, php-format +msgid "Feed for tag %s" +msgstr "Fonte para a etiqueta %s" + +#: ../lib/searchaction.php:105 +#: lib/searchaction.php:105 +msgid "Find content of notices" +msgstr "Atopar no contido dos chíos" + +#: ../lib/searchaction.php:101 +#: lib/searchaction.php:101 +msgid "Find people on this site" +msgstr "Atopar xente neste sitio" + +#: ../actions/login.php:122 +#: actions/login.php:142 +msgid "For security reasons, please re-enter your user name and password before changing your settings." +msgstr "Por razóns de seguranza, por favor re-insire o teu nome de usuario e contrasinal antes de cambiar as túas preferenzas." + +#: ../actions/profilesettings.php:44 +#: ../actions/register.php:164 +#: actions/profilesettings.php:77 +#: actions/register.php:178 +#: actions/profilesettings.php:79 +#: actions/register.php:205 +msgid "Full name" +msgstr "Nome completo" + +#: ../actions/profilesettings.php:98 +#: ../actions/register.php:79 +#: ../actions/updateprofile.php:93 +#: actions/profilesettings.php:213 +#: actions/register.php:86 +#: actions/updateprofile.php:94 +#: actions/profilesettings.php:232 +#: actions/register.php:95 +msgid "Full name is too long (max 255 chars)." +msgstr "O nome completo é demasiado longo (max 255 car)." + +#: ../lib/util.php:322 +#: lib/util.php:338 +#: lib/util.php:359 +#: lib/util.php:367 +msgid "Help" +msgstr "Axuda" + +#: ../lib/util.php:298 +#: lib/util.php:314 +#: lib/util.php:343 +msgid "Home" +msgstr "Persoal" + +#: ../actions/profilesettings.php:46 +#: ../actions/register.php:167 +#: actions/profilesettings.php:79 +#: actions/register.php:181 +#: actions/profilesettings.php:81 +#: actions/register.php:208 +msgid "Homepage" +msgstr "Páxina persoal" + +#: ../actions/profilesettings.php:95 +#: ../actions/register.php:76 +#: actions/profilesettings.php:210 +#: actions/register.php:83 +#: actions/profilesettings.php:229 +#: actions/register.php:92 +msgid "Homepage is not a valid URL." +msgstr "A páxina persoal semella que non é unha URL válida." + +#: ../actions/emailsettings.php:91 +#: actions/emailsettings.php:98 +msgid "I want to post notices by email." +msgstr "Quero enviar chíos dende o mail." + +#: ../lib/settingsaction.php:102 +#: lib/settingsaction.php:96 +#: actions/deleteprofile.php:253 +#: lib/settingsaction.php:100 +#: lib/settingsaction.php:102 +msgid "IM" +msgstr "IM" + +#: ../actions/imsettings.php:60 +#: actions/imsettings.php:61 +msgid "IM Address" +msgstr "Enderezo de IM" + +#: ../actions/imsettings.php:33 +#: actions/imsettings.php:33 +msgid "IM Settings" +msgstr "Configuracións de IM" + +#: ../actions/finishopenidlogin.php:88 +#: actions/finishopenidlogin.php:94 +msgid "If you already have an account, login with your username and password to connect it to your OpenID." +msgstr "Se xa tes unha conta, accede co teu usuario e contrasinal para conectar co teu OpenID." + +#: ../actions/openidsettings.php:45 +#: actions/openidsettings.php:46 +msgid "If you want to add an OpenID to your account, enter it in the box below and click \"Add\"." +msgstr "Se queres engadir un enderezo OpenID á tua conta, insirea na caixa de embaixo e fai clic en \"Engadir\"." + +#: ../actions/recoverpassword.php:137 +#: actions/recoverpassword.php:141 +msgid "If you've forgotten or lost your password, you can get a new one sent to the email address you have stored in your account." +msgstr "Se esquenceches ou perdeches a túa contrasinal, podes obter unha nova no enderezo de correo que configuraches na túa conta." + +#: ../actions/emailsettings.php:67 +#: ../actions/smssettings.php:76 +#: actions/emailsettings.php:68 +#: actions/smssettings.php:76 +msgid "Incoming email" +msgstr "Correo Entrante" + +#: ../actions/emailsettings.php:283 +#: actions/emailsettings.php:301 +#: actions/emailsettings.php:305 +msgid "Incoming email address removed." +msgstr "Dirección de correo entrante eliminada." + +#: ../actions/password.php:69 +#: actions/profilesettings.php:388 +#: actions/profilesettings.php:434 +msgid "Incorrect old password" +msgstr "Contrasinal actual incorrecta" + +#: ../actions/login.php:67 +#: actions/login.php:67 +#: actions/login.php:74 +msgid "Incorrect username or password." +msgstr "Usuario ou contrasinal incorrectos." + +#: ../actions/recoverpassword.php:265 +#: actions/recoverpassword.php:271 +msgid "Instructions for recovering your password have been sent to the email address registered to your account." +msgstr "As instruccións para recuperar a túa contrasinal foron enviadas ó enderezo de correo da túa conta." + +#: ../actions/updateprofile.php:114 +#: actions/updateprofile.php:115 +#, php-format +msgid "Invalid avatar URL '%s'" +msgstr "URL do avatar '%s' inválido" + +#: ../actions/invite.php:55 +#: actions/invite.php:62 +#, php-format +msgid "Invalid email address: %s" +msgstr "Dirección de correo Inválida: %s" + +#: ../actions/updateprofile.php:98 +#: actions/updateprofile.php:99 +#, php-format +msgid "Invalid homepage '%s'" +msgstr "Páxina persoal '%s' inválida" + +#: ../actions/updateprofile.php:82 +#: actions/updateprofile.php:83 +#, php-format +msgid "Invalid license URL '%s'" +msgstr "URL de licenza '%s' inválida" + +#: ../actions/postnotice.php:61 +#: actions/postnotice.php:62 +#: actions/postnotice.php:63 +msgid "Invalid notice content" +msgstr "Contido do chío inválido" + +#: ../actions/postnotice.php:67 +#: actions/postnotice.php:68 +#: actions/postnotice.php:69 +msgid "Invalid notice uri" +msgstr "Enderezo de chío inválido" + +#: ../actions/postnotice.php:72 +#: actions/postnotice.php:73 +#: actions/postnotice.php:74 +msgid "Invalid notice url" +msgstr "Enderezo de chío inválido" + +#: ../actions/updateprofile.php:87 +#: actions/updateprofile.php:88 +#, php-format +msgid "Invalid profile URL '%s'." +msgstr "Enderezo de perfil inválido '%s'." + +#: ../actions/remotesubscribe.php:96 +#: actions/remotesubscribe.php:105 +msgid "Invalid profile URL (bad format)" +msgstr "Enderezo de perfil inválido (formato incorrecto)" + +#: ../actions/finishremotesubscribe.php:77 +#: actions/finishremotesubscribe.php:79 +#: actions/finishremotesubscribe.php:78 +msgid "Invalid profile URL returned by server." +msgstr "Enderezo de perfil inválido devolto polo servidor." + +#: ../actions/avatarbynickname.php:37 +#: actions/avatarbynickname.php:37 +msgid "Invalid size." +msgstr "Tamaño inválido." + +#: ../actions/finishopenidlogin.php:235 +#: ../actions/register.php:93 +#: ../actions/register.php:111 +#: actions/finishopenidlogin.php:241 +#: actions/register.php:103 +#: actions/register.php:121 +#: actions/finishopenidlogin.php:256 +#: actions/register.php:112 +#: actions/register.php:130 +msgid "Invalid username or password." +msgstr "Usuario ou contrasinal inválidos." + +#: ../actions/invite.php:79 +#: actions/invite.php:86 +msgid "Invitation(s) sent" +msgstr "Invitación(s) enviada(s)." + +#: ../actions/invite.php:97 +#: actions/invite.php:104 +msgid "Invitation(s) sent to the following people:" +msgstr "Invitación(s) enviada(s) á seguinte xente:" + +#: ../lib/util.php:306 +#: lib/util.php:322 +#: lib/util.php:382 +msgid "Invite" +msgstr "Invitar" + +#: ../actions/invite.php:123 +#: actions/invite.php:130 +msgid "Invite new users" +msgstr "Invitar a novos usuarios" + +#: ../lib/util.php:261 +#: lib/util.php:277 +#: lib/util.php:294 +#, php-format +msgid "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)." +msgstr "Correndo o software de microblogaxe [StatusNet](http://status.net/), versión %s, dispoñible baixo licenza [GNU Affero General Public License](http://www.fsf.org/licensing/licenses/agpl-3.0.html)." + +#: ../actions/imsettings.php:173 +#: actions/imsettings.php:181 +#: actions/imsettings.php:186 +msgid "Jabber ID already belongs to another user." +msgstr "O identificador de Jabber xa pertence a outro usuario." + +#: ../actions/imsettings.php:62 +#: actions/imsettings.php:63 +#, php-format +msgid "Jabber or GTalk address, like \"UserName@example.org\". First, make sure to add %s to your buddy list in your IM client or on GTalk." +msgstr "Enderezo Jabber ou GTalk, coma \"NomeUsuario@Exemplo.org\". Primeiro, asegurate de engadir %s á tua lista de contactos no teu cliente de IM ou no GTalk." + +#: ../actions/profilesettings.php:57 +#: actions/profilesettings.php:90 +#: actions/profilesettings.php:98 +msgid "Language" +msgstr "Linguaxe" + +#: ../actions/profilesettings.php:113 +#: actions/profilesettings.php:228 +#: actions/profilesettings.php:247 +msgid "Language is too long (max 50 chars)." +msgstr "A Linguaxe é demasiado longa (max 50 car.)." + +#: ../actions/profilesettings.php:52 +#: ../actions/register.php:173 +#: actions/profilesettings.php:85 +#: actions/register.php:187 +#: actions/profilesettings.php:87 +#: actions/register.php:214 +msgid "Location" +msgstr "Localización" + +#: ../actions/profilesettings.php:104 +#: ../actions/register.php:85 +#: ../actions/updateprofile.php:108 +#: actions/profilesettings.php:219 +#: actions/register.php:92 +#: actions/updateprofile.php:109 +#: actions/profilesettings.php:238 +#: actions/register.php:101 +msgid "Location is too long (max 255 chars)." +msgstr "A localización é demasiado longa (max 255 car.)." + +#: ../actions/login.php:97 +#: ../actions/login.php:106 +#: ../actions/openidlogin.php:68 +#: ../lib/util.php:310 +#: actions/login.php:97 +#: actions/login.php:106 +#: actions/openidlogin.php:77 +#: lib/util.php:326 +#: actions/login.php:104 +#: actions/login.php:113 +#: actions/login.php:129 +#: actions/openidlogin.php:88 +#: lib/util.php:352 +msgid "Login" +msgstr "Inicio de sesión" + +#: ../actions/openidlogin.php:44 +#: actions/openidlogin.php:52 +#: actions/openidlogin.php:60 +#, php-format +msgid "Login with an [OpenID](%%doc.openid%%) account." +msgstr "Acceder con unha conta [OpenID](%%doc.openid%%)." + +#: ../actions/login.php:126 +#: actions/login.php:146 +#, php-format +msgid "Login with your username and password. Don't have a username yet? [Register](%%action.register%%) a new account, or try [OpenID](%%action.openidlogin%%). " +msgstr "Accede co teu nome de usuario e contrasinal. ¿Non tes un todavía?? [Rexistra](%%action.register%%) unha nova conta, ou accede co teu enderezo [OpenID](%%action.openidlogin%%). " + +#: ../lib/util.php:308 +#: lib/util.php:324 +#: lib/util.php:350 +msgid "Logout" +msgstr "Sair" + +#: ../actions/register.php:166 +#: actions/register.php:180 +#: actions/register.php:207 +msgid "Longer name, preferably your \"real\" name" +msgstr "Nome máis longo, preferiblemente o teu nome \"real\"" + +#: ../actions/login.php:110 +#: actions/login.php:110 +#: actions/login.php:118 +msgid "Lost or forgotten password?" +msgstr "¿Perdeches a contrasinal?" + +#: ../actions/emailsettings.php:80 +#: ../actions/smssettings.php:89 +#: actions/emailsettings.php:81 +#: actions/smssettings.php:89 +msgid "Make a new email address for posting to; cancels the old one." +msgstr "Crear unha nova dirección de correo para enviar, elimina a antiga." + +#: ../actions/emailsettings.php:27 +#: actions/emailsettings.php:27 +#, php-format +msgid "Manage how you get email from %%site.name%%." +msgstr "Xestina como recibir correo dende %%site.name%%." + +#: ../actions/showstream.php:300 +#: actions/showstream.php:315 +#: actions/showstream.php:363 +msgid "Member since" +msgstr "Membro dende" + +#: ../actions/userrss.php:70 +#: actions/userrss.php:67 +#, php-format +msgid "Microblog by %s" +msgstr "Microblogue por %s" + +#: ../actions/smssettings.php:304 +#: actions/smssettings.php:314 +#, php-format +msgid "Mobile carrier for your phone. If you know a carrier that accepts SMS over email but isn't listed here, send email to let us know at %s." +msgstr "Operadora móbil do teu teléfono. Se sabes se a operadora acepta SMS sobre email e non está listada aquí, envianos unha mensaxe para incluilo en %s." + +#: ../actions/finishopenidlogin.php:79 +#: ../actions/register.php:188 +#: actions/finishopenidlogin.php:85 +#: actions/register.php:202 +#: actions/register.php:229 +msgid "My text and files are available under " +msgstr "O meu texto e arquivos están dispoñibles baixo licenza " + +#: ../actions/emailsettings.php:82 +#: ../actions/smssettings.php:91 +#: actions/emailsettings.php:83 +#: actions/smssettings.php:91 +msgid "New" +msgstr "Novo" + +#: ../lib/mail.php:144 +#: lib/mail.php:144 +#: lib/mail.php:138 +#, php-format +msgid "New email address for posting to %s" +msgstr "Nova dirección de email para posterar en %s" + +#: ../actions/emailsettings.php:297 +#: actions/emailsettings.php:315 +#: actions/emailsettings.php:319 +msgid "New incoming email address added." +msgstr "Engadida nova dirección de correo entrante." + +#: ../actions/finishopenidlogin.php:71 +#: actions/finishopenidlogin.php:77 +msgid "New nickname" +msgstr "Novo alcume" + +#: ../actions/newnotice.php:87 +#: actions/newnotice.php:96 +#: actions/newnotice.php:141 +msgid "New notice" +msgstr "Novo chío" + +#: ../actions/password.php:41 +#: ../actions/recoverpassword.php:179 +#: actions/profilesettings.php:180 +#: actions/recoverpassword.php:185 +#: actions/profilesettings.php:197 +msgid "New password" +msgstr "Nova contrasinal" + +#: ../actions/recoverpassword.php:314 +#: actions/recoverpassword.php:327 +msgid "New password successfully saved. You are now logged in." +msgstr "A nova contrasinal gardouse correctamente. Xa estas logueado." + +#: ../actions/login.php:101 +#: ../actions/profilesettings.php:41 +#: ../actions/register.php:151 +#: actions/login.php:101 +#: actions/profilesettings.php:74 +#: actions/register.php:165 +#: actions/login.php:108 +#: actions/profilesettings.php:76 +#: actions/register.php:192 +msgid "Nickname" +msgstr "Alcume" + +#: ../actions/finishopenidlogin.php:175 +#: ../actions/profilesettings.php:110 +#: ../actions/register.php:69 +#: actions/finishopenidlogin.php:181 +#: actions/profilesettings.php:225 +#: actions/register.php:76 +#: actions/finishopenidlogin.php:192 +#: actions/profilesettings.php:244 +#: actions/register.php:85 +msgid "Nickname already in use. Try another one." +msgstr "O alcume xa está sendo empregado por outro usuario. Tenta con outro." + +#: ../actions/finishopenidlogin.php:165 +#: ../actions/profilesettings.php:88 +#: ../actions/register.php:67 +#: ../actions/updateprofile.php:77 +#: actions/finishopenidlogin.php:171 +#: actions/profilesettings.php:203 +#: actions/register.php:74 +#: actions/updateprofile.php:78 +#: actions/finishopenidlogin.php:182 +#: actions/profilesettings.php:222 +#: actions/register.php:83 +msgid "Nickname must have only lowercase letters and numbers and no spaces." +msgstr "O alcume debe ter só letras minúsculas e números, e sen espazos." + +#: ../actions/finishopenidlogin.php:170 +#: actions/finishopenidlogin.php:176 +#: actions/finishopenidlogin.php:187 +msgid "Nickname not allowed." +msgstr "Alcume non permitido." + +#: ../actions/remotesubscribe.php:72 +#: actions/remotesubscribe.php:81 +msgid "Nickname of the user you want to follow" +msgstr "Alcume de usuario que queres" + +#: ../actions/recoverpassword.php:162 +#: actions/recoverpassword.php:167 +msgid "Nickname or email" +msgstr "Alcume ou email" + +#: ../actions/deletenotice.php:59 +#: actions/deletenotice.php:60 +#: actions/block.php:104 +msgid "No" +msgstr "No" + +#: ../actions/imsettings.php:156 +#: actions/imsettings.php:164 +#: actions/imsettings.php:169 +msgid "No Jabber ID." +msgstr "Sen Identificador de Jabber." + +#: ../actions/userauthorization.php:129 +#: actions/userauthorization.php:136 +msgid "No authorization request!" +msgstr "Sen petición de autorización!" + +#: ../actions/smssettings.php:181 +#: actions/smssettings.php:189 +#: actions/smssettings.php:191 +msgid "No carrier selected." +msgstr "Non se seleccionou unha operadora." + +#: ../actions/smssettings.php:316 +#: actions/smssettings.php:324 +#: actions/smssettings.php:326 +msgid "No code entered" +msgstr "Non se inseriu ningún código" + +#: ../actions/confirmaddress.php:33 +#: actions/confirmaddress.php:33 +msgid "No confirmation code." +msgstr "Sen código de confirmación." + +#: ../actions/newnotice.php:44 +#: actions/newmessage.php:53 +#: actions/newnotice.php:44 +#: classes/Command.php:197 +#: actions/newmessage.php:52 +#: actions/newnotice.php:53 +msgid "No content!" +msgstr "Sen contido!" + +#: ../actions/emailsettings.php:174 +#: actions/emailsettings.php:192 +#: actions/emailsettings.php:198 +msgid "No email address." +msgstr "Non se inseriu unha dirección de correo" + +#: ../actions/userbyid.php:32 +#: actions/userbyid.php:32 +msgid "No id." +msgstr "Sen id." + +#: ../actions/emailsettings.php:271 +#: actions/emailsettings.php:289 +#: actions/emailsettings.php:293 +msgid "No incoming email address." +msgstr "Non hai direccións de correo entrante" + +#: ../actions/finishremotesubscribe.php:65 +#: actions/finishremotesubscribe.php:67 +#: actions/finishremotesubscribe.php:66 +msgid "No nickname provided by remote server." +msgstr "O servidor remoto non proporcionou un alcume." + +#: ../actions/avatarbynickname.php:27 +#: actions/avatarbynickname.php:27 +msgid "No nickname." +msgstr "Sen alcume." + +#: ../actions/emailsettings.php:222 +#: ../actions/imsettings.php:206 +#: ../actions/smssettings.php:229 +#: actions/emailsettings.php:240 +#: actions/imsettings.php:214 +#: actions/smssettings.php:237 +#: actions/emailsettings.php:244 +#: actions/imsettings.php:219 +#: actions/smssettings.php:239 +msgid "No pending confirmation to cancel." +msgstr "Non hai ningunha confirmación pendente para cancelar." + +#: ../actions/smssettings.php:176 +#: actions/smssettings.php:184 +#: actions/smspostsettings.php:76 +#: actions/smssettings.php:186 +#: actions/smspostsettings.php:81 +msgid "No phone number." +msgstr "Non hai ningún número de teléfono." + +#: ../actions/finishremotesubscribe.php:72 +#: actions/finishremotesubscribe.php:74 +#: actions/finishremotesubscribe.php:73 +msgid "No profile URL returned by server." +msgstr "O servidor non voltou ningún enderezo de perfil." + +#: ../actions/recoverpassword.php:226 +#: actions/recoverpassword.php:232 +msgid "No registered email address for that user." +msgstr "Non hai un enderezo de correo rexistrado para ese usuario." + +#: ../actions/userauthorization.php:49 +#: actions/userauthorization.php:55 +msgid "No request found!" +msgstr "¡Non se atoparon peticións!" + +#: ../actions/noticesearch.php:64 +#: ../actions/peoplesearch.php:64 +#: actions/noticesearch.php:69 +#: actions/peoplesearch.php:69 +#: actions/noticesearch.php:68 +#: actions/peoplesearch.php:59 +msgid "No results" +msgstr "Non se atoparon resultados" + +#: ../actions/avatarbynickname.php:32 +#: actions/avatarbynickname.php:32 +msgid "No size." +msgstr "Sen tamaño." + +#: ../actions/twitapistatuses.php:595 +#: actions/twitapifavorites.php:136 +#: actions/twitapistatuses.php:520 +#: actions/twitapifavorites.php:109 +#: actions/twitapistatuses.php:438 +msgid "No status found with that ID." +msgstr "Non se atopou un estado con ese ID." + +#: ../actions/twitapistatuses.php:555 +#: actions/twitapistatuses.php:478 +#: actions/twitapistatuses.php:411 +msgid "No status with that ID found." +msgstr "Non existe ningún estado con esa ID atopada." + +#: ../actions/openidsettings.php:135 +#: actions/openidsettings.php:144 +msgid "No such OpenID." +msgstr "Ningún OpenID." + +#: ../actions/doc.php:29 +#: actions/doc.php:29 +msgid "No such document." +msgstr "Ningún documento." + +#: ../actions/shownotice.php:32 +#: ../actions/shownotice.php:83 +#: ../lib/deleteaction.php:30 +#: actions/shownotice.php:32 +#: actions/shownotice.php:83 +#: lib/deleteaction.php:30 +#: actions/shownotice.php:38 +#: actions/shownotice.php:114 +msgid "No such notice." +msgstr "Ningún chío." + +#: ../actions/recoverpassword.php:56 +#: actions/recoverpassword.php:56 +msgid "No such recovery code." +msgstr "Ningún código de recuperación." + +#: ../actions/postnotice.php:56 +#: actions/postnotice.php:57 +msgid "No such subscription" +msgstr "Ningunha subscripción" + +#: ../actions/all.php:34 +#: ../actions/allrss.php:35 +#: ../actions/avatarbynickname.php:43 +#: ../actions/foaf.php:40 +#: ../actions/remotesubscribe.php:84 +#: ../actions/remotesubscribe.php:91 +#: ../actions/replies.php:57 +#: ../actions/repliesrss.php:35 +#: ../actions/showstream.php:110 +#: ../actions/userbyid.php:36 +#: ../actions/userrss.php:35 +#: ../actions/xrds.php:35 +#: ../lib/gallery.php:57 +#: ../lib/subs.php:33 +#: ../lib/subs.php:82 +#: actions/all.php:34 +#: actions/allrss.php:35 +#: actions/avatarbynickname.php:43 +#: actions/favoritesrss.php:35 +#: actions/foaf.php:40 +#: actions/ical.php:31 +#: actions/remotesubscribe.php:93 +#: actions/remotesubscribe.php:100 +#: actions/replies.php:57 +#: actions/repliesrss.php:35 +#: actions/showfavorites.php:34 +#: actions/showstream.php:110 +#: actions/userbyid.php:36 +#: actions/userrss.php:35 +#: actions/xrds.php:35 +#: classes/Command.php:120 +#: classes/Command.php:162 +#: classes/Command.php:203 +#: classes/Command.php:237 +#: lib/gallery.php:62 +#: lib/mailbox.php:36 +#: lib/subs.php:33 +#: lib/subs.php:95 +#: actions/showstream.php:157 +#: classes/Command.php:208 +#: classes/Command.php:242 +#: lib/gallery.php:85 +#: lib/subs.php:105 +msgid "No such user." +msgstr "Ningún usuario." + +#: ../actions/recoverpassword.php:211 +#: actions/recoverpassword.php:217 +msgid "No user with that email address or username." +msgstr "Non hai ningún usuario con isa dirección de correo ou nome de usuario." + +#: ../lib/gallery.php:80 +#: lib/gallery.php:85 +#: actions/users.php:59 +msgid "Nobody to show!" +msgstr "Ninguén para amosar" + +#: ../actions/recoverpassword.php:60 +#: actions/recoverpassword.php:60 +msgid "Not a recovery code." +msgstr "Non é un código de recuperación." + +#: ../scripts/maildaemon.php:50 +#: scripts/maildaemon.php:50 +msgid "Not a registered user." +msgstr "Non é un usuario rexistrado." + +#: ../lib/twitterapi.php:226 +#: ../lib/twitterapi.php:247 +#: ../lib/twitterapi.php:332 +#: lib/twitterapi.php:391 +#: lib/twitterapi.php:418 +#: lib/twitterapi.php:502 +#: lib/twitterapi.php:423 +#: lib/twitterapi.php:450 +#: lib/twitterapi.php:534 +msgid "Not a supported data format." +msgstr "Non é un formato de datos soportado." + +#: ../actions/imsettings.php:167 +#: actions/imsettings.php:175 +#: actions/imsettings.php:180 +msgid "Not a valid Jabber ID" +msgstr "Non é un Identificador de Jabber válido" + +#: ../lib/openid.php:131 +#: lib/openid.php:131 +msgid "Not a valid OpenID." +msgstr "Non é un enderezo OpenID válido." + +#: ../actions/emailsettings.php:185 +#: actions/emailsettings.php:203 +#: actions/emailsettings.php:209 +msgid "Not a valid email address" +msgstr "Non é unha dirección de correo válida" + +#: ../actions/register.php:63 +#: actions/register.php:70 +#: actions/register.php:79 +msgid "Not a valid email address." +msgstr "Non é un enderezo de correo válido." + +#: ../actions/profilesettings.php:91 +#: ../actions/register.php:71 +#: actions/profilesettings.php:206 +#: actions/register.php:78 +#: actions/profilesettings.php:225 +#: actions/register.php:87 +msgid "Not a valid nickname." +msgstr "Non é un alcume válido." + +#: ../actions/remotesubscribe.php:120 +#: actions/remotesubscribe.php:129 +msgid "Not a valid profile URL (incorrect services)." +msgstr "Non é un enderezo de perfil válido (servizos incorrectos)." + +#: ../actions/remotesubscribe.php:113 +#: actions/remotesubscribe.php:122 +msgid "Not a valid profile URL (no XRDS defined)." +msgstr "Non é un enderezo de perfil válido (non está definido ningún XRDS)." + +#: ../actions/remotesubscribe.php:104 +#: actions/remotesubscribe.php:113 +msgid "Not a valid profile URL (no YADIS document)." +msgstr "Non é un enderezo de perfil válido (non ten documento YADIS)." + +#: ../actions/avatar.php:95 +#: actions/profilesettings.php:332 +#: actions/profilesettings.php:378 +msgid "Not an image or corrupt file." +msgstr "Non é unha imaxe ou está corrupta." + +#: ../actions/finishremotesubscribe.php:51 +#: actions/finishremotesubscribe.php:53 +#: actions/finishremotesubscribe.php:52 +msgid "Not authorized." +msgstr "Non está autorizado." + +#: ../actions/finishremotesubscribe.php:38 +#: actions/finishremotesubscribe.php:38 +msgid "Not expecting this response!" +msgstr "¡Non esperaba esa resposta!" + +#: ../actions/twitapistatuses.php:422 +#: actions/twitapistatuses.php:361 +#: actions/twitapistatuses.php:304 +msgid "Not found" +msgstr "Non atopado" + +#: ../actions/finishaddopenid.php:29 +#: ../actions/logout.php:33 +#: ../actions/newnotice.php:29 +#: ../actions/subscribe.php:28 +#: ../actions/unsubscribe.php:25 +#: ../lib/deleteaction.php:38 +#: ../lib/settingsaction.php:27 +#: actions/disfavor.php:29 +#: actions/favor.php:30 +#: actions/finishaddopenid.php:29 +#: actions/logout.php:33 +#: actions/newmessage.php:28 +#: actions/newnotice.php:29 +#: actions/subscribe.php:28 +#: actions/unsubscribe.php:25 +#: lib/deleteaction.php:38 +#: lib/settingsaction.php:27 +#: actions/block.php:31 +#: actions/misc.php:27 +#: actions/newnotice.php:30 +#: actions/nudge.php:30 +#: actions/subedit.php:31 +#: actions/unblock.php:31 +msgid "Not logged in." +msgstr "Non está logueado." + +#: ../lib/subs.php:91 +#: lib/subs.php:104 +#: lib/subs.php:117 +msgid "Not subscribed!." +msgstr "Non está suscrito!" + +#: ../actions/opensearch.php:35 +#: actions/opensearch.php:35 +msgid "Notice Search" +msgstr "Procura de Chíos" + +#: ../actions/showstream.php:82 +#: actions/showstream.php:82 +#: actions/showstream.php:111 +#: actions/showstream.php:118 +#: actions/showstream.php:123 +#, php-format +msgid "Notice feed for %s" +msgstr "Fonte de chíos para %s" + +#: ../actions/shownotice.php:39 +#: actions/shownotice.php:39 +#: actions/shownotice.php:45 +msgid "Notice has no profile" +msgstr "O chío non ten perfil" + +#: ../actions/showstream.php:316 +#: actions/showstream.php:331 +#: actions/showstream.php:379 +msgid "Notices" +msgstr "Chíos" + +#: ../actions/tag.php:35 +#: ../actions/tag.php:81 +#: actions/tag.php:35 +#: actions/tag.php:81 +#, php-format +msgid "Notices tagged with %s" +msgstr "Chíos tagueados con %s" + +#: ../actions/password.php:39 +#: actions/profilesettings.php:178 +#: actions/profilesettings.php:195 +msgid "Old password" +msgstr "Contrasinal antiga" + +#: ../lib/settingsaction.php:96 +#: ../lib/util.php:314 +#: lib/settingsaction.php:90 +#: lib/util.php:330 +#: actions/deleteprofile.php:247 +msgid "OpenID" +msgstr "OpenID" + +#: ../actions/finishopenidlogin.php:61 +#: actions/finishopenidlogin.php:66 +msgid "OpenID Account Setup" +msgstr "Configuración de conta OpenID" + +#: ../lib/openid.php:180 +#: lib/openid.php:180 +msgid "OpenID Auto-Submit" +msgstr "Auto-Envío de OpenID" + +#: ../actions/finishaddopenid.php:99 +#: ../actions/finishopenidlogin.php:140 +#: ../actions/openidlogin.php:60 +#: actions/finishaddopenid.php:99 +#: actions/finishopenidlogin.php:146 +#: actions/openidlogin.php:68 +#: actions/finishopenidlogin.php:150 +#: actions/openidlogin.php:76 +msgid "OpenID Login" +msgstr "Acceso OpenID" + +#: ../actions/openidlogin.php:65 +#: ../actions/openidsettings.php:49 +#: actions/openidlogin.php:74 +#: actions/openidsettings.php:50 +#: actions/login.php:125 +#: actions/openidlogin.php:82 +msgid "OpenID URL" +msgstr "Enderezo OpenID" + +#: ../actions/finishaddopenid.php:42 +#: ../actions/finishopenidlogin.php:103 +#: actions/finishaddopenid.php:42 +#: actions/finishopenidlogin.php:109 +msgid "OpenID authentication cancelled." +msgstr "Autenticación OpenID cancelada." + +#: ../actions/finishaddopenid.php:46 +#: ../actions/finishopenidlogin.php:107 +#: actions/finishaddopenid.php:46 +#: actions/finishopenidlogin.php:113 +#, php-format +msgid "OpenID authentication failed: %s" +msgstr "A autenticación OpenID fallou: %s" + +#: ../lib/openid.php:133 +#: lib/openid.php:133 +#, php-format +msgid "OpenID failure: %s" +msgstr "Fallou o OpenID: %s" + +#: ../actions/openidsettings.php:144 +#: actions/openidsettings.php:153 +msgid "OpenID removed." +msgstr "OpenID eliminado." + +#: ../actions/openidsettings.php:37 +#: actions/openidsettings.php:37 +msgid "OpenID settings" +msgstr "Configuracións de OpenID" + +#: ../actions/invite.php:135 +#: actions/invite.php:143 +msgid "Optionally add a personal message to the invitation." +msgstr "Opcionalmente engadir unha mensaxe persoal á invitación." + +#: ../actions/avatar.php:84 +#: actions/profilesettings.php:321 +#: actions/profilesettings.php:367 +msgid "Partial upload." +msgstr "Carga parcial." + +#: ../actions/finishopenidlogin.php:90 +#: ../actions/login.php:102 +#: ../actions/register.php:153 +#: ../lib/settingsaction.php:93 +#: actions/finishopenidlogin.php:96 +#: actions/login.php:102 +#: actions/register.php:167 +#: actions/login.php:109 +#: actions/register.php:194 +msgid "Password" +msgstr "Contrasinal" + +#: ../actions/recoverpassword.php:288 +#: actions/recoverpassword.php:301 +msgid "Password and confirmation do not match." +msgstr "A contrasinal e a súa confirmación non coinciden." + +#: ../actions/recoverpassword.php:284 +#: actions/recoverpassword.php:297 +msgid "Password must be 6 chars or more." +msgstr "A contrasinal debe ter 6 caracteres ou máis." + +#: ../actions/recoverpassword.php:261 +#: ../actions/recoverpassword.php:263 +#: actions/recoverpassword.php:267 +#: actions/recoverpassword.php:269 +msgid "Password recovery requested" +msgstr "Petición de recuperación de contrasinal" + +#: ../actions/password.php:89 +#: ../actions/recoverpassword.php:313 +#: actions/profilesettings.php:408 +#: actions/recoverpassword.php:326 +#: actions/profilesettings.php:454 +msgid "Password saved." +msgstr "Contrasinal gardada." + +#: ../actions/password.php:61 +#: ../actions/register.php:88 +#: actions/profilesettings.php:380 +#: actions/register.php:98 +#: actions/profilesettings.php:426 +#: actions/register.php:107 +msgid "Passwords don't match." +msgstr "As contrasinais non coinciden" + +#: ../lib/searchaction.php:100 +#: lib/searchaction.php:100 +msgid "People" +msgstr "Xente" + +#: ../actions/opensearch.php:33 +#: actions/opensearch.php:33 +msgid "People Search" +msgstr "Procurar xente" + +#: ../actions/peoplesearch.php:33 +#: actions/peoplesearch.php:33 +msgid "People search" +msgstr "Procurar xente." + +#: ../lib/stream.php:50 +#: lib/personal.php:50 +msgid "Personal" +msgstr "Persoal" + +#: ../actions/invite.php:133 +#: actions/invite.php:141 +msgid "Personal message" +msgstr "Mensaxe persoal" + +#: ../actions/smssettings.php:69 +#: actions/smssettings.php:69 +#: actions/smspostsettings.php:49 +#: actions/smspostsettings.php:50 +msgid "Phone number, no punctuation or spaces, with area code" +msgstr "Número de teléfono, sen puntuacións ou espazos, co código de área" + +#: ../actions/userauthorization.php:78 +#: actions/userauthorization.php:84 +msgid "Please check these details to make sure that you want to subscribe to this user's notices. If you didn't just ask to subscribe to someone's notices, click \"Cancel\"." +msgstr "Please check these details to make sure that you want to subscribe to this user's notices. If you didn't just ask to subscribe to someone's notices, click \"Cancel\"." + +#: ../actions/imsettings.php:73 +#: actions/imsettings.php:74 +msgid "Post a notice when my Jabber/GTalk status changes." +msgstr "Post a notice when my Jabber/GTalk status changes." + +#: ../actions/emailsettings.php:85 +#: ../actions/imsettings.php:67 +#: ../actions/smssettings.php:94 +#: actions/emailsettings.php:86 +#: actions/imsettings.php:68 +#: actions/smssettings.php:94 +#: actions/twittersettings.php:70 +msgid "Preferences" +msgstr "Preferencias" + +#: ../actions/emailsettings.php:162 +#: ../actions/imsettings.php:144 +#: ../actions/smssettings.php:163 +#: actions/emailsettings.php:180 +#: actions/imsettings.php:152 +#: actions/smssettings.php:171 +#: actions/emailsettings.php:186 +#: actions/imsettings.php:157 +#: actions/othersettings.php:179 +#: actions/smssettings.php:173 +msgid "Preferences saved." +msgstr "Preferencias gardadas." + +#: ../actions/profilesettings.php:57 +#: actions/profilesettings.php:90 +#: actions/profilesettings.php:98 +msgid "Preferred language" +msgstr "Linguaxe preferida" + +#: ../lib/util.php:328 +#: lib/util.php:344 +#: lib/util.php:373 +msgid "Privacy" +msgstr "Privacidade" + +#: ../classes/Notice.php:95 +#: ../classes/Notice.php:106 +#: classes/Notice.php:109 +#: classes/Notice.php:119 +#: classes/Notice.php:139 +#: classes/Notice.php:149 +msgid "Problem saving notice." +msgstr "Aconteceu un erro ó gardar o chío." + +#: ../lib/settingsaction.php:84 +#: ../lib/stream.php:60 +#: lib/personal.php:60 +#: lib/settingsaction.php:84 +#: actions/deleteprofile.php:241 +msgid "Profile" +msgstr "Perfil" + +#: ../actions/remotesubscribe.php:73 +#: actions/remotesubscribe.php:82 +msgid "Profile URL" +msgstr "Enderezo de perfil" + +#: ../actions/profilesettings.php:34 +#: actions/profilesettings.php:32 +msgid "Profile settings" +msgstr "Configuración de perfil" + +#: ../actions/postnotice.php:51 +#: ../actions/updateprofile.php:52 +#: actions/postnotice.php:52 +#: actions/updateprofile.php:53 +msgid "Profile unknown" +msgstr "Perfil descoñecido" + +#: ../actions/public.php:54 +#: actions/public.php:54 +#: actions/public.php:77 +msgid "Public Stream Feed" +msgstr "Sindicación do Fio Público" + +#: ../actions/public.php:33 +#: actions/public.php:33 +#: lib/stream.php:34 +msgid "Public timeline" +msgstr "Liña de tempo pública" + +#: ../actions/imsettings.php:79 +#: actions/imsettings.php:80 +msgid "Publish a MicroID for my Jabber/GTalk address." +msgstr "Publicar unha MicroID dende a miña dirección de Jabber/GTalk." + +#: ../actions/emailsettings.php:94 +#: actions/emailsettings.php:101 +msgid "Publish a MicroID for my email address." +msgstr "Publicar unha MicroID dende a miña dirección de correo." + +#: ../actions/tag.php:75 +#: ../actions/tag.php:76 +#: actions/tag.php:75 +#: actions/tag.php:76 +msgid "Recent Tags" +msgstr "Tags Recentes" + +#: ../actions/recoverpassword.php:166 +#: actions/recoverpassword.php:171 +msgid "Recover" +msgstr "Recuperar" + +#: ../actions/recoverpassword.php:156 +#: actions/recoverpassword.php:161 +msgid "Recover password" +msgstr "Recuperar contrasinal" + +#: ../actions/recoverpassword.php:67 +#: actions/recoverpassword.php:67 +msgid "Recovery code for unknown user." +msgstr "Código de recuperación para usuario descoñecido." + +#: ../actions/register.php:142 +#: ../actions/register.php:193 +#: ../lib/util.php:312 +#: actions/register.php:152 +#: actions/register.php:207 +#: lib/util.php:328 +#: actions/register.php:181 +#: actions/register.php:234 +#: lib/util.php:354 +msgid "Register" +msgstr "Rexistrar" + +#: ../actions/register.php:28 +#: actions/register.php:28 +#: actions/finishopenidlogin.php:173 +msgid "Registration not allowed." +msgstr "Non se permite o rexistro neste intre." + +#: ../actions/register.php:200 +#: actions/register.php:214 +#: actions/register.php:241 +msgid "Registration successful" +msgstr "Xa estas rexistrado!!" + +#: ../actions/userauthorization.php:120 +#: actions/userauthorization.php:127 +msgid "Reject" +msgstr "Rexeitar" + +#: ../actions/login.php:103 +#: ../actions/register.php:176 +#: actions/login.php:103 +#: actions/register.php:190 +#: actions/login.php:110 +#: actions/openidlogin.php:85 +#: actions/register.php:217 +msgid "Remember me" +msgstr "Lembrarme" + +#: ../actions/updateprofile.php:70 +#: actions/updateprofile.php:71 +msgid "Remote profile with no matching profile" +msgstr "Non hai ningún perfil que coincida co perfil remoto" + +#: ../actions/remotesubscribe.php:65 +#: actions/remotesubscribe.php:73 +msgid "Remote subscribe" +msgstr "Suscrición remota" + +#: ../actions/emailsettings.php:47 +#: ../actions/emailsettings.php:75 +#: ../actions/imsettings.php:48 +#: ../actions/openidsettings.php:106 +#: ../actions/smssettings.php:50 +#: ../actions/smssettings.php:84 +#: actions/emailsettings.php:48 +#: actions/emailsettings.php:76 +#: actions/imsettings.php:49 +#: actions/openidsettings.php:108 +#: actions/smssettings.php:50 +#: actions/smssettings.php:84 +#: actions/twittersettings.php:59 +#: actions/smspostsettings.php:45 +#: actions/twittersettings.php:61 +#: actions/smspostsettings.php:46 +msgid "Remove" +msgstr "Eliminar" + +#: ../actions/openidsettings.php:68 +#: actions/openidsettings.php:69 +msgid "Remove OpenID" +msgstr "Eliminar OpenID" + +#: ../actions/openidsettings.php:73 +#: actions/openidsettings.php:74 +msgid "Removing your only OpenID would make it impossible to log in! If you need to remove it, add another OpenID first." +msgstr "Eliminando o teu enderezo OpenID vaiche ser imposible acceder! Se queres eliminalo, primeiro engade outro enderezo OpenID." + +#: ../lib/stream.php:55 +#: lib/personal.php:55 +msgid "Replies" +msgstr "Respostas" + +#: ../actions/replies.php:47 +#: ../actions/repliesrss.php:76 +#: ../lib/stream.php:56 +#: actions/replies.php:47 +#: actions/repliesrss.php:62 +#: lib/personal.php:56 +#, php-format +msgid "Replies to %s" +msgstr "Replies to %s" + +#: ../actions/recoverpassword.php:183 +#: actions/recoverpassword.php:189 +msgid "Reset" +msgstr "Restaurar" + +#: ../actions/recoverpassword.php:173 +#: actions/recoverpassword.php:178 +msgid "Reset password" +msgstr "Restaurar contrasinal" + +#: ../lib/settingsaction.php:99 +#: lib/settingsaction.php:93 +#: actions/deleteprofile.php:250 +#: actions/subscriptions.php:73 +msgid "SMS" +msgstr "SMS" + +#: ../actions/smssettings.php:67 +#: actions/smssettings.php:67 +#: actions/smspostsettings.php:38 +#: actions/smspostsettings.php:39 +msgid "SMS Phone number" +msgstr "Número de Teléfono do SMS" + +#: ../actions/smssettings.php:33 +#: actions/smssettings.php:33 +msgid "SMS Settings" +msgstr "Configuracións de SMS" + +#: ../lib/mail.php:219 +#: lib/mail.php:225 +#: lib/mail.php:220 +msgid "SMS confirmation" +msgstr "Confirmación de SMS" + +#: ../actions/recoverpassword.php:182 +#: actions/recoverpassword.php:188 +msgid "Same as password above" +msgstr "Igual que a contrasinal de enriba" + +#: ../actions/register.php:156 +#: actions/register.php:170 +#: actions/register.php:197 +msgid "Same as password above. Required." +msgstr "A mesma contrasinal que arriba. Requerido." + +#: ../actions/emailsettings.php:97 +#: ../actions/imsettings.php:81 +#: ../actions/profilesettings.php:67 +#: ../actions/smssettings.php:100 +#: actions/emailsettings.php:104 +#: actions/imsettings.php:82 +#: actions/profilesettings.php:101 +#: actions/smssettings.php:100 +#: actions/twittersettings.php:83 +#: actions/emailsettings.php:108 +#: actions/imsettings.php:85 +#: actions/othersettings.php:56 +#: actions/profilesettings.php:118 +#: actions/subscriptions.php:74 +#: actions/tagother.php:100 +#: actions/twittersettings.php:82 +msgid "Save" +msgstr "Gardar" + +#: ../lib/searchaction.php:84 +#: ../lib/util.php:300 +#: lib/searchaction.php:84 +#: lib/util.php:316 +#: lib/util.php:345 +msgid "Search" +msgstr "Buscar" + +#: ../actions/noticesearch.php:80 +#: actions/noticesearch.php:85 +#: actions/noticesearch.php:84 +msgid "Search Stream Feed" +msgstr "Procura no Fío" + +#: ../actions/noticesearch.php:30 +#: actions/noticesearch.php:30 +#: actions/noticesearch.php:29 +#, php-format +msgid "Search for notices on %%site.name%% by their contents. Separate search terms by spaces; they must be 3 characters or more." +msgstr "Procurar chíos en %%site.name%% polos seus contidos. Separa os termos de procura por espazos, deben ter 3 caracteres ou máis." + +#: ../actions/peoplesearch.php:28 +#: actions/peoplesearch.php:28 +#, php-format +msgid "Search for people on %%site.name%% by their name, location, or interests. Separate the terms by spaces; they must be 3 characters or more." +msgstr "Procurar xente en %%site.name%% pola seu nome, localización, ou intereses. Separa os termos por espazos; deben ter 3 caracteres ou máis." + +#: ../actions/smssettings.php:296 +#: actions/smssettings.php:304 +#: actions/smssettings.php:306 +msgid "Select a carrier" +msgstr "Selecciona unha operadora" + +#: ../actions/invite.php:137 +#: ../lib/util.php:1172 +#: actions/invite.php:145 +#: lib/util.php:1306 +#: lib/util.php:1731 +#: lib/util.php:1705 +#: lib/util.php:2217 +msgid "Send" +msgstr "Enviar" + +#: ../actions/emailsettings.php:73 +#: ../actions/smssettings.php:82 +#: actions/emailsettings.php:74 +#: actions/smssettings.php:82 +msgid "Send email to this address to post new notices." +msgstr "Enviar un correo a esta dirección para enviar novos chíos." + +#: ../actions/emailsettings.php:88 +#: actions/emailsettings.php:89 +msgid "Send me notices of new subscriptions through email." +msgstr "Envíame chios de novas suscricións por email." + +#: ../actions/imsettings.php:70 +#: actions/imsettings.php:71 +msgid "Send me notices through Jabber/GTalk." +msgstr "Enviarme advertencias a través de Jabber/GTalk." + +#: ../actions/smssettings.php:97 +#: actions/smssettings.php:97 +msgid "Send me notices through SMS; I understand I may incur exorbitant charges from my carrier." +msgstr "Enviarme chíos mediante SMS, entendo que a miña operadora poida cobrarme grandes facturas." + +#: ../actions/imsettings.php:76 +#: actions/imsettings.php:77 +msgid "Send me replies through Jabber/GTalk from people I'm not subscribed to." +msgstr "Envíame respostas a través de Jabber/GTalk da xente á que non estou suscrito." + +#: ../lib/util.php:304 +#: lib/util.php:320 +#: lib/util.php:348 +msgid "Settings" +msgstr "Configuración" + +#: ../actions/profilesettings.php:192 +#: actions/profilesettings.php:307 +#: actions/profilesettings.php:353 +msgid "Settings saved." +msgstr "Configuracións gardadas." + +#: ../actions/tag.php:60 +#: actions/tag.php:60 +#: actions/tag.php:67 +msgid "Showing most popular tags from the last week" +msgstr "Amoa os tags máis populares dende a semana pasada" + +#: ../actions/finishaddopenid.php:66 +#: actions/finishaddopenid.php:66 +msgid "Someone else already has this OpenID." +msgstr "Alguen máis ten ese enderezo OpenID." + +#: ../actions/finishopenidlogin.php:42 +#: ../actions/openidsettings.php:126 +#: actions/finishopenidlogin.php:47 +#: actions/openidsettings.php:135 +msgid "Something weird happened." +msgstr "Algo gordo aconteceu." + +#: ../scripts/maildaemon.php:58 +#: scripts/maildaemon.php:58 +msgid "Sorry, no incoming email allowed." +msgstr "Aivá, non se permiten correos entrantes." + +#: ../scripts/maildaemon.php:54 +#: scripts/maildaemon.php:54 +msgid "Sorry, that is not your incoming email address." +msgstr "Ise é un enderezo IM incorrecto." + +#: ../lib/util.php:330 +#: lib/util.php:346 +#: lib/util.php:375 +msgid "Source" +msgstr "Fonte" + +#: ../actions/showstream.php:296 +#: actions/showstream.php:311 +#: actions/showstream.php:359 +#: actions/misc.php:87 +msgid "Statistics" +msgstr "Estatísticas" + +#: ../actions/finishopenidlogin.php:182 +#: ../actions/finishopenidlogin.php:246 +#: actions/finishopenidlogin.php:188 +#: actions/finishopenidlogin.php:252 +#: actions/finishopenidlogin.php:199 +#: actions/finishopenidlogin.php:267 +msgid "Stored OpenID not found." +msgstr "OpenID almacenado non atopado" + +#: ../actions/remotesubscribe.php:75 +#: ../actions/showstream.php:188 +#: ../actions/showstream.php:197 +#: actions/remotesubscribe.php:84 +#: actions/showstream.php:197 +#: actions/showstream.php:206 +#: actions/showstream.php:254 +#: lib/util.php:2137 +msgid "Subscribe" +msgstr "Subscribir" + +#: ../actions/showstream.php:313 +#: ../actions/subscribers.php:27 +#: actions/showstream.php:328 +#: actions/subscribers.php:27 +#: actions/showstream.php:376 +#: lib/gallery.php:136 +#: lib/gallery.php:137 +msgid "Subscribers" +msgstr "Subscritores" + +#: ../actions/userauthorization.php:310 +#: actions/userauthorization.php:322 +msgid "Subscription authorized" +msgstr "Subscrición autorizada" + +#: ../actions/userauthorization.php:320 +#: actions/userauthorization.php:332 +msgid "Subscription rejected" +msgstr "Subscrición rexeitada" + +#: ../actions/showstream.php:230 +#: ../actions/showstream.php:307 +#: ../actions/subscriptions.php:27 +#: actions/showstream.php:240 +#: actions/showstream.php:322 +#: actions/subscriptions.php:27 +#: actions/showstream.php:288 +#: actions/showstream.php:370 +#: lib/gallery.php:131 +#: lib/gallery.php:132 +msgid "Subscriptions" +msgstr "Subscricións" + +#: ../actions/avatar.php:87 +#: actions/profilesettings.php:324 +#: actions/profilesettings.php:370 +msgid "System error uploading file." +msgstr "Aconteceu un erro no sistema namentras se estaba cargando o ficheiro." + +#: ../actions/tag.php:41 +#: ../lib/util.php:301 +#: actions/tag.php:41 +#: lib/util.php:317 +#: actions/profilesettings.php:90 +#: actions/showstream.php:382 +#: actions/tagother.php:96 +#: actions/tagother.php:162 +#: actions/tag.php:47 +#: lib/profilelist.php:126 +#: lib/profilelist.php:128 +msgid "Tags" +msgstr "Tags" + +#: ../lib/searchaction.php:104 +#: lib/searchaction.php:104 +msgid "Text" +msgstr "Texto" + +#: ../actions/noticesearch.php:34 +#: actions/noticesearch.php:34 +#: actions/noticesearch.php:33 +msgid "Text search" +msgstr "Procura de texto" + +#: ../actions/openidsettings.php:140 +#: actions/openidsettings.php:149 +msgid "That OpenID does not belong to you." +msgstr "Ese OpenID non che pertence." + +#: ../actions/confirmaddress.php:52 +#: actions/confirmaddress.php:52 +msgid "That address has already been confirmed." +msgstr "Esa dirección xa foi confirmada." + +#: ../actions/confirmaddress.php:43 +#: actions/confirmaddress.php:43 +msgid "That confirmation code is not for you!" +msgstr "¡Ese código de confirmación non é para ti!" + +#: ../actions/emailsettings.php:191 +#: actions/emailsettings.php:209 +#: actions/emailsettings.php:215 +msgid "That email address already belongs to another user." +msgstr "Este enderezo de correo xa pertence a outro usuario." + +#: ../actions/avatar.php:80 +#: actions/profilesettings.php:317 +#: actions/profilesettings.php:363 +msgid "That file is too big." +msgstr "Ese arquivo é demasiado grande." + +#: ../actions/imsettings.php:170 +#: actions/imsettings.php:178 +#: actions/imsettings.php:183 +msgid "That is already your Jabber ID." +msgstr "Xa é a túa conta de Jabber." + +#: ../actions/emailsettings.php:188 +#: actions/emailsettings.php:206 +#: actions/emailsettings.php:212 +msgid "That is already your email address." +msgstr "Xa é o teu enderezo de correo." + +#: ../actions/smssettings.php:188 +#: actions/smssettings.php:196 +#: actions/smspostsettings.php:83 +#: actions/smssettings.php:198 +#: actions/smspostsettings.php:88 +msgid "That is already your phone number." +msgstr "Xa é o teu número de teléfono." + +#: ../actions/imsettings.php:233 +#: actions/imsettings.php:241 +#: actions/imsettings.php:246 +msgid "That is not your Jabber ID." +msgstr "Esa non é a túa conta Jabber." + +#: ../actions/emailsettings.php:249 +#: actions/emailsettings.php:267 +#: actions/emailsettings.php:271 +msgid "That is not your email address." +msgstr "Esa non é a túa dirección de correo." + +#: ../actions/smssettings.php:257 +#: actions/smssettings.php:265 +#: actions/smspostsettings.php:113 +#: actions/smssettings.php:267 +#: actions/smspostsettings.php:118 +msgid "That is not your phone number." +msgstr "Ese non é o teu número de teléfono." + +#: ../actions/emailsettings.php:226 +#: ../actions/imsettings.php:210 +#: actions/emailsettings.php:244 +#: actions/imsettings.php:218 +#: actions/emailsettings.php:248 +#: actions/imsettings.php:223 +msgid "That is the wrong IM address." +msgstr "Esa é unha enderezo IM incorrecto." + +#: ../actions/smssettings.php:233 +#: actions/smssettings.php:241 +#: actions/smssettings.php:243 +msgid "That is the wrong confirmation number." +msgstr "Ese é un número de confirmación incorrecto." + +#: ../actions/smssettings.php:191 +#: actions/smssettings.php:199 +#: actions/smspostsettings.php:86 +#: actions/smssettings.php:201 +#: actions/smspostsettings.php:91 +msgid "That phone number already belongs to another user." +msgstr "O número de teléfono xa pertence a outro usuario." + +#: ../actions/newnotice.php:49 +#: ../actions/twitapistatuses.php:408 +#: actions/newnotice.php:49 +#: actions/twitapistatuses.php:330 +#: actions/newnotice.php:61 +#: actions/newsmsnotice.php:73 +#: actions/twitapistatuses.php:271 +#: actions/newsmsnotice.php:79 +msgid "That's too long. Max notice size is 140 chars." +msgstr "Iso é demasiado longo. O tamaño máximo para un chío é de 140 caracteres." + +#: ../actions/twitapiaccount.php:74 +#: actions/twitapiaccount.php:72 +#: actions/twitapiaccount.php:58 +msgid "That's too long. Max notice size is 255 chars." +msgstr "Iso é demasiado longo. O tamaño máximo para un chío é de 255 caracteres." + +#: ../actions/confirmaddress.php:92 +#: actions/confirmaddress.php:92 +#, php-format +msgid "The address \"%s\" has been confirmed for your account." +msgstr "A dirección \"%s\" xa foi confirmada para a túa conta." + +#: ../actions/emailsettings.php:264 +#: ../actions/imsettings.php:250 +#: ../actions/smssettings.php:274 +#: actions/emailsettings.php:282 +#: actions/imsettings.php:258 +#: actions/smssettings.php:282 +#: actions/emailsettings.php:286 +#: actions/imsettings.php:263 +#: actions/smspostsettings.php:128 +#: actions/smssettings.php:284 +#: actions/smspostsettings.php:133 +msgid "The address was removed." +msgstr "Enderezo eliminado." + +#: ../actions/userauthorization.php:312 +#: actions/userauthorization.php:324 +msgid "The subscription has been authorized, but no callback URL was passed. Check with the site's instructions for details on how to authorize the subscription. Your subscription token is:" +msgstr "A subscrición foi autorizada, pero ningunha URL de retorno foi proporcionada. Comproba coas instruccións do sitio para máis detalles en como autorizar subscricións. O teu token de subscrición é:" + +#: ../actions/userauthorization.php:322 +#: actions/userauthorization.php:334 +msgid "The subscription has been rejected, but no callback URL was passed. Check with the site's instructions for details on how to fully reject the subscription." +msgstr "The subscription has been rejected, but no callback URL was passed. Check with the site's instructions for details on how to fully reject the subscription." + +#: ../actions/subscribers.php:35 +#: actions/subscribers.php:35 +#, php-format +msgid "These are the people who listen to %s's notices." +msgstr "Esa é a xente que escoita os chíos de %s." + +#: ../actions/subscribers.php:33 +#: actions/subscribers.php:33 +msgid "These are the people who listen to your notices." +msgstr "Esa é a xente que escoita os teus chíos." + +#: ../actions/subscriptions.php:35 +#: actions/subscriptions.php:35 +#, php-format +msgid "These are the people whose notices %s listens to." +msgstr "Esta é a xente á que lle estas a escoitar os chíos %s." + +#: ../actions/subscriptions.php:33 +#: actions/subscriptions.php:33 +msgid "These are the people whose notices you listen to." +msgstr "Esa é a xente á que lle estas a escoitar os seus chíos" + +#: ../actions/invite.php:89 +#: actions/invite.php:96 +msgid "These people are already users and you were automatically subscribed to them:" +msgstr "Esta xente xa é usuario e ti foches suscrito automaticamente a eles:" + +#: ../actions/recoverpassword.php:88 +#: actions/recoverpassword.php:91 +msgid "This confirmation code is too old. Please start again." +msgstr "Ese código de confirmación é demasiado antigo. Comeza de novo." + +#: ../lib/openid.php:195 +#: lib/openid.php:195 +msgid "This form should automatically submit itself. If not, click the submit button to go to your OpenID provider." +msgstr "Este formulario debería enviarse automáticamente. Se non é así, fai clic no botón de enviar para ir ó teu proveedro OpenID." + +#: ../actions/finishopenidlogin.php:56 +#: actions/finishopenidlogin.php:61 +#, php-format +msgid "This is the first time you've logged into %s so we must connect your OpenID to a local account. You can either create a new account, or connect with your existing account, if you have one." +msgstr "Esta é a primeria vez que accedes a %s polo que debes conectar o teu enderezo OpenID á conta local. Podes ademáis crear unha nova conta, ou conectarte cunha existente, se xa tes unha." + +#: ../actions/twitapifriendships.php:108 +#: ../actions/twitapistatuses.php:586 +#: actions/twitapifavorites.php:127 +#: actions/twitapifriendships.php:108 +#: actions/twitapistatuses.php:511 +#: actions/twitapifavorites.php:94 +#: actions/twitapifriendships.php:82 +#: actions/twitapistatuses.php:428 +msgid "This method requires a POST or DELETE." +msgstr "Este método require un POST ou DELETE." + +#: ../actions/twitapiaccount.php:65 +#: ../actions/twitapifriendships.php:44 +#: ../actions/twitapistatuses.php:381 +#: actions/twitapiaccount.php:63 +#: actions/twitapidirect_messages.php:114 +#: actions/twitapifriendships.php:44 +#: actions/twitapistatuses.php:303 +#: actions/twitapiaccount.php:49 +#: actions/twitapidirect_messages.php:117 +#: actions/twitapifriendships.php:30 +#: actions/twitapistatuses.php:239 +msgid "This method requires a POST." +msgstr "Este método require un POST." + +#: ../lib/util.php:164 +#: lib/util.php:246 +#: lib/util.php:263 +msgid "This page is not available in a media type you accept" +msgstr "Esta páxina non está dispoñíbel no tipo de medio que aceptas" + +#: ../actions/profilesettings.php:63 +#: actions/profilesettings.php:96 +#: actions/profilesettings.php:109 +msgid "Timezone" +msgstr "Fuso Horario" + +#: ../actions/profilesettings.php:107 +#: actions/profilesettings.php:222 +#: actions/profilesettings.php:241 +msgid "Timezone not selected." +msgstr "Fuso Horario non seleccionado" + +#: ../actions/remotesubscribe.php:43 +#: actions/remotesubscribe.php:51 +#, php-format +msgid "To subscribe, you can [login](%%action.login%%), or [register](%%action.register%%) a new account. If you already have an account on a [compatible microblogging site](%%doc.openmublog%%), enter your profile URL below." +msgstr "Para subscribirse, podes [acceder](%%action.login%%), ou [rexistrar](%%action.register%%) unha nova conta. Se xa tes unha conta nun [sitio de microblogaxe compatíbel](%%doc.openmublog%%), insire a dirección do perfil abaixo." + +#: ../actions/twitapifriendships.php:163 +#: actions/twitapifriendships.php:167 +#: actions/twitapifriendships.php:128 +msgid "Two user ids or screen_names must be supplied." +msgstr "Dous identificadores de usuario ou nomes_en_pantalla deben ser proporcionados." + +#: ../actions/profilesettings.php:48 +#: ../actions/register.php:169 +#: actions/profilesettings.php:81 +#: actions/register.php:183 +#: actions/profilesettings.php:83 +#: actions/register.php:210 +msgid "URL of your homepage, blog, or profile on another site" +msgstr "Enderezo da túa páxina persoal, blogue, ou perfil noutro sitio" + +#: ../actions/remotesubscribe.php:74 +#: actions/remotesubscribe.php:83 +msgid "URL of your profile on another compatible microblogging service" +msgstr "Enderezo do teu perfil en outro servizo de microblogaxe compatíbel" + +#: ../actions/emailsettings.php:130 +#: ../actions/imsettings.php:110 +#: ../actions/recoverpassword.php:39 +#: ../actions/smssettings.php:135 +#: actions/emailsettings.php:144 +#: actions/imsettings.php:118 +#: actions/recoverpassword.php:39 +#: actions/smssettings.php:143 +#: actions/twittersettings.php:108 +#: actions/emailsettings.php:148 +#: actions/imsettings.php:121 +#: actions/othersettings.php:146 +#: actions/smspostsettings.php:64 +#: actions/smssettings.php:145 +#: actions/twittersettings.php:199 +#: actions/smspostsettings.php:69 +msgid "Unexpected form submission." +msgstr "Envio de formulario non esperada." + +#: ../actions/recoverpassword.php:276 +#: actions/recoverpassword.php:289 +msgid "Unexpected password reset." +msgstr "Restauración de contrasinal non esperada." + +#: ../index.php:57 +#: index.php:57 +msgid "Unknown action" +msgstr "Acción descoñecida" + +#: ../actions/finishremotesubscribe.php:58 +#: actions/finishremotesubscribe.php:60 +#: actions/finishremotesubscribe.php:59 +msgid "Unknown version of OMB protocol." +msgstr "Versión de protocolo OMB descoñecida." + +#: ../lib/util.php:269 +#: lib/util.php:285 +#: lib/util.php:302 +msgid "Unless otherwise specified, contents of this site are copyright by the contributors and available under the " +msgstr "Aínda que especifiques outro, os contidos de este sitio teñen copyright polos contribuidores e está dispoñible baixo " + +#: ../actions/confirmaddress.php:48 +#: actions/confirmaddress.php:48 +#, php-format +msgid "Unrecognized address type %s" +msgstr "Tipo de enderezo %s non recoñecido" + +#: ../actions/showstream.php:209 +#: actions/showstream.php:219 +#: actions/showstream.php:267 +#: lib/util.php:2153 +msgid "Unsubscribe" +msgstr "Eliminar subscrición" + +#: ../actions/postnotice.php:44 +#: ../actions/updateprofile.php:45 +#: actions/postnotice.php:45 +#: actions/updateprofile.php:46 +msgid "Unsupported OMB version" +msgstr "Versión OMB non soportada" + +#: ../actions/avatar.php:105 +#: actions/profilesettings.php:342 +#: actions/profilesettings.php:388 +msgid "Unsupported image file format." +msgstr "Formato de ficheiro de imaxe non soportado." + +#: ../lib/settingsaction.php:100 +#: lib/settingsaction.php:94 +#: actions/deleteprofile.php:251 +msgid "Updates by SMS" +msgstr "Chíos dende SMS" + +#: ../lib/settingsaction.php:103 +#: lib/settingsaction.php:97 +#: actions/deleteprofile.php:254 +#: lib/settingsaction.php:101 +#: lib/settingsaction.php:103 +msgid "Updates by instant messenger (IM)" +msgstr "Chíos dende mensaxería instantánea (IM)" + +#: ../actions/twitapistatuses.php:241 +#: actions/twitapistatuses.php:158 +#: actions/twitapistatuses.php:126 +#, php-format +msgid "Updates from %1$s and friends on %2$s!" +msgstr "Actualizacións dende %1$s e amigos en %2$s!" + +#: ../actions/twitapistatuses.php:341 +#: actions/twitapistatuses.php:268 +#: actions/twitapistatuses.php:198 +#, php-format +msgid "Updates from %1$s on %2$s!" +msgstr "Actualizacións dende %1$s en %2$s!" + +#: ../actions/avatar.php:68 +#: actions/profilesettings.php:161 +#: actions/profilesettings.php:178 +msgid "Upload" +msgstr "Subir" + +#: ../actions/avatar.php:27 +msgid "Upload a new \"avatar\" (user image) here. You can't edit the picture after you upload it, so make sure it's more or less square. It must be under the site license, also. Use a picture that belongs to you and that you want to share." +msgstr "Sube un novo \"avatar\" (imaxe de usuario) dende aquí. Non podes editar a imaxe despois de subila, polo que asegurate de que é máis ou menos cadrado. Debe estar baixo a licenza do sistio. Emprega unha imaxe que che pertenza e que queiras compartir." + +#: ../lib/settingsaction.php:91 +msgid "Upload a new profile image" +msgstr "Subir unha nova imaxe de usuario" + +#: ../actions/invite.php:114 +#: actions/invite.php:121 +msgid "Use this form to invite your friends and colleagues to use this service." +msgstr "Emprega este formulario para invitar ós teus amigos e colegas a empregar este servizo." + +#: ../actions/register.php:159 +#: ../actions/register.php:162 +#: actions/register.php:173 +#: actions/register.php:176 +#: actions/register.php:200 +#: actions/register.php:203 +msgid "Used only for updates, announcements, and password recovery" +msgstr "Empregado só para actualizacións, novidades, e recuperación de contrasinais" + +#: ../actions/finishremotesubscribe.php:86 +#: actions/finishremotesubscribe.php:88 +#: actions/finishremotesubscribe.php:92 +msgid "User being listened to doesn't exist." +msgstr "O usuario que está sendo escoitado non existe." + +#: ../actions/all.php:41 +#: ../actions/avatarbynickname.php:48 +#: ../actions/foaf.php:47 +#: ../actions/replies.php:41 +#: ../actions/showstream.php:44 +#: ../actions/twitapiaccount.php:82 +#: ../actions/twitapistatuses.php:319 +#: ../actions/twitapistatuses.php:685 +#: ../actions/twitapiusers.php:82 +#: actions/all.php:41 +#: actions/avatarbynickname.php:48 +#: actions/foaf.php:47 +#: actions/replies.php:41 +#: actions/showfavorites.php:41 +#: actions/showstream.php:44 +#: actions/twitapiaccount.php:80 +#: actions/twitapifavorites.php:68 +#: actions/twitapistatuses.php:235 +#: actions/twitapistatuses.php:609 +#: actions/twitapiusers.php:87 +#: lib/mailbox.php:50 +#: actions/showstream.php:57 +#: actions/twitapiaccount.php:66 +#: actions/twitapifavorites.php:40 +#: actions/twitapistatuses.php:163 +#: actions/twitapistatuses.php:492 +#: actions/twitapiusers.php:53 +msgid "User has no profile." +msgstr "O usuario non ten perfil." + +#: ../actions/remotesubscribe.php:71 +#: actions/remotesubscribe.php:80 +msgid "User nickname" +msgstr "Alcume de usuario" + +#: ../actions/twitapiusers.php:75 +#: actions/twitapiusers.php:80 +msgid "User not found." +msgstr "Usuario non atopado." + +#: ../actions/profilesettings.php:63 +#: actions/profilesettings.php:96 +#: actions/profilesettings.php:109 +msgid "What timezone are you normally in?" +msgstr "En que fuso horario estas normalmente?" + +#: ../lib/util.php:1159 +#: lib/util.php:1293 +#: lib/util.php:1689 +#, php-format +msgid "What's up, %s?" +msgstr "¿Que pasa, %s?" + +#: ../actions/profilesettings.php:54 +#: ../actions/register.php:175 +#: actions/profilesettings.php:87 +#: actions/register.php:189 +#: actions/profilesettings.php:89 +#: actions/register.php:216 +msgid "Where you are, like \"City, State (or Region), Country\"" +msgstr "¿Onde estas, coma \"Cidade, Provincia, País\"" + +#: ../actions/updateprofile.php:128 +#: actions/updateprofile.php:129 +#, php-format +msgid "Wrong image type for '%s'" +msgstr "Tipo de imaxe incorrecto para '%s'" + +#: ../actions/updateprofile.php:123 +#: actions/updateprofile.php:124 +#, php-format +msgid "Wrong size image at '%s'" +msgstr "Tamaño de imaxe incorrecto en '%s'" + +#: ../actions/deletenotice.php:63 +#: ../actions/deletenotice.php:72 +#: actions/deletenotice.php:64 +#: actions/deletenotice.php:79 +#: actions/block.php:105 +msgid "Yes" +msgstr "Si" + +#: ../actions/finishaddopenid.php:64 +#: actions/finishaddopenid.php:64 +msgid "You already have this OpenID!" +msgstr "¡Xa tes esa OpenID!" + +#: ../actions/deletenotice.php:37 +#: actions/deletenotice.php:37 +msgid "You are about to permanently delete a notice. Once this is done, it cannot be undone." +msgstr "Vas a eliminar permanentemente este chío. Unha vez feito, xa non hai volta atrás... Quedas avisado!" + +#: ../actions/recoverpassword.php:31 +#: actions/recoverpassword.php:31 +msgid "You are already logged in!" +msgstr "¡Xa estás logueado!" + +#: ../actions/invite.php:81 +#: actions/invite.php:88 +msgid "You are already subscribed to these users:" +msgstr "Xa estas suscrito a estes usuarios:" + +#: ../actions/twitapifriendships.php:128 +#: actions/twitapifriendships.php:128 +#: actions/twitapifriendships.php:102 +msgid "You are not friends with the specified user." +msgstr "No tes amigos con un usuario específico." + +#: ../actions/password.php:27 +msgid "You can change your password here. Choose a good one!" +msgstr "Podes cambiar a túa contrasinal aquí. ¡Escolle unha boa!" + +#: ../actions/register.php:135 +#: actions/register.php:145 +msgid "You can create a new account to start posting notices." +msgstr "Podes crear unha nova conta para comezar a escribir chíos." + +#: ../actions/smssettings.php:28 +#: actions/smssettings.php:28 +#, php-format +msgid "You can receive SMS messages through email from %%site.name%%." +msgstr "Podes recibir mensaxes SMS a través do email dende %%site.name%%." + +#: ../actions/openidsettings.php:86 +#: actions/openidsettings.php:87 +msgid "You can remove an OpenID from your account by clicking the button marked \"Remove\"." +msgstr "Podes eliminar unha OpenID da túa conta facendo clic no botón marcado \"Eliminar\"." + +#: ../actions/imsettings.php:28 +#: actions/imsettings.php:28 +#, php-format +msgid "You can send and receive notices through Jabber/GTalk [instant messages](%%doc.im%%). Configure your address and settings below." +msgstr "Podes enviar e recibir chíos a través de Jabber/GTalk [mensaxes instantáneos](%%doc.im%%). Configura a túa conta e configuracións abaixo." + +#: ../actions/profilesettings.php:27 +#: actions/profilesettings.php:27 +msgid "You can update your personal profile info here so people know more about you." +msgstr "Podes actualizar a túa información do perfil persoal aquí para que a xente che poida coñecer mellor." + +#: ../actions/finishremotesubscribe.php:31 +#: ../actions/remotesubscribe.php:31 +#: actions/finishremotesubscribe.php:31 +#: actions/remotesubscribe.php:31 +#: actions/finishremotesubscribe.php:83 +#: actions/finishremotesubscribe.php:99 +msgid "You can use the local subscription!" +msgstr "¡Podes empregar a túa subscrición local!" + +#: ../actions/finishopenidlogin.php:33 +#: ../actions/register.php:61 +#: actions/finishopenidlogin.php:38 +#: actions/register.php:68 +#: actions/register.php:77 +msgid "You can't register if you don't agree to the license." +msgstr "Non podes rexistrarte se non estas de acordo coa licenza." + +#: ../actions/updateprofile.php:63 +#: actions/updateprofile.php:64 +msgid "You did not send us that profile" +msgstr "Non nos enviaches ese perfil" + +#: ../lib/mail.php:147 +#: lib/mail.php:141 +#, php-format +msgid "" +"You have a new posting address on %1$s.\n" +"\n" +"Send email to %2$s to post new messages.\n" +"\n" +"More email instructions at %3$s.\n" +"\n" +"Faithfully yours,\n" +"%4$s" +msgstr "" +"Tes unha nova dirección de envio de mensaxes en %1$s.\n" +"\n" +"Envia unha mensaxe a %2$s para enviar novas mensaxes.\n" +"\n" +"Hai máis instruccións de envio en %3$s.\n" +"\n" +"Sempre teu...,\n" +"%4$s" + +#: ../actions/twitapistatuses.php:612 +#: actions/twitapistatuses.php:537 +#: actions/twitapistatuses.php:455 +msgid "You may not delete another user's status." +msgstr "Non deberías eliminar o estado de outro usuario" + +#: ../actions/invite.php:31 +#: actions/invite.php:31 +#, php-format +msgid "You must be logged in to invite other users to use %s" +msgstr "Debes estar logueado para invitar a outros usuarios a empregar %s" + +#: ../actions/invite.php:103 +#: actions/invite.php:110 +msgid "You will be notified when your invitees accept the invitation and register on the site. Thanks for growing the community!" +msgstr "Notificaráseche cando os teus invitados acepten unha invitación e se rexistren neste sitio. Grazas por facer crecer o gremio lareteiro!" + +#: ../actions/recoverpassword.php:149 +#: actions/recoverpassword.php:154 +msgid "You've been identified. Enter a new password below. " +msgstr "Foiches identificado. Insire unha nova contrasinal abaixo." + +#: ../actions/openidlogin.php:67 +#: actions/openidlogin.php:76 +#: actions/login.php:127 +#: actions/openidlogin.php:84 +msgid "Your OpenID URL" +msgstr "O teu enderezo OpenID" + +#: ../actions/recoverpassword.php:164 +#: actions/recoverpassword.php:169 +msgid "Your nickname on this server, or your registered email address." +msgstr "O teu alcume neste servidor, ou o teu enderezo rexistrado." + +#: ../actions/openidsettings.php:28 +#: actions/openidsettings.php:28 +#, php-format +msgid "[OpenID](%%doc.openid%%) lets you log into many sites with the same user account. Manage your associated OpenIDs from here." +msgstr "[OpenID](%%doc.openid%%) permiteche acceder en moitos sitios coa mesma conta. Xestina os teus OpenIDs asociados dende aquí." + +#: ../lib/util.php:943 +#: lib/util.php:992 +#: lib/util.php:1349 +msgid "a few seconds ago" +msgstr "fai uns segundos" + +#: ../lib/util.php:955 +#: lib/util.php:1004 +#: lib/util.php:1361 +#, php-format +msgid "about %d days ago" +msgstr "fai %d días" + +#: ../lib/util.php:951 +#: lib/util.php:1000 +#: lib/util.php:1357 +#, php-format +msgid "about %d hours ago" +msgstr "fai %d horas" + +#: ../lib/util.php:947 +#: lib/util.php:996 +#: lib/util.php:1353 +#, php-format +msgid "about %d minutes ago" +msgstr "fai %d minutos" + +#: ../lib/util.php:959 +#: lib/util.php:1008 +#: lib/util.php:1365 +#, php-format +msgid "about %d months ago" +msgstr "fai %d meses" + +#: ../lib/util.php:953 +#: lib/util.php:1002 +#: lib/util.php:1359 +msgid "about a day ago" +msgstr "fai un día" + +#: ../lib/util.php:945 +#: lib/util.php:994 +#: lib/util.php:1351 +msgid "about a minute ago" +msgstr "fai un minuto" + +#: ../lib/util.php:957 +#: lib/util.php:1006 +#: lib/util.php:1363 +msgid "about a month ago" +msgstr "fai un mes" + +#: ../lib/util.php:961 +#: lib/util.php:1010 +#: lib/util.php:1367 +msgid "about a year ago" +msgstr "fai un ano" + +#: ../lib/util.php:949 +#: lib/util.php:998 +#: lib/util.php:1355 +msgid "about an hour ago" +msgstr "fai unha hora" + +#: ../actions/showstream.php:423 +#: ../lib/stream.php:132 +#: actions/showstream.php:441 +#: lib/stream.php:99 +#: lib/noticelist.php:211 +msgid "delete" +msgstr "eliminar" + +#: ../actions/noticesearch.php:130 +#: ../actions/showstream.php:408 +#: ../lib/stream.php:117 +#: actions/noticesearch.php:136 +#: actions/showstream.php:426 +#: lib/stream.php:84 +#: actions/noticesearch.php:135 +#: lib/facebookaction.php:202 +#: lib/noticelist.php:189 +msgid "in reply to..." +msgstr "en contestación a..." + +#: ../actions/noticesearch.php:137 +#: ../actions/showstream.php:415 +#: ../lib/stream.php:124 +#: actions/noticesearch.php:143 +#: actions/showstream.php:433 +#: lib/stream.php:91 +#: actions/noticesearch.php:142 +#: lib/noticelist.php:199 +msgid "reply" +msgstr "contestar" + +#: ../actions/password.php:44 +#: actions/profilesettings.php:183 +#: actions/profilesettings.php:200 +msgid "same as password above" +msgstr "igual á contrasinal de enriba" + +#: ../actions/twitapistatuses.php:755 +#: actions/twitapistatuses.php:678 +#: actions/twitapistatuses.php:543 +msgid "unsupported file type" +msgstr "tipo de ficheiro non soportado" + +#: ../lib/util.php:1309 +#: lib/util.php:1443 +#: lib/facebookaction.php:251 +#: lib/util.php:1842 +msgid "« After" +msgstr "« Despois" + +#: actions/deletenotice.php:74 +#: actions/disfavor.php:43 +#: actions/emailsettings.php:127 +#: actions/favor.php:45 +#: actions/finishopenidlogin.php:33 +#: actions/imsettings.php:105 +#: actions/invite.php:46 +#: actions/newmessage.php:45 +#: actions/openidlogin.php:36 +#: actions/openidsettings.php:123 +#: actions/profilesettings.php:47 +#: actions/recoverpassword.php:282 +#: actions/register.php:42 +#: actions/remotesubscribe.php:40 +#: actions/smssettings.php:124 +#: actions/subscribe.php:44 +#: actions/twittersettings.php:97 +#: actions/unsubscribe.php:41 +#: actions/userauthorization.php:35 +#: actions/block.php:38 +#: actions/deleteprofile.php:127 +#: actions/disfavor.php:47 +#: actions/emailsettings.php:131 +#: actions/favor.php:49 +#: actions/imsettings.php:108 +#: actions/login.php:45 +#: actions/newmessage.php:44 +#: actions/newnotice.php:36 +#: actions/nudge.php:47 +#: actions/othersettings.php:139 +#: actions/profilesettings.php:49 +#: actions/smssettings.php:126 +#: actions/subedit.php:38 +#: actions/tagother.php:113 +#: actions/twittersettings.php:188 +#: actions/unblock.php:38 +msgid "There was a problem with your session token. Try again, please." +msgstr "Houbo un problema co teu token de sesión. Tentao de novo, anda..." + +#: actions/disfavor.php:55 +msgid "This notice is not a favorite!" +msgstr "Este chío non é un favorito!" + +#: actions/disfavor.php:63 +msgid "Could not delete favorite." +msgstr "Non se puido eliminar o favorito." + +#: actions/disfavor.php:72 +msgid "Favor" +msgstr "Gostame" + +#: actions/emailsettings.php:92 +msgid "Send me email when someone adds my notice as a favorite." +msgstr "Enviar un correo cando alguen enganda un chío meu coma favorito." + +#: actions/emailsettings.php:95 +msgid "Send me email when someone sends me a private message." +msgstr "Enviarme un email cando alguén me envíe unha mensaxe privada." + +#: actions/favor.php:53 +#: actions/twitapifavorites.php:142 +#: actions/favor.php:54 +#: actions/twitapifavorites.php:115 +msgid "This notice is already a favorite!" +msgstr "Este chío xa é un favorito!" + +#: actions/favor.php:60 +#: actions/twitapifavorites.php:151 +#: classes/Command.php:132 +#: actions/favor.php:61 +#: actions/twitapifavorites.php:122 +msgid "Could not create favorite." +msgstr "Non se puido crear o favorito." + +#: actions/favor.php:70 +msgid "Disfavor" +msgstr "Non me gosta" + +#: actions/favoritesrss.php:60 +#: actions/showfavorites.php:47 +#: actions/favoritesrss.php:62 +#, php-format +msgid "%s favorite notices" +msgstr "%s chíos favoritos" + +#: actions/favoritesrss.php:64 +#: actions/favoritesrss.php:66 +#, php-format +msgid "Feed of favorite notices of %s" +msgstr "Fonte para os chíos favoritos de %s" + +#: actions/inbox.php:28 +#, php-format +msgid "Inbox for %s - page %d" +msgstr "Band. Entrada para %s - páxina %d" + +#: actions/inbox.php:30 +#, php-format +msgid "Inbox for %s" +msgstr "Band. Entrada para %s" + +#: actions/inbox.php:53 +msgid "This is your inbox, which lists your incoming private messages." +msgstr "Esta é a túa bandexa de entrada, aquí móstranse as túas mensaxes privadas." + +#: actions/invite.php:178 +#, php-format +msgid "" +"%1$s has invited you to join them on %2$s (%3$s).\n" +"\n" +msgstr "Acabas de invitar a %1$s a unirse a %2$s (%3$s).\n" + +#: actions/login.php:104 +msgid "Automatically login in the future; " +msgstr "Loguearse automáticamente no futuro:" + +#: actions/login.php:122 +msgid "For security reasons, please re-enter your " +msgstr "Por razóns de seguranza, por favor re-insire o teu " + +#: actions/login.php:126 +msgid "Login with your username and password. " +msgstr "Accede co teu nome de usuario e contrasinal." + +#: actions/newmessage.php:58 +#: actions/twitapidirect_messages.php:130 +#: actions/newmessage.php:60 +#: actions/twitapidirect_messages.php:136 +msgid "That's too long. Max message size is 140 chars." +msgstr "Iso é demasiado longo. O tamaño máximo para unha mensaxe é de 140 caracteres." + +#: actions/newmessage.php:65 +#: actions/newmessage.php:68 +msgid "No recipient specified." +msgstr "Non se especificou ningún destinatario" + +#: actions/newmessage.php:68 +#: actions/newmessage.php:113 +#: classes/Command.php:206 +#: actions/newmessage.php:71 +#: actions/newmessage.php:116 +#: classes/Command.php:211 +msgid "You can't send a message to this user." +msgstr "Non podes enviar mensaxes a este usurio." + +#: actions/newmessage.php:71 +#: actions/twitapidirect_messages.php:146 +#: classes/Command.php:209 +#: actions/newmessage.php:74 +#: actions/twitapidirect_messages.php:153 +#: classes/Command.php:214 +msgid "Don't send a message to yourself; just say it to yourself quietly instead." +msgstr "Non te envies mensaxes a ti mesmo!! só fala contigo mesmo baixiño, senón vante tomar por tolo." + +#: actions/newmessage.php:108 +#: actions/microsummary.php:32 +#: actions/newmessage.php:111 +msgid "No such user" +msgstr "Non é o usuario" + +#: actions/newmessage.php:117 +#: actions/newmessage.php:120 +msgid "New message" +msgstr "Nova mensaxe" + +#: actions/noticesearch.php:95 +#: actions/noticesearch.php:94 +msgid "Notice without matching profile" +msgstr "Chío sen perfil coincidente" + +#: actions/openidsettings.php:28 +#, php-format +msgid "[OpenID](%%doc.openid%%) lets you log into many sites " +msgstr "[OpenID](%%doc.openid%%) permiteche acceder en moitos sitios" + +#: actions/openidsettings.php:46 +msgid "If you want to add an OpenID to your account, " +msgstr "Se queres engadir un enderezo OpenID á tua conta, " + +#: actions/openidsettings.php:74 +msgid "Removing your only OpenID would make it impossible to log in! " +msgstr "Eliminando o teu enderezo OpenID serache imposíbel acceder!" + +#: actions/openidsettings.php:87 +msgid "You can remove an OpenID from your account " +msgstr "Podes eliminar un identificador OpenID da túa conta " + +#: actions/outbox.php:28 +#, php-format +msgid "Outbox for %s - page %d" +msgstr "Band. Saída para %s - páxina %d" + +#: actions/outbox.php:30 +#, php-format +msgid "Outbox for %s" +msgstr "Band. Saída para %s" + +#: actions/outbox.php:53 +msgid "This is your outbox, which lists private messages you have sent." +msgstr "Esta é a túa band. saída, que mostra as mensaxes privadas que enviaches." + +#: actions/peoplesearch.php:28 +#, php-format +msgid "Search for people on %%site.name%% by their name, location, or interests. " +msgstr "Procurar xente en %%site.name%% polo seu nome, localización, ou intereses. " + +#: actions/profilesettings.php:27 +msgid "You can update your personal profile info here " +msgstr "Podes actualizar a túa información do perfil persoal aquí" + +#: actions/profilesettings.php:115 +#: actions/remotesubscribe.php:320 +#: actions/userauthorization.php:159 +#: actions/userrss.php:76 +#: actions/profilesettings.php:132 +#: actions/remotesubscribe.php:333 +msgid "User without matching profile" +msgstr "Usuario sen un perfil que coincida." + +#: actions/recoverpassword.php:91 +msgid "This confirmation code is too old. " +msgstr "Ese código de confirmación é demasiado antigo." + +#: actions/recoverpassword.php:141 +msgid "If you've forgotten or lost your" +msgstr "Se esquenciches ou perdeches a túa" + +#: actions/recoverpassword.php:154 +msgid "You've been identified. Enter a " +msgstr "Foches identificado. Insire unha " + +#: actions/recoverpassword.php:169 +msgid "Your nickname on this server, " +msgstr "O teu alcume neste servidor, " + +#: actions/recoverpassword.php:271 +msgid "Instructions for recovering your password " +msgstr "Instruccións para recuperar a túa contrasinal." + +#: actions/recoverpassword.php:327 +msgid "New password successfully saved. " +msgstr "A nova contrasinal foi gardada correctamente." + +#: actions/register.php:95 +#: actions/register.php:104 +msgid "Password must be 6 or more characters." +msgstr "A contrasinal debe ter 6 caracteres ou máis." + +#: actions/register.php:216 +#, php-format +msgid "Congratulations, %s! And welcome to %%%%site.name%%%%. From here, you may want to..." +msgstr "Noraboa, %s! E benvido a %%%%site.name%%%%. Dende aquí, igual queres..." + +#: actions/register.php:227 +msgid "(You should receive a message by email momentarily, with " +msgstr "(Deberías recibir unha mensaxe no teu email nun intre, con" + +#: actions/remotesubscribe.php:51 +#, php-format +msgid "To subscribe, you can [login](%%action.login%%)," +msgstr "Para suscribirse, podes [loguearte](%%action.login%%)," + +#: actions/showfavorites.php:61 +#, php-format +msgid "Feed for favorites of %s" +msgstr "Fonte para os favoritos de %s" + +#: actions/showfavorites.php:84 +#: actions/twitapifavorites.php:85 +#: actions/showfavorites.php:88 +#: actions/twitapifavorites.php:57 +msgid "Could not retrieve favorite notices." +msgstr "Non se pode " + +#: actions/showmessage.php:33 +msgid "No such message." +msgstr "Non existe a mensaxe." + +#: actions/showmessage.php:42 +msgid "Only the sender and recipient may read this message." +msgstr "Só o emisor e destinatario poden ler esta mensaxe." + +#: actions/showmessage.php:61 +#, php-format +msgid "Message to %1$s on %2$s" +msgstr "Mensaxe de %1$s en %2$s" + +#: actions/showmessage.php:66 +#, php-format +msgid "Message from %1$s on %2$s" +msgstr "Mensaxe dende %1$s en %2$s" + +#: actions/showstream.php:154 +#: lib/util.php:2164 +msgid "Send a message" +msgstr "Enviar unha mensaxe" + +#: actions/smssettings.php:312 +#, php-format +msgid "Mobile carrier for your phone. " +msgstr "Operadora móbil do teu teléfono." + +#: actions/twitapidirect_messages.php:76 +#: actions/twitapidirect_messages.php:64 +#, php-format +msgid "Direct messages to %s" +msgstr "Mensaxes directas para %s" + +#: actions/twitapidirect_messages.php:77 +#: actions/twitapidirect_messages.php:65 +#, php-format +msgid "All the direct messages sent to %s" +msgstr "Tódalas mensaxes directas enviadas a %s" + +#: actions/twitapidirect_messages.php:81 +#: actions/twitapidirect_messages.php:69 +msgid "Direct Messages You've Sent" +msgstr "Mensaxes Directas que Enviaches." + +#: actions/twitapidirect_messages.php:82 +#: actions/twitapidirect_messages.php:70 +#, php-format +msgid "All the direct messages sent from %s" +msgstr "Tódalas mensaxes directas enviadas dende %s" + +#: actions/twitapidirect_messages.php:128 +#: actions/twitapidirect_messages.php:132 +msgid "No message text!" +msgstr "Non hai mensaxes de texto!" + +#: actions/twitapidirect_messages.php:138 +#: actions/twitapidirect_messages.php:145 +msgid "Recipient user not found." +msgstr "Usuario destinatario non atopado." + +#: actions/twitapidirect_messages.php:141 +#: actions/twitapidirect_messages.php:148 +msgid "Can't send direct messages to users who aren't your friend." +msgstr "Non se pode enviar a mensaxe directa a usuarios dos que non eres amigo." + +#: actions/twitapifavorites.php:92 +#: actions/twitapifavorites.php:64 +#, php-format +msgid "%s / Favorites from %s" +msgstr "%s / Favoritos dende %s" + +#: actions/twitapifavorites.php:95 +#: actions/twitapifavorites.php:67 +#, php-format +msgid "%s updates favorited by %s / %s." +msgstr "%s updates favorited by %s / %s." + +#: actions/twitapifavorites.php:187 +#: lib/mail.php:275 +#: actions/twitapifavorites.php:158 +#: lib/mail.php:293 +#, php-format +msgid "%s added your notice as a favorite" +msgstr "%s gustoulle o teu chío" + +#: actions/twitapifavorites.php:188 +#: lib/mail.php:276 +#, php-format +msgid "" +"%1$s just added your notice from %2$s as one of their favorites.\n" +"\n" +msgstr "" +"A %1$s gustoulle o teu chío %2$s e marcouno como favorito.\n" +"\n" + +#: actions/twittersettings.php:27 +msgid "Add your Twitter account to automatically send your notices to Twitter, " +msgstr "Engade a túa conta de Twitter para enviar automáticamente os teus chíos a Twitter." + +#: actions/twittersettings.php:41 +#: actions/twittersettings.php:43 +msgid "Twitter settings" +msgstr "Configuracións de Twitter" + +#: actions/twittersettings.php:48 +#: actions/twittersettings.php:50 +msgid "Twitter Account" +msgstr "Conta de Twitter" + +#: actions/twittersettings.php:56 +#: actions/twittersettings.php:58 +msgid "Current verified Twitter account." +msgstr "Conta de twitter verificada actualmente." + +#: actions/twittersettings.php:63 +msgid "Twitter Username" +msgstr "Nome de usuario en Twitter" + +#: actions/twittersettings.php:65 +msgid "No spaces, please." +msgstr "Sen espazos, anda..." + +#: actions/twittersettings.php:67 +msgid "Twitter Password" +msgstr "Contrasinal de Twitter" + +#: actions/twittersettings.php:72 +msgid "Automatically send my notices to Twitter." +msgstr "Enviar automáticamente os meus chíos a Twitter." + +#: actions/twittersettings.php:75 +msgid "Send local \"@\" replies to Twitter." +msgstr "Enviar respostas \"@\" locais a Twitter." + +#: actions/twittersettings.php:78 +msgid "Subscribe to my Twitter friends here." +msgstr "Suscribirse ós meus amigos de Twitter aquí." + +#: actions/twittersettings.php:122 +#: actions/twittersettings.php:216 +msgid "Username must have only numbers, upper- and lowercase letters, and underscore (_). 15 chars max." +msgstr "O nome de usuario debe ter só letras, minúsculas e maiúsculas, e números, e sen espazos." + +#: actions/twittersettings.php:128 +#: actions/twittersettings.php:221 +msgid "Could not verify your Twitter credentials!" +msgstr "Non se puideron verificar as túas credenciais en Twitter!" + +#: actions/twittersettings.php:137 +#: actions/twittersettings.php:228 +#, php-format +msgid "Unable to retrieve account information for \"%s\" from Twitter." +msgstr "Non se puido recoller información da túa conta \"%s\" en Twitter." + +#: actions/twittersettings.php:151 +#: actions/twittersettings.php:170 +#: actions/twittersettings.php:234 +#: actions/twittersettings.php:253 +msgid "Unable to save your Twitter settings!" +msgstr "Non se puideron gardar os teus axustes de Twitter!" + +#: actions/twittersettings.php:174 +#: actions/twittersettings.php:261 +msgid "Twitter settings saved." +msgstr "Configuracións de Twitter gardadas." + +#: actions/twittersettings.php:192 +#: actions/twittersettings.php:272 +msgid "That is not your Twitter account." +msgstr "Esa non é a túa conta de Twitter." + +#: actions/twittersettings.php:200 +#: actions/twittersettings.php:208 +#: actions/twittersettings.php:280 +msgid "Couldn't remove Twitter user." +msgstr "Non se puido eliminar o usuario." + +#: actions/twittersettings.php:212 +#: actions/twittersettings.php:284 +msgid "Twitter account removed." +msgstr "Conta de Twitter " + +#: actions/twittersettings.php:225 +#: actions/twittersettings.php:239 +#: actions/twittersettings.php:299 +#: actions/twittersettings.php:310 +#: actions/twittersettings.php:322 +msgid "Couldn't save Twitter preferences." +msgstr "Non se puideron gardar as preferenzas de Twitter." + +#: actions/twittersettings.php:245 +#: actions/twittersettings.php:330 +msgid "Twitter preferences saved." +msgstr "Preferencias de Twitter gardadas." + +#: actions/userauthorization.php:84 +msgid "Please check these details to make sure " +msgstr "Comproba estes datos para asegurarte" + +#: actions/userauthorization.php:324 +msgid "The subscription has been authorized, but no " +msgstr "A suscrición foi autorizada, pero non" + +#: actions/userauthorization.php:334 +msgid "The subscription has been rejected, but no " +msgstr "A suscrición foi rexeitada, pero non" + +#: classes/Channel.php:113 +#: classes/Channel.php:129 +msgid "Command results" +msgstr "Resultados do comando" + +#: classes/Channel.php:148 +#: classes/Channel.php:175 +msgid "Command complete" +msgstr "Comando completo" + +#: classes/Channel.php:158 +#: classes/Channel.php:185 +msgid "Command failed" +msgstr "Comando fallido" + +#: classes/Command.php:39 +msgid "Sorry, this command is not yet implemented." +msgstr "Desculpa, este comando todavía non está implementado." + +#: classes/Command.php:96 +#, php-format +msgid "Subscriptions: %1$s\n" +msgstr "Subscricións: %1$s.\n" + +#: classes/Command.php:125 +#: classes/Command.php:242 +#: classes/Command.php:247 +msgid "User has no last notice" +msgstr "O usuario non ten último chio." + +#: classes/Command.php:146 +msgid "Notice marked as fave." +msgstr "Chío marcado coma favorito." + +#: classes/Command.php:166 +#, php-format +msgid "%1$s (%2$s)" +msgstr "%1$s (%2$s)" + +#: classes/Command.php:169 +#, php-format +msgid "Fullname: %s" +msgstr "Nome completo: %s" + +#: classes/Command.php:172 +#, php-format +msgid "Location: %s" +msgstr "Ubicación: %s" + +#: classes/Command.php:175 +#, php-format +msgid "Homepage: %s" +msgstr "Páxina persoal: %s" + +#: classes/Command.php:178 +#, php-format +msgid "About: %s" +msgstr "Sobre: %s" + +#: classes/Command.php:200 +#: classes/Command.php:202 +#, php-format +msgid "Message too long - maximum is 140 characters, you sent %d" +msgstr "Mensaxe demasiado longa - o máximo é 140 caracteres, ti enviaches %d " + +#: classes/Command.php:214 +#: classes/Command.php:219 +#, php-format +msgid "Direct message to %s sent" +msgstr "Mensaxe directo a %s enviado" + +#: classes/Command.php:216 +#: classes/Command.php:221 +msgid "Error sending direct message." +msgstr "Erro ó enviar a mensaxe directa." + +#: classes/Command.php:263 +#: classes/Command.php:268 +msgid "Specify the name of the user to subscribe to" +msgstr "Especifica o nome do usuario ó que queres suscribirte" + +#: classes/Command.php:270 +#: classes/Command.php:275 +#, php-format +msgid "Subscribed to %s" +msgstr "Suscrito a %s" + +#: classes/Command.php:288 +#: classes/Command.php:293 +msgid "Specify the name of the user to unsubscribe from" +msgstr "Especifica o nome de usuario ó que queres deixar de seguir" + +#: classes/Command.php:295 +#: classes/Command.php:300 +#, php-format +msgid "Unsubscribed from %s" +msgstr "Desuscribir de %s" + +#: classes/Command.php:310 +#: classes/Command.php:330 +#: classes/Command.php:315 +#: classes/Command.php:335 +msgid "Command not yet implemented." +msgstr "Comando non implementado." + +#: classes/Command.php:313 +#: classes/Command.php:318 +msgid "Notification off." +msgstr "Notificación desactivada." + +#: classes/Command.php:315 +#: classes/Command.php:320 +msgid "Can't turn off notification." +msgstr "No se pode desactivar a notificación." + +#: classes/Command.php:333 +#: classes/Command.php:338 +msgid "Notification on." +msgstr "Notificación habilitada." + +#: classes/Command.php:335 +#: classes/Command.php:340 +msgid "Can't turn on notification." +msgstr "Non se pode activar a notificación." + +#: classes/Command.php:344 +msgid "Commands:\n" +msgstr "Comandos:\n" + +#: classes/Message.php:53 +msgid "Could not insert message." +msgstr "Non se pode inserir unha mensaxe." + +#: classes/Message.php:63 +msgid "Could not update message with new URI." +msgstr "Non se puido actualizar a mensaxe coa nova URI." + +#: lib/gallery.php:46 +#: lib/gallery.php:55 +msgid "User without matching profile in system." +msgstr "Usuario sen perfil coincidente no sistema." + +#: lib/mail.php:147 +#, php-format +msgid "" +"You have a new posting address on %1$s.\n" +"\n" +msgstr "" +"Tes novas direccións de posteo en %1$s.\n" +"\n" + +#: lib/mail.php:249 +#: lib/mail.php:265 +#, php-format +msgid "New private message from %s" +msgstr "%s enviouche unha nova mensaxe privada" + +#: lib/mail.php:253 +#, php-format +msgid "" +"%1$s (%2$s) sent you a private message:\n" +"\n" +msgstr "" +"%1$s (%2$s) enviouche unha mensaxe privada:\n" +"\n" + +#: lib/mailbox.php:43 +msgid "Only the user can read their own mailboxes." +msgstr "Só o usuario pode ler os seus propios buzóns." + +#: lib/openid.php:195 +msgid "This form should automatically submit itself. " +msgstr "Este formulario debería enviarse automáticamente él mesmo." + +#: lib/personal.php:65 +msgid "Favorites" +msgstr "Favoritos" + +#: lib/personal.php:66 +#, php-format +msgid "%s's favorite notices" +msgstr "Chíos favoritos de %s" + +#: lib/personal.php:66 +msgid "User" +msgstr "Usuario" + +#: lib/personal.php:75 +msgid "Inbox" +msgstr "Band. Entrada" + +#: lib/personal.php:76 +msgid "Your incoming messages" +msgstr "As túas mensaxes entrantes" + +#: lib/personal.php:80 +msgid "Outbox" +msgstr "Band. Saída" + +#: lib/personal.php:81 +msgid "Your sent messages" +msgstr "As túas mensaxes enviadas" + +#: lib/settingsaction.php:99 +#: actions/deleteprofile.php:256 +#: lib/settingsaction.php:103 +#: lib/settingsaction.php:105 +msgid "Twitter" +msgstr "Twitter" + +#: lib/settingsaction.php:100 +#: actions/deleteprofile.php:257 +#: lib/settingsaction.php:104 +#: lib/settingsaction.php:106 +msgid "Twitter integration options" +msgstr "Opcións de integración de Twitter" + +#: lib/util.php:1718 +#: lib/util.php:2204 +msgid "To" +msgstr "A" + +#: scripts/maildaemon.php:45 +msgid "Could not parse message." +msgstr "Non se puido analizaar a mensaxe." + +#: actions/block.php:45 +#: actions/subedit.php:45 +#: actions/unblock.php:45 +msgid "No profile specified." +msgstr "Non se especificou ningún perfil." + +#: actions/block.php:52 +#: actions/subedit.php:52 +#: actions/tagother.php:45 +#: actions/unblock.php:52 +msgid "No profile with that ID." +msgstr "Non se atopou un perfil con ese ID." + +#: actions/block.php:78 +msgid "Block user" +msgstr "Bloquear usuario" + +#: actions/block.php:81 +msgid "Are you sure you want to block this user? Afterwards, they will be unsubscribed from you, unable to subscribe to you in the future, and you will not be notified of any @-replies from them." +msgstr "Seguro que queres bloquear a este usuario? Despois diso, vai ser de-suscrito do teur perfil, non será capaz de suscribirse a ti nun futuro, e non vas a ser notificado de ningunha resposta-@ del." + +#: actions/block.php:117 +msgid "You have already blocked this user." +msgstr "Xa bloqueaches a este usuario." + +#: actions/block.php:124 +msgid "Failed to save block information." +msgstr "Erro ao gardar información de bloqueo." + +#: actions/deleteprofile.php:25 +msgid "Code not yet ready." +msgstr "Código non implementado." + +#: actions/deleteprofile.php:36 +msgid "Export and delete your user information." +msgstr "Exportar e eliminar a túa información de usuario." + +#: actions/deleteprofile.php:88 +#: actions/deleteprofile.php:119 +msgid "Delete my account" +msgstr "Borrar a miña conta" + +#: actions/deleteprofile.php:89 +msgid "Delete my account confirmation" +msgstr "Confirmación de borrado da miña conta" + +#: actions/deleteprofile.php:117 +msgid "Check if you are sure you want to delete your account." +msgstr "Estas seguro que queres eliminar a tua conta?" + +#: actions/deleteprofile.php:259 +#: lib/settingsaction.php:106 +#: lib/util.php:384 +#: lib/settingsaction.php:108 +msgid "Other" +msgstr "Outros" + +#: actions/deleteprofile.php:260 +#: lib/settingsaction.php:107 +#: lib/settingsaction.php:109 +msgid "Other options" +msgstr "Outras opcions" + +#: actions/disfavor.php:72 +msgid "Add to favorites" +msgstr "Engadir a favoritos" + +#: actions/emailsettings.php:98 +msgid "Allow friends to nudge me and send me an email." +msgstr "Permitir aos amigos darme toques e enviarme correos electrónicos." + +#: actions/facebookremove.php:54 +msgid "Couldn't remove Facebook user." +msgstr "Non se puido eliminar o usuario de Facebook." + +#: actions/favorited.php:31 +#: lib/stream.php:48 +msgid "Popular notices" +msgstr "Chíos populares" + +#: actions/favorited.php:54 +msgid "Showing recently popular notices" +msgstr "Amosando chíos populares recentes" + +#: actions/favor.php:71 +msgid "Disfavor favorite" +msgstr "Desactivar favorito" + +#: actions/featured.php:32 +#: actions/featured.php:54 +#: lib/stream.php:44 +msgid "Featured users" +msgstr "Usuarios destacados" + +#: actions/finishremotesubscribe.php:186 +msgid "That user has blocked you from subscribing." +msgstr "Este usuario non che permite suscribirte a el." + +#: actions/imsettings.php:83 +msgid "Send me notices from public timeline through Jabber/GTalk." +msgstr "Enviarme os chíos da liña de tempo pública a través de Jabber/GTalk." + +#: actions/login.php:120 +msgid "you can also login using OpenID" +msgstr "tamén te podes rexistrar cunha conta OpenID" + +#: actions/microsummary.php:39 +msgid "No current status" +msgstr "Sen estado actual" + +#: actions/misc.php:81 +msgid "Embedded" +msgstr "Embebida" + +#: actions/misc.php:82 +#, php-format +msgid "Embedded %1s" +msgstr "%1s embebida" + +#: actions/misc.php:84 +msgid "WP" +msgstr "WP" + +#: actions/newnotice.php:93 +msgid "Notice posted" +msgstr "Chío publicado" + +#: actions/newnotice.php:116 +#: classes/Channel.php:140 +msgid "Ajax Error" +msgstr "Erro de Ajax" + +#: actions/nudge.php:52 +msgid "This user doesn't allow nudges or hasn't confirmed or set his email yet." +msgstr "Este usuario non permite toques, ou non confirmou ainda o seu correo electrónico." + +#: actions/nudge.php:61 +msgid "Nudge sent" +msgstr "Toque enviado" + +#: actions/othersettings.php:27 +msgid "Manage various other options." +msgstr "Xestionár axustes varios." + +#: actions/othersettings.php:33 +msgid "Other Settings" +msgstr "Outros axustes" + +#: actions/othersettings.php:35 +msgid "URL Auto-shortening" +msgstr "Auto-acortado de URL" + +#: actions/othersettings.php:54 +msgid "Service" +msgstr "Servizo" + +#: actions/othersettings.php:54 +msgid "Automatic shortening service to use." +msgstr "Servizo de acortado automático a usar." + +#: actions/othersettings.php:155 +msgid "URL shortening service is too long (max 50 chars)." +msgstr "Sistema de acortamento de URLs demasiado longo (max 50 car.)." + +#: actions/peopletag.php:33 +#, php-format +msgid "Not a valid people tag: %s" +msgstr "%s non é unha etiqueta de xente válida" + +#: actions/peopletag.php:45 +#, php-format +msgid "Users self-tagged with %s - page %d" +msgstr "Usuarios auto-etiquetados como %s - páxina %d" + +#: actions/peopletag.php:87 +#, php-format +msgid "These are users who have tagged themselves \"%s\" to show a common interest, characteristic, hobby or job." +msgstr "Estes son usuarios que se etiquetaron a sí mesmos como \"%s\" para mostrar intereses comuns, características, aficións ou traballos." + +#: actions/profilesettings.php:92 +msgid "Tags for yourself (letters, numbers, -, ., and _), comma- or space- separated" +msgstr "Etiquetas para o teu usuario (letras, números, -, ., e _), separados por coma ou espazo" + +#: actions/profilesettings.php:116 +msgid "Theme" +msgstr "Tema" + +#: actions/profilesettings.php:116 +msgid "Preferred theme" +msgstr "Tema preferido" + +#: actions/profilesettings.php:259 +#: actions/tagother.php:131 +#, php-format +msgid "Invalid tag: \"%s\"" +msgstr "Etiqueta inválida: '%s'" + +#: actions/profilesettings.php:345 +msgid "Couldn't save tags." +msgstr "Non se puideron gardar as etiquetas." + +#: actions/public.php:68 +#, php-format +msgid "This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service based on the Free Software [StatusNet](http://status.net/) tool. [Join now](%%action.register%%) to share notices about yourself with friends, family, and colleagues! ([Read more](%%doc.help%%))" +msgstr "Esto é %%site.name%%, un servizo de [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) basado na ferramenta de código aberto [StatusNet](http://status.net/). [Únete agora](%%action.register%%) para compartir chíos cos teus amigos, colegas e familia! ([Ler mais](%%doc.help%%))" + +#: actions/public.php:90 +msgid "Could not retrieve public stream." +msgstr "Non se pudo recuperar a liña de tempo publica." + +#: actions/register.php:67 +#: actions/register.php:177 +msgid "Sorry, only invited people can register." +msgstr "Desculpa, só se pode rexistrar a xente con invitación." + +#: actions/register.php:156 +#, php-format +msgid "With this form you can create a new account. You can then post notices and link up to friends and colleagues. (Have an [OpenID](http://openid.net/)? Try our [OpenID registration](%%action.openidlogin%%)!)" +msgstr "Neste formulario podes crear unha conta de usuario. Logo poderás publicar chíos, e suscribirte a amigos. (Tes unha conta [OpenID](http://openid.net/)? Proba o noso [Rexistro OpenID](%%action.openidlogin%%)!)" + +#: actions/remotesubscribe.php:136 +#: actions/remotesubscribe.php:141 +msgid "That's a local profile! Login to subscribe." +msgstr "Este é un perfil local! Rexístrate para suscribirte." + +#: actions/smspostsettings.php:27 +#, php-format +msgid "You can post on %1s sending an sms to %2s in the followin format: '%3s'" +msgstr "Podes publicar chíos en %1s enviando un SMS a %2s co seguinte formato: '%3s'" + +#: actions/smspostsettings.php:32 +#: actions/smspostsettings.php:33 +#: actions/smspostsettings.php:57 +msgid "SMS Post Settings" +msgstr "Configuracións de envio por SMS" + +#: actions/smspostsettings.php:101 +#: actions/smspostsettings.php:106 +msgid "The address was added." +msgstr "Enderezo engadido." + +#: actions/subedit.php:68 +msgid "You are not subscribed to that profile." +msgstr "Non estás suscrito a ese perfil" + +#: actions/subedit.php:81 +msgid "Could not save subscription." +msgstr "Non se pode gardar a subscrición." + +#: actions/subscribe.php:53 +msgid "Not a local user." +msgstr "Non é usuario local." + +#: actions/subscribe.php:67 +msgid "Subscribed" +msgstr "Suscrito" + +#: actions/subscriptions.php:72 +msgid "Jabber" +msgstr "Jabber." + +#: actions/tagother.php:31 +msgid "Not logged in" +msgstr "Non estás logueado." + +#: actions/tagother.php:40 +msgid "No id argument." +msgstr "Non hai argumento id." + +#: actions/tagother.php:56 +msgid "Tag a person" +msgstr "Etiquetar a unha persoa" + +#: actions/tagother.php:98 +msgid "Tags for this user (letters, numbers, -, ., and _), comma- or space- separated" +msgstr "Etiquetas para este usuario (letras, numeros, -, ., e _), separados por coma ou espazo" + +#: actions/tagother.php:120 +msgid "No such profile." +msgstr "Non existe o perfil." + +#: actions/tagother.php:146 +msgid "You can only tag people you are subscribed to or who are subscribed to you." +msgstr "Só podes etiquetar xente á que estás suscrito ou aos que están suscritos a ti." + +#: actions/tagother.php:153 +msgid "Could not save tags." +msgstr "Non se poden gardar as etiquetas." + +#: actions/tagother.php:188 +msgid "Use this form to add tags to your subscribers or subscriptions." +msgstr "Usa este formulario para engadir etiquetas aos teus seguidores ou aos que sigues." + +#: actions/tag.php:66 +msgid "Showing all tags" +msgstr "Amosando tódalas etiquetas" + +#: actions/tagrss.php:33 +msgid "No such tag." +msgstr "Non existe a etiqueta." + +#: actions/tagrss.php:62 +#, php-format +msgid "Microblog tagged with %s" +msgstr "Microblog etiquetado con %s" + +#: actions/twitapiblocks.php:45 +msgid "Block user failed." +msgstr "Bloqueo de usuario fallido." + +#: actions/twitapiblocks.php:66 +msgid "Unblock user failed." +msgstr "Desbloqueo de usuario fallido." + +#: actions/twitapifavorites.php:159 +#: lib/mail.php:294 +#, php-format +msgid "" +"%1$s just added your notice from %2$s as one of their favorites.\n" +"\n" +"In case you forgot, you can see the text of your notice here:\n" +"\n" +"%3$s\n" +"\n" +"You can see the list of %1$s's favorites here:\n" +"\n" +"%4$s\n" +"\n" +"Faithfully yours,\n" +"%5$s\n" +msgstr "" +"%1$s acaba de engadir o teu chío en %2$s como un dos seus favoritos.\n" +"\n" +"Se o olvidaches, podes velo texto do teu chío aquí:\n" +"\n" +"%3$s\n" +"\n" +"Podes vela lista de cíos favoritos de %1$s aquí:\n" +"\n" +"%4$s\n" +"\n" +"Fielmente teu,\n" +"%5$s\n" + +#: actions/twitapiusers.php:46 +msgid "Not found." +msgstr "Non atopado" + +#: actions/twittersettings.php:29 +msgid "Add your Twitter account to automatically send your notices to Twitter, and subscribe to Twitter friends already here." +msgstr "Engade a túa conta de Twitter para enviar automáticamente os teus chíos a Twitter, e suscribirte aos usuarios de twiter que teñas como amigos aqui." + +#: actions/twittersettings.php:63 +msgid "Twitter user name" +msgstr "Nome de usuario en Twitter" + +#: actions/twittersettings.php:67 +msgid "Twitter password" +msgstr "Contrasinal de Twitter" + +#: actions/twittersettings.php:129 +msgid "Twitter Friends" +msgstr "Amigos de Twitter" + +#: actions/unblock.php:73 +msgid "Error removing the block." +msgstr "Acounteceu un erro borrando o bloqueo." + +#: actions/unsubscribe.php:48 +msgid "No profile id in request." +msgstr "Non hai identificador de perfil na peticion." + +#: actions/unsubscribe.php:55 +msgid "No profile with that id." +msgstr "Non se atopou un perfil con ese ID." + +#: actions/unsubscribe.php:69 +msgid "Unsubscribed" +msgstr "De-suscribido" + +#: actions/users.php:38 +#: lib/util.php:378 +msgid "Users list" +msgstr "Lista de usuarios" + +#: classes/Command.php:96 +#, php-format +msgid "" +"Subscriptions: %1$s\n" +"Subscribers: %2$s\n" +"Notices: %3$s" +msgstr "" +"Suscripcións: %1$s\n" +"Suscriptores: %2$s\n" +"Chíos: %3$s" + +#: classes/Command.php:349 +msgid "" +"Commands:\n" +"on - turn on notifications\n" +"off - turn off notifications\n" +"help - show this help\n" +"follow - subscribe to user\n" +"leave - unsubscribe from user\n" +"d - direct message to user\n" +"get - get last notice from user\n" +"whois - get profile info on user\n" +"fav - add user's last notice as a 'fave'\n" +"stats - get your stats\n" +"stop - same as 'off'\n" +"quit - same as 'off'\n" +"sub - same as 'follow'\n" +"unsub - same as 'leave'\n" +"last - same as 'get'\n" +"on - not yet implemented.\n" +"off - not yet implemented.\n" +"nudge - not yet implemented.\n" +"invite - not yet implemented.\n" +"track - not yet implemented.\n" +"untrack - not yet implemented.\n" +"track off - not yet implemented.\n" +"untrack all - not yet implemented.\n" +"tracks - not yet implemented.\n" +"tracking - not yet implemented.\n" +msgstr "" +"Comandos:\n" +"on - activar as notificacións\n" +"off - desactivar as notificacións\n" +"help - mostrar esta axuda\n" +"follow - suscribirse ao usuario\n" +"leave - de-suscribirse do usuario\n" +"d - mensaxe directa ao usuario\n" +"get - lelo último chío do usuario\n" +"whois - amosar informacion do usuario\n" +"fav - engadilo último chío do usuario como favorito\n" +"stats - amosalas túas estatísticas\n" +"stop - o mesmo que 'off'\n" +"quit - o mesmo que 'off'\n" +"sub - o mesmo que 'follow'\n" +"unsub - o mesmo que 'leave'\n" +"last - o mesmo que 'get'\n" +"on - non implementado por agora.\n" +"off - non implementado por agora.\n" +"nudge - non implementado por agora.\n" +"invite - non implementado por agora.\n" +"track - non implementado por agora.\n" +"untrack - non implementado por agora.\n" +"track off - non implementado por agora.\n" +"untrack all - non implementado por agora.\n" +"tracks - non implementado por agora.\n" +"tracking - non implementado por agora.\n" + +#: classes/Notice.php:100 +msgid "Problem saving notice. Unknown user." +msgstr "Aconteceu un erro ó gardar o chío. Usuario descoñecido." + +#: classes/Notice.php:105 +msgid "Too many notices too fast; take a breather and post again in a few minutes." +msgstr "Demasiados chíos en pouco tempo; tomate un respiro e envíao de novo dentro duns minutos." + +#: classes/Notice.php:112 +msgid "You are banned from posting notices on this site." +msgstr "Tes restrinxido o envio de chíos neste sitio." + +#: lib/gallery.php:98 +msgid "Filter tags" +msgstr "Filtrar etiquetas" + +#: lib/gallery.php:104 +msgid "All" +msgstr "Todos" + +#: lib/gallery.php:108 +msgid "Tag" +msgstr "Etiqueta" + +#: lib/gallery.php:109 +msgid "Choose a tag to narrow list" +msgstr "Elixe unha etiqueta para reducila lista" + +#: lib/gallery.php:110 +msgid "Go" +msgstr "Ir" + +#: lib/gallery.php:264 +msgid "Subscriptions navigation" +msgstr "Navegación de subscricións" + +#: lib/gallery.php:270 +#: lib/gallery.php:292 +msgid "List" +msgstr "Lista" + +#: lib/gallery.php:280 +#: lib/gallery.php:294 +msgid "Icons" +msgstr "Iconos" + +#: lib/mail.php:92 +#, php-format +msgid "" +"Hey, %s.\n" +"\n" +"Someone just entered this email address on %s.\n" +"\n" +"If it was you, and you want to confirm your entry, use the URL below:\n" +"\n" +"\t%s\n" +"\n" +"If not, just ignore this message.\n" +"\n" +"Thanks for your time, \n" +"%s\n" +msgstr "" +"Ei, %s.\n" +"\n" +"Alguén introduceu o teu correo electrónico en %s.\n" +"\n" +"Se foches ti, e queres confirmar a entrada, pincha na seguinte URL:\n" +"\n" +"\t%s\n" +"\n" +"Se non, simplemente ignora esta mensaxe.\n" +"\n" +"Grazas polo teu tempo, \n" +"%s\n" + +#: lib/mail.php:232 +#, php-format +msgid "You've been nudged by %s" +msgstr "%s douche un toque" + +#: lib/mail.php:236 +#, php-format +msgid "" +"%1$s (%2$s) is wondering what you are up to these days and is inviting you to post some news.\n" +"\n" +"So let's hear from you :)\n" +"\n" +"%3$s\n" +"\n" +"Don't reply to this email; it won't get to them.\n" +"\n" +"With kind regards,\n" +"%4$s\n" +msgstr "" +"%1$s (%2$s) preguntase que é de ti, e invítate a publicar algun chío.\n" +"\n" +"So let's hear from you :)\n" +"\n" +"%3$s\n" +"\n" +"Don't reply to this email; it won't get to them.\n" +"\n" +"With kind regards,\n" +"%4$s\n" + +#: lib/mail.php:269 +#, php-format +msgid "" +"%1$s (%2$s) sent you a private message:\n" +"\n" +"------------------------------------------------------\n" +"%3$s\n" +"------------------------------------------------------\n" +"\n" +"You can reply to their message here:\n" +"\n" +"%4$s\n" +"\n" +"Don't reply to this email; it won't get to them.\n" +"\n" +"With kind regards,\n" +"%5$s\n" +msgstr "" +"%1$s (%2$s) enviouche unha mensaxe privada:\n" +"\n" +"------------------------------------------------------\n" +"%3$s\n" +"------------------------------------------------------\n" +"\n" +"You can reply to their message here:\n" +"\n" +"%4$s\n" +"\n" +"Don't reply to this email; it won't get to them.\n" +"\n" +"With kind regards,\n" +"%5$s\n" + +#: lib/profilelist.php:146 +msgid "(none)" +msgstr "(nada)" + +#: lib/settingsaction.php:97 +#: lib/settingsaction.php:98 +msgid "SMS Post" +msgstr "Envío por SMS" + +#: lib/settingsaction.php:98 +#: lib/settingsaction.php:99 +msgid "Posts by SMS" +msgstr "Chíos dende SMS" + +#: lib/stream.php:33 +msgid "Public" +msgstr "Público" + +#: lib/stream.php:36 +#: lib/stream.php:37 +msgid "Recent tags" +msgstr "Etiquetas recentes" + +#: lib/stream.php:39 +#: lib/stream.php:40 +msgid "All tags" +msgstr "Tódalas etiquetas" + +#: lib/stream.php:43 +msgid "Featured" +msgstr "Destacado" + +#: lib/stream.php:47 +msgid "Popular" +msgstr "Popular" + +#: lib/subs.php:51 +msgid "User has blocked you." +msgstr "O usuario bloqueoute." + +#: lib/util.php:379 +msgid "Users" +msgstr "Usuarios" + +#: lib/util.php:2118 +msgid "Send a nudge" +msgstr "Dar un toque" + +#: lib/util.php:2122 +msgid "Nudge sent!" +msgstr "Toque enviado!" + +#: lib/util.php:2253 +msgid "Block" +msgstr "Bloquear" + +#: lib/util.php:2257 +msgid "Unblock" +msgstr "Desbloquear" + +#: actions/newsmsnotice.php:29 +#: actions/smspostsettings.php:57 +msgid "SMS Post Disabled!" +msgstr "Publicación de chíos por SMS desactivado!" + +#: actions/badgemisc.php:31 +#, php-format +msgid "%1s in your blog" +msgstr "%1s no teu blogue" + +#: actions/misc.php:85 +msgid "WordPress Plugin" +msgstr "Plugin WordPress" + +#: actions/misc.php:88 +#, php-format +msgid "Graphics and statistics about the state of %1s" +msgstr "Gráficos e estatísticas sobre o estado de %1s" + +#: actions/newsmsnotice.php:35 +#, php-format +msgid "%1s is not a reliable source." +msgstr "%1s non é unha orixe fiable." + +#: actions/newsmsnotice.php:60 +msgid "Unexpected error" +msgstr "Erro inesperado" + +#: actions/newsmsnotice.php:65 +msgid "No such phone" +msgstr "Non existe o telefono" + +#: actions/newsmsnotice.php:75 +msgid "Missing message" +msgstr "Falta a mensaxe" + +#: actions/newsmsnotice.php:91 +msgid "Notice published correctly" +msgstr "Chío publicado correctamente" + +#: actions/wpmisc.php:27 +msgid "If you want to have your notices on your Wordpress, then follow the instructions" +msgstr "Se queres ter os teus chios no teu Wordpress, sigue as instruccións" + +#: actions/wpmisc.php:31 +#, php-format +msgid "%1s on your Wordpress" +msgstr "%1s no teu Wordpress" + +#: actions/badgemisc.php:27 +msgid "If you want to have your notices on your blog/website, then follow the instructions" +msgstr "Se queres ter os teus chios no teu blogue/sitio web, sigue as instruccións" + diff --git a/locale/he_IL/LC_MESSAGES/statusnet.mo b/locale/he/LC_MESSAGES/statusnet.mo similarity index 100% rename from locale/he_IL/LC_MESSAGES/statusnet.mo rename to locale/he/LC_MESSAGES/statusnet.mo diff --git a/locale/he_IL/LC_MESSAGES/statusnet.po b/locale/he/LC_MESSAGES/statusnet.po similarity index 100% rename from locale/he_IL/LC_MESSAGES/statusnet.po rename to locale/he/LC_MESSAGES/statusnet.po diff --git a/locale/is/LC_MESSAGES/statusnet.mo b/locale/is/LC_MESSAGES/statusnet.mo new file mode 100644 index 0000000000..36039f4aad Binary files /dev/null and b/locale/is/LC_MESSAGES/statusnet.mo differ diff --git a/locale/is_IS/LC_MESSAGES/statusnet.po b/locale/is/LC_MESSAGES/statusnet.po similarity index 100% rename from locale/is_IS/LC_MESSAGES/statusnet.po rename to locale/is/LC_MESSAGES/statusnet.po diff --git a/locale/it/LC_MESSAGES/statusnet.mo b/locale/it/LC_MESSAGES/statusnet.mo new file mode 100644 index 0000000000..00ab59804a Binary files /dev/null and b/locale/it/LC_MESSAGES/statusnet.mo differ diff --git a/locale/it_IT/LC_MESSAGES/statusnet.po b/locale/it/LC_MESSAGES/statusnet.po similarity index 100% rename from locale/it_IT/LC_MESSAGES/statusnet.po rename to locale/it/LC_MESSAGES/statusnet.po diff --git a/locale/it_IT/LC_MESSAGES/statusnet.mo b/locale/it_IT/LC_MESSAGES/statusnet.mo deleted file mode 100644 index 95764f1e29..0000000000 Binary files a/locale/it_IT/LC_MESSAGES/statusnet.mo and /dev/null differ diff --git a/locale/ja/LC_MESSAGES/statusnet.mo b/locale/ja/LC_MESSAGES/statusnet.mo new file mode 100644 index 0000000000..7026035cc0 Binary files /dev/null and b/locale/ja/LC_MESSAGES/statusnet.mo differ diff --git a/locale/ja_JP/LC_MESSAGES/statusnet.po b/locale/ja/LC_MESSAGES/statusnet.po similarity index 100% rename from locale/ja_JP/LC_MESSAGES/statusnet.po rename to locale/ja/LC_MESSAGES/statusnet.po diff --git a/locale/ja_JP/LC_MESSAGES/statusnet.mo b/locale/ja_JP/LC_MESSAGES/statusnet.mo deleted file mode 100644 index 86efaaf5d3..0000000000 Binary files a/locale/ja_JP/LC_MESSAGES/statusnet.mo and /dev/null differ diff --git a/locale/ko_KR/LC_MESSAGES/statusnet.mo b/locale/ko/LC_MESSAGES/statusnet.mo similarity index 100% rename from locale/ko_KR/LC_MESSAGES/statusnet.mo rename to locale/ko/LC_MESSAGES/statusnet.mo diff --git a/locale/ko_KR/LC_MESSAGES/statusnet.po b/locale/ko/LC_MESSAGES/statusnet.po similarity index 100% rename from locale/ko_KR/LC_MESSAGES/statusnet.po rename to locale/ko/LC_MESSAGES/statusnet.po diff --git a/locale/mk/LC_MESSAGES/statusnet.mo b/locale/mk/LC_MESSAGES/statusnet.mo new file mode 100644 index 0000000000..5dec309dd9 Binary files /dev/null and b/locale/mk/LC_MESSAGES/statusnet.mo differ diff --git a/locale/mk_MK/LC_MESSAGES/statusnet.po b/locale/mk/LC_MESSAGES/statusnet.po similarity index 99% rename from locale/mk_MK/LC_MESSAGES/statusnet.po rename to locale/mk/LC_MESSAGES/statusnet.po index d4c4eb2354..0e91f05224 100644 --- a/locale/mk_MK/LC_MESSAGES/statusnet.po +++ b/locale/mk/LC_MESSAGES/statusnet.po @@ -4670,12 +4670,12 @@ msgstr "%1$s сега ги следи вашите забелешки за %2$s. #: lib/mail.php:254 #, fuzzy, php-format msgid "Location: %s\n" -msgstr "Локација" +msgstr "" #: lib/mail.php:256 #, fuzzy, php-format msgid "Homepage: %s\n" -msgstr "Домашна страница" +msgstr "" #: lib/mail.php:258 #, php-format diff --git a/locale/mk_MK/LC_MESSAGES/statusnet.mo b/locale/mk_MK/LC_MESSAGES/statusnet.mo deleted file mode 100644 index 0ac378c79e..0000000000 Binary files a/locale/mk_MK/LC_MESSAGES/statusnet.mo and /dev/null differ diff --git a/locale/nb_NO/LC_MESSAGES/statusnet.mo b/locale/nb/LC_MESSAGES/statusnet.mo similarity index 100% rename from locale/nb_NO/LC_MESSAGES/statusnet.mo rename to locale/nb/LC_MESSAGES/statusnet.mo diff --git a/locale/nb_NO/LC_MESSAGES/statusnet.po b/locale/nb/LC_MESSAGES/statusnet.po similarity index 100% rename from locale/nb_NO/LC_MESSAGES/statusnet.po rename to locale/nb/LC_MESSAGES/statusnet.po diff --git a/locale/nl/LC_MESSAGES/statusnet.mo b/locale/nl/LC_MESSAGES/statusnet.mo new file mode 100644 index 0000000000..122a49285d Binary files /dev/null and b/locale/nl/LC_MESSAGES/statusnet.mo differ diff --git a/locale/nl_NL/LC_MESSAGES/statusnet.po b/locale/nl/LC_MESSAGES/statusnet.po similarity index 100% rename from locale/nl_NL/LC_MESSAGES/statusnet.po rename to locale/nl/LC_MESSAGES/statusnet.po diff --git a/locale/nl_NL/LC_MESSAGES/statusnet.mo b/locale/nl_NL/LC_MESSAGES/statusnet.mo deleted file mode 100644 index 16ce96d0dd..0000000000 Binary files a/locale/nl_NL/LC_MESSAGES/statusnet.mo and /dev/null differ diff --git a/locale/nn_NO/LC_MESSAGES/statusnet.mo b/locale/nn/LC_MESSAGES/statusnet.mo similarity index 100% rename from locale/nn_NO/LC_MESSAGES/statusnet.mo rename to locale/nn/LC_MESSAGES/statusnet.mo diff --git a/locale/nn_NO/LC_MESSAGES/statusnet.po b/locale/nn/LC_MESSAGES/statusnet.po similarity index 100% rename from locale/nn_NO/LC_MESSAGES/statusnet.po rename to locale/nn/LC_MESSAGES/statusnet.po diff --git a/locale/pl_PL/LC_MESSAGES/statusnet.mo b/locale/pl/LC_MESSAGES/statusnet.mo similarity index 100% rename from locale/pl_PL/LC_MESSAGES/statusnet.mo rename to locale/pl/LC_MESSAGES/statusnet.mo diff --git a/locale/pl_PL/LC_MESSAGES/statusnet.po b/locale/pl/LC_MESSAGES/statusnet.po similarity index 100% rename from locale/pl_PL/LC_MESSAGES/statusnet.po rename to locale/pl/LC_MESSAGES/statusnet.po diff --git a/locale/pt/LC_MESSAGES/statusnet.mo b/locale/pt/LC_MESSAGES/statusnet.mo index 35d7053bea..e6168a340f 100644 Binary files a/locale/pt/LC_MESSAGES/statusnet.mo and b/locale/pt/LC_MESSAGES/statusnet.mo differ diff --git a/locale/pt_BR/LC_MESSAGES/statusnet.mo b/locale/pt_BR/LC_MESSAGES/statusnet.mo index 9db1638b08..a5a6f27253 100644 Binary files a/locale/pt_BR/LC_MESSAGES/statusnet.mo and b/locale/pt_BR/LC_MESSAGES/statusnet.mo differ diff --git a/locale/ru_RU/LC_MESSAGES/statusnet.mo b/locale/ru/LC_MESSAGES/statusnet.mo similarity index 100% rename from locale/ru_RU/LC_MESSAGES/statusnet.mo rename to locale/ru/LC_MESSAGES/statusnet.mo diff --git a/locale/ru_RU/LC_MESSAGES/statusnet.po b/locale/ru/LC_MESSAGES/statusnet.po similarity index 100% rename from locale/ru_RU/LC_MESSAGES/statusnet.po rename to locale/ru/LC_MESSAGES/statusnet.po diff --git a/locale/sv/LC_MESSAGES/statusnet.mo b/locale/sv/LC_MESSAGES/statusnet.mo new file mode 100644 index 0000000000..2cb0397ec4 Binary files /dev/null and b/locale/sv/LC_MESSAGES/statusnet.mo differ diff --git a/locale/sv_SE/LC_MESSAGES/statusnet.po b/locale/sv/LC_MESSAGES/statusnet.po similarity index 100% rename from locale/sv_SE/LC_MESSAGES/statusnet.po rename to locale/sv/LC_MESSAGES/statusnet.po diff --git a/locale/sv_SE/LC_MESSAGES/statusnet.mo b/locale/sv_SE/LC_MESSAGES/statusnet.mo deleted file mode 100644 index ce3c6c1f55..0000000000 Binary files a/locale/sv_SE/LC_MESSAGES/statusnet.mo and /dev/null differ diff --git a/locale/te/LC_MESSAGES/statusnet.mo b/locale/te/LC_MESSAGES/statusnet.mo new file mode 100644 index 0000000000..5cfa0c3fb5 Binary files /dev/null and b/locale/te/LC_MESSAGES/statusnet.mo differ diff --git a/locale/te_IN/LC_MESSAGES/statusnet.po b/locale/te/LC_MESSAGES/statusnet.po similarity index 100% rename from locale/te_IN/LC_MESSAGES/statusnet.po rename to locale/te/LC_MESSAGES/statusnet.po diff --git a/locale/te_IN/LC_MESSAGES/statusnet.mo b/locale/te_IN/LC_MESSAGES/statusnet.mo deleted file mode 100644 index bb837b9778..0000000000 Binary files a/locale/te_IN/LC_MESSAGES/statusnet.mo and /dev/null differ diff --git a/locale/tr/LC_MESSAGES/statusnet.mo b/locale/tr/LC_MESSAGES/statusnet.mo new file mode 100644 index 0000000000..d49c7093d3 Binary files /dev/null and b/locale/tr/LC_MESSAGES/statusnet.mo differ diff --git a/locale/tr_TR/LC_MESSAGES/statusnet.po b/locale/tr/LC_MESSAGES/statusnet.po similarity index 99% rename from locale/tr_TR/LC_MESSAGES/statusnet.po rename to locale/tr/LC_MESSAGES/statusnet.po index e67fbf33c3..4dbc221d13 100644 --- a/locale/tr_TR/LC_MESSAGES/statusnet.po +++ b/locale/tr/LC_MESSAGES/statusnet.po @@ -4676,13 +4676,13 @@ msgstr "%1$s %2$s'da durumunuzu takip ediyor" #: lib/mail.php:254 #, fuzzy, php-format msgid "Location: %s\n" -msgstr "Yer" +msgstr "" # Belki Durum Merkezi falan denebilir mi ki? #: lib/mail.php:256 #, fuzzy, php-format msgid "Homepage: %s\n" -msgstr "Başlangıç Sayfası" +msgstr "" #: lib/mail.php:258 #, php-format diff --git a/locale/tr_TR/LC_MESSAGES/statusnet.mo b/locale/tr_TR/LC_MESSAGES/statusnet.mo deleted file mode 100644 index e0ef80560f..0000000000 Binary files a/locale/tr_TR/LC_MESSAGES/statusnet.mo and /dev/null differ diff --git a/locale/uk_UA/LC_MESSAGES/statusnet.mo b/locale/uk/LC_MESSAGES/statusnet.mo similarity index 100% rename from locale/uk_UA/LC_MESSAGES/statusnet.mo rename to locale/uk/LC_MESSAGES/statusnet.mo diff --git a/locale/uk_UA/LC_MESSAGES/statusnet.po b/locale/uk/LC_MESSAGES/statusnet.po similarity index 100% rename from locale/uk_UA/LC_MESSAGES/statusnet.po rename to locale/uk/LC_MESSAGES/statusnet.po diff --git a/locale/vi/LC_MESSAGES/statusnet.mo b/locale/vi/LC_MESSAGES/statusnet.mo new file mode 100644 index 0000000000..b2f4dd370a Binary files /dev/null and b/locale/vi/LC_MESSAGES/statusnet.mo differ diff --git a/locale/vi_VN/LC_MESSAGES/statusnet.po b/locale/vi/LC_MESSAGES/statusnet.po similarity index 100% rename from locale/vi_VN/LC_MESSAGES/statusnet.po rename to locale/vi/LC_MESSAGES/statusnet.po diff --git a/locale/vi_VN/LC_MESSAGES/statusnet.mo b/locale/vi_VN/LC_MESSAGES/statusnet.mo deleted file mode 100644 index 65add28b47..0000000000 Binary files a/locale/vi_VN/LC_MESSAGES/statusnet.mo and /dev/null differ diff --git a/locale/zh_TW/LC_MESSAGES/statusnet.mo b/locale/zh_TW/LC_MESSAGES/statusnet.mo index e135488319..9bdfbaf9f7 100644 Binary files a/locale/zh_TW/LC_MESSAGES/statusnet.mo and b/locale/zh_TW/LC_MESSAGES/statusnet.mo differ diff --git a/locale/zh_TW/LC_MESSAGES/statusnet.po b/locale/zh_TW/LC_MESSAGES/statusnet.po index a941875188..4f11686014 100644 --- a/locale/zh_TW/LC_MESSAGES/statusnet.po +++ b/locale/zh_TW/LC_MESSAGES/statusnet.po @@ -4563,12 +4563,12 @@ msgstr "現在%1$s在%2$s成為你的粉絲囉" #: lib/mail.php:254 #, fuzzy, php-format msgid "Location: %s\n" -msgstr "地點" +msgstr "" #: lib/mail.php:256 #, fuzzy, php-format msgid "Homepage: %s\n" -msgstr "個人首頁" +msgstr "" #: lib/mail.php:258 #, php-format diff --git a/plugins/FBConnect/README b/plugins/FBConnect/README deleted file mode 100644 index 77d57eff92..0000000000 --- a/plugins/FBConnect/README +++ /dev/null @@ -1,76 +0,0 @@ -This plugin allows you to utilize Facebook Connect with StatusNet. -Supported Facebook Connect features: - -- Authenticate (register/login/logout -- works similar to OpenID) -- Associate an existing StatusNet account with a Facebook account -- Disconnect a Facebook account from a StatusNet account - -Future planned functionality: - -- Invite Facebook friends to use your StatusNet installation -- Auto-subscribe Facebook friends already using StatusNet -- Share StatusNet favorite notices to your Facebook stream - -To use the plugin you will need to configure a Facebook application -to point to your StatusNet installation (see the Installation section -below). - -Installation -============ - -If you don't already have the built-in Facebook application configured, -you'll need to log into Facebook and create/configure a new application. -Please follow the instructions in the section titled, "Setting Up Your -Application and Getting an API Key," on the following page of the -Facebook developer wiki: - - http://wiki.developers.facebook.com/index.php/Connect/Setting_Up_Your_Site - -If you already are using the build-in StatusNet Facebook application, -you can modify your existing application's configuration using the -Facebook Developer Application on Facebook. Use it to edit your -application settings, and under the 'Connect' tab, change the 'Connect -URL' to be the main URL for your StatusNet site. E.g.: - - http://SITE/PATH_TO_STATUSNET/ - -After you application is created and configured, you'll need to add its -API key and secret to your StatusNet config.php file: - - $config['facebook']['apikey'] = 'APIKEY'; - $config['facebook']['secret'] = 'SECRET'; - -Finally, to enable the plugin, add the following stanza to your -config.php: - - addPlugin('FBConnect'); - -To try out the plugin, fire up your browser and connect to: - - http://SITE/PATH_TO_STATUSNET/main/facebooklogin - -or, if you do not have fancy URLs turned on: - - http://SITE/PATH_TO_STATUSNET/index.php/main/facebooklogin - -You should see a page with a blue button that says: "Connect with -Facebook". - -Connect/Disconnect existing account -=================================== - -If the Facebook Connect plugin is enabled, there will be a new Facebook -Connect Settings tab under each user's Connect menu. Users can connect -and disconnect to their Facebook accounts from it. Note: Before a user -can disconnect from Facebook, she must set a normal StatusNet password. -Otherwise, she might not be able to login in to her account in the -future. This is usually only required for users who have used Facebook -Connect to register their StatusNet account, and therefore haven't -already set a local password. - -Helpful links -============= - -Facebook Connect Homepage: -http://developers.facebook.com/connect.php - diff --git a/plugins/FBConnect/FBCLoginGroupNav.php b/plugins/Facebook/FBCLoginGroupNav.php similarity index 100% rename from plugins/FBConnect/FBCLoginGroupNav.php rename to plugins/Facebook/FBCLoginGroupNav.php diff --git a/plugins/FBConnect/FBCSettingsNav.php b/plugins/Facebook/FBCSettingsNav.php similarity index 100% rename from plugins/FBConnect/FBCSettingsNav.php rename to plugins/Facebook/FBCSettingsNav.php diff --git a/plugins/FBConnect/FBC_XDReceiver.php b/plugins/Facebook/FBC_XDReceiver.php similarity index 100% rename from plugins/FBConnect/FBC_XDReceiver.php rename to plugins/Facebook/FBC_XDReceiver.php diff --git a/plugins/FBConnect/FBConnectPlugin.css b/plugins/Facebook/FBConnect.css similarity index 100% rename from plugins/FBConnect/FBConnectPlugin.css rename to plugins/Facebook/FBConnect.css diff --git a/plugins/FBConnect/FBConnectAuth.php b/plugins/Facebook/FBConnectAuth.php similarity index 99% rename from plugins/FBConnect/FBConnectAuth.php rename to plugins/Facebook/FBConnectAuth.php index 647d5def89..b909a49771 100644 --- a/plugins/FBConnect/FBConnectAuth.php +++ b/plugins/Facebook/FBConnectAuth.php @@ -27,7 +27,7 @@ * @link http://status.net/ */ -require_once INSTALLDIR . '/plugins/FBConnect/FBConnectPlugin.php'; +require_once INSTALLDIR . '/plugins/Facebook/FacebookPlugin.php'; class FBConnectauthAction extends Action { diff --git a/plugins/FBConnect/FBConnectLogin.php b/plugins/Facebook/FBConnectLogin.php similarity index 96% rename from plugins/FBConnect/FBConnectLogin.php rename to plugins/Facebook/FBConnectLogin.php index 5696d88489..f146bef7d1 100644 --- a/plugins/FBConnect/FBConnectLogin.php +++ b/plugins/Facebook/FBConnectLogin.php @@ -21,7 +21,8 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -require_once INSTALLDIR . '/plugins/FBConnect/FBConnectPlugin.php'; + +require_once INSTALLDIR . '/plugins/Facebook/FacebookPlugin.php'; class FBConnectLoginAction extends Action { diff --git a/plugins/FBConnect/FBConnectSettings.php b/plugins/Facebook/FBConnectSettings.php similarity index 100% rename from plugins/FBConnect/FBConnectSettings.php rename to plugins/Facebook/FBConnectSettings.php diff --git a/plugins/FBConnect/FBConnectPlugin.php b/plugins/Facebook/FacebookPlugin.php similarity index 50% rename from plugins/FBConnect/FBConnectPlugin.php rename to plugins/Facebook/FacebookPlugin.php index ff74aade45..b68534b24f 100644 --- a/plugins/FBConnect/FBConnectPlugin.php +++ b/plugins/Facebook/FacebookPlugin.php @@ -2,7 +2,7 @@ /** * StatusNet, the distributed open-source microblogging tool * - * Plugin to enable Facebook Connect + * Plugin to add a StatusNet Facebook application * * PHP version 5 * @@ -27,22 +27,16 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { +if (!defined('STATUSNET')) { exit(1); } define("FACEBOOK_CONNECT_SERVICE", 3); -require_once INSTALLDIR . '/lib/facebookutil.php'; -require_once INSTALLDIR . '/plugins/FBConnect/FBConnectAuth.php'; -require_once INSTALLDIR . '/plugins/FBConnect/FBConnectLogin.php'; -require_once INSTALLDIR . '/plugins/FBConnect/FBConnectSettings.php'; -require_once INSTALLDIR . '/plugins/FBConnect/FBCLoginGroupNav.php'; -require_once INSTALLDIR . '/plugins/FBConnect/FBCSettingsNav.php'; -require_once INSTALLDIR . '/plugins/FBConnect/FBC_XDReceiver.php'; +require_once INSTALLDIR . '/plugins/Facebook/facebookutil.php'; /** - * Plugin to enable Facebook Connect + * Facebook plugin to add a StatusNet Facebook application * * @category Plugin * @package StatusNet @@ -51,22 +45,88 @@ require_once INSTALLDIR . '/plugins/FBConnect/FBC_XDReceiver.php'; * @link http://status.net/ */ -class FBConnectPlugin extends Plugin +class FacebookPlugin extends Plugin { - function __construct() - { - parent::__construct(); - } - // Hook in new actions - function onRouterInitialized(&$m) { + /** + * Add Facebook app actions to the router table + * + * Hook for RouterInitialized event. + * + * @param Net_URL_Mapper &$m path-to-action mapper + * + * @return boolean hook return + */ + + function onRouterInitialized($m) + { + + // Facebook App stuff + + $m->connect('facebook/app', array('action' => 'facebookhome')); + $m->connect('facebook/app/index.php', array('action' => 'facebookhome')); + $m->connect('facebook/app/settings.php', + array('action' => 'facebooksettings')); + $m->connect('facebook/app/invite.php', array('action' => 'facebookinvite')); + $m->connect('facebook/app/remove', array('action' => 'facebookremove')); + + // Facebook Connect stuff + $m->connect('main/facebookconnect', array('action' => 'FBConnectAuth')); $m->connect('main/facebooklogin', array('action' => 'FBConnectLogin')); $m->connect('settings/facebook', array('action' => 'FBConnectSettings')); $m->connect('xd_receiver.html', array('action' => 'FBC_XDReceiver')); - } - // Add in xmlns:fb + return true; + } + + /** + * Automatically load the actions and libraries used by the Facebook app + * + * @param Class $cls the class + * + * @return boolean hook return + * + */ + + function onAutoload($cls) + { + switch ($cls) { + case 'FacebookAction': + case 'FacebookhomeAction': + case 'FacebookinviteAction': + case 'FacebookremoveAction': + case 'FacebooksettingsAction': + include_once INSTALLDIR . '/plugins/Facebook/' . + strtolower(mb_substr($cls, 0, -6)) . '.php'; + return false; + case 'FBConnectAuthAction': + case 'FBConnectLoginAction': + case 'FBConnectSettingsAction': + case 'FBC_XDReceiverAction': + include_once INSTALLDIR . '/plugins/Facebook/' . + mb_substr($cls, 0, -6) . '.php'; + return false; + case 'FBCLoginGroupNav': + include_once INSTALLDIR . '/plugins/Facebook/FBCLoginGroupNav.php'; + return false; + case 'FBCSettingsNav': + include_once INSTALLDIR . '/plugins/Facebook/FBCSettingsNav.php'; + return false; + default: + return true; + } + } + + /** + * Override normal HTML output to force the content type to + * text/html and add in xmlns:fb + * + * @param Action $action the current action + * + * @return void + */ + function onStartShowHTML($action) { @@ -78,6 +138,7 @@ class FBConnectPlugin extends Plugin // text/html even though Facebook Connect uses XHTML. This is // A bug in Facebook Connect, and this is a temporary solution // until they fix their JavaScript libs. + header('Content-Type: text/html'); $action->extraHeaders(); @@ -100,59 +161,108 @@ class FBConnectPlugin extends Plugin } } - // Note: this script needs to appear in the + /** + * Add in the Facebook Connect JavaScript stuff + * + * Note: this script needs to appear in the + * + * @param Action $action the current action + * + * @return void + * + */ - function onStartShowHeader($action) + function onEndShowScripts($action) { if ($this->reqFbScripts($action)) { - $apikey = common_config('facebook', 'apikey'); - $plugin_path = common_path('plugins/FBConnect'); + $apikey = common_config('facebook', 'apikey'); + $plugin_path = common_path('plugins/Facebook'); - $login_url = common_local_url('FBConnectAuth'); + $login_url = common_local_url('FBConnectAuth'); $logout_url = common_local_url('logout'); // XXX: Facebook says we don't need this FB_RequireFeatures(), // but we actually do, for IE and Safari. Gar. - $html = sprintf('', $apikey, - $login_url, $logout_url); + // The below function alters the logout link so that it logs the user out + // of Facebook Connect as well as the site. However, for some pages + // (FB Connect Settings) we need to output the FB Connect scripts (to + // show an existing FB connection even if the user isn't authenticated + // with Facebook connect) but NOT alter the logout link. And the only + // way to reliably do that is with the FB Connect .js libs. Crazy. - $action->raw($html); + $js .= ' FB.ensureInit(function() {'; + $js .= ' FB.Connect.ifUserConnected('; + $js .= ' function() { '; + $js .= ' $(\'#nav_logout a\').attr(\'href\', \'#\');'; + $js .= ' $(\'#nav_logout a\').click(function() {'; + $js .= ' FB.Connect.logoutAndRedirect(\'%3$s\');'; + $js .= ' return false;'; + $js .= ' })'; + $js .= ' },'; + $js .= ' function() {'; + $js .= ' return false;'; + $js .= ' }'; + $js .= ' );'; + $js .= ' });'; + $js .= ''; + + $js = sprintf($js, $apikey, $login_url, $logout_url); + + // Compress the bugger down a bit + + $js = str_replace(' ', '', $js); + + $action->raw(" $js"); // leading two spaces to make it line up } } - // Note: this script needs to appear as close as possible to + /** + * Add in an additional Facebook Connect script that's supposed to + * appear as close as possible to + * + * @param Action $action the current action + * + * @return void + * + */ function onEndShowFooter($action) { if ($this->reqFbScripts($action)) { - $action->script('http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php'); + $action->script('http://static.ak.connect.facebook.com' . + '/js/api_lib/v0.4/FeatureLoader.js.php'); } } + /** + * Output Facebook Connect specific CSS link + * + * @param Action $action the current action + * + * @return void + * + */ + function onEndShowStatusNetStyles($action) { - if ($this->reqFbScripts($action)) { - $action->cssLink('plugins/FBConnect/FBConnectPlugin.css'); + $action->cssLink('plugins/Facebook/FBConnect.css'); } } @@ -161,12 +271,13 @@ class FBConnectPlugin extends Plugin * want to output FB namespace, scripts, CSS, etc. on the pages that * really need them. * - * @param Action the action in question + * @param Action $action the current action * * @return boolean true */ - function reqFbScripts($action) { + function reqFbScripts($action) + { // If you're logged in w/FB Connect, you always need the FB stuff @@ -228,10 +339,19 @@ class FBConnectPlugin extends Plugin return null; } + /** + * Add in a Facebook Connect avatar to the primary nav menu + * + * @param Action $action the current action + * + * @return void + * + */ + function onStartPrimaryNav($action) { - $user = common_current_user(); + $connect = 'FBConnectSettings'; if (common_config('xmpp', 'enabled')) { $connect = 'imsettings'; @@ -262,78 +382,31 @@ class FBConnectPlugin extends Plugin 'alt' => 'Facebook Connect User', 'width' => '16'), ''); - $iconurl = common_path('plugins/FBConnect/fbfavicon.ico'); + $iconurl = common_path('plugins/Facebook/fbfavicon.ico'); $action->element('img', array('id' => 'fb_favicon', 'src' => $iconurl)); $action->elementEnd('li'); } + } - $action->menuItem(common_local_url('all', array('nickname' => $user->nickname)), - _('Home'), _('Personal profile and friends timeline'), false, 'nav_home'); - $action->menuItem(common_local_url('profilesettings'), - _('Account'), _('Change your email, avatar, password, profile'), false, 'nav_account'); - $action->menuItem(common_local_url($connect), - _('Connect'), _('Connect to services'), false, 'nav_connect'); - if (common_config('invite', 'enabled')) { - $action->menuItem(common_local_url('invite'), - _('Invite'), - sprintf(_('Invite friends and colleagues to join you on %s'), - common_config('site', 'name')), - false, 'nav_invitecontact'); - } - - // Need to override the Logout link to make it do FB stuff - if (!empty($fbuid)) { - - $logout_url = common_local_url('logout'); - $title = _('Logout from the site'); - $text = _('Logout'); - - $html = sprintf('', - $title, $logout_url, $text); - - $action->raw($html); - - } else { - $action->menuItem(common_local_url('logout'), - _('Logout'), _('Logout from the site'), false, 'nav_logout'); - } - } - else { - if (!common_config('site', 'openidonly')) { - if (!common_config('site', 'closed')) { - $action->menuItem(common_local_url('register'), - _('Register'), _('Create an account'), false, 'nav_register'); - } - $action->menuItem(common_local_url('login'), - _('Login'), _('Login to the site'), false, 'nav_login'); - } else { - $this->menuItem(common_local_url('openidlogin'), - _('OpenID'), _('Login with OpenID'), false, 'nav_openid'); - } - } - - $action->menuItem(common_local_url('doc', array('title' => 'help')), - _('Help'), _('Help me!'), false, 'nav_help'); - if ($user || !common_config('site', 'private')) { - $action->menuItem(common_local_url('peoplesearch'), - _('Search'), _('Search for people or text'), false, 'nav_search'); - } - - // We are replacing the primary nav entirely; give other - // plugins a chance to handle it here. - - Event::handle('EndPrimaryNav', array($action)); - - return false; + return true; } + /** + * Alter the local nav menu to have a Facebook Connect login and + * settings pages + * + * @param Action $action the current action + * + * @return void + * + */ + function onStartShowLocalNavBlock($action) { - $action_name = get_class($action); + $action_name = get_class($action); $login_actions = array('LoginAction', 'RegisterAction', 'OpenidloginAction', 'FBConnectLoginAction'); @@ -356,8 +429,16 @@ class FBConnectPlugin extends Plugin return true; } + /** + * Have the logout process do some Facebook Connect cookie cleanup + * + * @param Action $action the current action + * + * @return void + */ + function onStartLogout($action) -{ + { $action->logout(); $fbuid = $this->loggedIn(); @@ -375,9 +456,16 @@ class FBConnectPlugin extends Plugin return true; } + /** + * Get the URL of the user's Facebook avatar + * + * @param int $fbuid the Facebook user ID + * + * @return string $url the url for the user's Facebook avatar + */ + function getProfilePicURL($fbuid) { - $facebook = getFacebook(); $url = null; @@ -396,8 +484,70 @@ class FBConnectPlugin extends Plugin "Facebook client failure requesting profile pic!"); } - return $url; + return $url; + } + /** + * Add a Facebook queue item for each notice + * + * @param Notice $notice the notice + * @param array &$transports the list of transports (queues) + * + * @return boolean hook return + */ + + function onStartEnqueueNotice($notice, &$transports) + { + array_push($transports, 'facebook'); + return true; + } + + /** + * broadcast the message when not using queuehandler + * + * @param Notice &$notice the notice + * @param array $queue destination queue + * + * @return boolean hook return + */ + + function onUnqueueHandleNotice(&$notice, $queue) + { + if (($queue == 'facebook') && ($this->_isLocal($notice))) { + facebookBroadcastNotice($notice); + return false; + } + return true; + } + + /** + * Determine whether the notice was locally created + * + * @param Notice $notice the notice + * + * @return boolean locality + */ + + function _isLocal($notice) + { + return ($notice->is_local == Notice::LOCAL_PUBLIC || + $notice->is_local == Notice::LOCAL_NONPUBLIC); + } + + /** + * Add Facebook queuehandler to the list of daemons to start + * + * @param array $daemons the list fo daemons to run + * + * @return boolean hook return + * + */ + + function onGetValidDaemons($daemons) + { + array_push($daemons, INSTALLDIR . + '/plugins/Facebook/facebookqueuehandler.php'); + return true; } } diff --git a/plugins/Facebook/README b/plugins/Facebook/README new file mode 100644 index 0000000000..bf2f4a1800 --- /dev/null +++ b/plugins/Facebook/README @@ -0,0 +1,129 @@ +This plugin allows you to use Facebook Connect with StatusNet, provides a +Facebook application for your users, and allows them to update their +Facebook statuses from StatusNet. + +Facebook Connect +---------------- + +Facebook connect allows users to register and login using nothing but their +Facebook credentials. With Facebook Connect, your users can: + +- Authenticate (register/login/logout -- works similar to OpenID) +- Associate an existing StatusNet account with a Facebook account +- Disconnect a Facebook account from a StatusNet account + +Built-in Facebook Application +----------------------------- + +The plugin also installs a StatusNet Facebook application that allows your +users to automatically update their Facebook statuses with their latest +notices, invite their friends to use the app (and thus your site), view +their notice timelines, and post notices -- all from within Facebook. The +application is built into the StatusNet Facebook plugin and runs on your +host. + +Quick setup instructions* +------------------------- + +Install the Facebook Developer application on Facebook: + + http://www.facebook.com/developers/ + +Use it to create a new application and generate an API key and secret. Add a +Facebook app section of your config.php and copy in the key and secret, +e.g.: + + // Config section for the built-in Facebook application + $config['facebook']['apikey'] = 'APIKEY'; + $config['facebook']['secret'] = 'SECRET'; + +In Facebook's application editor, specify the following URLs for your app: + +- Canvas Callback URL : http://example.net/mublog/facebook/app/ +- Post-Remove Callback URL: http://example.net/mublog/facebook/app/remove +- Post-Add Redirect URL : http://apps.facebook.com/yourapp/ +- Canvas Page URL : http://apps.facebook.com/yourapp/ +- Connect URL : http://example.net/mublog/ + + *** ATTENTION *** + These URLs have changed slightly since StatusNet version 0.8.1, + so if you have been using the Facebook app previously, you will + need to update your configuration! + +Replace "example.net" with your host's URL, "mublog" with the path to your +StatusNet installation, and 'yourapp' with the name of the Facebook +application you created. (If you don't have "Fancy URLs" on, you'll need to +change http://example.net/mublog/ to http://example.net/mublog/index.php/). + +Additionally, Choose "Web" for Application type in the Advanced tab. In the +"Canvas setting" section, choose the "FBML" for Render Method, "Smart Size" +for IFrame size, and "Full width (760px)" for Canvas Width. Everything else +can be left with default values. + +* NOTE: For more under-the-hood detailed instructions about setting up a + Facebook application and getting an API key, check out the + following pages on the Facebook wiki: + + http://wiki.developers.facebook.com/index.php/Connect/Setting_Up_Your_Site + http://wiki.developers.facebook.com/index.php/Creating_your_first_application + +Finally you must activate the plugin by adding the following line to your +config.php: + + addPlugin('Facebook'); + +Testing It Out +-------------- + +If the Facebook plugin is enabled and working, there will be a new Facebook +Connect Settings tab under each user's Connect menu. Users can connect and +disconnect* to their Facebook accounts from it. + +To try out the plugin, fire up your browser and connect to: + + http://SITE/PATH_TO_STATUSNET/main/facebooklogin + +or, if you do not have fancy URLs turned on: + + http://SITE/PATH_TO_STATUSNET/index.php/main/facebooklogin + +You should see a page with a blue button that says: "Connect with Facebook" +and you should be able to login or register. + +From within Facebook, you should also be able to get to the Facebook +application, and run it by hitting the link you specified above when +configuring it: + + http://apps.facebook.com/yourapp/ + +That link should be present you with a login screen. After logging in to +the app, you are given the option to update their Facebook status via +StatusNet. + +* Note: Before a user can disconnect from Facebook, she must set a normal + StatusNet password. Otherwise, she might not be able to login in to her + account in the future. This is usually only required for users who have + used Facebook Connect to register their StatusNet account, and therefore + haven't already set a local password. + +Offline Queue Handling +---------------------- + +For larger sites needing better performance it's possible to enable queuing +and have users' notices posted to Facebook via a separate "offline" +FacebookQueueHandler (facebookqueuhandler.php in the Facebook plugin +directory), which will be started by the plugin along with their other +daemons when you run scripts/startdaemons.sh. See the StatusNet README for +more about queuing and daemons. + +TODO +---- + +- Invite Facebook friends to use your StatusNet installation via Facebook + Connect +- Auto-subscribe Facebook friends already using StatusNet +- Share StatusNet favorite notices to your Facebook stream +- Allow users to update their Facebook statuses once they have authenticated + with Facebook Connect (no need for them to use the Facebook app if they + don't want to). +- Re-design the whole thing to support multiple instances of StatusNet diff --git a/extlib/facebook/facebook.php b/plugins/Facebook/facebook/facebook.php similarity index 100% rename from extlib/facebook/facebook.php rename to plugins/Facebook/facebook/facebook.php diff --git a/extlib/facebook/facebook_desktop.php b/plugins/Facebook/facebook/facebook_desktop.php similarity index 100% rename from extlib/facebook/facebook_desktop.php rename to plugins/Facebook/facebook/facebook_desktop.php diff --git a/extlib/facebook/facebookapi_php5_restlib.php b/plugins/Facebook/facebook/facebookapi_php5_restlib.php similarity index 100% rename from extlib/facebook/facebookapi_php5_restlib.php rename to plugins/Facebook/facebook/facebookapi_php5_restlib.php diff --git a/extlib/facebook/jsonwrapper/JSON/JSON.php b/plugins/Facebook/facebook/jsonwrapper/JSON/JSON.php similarity index 100% rename from extlib/facebook/jsonwrapper/JSON/JSON.php rename to plugins/Facebook/facebook/jsonwrapper/JSON/JSON.php diff --git a/extlib/facebook/jsonwrapper/JSON/LICENSE b/plugins/Facebook/facebook/jsonwrapper/JSON/LICENSE similarity index 100% rename from extlib/facebook/jsonwrapper/JSON/LICENSE rename to plugins/Facebook/facebook/jsonwrapper/JSON/LICENSE diff --git a/extlib/facebook/jsonwrapper/jsonwrapper.php b/plugins/Facebook/facebook/jsonwrapper/jsonwrapper.php similarity index 100% rename from extlib/facebook/jsonwrapper/jsonwrapper.php rename to plugins/Facebook/facebook/jsonwrapper/jsonwrapper.php diff --git a/extlib/facebook/jsonwrapper/jsonwrapper_inner.php b/plugins/Facebook/facebook/jsonwrapper/jsonwrapper_inner.php similarity index 100% rename from extlib/facebook/jsonwrapper/jsonwrapper_inner.php rename to plugins/Facebook/facebook/jsonwrapper/jsonwrapper_inner.php diff --git a/lib/facebookaction.php b/plugins/Facebook/facebookaction.php similarity index 93% rename from lib/facebookaction.php rename to plugins/Facebook/facebookaction.php index 3f3a8d3b09..a10fdf90d4 100644 --- a/lib/facebookaction.php +++ b/plugins/Facebook/facebookaction.php @@ -2,7 +2,7 @@ /** * StatusNet, the distributed open-source microblogging tool * - * Low-level generator for HTML + * Base Facebook Action * * PHP version 5 * @@ -22,18 +22,17 @@ * @category Faceboook * @package StatusNet * @author Zach Copley - * @copyright 2008 StatusNet, Inc. + * @copyright 2008-2009 StatusNet, Inc. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) -{ +if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -require_once INSTALLDIR.'/lib/facebookutil.php'; -require_once INSTALLDIR.'/lib/noticeform.php'; +require_once INSTALLDIR . '/plugins/Facebook/facebookutil.php'; +require_once INSTALLDIR . '/lib/noticeform.php'; class FacebookAction extends Action { @@ -45,17 +44,6 @@ class FacebookAction extends Action var $app_uri = null; var $app_name = null; - /** - * Constructor - * - * Just wraps the HTMLOutputter constructor. - * - * @param string $output URI to output to, default = stdout - * @param boolean $indent Whether to indent output, default true - * - * @see XMLOutputter::__construct - * @see HTMLOutputter::__construct - */ function __construct($output='php://output', $indent=true, $facebook=null, $flink=null) { parent::__construct($output, $indent); @@ -95,8 +83,8 @@ class FacebookAction extends Action function showStylesheets() { $this->cssLink('css/display.css', 'base'); - $this->cssLink('css/display.css',null,'screen, projection, tv'); - $this->cssLink('css/facebookapp.css', 'base'); + $this->cssLink('css/display.css', null, 'screen, projection, tv'); + $this->cssLink('plugins/Facebook/facebookapp.css'); } function showScripts() @@ -107,10 +95,8 @@ class FacebookAction extends Action /** * Start an Facebook ready HTML document * - * For Facebook we don't want to actually output any headers, - * DTD info, etc. Just Stylesheet and JavaScript links. - * - * If $type isn't specified, will attempt to do content negotiation. + * For Facebook we don't want to actually output any headers, + * DTD info, etc. Just Stylesheet and JavaScript links. * * @param string $type MIME type to use; default is to do negotation. * @@ -139,8 +125,6 @@ class FacebookAction extends Action /** * Show notice form. * - * MAY overload if no notice form needed... or direct message box???? - * * @return nothing */ function showNoticeForm() @@ -157,10 +141,6 @@ class FacebookAction extends Action $this->elementEnd('div'); } - function showAside() - { - } - function showHead($error, $success) { @@ -214,8 +194,6 @@ class FacebookAction extends Action /** * Show header of the page. * - * Calls template methods - * * @return nothing */ function showHeader() @@ -257,7 +235,7 @@ class FacebookAction extends Action $this->element('a', array('href' => common_local_url('register')), _('Register')); $this->text($loginmsg_part2); - $this->elementEnd('p'); + $this->elementEnd('p'); $this->elementEnd('dd'); $this->elementEnd('dl'); @@ -295,7 +273,7 @@ class FacebookAction extends Action $this->elementEnd('ul'); $this->submit('submit', _('Login')); - $this->elementEnd('fieldset'); + $this->elementEnd('fieldset'); $this->elementEnd('form'); $this->elementStart('p'); @@ -313,8 +291,8 @@ class FacebookAction extends Action // Need to include inline CSS for styling the Profile box - $app_props = $this->facebook->api_client->Admin_getAppProperties(array('icon_url')); - $icon_url = $app_props['icon_url']; + $app_props = $this->facebook->api_client->Admin_getAppProperties(array('icon_url')); + $icon_url = $app_props['icon_url']; $style = '