summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--EVENTS.txt84
-rw-r--r--README265
-rw-r--r--actions/all.php14
-rw-r--r--actions/apidirectmessagenew.php2
-rw-r--r--actions/apifavoritecreate.php2
-rw-r--r--actions/apistatusesupdate.php70
-rw-r--r--actions/bookmarklet.php75
-rw-r--r--actions/emailsettings.php2
-rw-r--r--actions/getfile.php145
-rw-r--r--actions/groupmembers.php9
-rw-r--r--actions/invite.php2
-rw-r--r--actions/newmessage.php21
-rw-r--r--actions/newnotice.php207
-rw-r--r--actions/othersettings.php2
-rw-r--r--actions/profilesettings.php10
-rw-r--r--actions/public.php17
-rw-r--r--actions/publicxrds.php81
-rw-r--r--actions/register.php2
-rw-r--r--actions/replies.php24
-rw-r--r--actions/showfavorites.php26
-rw-r--r--actions/showgroup.php14
-rw-r--r--actions/shownotice.php4
-rw-r--r--actions/showstream.php26
-rw-r--r--actions/tag.php16
-rw-r--r--actions/xrds.php106
-rw-r--r--classes/Avatar.php2
-rw-r--r--classes/Location_namespace.php46
-rw-r--r--classes/Notice.php94
-rw-r--r--classes/Profile.php38
-rw-r--r--classes/User.php10
-rw-r--r--classes/statusnet.ini28
-rw-r--r--config.php.sample4
-rw-r--r--db/location_namespace.sql5
-rw-r--r--db/statusnet.sql19
-rw-r--r--doc-src/bookmarklet2
-rw-r--r--extlib/Auth/OpenID.php2
-rw-r--r--extlib/Auth/OpenID/BigMath.php2
-rw-r--r--extlib/Auth/OpenID/Consumer.php3
-rw-r--r--extlib/Auth/OpenID/Message.php5
-rw-r--r--extlib/Auth/Yadis/HTTPFetcher.php2
-rw-r--r--extlib/Auth/Yadis/ParanoidHTTPFetcher.php2
-rw-r--r--extlib/Auth/Yadis/PlainHTTPFetcher.php2
-rw-r--r--extlib/Auth/Yadis/XML.php4
-rw-r--r--extlib/DB/DataObject.php2
-rw-r--r--extlib/DB/DataObject/Cast.php8
-rw-r--r--extlib/DB/DataObject/Error.php8
-rw-r--r--extlib/README58
-rw-r--r--extlib/php-gettext/ChangeLog16
-rw-r--r--extlib/php-gettext/gettext.inc8
-rw-r--r--extlib/php-gettext/gettext.php6
-rw-r--r--htaccess.sample8
-rw-r--r--index.php2
-rw-r--r--install.php4
-rw-r--r--js/util.js671
-rw-r--r--lib/api.php20
-rw-r--r--lib/command.php124
-rw-r--r--lib/commandinterpreter.php11
-rw-r--r--lib/common.php10
-rw-r--r--lib/connectsettingsaction.php49
-rw-r--r--lib/curlclient.php2
-rw-r--r--lib/default.php29
-rw-r--r--lib/httpclient.php2
-rw-r--r--lib/jabber.php6
-rw-r--r--lib/language.php47
-rw-r--r--lib/location.php188
-rw-r--r--lib/mail.php72
-rw-r--r--lib/mediafile.php284
-rw-r--r--lib/messageform.php13
-rw-r--r--lib/noticeform.php13
-rw-r--r--lib/noticelist.php39
-rw-r--r--lib/omb.php2
-rw-r--r--lib/profilelist.php62
-rw-r--r--lib/queuehandler.php77
-rw-r--r--lib/router.php961
-rw-r--r--lib/unqueuemanager.php13
-rw-r--r--lib/util.php30
-rw-r--r--lib/xrdsoutputter.php (renamed from plugins/OpenID/publicxrds.php)76
-rw-r--r--locale/bg/LC_MESSAGES/statusnet.mobin0 -> 97732 bytes
-rw-r--r--locale/bg/LC_MESSAGES/statusnet.po (renamed from locale/bg_BG/LC_MESSAGES/statusnet.po)0
-rw-r--r--locale/bg_BG/LC_MESSAGES/statusnet.mobin89338 -> 0 bytes
-rw-r--r--locale/ca/LC_MESSAGES/statusnet.mo (renamed from locale/ca_ES/LC_MESSAGES/statusnet.mo)bin84543 -> 84543 bytes
-rw-r--r--locale/ca/LC_MESSAGES/statusnet.po (renamed from locale/ca_ES/LC_MESSAGES/statusnet.po)0
-rw-r--r--locale/cs/LC_MESSAGES/statusnet.mobin0 -> 38703 bytes
-rw-r--r--locale/cs/LC_MESSAGES/statusnet.po (renamed from locale/cs_CZ/LC_MESSAGES/statusnet.po)0
-rw-r--r--locale/cs_CZ/LC_MESSAGES/statusnet.mobin28419 -> 0 bytes
-rw-r--r--locale/de/LC_MESSAGES/statusnet.mobin0 -> 84579 bytes
-rw-r--r--locale/de/LC_MESSAGES/statusnet.po (renamed from locale/de_DE/LC_MESSAGES/statusnet.po)0
-rw-r--r--locale/de_DE/LC_MESSAGES/statusnet.mobin59656 -> 0 bytes
-rw-r--r--locale/el/LC_MESSAGES/statusnet.mo (renamed from locale/el_GR/LC_MESSAGES/statusnet.mo)bin27725 -> 27725 bytes
-rw-r--r--locale/el/LC_MESSAGES/statusnet.po (renamed from locale/el_GR/LC_MESSAGES/statusnet.po)0
-rw-r--r--locale/en_GB/LC_MESSAGES/statusnet.mobin77405 -> 78521 bytes
-rw-r--r--locale/es/LC_MESSAGES/statusnet.mobin71978 -> 83472 bytes
-rw-r--r--locale/fr/LC_MESSAGES/statusnet.mobin0 -> 86462 bytes
-rw-r--r--locale/fr/LC_MESSAGES/statusnet.po (renamed from locale/fr_FR/LC_MESSAGES/statusnet.po)0
-rw-r--r--locale/fr_FR/LC_MESSAGES/statusnet.mobin83964 -> 0 bytes
-rw-r--r--locale/ga/LC_MESSAGES/statusnet.mobin0 -> 73858 bytes
-rw-r--r--locale/ga/LC_MESSAGES/statusnet.po4713
-rw-r--r--locale/he/LC_MESSAGES/statusnet.mo (renamed from locale/he_IL/LC_MESSAGES/statusnet.mo)bin42235 -> 42235 bytes
-rw-r--r--locale/he/LC_MESSAGES/statusnet.po (renamed from locale/he_IL/LC_MESSAGES/statusnet.po)0
-rw-r--r--locale/is/LC_MESSAGES/statusnet.mobin0 -> 85990 bytes
-rw-r--r--locale/is/LC_MESSAGES/statusnet.po (renamed from locale/is_IS/LC_MESSAGES/statusnet.po)0
-rw-r--r--locale/it/LC_MESSAGES/statusnet.mobin0 -> 83401 bytes
-rw-r--r--locale/it/LC_MESSAGES/statusnet.po (renamed from locale/it_IT/LC_MESSAGES/statusnet.po)0
-rw-r--r--locale/it_IT/LC_MESSAGES/statusnet.mobin80186 -> 0 bytes
-rw-r--r--locale/ja/LC_MESSAGES/statusnet.mobin0 -> 46648 bytes
-rw-r--r--locale/ja/LC_MESSAGES/statusnet.po (renamed from locale/ja_JP/LC_MESSAGES/statusnet.po)0
-rw-r--r--locale/ja_JP/LC_MESSAGES/statusnet.mobin37594 -> 0 bytes
-rw-r--r--locale/ko/LC_MESSAGES/statusnet.mo (renamed from locale/ko_KR/LC_MESSAGES/statusnet.mo)bin88929 -> 88929 bytes
-rw-r--r--locale/ko/LC_MESSAGES/statusnet.po (renamed from locale/ko_KR/LC_MESSAGES/statusnet.po)0
-rw-r--r--locale/mk/LC_MESSAGES/statusnet.mobin0 -> 50541 bytes
-rw-r--r--locale/mk/LC_MESSAGES/statusnet.po (renamed from locale/mk_MK/LC_MESSAGES/statusnet.po)4
-rw-r--r--locale/mk_MK/LC_MESSAGES/statusnet.mobin37731 -> 0 bytes
-rw-r--r--locale/nb/LC_MESSAGES/statusnet.mo (renamed from locale/nb_NO/LC_MESSAGES/statusnet.mo)bin22230 -> 22230 bytes
-rw-r--r--locale/nb/LC_MESSAGES/statusnet.po (renamed from locale/nb_NO/LC_MESSAGES/statusnet.po)0
-rw-r--r--locale/nl/LC_MESSAGES/statusnet.mobin0 -> 63579 bytes
-rw-r--r--locale/nl/LC_MESSAGES/statusnet.po (renamed from locale/nl_NL/LC_MESSAGES/statusnet.po)0
-rw-r--r--locale/nl_NL/LC_MESSAGES/statusnet.mobin56796 -> 0 bytes
-rw-r--r--locale/nn/LC_MESSAGES/statusnet.mo (renamed from locale/nn_NO/LC_MESSAGES/statusnet.mo)bin80329 -> 80329 bytes
-rw-r--r--locale/nn/LC_MESSAGES/statusnet.po (renamed from locale/nn_NO/LC_MESSAGES/statusnet.po)0
-rw-r--r--locale/pl/LC_MESSAGES/statusnet.mo (renamed from locale/pl_PL/LC_MESSAGES/statusnet.mo)bin124708 -> 124708 bytes
-rw-r--r--locale/pl/LC_MESSAGES/statusnet.po (renamed from locale/pl_PL/LC_MESSAGES/statusnet.po)0
-rw-r--r--locale/pt/LC_MESSAGES/statusnet.mobin22701 -> 25415 bytes
-rw-r--r--locale/pt_BR/LC_MESSAGES/statusnet.mobin76797 -> 83652 bytes
-rw-r--r--locale/ru/LC_MESSAGES/statusnet.mo (renamed from locale/ru_RU/LC_MESSAGES/statusnet.mo)bin109421 -> 109421 bytes
-rw-r--r--locale/ru/LC_MESSAGES/statusnet.po (renamed from locale/ru_RU/LC_MESSAGES/statusnet.po)0
-rw-r--r--locale/sv/LC_MESSAGES/statusnet.mobin0 -> 69744 bytes
-rw-r--r--locale/sv/LC_MESSAGES/statusnet.po (renamed from locale/sv_SE/LC_MESSAGES/statusnet.po)0
-rw-r--r--locale/sv_SE/LC_MESSAGES/statusnet.mobin54299 -> 0 bytes
-rw-r--r--locale/te/LC_MESSAGES/statusnet.mobin0 -> 43726 bytes
-rw-r--r--locale/te/LC_MESSAGES/statusnet.po (renamed from locale/te_IN/LC_MESSAGES/statusnet.po)0
-rw-r--r--locale/te_IN/LC_MESSAGES/statusnet.mobin29270 -> 0 bytes
-rw-r--r--locale/tr/LC_MESSAGES/statusnet.mobin0 -> 37703 bytes
-rw-r--r--locale/tr/LC_MESSAGES/statusnet.po (renamed from locale/tr_TR/LC_MESSAGES/statusnet.po)4
-rw-r--r--locale/tr_TR/LC_MESSAGES/statusnet.mobin27598 -> 0 bytes
-rw-r--r--locale/uk/LC_MESSAGES/statusnet.mo (renamed from locale/uk_UA/LC_MESSAGES/statusnet.mo)bin109628 -> 109628 bytes
-rw-r--r--locale/uk/LC_MESSAGES/statusnet.po (renamed from locale/uk_UA/LC_MESSAGES/statusnet.po)0
-rw-r--r--locale/vi/LC_MESSAGES/statusnet.mobin0 -> 78725 bytes
-rw-r--r--locale/vi/LC_MESSAGES/statusnet.po (renamed from locale/vi_VN/LC_MESSAGES/statusnet.po)0
-rw-r--r--locale/vi_VN/LC_MESSAGES/statusnet.mobin50650 -> 0 bytes
-rw-r--r--locale/zh_TW/LC_MESSAGES/statusnet.mobin11931 -> 17868 bytes
-rw-r--r--locale/zh_TW/LC_MESSAGES/statusnet.po4
-rw-r--r--plugins/FBConnect/README76
-rw-r--r--plugins/Facebook/FBCLoginGroupNav.php (renamed from plugins/FBConnect/FBCLoginGroupNav.php)0
-rw-r--r--plugins/Facebook/FBCSettingsNav.php (renamed from plugins/FBConnect/FBCSettingsNav.php)0
-rw-r--r--plugins/Facebook/FBC_XDReceiver.php (renamed from plugins/FBConnect/FBC_XDReceiver.php)0
-rw-r--r--plugins/Facebook/FBConnect.css (renamed from plugins/FBConnect/FBConnectPlugin.css)0
-rw-r--r--plugins/Facebook/FBConnectAuth.php (renamed from plugins/FBConnect/FBConnectAuth.php)2
-rw-r--r--plugins/Facebook/FBConnectLogin.php (renamed from plugins/FBConnect/FBConnectLogin.php)3
-rw-r--r--plugins/Facebook/FBConnectSettings.php (renamed from plugins/FBConnect/FBConnectSettings.php)0
-rw-r--r--plugins/Facebook/FacebookPlugin.php (renamed from plugins/FBConnect/FBConnectPlugin.php)378
-rw-r--r--plugins/Facebook/README129
-rw-r--r--plugins/Facebook/facebook/facebook.php (renamed from extlib/facebook/facebook.php)0
-rw-r--r--plugins/Facebook/facebook/facebook_desktop.php (renamed from extlib/facebook/facebook_desktop.php)0
-rwxr-xr-xplugins/Facebook/facebook/facebookapi_php5_restlib.php (renamed from extlib/facebook/facebookapi_php5_restlib.php)0
-rw-r--r--plugins/Facebook/facebook/jsonwrapper/JSON/JSON.php (renamed from extlib/facebook/jsonwrapper/JSON/JSON.php)0
-rw-r--r--plugins/Facebook/facebook/jsonwrapper/JSON/LICENSE (renamed from extlib/facebook/jsonwrapper/JSON/LICENSE)0
-rw-r--r--plugins/Facebook/facebook/jsonwrapper/jsonwrapper.php (renamed from extlib/facebook/jsonwrapper/jsonwrapper.php)0
-rw-r--r--plugins/Facebook/facebook/jsonwrapper/jsonwrapper_inner.php (renamed from extlib/facebook/jsonwrapper/jsonwrapper_inner.php)0
-rw-r--r--plugins/Facebook/facebookaction.php (renamed from lib/facebookaction.php)48
-rw-r--r--plugins/Facebook/facebookapp.css (renamed from theme/base/css/facebookapp.css)24
-rw-r--r--plugins/Facebook/facebookhome.php (renamed from actions/facebookhome.php)6
-rw-r--r--plugins/Facebook/facebookinvite.php (renamed from actions/facebookinvite.php)3
-rw-r--r--plugins/Facebook/facebooklogin.php (renamed from actions/facebooklogin.php)34
-rwxr-xr-xplugins/Facebook/facebookqueuehandler.php (renamed from scripts/facebookqueuehandler.php)7
-rw-r--r--plugins/Facebook/facebookremove.php (renamed from actions/facebookremove.php)6
-rw-r--r--plugins/Facebook/facebooksettings.php (renamed from actions/facebooksettings.php)35
-rw-r--r--plugins/Facebook/facebookutil.php (renamed from lib/facebookutil.php)45
-rw-r--r--plugins/Facebook/fbfavicon.ico (renamed from plugins/FBConnect/fbfavicon.ico)bin1150 -> 1150 bytes
-rw-r--r--plugins/GeonamesPlugin.php305
-rw-r--r--plugins/OpenID/OpenIDPlugin.php75
-rw-r--r--plugins/OpenID/User_openid_trustroot.php29
-rw-r--r--plugins/OpenID/finishopenidlogin.php2
-rw-r--r--plugins/OpenID/openid.php10
-rw-r--r--plugins/OpenID/openidserver.php151
-rw-r--r--plugins/OpenID/openidtrust.php142
-rw-r--r--plugins/PubSubHubBub/PubSubHubBubPlugin.php27
-rw-r--r--plugins/Realtime/realtimeupdate.js13
-rw-r--r--plugins/TemplatePlugin.php2
-rw-r--r--plugins/TwitterBridge/README85
-rw-r--r--plugins/TwitterBridge/TwitterBridgePlugin.php187
-rwxr-xr-xplugins/TwitterBridge/daemons/synctwitterfriends.php (renamed from scripts/synctwitterfriends.php)13
-rwxr-xr-xplugins/TwitterBridge/daemons/twitterqueuehandler.php (renamed from scripts/twitterqueuehandler.php)7
-rwxr-xr-xplugins/TwitterBridge/daemons/twitterstatusfetcher.php (renamed from scripts/twitterstatusfetcher.php)14
-rw-r--r--plugins/TwitterBridge/twitter.php (renamed from lib/twitter.php)40
-rw-r--r--plugins/TwitterBridge/twitterauthorization.php (renamed from actions/twitterauthorization.php)25
-rw-r--r--plugins/TwitterBridge/twitterbasicauthclient.php (renamed from lib/twitterbasicauthclient.php)0
-rw-r--r--plugins/TwitterBridge/twitteroauthclient.php (renamed from lib/twitteroauthclient.php)0
-rw-r--r--plugins/TwitterBridge/twittersettings.php (renamed from actions/twittersettings.php)11
-rwxr-xr-xscripts/getvaliddaemons.php10
-rwxr-xr-xscripts/maildaemon.php144
-rw-r--r--tests/LocationTest.php87
-rw-r--r--tests/URLDetectionTest.php6
-rw-r--r--theme/base/css/display.css82
-rw-r--r--theme/base/css/ie.css10
-rw-r--r--theme/default/css/display.css12
-rw-r--r--theme/default/css/ie.css4
-rw-r--r--theme/identica/css/display.css10
-rw-r--r--theme/identica/css/ie.css4
199 files changed, 9354 insertions, 2093 deletions
diff --git a/.gitignore b/.gitignore
index 1cde3a625..217622c84 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 9de2f8bc6..a8a77390f 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 <ul>)
+- $profilelist: ProfileList widget, with $profile, $action, and $out
+
+EndProfileList: when ending a list of profiles (after </ul>)
+- $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 <div>
+- $item: ProfileListItem widget
+
+EndProfileListItemProfileElements: inside the <div>
+- $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 037027d43..952c914fe 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:
-
-- 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 <http://recaptcha.net>.
-- 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 <http://lighttpd.org/> 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
- <http://www.oembed.com>.
-- 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.
+This is a minor feature and bugfix release since version 0.8.1,
+released Aug 26 2009. Notable changes this version:
+
+- 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 <dl> 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 <http://twitter.com/help/request_source>, 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 f1786462e..61cedce74 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 fa6cafbe8..ca1ee70dd 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 a80a6492e..436739770 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 0d71e1512..898a4bd72 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 000000000..0603a7456
--- /dev/null
+++ b/actions/bookmarklet.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Handler for posting new notices
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Bookmarklet
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @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 <csarven@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class 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 6eff06c0d..67b991cdc 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 000000000..ecda34c0f
--- /dev/null
+++ b/actions/getfile.php
@@ -0,0 +1,145 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Returns a given file attachment, allowing private sites to only allow
+ * access to file attachments after login.
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Personal
+ * @package StatusNet
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @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 <jeffery.to@gmail.com>
+ * @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 dcbdd3759..b326a0df7 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 788130c58..3015202e9 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 a0b17fc18..37fca1ca2 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 9ee031f93..fbd7ab6bc 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;
-
- case UPLOAD_ERR_OK:
- $mimetype = $this->getUploadedFileType();
- if (!$this->isRespectsQuota($user)) {
- die('clientError() should trigger an exception before reaching here.');
- }
- break;
-
- 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.'));
+ $upload = null;
+ $upload = MediaFile::fromUpload('attach');
- case UPLOAD_ERR_PARTIAL:
- $this->clientError(_('The uploaded file was only partially uploaded.'));
+ if (isset($upload)) {
- 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 011b4fc83..d32a2d651 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 5445d9bb2..0a0cc5997 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 73fad182a..982dfde15 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 <head> 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 000000000..5fd4eead7
--- /dev/null
+++ b/actions/publicxrds.php
@@ -0,0 +1,81 @@
+<?php
+
+/**
+ * Public XRDS for OpenID
+ *
+ * PHP version 5
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
+ * @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 <http://www.gnu.org/licenses/>.
+ */
+
+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 <evan@status.net>
+ * @author Robin Millette <millette@status.net>
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @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 100ab7424..a6c1a903a 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 6003ad30b..a13b5a227 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 b96d2af37..b12fcdd9a 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 bfe45ddad..a4af29391 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 41408c23c..5d16fdad9 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 b3a9b1f05..4f4806037 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 f0ab30308..3a88c1229 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 8ba89fec0..8f09557d1 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,60 +61,87 @@ class XrdsAction extends Action
{
return true;
}
-
- /**
- * Class handler.
- *
- * @param array $args query arguments
- *
- * @return void
- */
- function handle($args)
+
+ function prepare($args)
{
- parent::handle($args);
+ parent::prepare($args);
$nickname = $this->trimmed('nickname');
- $user = User::staticGet('nickname', $nickname);
- if (!$user) {
+ $this->user = User::staticGet('nickname', $nickname);
+ if (!$this->user) {
$this->clientError(_('No such user.'));
return;
}
- $this->showXrds($user);
+ return true;
}
/**
- * Show XRDS for a user.
+ * Class handler.
*
- * @param class $user XRDS for this user.
+ * @param array $args query arguments
*
* @return void
*/
- function showXrds($user)
+ function handle($args)
{
- $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);
- }
-}
+ parent::handle($args);
+ $xrdsOutputter = new XRDSOutputter();
+ $xrdsOutputter->startXRDS();
-class Laconica_XRDS_Mapper implements OMB_XRDS_Mapper
-{
- protected $urls;
+ Event::handle('StartUserXRDS', array($this,&$xrdsOutputter));
- 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');
- }
+ //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 getURL($action)
- {
- return common_local_url($this->urls[$action]);
+ Event::handle('EndUserXRDS', array($this,&$xrdsOutputter));
+
+ $xrdsOutputter->endXRDS();
+
}
}
?>
diff --git a/classes/Avatar.php b/classes/Avatar.php
index 5e8b315fe..64f105179 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 000000000..5ab95d9ef
--- /dev/null
+++ b/classes/Location_namespace.php
@@ -0,0 +1,46 @@
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+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 cd3906ca1..a9dbaa461 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; $i<count($names); $i++) {
$nickname = $names[$i];
$recipient = common_relative_profile($sender, $nickname, $this->created);
- 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 4a069ee84..7c1e9db33 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 0a70c9801..3fa9cc152 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 453981cd6..623790b10 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 997c9d6b0..9fccb84f3 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 000000000..59b2ce67c
--- /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 dfcddb643..1524d8395 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 e5ded7702..6ce23bd0b 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.
-<a href="javascript:var%20d=document,w=window,e=w.getSelection,k=d.getSelection,x=d.selection,s=(e?e():(k)?k():(x?x.createRange().text:0)),f='http://%%site.server%%/%%site.path%%/index.php?action=newnotice',l=d.location,e=encodeURIComponent,g=f+'&amp;status_textarea=%22'+((e(s))?e(s):e(document.title))+'%22 from '+l.href;function%20a(){if(!w.open(g,'t','toolbar=0,resizable=0,scrollbars=1,status=1,width=800,height=570')){l.href=g;}}a();void(0);">Post to %%site.name%%</a>
+<a href="javascript:(function(){var%20d=document,w=window,e=w.getSelection,k=d.getSelection,x=d.selection,s=(e?e():(k)?k():(x?x.createRange().text:0)),f='http://%%site.server%%/%%site.path%%/index.php?action=bookmarklet',l=d.location,e=encodeURIComponent,g=f+'&status_textarea=%22'+((e(s))?e(s):e(document.title))+'%22%20%E2%80%94%20'+l.href;function%20a(){if(!w.open(g,'t','toolbar=0,resizable=0,scrollbars=1,status=1,width=450,height=200')){l.href=g;}}a();})()">Post to %%site.name%%</a>
diff --git a/extlib/Auth/OpenID.php b/extlib/Auth/OpenID.php
index 6556b5b01..db6164256 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 b5fc627a0..45104947d 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 a72684c6b..500890b65 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 fd23e67a3..5ab115a86 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 a1825403d..963b9a49a 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 8975d7f89..6a418260e 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 8882e3cef..3e0ca2bb0 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 7232d6cbd..81b2ce221 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 8e226b8fa..60ff1441b 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 095d2a4d2..2049beb58 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 <alan@akbkhome.com>
* @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 382115453..cdb863d83 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 <alan@akbkhome.com>
* @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 000000000..cfc2f9c8c
--- /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 5e0949dfd..ab77d8081 100644
--- a/extlib/php-gettext/ChangeLog
+++ b/extlib/php-gettext/ChangeLog
@@ -1,3 +1,19 @@
+2006-02-28 Danilo Šegan <danilo@gnome.org>
+
+ * gettext.php: Added some comments about these workarounds for
+ different PHP versions and architectures.
+
+2006-02-28 Danilo Šegan <danilo@gnome.org>
+
+ 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 <danilo@gnome.org>
+
+ * gettext.inc (_bindtextdomain): Use php_uname to detect Windows.
+
2006-02-07 Danilo Šegan <danilo@gnome.org>
* examples/pigs_dropin.php: comment-out bind_textdomain_codeset
diff --git a/extlib/php-gettext/gettext.inc b/extlib/php-gettext/gettext.inc
index eb94b256a..7c95e40ec 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 ad94a987b..cd080444c 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 37eb8e01e..91ae9da9b 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 644812bd5..3acdba375 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 319c261e4..6bfc4c2e2 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 0a943512f..663ec8986 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 <http://www.gnu.org/licenses/>.
+ *
+ * @category UI interaction
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
*/
$(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);
+ SN.U.NoticeAttachments();
+});
- if($('body')[0].id != 'conversation') {
- $("#notice_data-text").focus();
- }
- }
- // XXX: refactor this code
+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]
+ },
- 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);
- }
- };
+ 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'
+ }
+ },
- 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);
- }
- };
+ 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);
+ }
- 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);
- }
- };
+ $('#'+form_id+' #'+SN.C.S.NoticeDataText).bind('keydown', function(e) {
+ SN.U.SubmitOnReturn(e, form);
+ });
- 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);
- }
- };
+ if($('body')[0].id != 'conversation') {
+ $('#'+form_id+' textarea').focus();
+ }
- function addAjaxHidden() {
- var ajax = document.createElement('input');
- ajax.setAttribute('type', 'hidden');
- ajax.setAttribute('name', 'ajax');
- ajax.setAttribute('value', 1);
- this.appendChild(ajax);
- }
+ SN.U.FormNoticeXHR(form);
+ },
- $("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);
+ 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;
+ },
- $("#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);
+ Counter: function(form) {
+ SN.C.I.FormNoticeCurrent = form;
+ form_id = form.attr('id');
+ if (typeof(maxLength) == "undefined") {
+ maxLength = SN.C.I.MaxLength;
+ }
- 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");
- }
- };
+ if (maxLength <= 0) {
+ return;
+ }
- 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");
- }
- };
+ var remaining = maxLength - $('#'+form_id+' #'+SN.C.S.NoticeDataText).val().length;
+ var counter = $('#'+form_id+' #'+SN.C.S.NoticeTextCount);
- $(".form_user_subscribe").ajaxForm(Subscribe);
- $(".form_user_unsubscribe").ajaxForm(UnSubscribe);
- $(".form_user_subscribe").each(addAjaxHidden);
- $(".form_user_unsubscribe").each(addAjaxHidden);
+ 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);
+ }
+ }
+ }
+ },
- 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('<ul class="notices"></ul>');
- }
- $($(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();
-});
+ 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);
+ },
-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());
+ 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;
});
- });
- }
-}
-
-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('<button>&#215;</button>');
- $('#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;
- });
+ FormNoticeXHR: function(form) {
+ form_id = form.attr('id');
+ form.append('<input type="hidden" name="ajax" value="1"/>');
+ 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();
+ }
- 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 ($('#'+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('<ul class="notices"></ul>');
+ }
+ $($(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);
+ }
+ });
+ },
- 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);
+ 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;
});
- }, 500);
+ });
}
- else {
- anchor.children('img').show();
+ },
+
+ 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;
},
- function() {
- clearTimeout(t);
- $("a.thumbnail").children('img').hide();
- $(this).closest(".entry-title").removeClass('ov');
- }
- );
-}
-function NoticeDataAttach() {
- NDA = $('#notice_data-attach');
- NDA.change(function() {
- S = '<div id="notice_data-attach_selected" class="success"><code>'+$(this).val()+'</code> <button>&#215;</button></div>';
- 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('');
- });
- });
+ 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('<button>&#215;</button>');
+ $('#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 = '<div id="'+SN.C.S.NoticeDataAttachSelected+'" class="'+SN.C.S.Success+'"><code>'+$(this).val()+'</code> <button>&#215;</button></div>';
+ 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('<button>&#215;</button>');
+ $('.entity_send-a-message button').click(function(){
+ NDMF.hide();
+ return false;
+ });
+ });
+ }
+ else {
+ NDMF.show();
+ $('.entity_send-a-message textarea').focus();
+ }
+ return false;
+ });
+ }
+ }
}
diff --git a/lib/api.php b/lib/api.php
index 7a63a4a78..9bd2083de 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 11d40b8e1..9efa40696 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 <nickname> - get last notice from user\n".
"whois <nickname> - get profile info on user\n".
"fav <nickname> - add user's last notice as a 'fave'\n".
+ "fav #<notice_id> - add notice with the given id as a 'fave'\n".
+ "reply #<notice_id> - reply to notice with a given id\n".
+ "reply <nickname> - reply to the last notice from user\n".
"join <group> - join group\n".
"drop <group> - leave group\n".
"stats - get your stats\n".
@@ -507,7 +607,7 @@ class HelpCommand extends Command
"last <nickname> - same as 'get'\n".
"on <nickname> - not yet implemented.\n".
"off <nickname> - not yet implemented.\n".
- "nudge <nickname> - not yet implemented.\n".
+ "nudge <nickname> - remind a user to update.\n".
"invite <phone number> - not yet implemented.\n".
"track <word> - not yet implemented.\n".
"untrack <word> - not yet implemented.\n".
diff --git a/lib/commandinterpreter.php b/lib/commandinterpreter.php
index 60fc4c3c4..b921a17cc 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 ce33c871b..2c2f6869e 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 '<p>'. _('No configuation file found. ') .'</p>';
+ echo '<p>'. _('I looked for configuration files in the following places: ') .'<br/> '. implode($_config_files, '<br/>');
+ echo '<p>'. _('You may wish to run the installer to fix this.') .'</p>';
+ echo '<a href="install.php">'. _('Go to the installer.') .'</a>';
+ 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 2095a7ceb..e5fb8727b 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 36fc7d157..c307c2984 100644
--- a/lib/curlclient.php
+++ b/lib/curlclient.php
@@ -1,4 +1,4 @@
-n<?php
+<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
diff --git a/lib/default.php b/lib/default.php
index 9f3d4b1f9..7ec8558b0 100644
--- a/lib/default.php
+++ b/lib/default.php
@@ -84,7 +84,8 @@ $default =
'image' => '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 c8c8ae5b2..f16e31e10 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 3dcdce5db..73f2ec660 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 561a4ddb8..7dcb808c9 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 000000000..bbfc15a36
--- /dev/null
+++ b/lib/location.php
@@ -0,0 +1,188 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Class for locations
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Location
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !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 <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class 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 5bf4d7425..5218059e9 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 000000000..d4d184dd0
--- /dev/null
+++ b/lib/mediafile.php
@@ -0,0 +1,284 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Abstraction for media files in general
+ *
+ * TODO: combine with ImageFile?
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Media
+ * @package StatusNet
+ * @author Robin Millette <robin@millette.info>
+ * @author Zach Copley <zach@status.net>
+ * @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 e25ebfa08..b034be312 100644
--- a/lib/messageform.php
+++ b/lib/messageform.php
@@ -80,11 +80,22 @@ 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 9864d15eb..1be011c18 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 6c296f82a..8b3015cc3 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');
@@ -370,6 +371,44 @@ class NoticeListItem extends Widget
}
/**
+ * 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
*
* Either the name (and link) of the API client that posted the notice,
diff --git a/lib/omb.php b/lib/omb.php
index 0566701ff..cd6d6e1b2 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 331430b3e..5cc211e36 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 8c65a97c6..cd43b1e09 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 b9a45d867..64853e419 100644
--- a/lib/router.php
+++ b/lib/router.php
@@ -71,574 +71,573 @@ 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/sup/:seconds', array('action' => 'sup'),
- array('seconds' => '[0-9]+'));
+ $m->connect('main/oembed',
+ array('action' => 'oembed'));
- $m->connect('main/tagother/:id', array('action' => 'tagother'));
+ $m->connect('main/xrds',
+ array('action' => 'publicxrds'));
- $m->connect('main/oembed',
- array('action' => 'oembed'));
+ // these take a code
- // these take a code
+ foreach (array('register', 'confirmaddress', 'recoverpassword') as $c) {
+ $m->connect('main/'.$c.'/:code', array('action' => $c));
+ }
- foreach (array('register', 'confirmaddress', 'recoverpassword') as $c) {
- $m->connect('main/'.$c.'/:code', array('action' => $c));
- }
+ // exceptional
- // exceptional
+ $m->connect('main/remote', array('action' => 'remotesubscribe'));
+ $m->connect('main/remote?nickname=:nickname', array('action' => 'remotesubscribe'), array('nickname' => '[A-Za-z0-9_-]+'));
- $m->connect('main/remote', array('action' => 'remotesubscribe'));
- $m->connect('main/remote?nickname=:nickname', array('action' => 'remotesubscribe'), array('nickname' => '[A-Za-z0-9_-]+'));
+ foreach (Router::$bare as $action) {
+ $m->connect('index.php?action=' . $action, array('action' => $action));
+ }
- foreach (Router::$bare as $action) {
- $m->connect('index.php?action=' . $action, array('action' => $action));
- }
+ // settings
- // settings
+ foreach (array('profile', 'avatar', 'password', 'im',
+ 'email', 'sms', 'userdesign', 'other') as $s) {
+ $m->connect('settings/'.$s, array('action' => $s.'settings'));
+ }
- foreach (array('profile', 'avatar', 'password', 'im',
- 'email', 'sms', 'twitter', 'userdesign', 'other') as $s) {
- $m->connect('settings/'.$s, array('action' => $s.'settings'));
- }
+ // search
- // 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'),
+ array('q' => '.+'));
+ }
- 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/ajax',
- array('action' => 'attachment_ajax'),
- 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/: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]+'));
-
- // conversation
-
- $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('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('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'));
-
- // groups
-
- $m->connect('group/new', array('action' => 'newgroup'));
-
- foreach (array('edit', 'join', 'leave') as $v) {
- $m->connect('group/:nickname/'.$v,
- array('action' => $v.'group'),
+ $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/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/: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('bookmarklet/new', array('action' => 'bookmarklet'));
+
+ // conversation
+
+ $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('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('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'));
+
+ // groups
+
+ $m->connect('group/new', array('action' => 'newgroup'));
+
+ 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('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/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/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('group/:nickname/makeadmin',
+ array('action' => 'makeadmin'),
+ array('nickname' => '[a-zA-Z0-9]+'));
- $m->connect('api/statuses/friends/:id.:format',
- array('action' => 'ApiUserFriends',
- 'id' => '[a-zA-Z0-9]+',
- 'format' => '(xml|json)'));
+ $m->connect('group/:id/id',
+ array('action' => 'groupbyid'),
+ array('id' => '[0-9]+'));
- $m->connect('api/statuses/followers.:format',
- array('action' => 'ApiUserFollowers',
- 'format' => '(xml|json)'));
+ $m->connect('group/:nickname',
+ array('action' => 'showgroup'),
+ array('nickname' => '[a-zA-Z0-9]+'));
- $m->connect('api/statuses/followers/:id.:format',
- array('action' => 'ApiUserFollowers',
- 'id' => '[a-zA-Z0-9]+',
- 'format' => '(xml|json)'));
+ $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/show.:format',
- array('action' => 'ApiStatusesShow',
- 'format' => '(xml|json)'));
+ $m->connect('api/statuses/user_timeline.:format',
+ array('action' => 'ApiTimelineUser',
+ 'format' => '(xml|json|rss|atom)'));
- $m->connect('api/statuses/show/:id.:format',
- array('action' => 'ApiStatusesShow',
- 'id' => '[0-9]+',
- 'format' => '(xml|json)'));
+ $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/update.:format',
- array('action' => 'ApiStatusesUpdate',
- 'format' => '(xml|json)'));
+ $m->connect('api/statuses/followers.:format',
+ array('action' => 'ApiUserFollowers',
+ 'format' => '(xml|json)'));
- $m->connect('api/statuses/destroy.:format',
- array('action' => 'ApiStatusesDestroy',
- '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/destroy/:id.:format',
- array('action' => 'ApiStatusesDestroy',
- 'id' => '[0-9]+',
- 'format' => '(xml|json)'));
+ $m->connect('api/statuses/show.:format',
+ array('action' => 'ApiStatusesShow',
+ 'format' => '(xml|json)'));
- // users
+ $m->connect('api/statuses/show/:id.:format',
+ array('action' => 'ApiStatusesShow',
+ 'id' => '[0-9]+',
+ '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/update.:format',
+ array('action' => 'ApiStatusesUpdate',
+ 'format' => '(xml|json)'));
- $m->connect('api/users/:method',
- array('action' => 'api',
- 'apiaction' => 'users'),
- array('method' => 'show(\.(xml|json))?'));
+ $m->connect('api/statuses/destroy.:format',
+ array('action' => 'ApiStatusesDestroy',
+ 'format' => '(xml|json)'));
- // direct messages
+ $m->connect('api/statuses/destroy/:id.:format',
+ array('action' => 'ApiStatusesDestroy',
+ 'id' => '[0-9]+',
+ 'format' => '(xml|json)'));
+ // users
- $m->connect('api/direct_messages.:format',
- array('action' => 'ApiDirectMessage',
- 'format' => '(xml|json|rss|atom)'));
+ $m->connect('api/users/show/:id.:format',
+ array('action' => 'ApiUserShow',
+ 'id' => '[a-zA-Z0-9]+',
+ 'format' => '(xml|json)'));
- $m->connect('api/direct_messages/sent.:format',
- array('action' => 'ApiDirectMessage',
- 'format' => '(xml|json|rss|atom)',
- 'sent' => true));
+ $m->connect('api/users/:method',
+ array('action' => 'api',
+ 'apiaction' => 'users'),
+ array('method' => 'show(\.(xml|json))?'));
- $m->connect('api/direct_messages/new.:format',
- array('action' => 'ApiDirectMessageNew',
- 'format' => '(xml|json)'));
+ // direct messages
- // 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
-
- $m->connect('api/laconica/version.:format',
- array('action' => 'ApiStatusnetVersion',
- 'format' => '(xml|json)'));
-
- $m->connect('api/laconica/config.:format',
- array('action' => 'ApiStatusnetConfig',
- 'format' => '(xml|json)'));
+ // statusnet
- // Groups and tags are newer than 0.8.1 so no backward-compatibility
- // necessary
+ $m->connect('api/statusnet/version.:format',
+ array('action' => 'ApiStatusnetVersion',
+ 'format' => '(xml|json)'));
- // Groups
- //'list' has to be handled differently, as php will not allow a method to be named 'list'
+ $m->connect('api/statusnet/config.:format',
+ array('action' => 'ApiStatusnetConfig',
+ 'format' => '(xml|json)'));
- $m->connect('api/statusnet/groups/timeline/:id.:format',
- array('action' => 'ApiTimelineGroup',
- 'id' => '[a-zA-Z0-9]+',
- 'format' => '(xmljson|rss|atom)'));
+ // For older methods, we provide "laconica" base action
- $m->connect('api/statusnet/groups/show.:format',
- array('action' => 'ApiGroupShow',
- 'format' => '(xml|json)'));
+ $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/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),
- array('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]+'));
- 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/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}'));
+ $m->connect(':nickname',
+ array('action' => 'showstream'),
+ array('nickname' => '[a-zA-Z0-9]{1,64}'));
- Event::handle('RouterInitialized', array($m));
+ Event::handle('RouterInitialized', array($m));
+ }
return $m;
}
diff --git a/lib/unqueuemanager.php b/lib/unqueuemanager.php
index 6cfe5bcbd..72dbc4eed 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 be10647fc..d159c583e 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
index 1b2b359ca..4b77ed5a3 100644
--- a/plugins/OpenID/publicxrds.php
+++ b/lib/xrdsoutputter.php
@@ -1,21 +1,12 @@
<?php
-
/**
- * Public XRDS for OpenID
- *
- * PHP version 5
+ * StatusNet, the distributed open-source microblogging tool
*
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @author Robin Millette <millette@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
+ * Low-level generator for HTML
*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
+ * PHP version 5
*
- * 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 <http://www.gnu.org/licenses/>.
+ *
+ * @category Output
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @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 <evan@status.net>
- * @author Robin Millette <millette@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*
- * @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 000000000..335fe0b92
--- /dev/null
+++ b/locale/bg/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/bg_BG/LC_MESSAGES/statusnet.po b/locale/bg/LC_MESSAGES/statusnet.po
index c0bc8379f..c0bc8379f 100644
--- a/locale/bg_BG/LC_MESSAGES/statusnet.po
+++ b/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 8cfa1523d..000000000
--- a/locale/bg_BG/LC_MESSAGES/statusnet.mo
+++ /dev/null
Binary files differ
diff --git a/locale/ca_ES/LC_MESSAGES/statusnet.mo b/locale/ca/LC_MESSAGES/statusnet.mo
index aadf38da9..aadf38da9 100644
--- a/locale/ca_ES/LC_MESSAGES/statusnet.mo
+++ b/locale/ca/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/ca_ES/LC_MESSAGES/statusnet.po b/locale/ca/LC_MESSAGES/statusnet.po
index 44944c8ba..44944c8ba 100644
--- a/locale/ca_ES/LC_MESSAGES/statusnet.po
+++ b/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 000000000..4618fd73d
--- /dev/null
+++ b/locale/cs/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/cs_CZ/LC_MESSAGES/statusnet.po b/locale/cs/LC_MESSAGES/statusnet.po
index aee74f1af..aee74f1af 100644
--- a/locale/cs_CZ/LC_MESSAGES/statusnet.po
+++ b/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 e126daaf0..000000000
--- a/locale/cs_CZ/LC_MESSAGES/statusnet.mo
+++ /dev/null
Binary files differ
diff --git a/locale/de/LC_MESSAGES/statusnet.mo b/locale/de/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..335b26715
--- /dev/null
+++ b/locale/de/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/de_DE/LC_MESSAGES/statusnet.po b/locale/de/LC_MESSAGES/statusnet.po
index ed0252879..ed0252879 100644
--- a/locale/de_DE/LC_MESSAGES/statusnet.po
+++ b/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 fe6072c1b..000000000
--- a/locale/de_DE/LC_MESSAGES/statusnet.mo
+++ /dev/null
Binary files differ
diff --git a/locale/el_GR/LC_MESSAGES/statusnet.mo b/locale/el/LC_MESSAGES/statusnet.mo
index 184639963..184639963 100644
--- a/locale/el_GR/LC_MESSAGES/statusnet.mo
+++ b/locale/el/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/el_GR/LC_MESSAGES/statusnet.po b/locale/el/LC_MESSAGES/statusnet.po
index 4a54996a8..4a54996a8 100644
--- a/locale/el_GR/LC_MESSAGES/statusnet.po
+++ b/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 11eacc9ac..4eeac7304 100644
--- a/locale/en_GB/LC_MESSAGES/statusnet.mo
+++ b/locale/en_GB/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/es/LC_MESSAGES/statusnet.mo b/locale/es/LC_MESSAGES/statusnet.mo
index ab03d12e0..05eabcc75 100644
--- a/locale/es/LC_MESSAGES/statusnet.mo
+++ b/locale/es/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/fr/LC_MESSAGES/statusnet.mo b/locale/fr/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..1d3509af1
--- /dev/null
+++ b/locale/fr/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/fr_FR/LC_MESSAGES/statusnet.po b/locale/fr/LC_MESSAGES/statusnet.po
index 23365960b..23365960b 100644
--- a/locale/fr_FR/LC_MESSAGES/statusnet.po
+++ b/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 f26b8708d..000000000
--- a/locale/fr_FR/LC_MESSAGES/statusnet.mo
+++ /dev/null
Binary files differ
diff --git a/locale/ga/LC_MESSAGES/statusnet.mo b/locale/ga/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..c13acd1a8
--- /dev/null
+++ b/locale/ga/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/ga/LC_MESSAGES/statusnet.po b/locale/ga/LC_MESSAGES/statusnet.po
new file mode 100644
index 000000000..3815e4853
--- /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 <fran.dieguez@glug.es>, 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 <eu@martinvazquez.net>\n"
+"Language-Team: Galician <en@li.org>\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 <nickname> - subscribe to user\n"
+"leave <nickname> - unsubscribe from user\n"
+"d <nickname> <text> - direct message to user\n"
+"get <nickname> - get last notice from user\n"
+"whois <nickname> - get profile info on user\n"
+"fav <nickname> - 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 <nickname> - same as 'follow'\n"
+"unsub <nickname> - same as 'leave'\n"
+"last <nickname> - same as 'get'\n"
+"on <nickname> - not yet implemented.\n"
+"off <nickname> - not yet implemented.\n"
+"nudge <nickname> - not yet implemented.\n"
+"invite <phone number> - not yet implemented.\n"
+"track <word> - not yet implemented.\n"
+"untrack <word> - 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 <nickname> - suscribirse ao usuario\n"
+"leave <nickname> - de-suscribirse do usuario\n"
+"d <nickname> <text> - mensaxe directa ao usuario\n"
+"get <nickname> - lelo último chío do usuario\n"
+"whois <nickname> - amosar informacion do usuario\n"
+"fav <nickname> - 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 <nickname> - o mesmo que 'follow'\n"
+"unsub <nickname> - o mesmo que 'leave'\n"
+"last <nickname> - o mesmo que 'get'\n"
+"on <nickname> - non implementado por agora.\n"
+"off <nickname> - non implementado por agora.\n"
+"nudge <nickname> - non implementado por agora.\n"
+"invite <phone number> - non implementado por agora.\n"
+"track <word> - non implementado por agora.\n"
+"untrack <word> - 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
index 609918d92..609918d92 100644
--- a/locale/he_IL/LC_MESSAGES/statusnet.mo
+++ b/locale/he/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/he_IL/LC_MESSAGES/statusnet.po b/locale/he/LC_MESSAGES/statusnet.po
index 97a44a030..97a44a030 100644
--- a/locale/he_IL/LC_MESSAGES/statusnet.po
+++ b/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 000000000..36039f4aa
--- /dev/null
+++ b/locale/is/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/is_IS/LC_MESSAGES/statusnet.po b/locale/is/LC_MESSAGES/statusnet.po
index 524b85a0d..524b85a0d 100644
--- a/locale/is_IS/LC_MESSAGES/statusnet.po
+++ b/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 000000000..00ab59804
--- /dev/null
+++ b/locale/it/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/it_IT/LC_MESSAGES/statusnet.po b/locale/it/LC_MESSAGES/statusnet.po
index 1a59adf85..1a59adf85 100644
--- a/locale/it_IT/LC_MESSAGES/statusnet.po
+++ b/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 95764f1e2..000000000
--- a/locale/it_IT/LC_MESSAGES/statusnet.mo
+++ /dev/null
Binary files differ
diff --git a/locale/ja/LC_MESSAGES/statusnet.mo b/locale/ja/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..7026035cc
--- /dev/null
+++ b/locale/ja/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/ja_JP/LC_MESSAGES/statusnet.po b/locale/ja/LC_MESSAGES/statusnet.po
index bb7d777ba..bb7d777ba 100644
--- a/locale/ja_JP/LC_MESSAGES/statusnet.po
+++ b/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 86efaaf5d..000000000
--- a/locale/ja_JP/LC_MESSAGES/statusnet.mo
+++ /dev/null
Binary files differ
diff --git a/locale/ko_KR/LC_MESSAGES/statusnet.mo b/locale/ko/LC_MESSAGES/statusnet.mo
index 2b177ff86..2b177ff86 100644
--- a/locale/ko_KR/LC_MESSAGES/statusnet.mo
+++ b/locale/ko/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/ko_KR/LC_MESSAGES/statusnet.po b/locale/ko/LC_MESSAGES/statusnet.po
index 7bbdcdcf2..7bbdcdcf2 100644
--- a/locale/ko_KR/LC_MESSAGES/statusnet.po
+++ b/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 000000000..5dec309dd
--- /dev/null
+++ b/locale/mk/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/mk_MK/LC_MESSAGES/statusnet.po b/locale/mk/LC_MESSAGES/statusnet.po
index d4c4eb235..0e91f0522 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 0ac378c79..000000000
--- a/locale/mk_MK/LC_MESSAGES/statusnet.mo
+++ /dev/null
Binary files differ
diff --git a/locale/nb_NO/LC_MESSAGES/statusnet.mo b/locale/nb/LC_MESSAGES/statusnet.mo
index ee3bad415..ee3bad415 100644
--- a/locale/nb_NO/LC_MESSAGES/statusnet.mo
+++ b/locale/nb/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/nb_NO/LC_MESSAGES/statusnet.po b/locale/nb/LC_MESSAGES/statusnet.po
index 5e2d6613c..5e2d6613c 100644
--- a/locale/nb_NO/LC_MESSAGES/statusnet.po
+++ b/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 000000000..122a49285
--- /dev/null
+++ b/locale/nl/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/nl_NL/LC_MESSAGES/statusnet.po b/locale/nl/LC_MESSAGES/statusnet.po
index 6cc0a52c4..6cc0a52c4 100644
--- a/locale/nl_NL/LC_MESSAGES/statusnet.po
+++ b/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 16ce96d0d..000000000
--- a/locale/nl_NL/LC_MESSAGES/statusnet.mo
+++ /dev/null
Binary files differ
diff --git a/locale/nn_NO/LC_MESSAGES/statusnet.mo b/locale/nn/LC_MESSAGES/statusnet.mo
index 7dbde4019..7dbde4019 100644
--- a/locale/nn_NO/LC_MESSAGES/statusnet.mo
+++ b/locale/nn/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/nn_NO/LC_MESSAGES/statusnet.po b/locale/nn/LC_MESSAGES/statusnet.po
index 4da276adb..4da276adb 100644
--- a/locale/nn_NO/LC_MESSAGES/statusnet.po
+++ b/locale/nn/LC_MESSAGES/statusnet.po
diff --git a/locale/pl_PL/LC_MESSAGES/statusnet.mo b/locale/pl/LC_MESSAGES/statusnet.mo
index dba116252..dba116252 100644
--- a/locale/pl_PL/LC_MESSAGES/statusnet.mo
+++ b/locale/pl/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/pl_PL/LC_MESSAGES/statusnet.po b/locale/pl/LC_MESSAGES/statusnet.po
index 54c52e949..54c52e949 100644
--- a/locale/pl_PL/LC_MESSAGES/statusnet.po
+++ b/locale/pl/LC_MESSAGES/statusnet.po
diff --git a/locale/pt/LC_MESSAGES/statusnet.mo b/locale/pt/LC_MESSAGES/statusnet.mo
index 35d7053be..e6168a340 100644
--- a/locale/pt/LC_MESSAGES/statusnet.mo
+++ b/locale/pt/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/pt_BR/LC_MESSAGES/statusnet.mo b/locale/pt_BR/LC_MESSAGES/statusnet.mo
index 9db1638b0..a5a6f2725 100644
--- a/locale/pt_BR/LC_MESSAGES/statusnet.mo
+++ b/locale/pt_BR/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/ru_RU/LC_MESSAGES/statusnet.mo b/locale/ru/LC_MESSAGES/statusnet.mo
index c4066c65e..c4066c65e 100644
--- a/locale/ru_RU/LC_MESSAGES/statusnet.mo
+++ b/locale/ru/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/ru_RU/LC_MESSAGES/statusnet.po b/locale/ru/LC_MESSAGES/statusnet.po
index 8a553a37f..8a553a37f 100644
--- a/locale/ru_RU/LC_MESSAGES/statusnet.po
+++ b/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 000000000..2cb0397ec
--- /dev/null
+++ b/locale/sv/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/sv_SE/LC_MESSAGES/statusnet.po b/locale/sv/LC_MESSAGES/statusnet.po
index d0a5001da..d0a5001da 100644
--- a/locale/sv_SE/LC_MESSAGES/statusnet.po
+++ b/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 ce3c6c1f5..000000000
--- a/locale/sv_SE/LC_MESSAGES/statusnet.mo
+++ /dev/null
Binary files differ
diff --git a/locale/te/LC_MESSAGES/statusnet.mo b/locale/te/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..5cfa0c3fb
--- /dev/null
+++ b/locale/te/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/te_IN/LC_MESSAGES/statusnet.po b/locale/te/LC_MESSAGES/statusnet.po
index 4576f3613..4576f3613 100644
--- a/locale/te_IN/LC_MESSAGES/statusnet.po
+++ b/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 bb837b977..000000000
--- a/locale/te_IN/LC_MESSAGES/statusnet.mo
+++ /dev/null
Binary files differ
diff --git a/locale/tr/LC_MESSAGES/statusnet.mo b/locale/tr/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..d49c7093d
--- /dev/null
+++ b/locale/tr/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/tr_TR/LC_MESSAGES/statusnet.po b/locale/tr/LC_MESSAGES/statusnet.po
index e67fbf33c..4dbc221d1 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 e0ef80560..000000000
--- a/locale/tr_TR/LC_MESSAGES/statusnet.mo
+++ /dev/null
Binary files differ
diff --git a/locale/uk_UA/LC_MESSAGES/statusnet.mo b/locale/uk/LC_MESSAGES/statusnet.mo
index e08dc4e9c..e08dc4e9c 100644
--- a/locale/uk_UA/LC_MESSAGES/statusnet.mo
+++ b/locale/uk/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/uk_UA/LC_MESSAGES/statusnet.po b/locale/uk/LC_MESSAGES/statusnet.po
index 55cea21c3..55cea21c3 100644
--- a/locale/uk_UA/LC_MESSAGES/statusnet.po
+++ b/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 000000000..b2f4dd370
--- /dev/null
+++ b/locale/vi/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/vi_VN/LC_MESSAGES/statusnet.po b/locale/vi/LC_MESSAGES/statusnet.po
index af34d5210..af34d5210 100644
--- a/locale/vi_VN/LC_MESSAGES/statusnet.po
+++ b/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 65add28b4..000000000
--- a/locale/vi_VN/LC_MESSAGES/statusnet.mo
+++ /dev/null
Binary files differ
diff --git a/locale/zh_TW/LC_MESSAGES/statusnet.mo b/locale/zh_TW/LC_MESSAGES/statusnet.mo
index e13548831..9bdfbaf9f 100644
--- a/locale/zh_TW/LC_MESSAGES/statusnet.mo
+++ b/locale/zh_TW/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/zh_TW/LC_MESSAGES/statusnet.po b/locale/zh_TW/LC_MESSAGES/statusnet.po
index a94187518..4f1168601 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 77d57eff9..000000000
--- 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
index 81b2520a4..81b2520a4 100644
--- a/plugins/FBConnect/FBCLoginGroupNav.php
+++ b/plugins/Facebook/FBCLoginGroupNav.php
diff --git a/plugins/FBConnect/FBCSettingsNav.php b/plugins/Facebook/FBCSettingsNav.php
index ed02371e2..ed02371e2 100644
--- a/plugins/FBConnect/FBCSettingsNav.php
+++ b/plugins/Facebook/FBCSettingsNav.php
diff --git a/plugins/FBConnect/FBC_XDReceiver.php b/plugins/Facebook/FBC_XDReceiver.php
index 2bc790d5a..2bc790d5a 100644
--- a/plugins/FBConnect/FBC_XDReceiver.php
+++ b/plugins/Facebook/FBC_XDReceiver.php
diff --git a/plugins/FBConnect/FBConnectPlugin.css b/plugins/Facebook/FBConnect.css
index 49217bf13..49217bf13 100644
--- a/plugins/FBConnect/FBConnectPlugin.css
+++ b/plugins/Facebook/FBConnect.css
diff --git a/plugins/FBConnect/FBConnectAuth.php b/plugins/Facebook/FBConnectAuth.php
index 647d5def8..b909a4977 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
index 5696d8848..f146bef7d 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
index 911c56787..911c56787 100644
--- a/plugins/FBConnect/FBConnectSettings.php
+++ b/plugins/Facebook/FBConnectSettings.php
diff --git a/plugins/FBConnect/FBConnectPlugin.php b/plugins/Facebook/FacebookPlugin.php
index ff74aade4..b68534b24 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()
+
+ /**
+ * 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)
{
- parent::__construct();
- }
- // Hook in new actions
- 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 <body>
+ /**
+ * Add in the Facebook Connect JavaScript stuff
+ *
+ * Note: this script needs to appear in the <body>
+ *
+ * @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('<script type="text/javascript">
- $(document).ready(function () {
- FB_RequireFeatures(
- ["XFBML"],
- function() {
- FB.init("%s", "../xd_receiver.html");
- }
- ); });
-
- function goto_login() {
- window.location = "%s";
- }
-
- function goto_logout() {
- window.location = "%s";
- }
- </script>', $apikey,
- $login_url, $logout_url);
-
- $action->raw($html);
+ $js = '<script type="text/javascript">';
+ $js .= ' $(document).ready(function () {';
+ $js .= ' FB_RequireFeatures(';
+ $js .= ' ["XFBML"], function() {';
+ $js .= ' FB.init("%1$s", "../xd_receiver.html");';
+ $js .= ' }';
+ $js .= ' );';
+ $js .= ' });';
+
+ $js .= ' function goto_login() {';
+ $js .= ' window.location = "%2$s";';
+ $js .= ' }';
+
+ // 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.
+
+ $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 .= '</script>';
+
+ $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 </body>
+ /**
+ * Add in an additional Facebook Connect script that's supposed to
+ * appear as close as possible to </body>
+ *
+ * @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('<li id="nav_logout"><a href="#" title="%s" ' .
- 'onclick="FB.Connect.logoutAndRedirect(\'%s\');">%s</a></li>',
- $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 000000000..bf2f4a180
--- /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
index 016e8e8e0..016e8e8e0 100644
--- a/extlib/facebook/facebook.php
+++ b/plugins/Facebook/facebook/facebook.php
diff --git a/extlib/facebook/facebook_desktop.php b/plugins/Facebook/facebook/facebook_desktop.php
index e79a2ca34..e79a2ca34 100644
--- a/extlib/facebook/facebook_desktop.php
+++ b/plugins/Facebook/facebook/facebook_desktop.php
diff --git a/extlib/facebook/facebookapi_php5_restlib.php b/plugins/Facebook/facebook/facebookapi_php5_restlib.php
index 55cb7fb86..55cb7fb86 100755
--- a/extlib/facebook/facebookapi_php5_restlib.php
+++ b/plugins/Facebook/facebook/facebookapi_php5_restlib.php
diff --git a/extlib/facebook/jsonwrapper/JSON/JSON.php b/plugins/Facebook/facebook/jsonwrapper/JSON/JSON.php
index 0cddbddb4..0cddbddb4 100644
--- a/extlib/facebook/jsonwrapper/JSON/JSON.php
+++ b/plugins/Facebook/facebook/jsonwrapper/JSON/JSON.php
diff --git a/extlib/facebook/jsonwrapper/JSON/LICENSE b/plugins/Facebook/facebook/jsonwrapper/JSON/LICENSE
index 4ae6bef55..4ae6bef55 100644
--- a/extlib/facebook/jsonwrapper/JSON/LICENSE
+++ b/plugins/Facebook/facebook/jsonwrapper/JSON/LICENSE
diff --git a/extlib/facebook/jsonwrapper/jsonwrapper.php b/plugins/Facebook/facebook/jsonwrapper/jsonwrapper.php
index 29509deba..29509deba 100644
--- a/extlib/facebook/jsonwrapper/jsonwrapper.php
+++ b/plugins/Facebook/facebook/jsonwrapper/jsonwrapper.php
diff --git a/extlib/facebook/jsonwrapper/jsonwrapper_inner.php b/plugins/Facebook/facebook/jsonwrapper/jsonwrapper_inner.php
index 36a3f2863..36a3f2863 100644
--- a/extlib/facebook/jsonwrapper/jsonwrapper_inner.php
+++ b/plugins/Facebook/facebook/jsonwrapper/jsonwrapper_inner.php
diff --git a/lib/facebookaction.php b/plugins/Facebook/facebookaction.php
index 3f3a8d3b0..a10fdf90d 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 <zach@status.net>
- * @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 = '<style>
.entry-title *,
diff --git a/theme/base/css/facebookapp.css b/plugins/Facebook/facebookapp.css
index e6b1c9ee5..8cd06f78a 100644
--- a/theme/base/css/facebookapp.css
+++ b/plugins/Facebook/facebookapp.css
@@ -5,8 +5,8 @@ font-family:"Lucida Sans Unicode", "Lucida Grande", sans-serif;
#wrap {
background-color:#F0F2F5;
-padding-left:18px;
-padding-right:18px;
+padding-left:1.795%;
+padding-right:1.795%;
width:auto;
}
@@ -15,8 +15,16 @@ h1,h2,h3,h4,h5,h6 {
color:#000;
}
+#header {
+width:131%;
+}
+
#content {
-width:95%;
+width:92.7%;
+}
+
+#aside_primary {
+display:none;
}
#site_nav_local_views a {
@@ -26,6 +34,16 @@ background-color:#D0DFE7;
background-color:#FAFBFC;
}
+#form_notice .form_note + label,
+#form_notice #notice_data-attach {
+display:none;
+}
+
+#form_notice #notice_action-submit {
+height:47px !important;
+}
+
+
span.facebook-button {
border: 2px solid #aaa;
padding: 3px;
diff --git a/actions/facebookhome.php b/plugins/Facebook/facebookhome.php
index 70f205205..91c0cc6b8 100644
--- a/actions/facebookhome.php
+++ b/plugins/Facebook/facebookhome.php
@@ -17,9 +17,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
-require_once INSTALLDIR.'/lib/facebookaction.php';
+require_once INSTALLDIR . '/plugins/Facebook/facebookaction.php';
class FacebookhomeAction extends FacebookAction
{
diff --git a/actions/facebookinvite.php b/plugins/Facebook/facebookinvite.php
index 6dfc9d688..3380b4c85 100644
--- a/actions/facebookinvite.php
+++ b/plugins/Facebook/facebookinvite.php
@@ -21,7 +21,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
-require_once(INSTALLDIR.'/lib/facebookaction.php');
+require_once INSTALLDIR . '/plugins/Facebook/facebookaction.php';
class FacebookinviteAction extends FacebookAction
{
@@ -105,6 +105,7 @@ class FacebookinviteAction extends FacebookAction
$multi_params = array('showborder' => 'false');
$multi_params['actiontext'] = $actiontext;
$multi_params['bypass'] = 'cancel';
+ $multi_params['cols'] = 4;
// Get a list of users who are already using the app for exclusion
$exclude_ids = $this->facebook->api_client->friends_getAppUsers();
diff --git a/actions/facebooklogin.php b/plugins/Facebook/facebooklogin.php
index 8ac2477ab..f77aecca3 100644
--- a/actions/facebooklogin.php
+++ b/plugins/Facebook/facebooklogin.php
@@ -17,9 +17,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
-require_once(INSTALLDIR.'/lib/facebookaction.php');
+require_once INSTALLDIR . '/plugins/Facebook/facebookaction.php';
class FacebookinviteAction extends FacebookAction
{
@@ -27,25 +29,24 @@ class FacebookinviteAction extends FacebookAction
function handle($args)
{
parent::handle($args);
-
+
$this->error = $error;
-
+
if ($this->flink) {
if (!$this->facebook->api_client->users_hasAppPermission('publish_stream') &&
$this->facebook->api_client->data_getUserPreference(
FACEBOOK_PROMPTED_UPDATE_PREF) == 'true') {
-
+
echo '<h1>REDIRECT TO HOME</h1>';
}
- } else {
+ } else {
$this->showPage();
}
}
-
function showContent()
{
-
+
// If the user has opted not to initially allow the app to have
// Facebook status update permission, store that preference. Only
// promt the user the first time she uses the app
@@ -68,34 +69,31 @@ class FacebookinviteAction extends FacebookAction
return;
}
}
-
+
} else {
$this->showLoginForm();
}
-
+
}
function showSuccessContent()
{
-
-
}
function showFormContent()
{
-
}
-
- function title()
+
+ function title()
{
return sprintf(_('Login'));
}
-
- function redirectHome()
+
+ function redirectHome()
{
-
+
}
}
diff --git a/scripts/facebookqueuehandler.php b/plugins/Facebook/facebookqueuehandler.php
index e13ac4e85..e4ae7d4ee 100755
--- a/scripts/facebookqueuehandler.php
+++ b/plugins/Facebook/facebookqueuehandler.php
@@ -18,7 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/../..'));
$shortoptions = 'i::';
$longoptions = array('id::');
@@ -30,9 +30,8 @@ Daemon script for pushing new notices to Facebook.
END_OF_FACEBOOK_HELP;
-require_once INSTALLDIR.'/scripts/commandline.inc';
-
-require_once INSTALLDIR . '/lib/facebookutil.php';
+require_once INSTALLDIR . '/scripts/commandline.inc';
+require_once INSTALLDIR . '/plugins/Facebook/facebookutil.php';
require_once INSTALLDIR . '/lib/queuehandler.php';
class FacebookQueueHandler extends QueueHandler
diff --git a/actions/facebookremove.php b/plugins/Facebook/facebookremove.php
index ae231c0fb..8531a8e6e 100644
--- a/actions/facebookremove.php
+++ b/plugins/Facebook/facebookremove.php
@@ -17,9 +17,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
-require_once INSTALLDIR.'/lib/facebookaction.php';
+require_once INSTALLDIR . '/plugins/Facebook/facebookaction.php';
class FacebookremoveAction extends FacebookAction
{
diff --git a/actions/facebooksettings.php b/plugins/Facebook/facebooksettings.php
index 84bdde910..2f182e368 100644
--- a/actions/facebooksettings.php
+++ b/plugins/Facebook/facebooksettings.php
@@ -17,9 +17,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
-require_once INSTALLDIR.'/lib/facebookaction.php';
+require_once INSTALLDIR . '/plugins/Facebook/facebookaction.php';
class FacebooksettingsAction extends FacebookAction
{
@@ -58,8 +60,15 @@ class FacebooksettingsAction extends FacebookAction
$this->flink->set_flags($noticesync, $replysync, false, false);
$result = $this->flink->update($original);
+ if ($prefix == '' || $prefix == '0') {
+ // Facebook bug: saving empty strings to prefs now fails
+ // http://bugs.developers.facebook.com/show_bug.cgi?id=7110
+ $trimmed = $prefix . ' ';
+ } else {
+ $trimmed = substr($prefix, 0, 128);
+ }
$this->facebook->api_client->data_setUserPreference(FACEBOOK_NOTICE_PREFIX,
- substr($prefix, 0, 128));
+ $trimmed);
if ($result === false) {
$this->showForm(_('There was a problem saving your sync preferences!'));
@@ -84,16 +93,16 @@ class FacebooksettingsAction extends FacebookAction
'id' => 'facebook_settings'));
$this->elementStart('ul', 'form_data');
-
+
$this->elementStart('li');
-
+
$this->checkbox('noticesync', _('Automatically update my Facebook status with my notices.'),
($this->flink) ? ($this->flink->noticesync & FOREIGN_NOTICE_SEND) : true);
$this->elementEnd('li');
-
+
$this->elementStart('li');
-
+
$this->checkbox('replysync', _('Send "@" replies to Facebook.'),
($this->flink) ? ($this->flink->noticesync & FOREIGN_NOTICE_SEND_REPLY) : true);
@@ -101,22 +110,22 @@ class FacebooksettingsAction extends FacebookAction
$this->elementStart('li');
- $prefix = $this->facebook->api_client->data_getUserPreference(FACEBOOK_NOTICE_PREFIX);
+ $prefix = trim($this->facebook->api_client->data_getUserPreference(FACEBOOK_NOTICE_PREFIX));
$this->input('prefix', _('Prefix'),
($prefix) ? $prefix : null,
_('A string to prefix notices with.'));
$this->elementEnd('li');
-
+
$this->elementStart('li');
-
+
$this->submit('save', _('Save'));
$this->elementEnd('li');
$this->elementEnd('ul');
-
+
$this->elementEnd('form');
} else {
@@ -141,8 +150,8 @@ class FacebooksettingsAction extends FacebookAction
}
}
-
- function title()
+
+ function title()
{
return _('Sync preferences');
}
diff --git a/lib/facebookutil.php b/plugins/Facebook/facebookutil.php
index f5121609d..6f50c173a 100644
--- a/lib/facebookutil.php
+++ b/plugins/Facebook/facebookutil.php
@@ -17,9 +17,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-require_once INSTALLDIR.'/extlib/facebook/facebook.php';
-require_once INSTALLDIR.'/lib/facebookaction.php';
-require_once INSTALLDIR.'/lib/noticelist.php';
+require_once INSTALLDIR . '/plugins/Facebook/facebook/facebook.php';
+require_once INSTALLDIR . '/plugins/Facebook/facebookaction.php';
+require_once INSTALLDIR . '/lib/noticelist.php';
define("FACEBOOK_SERVICE", 2); // Facebook is foreign_service ID 2
define("FACEBOOK_NOTICE_PREFIX", 1);
@@ -99,8 +99,8 @@ function facebookBroadcastNotice($notice)
// XXX: Does this call count against our per user FB request limit?
// If so we should consider storing verb elsewhere or not storing
- $prefix = $facebook->api_client->data_getUserPreference(FACEBOOK_NOTICE_PREFIX,
- $fbuid);
+ $prefix = trim($facebook->api_client->data_getUserPreference(FACEBOOK_NOTICE_PREFIX,
+ $fbuid));
$status = "$prefix $notice->content";
@@ -258,3 +258,38 @@ function remove_facebook_app($flink)
}
}
+
+/**
+ * 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/plugins/FBConnect/fbfavicon.ico b/plugins/Facebook/fbfavicon.ico
index c57c0342f..c57c0342f 100644
--- a/plugins/FBConnect/fbfavicon.ico
+++ b/plugins/Facebook/fbfavicon.ico
Binary files differ
diff --git a/plugins/GeonamesPlugin.php b/plugins/GeonamesPlugin.php
new file mode 100644
index 000000000..80ef44cc9
--- /dev/null
+++ b/plugins/GeonamesPlugin.php
@@ -0,0 +1,305 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Plugin to convert string locations to Geonames IDs and vice versa
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Plugin to convert string locations to Geonames IDs and vice versa
+ *
+ * This handles most of the events that Location class emits. It uses
+ * the geonames.org Web service to convert names like 'Montreal, Quebec, Canada'
+ * into IDs and lat/lon pairs.
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ *
+ * @seeAlso Location
+ */
+
+class GeonamesPlugin extends Plugin
+{
+ const NAMESPACE = 1;
+
+ /**
+ * convert a name into a Location object
+ *
+ * @param string $name Name to convert
+ * @param string $language ISO code for anguage the name is in
+ * @param Location &$location Location object (may be null)
+ *
+ * @return boolean whether to continue (results in $location)
+ */
+
+ function onLocationFromName($name, $language, &$location)
+ {
+ $client = HTTPClient::start();
+
+ // XXX: break down a name by commas, narrow by each
+
+ $str = http_build_query(array('maxRows' => 1,
+ 'q' => $name,
+ 'lang' => $language,
+ 'type' => 'json'));
+
+ $result = $client->get('http://ws.geonames.org/search?'.$str);
+
+ if ($result->code == "200") {
+ $rj = json_decode($result->body);
+ if (count($rj->geonames) > 0) {
+ $n = $rj->geonames[0];
+
+ $location = new Location();
+
+ $location->lat = $n->lat;
+ $location->lon = $n->lng;
+ $location->names[$language] = $n->name;
+ $location->location_id = $n->geonameId;
+ $location->location_ns = self::NAMESPACE;
+
+ // handled, don't continue processing!
+ return false;
+ }
+ }
+
+ // Continue processing; we don't have the answer
+ return true;
+ }
+
+ /**
+ * convert an id into a Location object
+ *
+ * @param string $id Name to convert
+ * @param string $ns Name to convert
+ * @param string $language ISO code for language for results
+ * @param Location &$location Location object (may be null)
+ *
+ * @return boolean whether to continue (results in $location)
+ */
+
+ function onLocationFromId($id, $ns, $language, &$location)
+ {
+ if ($ns != self::NAMESPACE) {
+ // It's not one of our IDs... keep processing
+ return true;
+ }
+
+ $client = HTTPClient::start();
+
+ $str = http_build_query(array('geonameId' => $id,
+ 'lang' => $language));
+
+ $result = $client->get('http://ws.geonames.org/hierarchyJSON?'.$str);
+
+ if ($result->code == "200") {
+
+ $rj = json_decode($result->body);
+
+ if (count($rj->geonames) > 0) {
+
+ $parts = array();
+
+ foreach ($rj->geonames as $level) {
+ if (in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
+ $parts[] = $level->name;
+ }
+ }
+
+ $last = $rj->geonames[count($rj->geonames)-1];
+
+ if (!in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
+ $parts[] = $last->name;
+ }
+
+ $location = new Location();
+
+ $location->location_id = $last->geonameId;
+ $location->location_ns = self::NAMESPACE;
+ $location->lat = $last->lat;
+ $location->lon = $last->lng;
+ $location->names[$language] = implode(', ', array_reverse($parts));
+ }
+ }
+
+ // We're responsible for this NAMESPACE; nobody else
+ // can resolve it
+
+ return false;
+ }
+
+ /**
+ * convert a lat/lon pair into a Location object
+ *
+ * Given a lat/lon, we try to find a Location that's around
+ * it or nearby. We prefer populated places (cities, towns, villages).
+ *
+ * @param string $lat Latitude
+ * @param string $lon Longitude
+ * @param string $language ISO code for language for results
+ * @param Location &$location Location object (may be null)
+ *
+ * @return boolean whether to continue (results in $location)
+ */
+
+ function onLocationFromLatLon($lat, $lon, $language, &$location)
+ {
+ $client = HTTPClient::start();
+
+ $str = http_build_query(array('lat' => $lat,
+ 'lng' => $lon,
+ 'lang' => $language));
+
+ $result =
+ $client->get('http://ws.geonames.org/findNearbyPlaceNameJSON?'.$str);
+
+ if ($result->code == "200") {
+
+ $rj = json_decode($result->body);
+
+ if (count($rj->geonames) > 0) {
+
+ $n = $rj->geonames[0];
+
+ $parts = array();
+
+ $location = new Location();
+
+ $parts[] = $n->name;
+
+ if (!empty($n->adminName1)) {
+ $parts[] = $n->adminName1;
+ }
+
+ if (!empty($n->countryName)) {
+ $parts[] = $n->countryName;
+ }
+
+ $location->location_id = $n->geonameId;
+ $location->location_ns = self::NAMESPACE;
+ $location->lat = $lat;
+ $location->lon = $lon;
+
+ $location->names[$language] = implode(', ', $parts);
+
+ // Success! We handled it, so no further processing
+
+ return false;
+ }
+ }
+
+ // For some reason we don't know, so pass.
+
+ return true;
+ }
+
+ /**
+ * Human-readable name for a location
+ *
+ * Given a location, we try to retrieve a human-readable name
+ * in the target language.
+ *
+ * @param Location $location Location to get the name for
+ * @param string $language ISO code for language to find name in
+ * @param string &$name Place to put the name
+ *
+ * @return boolean whether to continue
+ */
+
+ function onLocationNameLanguage($location, $language, &$name)
+ {
+ if ($location->location_ns != self::NAMESPACE) {
+ // It's not one of our IDs... keep processing
+ return true;
+ }
+
+ $client = HTTPClient::start();
+
+ $str = http_build_query(array('geonameId' => $id,
+ 'lang' => $language));
+
+ $result = $client->get('http://ws.geonames.org/hierarchyJSON?'.$str);
+
+ if ($result->code == "200") {
+
+ $rj = json_decode($result->body);
+
+ if (count($rj->geonames) > 0) {
+
+ $parts = array();
+
+ foreach ($rj->geonames as $level) {
+ if (in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
+ $parts[] = $level->name;
+ }
+ }
+
+ $last = $rj->geonames[count($rj->geonames)-1];
+
+ if (!in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
+ $parts[] = $last->name;
+ }
+
+ if (count($parts)) {
+ $name = implode(', ', array_reverse($parts));
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Human-readable name for a location
+ *
+ * Given a location, we try to retrieve a geonames.org URL.
+ *
+ * @param Location $location Location to get the url for
+ * @param string &$url Place to put the url
+ *
+ * @return boolean whether to continue
+ */
+
+ function onLocationUrl($location, &$url)
+ {
+ if ($location->location_ns != self::NAMESPACE) {
+ // It's not one of our IDs... keep processing
+ return true;
+ }
+
+ $url = 'http://www.geonames.org/' . $location->location_id;
+
+ // it's been filled, so don't process further.
+ return false;
+ }
+}
diff --git a/plugins/OpenID/OpenIDPlugin.php b/plugins/OpenID/OpenIDPlugin.php
index a933a1155..2309eea9d 100644
--- a/plugins/OpenID/OpenIDPlugin.php
+++ b/plugins/OpenID/OpenIDPlugin.php
@@ -62,17 +62,59 @@ class OpenIDPlugin extends Plugin
* @return boolean hook return
*/
- function onRouterInitialized(&$m)
+ function onStartInitializeRouter($m)
{
$m->connect('main/openid', array('action' => 'openidlogin'));
+ $m->connect('main/openidtrust', array('action' => 'openidtrust'));
$m->connect('settings/openid', array('action' => 'openidsettings'));
- $m->connect('xrds', array('action' => 'publicxrds'));
$m->connect('index.php?action=finishopenidlogin', array('action' => 'finishopenidlogin'));
$m->connect('index.php?action=finishaddopenid', array('action' => 'finishaddopenid'));
-
+ $m->connect('main/openidserver', array('action' => 'openidserver'));
+
return true;
}
+ function onEndPublicXRDS($action, &$xrdsOutputter)
+ {
+ $xrdsOutputter->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
+ 'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
+ 'version' => '2.0'));
+ $xrdsOutputter->element('Type', null, 'xri://$xrds*simple');
+ //consumer
+ foreach (array('finishopenidlogin', 'finishaddopenid') as $finish) {
+ $xrdsOutputter->showXrdsService(Auth_OpenID_RP_RETURN_TO_URL_TYPE,
+ common_local_url($finish));
+ }
+ //provider
+ $xrdsOutputter->showXrdsService('http://specs.openid.net/auth/2.0/server',
+ common_local_url('openidserver'),
+ null,
+ null,
+ 'http://specs.openid.net/auth/2.0/identifier_select');
+ $xrdsOutputter->elementEnd('XRD');
+ }
+
+ function onEndUserXRDS($action, &$xrdsOutputter)
+ {
+ $xrdsOutputter->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
+ 'xml:id' => 'openid',
+ 'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
+ 'version' => '2.0'));
+ $xrdsOutputter->element('Type', null, 'xri://$xrds*simple');
+
+ //consumer
+ $xrdsOutputter->showXrdsService('http://specs.openid.net/auth/2.0/return_to',
+ common_local_url('finishopenidlogin'));
+
+ //provider
+ $xrdsOutputter->showXrdsService('http://specs.openid.net/auth/2.0/signon',
+ common_local_url('openidserver'),
+ null,
+ null,
+ common_profile_url($action->user->nickname));
+ $xrdsOutputter->elementEnd('XRD');
+ }
+
function onEndLoginGroupNav(&$action)
{
$action_name = $action->trimmed('action');
@@ -107,6 +149,8 @@ class OpenIDPlugin extends Plugin
case 'XrdsAction':
case 'PublicxrdsAction':
case 'OpenidsettingsAction':
+ case 'OpenidserverAction':
+ case 'OpenidtrustAction':
require_once(INSTALLDIR.'/plugins/OpenID/' . strtolower(mb_substr($cls, 0, -6)) . '.php');
return false;
case 'User_openid':
@@ -136,6 +180,7 @@ class OpenIDPlugin extends Plugin
{
case 'openidlogin':
case 'finishopenidlogin':
+ case 'openidserver':
$login = true;
return false;
default:
@@ -150,11 +195,19 @@ class OpenIDPlugin extends Plugin
* @return void
*/
- function onEndHeadChildren($action)
+ function onEndShowHeadElements($action)
{
- // for client side of OpenID authentication
- $action->element('meta', array('http-equiv' => 'X-XRDS-Location',
- 'content' => common_local_url('publicxrds')));
+ if($action instanceof ShowstreamAction){
+ $action->element('link', array('rel' => 'openid2.provider',
+ 'href' => common_local_url('openidserver')));
+ $action->element('link', array('rel' => 'openid2.local_id',
+ 'href' => $action->profile->profileurl));
+ $action->element('link', array('rel' => 'openid.server',
+ 'href' => common_local_url('openidserver')));
+ $action->element('link', array('rel' => 'openid.delegate',
+ 'href' => $action->profile->profileurl));
+ }
+ return true;
}
/**
@@ -235,6 +288,14 @@ class OpenIDPlugin extends Plugin
new ColumnDef('created', 'datetime',
null, false),
new ColumnDef('modified', 'timestamp')));
+ $schema->ensureTable('user_openid_trustroot',
+ array(new ColumnDef('trustroot', 'varchar',
+ '255', false, 'PRI'),
+ new ColumnDef('user_id', 'integer',
+ null, false, 'PRI'),
+ new ColumnDef('created', 'datetime',
+ null, false),
+ new ColumnDef('modified', 'timestamp')));
return true;
}
}
diff --git a/plugins/OpenID/User_openid_trustroot.php b/plugins/OpenID/User_openid_trustroot.php
new file mode 100644
index 000000000..4654b72df
--- /dev/null
+++ b/plugins/OpenID/User_openid_trustroot.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Table Definition for user_openid_trustroot
+ */
+require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
+
+class User_openid_trustroot extends Memcached_DataObject
+{
+ ###START_AUTOCODE
+ /* the code below is auto generated do not remove the above tag */
+
+ public $__table = 'user_openid_trustroot'; // table name
+ public $trustroot; // varchar(255) primary_key not_null
+ public $user_id; // int(4) primary_key not_null
+ public $created; // datetime() not_null
+ public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
+
+ /* Static get */
+ function staticGet($k,$v=null)
+ { return Memcached_DataObject::staticGet('User_openid_trustroot',$k,$v); }
+
+ /* the code above is auto generated do not remove the tag below */
+ ###END_AUTOCODE
+
+ function &pkeyGet($kv)
+ {
+ return Memcached_DataObject::pkeyGet('User_openid_trustroot', $kv);
+ }
+}
diff --git a/plugins/OpenID/finishopenidlogin.php b/plugins/OpenID/finishopenidlogin.php
index 50a9c15c8..ff0b451d3 100644
--- a/plugins/OpenID/finishopenidlogin.php
+++ b/plugins/OpenID/finishopenidlogin.php
@@ -265,7 +265,7 @@ class FinishopenidloginAction extends Action
$fullname = '';
}
- if (!empty($sreg['email']) && Validate::email($sreg['email'], true)) {
+ if (!empty($sreg['email']) && Validate::email($sreg['email'], common_config('email', 'check_domain'))) {
$email = $sreg['email'];
} else {
$email = '';
diff --git a/plugins/OpenID/openid.php b/plugins/OpenID/openid.php
index 0944117c0..ff7a93899 100644
--- a/plugins/OpenID/openid.php
+++ b/plugins/OpenID/openid.php
@@ -23,6 +23,7 @@ require_once(INSTALLDIR.'/plugins/OpenID/User_openid.php');
require_once('Auth/OpenID.php');
require_once('Auth/OpenID/Consumer.php');
+require_once('Auth/OpenID/Server.php');
require_once('Auth/OpenID/SReg.php');
require_once('Auth/OpenID/MySQLStore.php');
@@ -50,6 +51,13 @@ function oid_consumer()
return $consumer;
}
+function oid_server()
+{
+ $store = oid_store();
+ $server = new Auth_OpenID_Server($store, common_local_url('openidserver'));
+ return $server;
+}
+
function oid_clear_last()
{
oid_set_last('');
@@ -241,7 +249,7 @@ function oid_update_user(&$user, &$sreg)
$orig_user = clone($user);
- if ($sreg['email'] && Validate::email($sreg['email'], true)) {
+ if ($sreg['email'] && Validate::email($sreg['email'], common_config('email', 'check_domain'))) {
$user->email = $sreg['email'];
}
diff --git a/plugins/OpenID/openidserver.php b/plugins/OpenID/openidserver.php
new file mode 100644
index 000000000..dab97c93e
--- /dev/null
+++ b/plugins/OpenID/openidserver.php
@@ -0,0 +1,151 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Settings for OpenID
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Settings
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @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.'/lib/action.php';
+require_once INSTALLDIR.'/plugins/OpenID/openid.php';
+require_once(INSTALLDIR.'/plugins/OpenID/User_openid_trustroot.php');
+
+/**
+ * Settings for OpenID
+ *
+ * Lets users add, edit and delete OpenIDs from their account
+ *
+ * @category Settings
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class OpenidserverAction extends Action
+{
+ var $oserver;
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+ $this->oserver = oid_server();
+ return true;
+ }
+
+ function handle($args)
+ {
+ parent::handle($args);
+ $request = $this->oserver->decodeRequest();
+ if (in_array($request->mode, array('checkid_immediate',
+ 'checkid_setup'))) {
+ $user = common_current_user();
+ if(!$user){
+ if($request->immediate){
+ //cannot prompt the user to login in immediate mode, so answer false
+ $response = $this->generateDenyResponse($request);
+ }else{
+ /* Go log in, and then come back. */
+ common_set_returnto($_SERVER['REQUEST_URI']);
+ common_redirect(common_local_url('login'));
+ return;
+ }
+ }else if(common_profile_url($user->nickname) == $request->identity || $request->idSelect()){
+ $user_openid_trustroot = User_openid_trustroot::pkeyGet(
+ array('user_id'=>$user->id, 'trustroot'=>$request->trust_root));
+ if(empty($user_openid_trustroot)){
+ if($request->immediate){
+ //cannot prompt the user to trust this trust root in immediate mode, so answer false
+ $response = $this->generateDenyResponse($request);
+ }else{
+ common_ensure_session();
+ $_SESSION['openid_trust_root'] = $request->trust_root;
+ $allowResponse = $this->generateAllowResponse($request, $user);
+ $this->oserver->encodeResponse($allowResponse); //sign the response
+ $denyResponse = $this->generateDenyResponse($request);
+ $this->oserver->encodeResponse($denyResponse); //sign the response
+ $_SESSION['openid_allow_url'] = $allowResponse->encodeToUrl();
+ $_SESSION['openid_deny_url'] = $denyResponse->encodeToUrl();
+ //ask the user to trust this trust root
+ common_redirect(common_local_url('openidtrust'));
+ return;
+ }
+ }else{
+ //user has previously authorized this trust root
+ $response = $this->generateAllowResponse($request, $user);
+ //$response = $request->answer(true, null, common_profile_url($user->nickname));
+ }
+ } else if ($request->immediate) {
+ $response = $this->generateDenyResponse($request);
+ } else {
+ //invalid
+ $this->clientError(sprintf(_('You are not authorized to use the identity %s'),$request->identity),$code=403);
+ }
+ } else {
+ $response = $this->oserver->handleRequest($request);
+ }
+
+ if($response){
+ $response = $this->oserver->encodeResponse($response);
+ if ($response->code != AUTH_OPENID_HTTP_OK) {
+ header(sprintf("HTTP/1.1 %d ", $response->code),
+ true, $response->code);
+ }
+
+ if($response->headers){
+ foreach ($response->headers as $k => $v) {
+ header("$k: $v");
+ }
+ }
+ $this->raw($response->body);
+ }else{
+ $this->clientError(_('Just an OpenID provider. Nothing to see here, move along...'),$code=500);
+ }
+ }
+
+ function generateAllowResponse($request, $user){
+ $response = $request->answer(true, null, common_profile_url($user->nickname));
+
+ $profile = $user->getProfile();
+ $sreg_data = array(
+ 'fullname' => $profile->fullname,
+ 'nickname' => $user->nickname,
+ 'email' => $user->email,
+ 'language' => $user->language,
+ 'timezone' => $user->timezone);
+ $sreg_request = Auth_OpenID_SRegRequest::fromOpenIDRequest($request);
+ $sreg_response = Auth_OpenID_SRegResponse::extractResponse(
+ $sreg_request, $sreg_data);
+ $sreg_response->toMessage($response->fields);
+ return $response;
+ }
+
+ function generateDenyResponse($request){
+ $response = $request->answer(false);
+ return $response;
+ }
+}
diff --git a/plugins/OpenID/openidtrust.php b/plugins/OpenID/openidtrust.php
new file mode 100644
index 000000000..29c7bdc23
--- /dev/null
+++ b/plugins/OpenID/openidtrust.php
@@ -0,0 +1,142 @@
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
+
+require_once INSTALLDIR.'/plugins/OpenID/openid.php';
+require_once(INSTALLDIR.'/plugins/OpenID/User_openid_trustroot.php');
+
+class OpenidtrustAction extends Action
+{
+ var $trust_root;
+ var $allowUrl;
+ var $denyUrl;
+ var $user;
+
+ /**
+ * Is this a read-only action?
+ *
+ * @return boolean false
+ */
+
+ function isReadOnly($args)
+ {
+ return false;
+ }
+
+ /**
+ * Title of the page
+ *
+ * @return string title of the page
+ */
+
+ function title()
+ {
+ return _('OpenID Identity Verification');
+ }
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+ common_ensure_session();
+ $this->user = common_current_user();
+ if(empty($this->user)){
+ /* Go log in, and then come back. */
+ common_set_returnto($_SERVER['REQUEST_URI']);
+ common_redirect(common_local_url('login'));
+ return;
+ }
+ $this->trust_root = $_SESSION['openid_trust_root'];
+ $this->allowUrl = $_SESSION['openid_allow_url'];
+ $this->denyUrl = $_SESSION['openid_deny_url'];
+ if(empty($this->trust_root) || empty($this->allowUrl) || empty($this->denyUrl)){
+ $this->clientError(_('This page should only be reached during OpenID processing, not directly.'));
+ return;
+ }
+ return true;
+ }
+
+ function handle($args)
+ {
+ parent::handle($args);
+ if($_SERVER['REQUEST_METHOD'] == 'POST'){
+ $this->handleSubmit();
+ }else{
+ $this->showPage();
+ }
+ }
+
+ function handleSubmit()
+ {
+ unset($_SESSION['openid_trust_root']);
+ unset($_SESSION['openid_allow_url']);
+ unset($_SESSION['openid_deny_url']);
+ if($this->arg('allow'))
+ {
+ //save to database
+ $user_openid_trustroot = new User_openid_trustroot();
+ $user_openid_trustroot->user_id = $this->user->id;
+ $user_openid_trustroot->trustroot = $this->trust_root;
+ $user_openid_trustroot->created = DB_DataObject_Cast::dateTime();
+ if (!$user_openid_trustroot->insert()) {
+ $err = PEAR::getStaticProperty('DB_DataObject','lastError');
+ common_debug('DB error ' . $err->code . ': ' . $err->message, __FILE__);
+ }
+ common_redirect($this->allowUrl, $code=302);
+ }else{
+ common_redirect($this->denyUrl, $code=302);
+ }
+ }
+
+ /**
+ * Show page notice
+ *
+ * Display a notice for how to use the page, or the
+ * error if it exists.
+ *
+ * @return void
+ */
+
+ function showPageNotice()
+ {
+ $this->element('p',null,sprintf(_('%s has asked to verify your identity. Click Continue to verify your identity and login without creating a new password.'),$this->trust_root));
+ }
+
+ /**
+ * Core of the display code
+ *
+ * Shows the login form.
+ *
+ * @return void
+ */
+
+ function showContent()
+ {
+ $this->elementStart('form', array('method' => 'post',
+ 'id' => 'form_openidtrust',
+ 'class' => 'form_settings',
+ 'action' => common_local_url('openidtrust')));
+ $this->elementStart('fieldset');
+ $this->submit('allow', _('Continue'));
+ $this->submit('deny', _('Cancel'));
+
+ $this->elementEnd('fieldset');
+ $this->elementEnd('form');
+ }
+}
diff --git a/plugins/PubSubHubBub/PubSubHubBubPlugin.php b/plugins/PubSubHubBub/PubSubHubBubPlugin.php
index e1e82e352..d15a869cb 100644
--- a/plugins/PubSubHubBub/PubSubHubBubPlugin.php
+++ b/plugins/PubSubHubBub/PubSubHubBubPlugin.php
@@ -65,21 +65,21 @@ class PubSubHubBubPlugin extends Plugin
$feeds = array();
//public timeline feeds
- $feeds[]=common_local_url('api',array('apiaction' => 'statuses','method' => 'public_timeline.rss'));
- $feeds[]=common_local_url('api',array('apiaction' => 'statuses','method' => 'public_timeline.atom'));
+ $feeds[]=common_local_url('ApiTimelinePublic',array('format' => 'rss'));
+ $feeds[]=common_local_url('ApiTimelinePublic',array('format' => 'atom'));
//author's own feeds
$user = User::staticGet('id',$notice->profile_id);
- $feeds[]=common_local_url('api',array('apiaction' => 'statuses','method' => 'user_timeline','argument' => $user->nickname.'.rss'));
- $feeds[]=common_local_url('api',array('apiaction' => 'statuses','method' => 'user_timeline','argument' => $user->nickname.'.atom'));
+ $feeds[]=common_local_url('ApiTimelineUser',array('id' => $user->nickname, 'format'=>'rss'));
+ $feeds[]=common_local_url('ApiTimelineUser',array('id' => $user->nickname, 'format'=>'atom'));
//tag feeds
$tag = new Notice_tag();
$tag->notice_id = $notice->id;
if ($tag->find()) {
while ($tag->fetch()) {
- $feeds[]=common_local_url('api',array('apiaction' => 'tags','method' => 'timeline', 'argument'=>$tag->tag.'.atom'));
- $feeds[]=common_local_url('api',array('apiaction' => 'tags','method' => 'timeline', 'argument'=>$tag->tag.'.rss'));
+ $feeds[]=common_local_url('ApiTimelineTag',array('tag'=>$tag->tag, 'format'=>'rss'));
+ $feeds[]=common_local_url('ApiTimelineTag',array('tag'=>$tag->tag, 'format'=>'atom'));
}
}
@@ -89,8 +89,8 @@ class PubSubHubBubPlugin extends Plugin
if ($group_inbox->find()) {
while ($group_inbox->fetch()) {
$group = User_group::staticGet('id',$group_inbox->group_id);
- $feeds[]=common_local_url('api',array('apiaction' => 'groups','method' => 'timeline','argument' => $group->nickname.'.rss'));
- $feeds[]=common_local_url('api',array('apiaction' => 'groups','method' => 'timeline','argument' => $group->nickname.'.atom'));
+ $feeds[]=common_local_url('ApiTimelineGroup',array('id' => $group->nickname,'format'=>'rss'));
+ $feeds[]=common_local_url('ApiTimelineGroup',array('id' => $group->nickname,'format'=>'atom'));
}
}
@@ -100,18 +100,17 @@ class PubSubHubBubPlugin extends Plugin
if ($notice_inbox->find()) {
while ($notice_inbox->fetch()) {
$user = User::staticGet('id',$notice_inbox->user_id);
- $feeds[]=common_local_url('api',array('apiaction' => 'statuses','method' => 'user_timeline','argument' => $user->nickname.'.rss'));
- $feeds[]=common_local_url('api',array('apiaction' => 'statuses','method' => 'user_timeline','argument' => $user->nickname.'.atom'));
+ $feeds[]=common_local_url('ApiTimelineUser',array('id' => $user->nickname, 'format'=>'rss'));
+ $feeds[]=common_local_url('ApiTimelineUser',array('id' => $user->nickname, 'format'=>'atom'));
}
}
- /* TODO: when the reply page gets RSS and ATOM feeds, implement this
//feed of user replied to
if($notice->reply_to){
$user = User::staticGet('id',$notice->reply_to);
- $feeds[]=common_local_url('api',array('apiaction' => 'statuses','method' => 'user_timeline','argument' => $user->nickname.'.rss'));
- $feeds[]=common_local_url('api',array('apiaction' => 'statuses','method' => 'user_timeline','argument' => $user->nickname.'.atom'));
- }*/
+ $feeds[]=common_local_url('ApiTimelineMentions',array('id' => $user->nickname,'format'=>'rss'));
+ $feeds[]=common_local_url('ApiTimelineMentions',array('id' => $user->nickname,'format'=>'atom'));
+ }
foreach(array_unique($feeds) as $feed){
if(! $publisher->publish_update($feed)){
diff --git a/plugins/Realtime/realtimeupdate.js b/plugins/Realtime/realtimeupdate.js
index a75f17d8c..9371326fe 100644
--- a/plugins/Realtime/realtimeupdate.js
+++ b/plugins/Realtime/realtimeupdate.js
@@ -7,6 +7,7 @@ RealtimeUpdate = {
_replyurl: '',
_favorurl: '',
_deleteurl: '',
+ _updatecounter: 0,
init: function(userid, replyurl, favorurl, deleteurl)
{
@@ -15,6 +16,8 @@ RealtimeUpdate = {
RealtimeUpdate._favorurl = favorurl;
RealtimeUpdate._deleteurl = deleteurl;
+ DT = document.title;
+
$(window).blur(function() {
$('#notices_primary .notice').css({
'border-top-color':$('#notices_primary .notice:last').css('border-top-color'),
@@ -25,7 +28,10 @@ RealtimeUpdate = {
'border-top-color':'#AAAAAA',
'border-top-style':'solid'
});
-
+
+ RealtimeUpdate._updatecounter = 0;
+ document.title = DT;
+
return false;
});
},
@@ -39,12 +45,15 @@ RealtimeUpdate = {
if ($("#notice-"+id).length > 0) {
return;
}
-
+
var noticeItem = RealtimeUpdate.makeNoticeItem(data);
$("#notices_primary .notices").prepend(noticeItem);
$("#notices_primary .notice:first").css({display:"none"});
$("#notices_primary .notice:first").fadeIn(1000);
NoticeReply();
+
+ RealtimeUpdate._updatecounter += 1;
+ document.title = '('+RealtimeUpdate._updatecounter+') ' + DT;
}, 500);
},
diff --git a/plugins/TemplatePlugin.php b/plugins/TemplatePlugin.php
index cfa051162..5f3ad81f5 100644
--- a/plugins/TemplatePlugin.php
+++ b/plugins/TemplatePlugin.php
@@ -32,7 +32,7 @@ class TemplatePlugin extends Plugin {
// capture the RouterInitialized event
// and connect a new API method
// for updating the template
- function onRouterInitialized( &$m ) {
+ function onRouterInitialized( $m ) {
$m->connect( 'template/update', array(
'action' => 'template',
));
diff --git a/plugins/TwitterBridge/README b/plugins/TwitterBridge/README
new file mode 100644
index 000000000..d3bcda598
--- /dev/null
+++ b/plugins/TwitterBridge/README
@@ -0,0 +1,85 @@
+This Twitter "bridge" plugin allows you to integrate your StatusNet
+instance with Twitter. Installing it will allow your users to:
+
+ - automatically post notices to thier Twitter accounts
+ - automatically subscribe to other Twitter users who are also using
+ your StatusNet install, if possible (requires running a daemon)
+ - import their Twitter friends' tweets (requires running a daemon)
+
+Installation
+------------
+
+To enable the plugin, add the following to your config.php:
+
+ addPlugin("TwitterBridge");
+
+OAuth is used to to access protected resources on Twitter (as opposed to
+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".
+
+* Note: The plugin will still push notices to Twitter for users who
+ have previously setup the Twitter bridge using their Twitter name and
+ password under an older versions of StatusNet, but all new Twitter
+ bridge connections will use OAuth.
+
+Deamons
+-------
+
+For friend syncing and importing notices running two additional daemon
+scripts is necessary (synctwitterfriends.php and
+twitterstatusfetcher.php).
+
+In the daemons subidrectory of the plugin are three scripts:
+
+* Twitter Friends Syncing (daemons/synctwitterfriends.php)
+
+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.
+
+The plugin will try to start this daemon when you run
+scripts/startdaemons.sh.
+
+* Importing statuses from Twitter (daemons/twitterstatusfetcher.php)
+
+To allow your users to import their friends' Twitter statuses, you will
+need to enable the bidirectional Twitter bridge in your config.php:
+
+ $config['twitterimport']['enabled'] = true;
+
+The plugin will then start the TwitterStatusFetcher daemon along with the
+other daemons when you run scripts/startdaemons.sh.
+
+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';
+
+* TwitterQueueHandler (daemons/twitterqueuehandler.php)
+
+This script sends queued notices to Twitter for user who have opted to
+set up Twitter bridging.
+
+It's not strictly necessary to run this queue handler, and sites that
+haven't enabled queuing are still able to push notices to Twitter, but
+for larger sites and sites that wish to improve performance, this
+script allows notices to be sent "offline" via a separate process.
+
+The plugin will start this script when you run scripts/startdaemons.sh.
diff --git a/plugins/TwitterBridge/TwitterBridgePlugin.php b/plugins/TwitterBridge/TwitterBridgePlugin.php
new file mode 100644
index 000000000..ad3c2e551
--- /dev/null
+++ b/plugins/TwitterBridge/TwitterBridgePlugin.php
@@ -0,0 +1,187 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2009 Control Yourself, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://laconi.ca/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
+
+/**
+ * Plugin for sending and importing Twitter statuses
+ *
+ * This class allows users to link their Twitter accounts
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://laconi.ca/
+ * @link http://twitter.com/
+ */
+
+class TwitterBridgePlugin extends Plugin
+{
+ /**
+ * Initializer for the plugin.
+ */
+
+ function __construct()
+ {
+ parent::__construct();
+ }
+
+ /**
+ * Add Twitter-related paths to the router table
+ *
+ * Hook for RouterInitialized event.
+ *
+ * @param Net_URL_Mapper $m path-to-action mapper
+ *
+ * @return boolean hook return
+ */
+
+ function onRouterInitialized($m)
+ {
+ $m->connect('twitter/authorization',
+ array('action' => 'twitterauthorization'));
+ $m->connect('settings/twitter', array('action' => 'twittersettings'));
+
+ return true;
+ }
+
+ /**
+ * Add the Twitter Settings page to the Connect Settings menu
+ *
+ * @param Action &$action The calling page
+ *
+ * @return boolean hook return
+ */
+ function onEndConnectSettingsNav(&$action)
+ {
+ $action_name = $action->trimmed('action');
+
+ $action->menuItem(common_local_url('twittersettings'),
+ _('Twitter'),
+ _('Twitter integration options'),
+ $action_name === 'twittersettings');
+
+ return true;
+ }
+
+ /**
+ * Automatically load the actions and libraries used by the Twitter bridge
+ *
+ * @param Class $cls the class
+ *
+ * @return boolean hook return
+ *
+ */
+ function onAutoload($cls)
+ {
+ switch ($cls) {
+ case 'TwittersettingsAction':
+ case 'TwitterauthorizationAction':
+ include_once INSTALLDIR . '/plugins/TwitterBridge/' .
+ strtolower(mb_substr($cls, 0, -6)) . '.php';
+ return false;
+ case 'TwitterOAuthClient':
+ include_once INSTALLDIR . '/plugins/TwitterBridge/twitteroauthclient.php';
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ /**
+ * Add a Twitter 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, 'twitter');
+ 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 == 'twitter') && ($this->_isLocal($notice))) {
+ broadcast_twitter($notice);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Determine whether the notice was locally created
+ *
+ * @param Notice $notice
+ *
+ * @return boolean locality
+ */
+ function _isLocal($notice)
+ {
+ return ($notice->is_local == Notice::LOCAL_PUBLIC ||
+ $notice->is_local == Notice::LOCAL_NONPUBLIC);
+ }
+
+ /**
+ * Add Twitter bridge daemons 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/TwitterBridge/daemons/twitterqueuehandler.php');
+ array_push($daemons, INSTALLDIR .
+ '/plugins/TwitterBridge/daemons/synctwitterfriends.php');
+
+ if (common_config('twitterimport', 'enabled')) {
+ array_push($daemons, INSTALLDIR
+ . '/plugins/TwitterBridge/daemons/twitterstatusfetcher.php');
+ }
+
+ return true;
+ }
+
+}
diff --git a/scripts/synctwitterfriends.php b/plugins/TwitterBridge/daemons/synctwitterfriends.php
index b30e700a1..ed2bf48a2 100755
--- a/scripts/synctwitterfriends.php
+++ b/plugins/TwitterBridge/daemons/synctwitterfriends.php
@@ -18,7 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/../../..'));
$shortoptions = 'di::';
$longoptions = array('id::', 'debug');
@@ -32,6 +32,9 @@ END_OF_TRIM_HELP;
require_once INSTALLDIR . '/scripts/commandline.inc';
require_once INSTALLDIR . '/lib/parallelizingdaemon.php';
+require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
+require_once INSTALLDIR . '/plugins/TwitterBridge/twitterbasicauthclient.php';
+require_once INSTALLDIR . '/plugins/TwitterBridge/twitteroauthclient.php';
/**
* Daemon to sync local friends with Twitter friends
@@ -44,14 +47,6 @@ require_once INSTALLDIR . '/lib/parallelizingdaemon.php';
* @link http://status.net/
*/
-$helptext = <<<END_OF_TWITTER_HELP
-Batch script for synching local friends with Twitter friends.
-
-END_OF_TWITTER_HELP;
-
-require_once INSTALLDIR . '/scripts/commandline.inc';
-require_once INSTALLDIR . '/lib/parallelizingdaemon.php';
-
class SyncTwitterFriendsDaemon extends ParallelizingDaemon
{
/**
diff --git a/scripts/twitterqueuehandler.php b/plugins/TwitterBridge/daemons/twitterqueuehandler.php
index ce4d824d0..f0e76bb74 100755
--- a/scripts/twitterqueuehandler.php
+++ b/plugins/TwitterBridge/daemons/twitterqueuehandler.php
@@ -18,7 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/../../..'));
$shortoptions = 'i::';
$longoptions = array('id::');
@@ -30,10 +30,9 @@ Daemon script for pushing new notices to Twitter.
END_OF_ENJIT_HELP;
-require_once INSTALLDIR.'/scripts/commandline.inc';
-
-require_once INSTALLDIR . '/lib/twitter.php';
+require_once INSTALLDIR . '/scripts/commandline.inc';
require_once INSTALLDIR . '/lib/queuehandler.php';
+require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
class TwitterQueueHandler extends QueueHandler
{
diff --git a/scripts/twitterstatusfetcher.php b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php
index 3cdf1867a..81bbbc7c5 100755
--- a/scripts/twitterstatusfetcher.php
+++ b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php
@@ -18,7 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/../../..'));
// Tune number of processes and how often to poll Twitter
// XXX: Should these things be in config.php?
@@ -36,8 +36,12 @@ Batch script for retrieving Twitter messages from foreign service.
END_OF_TRIM_HELP;
-require_once INSTALLDIR .'/scripts/commandline.inc';
+require_once INSTALLDIR . '/scripts/commandline.inc';
+require_once INSTALLDIR . '/lib/common.php';
require_once INSTALLDIR . '/lib/daemon.php';
+require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
+require_once INSTALLDIR . '/plugins/TwitterBridge/twitterbasicauthclient.php';
+require_once INSTALLDIR . '/plugins/TwitterBridge/twitteroauthclient.php';
/**
* Fetcher for statuses from Twitter
@@ -496,8 +500,6 @@ class TwitterStatusFetcher extends ParallelizingDaemon
$avatar->filename = $filename;
$avatar->url = Avatar::url($filename);
- common_debug($this->name() . " - New filename: $avatar->url");
-
$avatar->created = common_sql_now();
$id = $avatar->insert();
@@ -515,9 +517,7 @@ class TwitterStatusFetcher extends ParallelizingDaemon
function fetchAvatar($url, $filename)
{
- $avatar_dir = INSTALLDIR . '/avatar/';
-
- $avatarfile = $avatar_dir . $filename;
+ $avatarfile = Avatar::path($filename);
$out = fopen($avatarfile, 'wb');
if (!$out) {
diff --git a/lib/twitter.php b/plugins/TwitterBridge/twitter.php
index afc3f55ba..1a5248a9b 100644
--- a/lib/twitter.php
+++ b/plugins/TwitterBridge/twitter.php
@@ -23,6 +23,9 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
define('TWITTER_SERVICE', 1); // Twitter is foreign_service ID 1
+require_once INSTALLDIR . '/plugins/TwitterBridge/twitterbasicauthclient.php';
+require_once INSTALLDIR . '/plugins/TwitterBridge/twitteroauthclient.php';
+
function updateTwitter_user($twitter_id, $screen_name)
{
$uri = 'http://twitter.com/' . $screen_name;
@@ -309,3 +312,40 @@ function remove_twitter_link($flink)
}
}
+
+/**
+ * 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);
+}
+
diff --git a/actions/twitterauthorization.php b/plugins/TwitterBridge/twitterauthorization.php
index 630ac426f..2a93ff13e 100644
--- a/actions/twitterauthorization.php
+++ b/plugins/TwitterBridge/twitterauthorization.php
@@ -31,9 +31,32 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
+require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
+
+/**
+ * Class for doing OAuth authentication against Twitter
+ *
+ * Peforms the OAuth "dance" between StatusNet and Twitter -- requests a token,
+ * authorizes it, and exchanges it for an access token. It also creates a link
+ * (Foreign_link) between the StatusNet user and Twitter user and stores the
+ * access token and secret in the link.
+ *
+ * @category Twitter
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://laconi.ca/
+ *
+ */
class TwitterauthorizationAction extends Action
{
-
+ /**
+ * Initialize class members. Looks for 'oauth_token' parameter.
+ *
+ * @param array $args misc. arguments
+ *
+ * @return boolean true
+ */
function prepare($args)
{
parent::prepare($args);
diff --git a/lib/twitterbasicauthclient.php b/plugins/TwitterBridge/twitterbasicauthclient.php
index 1040d72fb..1040d72fb 100644
--- a/lib/twitterbasicauthclient.php
+++ b/plugins/TwitterBridge/twitterbasicauthclient.php
diff --git a/lib/twitteroauthclient.php b/plugins/TwitterBridge/twitteroauthclient.php
index bad2b74ca..bad2b74ca 100644
--- a/lib/twitteroauthclient.php
+++ b/plugins/TwitterBridge/twitteroauthclient.php
diff --git a/actions/twittersettings.php b/plugins/TwitterBridge/twittersettings.php
index 89169941e..ca22c9553 100644
--- a/actions/twittersettings.php
+++ b/plugins/TwitterBridge/twittersettings.php
@@ -31,8 +31,8 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
-require_once INSTALLDIR.'/lib/connectsettingsaction.php';
-require_once INSTALLDIR.'/lib/twitter.php';
+require_once INSTALLDIR . '/lib/connectsettingsaction.php';
+require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
/**
* Settings for Twitter integration
@@ -82,11 +82,6 @@ class TwittersettingsAction extends ConnectSettingsAction
function showContent()
{
- if (!common_config('twitter', 'enabled')) {
- $this->element('div', array('class' => 'error'),
- _('Twitter is not available.'));
- return;
- }
$user = common_current_user();
@@ -157,7 +152,7 @@ class TwittersettingsAction extends ConnectSettingsAction
false);
$this->elementEnd('li');
- if (common_config('twitterbridge','enabled')) {
+ if (common_config('twitterimport','enabled')) {
$this->elementStart('li');
$this->checkbox('noticerecv',
_('Import my Friends Timeline.'),
diff --git a/scripts/getvaliddaemons.php b/scripts/getvaliddaemons.php
index 6dd019712..99ad41b37 100755
--- a/scripts/getvaliddaemons.php
+++ b/scripts/getvaliddaemons.php
@@ -39,7 +39,6 @@ $daemons = array();
$daemons[] = INSTALLDIR.'/scripts/pluginqueuehandler.php';
$daemons[] = INSTALLDIR.'/scripts/ombqueuehandler.php';
-$daemons[] = INSTALLDIR.'/scripts/facebookqueuehandler.php';
$daemons[] = INSTALLDIR.'/scripts/pingqueuehandler.php';
if(common_config('xmpp','enabled')) {
@@ -49,15 +48,6 @@ if(common_config('xmpp','enabled')) {
$daemons[] = INSTALLDIR.'/scripts/xmppconfirmhandler.php';
}
-if(common_config('twitterbridge','enabled')) {
- $daemons[] = INSTALLDIR.'/scripts/twitterstatusfetcher.php';
-}
-
-if (common_config('twitter', 'enabled')) {
- $daemons[] = INSTALLDIR.'/scripts/twitterqueuehandler.php';
- $daemons[] = INSTALLDIR.'/scripts/synctwitterfriends.php';
-}
-
if (common_config('sms', 'enabled')) {
$daemons[] = INSTALLDIR.'/scripts/smsqueuehandler.php';
}
diff --git a/scripts/maildaemon.php b/scripts/maildaemon.php
index 586bef624..b4e4d9f08 100755
--- a/scripts/maildaemon.php
+++ b/scripts/maildaemon.php
@@ -29,6 +29,7 @@ END_OF_HELP;
require_once INSTALLDIR.'/scripts/commandline.inc';
require_once(INSTALLDIR . '/lib/mail.php');
+require_once(INSTALLDIR . '/lib/mediafile.php');
require_once('Mail/mimeDecode.php');
# FIXME: we use both Mail_mimeDecode and mailparse
@@ -71,43 +72,27 @@ class MailerDaemon
'Max notice size is %d chars.'),
Notice::maxContent()));
}
- $fileRecords = array();
- foreach($attachments as $attachment){
- $mimetype = $this->getUploadedFileType($attachment);
- $stream = stream_get_meta_data($attachment);
- if (!$this->isRespectsQuota($user,filesize($stream['uri']))) {
- die('error() should trigger an exception before reaching here.');
- }
- $filename = $this->saveFile($user, $attachment,$mimetype);
- fclose($attachment);
+ $mediafiles = array();
- if (empty($filename)) {
- $this->error($from,_('Couldn\'t save file.'));
- }
-
- $fileRecord = $this->storeFile($filename, $mimetype);
- $fileRecords[] = $fileRecord;
- $fileurl = common_local_url('attachment',
- array('attachment' => $fileRecord->id));
-
- // not sure this is necessary -- Zach
- $this->maybeAddRedir($fileRecord->id, $fileurl);
+ foreach($attachments as $attachment){
- $short_fileurl = common_shorten_url($fileurl);
- $msg .= ' ' . $short_fileurl;
+ $mf = null;
- if (Notice::contentTooLong($msg)) {
- $this->deleteFile($filename);
- $this->error($from, sprintf(_('Max notice size is %d chars, including attachment URL.'),
- Notice::maxContent()));
+ try {
+ $mf = MediaFile::fromFileHandle($attachment, $user);
+ } catch(ClientException $ce) {
+ $this->error($from, $ce->getMessage());
}
- // Also, not sure this is necessary -- Zach
- $this->maybeAddRedir($fileRecord->id, $short_fileurl);
+ $msg .= ' ' . $mf->shortUrl();
+
+ array_push($mediafiles, $mf);
+ fclose($attachment);
}
- $err = $this->add_notice($user, $msg, $fileRecords);
+ $err = $this->add_notice($user, $msg, $mediafiles);
+
if (is_string($err)) {
$this->error($from, $err);
return false;
@@ -116,89 +101,6 @@ class MailerDaemon
}
}
- function saveFile($user, $attachment, $mimetype) {
-
- $filename = File::filename($user->getProfile(), "email", $mimetype);
-
- $filepath = File::path($filename);
-
- $stream = stream_get_meta_data($attachment);
- if (copy($stream['uri'], $filepath) && chmod($filepath,0664)) {
- return $filename;
- } else {
- $this->error(null,_('File could not be moved to destination directory.' . $stream['uri'] . ' ' . $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->error(null,_('There was a database error while saving your file. Please try again.'));
- }
-
- return $file;
- }
-
- 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->error(null,_('There was a database error while saving your file. Please try again.'));
- }
- }
- }
-
- function getUploadedFileType($fileHandle) {
- require_once 'MIME/Type.php';
-
- $cmd = &PEAR::getStaticProperty('MIME_Type', 'fileCmd');
- $cmd = common_config('attachments', 'filecommand');
-
- $stream = stream_get_meta_data($fileHandle);
- $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 = '';
- }
- $this->error(null,sprintf(
- _('%s is not a supported filetype on this server.'), $filetype) . $hint);
- }
-
- function isRespectsQuota($user,$fileSize) {
- $file = new File;
- $ret = $file->isRespectsQuota($user,$fileSize);
- if (true === $ret) return true;
- $this->error(null,$ret);
- }
-
function error($from, $msg)
{
file_put_contents("php://stderr", $msg . "\n");
@@ -258,7 +160,7 @@ class MailerDaemon
common_log($level, 'MailDaemon: '.$msg);
}
- function add_notice($user, $msg, $fileRecords)
+ function add_notice($user, $msg, $mediafiles)
{
try {
$notice = Notice::saveNew($user->id, $msg, 'mail');
@@ -266,8 +168,8 @@ class MailerDaemon
$this->log(LOG_ERR, $e->getMessage());
return $e->getMessage();
}
- foreach($fileRecords as $fileRecord){
- $this->attachFile($notice, $fileRecord);
+ foreach($mediafiles as $mf){
+ $mf->attachToNotice($notice);
}
common_broadcast_notice($notice);
$this->log(LOG_INFO,
@@ -275,14 +177,6 @@ class MailerDaemon
return true;
}
- function attachFile($notice, $filerec)
- {
- File_to_post::processNew($filerec->id, $notice->id);
-
- $this->maybeAddRedir($filerec->id,
- common_local_url('file', array('notice' => $notice->id)));
- }
-
function parse_message($fname)
{
$contents = file_get_contents($fname);
@@ -365,6 +259,10 @@ class MailerDaemon
if (preg_match('/^\s*Sent via/', $line)) {
continue;
}
+ if (preg_match('/^\s*Sent from my/', $line)) {
+ continue;
+ }
+
// skip everything after a sig
if (preg_match('/^\s*--+\s*$/', $line) ||
preg_match('/^\s*__+\s*$/', $line))
diff --git a/tests/LocationTest.php b/tests/LocationTest.php
new file mode 100644
index 000000000..62849eb9f
--- /dev/null
+++ b/tests/LocationTest.php
@@ -0,0 +1,87 @@
+<?php
+
+if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
+ print "This script must be run from the command line\n";
+ exit();
+}
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+define('STATUSNET', true);
+
+require_once INSTALLDIR . '/lib/common.php';
+
+// Make sure this is loaded
+// XXX: how to test other plugins...?
+
+addPlugin('Geonames');
+
+class LocationTest extends PHPUnit_Framework_TestCase
+{
+
+ /**
+ * @dataProvider locationNames
+ */
+
+ public function testLocationFromName($name, $language, $location)
+ {
+ $result = Location::fromName($name, $language);
+ $this->assertEquals($result, $location);
+ }
+
+ static public function locationNames()
+ {
+ return array(array('Montreal', 'en', null),
+ array('San Francisco, CA', 'en', null),
+ array('Paris, France', 'en', null),
+ array('Paris, Texas', 'en', null));
+ }
+
+ /**
+ * @dataProvider locationIds
+ */
+
+ public function testLocationFromId($id, $ns, $language, $location)
+ {
+ $result = Location::fromId($id, $ns, $language);
+ $this->assertEquals($result, $location);
+ }
+
+ static public function locationIds()
+ {
+ return array(array(6077243, GeonamesPlugin::NAMESPACE, 'en', null),
+ array(5391959, GeonamesPlugin::NAMESPACE, 'en', null));
+ }
+
+ /**
+ * @dataProvider locationLatLons
+ */
+
+ public function testLocationFromLatLon($lat, $lon, $language, $location)
+ {
+ $result = Location::fromLatLon($lat, $lon, $language);
+ $this->assertEquals($result, $location);
+ }
+
+ static public function locationLatLons()
+ {
+ return array(array(37.77493, -122.41942, 'en', null),
+ array(45.509, -73.588, 'en', null));
+ }
+
+ /**
+ * @dataProvider nameOfLocation
+ */
+
+ public function testLocationGetName($location, $language, $name)
+ {
+ $result = $location->getName($language);
+ $this->assertEquals($result, $name);
+ }
+
+ static public function nameOfLocation()
+ {
+ return array(array(new Location(), 'en', 'Montreal'),
+ array(new Location(), 'fr', 'Montréal'));
+ }
+}
+
diff --git a/tests/URLDetectionTest.php b/tests/URLDetectionTest.php
index 45203bf6e..0cc03ccce 100644
--- a/tests/URLDetectionTest.php
+++ b/tests/URLDetectionTest.php
@@ -47,7 +47,9 @@ class URLDetectionTest extends PHPUnit_Framework_TestCase
array('127.0.0.1/\'test',
'<a href="http://127.0.0.1/\'test" title="http://127.0.0.1/\'test" rel="external">127.0.0.1/\'test</a>'),
array('127.0.0.1/"test',
- '<a href="http://127.0.0.1/&quot;test" title="http://127.0.0.1/&quot;test" rel="external">127.0.0.1/&quot;test</a>'),
+ '<a href="http://127.0.0.1/" title="http://127.0.0.1/" rel="external">127.0.0.1/</a>&quot;test'),
+ array('127.0.0.1/test"test',
+ '<a href="http://127.0.0.1/test" title="http://127.0.0.1/test" rel="external">127.0.0.1/test</a>&quot;test'),
array('127.0.0.1/-test',
'<a href="http://127.0.0.1/-test" title="http://127.0.0.1/-test" rel="external">127.0.0.1/-test</a>'),
array('127.0.0.1/_test',
@@ -170,6 +172,8 @@ class URLDetectionTest extends PHPUnit_Framework_TestCase
'\'<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>\''),
array('"http://example.com"',
'&quot;<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>&quot;'),
+ array('"http://example.com/"',
+ '&quot;<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com/</a>&quot;'),
array('http://example.com',
'<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>'),
array('(http://example.com)',
diff --git a/theme/base/css/display.css b/theme/base/css/display.css
index d9dca9815..8355a0a5c 100644
--- a/theme/base/css/display.css
+++ b/theme/base/css/display.css
@@ -432,21 +432,21 @@ border-width:1px;
border-style:solid;
}
-#form_notice {
+.form_notice {
width:45%;
float:left;
position:relative;
line-height:1;
}
-#form_notice fieldset {
+.form_notice fieldset {
border:0;
padding:0;
position:relative;
}
-#form_notice legend {
+.form_notice legend {
display:none;
}
-#form_notice textarea {
+.form_notice textarea {
float:left;
border-radius:7px;
-moz-border-radius:7px;
@@ -458,44 +458,44 @@ padding:7px 7px 16px 7px;
position:relative;
z-index:2;
}
-#form_notice label {
+.form_notice label {
display:block;
float:left;
font-size:1.3em;
margin-bottom:7px;
}
-#form_notice label[for=notice_data-attach],
-#form_notice #notice_data-attach {
+.form_notice label[for=notice_data-attach],
+.form_notice #notice_data-attach {
position:absolute;
top:25px;
right:10.5%;
cursor:pointer;
}
-#form_notice label[for=notice_data-attach] {
+.form_notice label[for=notice_data-attach] {
text-indent:-9999px;
width:16px;
height:16px;
}
-#form_notice #notice_data-attach {
+.form_notice #notice_data-attach {
padding:0;
height:16px;
}
-#form_notice .form_note {
+.form_notice .form_note {
position:absolute;
bottom:2px;
right:21.715%;
z-index:9;
}
-#form_notice .form_note dt {
+.form_notice .form_note dt {
font-weight:bold;
display:none;
}
-#notice_text-count {
+.form_notice #notice_text-count {
font-weight:bold;
line-height:1.15;
padding:1px 2px;
}
-#form_notice #notice_action-submit {
+.form_notice #notice_action-submit {
width:14%;
height:47px;
padding:0;
@@ -503,24 +503,24 @@ position:absolute;
bottom:0;
right:0;
}
-#form_notice label[for=to] {
+.form_notice label[for=to] {
margin-top:7px;
}
-#form_notice select[id=to] {
+.form_notice select[id=to] {
margin-bottom:7px;
margin-left:18px;
float:left;
max-width:322px;
}
-#form_notice .error,
-#form_notice .success {
+.form_notice .error,
+.form_notice .success {
float:left;
clear:both;
width:81.5%;
margin-bottom:0;
line-height:1.618;
}
-#form_notice #notice_data-attach_selected code {
+.form_notice #notice_data-attach_selected code {
float:left;
width:90%;
display:block;
@@ -528,7 +528,7 @@ font-size:1.1em;
line-height:1.8;
overflow:auto;
}
-#form_notice #notice_data-attach_selected button {
+.form_notice #notice_data-attach_selected button {
float:right;
font-size:0.8em;
}
@@ -670,6 +670,40 @@ border-radius:4px;
margin-bottom:18px;
}
+
+.entity_send-a-message button {
+position:absolute;
+top:0;
+right:0;
+}
+
+.entity_send-a-message .form_notice {
+position:absolute;
+top:34px;
+right:-1px;
+padding:1.795%;
+width:65%;
+z-index:1;
+
+background-color:#FFFFFF;
+border:1px solid #CCCCCC;
+-moz-box-shadow:3px 7px 5px rgba(194, 194, 194, 0.7);
+-moz-border-radius:7px;
+}
+.entity_send-a-message .form_notice legend {
+display:block;
+margin-bottom:11px;
+}
+
+.entity_send-a-message .form_notice label,
+.entity_send-a-message .form_notice select {
+display:none;
+}
+.entity_send-a-message .form_notice input.submit {
+text-align:center;
+}
+
+
.entity_tags ul {
list-style-type:none;
display:inline;
@@ -1295,3 +1329,13 @@ display:none;
.guide {
clear:both;
}
+
+#bookmarklet address {
+display:none;
+}
+#bookmarklet .form_notice {
+width:auto;
+}
+#bookmarklet #wrap {
+min-width:0;
+}
diff --git a/theme/base/css/ie.css b/theme/base/css/ie.css
index 3e128b84e..84bc1b1d6 100644
--- a/theme/base/css/ie.css
+++ b/theme/base/css/ie.css
@@ -3,10 +3,10 @@ input.checkbox,
input.radio {
top:0;
}
-#form_notice textarea {
+.form_notice textarea {
width:78%;
}
-#form_notice .form_note + label {
+.form_notice .form_note + label {
position:absolute;
top:25px;
left:83%;
@@ -15,14 +15,14 @@ height:16px;
width:16px;
display:block;
}
-#form_notice #notice_action-submit {
+.form_notice #notice_action-submit {
width:17%;
max-width:17%;
}
-#form_notice #notice_data-attach_selected {
+.form_notice #notice_data-attach_selected {
width:78.5%;
}
-#form_notice #notice_data-attach_selected button {
+.form_notice #notice_data-attach_selected button {
padding:0 4px;
}
.notice-options input.submit {
diff --git a/theme/default/css/display.css b/theme/default/css/display.css
index 3993da717..5eff5842a 100644
--- a/theme/default/css/display.css
+++ b/theme/default/css/display.css
@@ -18,7 +18,7 @@ font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif;
font-size:1em;
}
address {
-margin-right:7.2%;
+margin-right:5.7%;
}
input, textarea, select, option {
@@ -37,14 +37,14 @@ background:none;
}
input.submit,
-#form_notice.warning #notice_text-count,
+.form_notice.warning #notice_text-count,
.form_settings .form_note,
.entity_remote_subscribe {
background-color:#9BB43E;
}
input:focus, textarea:focus, select:focus,
-#form_notice.warning #notice_data-text {
+.form_notice.warning #notice_data-text {
border-color:#9BB43E;
box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
-moz-box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
@@ -84,13 +84,13 @@ background-color:#C8D1D5;
#notice_text-count {
color:#333333;
}
-#form_notice.warning #notice_text-count {
+.form_notice.warning #notice_text-count {
color:#000000;
}
-#form_notice label[for=notice_data-attach] {
+.form_notice label[for=notice_data-attach] {
background:transparent url(../../base/images/icons/icons-01.png) no-repeat 0 -328px;
}
-#form_notice #notice_data-attach {
+.form_notice #notice_data-attach {
opacity:0;
}
diff --git a/theme/default/css/ie.css b/theme/default/css/ie.css
index cbbd49ce6..a0d3cd682 100644
--- a/theme/default/css/ie.css
+++ b/theme/default/css/ie.css
@@ -6,9 +6,9 @@ color:#FFFFFF;
#site_nav_local_views a {
background-color:#C8D1D5;
}
-#form_notice .form_note + label {
+.form_notice .form_note + label {
background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no-repeat 0 45%;
}
-#form_notice #notice_data-attach {
+.form_notice #notice_data-attach {
filter: alpha(opacity=0);
}
diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css
index 6339c9314..8aedd5144 100644
--- a/theme/identica/css/display.css
+++ b/theme/identica/css/display.css
@@ -37,14 +37,14 @@ background:none;
}
input.submit,
-#form_notice.warning #notice_text-count,
+.form_notice.warning #notice_text-count,
.form_settings .form_note,
.entity_remote_subscribe {
background-color:#9BB43E;
}
input:focus, textarea:focus, select:focus,
-#form_notice.warning #notice_data-text {
+.form_notice.warning #notice_data-text {
border-color:#9BB43E;
box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
-moz-box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
@@ -84,13 +84,13 @@ background-color:#CEE1E9;
#notice_text-count {
color:#333333;
}
-#form_notice.warning #notice_text-count {
+.form_notice.warning #notice_text-count {
color:#000000;
}
-#form_notice label[for=notice_data-attach] {
+.form_notice label[for=notice_data-attach] {
background:transparent url(../../base/images/icons/icons-01.png) no-repeat 0 -328px;
}
-#form_notice #notice_data-attach {
+.form_notice #notice_data-attach {
opacity:0;
}
diff --git a/theme/identica/css/ie.css b/theme/identica/css/ie.css
index 044c32ff1..9ede1e324 100644
--- a/theme/identica/css/ie.css
+++ b/theme/identica/css/ie.css
@@ -6,10 +6,10 @@ color:#FFFFFF;
#site_nav_local_views a {
background-color:#D9DADB;
}
-#form_notice .form_note + label {
+.form_notice .form_note + label {
background:transparent url(../../base/images/icons/icons-01.png) no-repeat 0 -328px;
}
-#form_notice #notice_data-attach {
+.form_notice #notice_data-attach {
filter: alpha(opacity=0);
}
.notice-options form.form_favor input.submit {