From e547a2f54c2a2184d55c57c7712d4d50621f5fc2 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Mon, 19 Apr 2010 18:45:50 +0200 Subject: Fix ticket #2289: registration links were showing in top nav bar, login page message when site set to invite-only or closed registration, when the 'register' action can't be used. --- lib/action.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/action.php b/lib/action.php index 0fc3a0dc4..c4d9fd5cb 100644 --- a/lib/action.php +++ b/lib/action.php @@ -464,7 +464,7 @@ class Action extends HTMLOutputter // lawsuit _m('MENU', 'Logout'), $tooltip, false, 'nav_logout'); } else { - if (!common_config('site', 'closed')) { + if (!common_config('site', 'closed') && !common_config('site', 'inviteonly')) { // TRANS: Tooltip for main menu option "Register" $tooltip = _m('TOOLTIP', 'Create an account'); // TRANS: Main menu option when not logged in to register a new account -- cgit v1.2.3-54-g00ecf From 32918bb7c18c6c098a16e88d169099c6ce371dfe Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Mon, 19 Apr 2010 20:57:12 +0200 Subject: Test for and use mysqli in installer, since that's what we use later, rather than mysql. --- lib/installer.php | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/installer.php b/lib/installer.php index d0e46f95c..589a19a66 100644 --- a/lib/installer.php +++ b/lib/installer.php @@ -51,7 +51,7 @@ abstract class Installer public static $dbModules = array( 'mysql' => array( 'name' => 'MySQL', - 'check_module' => 'mysql', // mysqli? + 'check_module' => 'mysqli', 'installer' => 'mysql_db_installer', ), 'pgsql' => array( @@ -341,7 +341,6 @@ abstract class Installer * @param string $password * @return mixed array of database connection params on success, false on failure * - * @fixme be consistent about using mysqli vs mysql! * @fixme escape things in the connection string in case we have a funny pass etc */ function Mysql_Db_installer($host, $database, $username, $password) @@ -349,14 +348,13 @@ abstract class Installer $this->updateStatus("Starting installation..."); $this->updateStatus("Checking database..."); - $conn = mysql_connect($host, $username, $password); - if (!$conn) { + $conn = mysqli_init(); + if (!$conn->real_connect($host, $username, $password)) { $this->updateStatus("Can't connect to server '$host' as '$username'.", true); return false; } $this->updateStatus("Changing to database..."); - $res = mysql_select_db($database, $conn); - if (!$res) { + if (!$conn->select_db($database)) { $this->updateStatus("Can't change to database.", true); return false; } @@ -438,9 +436,9 @@ abstract class Installer // FIXME: use PEAR::DB or PDO instead of our own switch switch ($type) { case 'mysqli': - $res = mysql_query($stmt, $conn); + $res = $conn->query($stmt); if ($res === false) { - $error = mysql_error(); + $error = $conn->error(); } break; case 'pgsql': -- cgit v1.2.3-54-g00ecf From c48caa85e12063c2df9913957dbd11af6b5e3ea6 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 20 Apr 2010 12:06:54 +0200 Subject: Fix email notifications for @-replies that come via OStatus. * Moved notification sending from Notice::saveReplies to distrib queue handler, so it'll pull from the reply set we've saved regardless of how we got it. * Set up gettext infrastructure for command-line scripts; gets localization mail notifications etc working from background queues. * Adjusted locale switching: common_switch_locale() works at runtime for bg scripts, forces a message catalog update --- classes/Notice.php | 44 ++++++++++++++++++++++++++++++++------------ lib/distribqueuehandler.php | 17 +++++++++++++---- lib/mail.php | 4 ++-- lib/util.php | 31 ++++++++++++++++++++++++++++++- scripts/commandline.inc | 4 ++++ 5 files changed, 81 insertions(+), 19 deletions(-) (limited to 'lib') diff --git a/classes/Notice.php b/classes/Notice.php index a8147e4c4..4cf12fc6f 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -959,8 +959,7 @@ class Notice extends Memcached_DataObject * messages, we won't deliver to any remote targets as that's the * source service's responsibility. * - * @fixme Unlike saveReplies() there's no mail notification here. - * Move that to distrib queue handler? + * Mail notifications etc will be handled later. * * @param array of unique identifier URIs for recipients */ @@ -999,8 +998,7 @@ class Notice extends Memcached_DataObject * and save reply records indicating that this message needs to be * delivered to those users. * - * Side effect: local recipients get e-mail notifications here. - * @fixme move mail notifications to distrib? + * Mail notifications to local profiles will be sent later. * * @return array of integer profile IDs */ @@ -1060,17 +1058,14 @@ class Notice extends Memcached_DataObject $recipientIds = array_keys($replied); - foreach ($recipientIds as $recipientId) { - $user = User::staticGet('id', $recipientId); - if (!empty($user)) { - self::blow('reply:stream:%d', $reply->profile_id); - mail_notify_attn($user, $this); - } - } - return $recipientIds; } + /** + * Pull the complete list of @-reply targets for this notice. + * + * @return array of integer profile ids + */ function getReplies() { // XXX: cache me @@ -1093,6 +1088,31 @@ class Notice extends Memcached_DataObject return $ids; } + /** + * Send e-mail notifications to local @-reply targets. + * + * Replies must already have been saved; this is expected to be run + * from the distrib queue handler. + */ + function sendReplyNotifications() + { + // Don't send reply notifications for repeats + + if (!empty($this->repeat_of)) { + return array(); + } + + $recipientIds = $this->getReplies(); + + foreach ($recipientIds as $recipientId) { + $user = User::staticGet('id', $recipientId); + if (!empty($user)) { + self::blow('reply:stream:%d', $recipientId); + mail_notify_attn($user, $this); + } + } + } + /** * Pull list of groups this notice needs to be delivered to, * as previously recorded by saveGroups() or saveKnownGroups(). diff --git a/lib/distribqueuehandler.php b/lib/distribqueuehandler.php index d2be7a92c..8f4b72d5c 100644 --- a/lib/distribqueuehandler.php +++ b/lib/distribqueuehandler.php @@ -49,25 +49,34 @@ class DistribQueueHandler } /** - * Here's the meat of your queue handler -- you're handed a Notice - * object, which you may do as you will with. + * Handle distribution of a notice after we've saved it: + * @li add to local recipient inboxes + * @li send email notifications to local @-reply targets + * @li run final EndNoticeSave plugin events + * @li put any remaining post-processing into the queues * * If this function indicates failure, a warning will be logged * and the item is placed back in the queue to be re-run. * + * @fixme addToInboxes is known to fail sometimes with large recipient sets + * * @param Notice $notice * @return boolean true on success, false on failure */ function handle($notice) { - // XXX: do we need to change this for remote users? - try { $notice->addToInboxes(); } catch (Exception $e) { $this->logit($notice, $e); } + try { + $notice->sendReplyNotifications(); + } catch (Exception $e) { + $this->logit($notice, $e); + } + try { Event::handle('EndNoticeSave', array($notice)); // Enqueue for other handlers diff --git a/lib/mail.php b/lib/mail.php index 807b6a363..d73603694 100644 --- a/lib/mail.php +++ b/lib/mail.php @@ -620,7 +620,7 @@ function mail_notify_attn($user, $notice) $bestname = $sender->getBestName(); - common_init_locale($user->language); + common_switch_locale($user->language); if ($notice->conversation != $notice->id) { $conversationEmailText = "The full conversation can be read here:\n\n". @@ -662,7 +662,7 @@ function mail_notify_attn($user, $notice) $headers = _mail_prepare_headers('mention', $user->nickname, $sender->nickname); - common_init_locale(); + common_switch_locale(); mail_to_user($user, $subject, $body, $headers); } diff --git a/lib/util.php b/lib/util.php index e37df6348..58d54cda3 100644 --- a/lib/util.php +++ b/lib/util.php @@ -41,11 +41,13 @@ function common_init_locale($language=null) } putenv('LANGUAGE='.$language); putenv('LANG='.$language); - return setlocale(LC_ALL, $language . ".utf8", + $ok = setlocale(LC_ALL, $language . ".utf8", $language . ".UTF8", $language . ".utf-8", $language . ".UTF-8", $language); + + return $ok; } function common_init_language() @@ -89,6 +91,32 @@ function common_init_language() $locale_set = common_init_locale($language); } + common_init_gettext(); +} + +/** + * @access private + */ +function common_init_gettext() +{ + setlocale(LC_CTYPE, 'C'); + // So we do not 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"); +} + +/** + * Switch locale during runtime, and poke gettext until it cries uncle. + * Otherwise, sometimes it doesn't actually switch away from the old language. + * + * @param string $language code for locale ('en', 'fr', 'pt_BR' etc) + */ +function common_switch_locale($language=null) +{ + common_init_locale($language); + setlocale(LC_CTYPE, 'C'); // So we do not have to make people install the gettext locales $path = common_config('site','locale_path'); @@ -97,6 +125,7 @@ function common_init_language() textdomain("statusnet"); } + function common_timezone() { if (common_logged_in()) { diff --git a/scripts/commandline.inc b/scripts/commandline.inc index 9029bb19d..a475e11d0 100644 --- a/scripts/commandline.inc +++ b/scripts/commandline.inc @@ -123,6 +123,10 @@ require_once INSTALLDIR . '/lib/common.php'; set_error_handler('common_error_handler'); +// Set up the language infrastructure so we can localize anything that +// needs to be sent out to users, such as mail notifications. +common_init_language(); + function _make_matches($opt, $alt) { $matches = array(); -- cgit v1.2.3-54-g00ecf From 98f0d970da98e5b6de18972d033320a191152eb4 Mon Sep 17 00:00:00 2001 From: Zachary Copley Date: Tue, 20 Apr 2010 15:01:23 -0700 Subject: Update release notes and version number for 0.9.2 --- README | 55 ++++++++++++++++++++++++++----------------------------- lib/common.php | 2 +- 2 files changed, 27 insertions(+), 30 deletions(-) (limited to 'lib') diff --git a/README b/README index c687cb240..98ebe1506 100644 --- a/README +++ b/README @@ -2,8 +2,8 @@ README ------ -StatusNet 0.9.1 ("Everybody Hurts") -28 Mar 2010 +StatusNet 0.9.2 ("King of Birds") +21 Apr 2010 This is the README file for StatusNet, the Open Source microblogging platform. It includes installation instructions, descriptions of @@ -77,7 +77,7 @@ for additional terms. New this version ================ -This is a minor bug and feature release since version 0.9.0 released 4 +This is a minor bug and feature release since version 0.9.1 released 28 March 2010. Because of fixes to OStatus bugs, it is highly recommended that all @@ -85,26 +85,23 @@ public sites upgrade to the new version immediately. Notable changes this version: -- Twitter bridge truncates and links back to original for long - notices. -- Changed "Home" link in main menu to "Personal". -- A new memcached plugin (using pecl/memcached versus pecl/memcache) -- Opt-in subscription to update@status.net -- Script to run commands on behalf of a user. -- Better Web UI for long notices. -- A plugin to open external links in their own window or tab -- Fixes to Salmon protocol for compatibility with other systems. -- Updates to latest ActivityStreams definition. -- Twitpic-compatible API for image upload. -- Background deletion of user accounts. -- Better support for HTTP basic authentication with CGI/FastCGI -- Better discovery on OStatus -- Support for PuSH-enabled RSS 2.0 feeds -- OpenID-only mode -- OpenID blacklist/whitelist -- OStatus unit tests - -A full changelog is available at http://status.net/wiki/StatusNet_0.9.1. +- Fixed email notifications for @-replies that come in via OStatus +- OStatus related Fixes to the cloudy theme +- Pass geo locations over Twitter bridge (will only be used if enabled on the Twitter side) +- scripts/showplugins.php - script to dump the list of activated plugins and their settings +- scripts/fixup_blocks.php - script to finds any stray subscriptions in violation of blocks, and removes them +- Allow blocking someone who's not currently subscribed to you (prevents seeing @-replies from them, or them subbing to you in future) +- Default 2-second timeout on Geonames web service lookups +- Improved localization for plugins +- New anti-spam measures: added nofollow rels to group members list, subscribers list +- Shared cache key option for Geonames plugin (lets multi-instance sites share their cached geoname lookups) +- Stability fixes to the TwitterStatusFetcher +- If user allows location sharing but turned off browser location use profile location +- Improved group listing via the API +- Improved FOAF output +- Several other bugfixes + +A full changelog is available at http://status.net/wiki/StatusNet_0.9.2. Prerequisites ============= @@ -216,9 +213,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.9.1.tar.gz + tar zxf statusnet-0.9.2.tar.gz - ...which will make a statusnet-0.9.1 subdirectory in your current + ...which will make a statusnet-0.9.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.) @@ -226,7 +223,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.9.1 /var/www/statusnet + mv statusnet-0.9.2 /var/www/statusnet This will make your StatusNet instance available in the statusnet path of your server, like "http://example.net/statusnet". "microblog" or @@ -641,7 +638,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.9.1. Try these step-by-step +upgrade procedure in StatusNet 0.9.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 @@ -662,7 +659,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 "statusnet.bak". -7. Unpack your StatusNet 0.9.1 tarball and move it to "statusnet" or +7. Unpack your StatusNet 0.9.2 tarball and move it to "statusnet" or wherever your code used to be. 8. Copy the config.php file and avatar directory from your old directory to your new directory. @@ -1499,7 +1496,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.9.1 without reading the "Notice +If you upgraded to StatusNet 0.9.2 without reading the "Notice inboxes" section above, and all your users' 'Personal' tabs are empty, read the "Notice inboxes" section above. diff --git a/lib/common.php b/lib/common.php index 8d2e6b420..b29719b75 100644 --- a/lib/common.php +++ b/lib/common.php @@ -22,7 +22,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } //exit with 200 response, if this is checking fancy from the installer if (isset($_REQUEST['p']) && $_REQUEST['p'] == 'check-fancy') { exit; } -define('STATUSNET_VERSION', '0.9.1'); +define('STATUSNET_VERSION', '0.9.2'); define('LACONICA_VERSION', STATUSNET_VERSION); // compatibility define('STATUSNET_CODENAME', 'Everybody Hurts'); -- cgit v1.2.3-54-g00ecf From 1d94b08efcda56fa5efdef19721bcef21410177a Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 21 Apr 2010 16:24:15 +0200 Subject: Revert "Update release notes and version number for 0.9.2" This reverts commit 98f0d970da98e5b6de18972d033320a191152eb4. Per xopher we're not yet ready to push 0.9.2 theme directories live; we also haven't merged down various things from testing that need to be in the release such as installer fixes. --- README | 55 +++++++++++++++++++++++++++++-------------------------- lib/common.php | 2 +- 2 files changed, 30 insertions(+), 27 deletions(-) (limited to 'lib') diff --git a/README b/README index 98ebe1506..c687cb240 100644 --- a/README +++ b/README @@ -2,8 +2,8 @@ README ------ -StatusNet 0.9.2 ("King of Birds") -21 Apr 2010 +StatusNet 0.9.1 ("Everybody Hurts") +28 Mar 2010 This is the README file for StatusNet, the Open Source microblogging platform. It includes installation instructions, descriptions of @@ -77,7 +77,7 @@ for additional terms. New this version ================ -This is a minor bug and feature release since version 0.9.1 released 28 +This is a minor bug and feature release since version 0.9.0 released 4 March 2010. Because of fixes to OStatus bugs, it is highly recommended that all @@ -85,23 +85,26 @@ public sites upgrade to the new version immediately. Notable changes this version: -- Fixed email notifications for @-replies that come in via OStatus -- OStatus related Fixes to the cloudy theme -- Pass geo locations over Twitter bridge (will only be used if enabled on the Twitter side) -- scripts/showplugins.php - script to dump the list of activated plugins and their settings -- scripts/fixup_blocks.php - script to finds any stray subscriptions in violation of blocks, and removes them -- Allow blocking someone who's not currently subscribed to you (prevents seeing @-replies from them, or them subbing to you in future) -- Default 2-second timeout on Geonames web service lookups -- Improved localization for plugins -- New anti-spam measures: added nofollow rels to group members list, subscribers list -- Shared cache key option for Geonames plugin (lets multi-instance sites share their cached geoname lookups) -- Stability fixes to the TwitterStatusFetcher -- If user allows location sharing but turned off browser location use profile location -- Improved group listing via the API -- Improved FOAF output -- Several other bugfixes - -A full changelog is available at http://status.net/wiki/StatusNet_0.9.2. +- Twitter bridge truncates and links back to original for long + notices. +- Changed "Home" link in main menu to "Personal". +- A new memcached plugin (using pecl/memcached versus pecl/memcache) +- Opt-in subscription to update@status.net +- Script to run commands on behalf of a user. +- Better Web UI for long notices. +- A plugin to open external links in their own window or tab +- Fixes to Salmon protocol for compatibility with other systems. +- Updates to latest ActivityStreams definition. +- Twitpic-compatible API for image upload. +- Background deletion of user accounts. +- Better support for HTTP basic authentication with CGI/FastCGI +- Better discovery on OStatus +- Support for PuSH-enabled RSS 2.0 feeds +- OpenID-only mode +- OpenID blacklist/whitelist +- OStatus unit tests + +A full changelog is available at http://status.net/wiki/StatusNet_0.9.1. Prerequisites ============= @@ -213,9 +216,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.9.2.tar.gz + tar zxf statusnet-0.9.1.tar.gz - ...which will make a statusnet-0.9.2 subdirectory in your current + ...which will make a statusnet-0.9.1 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.) @@ -223,7 +226,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.9.2 /var/www/statusnet + mv statusnet-0.9.1 /var/www/statusnet This will make your StatusNet instance available in the statusnet path of your server, like "http://example.net/statusnet". "microblog" or @@ -638,7 +641,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.9.2. Try these step-by-step +upgrade procedure in StatusNet 0.9.1. 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 @@ -659,7 +662,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 "statusnet.bak". -7. Unpack your StatusNet 0.9.2 tarball and move it to "statusnet" or +7. Unpack your StatusNet 0.9.1 tarball and move it to "statusnet" or wherever your code used to be. 8. Copy the config.php file and avatar directory from your old directory to your new directory. @@ -1496,7 +1499,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.9.2 without reading the "Notice +If you upgraded to StatusNet 0.9.1 without reading the "Notice inboxes" section above, and all your users' 'Personal' tabs are empty, read the "Notice inboxes" section above. diff --git a/lib/common.php b/lib/common.php index b29719b75..8d2e6b420 100644 --- a/lib/common.php +++ b/lib/common.php @@ -22,7 +22,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } //exit with 200 response, if this is checking fancy from the installer if (isset($_REQUEST['p']) && $_REQUEST['p'] == 'check-fancy') { exit; } -define('STATUSNET_VERSION', '0.9.2'); +define('STATUSNET_VERSION', '0.9.1'); define('LACONICA_VERSION', STATUSNET_VERSION); // compatibility define('STATUSNET_CODENAME', 'Everybody Hurts'); -- cgit v1.2.3-54-g00ecf From c78a10b476bb6d84e4056038fea1b8185d20ef46 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Wed, 21 Apr 2010 17:14:25 -0400 Subject: add 'always' parameter to common_shorten_links --- lib/util.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/util.php b/lib/util.php index 81920eb44..e0669a1d5 100644 --- a/lib/util.php +++ b/lib/util.php @@ -855,10 +855,10 @@ function common_linkify($url) { return XMLStringer::estring('a', $attrs, $url); } -function common_shorten_links($text) +function common_shorten_links($text, $always = false) { $maxLength = Notice::maxContent(); - if ($maxLength == 0 || mb_strlen($text) <= $maxLength) return $text; + if (!$always && ($maxLength == 0 || mb_strlen($text) <= $maxLength)) return $text; return common_replace_urls_callback($text, array('File_redirection', 'makeShort')); } -- cgit v1.2.3-54-g00ecf From beaecb18d5b92b913473dfffd545dc436f50cf66 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 22 Apr 2010 08:49:33 -0700 Subject: Add statusnet: prefix for API to JSON and XML output I added the statusnet: prefix to the xml output. This prefix should be declared on the root element of all relevant XML output. I also added two StatusNet-specific fields: * statusnet:html - rendered HTML. Clients shouldn't have to guess at the correct HTML rendering for notices, especially since some of the links depend on context. * statusnet:profile_url - profile URL for a user. You can't count on a user being a local user in a distributed microblogging world. So, this shows the explicit profile_url. --- actions/apidirectmessage.php | 3 ++- actions/apiusershow.php | 2 +- lib/apiaction.php | 42 ++++++++++++++++++++++++++++++++---------- 3 files changed, 35 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/actions/apidirectmessage.php b/actions/apidirectmessage.php index 53da9e0c6..7a0f46274 100644 --- a/actions/apidirectmessage.php +++ b/actions/apidirectmessage.php @@ -232,7 +232,8 @@ class ApiDirectMessageAction extends ApiAuthAction function showXmlDirectMessages() { $this->initDocument('xml'); - $this->elementStart('direct-messages', array('type' => 'array')); + $this->elementStart('direct-messages', array('type' => 'array', + 'xmlns:statusnet' => 'http://status.net/schema/api/1/')); foreach ($this->messages as $m) { $dm_array = $this->directMessageArray($m); diff --git a/actions/apiusershow.php b/actions/apiusershow.php index 6c8fad49b..28993102c 100644 --- a/actions/apiusershow.php +++ b/actions/apiusershow.php @@ -113,7 +113,7 @@ class ApiUserShowAction extends ApiPrivateAuthAction if ($this->format == 'xml') { $this->initDocument('xml'); - $this->showTwitterXmlUser($twitter_user); + $this->showTwitterXmlUser($twitter_user, 'user', true); $this->endDocument('xml'); } elseif ($this->format == 'json') { $this->initDocument('json'); diff --git a/lib/apiaction.php b/lib/apiaction.php index 59dc47c23..6ee0a94d9 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -223,6 +223,10 @@ class ApiAction extends Action } } + // StatusNet-specific + + $twitter_user['statusnet:profile_url'] = $profile->profileurl; + return $twitter_user; } @@ -308,6 +312,10 @@ class ApiAction extends Action $twitter_status['user'] = $twitter_user; } + // StatusNet-specific + + $twitter_status['statusnet:html'] = $notice->rendered; + return $twitter_status; } @@ -475,9 +483,13 @@ class ApiAction extends Action } } - function showTwitterXmlStatus($twitter_status, $tag='status') + function showTwitterXmlStatus($twitter_status, $tag='status', $namespaces=false) { - $this->elementStart($tag); + $attrs = array(); + if ($namespaces) { + $attrs['xmlns:statusnet'] = 'http://status.net/schema/api/1/'; + } + $this->elementStart($tag, $attrs); foreach($twitter_status as $element => $value) { switch ($element) { case 'user': @@ -511,9 +523,13 @@ class ApiAction extends Action $this->elementEnd('group'); } - function showTwitterXmlUser($twitter_user, $role='user') + function showTwitterXmlUser($twitter_user, $role='user', $namespaces=false) { - $this->elementStart($role); + $attrs = array(); + if ($namespaces) { + $attrs['xmlns:statusnet'] = 'http://status.net/schema/api/1/'; + } + $this->elementStart($role, $attrs); foreach($twitter_user as $element => $value) { if ($element == 'status') { $this->showTwitterXmlStatus($twitter_user['status']); @@ -595,7 +611,7 @@ class ApiAction extends Action { $this->initDocument('xml'); $twitter_status = $this->twitterStatusArray($notice); - $this->showTwitterXmlStatus($twitter_status); + $this->showTwitterXmlStatus($twitter_status, 'status', true); $this->endDocument('xml'); } @@ -611,7 +627,8 @@ class ApiAction extends Action { $this->initDocument('xml'); - $this->elementStart('statuses', array('type' => 'array')); + $this->elementStart('statuses', array('type' => 'array', + 'xmlns:statusnet' => 'http://status.net/schema/api/1/')); if (is_array($notice)) { foreach ($notice as $n) { @@ -778,9 +795,13 @@ class ApiAction extends Action $this->elementEnd('entry'); } - function showXmlDirectMessage($dm) + function showXmlDirectMessage($dm, $namespaces=false) { - $this->elementStart('direct_message'); + $attrs = array(); + if ($namespaces) { + $attrs['xmlns:statusnet'] = 'http://status.net/schema/api/1/'; + } + $this->elementStart('direct_message', $attrs); foreach($dm as $element => $value) { switch ($element) { case 'sender': @@ -857,7 +878,7 @@ class ApiAction extends Action { $this->initDocument('xml'); $dmsg = $this->directMessageArray($message); - $this->showXmlDirectMessage($dmsg); + $this->showXmlDirectMessage($dmsg, true); $this->endDocument('xml'); } @@ -974,7 +995,8 @@ class ApiAction extends Action { $this->initDocument('xml'); - $this->elementStart('users', array('type' => 'array')); + $this->elementStart('users', array('type' => 'array', + 'xmlns:statusnet' => 'http://status.net/schema/api/1/')); if (is_array($user)) { foreach ($user as $u) { -- cgit v1.2.3-54-g00ecf From 1b561065b0ff8d7082d8da49750a4bc99a4830e2 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 30 Mar 2010 18:52:21 -0700 Subject: Some initial Doxygen-based documentation for the API --- actions/apistatusesupdate.php | 91 +++ actions/apitimelinefriends.php | 97 ++- lib/apiaction.php | 60 ++ lib/apiauth.php | 18 + scripts/apidocs.config | 1551 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1816 insertions(+), 1 deletion(-) create mode 100644 scripts/apidocs.config (limited to 'lib') diff --git a/actions/apistatusesupdate.php b/actions/apistatusesupdate.php index d4ef6b550..5f3a447c2 100644 --- a/actions/apistatusesupdate.php +++ b/actions/apistatusesupdate.php @@ -33,6 +33,97 @@ * @link http://status.net/ */ +/* External API usage documentation. Please update when you change how this method works. */ + +/*! @page statusesupdate statuses/update + + @section Description + Updates the authenticating user's status. Requires the status parameter specified below. + Request must be a POST. + + @par URL pattern + /api/statuses/update.:format + + @par Formats (:format) + xml, json + + @par HTTP Method(s) + POST + + @par Requires Authentication + Yes + + @param status (Required) The URL-encoded text of the status update. + @param source (Optional) The source of the status. + @param in_reply_to_status_id (Optional) The ID of an existing status that the update is in reply to. + @param lat (Optional) The latitude the status refers to. + @param long (Optional) The longitude the status refers to. + @param media (Optional) a media upload, such as an image or movie file. + + @sa @ref authentication + @sa @ref apiroot + + @subsection usagenotes Usage notes + + @li The URL pattern is relative to the @ref apiroot. + @li If the @e source parameter is not supplied the source of the status will default to 'api'. + @li The XML response uses GeoRSS + to encode the latitude and longitude (see example response below ). + @li Data uploaded via the @e media parameter should be multipart/form-data encoded. + + @subsection exampleusage Example usage + + @verbatim + curl -u username:password http://example.com/api/statuses/update.xml -d status='Howdy!' -d lat='30.468' -d long='-94.743' + @endverbatim + + @subsection exampleresponse Example response + + @verbatim + + + Howdy! + false + Tue Mar 30 23:28:05 +0000 2010 + + api + 26668724 + + + + 30.468 -94.743 + + false + + 25803 + Jed Sanders + jedsanders + Hoop and Holler, Texas + I like to think of myself as America's Favorite. + http://avatar.example.com/25803-48-20080924200604.png + http://jedsanders.net + false + 5 + + + + + + 2 + Wed Sep 24 20:04:00 +0000 2008 + 0 + 0 + UTC + + false + 70 + true + true + + + @endverbatim +*/ + if (!defined('STATUSNET')) { exit(1); } diff --git a/actions/apitimelinefriends.php b/actions/apitimelinefriends.php index 7f80f252e..3c25c049e 100644 --- a/actions/apitimelinefriends.php +++ b/actions/apitimelinefriends.php @@ -28,11 +28,106 @@ * @author Mike Cochrane * @author Robin Millette * @author Zach Copley - * @copyright 2009 StatusNet, Inc. + * @copyright 2009-2010 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/ */ +/* External API usage documentation. Please update when you change how this method works. */ + +/*! @page friendstimeline statuses/friends_timeline + + @section Description + Returns the 20 most recent statuses posted by the authenticating + user and that user's friends. This is the equivalent of "You and + friends" page in the web interface. + + @par URL patterns + @li /api/statuses/friends_timeline.:format + @li /api/statuses/friends_timeline/:id.:format + + @par Formats (:format) + xml, json, rss, atom + + @par ID (:id) + username, user id + + @par HTTP Method(s) + GET + + @par Requires Authentication + Sometimes (see: @ref authentication) + + @param user_id (Optional) Specifies a user by ID + @param screen_name (Optional) Specifies a user by screename (nickname) + @param since_id (Optional) Returns only statuses with an ID greater + than (that is, more recent than) the specified ID. + @param max_id (Optional) Returns only statuses with an ID less than + (that is, older than) or equal to the specified ID. + @param count (Optional) Specifies the number of statuses to retrieve. + @param page (Optional) Specifies the page of results to retrieve. + + @sa @ref authentication + @sa @ref apiroot + + @subsection usagenotes Usage notes + @li The URL pattern is relative to the @ref apiroot. + @li The XML response uses GeoRSS + to encode the latitude and longitude (see example response below ). + + @subsection exampleusage Example usage + + @verbatim + curl http://identi.ca/api/statuses/friends_timeline/evan.xml?count=1&page=2 + @endverbatim + + @subsection exampleresponse Example response + + @verbatim + + + + back from the !yul !drupal meet with Evolving Web folk, @anarcat, @webchick and others, and an interesting refresher on SQL indexing + false + Wed Mar 31 01:33:02 +0000 2010 + + <a href="http://code.google.com/p/microblog-purple/">mbpidgin</a> + 26674201 + + + + false + + 246 + Mark + lambic + Montreal, Canada + Geek + http://avatar.identi.ca/246-48-20080702141545.png + http://lambic.co.uk + false + 73 + #F0F2F5 + + #002E6E + #CEE1E9 + + 58 + Wed Jul 02 14:12:15 +0000 2008 + 2 + -14400 + US/Eastern + + false + 933 + false + false + + + + @endverbatim +*/ + if (!defined('STATUSNET')) { exit(1); } diff --git a/lib/apiaction.php b/lib/apiaction.php index d5580abd3..f206f1d5c 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -32,6 +32,66 @@ * @link http://status.net/ */ +/* External API usage documentation. Please update when you change how the API works. */ + +/*! @mainpage StatusNet REST API + + @section Introduction + + Some explanatory text about the API would be nice. + + @section API Methods + + @subsection timelinesmethods_sec Timeline Methods + + @li @ref friendstimeline + + @subsection statusmethods_sec Status Methods + + @li @ref statusesupdate + + @subsection usermethods_sec User Methods + + @subsection directmessagemethods_sec Direct Message Methods + + @subsection friendshipmethods_sec Friendship Methods + + @subsection socialgraphmethods_sec Social Graph Methods + + @subsection accountmethods_sec Account Methods + + @subsection favoritesmethods_sec Favorites Methods + + @subsection blockmethods_sec Block Methods + + @subsection oauthmethods_sec OAuth Methods + + @subsection helpmethods_sec Help Methods + + @subsection groupmethods_sec Group Methods + + @page apiroot API Root + + The URLs for methods referred to in this API documentation are + relative to the StatusNet API root. The API root is determined by the + site's @b server and @b path variables, which are generally specified + in config.php. For example: + + @code + $config['site']['server'] = 'example.org'; + $config['site']['path'] = 'statusnet' + @endcode + + The pattern for a site's API root is: @c protocol://server/path/api E.g: + + @c http://example.org/statusnet/api + + The @b path can be empty. In that case the API root would simply be: + + @c http://example.org/api + +*/ + if (!defined('STATUSNET')) { exit(1); } diff --git a/lib/apiauth.php b/lib/apiauth.php index d6ad7e021..8c3998888 100644 --- a/lib/apiauth.php +++ b/lib/apiauth.php @@ -34,6 +34,24 @@ * @link http://status.net/ */ +/* External API usage documentation. Please update when you change how this method works. */ + +/*! @page authentication Authentication + + StatusNet supports HTTP Basic Authentication and OAuth for API calls. + + @warning Currently, users who have created accounts without setting a + password via OpenID, Facebook Connect, etc., cannot use the API until + they set a password with their account settings panel. + + @section HTTP Basic Auth + + + + @section OAuth + +*/ + if (!defined('STATUSNET')) { exit(1); } diff --git a/scripts/apidocs.config b/scripts/apidocs.config new file mode 100644 index 000000000..fdbe35ba1 --- /dev/null +++ b/scripts/apidocs.config @@ -0,0 +1,1551 @@ +# Doxyfile 1.6.2 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = "StatusNet REST API" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ../apidocs + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = NO + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = NO + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = NO + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it parses. +# With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this tag. +# The format is ext=language, where ext is a file extension, and language is one of +# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, +# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = NO + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = NO + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = NO + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = NO + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= NO + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = NO + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = NO + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = NO + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../actions ../lib + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = api*.php + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = *Action Api* if* + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = NO + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. +# For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's +# filter section matches. +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be implemented using a PHP enabled web server instead of at the web client using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server based approach is that it scales better to large projects and allows full text search. The disadvances is that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = NO + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES -- cgit v1.2.3-54-g00ecf From f852a1931b352ede261ec4597abdbb63683cc9a8 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 16 Apr 2010 17:54:43 -0700 Subject: Add docs for public_timeline --- actions/apitimelinepublic.php | 89 +++++++++++++++++++++++++++++++++++++++++++ lib/apiaction.php | 1 + 2 files changed, 90 insertions(+) (limited to 'lib') diff --git a/actions/apitimelinepublic.php b/actions/apitimelinepublic.php index 903461425..30f9f4cda 100644 --- a/actions/apitimelinepublic.php +++ b/actions/apitimelinepublic.php @@ -55,6 +55,95 @@ require_once INSTALLDIR . '/lib/apiprivateauth.php'; * @link http://status.net/ */ +/* External API usage documentation. Please update when you change how this method works. */ + +/*! @page publictimeline statuses/public_timeline + + @section Description + Returns the 20 most recent notices from users throughout the system who have + uploaded their own avatars. Depending on configuration, it may or may not + not include notices from automatic posting services. + + @par URL patterns + @li /api/statuses/public_timeline.:format + + @par Formats (:format) + xml, json, rss, atom + + @par HTTP Method(s) + GET + + @par Requires Authentication + No + + @param since_id (Optional) Returns only statuses with an ID greater + than (that is, more recent than) the specified ID. + @param max_id (Optional) Returns only statuses with an ID less than + (that is, older than) or equal to the specified ID. + @param count (Optional) Specifies the number of statuses to retrieve. + @param page (Optional) Specifies the page of results to retrieve. + + @sa @ref apiroot + + @subsection usagenotes Usage notes + @li The URL pattern is relative to the @ref apiroot. + @li The XML response uses GeoRSS + to encode the latitude and longitude (see example response below ). + + @subsection exampleusage Example usage + + @verbatim + curl http://identi.ca/api/statuses/friends_timeline/evan.xml?count=1&page=2 + @endverbatim + + @subsection exampleresponse Example response + + @verbatim + + + + @skwashd oh, commbank reenabled me super quick both times. but disconcerting when you don't expect it though + false + Sat Apr 17 00:49:12 +0000 2010 + 28838393 + xmpp + 28838456 + 39303 + skwashd + + false + + 44517 + joshua may + notjosh + + + http://avatar.identi.ca/44517-48-20090321004106.jpeg + + false + 17 + + + + + + 20 + Sat Mar 21 00:40:25 +0000 2009 + 0 + 0 + UTC + + false + 100 + false + false + + + [....] + +@endverbatim +*/ + class ApiTimelinePublicAction extends ApiPrivateAuthAction { diff --git a/lib/apiaction.php b/lib/apiaction.php index f206f1d5c..a3c34a91b 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -44,6 +44,7 @@ @subsection timelinesmethods_sec Timeline Methods + @li @ref publictimeline @li @ref friendstimeline @subsection statusmethods_sec Status Methods -- cgit v1.2.3-54-g00ecf From 8fd0059bf69ed16ed4efad7b8e16dc2afda32e18 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 23 Apr 2010 15:40:48 -0700 Subject: Test cases and fixes for Atom and RSS content decoding. Fix extraction of Atom and ; we were failing to escape plaintext source data to HTML, and doing an extraneous double-deescape on HTML source resulting in breakage of notices containing text that looks like HTML. Only was working correctly previously. Fixes for RSS2 content processing: we were failing to load at all due to using wrong element name, and were applying an extraneous de-escape for rather than the escaping that is required to turn plaintext into HTML. (Per spec, must be plaintext.) --- lib/activity.php | 14 ++++++-- lib/activityutils.php | 12 +++++-- tests/ActivityParseTests.php | 77 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/activity.php b/lib/activity.php index 5d6230c6d..27f09ab4d 100644 --- a/lib/activity.php +++ b/lib/activity.php @@ -83,6 +83,7 @@ class Activity const CREATOR = 'creator'; const CONTENTNS = 'http://purl.org/rss/1.0/modules/content/'; + const ENCODED = 'encoded'; public $actor; // an ActivityObject public $verb; // a string (the URL) @@ -268,14 +269,21 @@ class Activity $this->title = ActivityUtils::childContent($item, ActivityObject::TITLE, self::RSS); - $contentEl = ActivityUtils::child($item, ActivityUtils::CONTENT, self::CONTENTNS); + $contentEl = ActivityUtils::child($item, self::ENCODED, self::CONTENTNS); if (!empty($contentEl)) { - $this->content = htmlspecialchars_decode($contentEl->textContent, ENT_QUOTES); + // XML node's text content is HTML; no further processing needed. + $this->content = $contentEl->textContent; } else { $descriptionEl = ActivityUtils::child($item, self::DESCRIPTION, self::RSS); if (!empty($descriptionEl)) { - $this->content = htmlspecialchars_decode($descriptionEl->textContent, ENT_QUOTES); + // Per spec, must be plaintext. + // In practice, often there's HTML... but these days good + // feeds are using which is explicitly + // real HTML. + // We'll treat this following spec, and do HTML escaping + // to convert from plaintext to HTML. + $this->content = htmlspecialchars($descriptionEl->textContent); } } diff --git a/lib/activityutils.php b/lib/activityutils.php index a7e99fb11..401fd7fc2 100644 --- a/lib/activityutils.php +++ b/lib/activityutils.php @@ -213,11 +213,19 @@ class ActivityUtils // slavishly following http://atompub.org/rfc4287.html#rfc.section.4.1.3.3 if (empty($type) || $type == 'text') { - return $el->textContent; + // We have plaintext saved as the XML text content. + // Since we want HTML, we need to escape any special chars. + return htmlspecialchars($el->textContent); } else if ($type == 'html') { + // We have HTML saved as the XML text content. + // No additional processing required once we've got it. $text = $el->textContent; - return htmlspecialchars_decode($text, ENT_QUOTES); + return $text; } else if ($type == 'xhtml') { + // Per spec, the contains a single + // HTML
with XHTML namespace on it as a child node. + // We need to pull all of that
's child nodes and + // serialize them back to an (X)HTML source fragment. $divEl = ActivityUtils::child($el, 'div', 'http://www.w3.org/1999/xhtml'); if (empty($divEl)) { return null; diff --git a/tests/ActivityParseTests.php b/tests/ActivityParseTests.php index 4563da914..378478d74 100644 --- a/tests/ActivityParseTests.php +++ b/tests/ActivityParseTests.php @@ -32,6 +32,18 @@ class ActivityParseTests extends PHPUnit_Framework_TestCase $this->assertEquals('tag:versioncentral.example.org,2009:/change/1643245', $act->objects[0]->id); } + public function testExample2() + { + global $_example2; + $dom = DOMDocument::loadXML($_example2); + $act = new Activity($dom->documentElement); + + $this->assertFalse(empty($act)); + // Did we handle correctly with a typical payload? + $this->assertEquals("

Geraldine posted a Photo on PhotoPanic

\n " . + "", trim($act->content)); + } + public function testExample3() { global $_example3; @@ -305,6 +317,71 @@ class ActivityParseTests extends PHPUnit_Framework_TestCase } + public function testAtomContent() + { + $tests = array(array("Some regular plain text.", + "Some regular plain text."), + array("<b>this is not HTML</b>", + "<b>this is not HTML</b>"), + array("Some regular plain HTML.", + "Some regular plain HTML."), + array("<b>this is too HTML</b>", + "this is too HTML"), + array("&lt;b&gt;but this is not HTML!&lt;/b&gt;", + "<b>but this is not HTML!</b>"), + array("
Some regular plain XHTML.
", + "Some regular plain XHTML."), + array("
This is some XHTML!
", + "This is some XHTML!"), + array("
<b>This is not some XHTML!</b>
", + "<b>This is not some XHTML!</b>"), + array("
&lt;b&gt;This is not some XHTML either!&lt;/b&gt;
", + "&lt;b&gt;This is not some XHTML either!&lt;/b&gt;")); + foreach ($tests as $data) { + list($source, $output) = $data; + $xml = "" . + "http://example.com/fakeid" . + "Test" . + "Atom content tests" . + $source . + ""; + $dom = DOMDocument::loadXML($xml); + $act = new Activity($dom->documentElement); + + $this->assertFalse(empty($act)); + $this->assertEquals($output, trim($act->content)); + } + } + + public function testRssContent() + { + $tests = array(array("Some regular plain HTML.", + "Some regular plain HTML."), + array("Some <b>exciting bold HTML</b>", + "Some exciting bold HTML"), + array("Some &lt;b&gt;escaped non-HTML.&lt;/b&gt;", + "Some <b>escaped non-HTML.</b>"), + array("Some plain text.", + "Some plain text."), + array("Some <b>non-HTML text</b>", + "Some <b>non-HTML text</b>"), + array("Some &lt;b&gt;double-escaped text&lt;/b&gt;", + "Some &lt;b&gt;double-escaped text&lt;/b&gt;")); + foreach ($tests as $data) { + list($source, $output) = $data; + $xml = "" . + "http://example.com/fakeid" . + "RSS content tests" . + $source . + ""; + $dom = DOMDocument::loadXML($xml); + $act = new Activity($dom->documentElement); + + $this->assertFalse(empty($act)); + $this->assertEquals($output, trim($act->content)); + } + } + } $_example1 = << Date: Wed, 28 Apr 2010 23:06:08 +0000 Subject: Fix charset setting for plugin localizations; default setting was blanking out non-ASCII chars. Needed for eg Bulgarian translation of Facebook plugin, was previously showing all as ???s. Now works yay! --- lib/plugin.php | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/plugin.php b/lib/plugin.php index 65ccdafbb..f63bdf309 100644 --- a/lib/plugin.php +++ b/lib/plugin.php @@ -91,6 +91,7 @@ class Plugin $path = INSTALLDIR . "/plugins/$name/locale"; if (file_exists($path) && is_dir($path)) { bindtextdomain($name, $path); + bind_textdomain_codeset($name, 'UTF-8'); } } } -- cgit v1.2.3-54-g00ecf From a5761dd814e385c8479708334d884522dfa614a9 Mon Sep 17 00:00:00 2001 From: Zachary Copley Date: Tue, 20 Apr 2010 15:01:23 -0700 Subject: Update release notes and version number for 0.9.2 --- README | 55 ++++++++++++++++++++++++++----------------------------- lib/common.php | 2 +- 2 files changed, 27 insertions(+), 30 deletions(-) (limited to 'lib') diff --git a/README b/README index 1e244c448..ddc725d3c 100644 --- a/README +++ b/README @@ -2,8 +2,8 @@ README ------ -StatusNet 0.9.1 ("Everybody Hurts") -28 Mar 2010 +StatusNet 0.9.2 ("King of Birds") +21 Apr 2010 This is the README file for StatusNet, the Open Source microblogging platform. It includes installation instructions, descriptions of @@ -77,7 +77,7 @@ for additional terms. New this version ================ -This is a minor bug and feature release since version 0.9.0 released 4 +This is a minor bug and feature release since version 0.9.1 released 28 March 2010. Because of fixes to OStatus bugs, it is highly recommended that all @@ -85,26 +85,23 @@ public sites upgrade to the new version immediately. Notable changes this version: -- Twitter bridge truncates and links back to original for long - notices. -- Changed "Home" link in main menu to "Personal". -- A new memcached plugin (using pecl/memcached versus pecl/memcache) -- Opt-in subscription to update@status.net -- Script to run commands on behalf of a user. -- Better Web UI for long notices. -- A plugin to open external links in their own window or tab -- Fixes to Salmon protocol for compatibility with other systems. -- Updates to latest ActivityStreams definition. -- Twitpic-compatible API for image upload. -- Background deletion of user accounts. -- Better support for HTTP basic authentication with CGI/FastCGI -- Better discovery on OStatus -- Support for PuSH-enabled RSS 2.0 feeds -- OpenID-only mode -- OpenID blacklist/whitelist -- OStatus unit tests - -A full changelog is available at http://status.net/wiki/StatusNet_0.9.1. +- Fixed email notifications for @-replies that come in via OStatus +- OStatus related Fixes to the cloudy theme +- Pass geo locations over Twitter bridge (will only be used if enabled on the Twitter side) +- scripts/showplugins.php - script to dump the list of activated plugins and their settings +- scripts/fixup_blocks.php - script to finds any stray subscriptions in violation of blocks, and removes them +- Allow blocking someone who's not currently subscribed to you (prevents seeing @-replies from them, or them subbing to you in future) +- Default 2-second timeout on Geonames web service lookups +- Improved localization for plugins +- New anti-spam measures: added nofollow rels to group members list, subscribers list +- Shared cache key option for Geonames plugin (lets multi-instance sites share their cached geoname lookups) +- Stability fixes to the TwitterStatusFetcher +- If user allows location sharing but turned off browser location use profile location +- Improved group listing via the API +- Improved FOAF output +- Several other bugfixes + +A full changelog is available at http://status.net/wiki/StatusNet_0.9.2. Prerequisites ============= @@ -216,9 +213,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.9.1.tar.gz + tar zxf statusnet-0.9.2.tar.gz - ...which will make a statusnet-0.9.1 subdirectory in your current + ...which will make a statusnet-0.9.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.) @@ -226,7 +223,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.9.1 /var/www/statusnet + mv statusnet-0.9.2 /var/www/statusnet This will make your StatusNet instance available in the statusnet path of your server, like "http://example.net/statusnet". "microblog" or @@ -641,7 +638,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.9.1. Try these step-by-step +upgrade procedure in StatusNet 0.9.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 @@ -662,7 +659,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 "statusnet.bak". -7. Unpack your StatusNet 0.9.1 tarball and move it to "statusnet" or +7. Unpack your StatusNet 0.9.2 tarball and move it to "statusnet" or wherever your code used to be. 8. Copy the config.php file and avatar directory from your old directory to your new directory. @@ -1525,7 +1522,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.9.1 without reading the "Notice +If you upgraded to StatusNet 0.9.2 without reading the "Notice inboxes" section above, and all your users' 'Personal' tabs are empty, read the "Notice inboxes" section above. diff --git a/lib/common.php b/lib/common.php index 8d2e6b420..b29719b75 100644 --- a/lib/common.php +++ b/lib/common.php @@ -22,7 +22,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } //exit with 200 response, if this is checking fancy from the installer if (isset($_REQUEST['p']) && $_REQUEST['p'] == 'check-fancy') { exit; } -define('STATUSNET_VERSION', '0.9.1'); +define('STATUSNET_VERSION', '0.9.2'); define('LACONICA_VERSION', STATUSNET_VERSION); // compatibility define('STATUSNET_CODENAME', 'Everybody Hurts'); -- cgit v1.2.3-54-g00ecf From ecfe6b89443227854c057bb45b107368b860ad02 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 29 Apr 2010 16:08:20 -0700 Subject: Update codename in common.php --- lib/common.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/common.php b/lib/common.php index b29719b75..064f6f73a 100644 --- a/lib/common.php +++ b/lib/common.php @@ -25,7 +25,7 @@ if (isset($_REQUEST['p']) && $_REQUEST['p'] == 'check-fancy') { exit; } define('STATUSNET_VERSION', '0.9.2'); define('LACONICA_VERSION', STATUSNET_VERSION); // compatibility -define('STATUSNET_CODENAME', 'Everybody Hurts'); +define('STATUSNET_CODENAME', 'King of Birds'); define('AVATAR_PROFILE_SIZE', 96); define('AVATAR_STREAM_SIZE', 48); -- cgit v1.2.3-54-g00ecf From 5414396a2ee9f1401d69b60969e04a1941e24e21 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 30 Apr 2010 14:41:54 -0700 Subject: IM cleanup on 1.0.x branch: * Fake_XMPP back to Queued_XMPP, refactor how we use it and don't create objects and load classes until we need them. * fix fatal error in IM settings while waiting for a Jabber confirmation. * Caching fix for user_im_prefs * fix for saving multiple transport settings * some fixes for AIM & using normalized addresses for lookups --- actions/imsettings.php | 17 +++--- classes/User_im_prefs.php | 23 ++++++++ classes/statusnet.ini | 6 ++- lib/implugin.php | 25 ++++++--- plugins/Aim/AimPlugin.php | 9 +++- plugins/Aim/README | 2 +- plugins/Xmpp/Fake_XMPP.php | 114 ---------------------------------------- plugins/Xmpp/Queued_XMPP.php | 121 +++++++++++++++++++++++++++++++++++++++++++ plugins/Xmpp/XmppPlugin.php | 27 +++++----- 9 files changed, 198 insertions(+), 146 deletions(-) delete mode 100644 plugins/Xmpp/Fake_XMPP.php create mode 100644 plugins/Xmpp/Queued_XMPP.php (limited to 'lib') diff --git a/actions/imsettings.php b/actions/imsettings.php index 2c2606b76..662b1063e 100644 --- a/actions/imsettings.php +++ b/actions/imsettings.php @@ -133,8 +133,7 @@ class ImsettingsAction extends ConnectSettingsAction 'message with further instructions. '. '(Did you add %s to your buddy list?)'), $transport_info['display'], - $transport_info['daemon_screenname'], - jabber_daemon_address())); + $transport_info['daemon_screenname'])); $this->hidden('screenname', $confirm->address); // TRANS: Button label to cancel an IM address confirmation procedure. $this->submit('cancel', _m('BUTTON','Cancel')); @@ -163,12 +162,11 @@ class ImsettingsAction extends ConnectSettingsAction 'action' => common_local_url('imsettings'))); $this->elementStart('fieldset', array('id' => 'settings_im_preferences')); - $this->element('legend', null, _('Preferences')); + // TRANS: Header for IM preferences form. + $this->element('legend', null, _('IM Preferences')); $this->hidden('token', common_session_token()); $this->elementStart('table'); $this->elementStart('tr'); - // TRANS: Header for IM preferences form. - $this->element('th', null, _('IM Preferences')); foreach($user_im_prefs_by_transport as $transport=>$user_im_prefs) { $this->element('th', null, $transports[$transport]['display']); @@ -278,19 +276,20 @@ class ImsettingsAction extends ConnectSettingsAction $user = common_current_user(); $user_im_prefs = new User_im_prefs(); + $user_im_prefs->query('BEGIN'); $user_im_prefs->user_id = $user->id; if($user_im_prefs->find() && $user_im_prefs->fetch()) { $preferences = array('notify', 'updatefrompresence', 'replies', 'microid'); - $user_im_prefs->query('BEGIN'); do { $original = clone($user_im_prefs); + $new = clone($user_im_prefs); foreach($preferences as $preference) { - $user_im_prefs->$preference = $this->boolean($user_im_prefs->transport . '_' . $preference); + $new->$preference = $this->boolean($new->transport . '_' . $preference); } - $result = $user_im_prefs->update($original); + $result = $new->update($original); if ($result === false) { common_log_db_error($user, 'UPDATE', __FILE__); @@ -299,8 +298,8 @@ class ImsettingsAction extends ConnectSettingsAction return; } }while($user_im_prefs->fetch()); - $user_im_prefs->query('COMMIT'); } + $user_im_prefs->query('COMMIT'); // TRANS: Confirmation message for successful IM preferences save. $this->showForm(_('Preferences saved.'), true); } diff --git a/classes/User_im_prefs.php b/classes/User_im_prefs.php index 8ecdfe9fa..75be8969e 100644 --- a/classes/User_im_prefs.php +++ b/classes/User_im_prefs.php @@ -68,4 +68,27 @@ class User_im_prefs extends Memcached_DataObject { return array(false,false); } + + /** + * We have two compound keys with unique constraints: + * (transport, user_id) which is our primary key, and + * (transport, screenname) which is an additional constraint. + * + * Currently there's not a way to represent that second key + * in the general keys list, so we're adding it here to the + * list of keys to use for caching, ensuring that it gets + * cleared as well when we change. + * + * @return array of cache keys + */ + function _allCacheKeys() + { + $ukeys = 'transport,screenname'; + $uvals = $this->transport . ',' . $this->screenname; + + $ckeys = parent::_allCacheKeys(); + $ckeys[] = $this->cacheKey($this->tableName(), $ukeys, $uvals); + return $ckeys; + } + } diff --git a/classes/statusnet.ini b/classes/statusnet.ini index d13fdfa52..b57d86226 100644 --- a/classes/statusnet.ini +++ b/classes/statusnet.ini @@ -647,8 +647,10 @@ modified = 384 [user_im_prefs__keys] user_id = K transport = K -transport = U -screenname = U +; There's another unique index on (transport, screenname) +; but we have no way to represent a compound index other than +; the primary key in here. To ensure proper cache purging, +; we need to tweak the class. [user_urlshortener_prefs] user_id = 129 diff --git a/lib/implugin.php b/lib/implugin.php index 7302859a4..7125aaee8 100644 --- a/lib/implugin.php +++ b/lib/implugin.php @@ -107,10 +107,15 @@ abstract class ImPlugin extends Plugin * receive a raw message * Raw IM data is taken from the incoming queue, and passed to this function. * It should parse the raw message and call handle_incoming() + * + * Returning false may CAUSE REPROCESSING OF THE QUEUE ITEM, and should + * be used for temporary failures only. For permanent failures such as + * unrecognized addresses, return true to indicate your processing has + * completed. * * @param object $data raw IM data * - * @return boolean success value + * @return boolean true if processing completed, false for temporary failures */ abstract function receive_raw_message($data); @@ -185,9 +190,12 @@ abstract class ImPlugin extends Plugin */ function get_user_im_prefs_from_screenname($screenname) { - if($user_im_prefs = User_im_prefs::pkeyGet( array('transport' => $this->transport, 'screenname' => $screenname) )){ + $user_im_prefs = User_im_prefs::pkeyGet( + array('transport' => $this->transport, + 'screenname' => $this->normalize($screenname))); + if ($user_im_prefs) { return $user_im_prefs; - }else{ + } else { return false; } } @@ -203,9 +211,9 @@ abstract class ImPlugin extends Plugin function get_screenname($user) { $user_im_prefs = $this->get_user_im_prefs_from_user($user); - if($user_im_prefs){ + if ($user_im_prefs) { return $user_im_prefs->screenname; - }else{ + } else { return false; } } @@ -220,9 +228,12 @@ abstract class ImPlugin extends Plugin */ function get_user_im_prefs_from_user($user) { - if($user_im_prefs = User_im_prefs::pkeyGet( array('transport' => $this->transport, 'user_id' => $user->id) )){ + $user_im_prefs = User_im_prefs::pkeyGet( + array('transport' => $this->transport, + 'user_id' => $user->id)); + if ($user_im_prefs){ return $user_im_prefs; - }else{ + } else { return false; } } diff --git a/plugins/Aim/AimPlugin.php b/plugins/Aim/AimPlugin.php index 3855d1fb0..30da1dbc7 100644 --- a/plugins/Aim/AimPlugin.php +++ b/plugins/Aim/AimPlugin.php @@ -126,6 +126,11 @@ class AimPlugin extends ImPlugin return true; } + /** + * Accept a queued input message. + * + * @return true if processing completed, false if message should be reprocessed + */ function receive_raw_message($message) { $info=Aim::getMessageInfo($message); @@ -133,7 +138,9 @@ class AimPlugin extends ImPlugin $user = $this->get_user($from); $notice_text = $info['message']; - return $this->handle_incoming($from, $notice_text); + $this->handle_incoming($from, $notice_text); + + return true; } function initialize(){ diff --git a/plugins/Aim/README b/plugins/Aim/README index 046591738..7d486a036 100644 --- a/plugins/Aim/README +++ b/plugins/Aim/README @@ -6,7 +6,7 @@ add "addPlugin('aim', array('setting'=>'value', 'setting2'=>'value2', ...);" to the bottom of your config.php -The daemon included with this plugin must be running. It will be started by +scripts/imdaemon.php included with StatusNet must be running. It 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. diff --git a/plugins/Xmpp/Fake_XMPP.php b/plugins/Xmpp/Fake_XMPP.php deleted file mode 100644 index 0f7cfd3b4..000000000 --- a/plugins/Xmpp/Fake_XMPP.php +++ /dev/null @@ -1,114 +0,0 @@ -. - * - * @category Network - * @package StatusNet - * @author Brion Vibber - * @copyright 2010 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 Fake_XMPP extends XMPPHP_XMPP -{ - public $would_be_sent = null; - - /** - * Constructor - * - * @param string $host - * @param integer $port - * @param string $user - * @param string $password - * @param string $resource - * @param string $server - * @param boolean $printlog - * @param string $loglevel - */ - public function __construct($host, $port, $user, $password, $resource, $server = null, $printlog = false, $loglevel = null) - { - parent::__construct($host, $port, $user, $password, $resource, $server, $printlog, $loglevel); - - // We use $host to connect, but $server to build JIDs if specified. - // This seems to fix an upstream bug where $host was used to build - // $this->basejid, never seen since it isn't actually used in the base - // classes. - if (!$server) { - $server = $this->host; - } - $this->basejid = $this->user . '@' . $server; - - // Normally the fulljid is filled out by the server at resource binding - // time, but we need to do it since we're not talking to a real server. - $this->fulljid = "{$this->basejid}/{$this->resource}"; - } - - /** - * Send a formatted message to the outgoing queue for later forwarding - * to a real XMPP connection. - * - * @param string $msg - */ - public function send($msg, $timeout=NULL) - { - $this->would_be_sent = $msg; - } - - //@{ - /** - * Stream i/o functions disabled; only do output - */ - public function connect($timeout = 30, $persistent = false, $sendinit = true) - { - throw new Exception("Can't connect to server from fake XMPP."); - } - - public function disconnect() - { - throw new Exception("Can't connect to server from fake XMPP."); - } - - public function process() - { - throw new Exception("Can't read stream from fake XMPP."); - } - - public function processUntil($event, $timeout=-1) - { - throw new Exception("Can't read stream from fake XMPP."); - } - - public function read() - { - throw new Exception("Can't read stream from fake XMPP."); - } - - public function readyToProcess() - { - throw new Exception("Can't read stream from fake XMPP."); - } - //@} -} - diff --git a/plugins/Xmpp/Queued_XMPP.php b/plugins/Xmpp/Queued_XMPP.php new file mode 100644 index 000000000..73eff2246 --- /dev/null +++ b/plugins/Xmpp/Queued_XMPP.php @@ -0,0 +1,121 @@ +. + * + * @category Network + * @package StatusNet + * @author Brion Vibber + * @copyright 2010 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 Queued_XMPP extends XMPPHP_XMPP +{ + /** + * Reference to the XmppPlugin object we're hooked up to. + */ + public $plugin; + + /** + * Constructor + * + * @param XmppPlugin $plugin + * @param string $host + * @param integer $port + * @param string $user + * @param string $password + * @param string $resource + * @param string $server + * @param boolean $printlog + * @param string $loglevel + */ + public function __construct($plugin, $host, $port, $user, $password, $resource, $server = null, $printlog = false, $loglevel = null) + { + $this->plugin = $plugin; + + parent::__construct($host, $port, $user, $password, $resource, $server, $printlog, $loglevel); + + // We use $host to connect, but $server to build JIDs if specified. + // This seems to fix an upstream bug where $host was used to build + // $this->basejid, never seen since it isn't actually used in the base + // classes. + if (!$server) { + $server = $this->host; + } + $this->basejid = $this->user . '@' . $server; + + // Normally the fulljid is filled out by the server at resource binding + // time, but we need to do it since we're not talking to a real server. + $this->fulljid = "{$this->basejid}/{$this->resource}"; + } + + /** + * Send a formatted message to the outgoing queue for later forwarding + * to a real XMPP connection. + * + * @param string $msg + */ + public function send($msg, $timeout=NULL) + { + $this->plugin->enqueue_outgoing_raw($msg); + } + + //@{ + /** + * Stream i/o functions disabled; only do output + */ + public function connect($timeout = 30, $persistent = false, $sendinit = true) + { + throw new Exception("Can't connect to server from fake XMPP."); + } + + public function disconnect() + { + throw new Exception("Can't connect to server from fake XMPP."); + } + + public function process() + { + throw new Exception("Can't read stream from fake XMPP."); + } + + public function processUntil($event, $timeout=-1) + { + throw new Exception("Can't read stream from fake XMPP."); + } + + public function read() + { + throw new Exception("Can't read stream from fake XMPP."); + } + + public function readyToProcess() + { + throw new Exception("Can't read stream from fake XMPP."); + } + //@} + +} + diff --git a/plugins/Xmpp/XmppPlugin.php b/plugins/Xmpp/XmppPlugin.php index 03bf47fea..a2521536b 100644 --- a/plugins/Xmpp/XmppPlugin.php +++ b/plugins/Xmpp/XmppPlugin.php @@ -60,8 +60,6 @@ class XmppPlugin extends ImPlugin public $transport = 'xmpp'; - protected $fake_xmpp; - function getDisplayName(){ return _m('XMPP/Jabber/GTalk'); } @@ -292,7 +290,7 @@ class XmppPlugin extends ImPlugin require_once 'XMPP.php'; return false; case 'Sharing_XMPP': - case 'Fake_XMPP': + case 'Queued_XMPP': require_once $dir . '/'.$cls.'.php'; return false; case 'XmppManager': @@ -317,9 +315,7 @@ class XmppPlugin extends ImPlugin function send_message($screenname, $body) { - $this->fake_xmpp->message($screenname, $body, 'chat'); - $this->enqueue_outgoing_raw($this->fake_xmpp->would_be_sent); - return true; + $this->queuedConnection()->message($screenname, $body, 'chat'); } function send_notice($screenname, $notice) @@ -327,8 +323,7 @@ class XmppPlugin extends ImPlugin $msg = $this->format_notice($notice); $entry = $this->format_entry($notice); - $this->fake_xmpp->message($screenname, $msg, 'chat', null, $entry); - $this->enqueue_outgoing_raw($this->fake_xmpp->would_be_sent); + $this->queuedConnection()->message($screenname, $msg, 'chat', null, $entry); return true; } @@ -385,10 +380,19 @@ class XmppPlugin extends ImPlugin return true; } - return $this->handle_incoming($from, $pl['body']); + $this->handle_incoming($from, $pl['body']); + + return true; } - function initialize(){ + /** + * Build a queue-proxied XMPP interface object. Any outgoing messages + * will be run back through us for enqueing rather than sent directly. + * + * @return Queued_XMPP + * @throws Exception if server settings are invalid. + */ + function queuedConnection(){ if(!isset($this->server)){ throw new Exception("must specify a server"); } @@ -402,7 +406,7 @@ class XmppPlugin extends ImPlugin throw new Exception("must specify a password"); } - $this->fake_xmpp = new Fake_XMPP($this->host ? + return new Queued_XMPP($this, $this->host ? $this->host : $this->server, $this->port, @@ -415,7 +419,6 @@ class XmppPlugin extends ImPlugin $this->debug ? XMPPHP_Log::LEVEL_VERBOSE : null ); - return true; } function onPluginVersion(&$versions) -- cgit v1.2.3-54-g00ecf From 4fe00a3075c10c5b2168ac2b4996a32055a799ee Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Mon, 3 May 2010 23:02:25 -0400 Subject: When handling incoming mail, skip everything after a blank line if we already have content --- lib/mailhandler.php | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib') diff --git a/lib/mailhandler.php b/lib/mailhandler.php index 890f6d5b4..e9ba41839 100644 --- a/lib/mailhandler.php +++ b/lib/mailhandler.php @@ -265,6 +265,10 @@ class MailHandler if (preg_match('/^\s*Begin\s+forward/', $line)) { break; } + // skip everything after a blank line if we already have content + if ($output !== '' && $line === '') { + break; + } $output .= ' ' . $line; } -- cgit v1.2.3-54-g00ecf From bb94b78e8997ba1b66ddde7ad46653bfa6f958e6 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 4 May 2010 18:43:32 -0700 Subject: Handle timeout more gracefully in background pings Added a 2-second default timeout for XMLRPC/extended pings, configurable as [ping,timeout]. No longer repeating the entire ping section if we had an HTTP error during a submission. For now, dropping the bad item and continuing on with others. (Todo: individual retry and cleaner discards of blacklisted broken-for-now sites.) --- lib/default.php | 3 ++- lib/ping.php | 10 +++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/default.php b/lib/default.php index fa4ece10a..ab5f294de 100644 --- a/lib/default.php +++ b/lib/default.php @@ -188,7 +188,8 @@ $default = 'cache' => array('base' => null), 'ping' => - array('notify' => array()), + array('notify' => array(), + 'timeout' => 2), 'inboxes' => array('enabled' => true), # ignored after 0.9.x 'newuser' => diff --git a/lib/ping.php b/lib/ping.php index 735af9ef1..be2933ae3 100644 --- a/lib/ping.php +++ b/lib/ping.php @@ -45,7 +45,15 @@ function ping_broadcast_notice($notice) { $tags)); $request = HTTPClient::start(); - $httpResponse = $request->post($notify_url, array('Content-Type: text/xml'), $req); + $request->setConfig('connect_timeout', common_config('ping', 'timeout')); + $request->setConfig('timeout', common_config('ping', 'timeout')); + try { + $httpResponse = $request->post($notify_url, array('Content-Type: text/xml'), $req); + } catch (Exception $e) { + common_log(LOG_ERR, + "Exception pinging $notify_url: " . $e->getMessage()); + continue; + } if (!$httpResponse || mb_strlen($httpResponse->getBody()) == 0) { common_log(LOG_WARNING, -- cgit v1.2.3-54-g00ecf From c2bda7726c05c6c7f5ef4f9519e56f107bc4e1e5 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 5 May 2010 13:11:36 -0700 Subject: XMPP debugging: log the message source when discarding empty or unrecognized messages. --- lib/xmppmanager.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/xmppmanager.php b/lib/xmppmanager.php index cca54db08..829eaa36c 100644 --- a/lib/xmppmanager.php +++ b/lib/xmppmanager.php @@ -253,12 +253,12 @@ class XmppManager extends IoManager $from = jabber_normalize_jid($pl['from']); if ($pl['type'] != 'chat') { - $this->log(LOG_WARNING, "Ignoring message of type ".$pl['type']." from $from."); + $this->log(LOG_WARNING, "Ignoring message of type ".$pl['type']." from $from: " . $pl['xml']->toString()); return; } if (mb_strlen($pl['body']) == 0) { - $this->log(LOG_WARNING, "Ignoring message with empty body from $from."); + $this->log(LOG_WARNING, "Ignoring message with empty body from $from: " . $pl['xml']->toString()); return; } -- cgit v1.2.3-54-g00ecf From 3e8af172d636cc7ca3a9e2301b928f6ca79b9eb2 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 5 May 2010 17:30:42 -0700 Subject: Add ?uselang=xx language override option (only valid, locally-enabled languages supported, just as with headers and user settings). Great aid for debugging & translation testing --- lib/util.php | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/util.php b/lib/util.php index e7ea9df61..e15c69f95 100644 --- a/lib/util.php +++ b/lib/util.php @@ -138,23 +138,38 @@ function common_timezone() return common_config('site', 'timezone'); } +function common_valid_language($lang) +{ + if ($lang) { + // Validate -- we don't want to end up with a bogus code + // left over from some old junk. + foreach (common_config('site', 'languages') as $code => $info) { + if ($info['lang'] == $lang) { + return true; + } + } + } + return false; +} + function common_language() { + // Allow ?uselang=xx override, very useful for debugging + // and helping translators check usage and context. + if (isset($_GET['uselang'])) { + $uselang = strval($_GET['uselang']); + if (common_valid_language($uselang)) { + return $uselang; + } + } // If there is a user logged in and they've set a language preference // then return that one... if (_have_config() && common_logged_in()) { $user = common_current_user(); - $user_language = $user->language; - - if ($user->language) { - // Validate -- we don't want to end up with a bogus code - // left over from some old junk. - foreach (common_config('site', 'languages') as $code => $info) { - if ($info['lang'] == $user_language) { - return $user_language; - } - } + + if (common_valid_language($user->language)) { + return $user->language; } } -- cgit v1.2.3-54-g00ecf From b547079b280b9fa2f8877aab7ad5cd3761f500b9 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 5 May 2010 22:35:16 -0700 Subject: Add xmlns:statusnet and statusnet:notice_info element to Atom entries for notices --- classes/Notice.php | 17 +++++++++++++++-- lib/atomnoticefeed.php | 9 ++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/classes/Notice.php b/classes/Notice.php index c0828674d..e82a82526 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1172,7 +1172,7 @@ class Notice extends Memcached_DataObject return $groups; } - function asAtomEntry($namespace=false, $source=false, $author=true) + function asAtomEntry($namespace=false, $source=false, $author=true, $cur=null) { $profile = $this->getProfile(); @@ -1185,7 +1185,8 @@ class Notice extends Memcached_DataObject 'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/', 'xmlns:media' => 'http://purl.org/syndication/atommedia', 'xmlns:poco' => 'http://portablecontacts.net/spec/1.0', - 'xmlns:ostatus' => 'http://ostatus.org/schema/1.0'); + 'xmlns:ostatus' => 'http://ostatus.org/schema/1.0', + 'xmlns:statusnet' => 'http://status.net/ont/'); } else { $attrs = array(); } @@ -1211,6 +1212,18 @@ class Notice extends Memcached_DataObject $xs->element('icon', null, $profile->avatarUrl(AVATAR_PROFILE_SIZE)); $xs->element('updated', null, common_date_w3dtf($this->created)); + + $noticeInfoAttr = array( + 'local_id' => $this->id, // local notice ID (useful to clients for ordering) + 'source' => $this->source // the client name (source attribution) + // @todo source source_link + ); + + if (!empty($cur)) { + $noticeInfoAttr['favorited'] = ($cur->hasFave($this)) ? 'true' : 'false'; + } + + $xs->element('statusnet:notice_info', $noticeInfoAttr, null); } if ($source) { diff --git a/lib/atomnoticefeed.php b/lib/atomnoticefeed.php index e4df731fe..35a45118c 100644 --- a/lib/atomnoticefeed.php +++ b/lib/atomnoticefeed.php @@ -79,6 +79,11 @@ class AtomNoticeFeed extends Atom10Feed 'ostatus', 'http://ostatus.org/schema/1.0' ); + + $this->addNamespace( + 'statusnet', + 'http://status.net/ont/' + ); } /** @@ -110,7 +115,9 @@ class AtomNoticeFeed extends Atom10Feed $source = $this->showSource(); $author = $this->showAuthor(); - $this->addEntryRaw($notice->asAtomEntry(false, $source, $author)); + $cur = common_current_user(); + + $this->addEntryRaw($notice->asAtomEntry(false, $source, $author, $cur)); } function showSource() -- cgit v1.2.3-54-g00ecf From 22fde00defe79a153ed77ddf6a4e63dd7fef6743 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 6 May 2010 00:20:10 -0700 Subject: Refactor and centralize notice source link calculation --- actions/twitapisearchatom.php | 15 ++++++++++-- classes/Notice.php | 39 +++++++++++++++++++++++++++++- lib/apiaction.php | 51 ++++++++++----------------------------- lib/noticelist.php | 56 ++++++++++++++++++++----------------------- 4 files changed, 90 insertions(+), 71 deletions(-) (limited to 'lib') diff --git a/actions/twitapisearchatom.php b/actions/twitapisearchatom.php index 24aa619bd..3eb54ccc3 100644 --- a/actions/twitapisearchatom.php +++ b/actions/twitapisearchatom.php @@ -342,10 +342,21 @@ class TwitapisearchatomAction extends ApiAction 'rel' => 'related', 'href' => $profile->avatarUrl())); - // TODO: Here is where we'd put in a link to an atom feed for threads + // @todo: Here is where we'd put in a link to an atom feed for threads + + $source = null; + + $ns = $notice->getSource(); + if ($ns) { + if (!empty($ns->name) && !empty($ns->url)) { + $source = '' . $ns->name . ''; + } else { + $source = $ns->code; + } + } $this->element("twitter:source", null, - htmlentities($this->sourceLink($notice->source))); + htmlentities($source)); $this->elementStart('author'); diff --git a/classes/Notice.php b/classes/Notice.php index e82a82526..cd27376a4 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -704,7 +704,7 @@ class Notice extends Memcached_DataObject /** * Is this notice part of an active conversation? - * + * * @return boolean true if other messages exist in the same * conversation, false if this is the only one */ @@ -1812,4 +1812,41 @@ class Notice extends Memcached_DataObject return $result; } + + /** + * Get the source of the notice + * + * @return Notice_source $ns A notice source object. 'code' is the only attribute + * guaranteed to be populated. + */ + function getSource() + { + $ns = new Notice_source(); + if (!empty($this->source)) { + switch ($this->source) { + case 'web': + case 'xmpp': + case 'mail': + case 'omb': + case 'system': + case 'api': + $ns->code = $this->source; + break; + default: + $ns = Notice_source::staticGet($this->source); + if (!$ns) { + $ns = new Notice_source(); + $ns->code = $this->source; + $app = Oauth_application::staticGet('name', $this->source); + if ($app) { + $ns->name = $app->name; + $ns->url = $app->source_url; + } + } + break; + } + } + return $ns; + } + } diff --git a/lib/apiaction.php b/lib/apiaction.php index a3c34a91b..8c4dc6c26 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -313,7 +313,19 @@ class ApiAction extends Action $twitter_status['created_at'] = $this->dateTwitter($notice->created); $twitter_status['in_reply_to_status_id'] = ($notice->reply_to) ? intval($notice->reply_to) : null; - $twitter_status['source'] = $this->sourceLink($notice->source); + + $source = null; + + $ns = $notice->getSource(); + if ($ns) { + if (!empty($ns->name) && !empty($ns->url)) { + $source = '' . $ns->name . ''; + } else { + $source = $ns->code; + } + } + + $twitter_status['source'] = $source; $twitter_status['id'] = intval($notice->id); $replier_profile = null; @@ -1354,43 +1366,6 @@ class ApiAction extends Action } } - function sourceLink($source) - { - $source_name = _($source); - switch ($source) { - case 'web': - case 'xmpp': - case 'mail': - case 'omb': - case 'api': - break; - default: - - $name = null; - $url = null; - - $ns = Notice_source::staticGet($source); - - if ($ns) { - $name = $ns->name; - $url = $ns->url; - } else { - $app = Oauth_application::staticGet('name', $source); - if ($app) { - $name = $app->name; - $url = $app->source_url; - } - } - - if (!empty($name) && !empty($url)) { - $source_name = '' . $name . ''; - } - - break; - } - return $source_name; - } - /** * Returns query argument or default value if not found. Certain * parameters used throughout the API are lightly scrubbed and diff --git a/lib/noticelist.php b/lib/noticelist.php index 5265326b2..c42e4fb60 100644 --- a/lib/noticelist.php +++ b/lib/noticelist.php @@ -488,48 +488,44 @@ class NoticeListItem extends Widget function showNoticeSource() { - if ($this->notice->source) { + $ns = $this->notice->getSource(); + + if ($ns) { + $source_name = _($ns->code); $this->out->text(' '); $this->out->elementStart('span', 'source'); $this->out->text(_('from')); - $source_name = _($this->notice->source); $this->out->text(' '); - switch ($this->notice->source) { - case 'web': - case 'xmpp': - case 'mail': - case 'omb': - case 'system': - case 'api': - $this->out->element('span', 'device', $source_name); - break; - default: - $name = $source_name; - $url = null; + // if $ns->name and $ns->url are populated we have + // configured a source attr somewhere + if (empty($ns->name) && empty($ns->url)) { + // otherwise it's from normal channel such as web or api + $this->out->element('span', 'device', $source_name); + } else { + $name = null; + $url = null; + $title = null; if (Event::handle('StartNoticeSourceLink', array($this->notice, &$name, &$url, &$title))) { - $ns = Notice_source::staticGet($this->notice->source); - - if ($ns) { - $name = $ns->name; - $url = $ns->url; - } else { - $app = Oauth_application::staticGet('name', $this->notice->source); - if ($app) { - $name = $app->name; - $url = $app->source_url; - } - } + $name = $source_name; + $url = $ns->url; } Event::handle('EndNoticeSourceLink', array($this->notice, &$name, &$url, &$title)); if (!empty($name) && !empty($url)) { $this->out->elementStart('span', 'device'); - $this->out->element('a', array('href' => $url, - 'rel' => 'external', - 'title' => $title), - $name); + + $attrs = array( + 'href' => $url, + 'rel' => 'external' + ); + + if (isset($title)) { + $attrs['title'] = $title; + } + + $this->out->element('a', $attrs, $name); $this->out->elementEnd('span'); } else { $this->out->element('span', 'device', $name); -- cgit v1.2.3-54-g00ecf From 209fd12cd033c62619c68ac17a4fa70b1e981169 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 6 May 2010 00:55:17 -0700 Subject: HTML entity encode source link URLs in plain XML output and add rel="nofollow" to them --- actions/twitapisearchatom.php | 2 +- lib/apiaction.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/actions/twitapisearchatom.php b/actions/twitapisearchatom.php index 3eb54ccc3..6c740c490 100644 --- a/actions/twitapisearchatom.php +++ b/actions/twitapisearchatom.php @@ -349,7 +349,7 @@ class TwitapisearchatomAction extends ApiAction $ns = $notice->getSource(); if ($ns) { if (!empty($ns->name) && !empty($ns->url)) { - $source = '' . $ns->name . ''; + $source = '' . $ns->name . ''; } else { $source = $ns->code; } diff --git a/lib/apiaction.php b/lib/apiaction.php index 8c4dc6c26..2608be227 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -319,13 +319,13 @@ class ApiAction extends Action $ns = $notice->getSource(); if ($ns) { if (!empty($ns->name) && !empty($ns->url)) { - $source = '' . $ns->name . ''; + $source = '' . $ns->name . ''; } else { $source = $ns->code; } } - $twitter_status['source'] = $source; + $twitter_status['source'] = htmlentities($source); $twitter_status['id'] = intval($notice->id); $replier_profile = null; -- cgit v1.2.3-54-g00ecf From ce177400f876a1e48f38ef18635d5ecf486a6867 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 6 May 2010 19:52:25 +0000 Subject: - OStatusPlugin should return true if it doesn't need to handle source attribution - Remove stray break statement from NoticeList --- lib/noticelist.php | 1 - plugins/OStatus/OStatusPlugin.php | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/noticelist.php b/lib/noticelist.php index c42e4fb60..c7dc9d29d 100644 --- a/lib/noticelist.php +++ b/lib/noticelist.php @@ -530,7 +530,6 @@ class NoticeListItem extends Widget } else { $this->out->element('span', 'device', $name); } - break; } $this->out->elementEnd('span'); } diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index f183bc7ae..d3a92755c 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -452,6 +452,7 @@ class OStatusPlugin extends Plugin return false; } } + return true; } /** -- cgit v1.2.3-54-g00ecf From ee8c9d142251566f87ee0780b5788549cc0a0c12 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 6 May 2010 20:25:20 +0000 Subject: Allow OStatusPlugin to set the source attribution title --- lib/noticelist.php | 51 ++++++++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 27 deletions(-) (limited to 'lib') diff --git a/lib/noticelist.php b/lib/noticelist.php index c7dc9d29d..432ea78d5 100644 --- a/lib/noticelist.php +++ b/lib/noticelist.php @@ -497,40 +497,37 @@ class NoticeListItem extends Widget $this->out->text(_('from')); $this->out->text(' '); - // if $ns->name and $ns->url are populated we have - // configured a source attr somewhere - if (empty($ns->name) && empty($ns->url)) { - // otherwise it's from normal channel such as web or api - $this->out->element('span', 'device', $source_name); - } else { - $name = null; - $url = null; - $title = null; + $name = $source_name; + $url = $ns->url; + $title = null; - if (Event::handle('StartNoticeSourceLink', array($this->notice, &$name, &$url, &$title))) { - $name = $source_name; - $url = $ns->url; - } - Event::handle('EndNoticeSourceLink', array($this->notice, &$name, &$url, &$title)); + if (Event::handle('StartNoticeSourceLink', array($this->notice, &$name, &$url, &$title))) { + $name = $source_name; + $url = $ns->url; + } + Event::handle('EndNoticeSourceLink', array($this->notice, &$name, &$url, &$title)); - if (!empty($name) && !empty($url)) { - $this->out->elementStart('span', 'device'); + // if $ns->name and $ns->url are populated we have + // configured a source attr somewhere + if (!empty($name) && !empty($url)) { - $attrs = array( - 'href' => $url, - 'rel' => 'external' - ); + $this->out->elementStart('span', 'device'); - if (isset($title)) { - $attrs['title'] = $title; - } + $attrs = array( + 'href' => $url, + 'rel' => 'external' + ); - $this->out->element('a', $attrs, $name); - $this->out->elementEnd('span'); - } else { - $this->out->element('span', 'device', $name); + if (!empty($title)) { + $attrs['title'] = $title; } + + $this->out->element('a', $attrs, $name); + $this->out->elementEnd('span'); + } else { + $this->out->element('span', 'device', $name); } + $this->out->elementEnd('span'); } } -- cgit v1.2.3-54-g00ecf From 869bc32d0d8cd68d75483e33c62d8ea9f1cc8e2c Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 6 May 2010 21:36:13 +0000 Subject: Remove errant double HTML entity encoding in API source attribution --- actions/twitapisearchatom.php | 9 ++++++--- classes/Notice.php | 2 +- lib/apiaction.php | 8 ++++++-- 3 files changed, 13 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/actions/twitapisearchatom.php b/actions/twitapisearchatom.php index 6c740c490..51e8a8881 100644 --- a/actions/twitapisearchatom.php +++ b/actions/twitapisearchatom.php @@ -349,14 +349,17 @@ class TwitapisearchatomAction extends ApiAction $ns = $notice->getSource(); if ($ns) { if (!empty($ns->name) && !empty($ns->url)) { - $source = '' . $ns->name . ''; + $source = '' + . htmlspecialchars($ns->name) + . ''; } else { $source = $ns->code; } } - $this->element("twitter:source", null, - htmlentities($source)); + $this->element("twitter:source", null, $source); $this->elementStart('author'); diff --git a/classes/Notice.php b/classes/Notice.php index b3cfb2813..875bcaa02 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1221,7 +1221,7 @@ class Notice extends Memcached_DataObject $ns = $this->getSource(); if ($ns) { if (!empty($ns->url)) { - $noticeInfoAttr['source_link'] = htmlentities($ns->url); + $noticeInfoAttr['source_link'] = $ns->url; } } diff --git a/lib/apiaction.php b/lib/apiaction.php index 2608be227..42aa08ef7 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -319,13 +319,17 @@ class ApiAction extends Action $ns = $notice->getSource(); if ($ns) { if (!empty($ns->name) && !empty($ns->url)) { - $source = '' . $ns->name . ''; + $source = '' + . htmlspecialchars($ns->name) + . ''; } else { $source = $ns->code; } } - $twitter_status['source'] = htmlentities($source); + $twitter_status['source'] = $source; $twitter_status['id'] = intval($notice->id); $replier_profile = null; -- cgit v1.2.3-54-g00ecf From 30328fc1666b9e3a6651c5d8881933debaf5ecc6 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Thu, 6 May 2010 23:33:27 -0400 Subject: Enable ClientSideShorten plugin by default --- lib/default.php | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/default.php b/lib/default.php index 449d2b3bb..52a4ec783 100644 --- a/lib/default.php +++ b/lib/default.php @@ -287,6 +287,7 @@ $default = 'OStatus' => null, 'WikiHashtags' => null, 'RSSCloud' => null, + 'ClientSideShorten' => null, 'OpenID' => null), ), 'pluginlist' => array(), -- cgit v1.2.3-54-g00ecf From 4b0458801af03b40fa636849da0a7e96bbd3e860 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Thu, 6 May 2010 23:40:07 -0400 Subject: Ignore PEAR errors with code DB_DATAOBJECT_ERROR_NODATA --- lib/common.php | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'lib') diff --git a/lib/common.php b/lib/common.php index 2bda88c97..72a1b7075 100644 --- a/lib/common.php +++ b/lib/common.php @@ -132,6 +132,12 @@ require_once INSTALLDIR.'/lib/serverexception.php'; //set PEAR error handling to use regular PHP exceptions function PEAR_ErrorToPEAR_Exception($err) { + //DB_DataObject throws error when an empty set would be returned + //That behavior is weird, and not how the rest of StatusNet works. + //So just ignore those errors. + if ($err->getCode() == DB_DATAOBJECT_ERROR_NODATA) { + return; + } if ($err->getCode()) { throw new PEAR_Exception($err->getMessage(), $err->getCode()); } -- cgit v1.2.3-54-g00ecf From b407665b983297078f5361db24c60a7d46e0f4ba Mon Sep 17 00:00:00 2001 From: Zachary Copley Date: Tue, 20 Apr 2010 11:29:13 -0700 Subject: Initial work on API method for updating a group's profile info --- actions/apigroupprofileupdate.php | 370 ++++++++++++++++++++++++++++++++++++++ lib/router.php | 6 + 2 files changed, 376 insertions(+) create mode 100644 actions/apigroupprofileupdate.php (limited to 'lib') diff --git a/actions/apigroupprofileupdate.php b/actions/apigroupprofileupdate.php new file mode 100644 index 000000000..0d3620c26 --- /dev/null +++ b/actions/apigroupprofileupdate.php @@ -0,0 +1,370 @@ +. + * + * @category API + * @package StatusNet + * @author Zach Copley + * @copyright 2010 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); +} + +require_once INSTALLDIR . '/lib/apiauth.php'; + +class ApiValidationException extends Exception { } + +/** + * API analog to the group edit page + * + * @category API + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +class ApiGroupProfileUpdateAction extends ApiAuthAction +{ + + /** + * Take arguments for running + * + * @param array $args $_REQUEST args + * + * @return boolean success flag + * + */ + + function prepare($args) + { + parent::prepare($args); + + $this->nickname = common_canonical_nickname($this->trimmed('nickname')); + $this->fullname = $this->trimmed('fullname'); + $this->homepage = $this->trimmed('homepage'); + $this->description = $this->trimmed('description'); + $this->location = $this->trimmed('location'); + $this->aliasstring = $this->trimmed('aliases'); + + $this->user = $this->auth_user; + $this->group = $this->getTargetGroup($this->arg('id')); + + return true; + } + + /** + * Handle the request + * + * See which request params have been set, and update the profile + * + * @param array $args $_REQUEST data (unused) + * + * @return void + */ + + function handle($args) + { + parent::handle($args); + + if ($_SERVER['REQUEST_METHOD'] != 'POST') { + $this->clientError( + _('This method requires a POST.'), + 400, $this->format + ); + return; + } + + if (!in_array($this->format, array('xml', 'json'))) { + $this->clientError( + _('API method not found.'), + 404, + $this->format + ); + return; + } + + if (empty($this->user)) { + $this->clientError(_('No such user.'), 404, $this->format); + return; + } + + if (empty($this->group)) { + $this->clientError(_('Group not found.'), 404, $this->format); + return false; + } + + if (!$this->user->isAdmin($this->group)) { + $this->clientError(_('You must be an admin to edit the group.'), 403); + return false; + } + + $this->group->query('BEGIN'); + + $orig = clone($this->group); + + try { + + if (!empty($this->nickname)) { + if ($this->validateNickname()) { + $this->group->nickname = $this->nickname; + $this->group->mainpage = common_local_url( + 'showgroup', + array('nickname' => $this->nickname) + ); + } + } + + if (!empty($this->fullname)) { + $this->validateFullname(); + $this->group->fullname = $this->fullname; + } + + if (!empty($this->homepage)) { + $this->validateHomepage(); + $this->group->homepage = $this->hompage; + } + + if (!empty($this->description)) { + $this->validateDescription(); + $this->group->description = $this->decription; + } + + if (!empty($this->location)) { + $this->validateLocation(); + $this->group->location = $this->location; + } + + } catch (ApiValidationException $ave) { + $this->clientError( + $ave->getMessage(), + 403, + $this->format + ); + return; + } + + $result = $this->group->update($orig); + + if (!$result) { + common_log_db_error($this->group, 'UPDATE', __FILE__); + $this->serverError(_('Could not update group.')); + } + + $aliases = null; + + try { + + if (!empty($this->aliasstring)) { + $aliases = $this->parseAliases(); + } + + } catch (ApiValidationException $ave) { + $this->clientError( + $ave->getMessage(), + 403, + $this->format + ); + return; + } + + $result = $this->group->setAliases($aliases); + + if (!$result) { + $this->serverError(_('Could not create aliases.')); + } + + if (!empty($this->nickname) && $this->nickname != $orig->nickname) { + common_log(LOG_INFO, "Saving local group info."); + $local = Local_group::staticGet('group_id', $this->group->id); + $local->setNickname($this->nickname); + } + + $this->group->query('COMMIT'); + + switch($this->format) { + case 'xml': + $this->showSingleXmlGroup($this->group); + break; + case 'json': + $this->showSingleJsonGroup($this->group); + break; + default: + $this->clientError(_('API method not found.'), 404, $this->format); + break; + } + } + + function nicknameExists($nickname) + { + $group = Local_group::staticGet('nickname', $nickname); + + if (!empty($group) && + $group->group_id != $this->group->id) { + return true; + } + + $alias = Group_alias::staticGet('alias', $nickname); + + if (!empty($alias) && + $alias->group_id != $this->group->id) { + return true; + } + + return false; + } + + function validateNickname() + { + if (!Validate::string( + $this->nickname, array( + 'min_length' => 1, + 'max_length' => 64, + 'format' => NICKNAME_FMT + ) + ) + ) { + throw new ApiValidationException( + _( + 'Nickname must have only lowercase letters ' . + 'and numbers and no spaces.' + ) + ); + } else if ($this->nicknameExists($this->nickname)) { + throw new ApiValidationException( + _('Nickname already in use. Try another one.') + ); + } else if (!User_group::allowedNickname($this->nickname)) { + throw new ApiValidationException( + _('Not a valid nickname.') + ); + } + } + + function validateHomepage() + { + if (!is_null($this->homepage) + && (strlen($this->homepage) > 0) + && !Validate::uri( + $this->homepage, + array('allowed_schemes' => array('http', 'https') + ) + ) + ) { + throw new ApiValidationException( + _('Homepage is not a valid URL.') + ); + } + } + + function validateFullname() + { + if (!is_null($this->fullname) && mb_strlen($this->fullname) > 255) { + throw new ApiValidationException( + _('Full name is too long (max 255 chars).') + ); + } + } + + function validateDescription() + { + if (User_group::descriptionTooLong($this->description)) { + throw new ApiValidationException( + sprintf( + _('description is too long (max %d chars).'), + User_group::maxDescription() + ) + ); + } + } + + function validateLocation() + { + if (!is_null($this->location) && mb_strlen($this->location) > 255) { + throw new ApiValidationException( + _('Location is too long (max 255 chars).') + ); + } + } + + function validateAliases() + { + $aliases = array_map( + 'common_canonical_nickname', + array_unique( + preg_split('/[\s,]+/', + $this->aliasstring + ) + ) + ); + + if (empty($aliases)) { + $aliases = array(); + } + + if (count($aliases) > common_config('group', 'maxaliases')) { + throw new ApiValidationException( + sprintf( + _('Too many aliases! Maximum %d.'), + common_config('group', 'maxaliases') + ) + ); + } + + foreach ($aliases as $alias) { + if (!Validate::string( + $alias, array( + 'min_length' => 1, + 'max_length' => 64, + 'format' => NICKNAME_FMT) + ) + ) { + throw new ApiValidationException( + sprintf( + _('Invalid alias: "%s"'), + $alias + ) + ); + } + + if ($this->nicknameExists($alias)) { + throw new ApiValidationException( + sprintf( + _('Alias "%s" already in use. Try another one.'), + $alias) + ); + } + + // XXX assumes alphanum nicknames + if (strcmp($alias, $nickname) == 0) { + throw new ApiValidationException( + _('Alias can\'t be the same as nickname.') + ); + } + } + + return $aliases; + } + +} \ No newline at end of file diff --git a/lib/router.php b/lib/router.php index a040abb83..faa26c861 100644 --- a/lib/router.php +++ b/lib/router.php @@ -650,6 +650,12 @@ class Router $m->connect('api/statusnet/groups/create.:format', array('action' => 'ApiGroupCreate', 'format' => '(xml|json)')); + + $m->connect('api/statusnet/groups/update/:id.:format', + array('action' => 'ApiGroupProfileUpdate', + 'id' => '[a-zA-Z0-9]+', + 'format' => '(xml|json)')); + // Tags $m->connect('api/statusnet/tags/timeline/:tag.:format', array('action' => 'ApiTimelineTag', -- cgit v1.2.3-54-g00ecf From 06a63b0404aa96efc1118563482c11567b048961 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 7 May 2010 00:52:54 -0700 Subject: Finish api/statusnet/groups/update --- actions/apigroupprofileupdate.php | 19 ++++++++----------- lib/apiaction.php | 2 ++ 2 files changed, 10 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/actions/apigroupprofileupdate.php b/actions/apigroupprofileupdate.php index 0d3620c26..6ac4b5a4b 100644 --- a/actions/apigroupprofileupdate.php +++ b/actions/apigroupprofileupdate.php @@ -33,8 +33,6 @@ if (!defined('STATUSNET')) { require_once INSTALLDIR . '/lib/apiauth.php'; -class ApiValidationException extends Exception { } - /** * API analog to the group edit page * @@ -62,6 +60,7 @@ class ApiGroupProfileUpdateAction extends ApiAuthAction parent::prepare($args); $this->nickname = common_canonical_nickname($this->trimmed('nickname')); + $this->fullname = $this->trimmed('fullname'); $this->homepage = $this->trimmed('homepage'); $this->description = $this->trimmed('description'); @@ -172,12 +171,12 @@ class ApiGroupProfileUpdateAction extends ApiAuthAction $this->serverError(_('Could not update group.')); } - $aliases = null; + $aliases = array(); try { - if (!empty($this->aliasstring)) { - $aliases = $this->parseAliases(); + if (!empty($this->aliasstring)) { + $aliases = $this->validateAliases(); } } catch (ApiValidationException $ave) { @@ -195,7 +194,7 @@ class ApiGroupProfileUpdateAction extends ApiAuthAction $this->serverError(_('Could not create aliases.')); } - if (!empty($this->nickname) && $this->nickname != $orig->nickname) { + if (!empty($this->nickname) && ($this->nickname != $orig->nickname)) { common_log(LOG_INFO, "Saving local group info."); $local = Local_group::staticGet('group_id', $this->group->id); $local->setNickname($this->nickname); @@ -260,6 +259,8 @@ class ApiGroupProfileUpdateAction extends ApiAuthAction _('Not a valid nickname.') ); } + + return true; } function validateHomepage() @@ -319,10 +320,6 @@ class ApiGroupProfileUpdateAction extends ApiAuthAction ) ); - if (empty($aliases)) { - $aliases = array(); - } - if (count($aliases) > common_config('group', 'maxaliases')) { throw new ApiValidationException( sprintf( @@ -357,7 +354,7 @@ class ApiGroupProfileUpdateAction extends ApiAuthAction } // XXX assumes alphanum nicknames - if (strcmp($alias, $nickname) == 0) { + if (strcmp($alias, $this->nickname) == 0) { throw new ApiValidationException( _('Alias can\'t be the same as nickname.') ); diff --git a/lib/apiaction.php b/lib/apiaction.php index 42aa08ef7..d35391d4e 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -97,6 +97,8 @@ if (!defined('STATUSNET')) { exit(1); } +class ApiValidationException extends Exception { } + /** * Contains most of the Twitter-compatible API output functions. * -- cgit v1.2.3-54-g00ecf From 3c9686e80f50f24f302abf5dd27b74a44fa4ae56 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 7 May 2010 16:32:24 -0700 Subject: Fix for repeats from the API having null source attribution --- actions/apidirectmessagenew.php | 8 -------- actions/apistatusesretweet.php | 2 +- actions/apistatusesupdate.php | 12 ------------ lib/apiaction.php | 9 +++++++++ lib/apiauth.php | 3 +-- 5 files changed, 11 insertions(+), 23 deletions(-) (limited to 'lib') diff --git a/actions/apidirectmessagenew.php b/actions/apidirectmessagenew.php index b9ac92d77..65d065648 100644 --- a/actions/apidirectmessagenew.php +++ b/actions/apidirectmessagenew.php @@ -52,7 +52,6 @@ require_once INSTALLDIR . '/lib/apiauth.php'; class ApiDirectMessageNewAction extends ApiAuthAction { - var $source = null; var $other = null; var $content = null; @@ -76,13 +75,6 @@ class ApiDirectMessageNewAction extends ApiAuthAction return; } - $this->source = $this->trimmed('source'); // Not supported by Twitter. - - $reserved_sources = array('web', 'omb', 'mail', 'xmpp', 'api'); - if (empty($this->source) || in_array($this->source, $reserved_sources)) { - $source = 'api'; - } - $this->content = $this->trimmed('text'); $this->user = $this->auth_user; diff --git a/actions/apistatusesretweet.php b/actions/apistatusesretweet.php index 128c881e2..9aa337485 100644 --- a/actions/apistatusesretweet.php +++ b/actions/apistatusesretweet.php @@ -79,7 +79,7 @@ class ApiStatusesRetweetAction extends ApiAuthAction $this->user = $this->auth_user; - if ($this->user->id == $notice->profile_id) { + if ($this->user->id == $this->original->profile_id) { $this->clientError(_('Cannot repeat your own notice.'), 400, $this->format); return false; diff --git a/actions/apistatusesupdate.php b/actions/apistatusesupdate.php index 5f3a447c2..a0a81f336 100644 --- a/actions/apistatusesupdate.php +++ b/actions/apistatusesupdate.php @@ -155,8 +155,6 @@ class ApiStatusesUpdateAction extends ApiAuthAction var $lat = null; var $lon = null; - static $reserved_sources = array('web', 'omb', 'mail', 'xmpp', 'api'); - /** * Take arguments for running * @@ -171,19 +169,9 @@ class ApiStatusesUpdateAction extends ApiAuthAction parent::prepare($args); $this->status = $this->trimmed('status'); - $this->source = $this->trimmed('source'); $this->lat = $this->trimmed('lat'); $this->lon = $this->trimmed('long'); - // try to set the source attr from OAuth app - if (empty($this->source)) { - $this->source = $this->oauth_source; - } - - if (empty($this->source) || in_array($this->source, self::$reserved_sources)) { - $this->source = 'api'; - } - $this->in_reply_to_status_id = intval($this->trimmed('in_reply_to_status_id')); diff --git a/lib/apiaction.php b/lib/apiaction.php index 42aa08ef7..80a8a08d1 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -124,9 +124,12 @@ class ApiAction extends Action var $count = null; var $max_id = null; var $since_id = null; + var $source = null; var $access = self::READ_ONLY; // read (default) or read-write + static $reserved_sources = array('web', 'omb', 'ostatus', 'mail', 'xmpp', 'api'); + /** * Initialization. * @@ -150,6 +153,12 @@ class ApiAction extends Action header('X-StatusNet-Warning: since parameter is disabled; use since_id'); } + $this->source = $this->trimmed('source'); + + if (empty($this->source) || in_array($this->source, self::$reserved_sources)) { + $this->source = 'api'; + } + return true; } diff --git a/lib/apiauth.php b/lib/apiauth.php index 8c3998888..9c68e2771 100644 --- a/lib/apiauth.php +++ b/lib/apiauth.php @@ -72,7 +72,6 @@ class ApiAuthAction extends ApiAction { var $auth_user_nickname = null; var $auth_user_password = null; - var $oauth_source = null; /** * Take arguments for running, looks for an OAuth request, @@ -181,7 +180,7 @@ class ApiAuthAction extends ApiAction // set the source attr - $this->oauth_source = $app->name; + $this->source = $app->name; $appUser = Oauth_application_user::staticGet('token', $access_token); -- cgit v1.2.3-54-g00ecf From fba140f4e0246a244664f0c0fb2361b027508d35 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 7 May 2010 16:32:24 -0700 Subject: Fix for repeats from the API having null source attribution --- actions/apidirectmessagenew.php | 8 -------- actions/apistatusesretweet.php | 2 +- actions/apistatusesupdate.php | 12 ------------ lib/apiaction.php | 9 +++++++++ lib/apiauth.php | 3 +-- 5 files changed, 11 insertions(+), 23 deletions(-) (limited to 'lib') diff --git a/actions/apidirectmessagenew.php b/actions/apidirectmessagenew.php index b9ac92d77..65d065648 100644 --- a/actions/apidirectmessagenew.php +++ b/actions/apidirectmessagenew.php @@ -52,7 +52,6 @@ require_once INSTALLDIR . '/lib/apiauth.php'; class ApiDirectMessageNewAction extends ApiAuthAction { - var $source = null; var $other = null; var $content = null; @@ -76,13 +75,6 @@ class ApiDirectMessageNewAction extends ApiAuthAction return; } - $this->source = $this->trimmed('source'); // Not supported by Twitter. - - $reserved_sources = array('web', 'omb', 'mail', 'xmpp', 'api'); - if (empty($this->source) || in_array($this->source, $reserved_sources)) { - $source = 'api'; - } - $this->content = $this->trimmed('text'); $this->user = $this->auth_user; diff --git a/actions/apistatusesretweet.php b/actions/apistatusesretweet.php index 128c881e2..9aa337485 100644 --- a/actions/apistatusesretweet.php +++ b/actions/apistatusesretweet.php @@ -79,7 +79,7 @@ class ApiStatusesRetweetAction extends ApiAuthAction $this->user = $this->auth_user; - if ($this->user->id == $notice->profile_id) { + if ($this->user->id == $this->original->profile_id) { $this->clientError(_('Cannot repeat your own notice.'), 400, $this->format); return false; diff --git a/actions/apistatusesupdate.php b/actions/apistatusesupdate.php index d4ef6b550..e3e579b0d 100644 --- a/actions/apistatusesupdate.php +++ b/actions/apistatusesupdate.php @@ -64,8 +64,6 @@ class ApiStatusesUpdateAction extends ApiAuthAction var $lat = null; var $lon = null; - static $reserved_sources = array('web', 'omb', 'mail', 'xmpp', 'api'); - /** * Take arguments for running * @@ -80,19 +78,9 @@ class ApiStatusesUpdateAction extends ApiAuthAction parent::prepare($args); $this->status = $this->trimmed('status'); - $this->source = $this->trimmed('source'); $this->lat = $this->trimmed('lat'); $this->lon = $this->trimmed('long'); - // try to set the source attr from OAuth app - if (empty($this->source)) { - $this->source = $this->oauth_source; - } - - if (empty($this->source) || in_array($this->source, self::$reserved_sources)) { - $this->source = 'api'; - } - $this->in_reply_to_status_id = intval($this->trimmed('in_reply_to_status_id')); diff --git a/lib/apiaction.php b/lib/apiaction.php index 59dc47c23..f87b04611 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -63,9 +63,12 @@ class ApiAction extends Action var $count = null; var $max_id = null; var $since_id = null; + var $source = null; var $access = self::READ_ONLY; // read (default) or read-write + static $reserved_sources = array('web', 'omb', 'ostatus', 'mail', 'xmpp', 'api'); + /** * Initialization. * @@ -89,6 +92,12 @@ class ApiAction extends Action header('X-StatusNet-Warning: since parameter is disabled; use since_id'); } + $this->source = $this->trimmed('source'); + + if (empty($this->source) || in_array($this->source, self::$reserved_sources)) { + $this->source = 'api'; + } + return true; } diff --git a/lib/apiauth.php b/lib/apiauth.php index e78de618e..95acbbd7b 100644 --- a/lib/apiauth.php +++ b/lib/apiauth.php @@ -54,7 +54,6 @@ class ApiAuthAction extends ApiAction { var $auth_user_nickname = null; var $auth_user_password = null; - var $oauth_source = null; /** * Take arguments for running, looks for an OAuth request, @@ -162,7 +161,7 @@ class ApiAuthAction extends ApiAction // set the source attr - $this->oauth_source = $app->name; + $this->source = $app->name; $appUser = Oauth_application_user::staticGet('token', $access_token); -- cgit v1.2.3-54-g00ecf From da18701394ef717cd68dad11f5a830719ad675e6 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 7 May 2010 16:32:24 -0700 Subject: Fix for repeats from the API having null source attribution --- actions/apidirectmessagenew.php | 8 -------- actions/apistatusesretweet.php | 2 +- actions/apistatusesupdate.php | 12 ------------ lib/apiaction.php | 9 +++++++++ lib/apiauth.php | 3 +-- 5 files changed, 11 insertions(+), 23 deletions(-) (limited to 'lib') diff --git a/actions/apidirectmessagenew.php b/actions/apidirectmessagenew.php index b9ac92d77..65d065648 100644 --- a/actions/apidirectmessagenew.php +++ b/actions/apidirectmessagenew.php @@ -52,7 +52,6 @@ require_once INSTALLDIR . '/lib/apiauth.php'; class ApiDirectMessageNewAction extends ApiAuthAction { - var $source = null; var $other = null; var $content = null; @@ -76,13 +75,6 @@ class ApiDirectMessageNewAction extends ApiAuthAction return; } - $this->source = $this->trimmed('source'); // Not supported by Twitter. - - $reserved_sources = array('web', 'omb', 'mail', 'xmpp', 'api'); - if (empty($this->source) || in_array($this->source, $reserved_sources)) { - $source = 'api'; - } - $this->content = $this->trimmed('text'); $this->user = $this->auth_user; diff --git a/actions/apistatusesretweet.php b/actions/apistatusesretweet.php index 128c881e2..9aa337485 100644 --- a/actions/apistatusesretweet.php +++ b/actions/apistatusesretweet.php @@ -79,7 +79,7 @@ class ApiStatusesRetweetAction extends ApiAuthAction $this->user = $this->auth_user; - if ($this->user->id == $notice->profile_id) { + if ($this->user->id == $this->original->profile_id) { $this->clientError(_('Cannot repeat your own notice.'), 400, $this->format); return false; diff --git a/actions/apistatusesupdate.php b/actions/apistatusesupdate.php index 5f3a447c2..a0a81f336 100644 --- a/actions/apistatusesupdate.php +++ b/actions/apistatusesupdate.php @@ -155,8 +155,6 @@ class ApiStatusesUpdateAction extends ApiAuthAction var $lat = null; var $lon = null; - static $reserved_sources = array('web', 'omb', 'mail', 'xmpp', 'api'); - /** * Take arguments for running * @@ -171,19 +169,9 @@ class ApiStatusesUpdateAction extends ApiAuthAction parent::prepare($args); $this->status = $this->trimmed('status'); - $this->source = $this->trimmed('source'); $this->lat = $this->trimmed('lat'); $this->lon = $this->trimmed('long'); - // try to set the source attr from OAuth app - if (empty($this->source)) { - $this->source = $this->oauth_source; - } - - if (empty($this->source) || in_array($this->source, self::$reserved_sources)) { - $this->source = 'api'; - } - $this->in_reply_to_status_id = intval($this->trimmed('in_reply_to_status_id')); diff --git a/lib/apiaction.php b/lib/apiaction.php index d35391d4e..e481a1ef2 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -126,9 +126,12 @@ class ApiAction extends Action var $count = null; var $max_id = null; var $since_id = null; + var $source = null; var $access = self::READ_ONLY; // read (default) or read-write + static $reserved_sources = array('web', 'omb', 'ostatus', 'mail', 'xmpp', 'api'); + /** * Initialization. * @@ -152,6 +155,12 @@ class ApiAction extends Action header('X-StatusNet-Warning: since parameter is disabled; use since_id'); } + $this->source = $this->trimmed('source'); + + if (empty($this->source) || in_array($this->source, self::$reserved_sources)) { + $this->source = 'api'; + } + return true; } diff --git a/lib/apiauth.php b/lib/apiauth.php index 8c3998888..9c68e2771 100644 --- a/lib/apiauth.php +++ b/lib/apiauth.php @@ -72,7 +72,6 @@ class ApiAuthAction extends ApiAction { var $auth_user_nickname = null; var $auth_user_password = null; - var $oauth_source = null; /** * Take arguments for running, looks for an OAuth request, @@ -181,7 +180,7 @@ class ApiAuthAction extends ApiAction // set the source attr - $this->oauth_source = $app->name; + $this->source = $app->name; $appUser = Oauth_application_user::staticGet('token', $access_token); -- cgit v1.2.3-54-g00ecf From 45392bef3382cd0bad30ebcd343d1cdd21e16f08 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 11 May 2010 12:16:13 -0700 Subject: Installer tweak for Windows: normalize line endings to platform standard in generated config.php Added a comment that the writable directory checks are insufficient to catch ACL problems on Windows; need a better check for that. --- lib/installer.php | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib') diff --git a/lib/installer.php b/lib/installer.php index 589a19a66..58ffbfef7 100644 --- a/lib/installer.php +++ b/lib/installer.php @@ -128,6 +128,7 @@ abstract class Installer $pass = false; } + // @fixme this check seems to be insufficient with Windows ACLs if (!is_writable(INSTALLDIR)) { $this->warning(sprintf('Cannot write config file to: %s

', INSTALLDIR), sprintf('On your server, try this command: chmod a+w %s', INSTALLDIR)); @@ -409,6 +410,10 @@ abstract class Installer "\$config['db']['database'] = '{$this->db['database']}';\n\n". ($this->db['type'] == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n":''). "\$config['db']['type'] = '{$this->db['type']}';\n\n"; + + // Normalize line endings for Windows servers + $cfg = str_replace("\n", PHP_EOL, $cfg); + // write configuration file out to install directory $res = file_put_contents(INSTALLDIR.'/config.php', $cfg); -- cgit v1.2.3-54-g00ecf From 3d00cfd47fe5458a531df1b78b1833eb17321393 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 11 May 2010 12:22:14 -0700 Subject: Windows server fix: Use platform EOL in debug log file --- lib/util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/util.php b/lib/util.php index c0013bb3d..efede1d4b 100644 --- a/lib/util.php +++ b/lib/util.php @@ -1365,7 +1365,7 @@ function common_log_line($priority, $msg) { static $syslog_priorities = array('LOG_EMERG', 'LOG_ALERT', 'LOG_CRIT', 'LOG_ERR', 'LOG_WARNING', 'LOG_NOTICE', 'LOG_INFO', 'LOG_DEBUG'); - return date('Y-m-d H:i:s') . ' ' . $syslog_priorities[$priority] . ': ' . $msg . "\n"; + return date('Y-m-d H:i:s') . ' ' . $syslog_priorities[$priority] . ': ' . $msg . PHP_EOL; } function common_request_id() -- cgit v1.2.3-54-g00ecf From 599942f58a839a7d6d7ff92e31873f3d61faf326 Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Sat, 15 May 2010 14:56:40 +1200 Subject: sorted enums and auto_increments on postgres. Still needs inline indexes on table creation --- lib/pgsqlschema.php | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/pgsqlschema.php b/lib/pgsqlschema.php index 715065d77..7594edc8e 100644 --- a/lib/pgsqlschema.php +++ b/lib/pgsqlschema.php @@ -41,6 +41,7 @@ if (!defined('STATUSNET')) { * @category Database * @package StatusNet * @author Evan Prodromou + * @author Brenda Wallace * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ @@ -79,7 +80,6 @@ class PgsqlSchema extends Schema $row = array(); while ($res->fetchInto($row, DB_FETCHMODE_ASSOC)) { -// var_dump($row); $cd = new ColumnDef(); $cd->name = $row['field']; @@ -155,7 +155,6 @@ class PgsqlSchema extends Schema } $sql .= $this->_columnSql($cd); - switch ($cd->key) { case 'UNI': $uniques[] = $cd->name; @@ -188,7 +187,7 @@ class PgsqlSchema extends Schema $res = $this->conn->query($sql); if (PEAR::isError($res)) { - throw new Exception($res->getMessage()); + throw new Exception($res->getMessage(). ' SQL was '. $sql); } return true; @@ -223,7 +222,7 @@ class PgsqlSchema extends Schema */ private function _columnTypeTranslation($type) { $map = array( - 'datetime' => 'timestamp' + 'datetime' => 'timestamp', ); if(!empty($map[$type])) { return $map[$type]; @@ -397,16 +396,17 @@ class PgsqlSchema extends Schema $todrop = array_diff($cur, $new); $same = array_intersect($new, $cur); $tomod = array(); - foreach ($same as $m) { $curCol = $this->_byName($td->columns, $m); $newCol = $this->_byName($columns, $m); + if (!$newCol->equals($curCol)) { - $tomod[] = $newCol->name; + // BIG GIANT TODO! + // stop it detecting different types and trying to modify on every page request +// $tomod[] = $newCol->name; } } - if (count($toadd) + count($todrop) + count($tomod) == 0) { // nothing to do return true; @@ -434,7 +434,7 @@ class PgsqlSchema extends Schema } $sql = 'ALTER TABLE ' . $tableName . ' ' . implode(', ', $phrase); - + echo "

$sql

"; $res = $this->conn->query($sql); if (PEAR::isError($res)) { @@ -496,12 +496,21 @@ class PgsqlSchema extends Schema * * @return string correct SQL for that column */ - private function _columnSql($cd) { $sql = "{$cd->name} "; $type = $this->_columnTypeTranslation($cd->type); + //handle those mysql enum fields that postgres doesn't support + if (preg_match('!^enum!', $type)) { + $allowed_values = preg_replace('!^enum!', '', $type); + $sql .= " text check ({$cd->name} in $allowed_values)"; + return $sql; + } + if (!empty($cd->auto_increment)) { + $type = 'serial'; + } + if (!empty($cd->size)) { $sql .= "{$type}({$cd->size}) "; } else { @@ -513,10 +522,6 @@ class PgsqlSchema extends Schema } else { $sql .= ($cd->nullable) ? "null " : "not null "; } - - if (!empty($cd->auto_increment)) { - $sql .= " auto_increment "; - } if (!empty($cd->extra)) { $sql .= "{$cd->extra} "; -- cgit v1.2.3-54-g00ecf From 7cf250ff188bac16400b688dd309d189ef99fde8 Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Sat, 15 May 2010 15:08:22 +1200 Subject: removed sneaky debug echo that shouldn't be there --- lib/pgsqlschema.php | 1 - 1 file changed, 1 deletion(-) (limited to 'lib') diff --git a/lib/pgsqlschema.php b/lib/pgsqlschema.php index 7594edc8e..12f24cfbe 100644 --- a/lib/pgsqlschema.php +++ b/lib/pgsqlschema.php @@ -434,7 +434,6 @@ class PgsqlSchema extends Schema } $sql = 'ALTER TABLE ' . $tableName . ' ' . implode(', ', $phrase); - echo "

$sql

"; $res = $this->conn->query($sql); if (PEAR::isError($res)) { -- cgit v1.2.3-54-g00ecf From 191752138a26087648dc665595fb9ca566306637 Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Sat, 15 May 2010 15:14:11 +1200 Subject: indexes now working in postgres schemas --- lib/pgsqlschema.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pgsqlschema.php b/lib/pgsqlschema.php index 12f24cfbe..24b847a98 100644 --- a/lib/pgsqlschema.php +++ b/lib/pgsqlschema.php @@ -172,18 +172,16 @@ class PgsqlSchema extends Schema $sql .= ",\n primary key (" . implode(',', $primary) . ")"; } - - - foreach ($indices as $i) { - $sql .= ",\nindex {$name}_{$i}_idx ($i)"; - } - $sql .= "); "; foreach ($uniques as $u) { $sql .= "\n CREATE index {$name}_{$u}_idx ON {$name} ($u); "; } + + foreach ($indices as $i) { + $sql .= "CREATE index {$name}_{$i}_idx on {$name} ($i)"; + } $res = $this->conn->query($sql); if (PEAR::isError($res)) { -- cgit v1.2.3-54-g00ecf From a467c0ebbab22a220972e458de0652e523bc12d7 Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Sat, 15 May 2010 15:31:54 +1200 Subject: caitalise the sql keywords --- lib/pgsqlschema.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pgsqlschema.php b/lib/pgsqlschema.php index 24b847a98..16639ff1b 100644 --- a/lib/pgsqlschema.php +++ b/lib/pgsqlschema.php @@ -169,7 +169,7 @@ class PgsqlSchema extends Schema } if (count($primary) > 0) { // it really should be... - $sql .= ",\n primary key (" . implode(',', $primary) . ")"; + $sql .= ",\n PRIMARY KEY (" . implode(',', $primary) . ")"; } $sql .= "); "; @@ -180,7 +180,7 @@ class PgsqlSchema extends Schema } foreach ($indices as $i) { - $sql .= "CREATE index {$name}_{$i}_idx on {$name} ($i)"; + $sql .= "CREATE index {$name}_{$i}_idx ON {$name} ($i)"; } $res = $this->conn->query($sql); -- cgit v1.2.3-54-g00ecf From 7bd6b62461551f26fa5571b72b260d4e92c9bfd5 Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Sat, 15 May 2010 15:32:22 +1200 Subject: comment out the extra bit, cos there's always mysql-only stuff in therre. this isn't a very good idea --- lib/pgsqlschema.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pgsqlschema.php b/lib/pgsqlschema.php index 16639ff1b..583d01e0a 100644 --- a/lib/pgsqlschema.php +++ b/lib/pgsqlschema.php @@ -520,9 +520,9 @@ class PgsqlSchema extends Schema $sql .= ($cd->nullable) ? "null " : "not null "; } - if (!empty($cd->extra)) { - $sql .= "{$cd->extra} "; - } +// if (!empty($cd->extra)) { +// $sql .= "{$cd->extra} "; +// } return $sql; } -- cgit v1.2.3-54-g00ecf From 9bb18541df68b5a921d366c8cfb578887178b694 Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Sat, 15 May 2010 15:33:55 +1200 Subject: added missing field to the group by. this makes postgres happy --- lib/popularnoticesection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/popularnoticesection.php b/lib/popularnoticesection.php index 296ddbbb5..f70a972ef 100644 --- a/lib/popularnoticesection.php +++ b/lib/popularnoticesection.php @@ -72,7 +72,7 @@ class PopularNoticeSection extends NoticeSection $qry .= ' GROUP BY notice.id,notice.profile_id,notice.content,notice.uri,' . 'notice.rendered,notice.url,notice.created,notice.modified,' . 'notice.reply_to,notice.is_local,notice.source,notice.conversation, ' . - 'notice.lat,notice.lon,location_id,location_ns' . + 'notice.lat,notice.lon,location_id,location_ns,notice.repeat_of' . ' ORDER BY weight DESC'; $offset = 0; -- cgit v1.2.3-54-g00ecf From 6f19830c9a1f7f73e6a3b09e78f22f65eb1779c4 Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Mon, 17 May 2010 13:50:37 +1200 Subject: fix the column modify on stuff for postgres. change serial to bigserial --- lib/pgsqlschema.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pgsqlschema.php b/lib/pgsqlschema.php index 583d01e0a..272f7eff6 100644 --- a/lib/pgsqlschema.php +++ b/lib/pgsqlschema.php @@ -143,6 +143,7 @@ class PgsqlSchema extends Schema $uniques = array(); $primary = array(); $indices = array(); + $onupdate = array(); $sql = "CREATE TABLE $name (\n"; @@ -321,7 +322,7 @@ class PgsqlSchema extends Schema public function modifyColumn($table, $columndef) { - $sql = "ALTER TABLE $table MODIFY COLUMN " . + $sql = "ALTER TABLE $table ALTER COLUMN TYPE " . $this->_columnSql($columndef); $res = $this->conn->query($sql); @@ -428,7 +429,9 @@ class PgsqlSchema extends Schema foreach ($tomod as $columnName) { $cd = $this->_byName($columns, $columnName); - $phrase[] = 'MODIFY COLUMN ' . $this->_columnSql($cd); + /* brute force */ + $phrase[] = 'DROP COLUMN ' . $columnName; + $phrase[] = 'ADD COLUMN ' . $this->_columnSql($cd); } $sql = 'ALTER TABLE ' . $tableName . ' ' . implode(', ', $phrase); @@ -505,7 +508,7 @@ class PgsqlSchema extends Schema return $sql; } if (!empty($cd->auto_increment)) { - $type = 'serial'; + $type = "bigserial"; // FIXME: creates the wrong name for the sequence for some internal sequence-lookup function, so better fix this to do the real 'create sequence' dance. } if (!empty($cd->size)) { -- cgit v1.2.3-54-g00ecf From 48dc899acb9a0ac87140353092dab1f5e67753d8 Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Sat, 15 May 2010 15:56:43 +1200 Subject: added notice.location to group by --- lib/popularnoticesection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/popularnoticesection.php b/lib/popularnoticesection.php index f70a972ef..3f0241790 100644 --- a/lib/popularnoticesection.php +++ b/lib/popularnoticesection.php @@ -72,7 +72,7 @@ class PopularNoticeSection extends NoticeSection $qry .= ' GROUP BY notice.id,notice.profile_id,notice.content,notice.uri,' . 'notice.rendered,notice.url,notice.created,notice.modified,' . 'notice.reply_to,notice.is_local,notice.source,notice.conversation, ' . - 'notice.lat,notice.lon,location_id,location_ns,notice.repeat_of' . + 'notice.lat,notice.lon,location_id,location_ns,notice.repeat_of,notice.location' . ' ORDER BY weight DESC'; $offset = 0; -- cgit v1.2.3-54-g00ecf From d9fddff5395e77287c4de0796fd072b3073f1eb9 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 5 May 2010 22:35:16 -0700 Subject: Add xmlns:statusnet and statusnet:notice_info element to Atom entries for notices --- classes/Notice.php | 17 +++++++++++++++-- lib/atomnoticefeed.php | 9 ++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/classes/Notice.php b/classes/Notice.php index 0b1b2e402..9a9172cba 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1171,7 +1171,7 @@ class Notice extends Memcached_DataObject return $groups; } - function asAtomEntry($namespace=false, $source=false, $author=true) + function asAtomEntry($namespace=false, $source=false, $author=true, $cur=null) { $profile = $this->getProfile(); @@ -1184,7 +1184,8 @@ class Notice extends Memcached_DataObject 'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/', 'xmlns:media' => 'http://purl.org/syndication/atommedia', 'xmlns:poco' => 'http://portablecontacts.net/spec/1.0', - 'xmlns:ostatus' => 'http://ostatus.org/schema/1.0'); + 'xmlns:ostatus' => 'http://ostatus.org/schema/1.0', + 'xmlns:statusnet' => 'http://status.net/ont/'); } else { $attrs = array(); } @@ -1210,6 +1211,18 @@ class Notice extends Memcached_DataObject $xs->element('icon', null, $profile->avatarUrl(AVATAR_PROFILE_SIZE)); $xs->element('updated', null, common_date_w3dtf($this->created)); + + $noticeInfoAttr = array( + 'local_id' => $this->id, // local notice ID (useful to clients for ordering) + 'source' => $this->source // the client name (source attribution) + // @todo source source_link + ); + + if (!empty($cur)) { + $noticeInfoAttr['favorited'] = ($cur->hasFave($this)) ? 'true' : 'false'; + } + + $xs->element('statusnet:notice_info', $noticeInfoAttr, null); } if ($source) { diff --git a/lib/atomnoticefeed.php b/lib/atomnoticefeed.php index e4df731fe..35a45118c 100644 --- a/lib/atomnoticefeed.php +++ b/lib/atomnoticefeed.php @@ -79,6 +79,11 @@ class AtomNoticeFeed extends Atom10Feed 'ostatus', 'http://ostatus.org/schema/1.0' ); + + $this->addNamespace( + 'statusnet', + 'http://status.net/ont/' + ); } /** @@ -110,7 +115,9 @@ class AtomNoticeFeed extends Atom10Feed $source = $this->showSource(); $author = $this->showAuthor(); - $this->addEntryRaw($notice->asAtomEntry(false, $source, $author)); + $cur = common_current_user(); + + $this->addEntryRaw($notice->asAtomEntry(false, $source, $author, $cur)); } function showSource() -- cgit v1.2.3-54-g00ecf From c78f67aa7367acab5f9156ecf8963e2d5243e400 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 6 May 2010 00:20:10 -0700 Subject: Refactor and centralize notice source link calculation --- actions/twitapisearchatom.php | 15 ++++++++++-- classes/Notice.php | 39 +++++++++++++++++++++++++++++- lib/apiaction.php | 51 ++++++++++----------------------------- lib/noticelist.php | 56 ++++++++++++++++++++----------------------- 4 files changed, 90 insertions(+), 71 deletions(-) (limited to 'lib') diff --git a/actions/twitapisearchatom.php b/actions/twitapisearchatom.php index 24aa619bd..3eb54ccc3 100644 --- a/actions/twitapisearchatom.php +++ b/actions/twitapisearchatom.php @@ -342,10 +342,21 @@ class TwitapisearchatomAction extends ApiAction 'rel' => 'related', 'href' => $profile->avatarUrl())); - // TODO: Here is where we'd put in a link to an atom feed for threads + // @todo: Here is where we'd put in a link to an atom feed for threads + + $source = null; + + $ns = $notice->getSource(); + if ($ns) { + if (!empty($ns->name) && !empty($ns->url)) { + $source = '' . $ns->name . ''; + } else { + $source = $ns->code; + } + } $this->element("twitter:source", null, - htmlentities($this->sourceLink($notice->source))); + htmlentities($source)); $this->elementStart('author'); diff --git a/classes/Notice.php b/classes/Notice.php index 9a9172cba..2c2c87d56 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -703,7 +703,7 @@ class Notice extends Memcached_DataObject /** * Is this notice part of an active conversation? - * + * * @return boolean true if other messages exist in the same * conversation, false if this is the only one */ @@ -1809,4 +1809,41 @@ class Notice extends Memcached_DataObject return $result; } + + /** + * Get the source of the notice + * + * @return Notice_source $ns A notice source object. 'code' is the only attribute + * guaranteed to be populated. + */ + function getSource() + { + $ns = new Notice_source(); + if (!empty($this->source)) { + switch ($this->source) { + case 'web': + case 'xmpp': + case 'mail': + case 'omb': + case 'system': + case 'api': + $ns->code = $this->source; + break; + default: + $ns = Notice_source::staticGet($this->source); + if (!$ns) { + $ns = new Notice_source(); + $ns->code = $this->source; + $app = Oauth_application::staticGet('name', $this->source); + if ($app) { + $ns->name = $app->name; + $ns->url = $app->source_url; + } + } + break; + } + } + return $ns; + } + } diff --git a/lib/apiaction.php b/lib/apiaction.php index f87b04611..7a6a5549b 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -260,7 +260,19 @@ class ApiAction extends Action $twitter_status['created_at'] = $this->dateTwitter($notice->created); $twitter_status['in_reply_to_status_id'] = ($notice->reply_to) ? intval($notice->reply_to) : null; - $twitter_status['source'] = $this->sourceLink($notice->source); + + $source = null; + + $ns = $notice->getSource(); + if ($ns) { + if (!empty($ns->name) && !empty($ns->url)) { + $source = '' . $ns->name . ''; + } else { + $source = $ns->code; + } + } + + $twitter_status['source'] = $source; $twitter_status['id'] = intval($notice->id); $replier_profile = null; @@ -1298,43 +1310,6 @@ class ApiAction extends Action } } - function sourceLink($source) - { - $source_name = _($source); - switch ($source) { - case 'web': - case 'xmpp': - case 'mail': - case 'omb': - case 'api': - break; - default: - - $name = null; - $url = null; - - $ns = Notice_source::staticGet($source); - - if ($ns) { - $name = $ns->name; - $url = $ns->url; - } else { - $app = Oauth_application::staticGet('name', $source); - if ($app) { - $name = $app->name; - $url = $app->source_url; - } - } - - if (!empty($name) && !empty($url)) { - $source_name = '' . $name . ''; - } - - break; - } - return $source_name; - } - /** * Returns query argument or default value if not found. Certain * parameters used throughout the API are lightly scrubbed and diff --git a/lib/noticelist.php b/lib/noticelist.php index 4f997a328..e0d8bf560 100644 --- a/lib/noticelist.php +++ b/lib/noticelist.php @@ -480,48 +480,44 @@ class NoticeListItem extends Widget function showNoticeSource() { - if ($this->notice->source) { + $ns = $this->notice->getSource(); + + if ($ns) { + $source_name = _($ns->code); $this->out->text(' '); $this->out->elementStart('span', 'source'); $this->out->text(_('from')); - $source_name = _($this->notice->source); $this->out->text(' '); - switch ($this->notice->source) { - case 'web': - case 'xmpp': - case 'mail': - case 'omb': - case 'system': - case 'api': - $this->out->element('span', 'device', $source_name); - break; - default: - $name = $source_name; - $url = null; + // if $ns->name and $ns->url are populated we have + // configured a source attr somewhere + if (empty($ns->name) && empty($ns->url)) { + // otherwise it's from normal channel such as web or api + $this->out->element('span', 'device', $source_name); + } else { + $name = null; + $url = null; + $title = null; if (Event::handle('StartNoticeSourceLink', array($this->notice, &$name, &$url, &$title))) { - $ns = Notice_source::staticGet($this->notice->source); - - if ($ns) { - $name = $ns->name; - $url = $ns->url; - } else { - $app = Oauth_application::staticGet('name', $this->notice->source); - if ($app) { - $name = $app->name; - $url = $app->source_url; - } - } + $name = $source_name; + $url = $ns->url; } Event::handle('EndNoticeSourceLink', array($this->notice, &$name, &$url, &$title)); if (!empty($name) && !empty($url)) { $this->out->elementStart('span', 'device'); - $this->out->element('a', array('href' => $url, - 'rel' => 'external', - 'title' => $title), - $name); + + $attrs = array( + 'href' => $url, + 'rel' => 'external' + ); + + if (isset($title)) { + $attrs['title'] = $title; + } + + $this->out->element('a', $attrs, $name); $this->out->elementEnd('span'); } else { $this->out->element('span', 'device', $name); -- cgit v1.2.3-54-g00ecf From 0dfef88cacde19cf0afaefbd422a7f5230091064 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 6 May 2010 00:55:17 -0700 Subject: HTML entity encode source link URLs in plain XML output and add rel="nofollow" to them --- actions/twitapisearchatom.php | 2 +- lib/apiaction.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/actions/twitapisearchatom.php b/actions/twitapisearchatom.php index 3eb54ccc3..6c740c490 100644 --- a/actions/twitapisearchatom.php +++ b/actions/twitapisearchatom.php @@ -349,7 +349,7 @@ class TwitapisearchatomAction extends ApiAction $ns = $notice->getSource(); if ($ns) { if (!empty($ns->name) && !empty($ns->url)) { - $source = '' . $ns->name . ''; + $source = '' . $ns->name . ''; } else { $source = $ns->code; } diff --git a/lib/apiaction.php b/lib/apiaction.php index 7a6a5549b..f3efff402 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -266,13 +266,13 @@ class ApiAction extends Action $ns = $notice->getSource(); if ($ns) { if (!empty($ns->name) && !empty($ns->url)) { - $source = '' . $ns->name . ''; + $source = '' . $ns->name . ''; } else { $source = $ns->code; } } - $twitter_status['source'] = $source; + $twitter_status['source'] = htmlentities($source); $twitter_status['id'] = intval($notice->id); $replier_profile = null; -- cgit v1.2.3-54-g00ecf From 6187266205a55db0298e02df7d6996a735d42eba Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 6 May 2010 19:52:25 +0000 Subject: - OStatusPlugin should return true if it doesn't need to handle source attribution - Remove stray break statement from NoticeList --- lib/noticelist.php | 1 - plugins/OStatus/OStatusPlugin.php | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/noticelist.php b/lib/noticelist.php index e0d8bf560..d22010335 100644 --- a/lib/noticelist.php +++ b/lib/noticelist.php @@ -522,7 +522,6 @@ class NoticeListItem extends Widget } else { $this->out->element('span', 'device', $name); } - break; } $this->out->elementEnd('span'); } diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 5167842ca..5b153216e 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -452,6 +452,7 @@ class OStatusPlugin extends Plugin return false; } } + return true; } /** -- cgit v1.2.3-54-g00ecf From 3708341857a8ae26c2936df53fede09aa17b09f8 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 6 May 2010 20:25:20 +0000 Subject: Allow OStatusPlugin to set the source attribution title --- lib/noticelist.php | 51 ++++++++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 27 deletions(-) (limited to 'lib') diff --git a/lib/noticelist.php b/lib/noticelist.php index d22010335..81da9edc0 100644 --- a/lib/noticelist.php +++ b/lib/noticelist.php @@ -489,40 +489,37 @@ class NoticeListItem extends Widget $this->out->text(_('from')); $this->out->text(' '); - // if $ns->name and $ns->url are populated we have - // configured a source attr somewhere - if (empty($ns->name) && empty($ns->url)) { - // otherwise it's from normal channel such as web or api - $this->out->element('span', 'device', $source_name); - } else { - $name = null; - $url = null; - $title = null; + $name = $source_name; + $url = $ns->url; + $title = null; - if (Event::handle('StartNoticeSourceLink', array($this->notice, &$name, &$url, &$title))) { - $name = $source_name; - $url = $ns->url; - } - Event::handle('EndNoticeSourceLink', array($this->notice, &$name, &$url, &$title)); + if (Event::handle('StartNoticeSourceLink', array($this->notice, &$name, &$url, &$title))) { + $name = $source_name; + $url = $ns->url; + } + Event::handle('EndNoticeSourceLink', array($this->notice, &$name, &$url, &$title)); - if (!empty($name) && !empty($url)) { - $this->out->elementStart('span', 'device'); + // if $ns->name and $ns->url are populated we have + // configured a source attr somewhere + if (!empty($name) && !empty($url)) { - $attrs = array( - 'href' => $url, - 'rel' => 'external' - ); + $this->out->elementStart('span', 'device'); - if (isset($title)) { - $attrs['title'] = $title; - } + $attrs = array( + 'href' => $url, + 'rel' => 'external' + ); - $this->out->element('a', $attrs, $name); - $this->out->elementEnd('span'); - } else { - $this->out->element('span', 'device', $name); + if (!empty($title)) { + $attrs['title'] = $title; } + + $this->out->element('a', $attrs, $name); + $this->out->elementEnd('span'); + } else { + $this->out->element('span', 'device', $name); } + $this->out->elementEnd('span'); } } -- cgit v1.2.3-54-g00ecf From 5ea019c41ac4d6c161f3c8f287d405971d4aadea Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 6 May 2010 21:36:13 +0000 Subject: Remove errant double HTML entity encoding in API source attribution --- actions/twitapisearchatom.php | 9 ++++++--- classes/Notice.php | 2 +- lib/apiaction.php | 8 ++++++-- 3 files changed, 13 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/actions/twitapisearchatom.php b/actions/twitapisearchatom.php index 6c740c490..51e8a8881 100644 --- a/actions/twitapisearchatom.php +++ b/actions/twitapisearchatom.php @@ -349,14 +349,17 @@ class TwitapisearchatomAction extends ApiAction $ns = $notice->getSource(); if ($ns) { if (!empty($ns->name) && !empty($ns->url)) { - $source = '' . $ns->name . ''; + $source = '' + . htmlspecialchars($ns->name) + . ''; } else { $source = $ns->code; } } - $this->element("twitter:source", null, - htmlentities($source)); + $this->element("twitter:source", null, $source); $this->elementStart('author'); diff --git a/classes/Notice.php b/classes/Notice.php index 196501279..0dc7e10e7 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1220,7 +1220,7 @@ class Notice extends Memcached_DataObject $ns = $this->getSource(); if ($ns) { if (!empty($ns->url)) { - $noticeInfoAttr['source_link'] = htmlentities($ns->url); + $noticeInfoAttr['source_link'] = $ns->url; } } diff --git a/lib/apiaction.php b/lib/apiaction.php index f3efff402..68198effc 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -266,13 +266,17 @@ class ApiAction extends Action $ns = $notice->getSource(); if ($ns) { if (!empty($ns->name) && !empty($ns->url)) { - $source = '' . $ns->name . ''; + $source = '' + . htmlspecialchars($ns->name) + . ''; } else { $source = $ns->code; } } - $twitter_status['source'] = htmlentities($source); + $twitter_status['source'] = $source; $twitter_status['id'] = intval($notice->id); $replier_profile = null; -- cgit v1.2.3-54-g00ecf From 74a89b1fc37067d91d31bd66922053361eb4e616 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 19 May 2010 10:10:55 -0700 Subject: Locale switch cleanup: use common_switch_locale() which is safer for updating gettext state. Also moved a few calls to reduce chance of hitting an exception before switching back. Should help with problems where xmppdaemon would get stuck in wrong locale. --- lib/mail.php | 20 ++++++++++---------- lib/util.php | 17 +++++++++++++++++ plugins/Facebook/facebookutil.php | 6 +++--- plugins/TwitterBridge/twitter.php | 6 +++--- 4 files changed, 33 insertions(+), 16 deletions(-) (limited to 'lib') diff --git a/lib/mail.php b/lib/mail.php index 5fc584e28..a4065e8d5 100644 --- a/lib/mail.php +++ b/lib/mail.php @@ -224,9 +224,6 @@ function mail_subscribe_notify_profile($listenee, $other) if ($other->hasRight(Right::EMAILONSUBSCRIBE) && $listenee->email && $listenee->emailnotifysub) { - // use the recipient's localization - common_init_locale($listenee->language); - $profile = $listenee->getProfile(); $name = $profile->getBestName(); @@ -236,6 +233,9 @@ function mail_subscribe_notify_profile($listenee, $other) $recipients = $listenee->email; + // use the recipient's localization + common_switch_locale($listenee->language); + $headers = _mail_prepare_headers('subscribe', $listenee->nickname, $other->nickname); $headers['From'] = mail_notify_from(); $headers['To'] = $name . ' <' . $listenee->email . '>'; @@ -271,7 +271,7 @@ function mail_subscribe_notify_profile($listenee, $other) common_local_url('emailsettings')); // reset localization - common_init_locale(); + common_switch_locale(); mail_send($recipients, $headers, $body); } } @@ -473,7 +473,7 @@ function mail_confirm_sms($code, $nickname, $address) function mail_notify_nudge($from, $to) { - common_init_locale($to->language); + common_switch_locale($to->language); // TRANS: Subject for 'nudge' notification email $subject = sprintf(_('You\'ve been nudged by %s'), $from->nickname); @@ -491,7 +491,7 @@ function mail_notify_nudge($from, $to) $from->nickname, common_local_url('all', array('nickname' => $to->nickname)), common_config('site', 'name')); - common_init_locale(); + common_switch_locale(); $headers = _mail_prepare_headers('nudge', $to->nickname, $from->nickname); @@ -525,7 +525,7 @@ function mail_notify_message($message, $from=null, $to=null) return true; } - common_init_locale($to->language); + common_switch_locale($to->language); // TRANS: Subject for direct-message notification email $subject = sprintf(_('New private message from %s'), $from->nickname); @@ -549,7 +549,7 @@ function mail_notify_message($message, $from=null, $to=null) $headers = _mail_prepare_headers('message', $to->nickname, $from->nickname); - common_init_locale(); + common_switch_locale(); return mail_to_user($to, $subject, $body, $headers); } @@ -577,7 +577,7 @@ function mail_notify_fave($other, $user, $notice) $bestname = $profile->getBestName(); - common_init_locale($other->language); + common_switch_locale($other->language); // TRANS: Subject for favorite notification email $subject = sprintf(_('%s (@%s) added your notice as a favorite'), $bestname, $user->nickname); @@ -605,7 +605,7 @@ function mail_notify_fave($other, $user, $notice) $headers = _mail_prepare_headers('fave', $other->nickname, $user->nickname); - common_init_locale(); + common_switch_locale(); mail_to_user($other, $subject, $body, $headers); } diff --git a/lib/util.php b/lib/util.php index efede1d4b..597da22c0 100644 --- a/lib/util.php +++ b/lib/util.php @@ -34,6 +34,14 @@ function common_user_error($msg, $code=400) $err->showPage(); } +/** + * This should only be used at setup; processes switching languages + * to send text to other users should use common_switch_locale(). + * + * @param string $language Locale language code (optional; empty uses + * current user's preference or site default) + * @return mixed success + */ function common_init_locale($language=null) { if(!$language) { @@ -50,6 +58,15 @@ function common_init_locale($language=null) return $ok; } +/** + * Initialize locale and charset settings and gettext with our message catalog, + * using the current user's language preference or the site default. + * + * This should generally only be run at framework initialization; code switching + * languages at runtime should call common_switch_language(). + * + * @access private + */ function common_init_language() { mb_internal_encoding('UTF-8'); diff --git a/plugins/Facebook/facebookutil.php b/plugins/Facebook/facebookutil.php index ac532e18b..83664995a 100644 --- a/plugins/Facebook/facebookutil.php +++ b/plugins/Facebook/facebookutil.php @@ -272,12 +272,12 @@ function remove_facebook_app($flink) function mail_facebook_app_removed($user) { - common_init_locale($user->language); - $profile = $user->getProfile(); $site_name = common_config('site', 'name'); + common_switch_locale($user->language); + $subject = sprintf( _m('Your %1$s Facebook application access has been disabled.', $site_name)); @@ -291,7 +291,7 @@ function mail_facebook_app_removed($user) "re-installing the %2\$s Facebook application.\n\nRegards,\n\n%2\$s"), $user->nickname, $site_name); - common_init_locale(); + common_switch_locale(); return mail_to_user($user, $subject, $body); } diff --git a/plugins/TwitterBridge/twitter.php b/plugins/TwitterBridge/twitter.php index 21adc7a90..896eee2da 100644 --- a/plugins/TwitterBridge/twitter.php +++ b/plugins/TwitterBridge/twitter.php @@ -335,10 +335,10 @@ function remove_twitter_link($flink) function mail_twitter_bridge_removed($user) { - common_init_locale($user->language); - $profile = $user->getProfile(); + common_switch_locale($user->language); + $subject = sprintf(_m('Your Twitter bridge has been disabled.')); $site_name = common_config('site', 'name'); @@ -354,7 +354,7 @@ function mail_twitter_bridge_removed($user) common_local_url('twittersettings'), common_config('site', 'name')); - common_init_locale(); + common_switch_locale(); return mail_to_user($user, $subject, $body); } -- cgit v1.2.3-54-g00ecf From 708d22848ecffdb80ca2cd9e5f4a7f84d5ae3189 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 19 May 2010 16:19:06 -0700 Subject: Quick fix for creating OpenID accounts authenticating against a MediaWiki site; trim the 'User:' etc from the final path segment before generating a nickname from it. Avoids ending up with nicks like 'userbrion' on your first OpenID login! --- lib/util.php | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'lib') diff --git a/lib/util.php b/lib/util.php index 597da22c0..59d5132ec 100644 --- a/lib/util.php +++ b/lib/util.php @@ -1925,6 +1925,15 @@ function common_url_to_nickname($url) $path = preg_replace('@/$@', '', $parts['path']); $path = preg_replace('@^/@', '', $path); $path = basename($path); + + // Hack for MediaWiki user pages, in the form: + // http://example.com/wiki/User:Myname + // ('User' may be localized.) + if (strpos($path, ':')) { + $parts = array_filter(explode(':', $path)); + $path = $parts[count($parts) - 1]; + } + if ($path) { return common_nicknamize($path); } -- cgit v1.2.3-54-g00ecf From 68305d4b6848cec6afe887ee2a5735515060770e Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 20 May 2010 12:46:36 -0700 Subject: Added block link to subscription notification emails; block action can now take a profile ID on the URL; added profile details to block page so there's an indication of who you're blocking before you pull the trigger. Fixed typo in RedirectingAction when no return-to data provided in form submission. RedirectingAction::returnToArgs() has been renamed to returnToPrevious() to avoid conflict with Action::returnToArgs() which returns arguments to be passed to other actions as return-to arguments. All callers should now be updated. More profile settings actions will now redirect through a login form if visited as a GET request, as would be expected from a bookmark, link sent in e-mail etc. --- actions/block.php | 46 ++++++++++++++++++++++++++++++++++++++-- actions/deleteuser.php | 4 ++-- actions/groupblock.php | 4 ++-- lib/mail.php | 10 +++++++-- lib/profileformaction.php | 13 ++++++++++-- lib/redirectingaction.php | 9 ++++---- lib/router.php | 5 +++++ plugins/UserFlag/clearflag.php | 2 +- plugins/UserFlag/flagprofile.php | 2 +- 9 files changed, 79 insertions(+), 16 deletions(-) (limited to 'lib') diff --git a/actions/block.php b/actions/block.php index 7f609c253..239a50868 100644 --- a/actions/block.php +++ b/actions/block.php @@ -87,13 +87,15 @@ class BlockAction extends ProfileFormAction { if ($_SERVER['REQUEST_METHOD'] == 'POST') { if ($this->arg('no')) { - $this->returnToArgs(); + $this->returnToPrevious(); } elseif ($this->arg('yes')) { $this->handlePost(); - $this->returnToArgs(); + $this->returnToPrevious(); } else { $this->showPage(); } + } else { + $this->showPage(); } } @@ -118,6 +120,12 @@ class BlockAction extends ProfileFormAction */ function areYouSureForm() { + // @fixme if we ajaxify the confirmation form, skip the preview on ajax hits + $profile = new ArrayWrapper(array($this->profile)); + $preview = new ProfileList($profile, $this); + $preview->show(); + + $id = $this->profile->id; $this->elementStart('form', array('id' => 'block-' . $id, 'method' => 'post', @@ -175,4 +183,38 @@ class BlockAction extends ProfileFormAction $this->autofocus('form_action-yes'); } + /** + * Override for form session token checks; on our first hit we're just + * requesting confirmation, which doesn't need a token. We need to be + * able to take regular GET requests from email! + * + * @throws ClientException if token is bad on POST request or if we have + * confirmation parameters which could trigger something. + */ + function checkSessionToken() + { + if ($_SERVER['REQUEST_METHOD'] == 'POST' || + $this->arg('yes') || + $this->arg('no')) { + + return parent::checkSessionToken(); + } + } + + /** + * If we reached this form without returnto arguments, return to the + * current user's subscription list. + * + * @return string URL + */ + function defaultReturnTo() + { + $user = common_current_user(); + if ($user) { + return common_local_url('subscribers', + array('nickname' => $user->nickname)); + } else { + return common_local_url('public'); + } + } } diff --git a/actions/deleteuser.php b/actions/deleteuser.php index 42ef4b9f5..c0a8b20e2 100644 --- a/actions/deleteuser.php +++ b/actions/deleteuser.php @@ -92,10 +92,10 @@ class DeleteuserAction extends ProfileFormAction { if ($_SERVER['REQUEST_METHOD'] == 'POST') { if ($this->arg('no')) { - $this->returnToArgs(); + $this->returnToPrevious(); } elseif ($this->arg('yes')) { $this->handlePost(); - $this->returnToArgs(); + $this->returnToPrevious(); } else { $this->showPage(); } diff --git a/actions/groupblock.php b/actions/groupblock.php index fc95c0e66..2e06dc324 100644 --- a/actions/groupblock.php +++ b/actions/groupblock.php @@ -117,7 +117,7 @@ class GroupblockAction extends RedirectingAction parent::handle($args); if ($_SERVER['REQUEST_METHOD'] == 'POST') { if ($this->arg('no')) { - $this->returnToArgs(); + $this->returnToPrevious(); } elseif ($this->arg('yes')) { $this->blockProfile(); } elseif ($this->arg('blockto')) { @@ -195,7 +195,7 @@ class GroupblockAction extends RedirectingAction return false; } - $this->returnToArgs(); + $this->returnToPrevious(); } /** diff --git a/lib/mail.php b/lib/mail.php index a4065e8d5..ab5742e33 100644 --- a/lib/mail.php +++ b/lib/mail.php @@ -245,6 +245,11 @@ function mail_subscribe_notify_profile($listenee, $other) $other->getBestName(), common_config('site', 'name')); + $blocklink = sprintf(_("If you believe this account is being used abusively, " . + "you can block them from your subscribers list and " . + "report as spam to site administrators at %s"), + common_local_url('block', array('profileid' => $other->id))); + // TRANS: Main body of new-subscriber notification e-mail $body = sprintf(_('%1$s is now listening to your notices on %2$s.'."\n\n". "\t".'%3$s'."\n\n". @@ -264,9 +269,10 @@ function mail_subscribe_notify_profile($listenee, $other) ($other->homepage) ? // TRANS: Profile info line in new-subscriber notification e-mail sprintf(_("Homepage: %s"), $other->homepage) . "\n" : '', - ($other->bio) ? + (($other->bio) ? // TRANS: Profile info line in new-subscriber notification e-mail - sprintf(_("Bio: %s"), $other->bio) . "\n\n" : '', + sprintf(_("Bio: %s"), $other->bio) . "\n" : '') . + "\n\n" . $blocklink . "\n", common_config('site', 'name'), common_local_url('emailsettings')); diff --git a/lib/profileformaction.php b/lib/profileformaction.php index 0ffafe5fb..51c89a922 100644 --- a/lib/profileformaction.php +++ b/lib/profileformaction.php @@ -60,7 +60,16 @@ class ProfileFormAction extends RedirectingAction $this->checkSessionToken(); if (!common_logged_in()) { - $this->clientError(_('Not logged in.')); + if ($_SERVER['REQUEST_METHOD'] == 'POST') { + $this->clientError(_('Not logged in.')); + } else { + // Redirect to login. + common_set_returnto($this->selfUrl()); + $user = common_current_user(); + if (Event::handle('RedirectToLogin', array($this, $user))) { + common_redirect(common_local_url('login'), 303); + } + } return false; } @@ -97,7 +106,7 @@ class ProfileFormAction extends RedirectingAction if ($_SERVER['REQUEST_METHOD'] == 'POST') { $this->handlePost(); - $this->returnToArgs(); + $this->returnToPrevious(); } } diff --git a/lib/redirectingaction.php b/lib/redirectingaction.php index f11585274..3a358f891 100644 --- a/lib/redirectingaction.php +++ b/lib/redirectingaction.php @@ -53,12 +53,13 @@ class RedirectingAction extends Action * * To be called only after successful processing. * - * @fixme rename this -- it obscures Action::returnToArgs() which - * returns a list of arguments, and is a bit confusing. + * Note: this was named returnToArgs() up through 0.9.2, which + * caused problems because there's an Action::returnToArgs() + * already which does something different. * * @return void */ - function returnToArgs() + function returnToPrevious() { // Now, gotta figure where we go back to $action = false; @@ -77,7 +78,7 @@ class RedirectingAction extends Action if ($action) { common_redirect(common_local_url($action, $args, $params), 303); } else { - $url = $this->defaultReturnToUrl(); + $url = $this->defaultReturnTo(); } common_redirect($url, 303); } diff --git a/lib/router.php b/lib/router.php index a9d07276f..afe44f92a 100644 --- a/lib/router.php +++ b/lib/router.php @@ -136,6 +136,11 @@ class Router $m->connect('main/'.$a, array('action' => $a)); } + // Also need a block variant accepting ID on URL for mail links + $m->connect('main/block/:profileid', + array('action' => 'block'), + array('profileid' => '[0-9]+')); + $m->connect('main/sup/:seconds', array('action' => 'sup'), array('seconds' => '[0-9]+')); diff --git a/plugins/UserFlag/clearflag.php b/plugins/UserFlag/clearflag.php index bd6732e2d..f032527ed 100644 --- a/plugins/UserFlag/clearflag.php +++ b/plugins/UserFlag/clearflag.php @@ -81,7 +81,7 @@ class ClearflagAction extends ProfileFormAction if ($_SERVER['REQUEST_METHOD'] == 'POST') { $this->handlePost(); if (!$this->boolean('ajax')) { - $this->returnToArgs(); + $this->returnToPrevious(); } } } diff --git a/plugins/UserFlag/flagprofile.php b/plugins/UserFlag/flagprofile.php index 2d0f0abb9..018c1e8ac 100644 --- a/plugins/UserFlag/flagprofile.php +++ b/plugins/UserFlag/flagprofile.php @@ -87,7 +87,7 @@ class FlagprofileAction extends ProfileFormAction if ($_SERVER['REQUEST_METHOD'] == 'POST') { $this->handlePost(); if (!$this->boolean('ajax')) { - $this->returnToArgs(); + $this->returnToPrevious(); } } } -- cgit v1.2.3-54-g00ecf From 2c12d837c693a816541d32dd044de5277a46336d Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 21 May 2010 10:12:39 -0700 Subject: Disable SSL peer/hostname verification for HTTPClient unless we've configured a trusted CA bundle like this: $config['http']['ssl_cafile'] = '/usr/lib/ssl/certs/ca-certificates.crt'; The previous state was failing on all HTTPS hits due to HTTP_Request2 library turning on the validation check but not specifying a CA file. --- lib/default.php | 3 +++ lib/httpclient.php | 14 +++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/default.php b/lib/default.php index ab5f294de..950c6018d 100644 --- a/lib/default.php +++ b/lib/default.php @@ -304,4 +304,7 @@ $default = array('subscribers' => true, 'members' => true, 'peopletag' => true), + 'http' => // HTTP client settings when contacting other sites + array('ssl_cafile' => false // To enable SSL cert validation, point to a CA bundle (eg '/usr/lib/ssl/certs/ca-certificates.crt') + ), ); diff --git a/lib/httpclient.php b/lib/httpclient.php index 384626ae0..b69f718e5 100644 --- a/lib/httpclient.php +++ b/lib/httpclient.php @@ -132,7 +132,19 @@ class HTTPClient extends HTTP_Request2 // ought to be investigated to see if we can handle // it gracefully in that case as well. $this->config['protocol_version'] = '1.0'; - + + // Default state of OpenSSL seems to have no trusted + // SSL certificate authorities, which breaks hostname + // verification and means we have a hard time communicating + // with other sites' HTTPS interfaces. + // + // Turn off verification unless we've configured a CA bundle. + if (common_config('http', 'ssl_cafile')) { + $this->config['ssl_cafile'] = common_config('http', 'ssl_cafile'); + } else { + $this->config['ssl_verify_peer'] = false; + } + parent::__construct($url, $method, $config); $this->setHeader('User-Agent', $this->userAgent()); } -- cgit v1.2.3-54-g00ecf From 206229875511d24a97a0aac79605f6868d21ee7f Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 21 May 2010 14:07:59 -0700 Subject: Add $config['queue']['stomp_enqueue_to'] override for which queue server to send to. Must be set to a value that matches one of the entries in $config['queue']['stomp_server'] array, otherwise ignored. --- lib/stompqueuemanager.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php index 5d5c7ccfb..de4ba7f01 100644 --- a/lib/stompqueuemanager.php +++ b/lib/stompqueuemanager.php @@ -122,7 +122,19 @@ class StompQueueManager extends QueueManager public function enqueue($object, $queue) { $this->_connect(); - return $this->_doEnqueue($object, $queue, $this->defaultIdx); + if (common_config('queue', 'stomp_enqueue_on')) { + // We're trying to force all writes to a single server. + // WARNING: this might do odd things if that server connection dies. + $idx = array_search(common_config('queue', 'stomp_enqueue_on'), + $this->servers); + if ($idx === false) { + common_log(LOG_ERR, 'queue stomp_enqueue_on setting does not match our server list.'); + $idx = $this->defaultIdx; + } + } else { + $idx = $this->defaultIdx; + } + return $this->_doEnqueue($object, $queue, $idx); } /** -- cgit v1.2.3-54-g00ecf From c5b61078e1548fba2820620e2e8f5fcbbda611a8 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 27 May 2010 13:49:23 -0700 Subject: Pass auth user into Atom feed generators (needed for outputting favorited status in statusnet:notice_info tag) --- actions/apitimelinefavorites.php | 2 +- actions/apitimelinefriends.php | 2 +- actions/apitimelinegroup.php | 2 +- actions/apitimelinehome.php | 2 +- actions/apitimelinementions.php | 2 +- actions/apitimelinepublic.php | 2 +- actions/apitimelineretweetsofme.php | 2 +- actions/apitimelinetag.php | 2 +- actions/apitimelineuser.php | 2 +- lib/atomgroupnoticefeed.php | 5 +++-- lib/atomnoticefeed.php | 17 +++++++++++++++-- lib/atomusernoticefeed.php | 5 +++-- 12 files changed, 30 insertions(+), 15 deletions(-) (limited to 'lib') diff --git a/actions/apitimelinefavorites.php b/actions/apitimelinefavorites.php index 79632447e..a889b4918 100644 --- a/actions/apitimelinefavorites.php +++ b/actions/apitimelinefavorites.php @@ -150,7 +150,7 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction header('Content-Type: application/atom+xml; charset=utf-8'); - $atom = new AtomNoticeFeed(); + $atom = new AtomNoticeFeed($this->auth_user); $atom->setId($id); $atom->setTitle($title); diff --git a/actions/apitimelinefriends.php b/actions/apitimelinefriends.php index ac350ab1b..9c6ffcf9c 100644 --- a/actions/apitimelinefriends.php +++ b/actions/apitimelinefriends.php @@ -152,7 +152,7 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction header('Content-Type: application/atom+xml; charset=utf-8'); - $atom = new AtomNoticeFeed(); + $atom = new AtomNoticeFeed($this->auth_user); $atom->setId($id); $atom->setTitle($title); diff --git a/actions/apitimelinegroup.php b/actions/apitimelinegroup.php index 56d1de094..76fa74767 100644 --- a/actions/apitimelinegroup.php +++ b/actions/apitimelinegroup.php @@ -105,7 +105,7 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction function showTimeline() { // We'll pull common formatting out of this for other formats - $atom = new AtomGroupNoticeFeed($this->group); + $atom = new AtomGroupNoticeFeed($this->group, $this->auth_user); $self = $this->getSelfUri(); diff --git a/actions/apitimelinehome.php b/actions/apitimelinehome.php index 1618c9923..2a6b7bf5c 100644 --- a/actions/apitimelinehome.php +++ b/actions/apitimelinehome.php @@ -151,7 +151,7 @@ class ApiTimelineHomeAction extends ApiBareAuthAction header('Content-Type: application/atom+xml; charset=utf-8'); - $atom = new AtomNoticeFeed(); + $atom = new AtomNoticeFeed($this->auth_user); $atom->setId($id); $atom->setTitle($title); diff --git a/actions/apitimelinementions.php b/actions/apitimelinementions.php index c3aec7c5a..dc39122e5 100644 --- a/actions/apitimelinementions.php +++ b/actions/apitimelinementions.php @@ -151,7 +151,7 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction header('Content-Type: application/atom+xml; charset=utf-8'); - $atom = new AtomNoticeFeed(); + $atom = new AtomNoticeFeed($this->auth_user); $atom->setId($id); $atom->setTitle($title); diff --git a/actions/apitimelinepublic.php b/actions/apitimelinepublic.php index 903461425..49062e603 100644 --- a/actions/apitimelinepublic.php +++ b/actions/apitimelinepublic.php @@ -130,7 +130,7 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction header('Content-Type: application/atom+xml; charset=utf-8'); - $atom = new AtomNoticeFeed(); + $atom = new AtomNoticeFeed($this->auth_user); $atom->setId($id); $atom->setTitle($title); diff --git a/actions/apitimelineretweetsofme.php b/actions/apitimelineretweetsofme.php index c77912fd0..ea922fc42 100644 --- a/actions/apitimelineretweetsofme.php +++ b/actions/apitimelineretweetsofme.php @@ -117,7 +117,7 @@ class ApiTimelineRetweetsOfMeAction extends ApiAuthAction header('Content-Type: application/atom+xml; charset=utf-8'); - $atom = new AtomNoticeFeed(); + $atom = new AtomNoticeFeed($this->auth_user); $atom->setId($id); $atom->setTitle($title); diff --git a/actions/apitimelinetag.php b/actions/apitimelinetag.php index fed1437ea..c21b22702 100644 --- a/actions/apitimelinetag.php +++ b/actions/apitimelinetag.php @@ -138,7 +138,7 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction header('Content-Type: application/atom+xml; charset=utf-8'); - $atom = new AtomNoticeFeed(); + $atom = new AtomNoticeFeed($this->auth_user); $atom->setId($id); $atom->setTitle($title); diff --git a/actions/apitimelineuser.php b/actions/apitimelineuser.php index 11431a82c..9ee6abaf5 100644 --- a/actions/apitimelineuser.php +++ b/actions/apitimelineuser.php @@ -115,7 +115,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction // We'll use the shared params from the Atom stub // for other feed types. - $atom = new AtomUserNoticeFeed($this->user); + $atom = new AtomUserNoticeFeed($this->user, $this->auth_user); $link = common_local_url( 'showstream', diff --git a/lib/atomgroupnoticefeed.php b/lib/atomgroupnoticefeed.php index 08c1c707c..7934a4f9e 100644 --- a/lib/atomgroupnoticefeed.php +++ b/lib/atomgroupnoticefeed.php @@ -50,12 +50,13 @@ class AtomGroupNoticeFeed extends AtomNoticeFeed * Constructor * * @param Group $group the group for the feed + * @param User $cur the current authenticated user, if any * @param boolean $indent flag to turn indenting on or off * * @return void */ - function __construct($group, $indent = true) { - parent::__construct($indent); + function __construct($group, $cur = null, $indent = true) { + parent::__construct($cur, $indent); $this->group = $group; $title = sprintf(_("%s timeline"), $group->nickname); diff --git a/lib/atomnoticefeed.php b/lib/atomnoticefeed.php index 35a45118c..ef44de4b6 100644 --- a/lib/atomnoticefeed.php +++ b/lib/atomnoticefeed.php @@ -44,9 +44,22 @@ if (!defined('STATUSNET')) */ class AtomNoticeFeed extends Atom10Feed { - function __construct($indent = true) { + var $cur; + + /** + * Constructor - adds a bunch of XML namespaces we need in our + * notice-specific Atom feeds, and allows setting the current + * authenticated user (useful for API methods). + * + * @param User $cur the current authenticated user (optional) + * @param boolean $indent Whether to indent XML output + * + */ + function __construct($cur = null, $indent = true) { parent::__construct($indent); + $this->cur = $cur; + // Feeds containing notice info use these namespaces $this->addNamespace( @@ -115,7 +128,7 @@ class AtomNoticeFeed extends Atom10Feed $source = $this->showSource(); $author = $this->showAuthor(); - $cur = common_current_user(); + $cur = empty($this->cur) ? common_current_user() : $this->cur; $this->addEntryRaw($notice->asAtomEntry(false, $source, $author, $cur)); } diff --git a/lib/atomusernoticefeed.php b/lib/atomusernoticefeed.php index 428cc2de2..b569d9379 100644 --- a/lib/atomusernoticefeed.php +++ b/lib/atomusernoticefeed.php @@ -50,13 +50,14 @@ class AtomUserNoticeFeed extends AtomNoticeFeed * Constructor * * @param User $user the user for the feed + * @param User $cur the current authenticated user, if any * @param boolean $indent flag to turn indenting on or off * * @return void */ - function __construct($user, $indent = true) { - parent::__construct($indent); + function __construct($user, $cur = null, $indent = true) { + parent::__construct($cur, $indent); $this->user = $user; if (!empty($user)) { $profile = $user->getProfile(); -- cgit v1.2.3-54-g00ecf From 697a9948df3c9d4275b3525227007bfd5a1c5709 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 27 May 2010 14:18:08 -0700 Subject: Ticket #2329: fix for use of _m() translation functions from outside of plugin directories --- lib/language.php | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/language.php b/lib/language.php index 64b59e739..3846b8f35 100644 --- a/lib/language.php +++ b/lib/language.php @@ -205,12 +205,20 @@ function _mdomain($backtrace) if (DIRECTORY_SEPARATOR !== '/') { $path = strtr($path, DIRECTORY_SEPARATOR, '/'); } - $cut = strpos($path, '/plugins/') + 9; - $cut2 = strpos($path, '/', $cut); - if ($cut && $cut2) { - $cached[$path] = substr($path, $cut, $cut2 - $cut); - } else { + $plug = strpos($path, '/plugins/'); + if ($plug === false) { + // We're not in a plugin; return null for the default domain. return null; + } else { + $cut = $plug + 9; + $cut2 = strpos($path, '/', $cut); + if ($cut2) { + $cached[$path] = substr($path, $cut, $cut2 - $cut); + } else { + // We might be running directly from the plugins dir? + // If so, there's no place to store locale info. + return null; + } } } return $cached[$path]; -- cgit v1.2.3-54-g00ecf From 6317f7d92bf94f8563a7d9392631d0da06b3042b Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Thu, 27 May 2010 18:26:47 -0400 Subject: Assigning my copyrights to the Free Software Foundation --- actions/all.php | 1 + actions/apifavoritecreate.php | 1 + actions/apifavoritedestroy.php | 1 + actions/apigroupcreate.php | 1 + actions/apigroupismember.php | 1 + actions/apigroupjoin.php | 1 + actions/apigroupleave.php | 1 + actions/apigrouplist.php | 1 + actions/apigrouplistall.php | 1 + actions/apigroupmembership.php | 1 + actions/apigroupshow.php | 1 + actions/apistatusesdestroy.php | 1 + actions/apistatusesshow.php | 1 + actions/apistatusesupdate.php | 1 + actions/apitimelinefavorites.php | 1 + actions/apitimelinefriends.php | 1 + actions/apitimelinegroup.php | 1 + actions/apitimelinehome.php | 1 + actions/apitimelinementions.php | 1 + actions/apitimelinepublic.php | 1 + actions/apitimelinetag.php | 1 + actions/apitimelineuser.php | 1 + actions/geocode.php | 1 + actions/oembed.php | 1 + actions/publicxrds.php | 3 +++ actions/version.php | 2 ++ classes/Notice.php | 1 + index.php | 1 + install.php | 1 + lib/apiaction.php | 1 + lib/apiauth.php | 1 + lib/apibareauth.php | 3 ++- lib/apiprivateauth.php | 1 + lib/authenticationplugin.php | 1 + lib/authorizationplugin.php | 1 + lib/installer.php | 1 + lib/xrdsoutputter.php | 1 + plugins/Autocomplete/AutocompletePlugin.php | 3 ++- plugins/Autocomplete/autocomplete.php | 1 + plugins/BitlyUrl/BitlyUrlPlugin.php | 2 +- plugins/CasAuthentication/CasAuthenticationPlugin.php | 2 +- plugins/ClientSideShorten/ClientSideShortenPlugin.php | 2 +- plugins/ClientSideShorten/shorten.php | 1 + plugins/EmailAuthentication/EmailAuthenticationPlugin.php | 2 +- plugins/FirePHP/FirePHPPlugin.php | 8 +++++--- plugins/Imap/ImapPlugin.php | 4 +++- plugins/Imap/imapmanager.php | 2 ++ plugins/InfiniteScroll/InfiniteScrollPlugin.php | 2 +- plugins/LdapAuthentication/LdapAuthenticationPlugin.php | 2 +- plugins/LdapAuthorization/LdapAuthorizationPlugin.php | 2 +- plugins/LdapCommon/LdapCommon.php | 2 +- plugins/LdapCommon/MemcacheSchemaCache.php | 2 +- plugins/LilUrl/LilUrlPlugin.php | 2 +- plugins/Mapstraction/allmap.php | 1 + plugins/Mapstraction/map.php | 1 + plugins/Mapstraction/usermap.php | 1 + plugins/MemcachedPlugin.php | 8 ++++++-- plugins/Minify/MinifyPlugin.php | 1 + plugins/OpenID/OpenIDPlugin.php | 4 ++++ plugins/OpenID/openidserver.php | 2 ++ plugins/PtitUrl/PtitUrlPlugin.php | 2 +- plugins/RequireValidatedEmail/RequireValidatedEmailPlugin.php | 5 +++-- .../ReverseUsernameAuthenticationPlugin.php | 2 +- plugins/SimpleUrl/SimpleUrlPlugin.php | 2 +- plugins/TabFocus/TabFocusPlugin.php | 2 +- plugins/TightUrl/TightUrlPlugin.php | 2 +- plugins/UrlShortener/UrlShortenerPlugin.php | 1 + 67 files changed, 90 insertions(+), 25 deletions(-) (limited to 'lib') diff --git a/actions/all.php b/actions/all.php index a977fce95..a6738863b 100644 --- a/actions/all.php +++ b/actions/all.php @@ -27,6 +27,7 @@ * @author Craig Andrews * @author Jeffery To * @author Zach Copley + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license GNU Affero General Public License http://www.gnu.org/licenses/ * @link http://status.net */ diff --git a/actions/apifavoritecreate.php b/actions/apifavoritecreate.php index 00b6349b0..0447a92ba 100644 --- a/actions/apifavoritecreate.php +++ b/actions/apifavoritecreate.php @@ -25,6 +25,7 @@ * @author Evan Prodromou * @author Zach Copley * @copyright 2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/actions/apifavoritedestroy.php b/actions/apifavoritedestroy.php index c4daf480e..9f2efdd00 100644 --- a/actions/apifavoritedestroy.php +++ b/actions/apifavoritedestroy.php @@ -25,6 +25,7 @@ * @author Evan Prodromou * @author Zach Copley * @copyright 2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/actions/apigroupcreate.php b/actions/apigroupcreate.php index 3eb3ae5fc..d216c15cd 100644 --- a/actions/apigroupcreate.php +++ b/actions/apigroupcreate.php @@ -26,6 +26,7 @@ * @author Jeffery To * @author Zach Copley * @copyright 2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/actions/apigroupismember.php b/actions/apigroupismember.php index f51c747df..eaa4769f3 100644 --- a/actions/apigroupismember.php +++ b/actions/apigroupismember.php @@ -26,6 +26,7 @@ * @author Jeffery To * @author Zach Copley * @copyright 2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/actions/apigroupjoin.php b/actions/apigroupjoin.php index 28df72fa9..5265ec629 100644 --- a/actions/apigroupjoin.php +++ b/actions/apigroupjoin.php @@ -26,6 +26,7 @@ * @author Jeffery To * @author Zach Copley * @copyright 2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/actions/apigroupleave.php b/actions/apigroupleave.php index f6e52b26e..8c100d58a 100644 --- a/actions/apigroupleave.php +++ b/actions/apigroupleave.php @@ -26,6 +26,7 @@ * @author Jeffery To * @author Zach Copley * @copyright 2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/actions/apigrouplist.php b/actions/apigrouplist.php index 3ea2c30cb..148c802f4 100644 --- a/actions/apigrouplist.php +++ b/actions/apigrouplist.php @@ -26,6 +26,7 @@ * @author Jeffery To * @author Zach Copley * @copyright 2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/actions/apigrouplistall.php b/actions/apigrouplistall.php index bd05fa3ea..a8317608d 100644 --- a/actions/apigrouplistall.php +++ b/actions/apigrouplistall.php @@ -26,6 +26,7 @@ * @author Jeffery To * @author Zach Copley * @copyright 2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/actions/apigroupmembership.php b/actions/apigroupmembership.php index c97b27fac..ffd5c7c7d 100644 --- a/actions/apigroupmembership.php +++ b/actions/apigroupmembership.php @@ -26,6 +26,7 @@ * @author Jeffery To * @author Zach Copley * @copyright 2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/actions/apigroupshow.php b/actions/apigroupshow.php index 8e471689a..2998e505e 100644 --- a/actions/apigroupshow.php +++ b/actions/apigroupshow.php @@ -26,6 +26,7 @@ * @author Jeffery To * @author Zach Copley * @copyright 2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/actions/apistatusesdestroy.php b/actions/apistatusesdestroy.php index f7d52f020..250b4236b 100644 --- a/actions/apistatusesdestroy.php +++ b/actions/apistatusesdestroy.php @@ -29,6 +29,7 @@ * @author Robin Millette * @author Zach Copley * @copyright 2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/actions/apistatusesshow.php b/actions/apistatusesshow.php index 0315d2953..476820a43 100644 --- a/actions/apistatusesshow.php +++ b/actions/apistatusesshow.php @@ -29,6 +29,7 @@ * @author Robin Millette * @author Zach Copley * @copyright 2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/actions/apistatusesupdate.php b/actions/apistatusesupdate.php index a0a81f336..d65a068f5 100644 --- a/actions/apistatusesupdate.php +++ b/actions/apistatusesupdate.php @@ -29,6 +29,7 @@ * @author Robin Millette * @author Zach Copley * @copyright 2009-2010 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/actions/apitimelinefavorites.php b/actions/apitimelinefavorites.php index a889b4918..7228960c0 100644 --- a/actions/apitimelinefavorites.php +++ b/actions/apitimelinefavorites.php @@ -25,6 +25,7 @@ * @author Evan Prodromou * @author Zach Copley * @copyright 2009-2010 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/actions/apitimelinefriends.php b/actions/apitimelinefriends.php index a3340ff46..40ce35979 100644 --- a/actions/apitimelinefriends.php +++ b/actions/apitimelinefriends.php @@ -29,6 +29,7 @@ * @author Robin Millette * @author Zach Copley * @copyright 2009-2010 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/actions/apitimelinegroup.php b/actions/apitimelinegroup.php index 76fa74767..c4a6a18d2 100644 --- a/actions/apitimelinegroup.php +++ b/actions/apitimelinegroup.php @@ -26,6 +26,7 @@ * @author Jeffery To * @author Zach Copley * @copyright 2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/actions/apitimelinehome.php b/actions/apitimelinehome.php index 0470e96aa..27eb74169 100644 --- a/actions/apitimelinehome.php +++ b/actions/apitimelinehome.php @@ -29,6 +29,7 @@ * @author Robin Millette * @author Zach Copley * @copyright 2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/actions/apitimelinementions.php b/actions/apitimelinementions.php index dc39122e5..ed1ad20e3 100644 --- a/actions/apitimelinementions.php +++ b/actions/apitimelinementions.php @@ -29,6 +29,7 @@ * @author Robin Millette * @author Zach Copley * @copyright 2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/actions/apitimelinepublic.php b/actions/apitimelinepublic.php index 5b88c97d9..f90164288 100644 --- a/actions/apitimelinepublic.php +++ b/actions/apitimelinepublic.php @@ -29,6 +29,7 @@ * @author Robin Millette * @author Zach Copley * @copyright 2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/actions/apitimelinetag.php b/actions/apitimelinetag.php index c21b22702..c7ec172ae 100644 --- a/actions/apitimelinetag.php +++ b/actions/apitimelinetag.php @@ -26,6 +26,7 @@ * @author Jeffery To * @author Zach Copley * @copyright 2009-2010 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/actions/apitimelineuser.php b/actions/apitimelineuser.php index 9ee6abaf5..17a283663 100644 --- a/actions/apitimelineuser.php +++ b/actions/apitimelineuser.php @@ -29,6 +29,7 @@ * @author Robin Millette * @author Zach Copley * @copyright 2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/actions/geocode.php b/actions/geocode.php index e883c6ce4..d93493060 100644 --- a/actions/geocode.php +++ b/actions/geocode.php @@ -37,6 +37,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { * @category Action * @package StatusNet * @author Craig Andrews + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @link http://status.net/ */ diff --git a/actions/oembed.php b/actions/oembed.php index 1503aa9c2..e25e4cb25 100644 --- a/actions/oembed.php +++ b/actions/oembed.php @@ -23,6 +23,7 @@ * @package StatusNet * @author Evan Prodromou * @copyright 2008 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/actions/publicxrds.php b/actions/publicxrds.php index 5fd4eead7..8f0337e4f 100644 --- a/actions/publicxrds.php +++ b/actions/publicxrds.php @@ -8,7 +8,9 @@ * @category Action * @package StatusNet * @author Evan Prodromou + * @author Craig Andrews * @author Robin Millette + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @link http://status.net/ * @@ -44,6 +46,7 @@ require_once INSTALLDIR.'/lib/xrdsoutputter.php'; * @author Evan Prodromou * @author Robin Millette * @author Craig Andrews + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @link http://status.net/ * diff --git a/actions/version.php b/actions/version.php index b6593e5ed..9e4e836d2 100644 --- a/actions/version.php +++ b/actions/version.php @@ -41,6 +41,8 @@ if (!defined('STATUSNET')) { * @category Info * @package StatusNet * @author Evan Prodromou + * @author Craig Andrews + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 * @link http://status.net/ */ diff --git a/classes/Notice.php b/classes/Notice.php index 2613b1737..c8cfb5abb 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -29,6 +29,7 @@ * @author Robin Millette * @author Sarven Capadisli * @author Tom Adams + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license GNU Affero General Public License http://www.gnu.org/licenses/ */ diff --git a/index.php b/index.php index fa9f67269..d68a057c4 100644 --- a/index.php +++ b/index.php @@ -29,6 +29,7 @@ * @author Robin Millette * @author Sarven Capadisli * @author Tom Adams + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * * @license GNU Affero General Public License http://www.gnu.org/licenses/ */ diff --git a/install.php b/install.php index 08555d19b..158d51fa3 100644 --- a/install.php +++ b/install.php @@ -31,6 +31,7 @@ * @author Sarven Capadisli * @author Tom Adams * @author Zach Copley + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license GNU Affero General Public License http://www.gnu.org/licenses/ * @version 0.9.x * @link http://status.net diff --git a/lib/apiaction.php b/lib/apiaction.php index 80a8a08d1..7085c096b 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -28,6 +28,7 @@ * @author Toby Inkster * @author Zach Copley * @copyright 2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/lib/apiauth.php b/lib/apiauth.php index 9c68e2771..91cb64262 100644 --- a/lib/apiauth.php +++ b/lib/apiauth.php @@ -30,6 +30,7 @@ * @author Sarven Capadisli * @author Zach Copley * @copyright 2009-2010 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/lib/apibareauth.php b/lib/apibareauth.php index 2d29c1ddd..da7af1261 100644 --- a/lib/apibareauth.php +++ b/lib/apibareauth.php @@ -32,6 +32,7 @@ * @author Sarven Capadisli * @author Zach Copley * @copyright 2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ @@ -106,4 +107,4 @@ class ApiBareAuthAction extends ApiAuthAction return false; } -} \ No newline at end of file +} diff --git a/lib/apiprivateauth.php b/lib/apiprivateauth.php index 5d0033005..5e78c65a1 100644 --- a/lib/apiprivateauth.php +++ b/lib/apiprivateauth.php @@ -31,6 +31,7 @@ * @author Sarven Capadisli * @author Zach Copley * @copyright 2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/lib/authenticationplugin.php b/lib/authenticationplugin.php index 0a3763e2e..dbdf20629 100644 --- a/lib/authenticationplugin.php +++ b/lib/authenticationplugin.php @@ -22,6 +22,7 @@ * @category Plugin * @package StatusNet * @author Craig Andrews + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/lib/authorizationplugin.php b/lib/authorizationplugin.php index 3790bccf4..d71f77243 100644 --- a/lib/authorizationplugin.php +++ b/lib/authorizationplugin.php @@ -22,6 +22,7 @@ * @category Plugin * @package StatusNet * @author Craig Andrews + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/lib/installer.php b/lib/installer.php index 58ffbfef7..1cad2fd20 100644 --- a/lib/installer.php +++ b/lib/installer.php @@ -32,6 +32,7 @@ * @author Sarven Capadisli * @author Tom Adams * @author Zach Copley + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license GNU Affero General Public License http://www.gnu.org/licenses/ * @version 0.9.x * @link http://status.net diff --git a/lib/xrdsoutputter.php b/lib/xrdsoutputter.php index 4b77ed5a3..95dc73300 100644 --- a/lib/xrdsoutputter.php +++ b/lib/xrdsoutputter.php @@ -23,6 +23,7 @@ * @package StatusNet * @author Craig Andrews * @copyright 2008 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/Autocomplete/AutocompletePlugin.php b/plugins/Autocomplete/AutocompletePlugin.php index b2b18bf27..b2be365dd 100644 --- a/plugins/Autocomplete/AutocompletePlugin.php +++ b/plugins/Autocomplete/AutocompletePlugin.php @@ -22,7 +22,8 @@ * @category Plugin * @package StatusNet * @author Craig Andrews - * @copyright 2009 Craig Andrews http://candrews.integralblue.com + * @copyright 2010 Free Software Foundation http://fsf.org + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/Autocomplete/autocomplete.php b/plugins/Autocomplete/autocomplete.php index 379390ffd..9a30ba01d 100644 --- a/plugins/Autocomplete/autocomplete.php +++ b/plugins/Autocomplete/autocomplete.php @@ -23,6 +23,7 @@ * @package StatusNet * @author Craig Andrews * @copyright 2008-2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/BitlyUrl/BitlyUrlPlugin.php b/plugins/BitlyUrl/BitlyUrlPlugin.php index f7f28b4d6..11e3c0b84 100644 --- a/plugins/BitlyUrl/BitlyUrlPlugin.php +++ b/plugins/BitlyUrl/BitlyUrlPlugin.php @@ -22,7 +22,7 @@ * @category Plugin * @package StatusNet * @author Craig Andrews - * @copyright 2009 Craig Andrews http://candrews.integralblue.com + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/CasAuthentication/CasAuthenticationPlugin.php b/plugins/CasAuthentication/CasAuthenticationPlugin.php index 203e5fe42..1662db3eb 100644 --- a/plugins/CasAuthentication/CasAuthenticationPlugin.php +++ b/plugins/CasAuthentication/CasAuthenticationPlugin.php @@ -22,7 +22,7 @@ * @category Plugin * @package StatusNet * @author Craig Andrews - * @copyright 2009 Craig Andrews http://candrews.integralblue.com + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/ClientSideShorten/ClientSideShortenPlugin.php b/plugins/ClientSideShorten/ClientSideShortenPlugin.php index ba1f7d3a7..57f5ad89e 100644 --- a/plugins/ClientSideShorten/ClientSideShortenPlugin.php +++ b/plugins/ClientSideShorten/ClientSideShortenPlugin.php @@ -22,7 +22,7 @@ * @category Plugin * @package StatusNet * @author Craig Andrews - * @copyright 2009 Craig Andrews http://candrews.integralblue.com + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/ClientSideShorten/shorten.php b/plugins/ClientSideShorten/shorten.php index 07c19e2e7..f67cbf3b2 100644 --- a/plugins/ClientSideShorten/shorten.php +++ b/plugins/ClientSideShorten/shorten.php @@ -23,6 +23,7 @@ * @package StatusNet * @author Craig Andrews * @copyright 2008-2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/EmailAuthentication/EmailAuthenticationPlugin.php b/plugins/EmailAuthentication/EmailAuthenticationPlugin.php index 406c00073..4c018537b 100644 --- a/plugins/EmailAuthentication/EmailAuthenticationPlugin.php +++ b/plugins/EmailAuthentication/EmailAuthenticationPlugin.php @@ -22,7 +22,7 @@ * @category Plugin * @package StatusNet * @author Craig Andrews - * @copyright 2009 Craig Andrews http://candrews.integralblue.com + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/FirePHP/FirePHPPlugin.php b/plugins/FirePHP/FirePHPPlugin.php index 9143ff69c..d984ec1af 100644 --- a/plugins/FirePHP/FirePHPPlugin.php +++ b/plugins/FirePHP/FirePHPPlugin.php @@ -24,11 +24,13 @@ Author URI: http://candrews.integralblue.com/ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . - */ - -/** + * @category Plugin * @package MinifyPlugin * @maintainer Craig Andrews + * @author Craig Andrews + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ */ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } diff --git a/plugins/Imap/ImapPlugin.php b/plugins/Imap/ImapPlugin.php index d1e920b00..66be799d3 100644 --- a/plugins/Imap/ImapPlugin.php +++ b/plugins/Imap/ImapPlugin.php @@ -21,8 +21,9 @@ * * @category Plugin * @package StatusNet - * @author Zach Copley + * @author Craig Andrews * @copyright 2009-2010 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org + * @maintainer Craig Andrews * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/InfiniteScroll/InfiniteScrollPlugin.php b/plugins/InfiniteScroll/InfiniteScrollPlugin.php index a4d1a5d05..50c1b5a20 100644 --- a/plugins/InfiniteScroll/InfiniteScrollPlugin.php +++ b/plugins/InfiniteScroll/InfiniteScrollPlugin.php @@ -22,7 +22,7 @@ * @category Plugin * @package StatusNet * @author Craig Andrews - * @copyright 2009 Craig Andrews http://candrews.integralblue.com + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/LdapAuthentication/LdapAuthenticationPlugin.php b/plugins/LdapAuthentication/LdapAuthenticationPlugin.php index 0dfc4c63b..52d326287 100644 --- a/plugins/LdapAuthentication/LdapAuthenticationPlugin.php +++ b/plugins/LdapAuthentication/LdapAuthenticationPlugin.php @@ -22,7 +22,7 @@ * @category Plugin * @package StatusNet * @author Craig Andrews - * @copyright 2009 Craig Andrews http://candrews.integralblue.com + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/LdapAuthorization/LdapAuthorizationPlugin.php b/plugins/LdapAuthorization/LdapAuthorizationPlugin.php index 97103d158..3842385cf 100644 --- a/plugins/LdapAuthorization/LdapAuthorizationPlugin.php +++ b/plugins/LdapAuthorization/LdapAuthorizationPlugin.php @@ -22,7 +22,7 @@ * @category Plugin * @package StatusNet * @author Craig Andrews - * @copyright 2009 Craig Andrews http://candrews.integralblue.com + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/LdapCommon/LdapCommon.php b/plugins/LdapCommon/LdapCommon.php index ee436d824..1f1647a75 100644 --- a/plugins/LdapCommon/LdapCommon.php +++ b/plugins/LdapCommon/LdapCommon.php @@ -22,7 +22,7 @@ * @category Plugin * @package StatusNet * @author Craig Andrews - * @copyright 2009 Craig Andrews http://candrews.integralblue.com + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/LdapCommon/MemcacheSchemaCache.php b/plugins/LdapCommon/MemcacheSchemaCache.php index 6b91d17d6..4ee2e8e16 100644 --- a/plugins/LdapCommon/MemcacheSchemaCache.php +++ b/plugins/LdapCommon/MemcacheSchemaCache.php @@ -22,7 +22,7 @@ * @category Plugin * @package StatusNet * @author Craig Andrews - * @copyright 2009 Craig Andrews http://candrews.integralblue.com + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/LilUrl/LilUrlPlugin.php b/plugins/LilUrl/LilUrlPlugin.php index c3e37c0c0..1c3d6f84b 100644 --- a/plugins/LilUrl/LilUrlPlugin.php +++ b/plugins/LilUrl/LilUrlPlugin.php @@ -22,7 +22,7 @@ * @category Plugin * @package StatusNet * @author Craig Andrews - * @copyright 2009 Craig Andrews http://candrews.integralblue.com + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/Mapstraction/allmap.php b/plugins/Mapstraction/allmap.php index e73aa76e8..5dab670e2 100644 --- a/plugins/Mapstraction/allmap.php +++ b/plugins/Mapstraction/allmap.php @@ -38,6 +38,7 @@ if (!defined('STATUSNET')) { * @package StatusNet * @author Evan Prodromou * @author Craig Andrews + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/Mapstraction/map.php b/plugins/Mapstraction/map.php index b809c1b8e..7dab8e10a 100644 --- a/plugins/Mapstraction/map.php +++ b/plugins/Mapstraction/map.php @@ -38,6 +38,7 @@ if (!defined('STATUSNET')) { * @package StatusNet * @author Evan Prodromou * @author Craig Andrews + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/Mapstraction/usermap.php b/plugins/Mapstraction/usermap.php index ff47b6ada..094334f60 100644 --- a/plugins/Mapstraction/usermap.php +++ b/plugins/Mapstraction/usermap.php @@ -38,6 +38,7 @@ if (!defined('STATUSNET')) { * @package StatusNet * @author Evan Prodromou * @author Craig Andrews + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/MemcachedPlugin.php b/plugins/MemcachedPlugin.php index 707e6db9a..77b989b95 100644 --- a/plugins/MemcachedPlugin.php +++ b/plugins/MemcachedPlugin.php @@ -22,8 +22,10 @@ * * @category Cache * @package StatusNet - * @author Evan Prodromou , Craig Andrews + * @author Evan Prodromou + * @author Craig Andrews * @copyright 2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ @@ -43,8 +45,10 @@ if (!defined('STATUSNET')) { * * @category Cache * @package StatusNet - * @author Evan Prodromou , Craig Andrews + * @author Evan Prodromou + * @author Craig Andrews * @copyright 2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/Minify/MinifyPlugin.php b/plugins/Minify/MinifyPlugin.php index 69def6064..13010e75a 100644 --- a/plugins/Minify/MinifyPlugin.php +++ b/plugins/Minify/MinifyPlugin.php @@ -29,6 +29,7 @@ Author URI: http://candrews.integralblue.com/ /** * @package MinifyPlugin * @maintainer Craig Andrews + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org */ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } diff --git a/plugins/OpenID/OpenIDPlugin.php b/plugins/OpenID/OpenIDPlugin.php index fdcfacfa5..7d6a5dc00 100644 --- a/plugins/OpenID/OpenIDPlugin.php +++ b/plugins/OpenID/OpenIDPlugin.php @@ -20,7 +20,9 @@ * @category Plugin * @package StatusNet * @author Evan Prodromou + * @author Craig Andrews * @copyright 2009-2010 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ @@ -38,6 +40,8 @@ if (!defined('STATUSNET')) { * @category Plugin * @package StatusNet * @author Evan Prodromou + * @author Craig Andrews + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ * @link http://openid.net/ diff --git a/plugins/OpenID/openidserver.php b/plugins/OpenID/openidserver.php index f7e3a45f2..0e16881c5 100644 --- a/plugins/OpenID/openidserver.php +++ b/plugins/OpenID/openidserver.php @@ -23,6 +23,7 @@ * @package StatusNet * @author Craig Andrews * @copyright 2008-2009 StatusNet, Inc. + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ @@ -43,6 +44,7 @@ require_once(INSTALLDIR.'/plugins/OpenID/User_openid_trustroot.php'); * @category Settings * @package StatusNet * @author Craig Andrews + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/PtitUrl/PtitUrlPlugin.php b/plugins/PtitUrl/PtitUrlPlugin.php index ddba942e6..2963e8997 100644 --- a/plugins/PtitUrl/PtitUrlPlugin.php +++ b/plugins/PtitUrl/PtitUrlPlugin.php @@ -22,7 +22,7 @@ * @category Plugin * @package StatusNet * @author Craig Andrews - * @copyright 2009 Craig Andrews http://candrews.integralblue.com + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/RequireValidatedEmail/RequireValidatedEmailPlugin.php b/plugins/RequireValidatedEmail/RequireValidatedEmailPlugin.php index 009a2f78e..af75b96e0 100644 --- a/plugins/RequireValidatedEmail/RequireValidatedEmailPlugin.php +++ b/plugins/RequireValidatedEmail/RequireValidatedEmailPlugin.php @@ -21,8 +21,9 @@ * * @category Plugin * @package StatusNet - * @author Craig Andrews , Brion Vibber - * @copyright 2009 Craig Andrews http://candrews.integralblue.com + * @author Craig Andrews + * @author Brion Vibber + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/ReverseUsernameAuthentication/ReverseUsernameAuthenticationPlugin.php b/plugins/ReverseUsernameAuthentication/ReverseUsernameAuthenticationPlugin.php index dac5a1588..8a05a7734 100644 --- a/plugins/ReverseUsernameAuthentication/ReverseUsernameAuthenticationPlugin.php +++ b/plugins/ReverseUsernameAuthentication/ReverseUsernameAuthenticationPlugin.php @@ -22,7 +22,7 @@ * @category Plugin * @package StatusNet * @author Craig Andrews - * @copyright 2009 Craig Andrews http://candrews.integralblue.com + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/SimpleUrl/SimpleUrlPlugin.php b/plugins/SimpleUrl/SimpleUrlPlugin.php index 6eac7dbb1..5e2e85878 100644 --- a/plugins/SimpleUrl/SimpleUrlPlugin.php +++ b/plugins/SimpleUrl/SimpleUrlPlugin.php @@ -22,7 +22,7 @@ * @category Plugin * @package StatusNet * @author Craig Andrews - * @copyright 2009 Craig Andrews http://candrews.integralblue.com + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/TabFocus/TabFocusPlugin.php b/plugins/TabFocus/TabFocusPlugin.php index bf89c478c..46e329d8a 100644 --- a/plugins/TabFocus/TabFocusPlugin.php +++ b/plugins/TabFocus/TabFocusPlugin.php @@ -23,7 +23,7 @@ * @package StatusNet * @author Craig Andrews * @author Paul Irish - * @copyright 2009 Craig Andrews http://candrews.integralblue.com + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/TightUrl/TightUrlPlugin.php b/plugins/TightUrl/TightUrlPlugin.php index e2d494a7b..b8e5addb1 100644 --- a/plugins/TightUrl/TightUrlPlugin.php +++ b/plugins/TightUrl/TightUrlPlugin.php @@ -22,7 +22,7 @@ * @category Plugin * @package StatusNet * @author Craig Andrews - * @copyright 2009 Craig Andrews http://candrews.integralblue.com + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ diff --git a/plugins/UrlShortener/UrlShortenerPlugin.php b/plugins/UrlShortener/UrlShortenerPlugin.php index 027624b7a..41f64bb26 100644 --- a/plugins/UrlShortener/UrlShortenerPlugin.php +++ b/plugins/UrlShortener/UrlShortenerPlugin.php @@ -22,6 +22,7 @@ * @category Plugin * @package StatusNet * @author Craig Andrews + * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ -- cgit v1.2.3-54-g00ecf From f4539b52ad2c25a87e906c68d955ef921678e18c Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 28 May 2010 16:03:09 -0700 Subject: Ticket 2329 followup: my clever 'let it use the default' was foiled by PHP gettext module not quite exposing a compatible interface as the backend gettext library. (Most funcs squash null domain parameter into '' empty string, which isn't interpreted as 'use the current default'.) --- lib/language.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/language.php b/lib/language.php index 3846b8f35..cb12cca69 100644 --- a/lib/language.php +++ b/lib/language.php @@ -61,7 +61,7 @@ if (!function_exists('dpgettext')) { * Not currently exposed in PHP's gettext module; implemented to be compat * with gettext.h's macros. * - * @param string $domain domain identifier, or null for default domain + * @param string $domain domain identifier * @param string $context context identifier, should be some key like "menu|file" * @param string $msgid English source text * @return string original or translated message @@ -106,7 +106,7 @@ if (!function_exists('dnpgettext')) { * Not currently exposed in PHP's gettext module; implemented to be compat * with gettext.h's macros. * - * @param string $domain domain identifier, or null for default domain + * @param string $domain domain identifier * @param string $context context identifier, should be some key like "menu|file" * @param string $msg singular English source text * @param string $plural plural English source text @@ -180,7 +180,11 @@ function _m($msg/*, ...*/) } /** - * Looks for which plugin we've been called from to set the gettext domain. + * Looks for which plugin we've been called from to set the gettext domain; + * if not in a plugin subdirectory, we'll use the default 'statusnet'. + * + * Note: we can't return null for default domain since most of the PHP gettext + * wrapper functions turn null into "" before passing to the backend library. * * @param array $backtrace debug_backtrace() output * @return string @@ -207,8 +211,8 @@ function _mdomain($backtrace) } $plug = strpos($path, '/plugins/'); if ($plug === false) { - // We're not in a plugin; return null for the default domain. - return null; + // We're not in a plugin; return default domain. + return 'statusnet'; } else { $cut = $plug + 9; $cut2 = strpos($path, '/', $cut); @@ -217,7 +221,7 @@ function _mdomain($backtrace) } else { // We might be running directly from the plugins dir? // If so, there's no place to store locale info. - return null; + return 'statusnet'; } } } -- cgit v1.2.3-54-g00ecf From 9bb48c36eab5e6856b7768c273d382a825f22ff0 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 3 Jun 2010 10:13:28 -0700 Subject: Installer tweak to aid with IIS setup: if config.php exists, but is both empty and writable, let the installer proceed and overwrite it. --- lib/installer.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/installer.php b/lib/installer.php index 58ffbfef7..7936d5d5d 100644 --- a/lib/installer.php +++ b/lib/installer.php @@ -81,9 +81,12 @@ abstract class Installer { $pass = true; - if (file_exists(INSTALLDIR.'/config.php')) { - $this->warning('Config file "config.php" already exists.'); - $pass = false; + $config = INSTALLDIR.'/config.php'; + if (file_exists($config)) { + if (!is_writable($config) || filesize($config) > 0) { + $this->warning('Config file "config.php" already exists.'); + $pass = false; + } } if (version_compare(PHP_VERSION, '5.2.3', '<')) { -- cgit v1.2.3-54-g00ecf From 791b98046d2c81aecfa468c06d4b7fd1f06ea8fa Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 3 Jun 2010 16:09:47 -0700 Subject: Stomp blocking writes fix --- lib/liberalstomp.php | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/liberalstomp.php b/lib/liberalstomp.php index 3d38953fd..70c22c17e 100644 --- a/lib/liberalstomp.php +++ b/lib/liberalstomp.php @@ -147,5 +147,30 @@ class LiberalStomp extends Stomp } return $frame; } -} + + /** + * Write frame to server + * + * @param StompFrame $stompFrame + */ + protected function _writeFrame (StompFrame $stompFrame) + { + if (!is_resource($this->_socket)) { + require_once 'Stomp/Exception.php'; + throw new StompException('Socket connection hasn\'t been established'); + } + + $data = $stompFrame->__toString(); + + // Make sure the socket's in a writable state; if not, wait a bit. + stream_set_blocking($this->_socket, 1); + + $r = fwrite($this->_socket, $data, strlen($data)); + stream_set_blocking($this->_socket, 0); + if ($r === false || $r == 0) { + $this->_reconnect(); + $this->_writeFrame($stompFrame); + } + } + } -- cgit v1.2.3-54-g00ecf From 5f4c6ec626d3d641f0712b276deb32b218b7a330 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 3 Jun 2010 16:58:45 -0700 Subject: Skip enqueueing to outgoing bridges on incoming remote messages. Twitter, Facebook, RSSCloud, and OStatus checks were enqueued on these when they'd never do anything but churn the queue servers. Notice::isLocal() can replace a number of manual checks for $notice->is_local being LOCAL_PUBLIC or LOCAL_NONPUBLIC. --- classes/Notice.php | 12 ++++++++++++ lib/util.php | 5 ++--- plugins/Facebook/FacebookPlugin.php | 2 +- plugins/OStatus/OStatusPlugin.php | 6 ++++-- plugins/RSSCloud/RSSCloudPlugin.php | 18 +++--------------- plugins/TwitterBridge/TwitterBridgePlugin.php | 2 +- 6 files changed, 23 insertions(+), 22 deletions(-) (limited to 'lib') diff --git a/classes/Notice.php b/classes/Notice.php index 3d7d21533..cda632885 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1861,4 +1861,16 @@ class Notice extends Memcached_DataObject return $ns; } + /** + * Determine whether the notice was locally created + * + * @return boolean locality + */ + + public function isLocal() + { + return ($this->is_local == Notice::LOCAL_PUBLIC || + $this->is_local == Notice::LOCAL_NONPUBLIC); + } + } diff --git a/lib/util.php b/lib/util.php index 59d5132ec..049001aba 100644 --- a/lib/util.php +++ b/lib/util.php @@ -1235,9 +1235,8 @@ function common_enqueue_notice($notice) $transports[] = 'jabber'; } - // @fixme move these checks into QueueManager and/or individual handlers - if ($notice->is_local == Notice::LOCAL_PUBLIC || - $notice->is_local == Notice::LOCAL_NONPUBLIC) { + // We can skip these for gatewayed notices. + if ($notice->isLocal()) { $transports = array_merge($transports, $localTransports); if ($xmpp) { $transports[] = 'public'; diff --git a/plugins/Facebook/FacebookPlugin.php b/plugins/Facebook/FacebookPlugin.php index 5dba73a5d..19989a952 100644 --- a/plugins/Facebook/FacebookPlugin.php +++ b/plugins/Facebook/FacebookPlugin.php @@ -585,7 +585,7 @@ class FacebookPlugin extends Plugin function onStartEnqueueNotice($notice, &$transports) { - if (self::hasKeys()) { + if (self::hasKeys() && $notice->isLocal()) { array_push($transports, 'facebook'); } return true; diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 5b153216e..5a657c83d 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -102,8 +102,10 @@ class OStatusPlugin extends Plugin */ function onStartEnqueueNotice($notice, &$transports) { - // put our transport first, in case there's any conflict (like OMB) - array_unshift($transports, 'ostatus'); + if ($notice->isLocal()) { + // put our transport first, in case there's any conflict (like OMB) + array_unshift($transports, 'ostatus'); + } return true; } diff --git a/plugins/RSSCloud/RSSCloudPlugin.php b/plugins/RSSCloud/RSSCloudPlugin.php index 661c32141..c1951cdbf 100644 --- a/plugins/RSSCloud/RSSCloudPlugin.php +++ b/plugins/RSSCloud/RSSCloudPlugin.php @@ -192,24 +192,12 @@ class RSSCloudPlugin extends Plugin function onStartEnqueueNotice($notice, &$transports) { - array_push($transports, 'rsscloud'); + if ($notice->isLocal()) { + array_push($transports, 'rsscloud'); + } return true; } - /** - * Determine whether the notice was locally created - * - * @param Notice $notice the notice in question - * - * @return boolean locality - */ - - function _isLocal($notice) - { - return ($notice->is_local == Notice::LOCAL_PUBLIC || - $notice->is_local == Notice::LOCAL_NONPUBLIC); - } - /** * Create the rsscloud_subscription table if it's not * already in the DB diff --git a/plugins/TwitterBridge/TwitterBridgePlugin.php b/plugins/TwitterBridge/TwitterBridgePlugin.php index 1a0a69682..65b3a6b38 100644 --- a/plugins/TwitterBridge/TwitterBridgePlugin.php +++ b/plugins/TwitterBridge/TwitterBridgePlugin.php @@ -221,7 +221,7 @@ class TwitterBridgePlugin extends Plugin */ function onStartEnqueueNotice($notice, &$transports) { - if (self::hasKeys()) { + if (self::hasKeys() && $notice->isLocal()) { // Avoid a possible loop if ($notice->source != 'twitter') { array_push($transports, 'twitter'); -- cgit v1.2.3-54-g00ecf From 8b9436e8ae1ebcc7ef10752bb9666939200e26aa Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 3 Jun 2010 17:49:20 -0700 Subject: Option to divert PuSH items directly to the target site's queue when local --- classes/Status_network.php | 29 ++++++++++++++++++++--------- lib/stompqueuemanager.php | 9 +++++---- plugins/OStatus/classes/HubSub.php | 31 +++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/classes/Status_network.php b/classes/Status_network.php index a452c32ce..4a1f2c374 100644 --- a/classes/Status_network.php +++ b/classes/Status_network.php @@ -149,21 +149,15 @@ class Status_network extends Safe_DataObject $this->decache(); # while we still have the values! return parent::delete(); } - + /** * @param string $servername hostname - * @param string $pathname URL base path * @param string $wildcard hostname suffix to match wildcard config + * @return mixed Status_network or null */ - static function setupSite($servername, $pathname, $wildcard) + static function getFromHostname($servername, $wildcard) { - global $config; - $sn = null; - - // XXX I18N, probably not crucial for hostnames - // XXX This probably needs a tune up - if (0 == strncasecmp(strrev($wildcard), strrev($servername), strlen($wildcard))) { // special case for exact match if (0 == strcasecmp($servername, $wildcard)) { @@ -182,6 +176,23 @@ class Status_network extends Safe_DataObject } } } + return $sn; + } + + /** + * @param string $servername hostname + * @param string $pathname URL base path + * @param string $wildcard hostname suffix to match wildcard config + */ + static function setupSite($servername, $pathname, $wildcard) + { + global $config; + + $sn = null; + + // XXX I18N, probably not crucial for hostnames + // XXX This probably needs a tune up + $sn = self::getFromHostname($servername, $wildcard); if (!empty($sn)) { diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php index de4ba7f01..91faa8c36 100644 --- a/lib/stompqueuemanager.php +++ b/lib/stompqueuemanager.php @@ -115,11 +115,12 @@ class StompQueueManager extends QueueManager * * @param mixed $object * @param string $queue + * @param string $siteNickname optional override to drop into another site's queue * * @return boolean true on success * @throws StompException on connection or send error */ - public function enqueue($object, $queue) + public function enqueue($object, $queue, $siteNickname=null) { $this->_connect(); if (common_config('queue', 'stomp_enqueue_on')) { @@ -134,7 +135,7 @@ class StompQueueManager extends QueueManager } else { $idx = $this->defaultIdx; } - return $this->_doEnqueue($object, $queue, $idx); + return $this->_doEnqueue($object, $queue, $idx, $siteNickname); } /** @@ -144,10 +145,10 @@ class StompQueueManager extends QueueManager * @return boolean true on success * @throws StompException on connection or send error */ - protected function _doEnqueue($object, $queue, $idx) + protected function _doEnqueue($object, $queue, $idx, $siteNickname=null) { $rep = $this->logrep($object); - $envelope = array('site' => common_config('site', 'nickname'), + $envelope = array('site' => $siteNickname ? $siteNickname : common_config('site', 'nickname'), 'handler' => $queue, 'payload' => $this->encode($object)); $msg = serialize($envelope); diff --git a/plugins/OStatus/classes/HubSub.php b/plugins/OStatus/classes/HubSub.php index cdace3c1f..9748b4a56 100644 --- a/plugins/OStatus/classes/HubSub.php +++ b/plugins/OStatus/classes/HubSub.php @@ -260,6 +260,37 @@ class HubSub extends Memcached_DataObject $retries = intval(common_config('ostatus', 'hub_retries')); } + if (common_config('ostatus', 'local_push_bypass')) { + // If target is a local site, bypass the web server and drop the + // item directly into the target's input queue. + $url = parse_url($this->callback); + $wildcard = common_config('ostatus', 'local_wildcard'); + $site = Status_network::getFromHostname($url['host'], $wildcard); + + if ($site) { + if ($this->secret) { + $hmac = 'sha1=' . hash_hmac('sha1', $atom, $this->secret); + } else { + $hmac = ''; + } + + // Hack: at the moment we stick the subscription ID in the callback + // URL so we don't have to look inside the Atom to route the subscription. + // For now this means we need to extract that from the target URL + // so we can include it in the data. + $parts = explode('/', $url['path']); + $subId = intval(array_pop($parts)); + + $data = array('feedsub_id' => $subId, + 'post' => $atom, + 'hmac' => $hmac); + common_log(LOG_DEBUG, "Cross-site PuSH bypass enqueueing straight to $site->nickname feed $subId"); + $qm = QueueManager::get(); + $qm->enqueue($data, 'pushin', $site->nickname); + return; + } + } + // We dare not clone() as when the clone is discarded it'll // destroy the result data for the parent query. // @fixme use clone() again when it's safe to copy an -- cgit v1.2.3-54-g00ecf From 09208f8d654336d710069c1b4843de7e0d8c5d20 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 21 Apr 2010 17:16:42 +0200 Subject: Basic custom CSS and theme uploading features. 'local' subdir can now be customized to a distinct directory and URL path to make it easier to separate custom themes for a multi-site farm running a common code base. Currently only one custom theme may be uploaded per site, saved with the name 'custom' and stored into the local/themes subdirectory. Administrators can upload a .ZIP archive containing a theme through the design admin panel; its contents are validated to ensure that only legit files are saved, and a 5M size quota is enforced. Theme upload requires the zip extension for PHP; if not present, theme uploading is disabled by default. Uploading and the custom CSS can be controlled via $config['theme_upload']['enabled'] and $config['custom_css']['enabled']. Configurable directory/path/server for 'local' subdirectory (currently only as used for themes; local plugins not yet switched over) Can set $config['local']['dir'] etc; not currently exposed in the admin panels. Per-site directories on a separate themes server could be set up such as: $config['local']['dir'] = '/path/to/themes/local/' . $_nickname; $config['local']['server'] = 'themes.example.com'; $config['local']['path'] = '/local/' . $_nickname; $config['local']['ssl'] = 'never'; --- actions/designadminpanel.php | 84 +++++++++++- lib/action.php | 10 ++ lib/adminpanelaction.php | 3 +- lib/default.php | 10 ++ lib/theme.php | 82 ++++++++---- lib/themeuploader.php | 311 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 469 insertions(+), 31 deletions(-) create mode 100644 lib/themeuploader.php (limited to 'lib') diff --git a/actions/designadminpanel.php b/actions/designadminpanel.php index 092588019..a3f2dd055 100644 --- a/actions/designadminpanel.php +++ b/actions/designadminpanel.php @@ -125,9 +125,19 @@ class DesignadminpanelAction extends AdminPanelAction return; } - // check for an image upload + // check for file uploads $bgimage = $this->saveBackgroundImage(); + $customTheme = $this->saveCustomTheme(); + + $oldtheme = common_config('site', 'theme'); + if ($customTheme) { + // This feels pretty hacky :D + $this->args['theme'] = $customTheme; + $themeChanged = true; + } else { + $themeChanged = ($this->trimmed('theme') != $oldtheme); + } static $settings = array('theme', 'logo'); @@ -139,15 +149,13 @@ class DesignadminpanelAction extends AdminPanelAction $this->validate($values); - $oldtheme = common_config('site', 'theme'); - $config = new Config(); $config->query('BEGIN'); // Only update colors if the theme has not changed. - if ($oldtheme == $values['theme']) { + if (!$themeChanged) { $bgcolor = new WebColor($this->trimmed('design_background')); $ccolor = new WebColor($this->trimmed('design_content')); @@ -189,6 +197,13 @@ class DesignadminpanelAction extends AdminPanelAction Config::save('design', 'backgroundimage', $bgimage); } + if (common_config('custom_css', 'enabled')) { + $css = $this->arg('css'); + if ($css != common_config('custom_css', 'css')) { + Config::save('custom_css', 'css', $css); + } + } + $config->query('COMMIT'); } @@ -262,6 +277,33 @@ class DesignadminpanelAction extends AdminPanelAction } } + /** + * Save the custom theme if the user uploaded one. + * + * @return mixed custom theme name, if succesful, or null if no theme upload. + * @throws ClientException for invalid theme archives + * @throws ServerException if trouble saving the theme files + */ + + function saveCustomTheme() + { + if (common_config('theme_upload', 'enabled') && + $_FILES['design_upload_theme']['error'] == UPLOAD_ERR_OK) { + + $upload = ThemeUploader::fromUpload('design_upload_theme'); + $basedir = common_config('local', 'dir'); + if (empty($basedir)) { + $basedir = INSTALLDIR . '/local'; + } + $name = 'custom'; // @todo allow multiples, custom naming? + $outdir = $basedir . '/theme/' . $name; + $upload->extract($outdir); + return $name; + } else { + return null; + } + } + /** * Attempt to validate setting values * @@ -374,6 +416,7 @@ class DesignAdminPanelForm extends AdminForm $this->showTheme(); $this->showBackground(); $this->showColors(); + $this->showAdvanced(); } function showLogo() @@ -418,6 +461,16 @@ class DesignAdminPanelForm extends AdminForm false, $this->value('theme')); $this->unli(); + if (common_config('theme_upload', 'enabled')) { + $this->li(); + $this->out->element('label', array('for' => 'design_upload_theme'), _('Custom theme')); + $this->out->element('input', array('id' => 'design_upload_theme', + 'name' => 'design_upload_theme', + 'type' => 'file')); + $this->out->element('p', 'form_guide', _('You can upload a custom StatusNet theme as a .ZIP archive.')); + $this->unli(); + } + $this->out->elementEnd('ul'); $this->out->elementEnd('fieldset'); @@ -502,6 +555,8 @@ class DesignAdminPanelForm extends AdminForm function showColors() { + $design = $this->out->design; + $this->out->elementStart('fieldset', array('id' => 'settings_design_color')); $this->out->element('legend', null, _('Change colours')); @@ -586,6 +641,27 @@ class DesignAdminPanelForm extends AdminForm $this->out->elementEnd('ul'); } + function showAdvanced() + { + if (common_config('custom_css', 'enabled')) { + $this->out->elementStart('fieldset', array('id' => 'settings_design_advanced')); + $this->out->element('legend', null, _('Advanced')); + $this->out->elementStart('ul', 'form_data'); + + $this->li(); + $this->out->element('label', array('for' => 'css'), _('Custom CSS')); + $this->out->element('textarea', array('name' => 'css', + 'id' => 'css', + 'cols' => '50', + 'rows' => '10'), + strval(common_config('custom_css', 'css'))); + $this->unli(); + + $this->out->elementEnd('fieldset'); + $this->out->elementEnd('ul'); + } + } + /** * Action elements * diff --git a/lib/action.php b/lib/action.php index c4d9fd5cb..22ea4f275 100644 --- a/lib/action.php +++ b/lib/action.php @@ -233,6 +233,16 @@ class Action extends HTMLOutputter // lawsuit Event::handle('EndShowDesign', array($this)); } Event::handle('EndShowStyles', array($this)); + + if (common_config('custom_css', 'enabled')) { + $css = common_config('custom_css', 'css'); + if (Event::handle('StartShowCustomCss', array($this, &$css))) { + if (trim($css) != '') { + $this->style($css); + } + Event::handle('EndShowCustomCss', array($this)); + } + } } } diff --git a/lib/adminpanelaction.php b/lib/adminpanelaction.php index a927e2333..7d6a616eb 100644 --- a/lib/adminpanelaction.php +++ b/lib/adminpanelaction.php @@ -283,9 +283,10 @@ class AdminPanelAction extends Action $this->clientError(_("Unable to delete design setting.")); return null; } + return $result; } - return $result; + return null; } function canAdmin($name) diff --git a/lib/default.php b/lib/default.php index 950c6018d..dcf225d1f 100644 --- a/lib/default.php +++ b/lib/default.php @@ -141,10 +141,17 @@ $default = 'dir' => null, 'path'=> null, 'ssl' => null), + 'theme_upload' => + array('enabled' => extension_loaded('zip')), 'javascript' => array('server' => null, 'path'=> null, 'ssl' => null), + 'local' => // To override path/server for themes in 'local' dir (not currently applied to local plugins) + array('server' => null, + 'dir' => null, + 'path' => null, + 'ssl' => null), 'throttle' => array('enabled' => false, // whether to throttle edits; false by default 'count' => 20, // number of allowed messages in timespan @@ -260,6 +267,9 @@ $default = 'linkcolor' => null, 'backgroundimage' => null, 'disposition' => null), + 'custom_css' => + array('enabled' => true, + 'css' => ''), 'notice' => array('contentlimit' => null), 'message' => diff --git a/lib/theme.php b/lib/theme.php index 0be8c3b9d..a9d0cbc84 100644 --- a/lib/theme.php +++ b/lib/theme.php @@ -38,6 +38,9 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { * Themes are directories with some expected sub-directories and files * in them. They're found in either local/theme (for locally-installed themes) * or theme/ subdir of installation dir. + * + * Note that the 'local' directory can be overridden as $config['local']['path'] + * and $config['local']['dir'] etc. * * This used to be a couple of functions, but for various reasons it's nice * to have a class instead. @@ -76,7 +79,7 @@ class Theme if (file_exists($fulldir) && is_dir($fulldir)) { $this->dir = $fulldir; - $this->path = common_path('local/theme/'.$name.'/'); + $this->path = $this->relativeThemePath('local', 'local', 'theme/' . $name); return; } @@ -89,42 +92,63 @@ class Theme if (file_exists($fulldir) && is_dir($fulldir)) { $this->dir = $fulldir; + $this->path = $this->relativeThemePath('theme', 'theme', $name); + } + } - $path = common_config('theme', 'path'); + /** + * Build a full URL to the given theme's base directory, possibly + * using an offsite theme server path. + * + * @param string $group configuration section name to pull paths from + * @param string $fallbackSubdir default subdirectory under INSTALLDIR + * @param string $name theme name + * + * @return string URL + * + * @todo consolidate code with that for other customizable paths + */ - if (empty($path)) { - $path = common_config('site', 'path') . '/theme/'; - } + protected function relativeThemePath($group, $fallbackSubdir, $name) + { + $path = common_config($group, 'path'); - if ($path[strlen($path)-1] != '/') { - $path .= '/'; + if (empty($path)) { + $path = common_config('site', 'path') . '/'; + if ($fallbackSubdir) { + $path .= $fallbackSubdir . '/'; } + } - if ($path[0] != '/') { - $path = '/'.$path; - } + if ($path[strlen($path)-1] != '/') { + $path .= '/'; + } - $server = common_config('theme', 'server'); + if ($path[0] != '/') { + $path = '/'.$path; + } - if (empty($server)) { - $server = common_config('site', 'server'); - } + $server = common_config($group, 'server'); - $ssl = common_config('theme', 'ssl'); + if (empty($server)) { + $server = common_config('site', 'server'); + } - if (is_null($ssl)) { // null -> guess - if (common_config('site', 'ssl') == 'always' && - !common_config('theme', 'server')) { - $ssl = true; - } else { - $ssl = false; - } + $ssl = common_config($group, 'ssl'); + + if (is_null($ssl)) { // null -> guess + if (common_config('site', 'ssl') == 'always' && + !common_config($group, 'server')) { + $ssl = true; + } else { + $ssl = false; } + } - $protocol = ($ssl) ? 'https' : 'http'; + $protocol = ($ssl) ? 'https' : 'http'; - $this->path = $protocol . '://'.$server.$path.$name; - } + $path = $protocol . '://'.$server.$path.$name; + return $path; } /** @@ -236,7 +260,13 @@ class Theme protected static function localRoot() { - return INSTALLDIR.'/local/theme'; + $basedir = common_config('local', 'dir'); + + if (empty($basedir)) { + $basedir = INSTALLDIR . '/local'; + } + + return $basedir . '/theme'; } /** diff --git a/lib/themeuploader.php b/lib/themeuploader.php new file mode 100644 index 000000000..18ef8c4d1 --- /dev/null +++ b/lib/themeuploader.php @@ -0,0 +1,311 @@ +. + * + * @category Paths + * @package StatusNet + * @author Brion Vibber + * @copyright 2010 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); +} + +/** + * Encapsulation of the validation-and-save process when dealing with + * a user-uploaded StatusNet theme archive... + * + * @todo extract theme metadata from css/display.css + * @todo allow saving multiple themes + */ +class ThemeUploader +{ + protected $sourceFile; + protected $isUpload; + private $prevErrorReporting; + + public function __construct($filename) + { + if (!class_exists('ZipArchive')) { + throw new Exception(_("This server cannot handle theme uploads without ZIP support.")); + } + $this->sourceFile = $filename; + } + + public static function fromUpload($name) + { + if (!isset($_FILES[$name]['error'])) { + throw new ServerException(_("Theme upload missing or failed.")); + } + if ($_FILES[$name]['error'] != UPLOAD_ERR_OK) { + throw new ServerException(_("Theme upload missing or failed.")); + } + return new ThemeUploader($_FILES[$name]['tmp_name']); + } + + /** + * @param string $destDir + * @throws Exception on bogus files + */ + public function extract($destDir) + { + $zip = $this->openArchive(); + + // First pass: validate but don't save anything to disk. + // Any errors will trip an exception. + $this->traverseArchive($zip); + + // Second pass: now that we know we're good, actually extract! + $tmpDir = $destDir . '.tmp' . getmypid(); + $this->traverseArchive($zip, $tmpDir); + + $zip->close(); + + if (file_exists($destDir)) { + $killDir = $tmpDir . '.old'; + $this->quiet(); + $ok = rename($destDir, $killDir); + $this->loud(); + if (!$ok) { + common_log(LOG_ERR, "Could not move old custom theme from $destDir to $killDir"); + throw new ServerException(_("Failed saving theme.")); + } + } else { + $killDir = false; + } + + $this->quiet(); + $ok = rename($tmpDir, $destDir); + $this->loud(); + if (!$ok) { + common_log(LOG_ERR, "Could not move saved theme from $tmpDir to $destDir"); + throw new ServerException(_("Failed saving theme.")); + } + + if ($killDir) { + $this->recursiveRmdir($killDir); + } + } + + /** + * + */ + protected function traverseArchive($zip, $outdir=false) + { + $sizeLimit = 2 * 1024 * 1024; // 2 megabyte space limit? + $blockSize = 4096; // estimated; any entry probably takes this much space + + $totalSize = 0; + $hasMain = false; + $commonBaseDir = false; + + for ($i = 0; $i < $zip->numFiles; $i++) { + $data = $zip->statIndex($i); + $name = str_replace('\\', '/', $data['name']); + + if (substr($name, -1) == '/') { + // A raw directory... skip! + continue; + } + + // Check the directory structure... + $path = pathinfo($name); + $dirs = explode('/', $path['dirname']); + $baseDir = array_shift($dirs); + if ($commonBaseDir === false) { + $commonBaseDir = $baseDir; + } else { + if ($commonBaseDir != $baseDir) { + throw new ClientException(_("Invalid theme: bad directory structure.")); + } + } + + foreach ($dirs as $dir) { + $this->validateFileOrFolder($dir); + } + + // Is this a safe or skippable file? + if ($this->skippable($path['filename'], $path['extension'])) { + // Documentation and such... booooring + continue; + } else { + $this->validateFile($path['filename'], $path['extension']); + } + + $fullPath = $dirs; + $fullPath[] = $path['basename']; + $localFile = implode('/', $fullPath); + if ($localFile == 'css/display.css') { + $hasMain = true; + } + + $size = $data['size']; + $estSize = $blockSize * max(1, intval(ceil($size / $blockSize))); + $totalSize += $estSize; + if ($totalSize > $sizeLimit) { + $msg = sprintf(_("Uploaded theme is too large; " . + "must be less than %d bytes uncompressed."), + $sizeLimit); + throw new ClientException($msg); + } + + if ($outdir) { + $this->extractFile($zip, $data['name'], "$outdir/$localFile"); + } + } + + if (!$hasMain) { + throw new ClientException(_("Invalid theme archive: " . + "missing file css/display.css")); + } + } + + protected function skippable($filename, $ext) + { + $skip = array('txt', 'rtf', 'doc', 'docx', 'odt'); + if (strtolower($filename) == 'readme') { + return true; + } + if (in_array(strtolower($ext), $skip)) { + return true; + } + return false; + } + + protected function validateFile($filename, $ext) + { + $this->validateFileOrFolder($filename); + $this->validateExtension($ext); + // @fixme validate content + } + + protected function validateFileOrFolder($name) + { + if (!preg_match('/^[a-z0-9_-]+$/i', $name)) { + $msg = _("Theme contains invalid file or folder name. " . + "Stick with ASCII letters, digits, underscore, and minus sign."); + throw new ClientException($msg); + } + return true; + } + + protected function validateExtension($ext) + { + $allowed = array('css', 'png', 'gif', 'jpg', 'jpeg'); + if (!in_array(strtolower($ext), $allowed)) { + $msg = sprintf(_("Theme contains file of type '.%s', " . + "which is not allowed."), + $ext); + throw new ClientException($msg); + } + return true; + } + + /** + * @return ZipArchive + */ + protected function openArchive() + { + $zip = new ZipArchive; + $ok = $zip->open($this->sourceFile); + if ($ok !== true) { + common_log(LOG_ERR, "Error opening theme zip archive: " . + "{$this->sourceFile} code: {$ok}"); + throw new Exception(_("Error opening theme archive.")); + } + return $zip; + } + + /** + * @param ZipArchive $zip + * @param string $from original path inside ZIP archive + * @param string $to final destination path in filesystem + */ + protected function extractFile($zip, $from, $to) + { + $dir = dirname($to); + if (!file_exists($dir)) { + $this->quiet(); + $ok = mkdir($dir, 0755, true); + $this->loud(); + if (!$ok) { + common_log(LOG_ERR, "Failed to mkdir $dir while uploading theme"); + throw new ServerException(_("Failed saving theme.")); + } + } else if (!is_dir($dir)) { + common_log(LOG_ERR, "Output directory $dir not a directory while uploading theme"); + throw new ServerException(_("Failed saving theme.")); + } + + // ZipArchive::extractTo would be easier, but won't let us alter + // the directory structure. + $in = $zip->getStream($from); + if (!$in) { + common_log(LOG_ERR, "Couldn't open archived file $from while uploading theme"); + throw new ServerException(_("Failed saving theme.")); + } + $this->quiet(); + $out = fopen($to, "wb"); + $this->loud(); + if (!$out) { + common_log(LOG_ERR, "Couldn't open output file $to while uploading theme"); + throw new ServerException(_("Failed saving theme.")); + } + while (!feof($in)) { + $buffer = fread($in, 65536); + fwrite($out, $buffer); + } + fclose($in); + fclose($out); + } + + private function quiet() + { + $this->prevErrorReporting = error_reporting(); + error_reporting($this->prevErrorReporting & ~E_WARNING); + } + + private function loud() + { + error_reporting($this->prevErrorReporting); + } + + private function recursiveRmdir($dir) + { + $list = dir($dir); + while (($file = $list->read()) !== false) { + if ($file == '.' || $file == '..') { + continue; + } + $full = "$dir/$file"; + if (is_dir($full)) { + $this->recursiveRmdir($full); + } else { + unlink($full); + } + } + $list->close(); + rmdir($dir); + } + +} -- cgit v1.2.3-54-g00ecf From e121d472e7dbb914a85b10bde0a9e2add4d19d11 Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Wed, 9 Jun 2010 16:30:50 +1200 Subject: Revert "added notice.location to group by" This reverts commit 48dc899acb9a0ac87140353092dab1f5e67753d8. --- lib/popularnoticesection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/popularnoticesection.php b/lib/popularnoticesection.php index 3f0241790..f70a972ef 100644 --- a/lib/popularnoticesection.php +++ b/lib/popularnoticesection.php @@ -72,7 +72,7 @@ class PopularNoticeSection extends NoticeSection $qry .= ' GROUP BY notice.id,notice.profile_id,notice.content,notice.uri,' . 'notice.rendered,notice.url,notice.created,notice.modified,' . 'notice.reply_to,notice.is_local,notice.source,notice.conversation, ' . - 'notice.lat,notice.lon,location_id,location_ns,notice.repeat_of,notice.location' . + 'notice.lat,notice.lon,location_id,location_ns,notice.repeat_of' . ' ORDER BY weight DESC'; $offset = 0; -- cgit v1.2.3-54-g00ecf From ec155464765db36591bbb183b335abbc1ec8638c Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 11 Jun 2010 11:52:06 -0700 Subject: Fix a couple bad format entries in router setup (format param had 'xmljson' instead of 'xml|json'). Warning: the format strings aren't actually being enforced here which is probably why they weren't caught earlier. Not quite sure why, it should be looked at! --- lib/router.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/router.php b/lib/router.php index afe44f92a..f2b2b845f 100644 --- a/lib/router.php +++ b/lib/router.php @@ -540,7 +540,7 @@ class Router $m->connect('api/favorites/:id.:format', array('action' => 'ApiTimelineFavorites', 'id' => '[a-zA-Z0-9]+', - 'format' => '(xmljson|rss|atom)')); + 'format' => '(xml|json|rss|atom)')); $m->connect('api/favorites/create/:id.:format', array('action' => 'ApiFavoriteCreate', @@ -597,7 +597,7 @@ class Router $m->connect('api/statusnet/groups/timeline/:id.:format', array('action' => 'ApiTimelineGroup', 'id' => '[a-zA-Z0-9]+', - 'format' => '(xmljson|rss|atom)')); + 'format' => '(xml|json|rss|atom)')); $m->connect('api/statusnet/groups/show.:format', array('action' => 'ApiGroupShow', @@ -658,7 +658,7 @@ class Router // Tags $m->connect('api/statusnet/tags/timeline/:tag.:format', array('action' => 'ApiTimelineTag', - 'format' => '(xmljson|rss|atom)')); + 'format' => '(xml|json|rss|atom)')); // media related $m->connect( -- cgit v1.2.3-54-g00ecf From 3da8914edb81a1789d69ee6c32092959630e4e1c Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 11 Jun 2010 12:38:22 -0700 Subject: Fix for DB error reporting in installer (MySQL path) --- lib/installer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/installer.php b/lib/installer.php index 7936d5d5d..78461efb7 100644 --- a/lib/installer.php +++ b/lib/installer.php @@ -446,7 +446,7 @@ abstract class Installer case 'mysqli': $res = $conn->query($stmt); if ($res === false) { - $error = $conn->error(); + $error = $conn->error; } break; case 'pgsql': -- cgit v1.2.3-54-g00ecf From 327ed5b87e492380bc651ed03159ae7cd3a4a493 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 14 Jun 2010 15:51:49 -0400 Subject: fix URL regex for tags to use UTF-8 --- lib/router.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/router.php b/lib/router.php index f2b2b845f..fec229c9b 100644 --- a/lib/router.php +++ b/lib/router.php @@ -263,7 +263,7 @@ class Router $m->connect('tag', array('action' => 'publictagcloud')); $m->connect('tag/:tag/rss', array('action' => 'tagrss'), - array('tag' => '[a-zA-Z0-9]+')); + array('tag' => '[\pL\pN_\-\.]{1,64}')); $m->connect('tag/:tag', array('action' => 'tag'), array('tag' => '[\pL\pN_\-\.]{1,64}')); @@ -749,12 +749,12 @@ class Router $m->connect('tag/:tag/rss', array('action' => 'userrss', 'nickname' => $nickname), - array('tag' => '[a-zA-Z0-9]+')); + array('tag' => '[\pL\pN_\-\.]{1,64}')); $m->connect('tag/:tag', array('action' => 'showstream', 'nickname' => $nickname), - array('tag' => '[a-zA-Z0-9]+')); + array('tag' => '[\pL\pN_\-\.]{1,64}')); $m->connect('rsd.xml', array('action' => 'rsd', @@ -815,12 +815,12 @@ class Router $m->connect(':nickname/tag/:tag/rss', array('action' => 'userrss'), array('nickname' => '[a-zA-Z0-9]{1,64}'), - array('tag' => '[a-zA-Z0-9]+')); + array('tag' => '[\pL\pN_\-\.]{1,64}')); $m->connect(':nickname/tag/:tag', array('action' => 'showstream'), array('nickname' => '[a-zA-Z0-9]{1,64}'), - array('tag' => '[a-zA-Z0-9]+')); + array('tag' => '[\pL\pN_\-\.]{1,64}')); $m->connect(':nickname/rsd.xml', array('action' => 'rsd'), -- cgit v1.2.3-54-g00ecf From 4ee2c12507b046e048ff023b94872cbbe9bde9a4 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Tue, 15 Jun 2010 17:04:15 -0400 Subject: Use presence of IM plugins to decide if "IM" menu option should be shown in Connect --- lib/connectsettingsaction.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/connectsettingsaction.php b/lib/connectsettingsaction.php index b9c14799e..c3a88be55 100644 --- a/lib/connectsettingsaction.php +++ b/lib/connectsettingsaction.php @@ -105,7 +105,7 @@ class ConnectSettingsNav extends Widget # action => array('prompt', 'title') $menu = array(); - if (common_config('xmpp', 'enabled')) { + if (Event::handle('GetImTransports', array(&$transports))) { $menu['imsettings'] = array(_('IM'), _('Updates by instant messenger (IM)')); -- cgit v1.2.3-54-g00ecf From 1a62d1b49378bba4b69476282b9a5d0e03073405 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Wed, 16 Jun 2010 16:00:54 -0400 Subject: Use presence of IM plugins to decide if "IM" options should be available --- actions/subscriptions.php | 8 +++++--- lib/connectsettingsaction.php | 4 +++- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/actions/subscriptions.php b/actions/subscriptions.php index 7b10b3425..da563a218 100644 --- a/actions/subscriptions.php +++ b/actions/subscriptions.php @@ -185,7 +185,9 @@ class SubscriptionsListItem extends SubscriptionListItem return; } - if (!common_config('xmpp', 'enabled') && !common_config('sms', 'enabled')) { + $transports = array(); + Event::handle('GetImTransports', array(&$transports)); + if (!$transports && !common_config('sms', 'enabled')) { return; } @@ -195,7 +197,7 @@ class SubscriptionsListItem extends SubscriptionListItem 'action' => common_local_url('subedit'))); $this->out->hidden('token', common_session_token()); $this->out->hidden('profile', $this->profile->id); - if (common_config('xmpp', 'enabled')) { + if ($transports) { $attrs = array('name' => 'jabber', 'type' => 'checkbox', 'class' => 'checkbox', @@ -205,7 +207,7 @@ class SubscriptionsListItem extends SubscriptionListItem } $this->out->element('input', $attrs); - $this->out->element('label', array('for' => 'jabber-'.$this->profile->id), _('Jabber')); + $this->out->element('label', array('for' => 'jabber-'.$this->profile->id), _('IM')); } else { $this->out->hidden('jabber', $sub->jabber); } diff --git a/lib/connectsettingsaction.php b/lib/connectsettingsaction.php index c3a88be55..5d62fc56b 100644 --- a/lib/connectsettingsaction.php +++ b/lib/connectsettingsaction.php @@ -105,7 +105,9 @@ class ConnectSettingsNav extends Widget # action => array('prompt', 'title') $menu = array(); - if (Event::handle('GetImTransports', array(&$transports))) { + $transports = array(); + Event::handle('GetImTransports', array(&$transports)); + if ($transports) { $menu['imsettings'] = array(_('IM'), _('Updates by instant messenger (IM)')); -- cgit v1.2.3-54-g00ecf From d3d499879c4d01bde46033a3a98f9190ea18cb63 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 16 Jun 2010 14:29:24 -0700 Subject: - More useful group info from api/statusnet/group/show - Add statusnet:group_info tag to group Atom feeds --- actions/showgroup.php | 10 +--------- classes/User_group.php | 15 +++++++++++++++ lib/apiaction.php | 40 ++++++++++++++++++++++++++-------------- lib/atomgroupnoticefeed.php | 19 +++++++++++++++++++ 4 files changed, 61 insertions(+), 23 deletions(-) (limited to 'lib') diff --git a/actions/showgroup.php b/actions/showgroup.php index 3d369e9eb..17c37e4d7 100644 --- a/actions/showgroup.php +++ b/actions/showgroup.php @@ -430,14 +430,6 @@ class ShowgroupAction extends GroupDesignAction function showStatistics() { - // XXX: WORM cache this - $members = $this->group->getMembers(); - $members_count = 0; - /** $member->count() doesn't work. */ - while ($members->fetch()) { - $members_count++; - } - $this->elementStart('div', array('id' => 'entity_statistics', 'class' => 'section')); @@ -451,7 +443,7 @@ class ShowgroupAction extends GroupDesignAction $this->elementStart('dl', 'entity_members'); $this->element('dt', null, _('Members')); - $this->element('dd', null, (is_int($members_count)) ? $members_count : '0'); + $this->element('dd', null, $this->group->getMemberCount()); $this->elementEnd('dl'); $this->elementEnd('div'); diff --git a/classes/User_group.php b/classes/User_group.php index 110f08301..e04c46626 100644 --- a/classes/User_group.php +++ b/classes/User_group.php @@ -154,6 +154,21 @@ class User_group extends Memcached_DataObject return $members; } + function getMemberCount() + { + // XXX: WORM cache this + + $members = $this->getMembers(); + $member_count = 0; + + /** $member->count() doesn't work. */ + while ($members->fetch()) { + $member_count++; + } + + return $member_count; + } + function getAdmins($offset=0, $limit=null) { $qry = diff --git a/lib/apiaction.php b/lib/apiaction.php index 320aa0316..7cc473d51 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -346,20 +346,32 @@ class ApiAction extends Action function twitterGroupArray($group) { - $twitter_group=array(); - $twitter_group['id']=$group->id; - $twitter_group['url']=$group->permalink(); - $twitter_group['nickname']=$group->nickname; - $twitter_group['fullname']=$group->fullname; - $twitter_group['original_logo']=$group->original_logo; - $twitter_group['homepage_logo']=$group->homepage_logo; - $twitter_group['stream_logo']=$group->stream_logo; - $twitter_group['mini_logo']=$group->mini_logo; - $twitter_group['homepage']=$group->homepage; - $twitter_group['description']=$group->description; - $twitter_group['location']=$group->location; - $twitter_group['created']=$this->dateTwitter($group->created); - $twitter_group['modified']=$this->dateTwitter($group->modified); + $twitter_group = array(); + + $twitter_group['id'] = $group->id; + $twitter_group['url'] = $group->permalink(); + $twitter_group['nickname'] = $group->nickname; + $twitter_group['fullname'] = $group->fullname; + + if (isset($this->auth_user)) { + $twitter_group['member'] = $this->auth_user->isMember($group); + $twitter_group['blocked'] = Group_block::isBlocked( + $group, + $this->auth_user->getProfile() + ); + } + + $twitter_group['member_count'] = $group->getMemberCount(); + $twitter_group['original_logo'] = $group->original_logo; + $twitter_group['homepage_logo'] = $group->homepage_logo; + $twitter_group['stream_logo'] = $group->stream_logo; + $twitter_group['mini_logo'] = $group->mini_logo; + $twitter_group['homepage'] = $group->homepage; + $twitter_group['description'] = $group->description; + $twitter_group['location'] = $group->location; + $twitter_group['created'] = $this->dateTwitter($group->created); + $twitter_group['modified'] = $this->dateTwitter($group->modified); + return $twitter_group; } diff --git a/lib/atomgroupnoticefeed.php b/lib/atomgroupnoticefeed.php index 7934a4f9e..761df587c 100644 --- a/lib/atomgroupnoticefeed.php +++ b/lib/atomgroupnoticefeed.php @@ -93,4 +93,23 @@ class AtomGroupNoticeFeed extends AtomNoticeFeed return $this->group; } + function initFeed() + { + parent::initFeed(); + + $attrs = array(); + + if (!empty($this->cur)) { + $attrs['member'] = $this->cur->isMember($this->group) + ? 'true' : 'false'; + $attrs['blocked'] = Group_block::isBlocked( + $this->group, + $this->cur->getProfile() + ) ? 'true' : 'false'; + } + + $attrs['member_count'] = $this->group->getMemberCount(); + + $this->element('statusnet:group_info', $attrs, null); + } } -- cgit v1.2.3-54-g00ecf From a6ce4eef0df225dd863baf45d5615cbe22dcdea6 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 16 Jun 2010 18:27:51 -0700 Subject: Fix problem with AvatarLink in which it was sometimes leaving the width attribute empty --- lib/avatarlink.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/avatarlink.php b/lib/avatarlink.php index e67799e2e..7d4256d6e 100644 --- a/lib/avatarlink.php +++ b/lib/avatarlink.php @@ -76,8 +76,8 @@ class AvatarLink $alink = new AvatarLink(); $alink->url = $filename; $alink->height = $size; + $alink->width = $size; if (!empty($filename)) { - $alink->width = $size; $alink->type = self::mediatype($filename); } else { $alink->url = User_group::defaultLogo($size); -- cgit v1.2.3-54-g00ecf From 87125a1395ed4bf8660e2ba47645835b9d1f4acf Mon Sep 17 00:00:00 2001 From: Siebrand Mazeland Date: Mon, 21 Jun 2010 20:15:26 +0200 Subject: Improve error message per discussion on http://translatewiki.net/wiki/Thread:Support/Unclear_message. Spotted by Peter17 and changed per suggestion of McDutchie with approval of Brion. --- lib/themeuploader.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/themeuploader.php b/lib/themeuploader.php index 18ef8c4d1..370965db0 100644 --- a/lib/themeuploader.php +++ b/lib/themeuploader.php @@ -55,10 +55,10 @@ class ThemeUploader public static function fromUpload($name) { if (!isset($_FILES[$name]['error'])) { - throw new ServerException(_("Theme upload missing or failed.")); + throw new ServerException(_("The theme file is missing or the upload failed.")); } if ($_FILES[$name]['error'] != UPLOAD_ERR_OK) { - throw new ServerException(_("Theme upload missing or failed.")); + throw new ServerException(_("The theme file is missing or the upload failed.")); } return new ThemeUploader($_FILES[$name]['tmp_name']); } -- cgit v1.2.3-54-g00ecf From 1eec7f779fc85b530907ea31deceadb2a30d7614 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 22 Jun 2010 16:28:06 -0700 Subject: - Add profile_info tag to Atom author - Normalize xmlns:statusnet links in the API --- classes/Notice.php | 4 ++-- classes/Profile.php | 10 +++++++++- lib/apiaction.php | 2 ++ lib/atomnoticefeed.php | 2 +- 4 files changed, 14 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/classes/Notice.php b/classes/Notice.php index f8eda5777..c752e35a7 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1190,7 +1190,7 @@ class Notice extends Memcached_DataObject 'xmlns:media' => 'http://purl.org/syndication/atommedia', 'xmlns:poco' => 'http://portablecontacts.net/spec/1.0', 'xmlns:ostatus' => 'http://ostatus.org/schema/1.0', - 'xmlns:statusnet' => 'http://status.net/ont/'); + 'xmlns:statusnet' => 'http://status.net/schema/api/1/'); } else { $attrs = array(); } @@ -1225,7 +1225,7 @@ class Notice extends Memcached_DataObject $xs->element('title', null, common_xml_safe_str($this->content)); if ($author) { - $xs->raw($profile->asAtomAuthor()); + $xs->raw($profile->asAtomAuthor($cur)); $xs->raw($profile->asActivityActor()); } diff --git a/classes/Profile.php b/classes/Profile.php index 54f557ea7..a303469e9 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -849,15 +849,23 @@ class Profile extends Memcached_DataObject * * Assumes that Atom has been previously set up as the base namespace. * + * @param Profile $cur the current authenticated user + * * @return string */ - function asAtomAuthor() + function asAtomAuthor($cur = null) { $xs = new XMLStringer(true); $xs->elementStart('author'); $xs->element('name', null, $this->nickname); $xs->element('uri', null, $this->getUri()); + if ($cur != null) { + $attrs = Array(); + $attrs['following'] = $cur->isSubscribed($this) ? 'true' : 'false'; + $attrs['blocking'] = $cur->hasBlocked($this) ? 'true' : 'false'; + $xs->element('statusnet:profile_info', $attrs, null); + } $xs->elementEnd('author'); return $xs->getString(); diff --git a/lib/apiaction.php b/lib/apiaction.php index 7cc473d51..226481778 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -208,11 +208,13 @@ class ApiAction extends Action // Is the requesting user following this user? $twitter_user['following'] = false; + $twitter_user['statusnet:blocking'] = false; $twitter_user['notifications'] = false; if (isset($this->auth_user)) { $twitter_user['following'] = $this->auth_user->isSubscribed($profile); + $twitter_user['statusnet:blocking'] = $this->auth_user->hasBlocked($profile); // Notifications on? $sub = Subscription::pkeyGet(array('subscriber' => diff --git a/lib/atomnoticefeed.php b/lib/atomnoticefeed.php index ef44de4b6..6ed803ce4 100644 --- a/lib/atomnoticefeed.php +++ b/lib/atomnoticefeed.php @@ -95,7 +95,7 @@ class AtomNoticeFeed extends Atom10Feed $this->addNamespace( 'statusnet', - 'http://status.net/ont/' + 'http://status.net/schema/api/1/' ); } -- cgit v1.2.3-54-g00ecf From dad0b06a386092b159118780a6a6801f3cf674de Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Tue, 22 Jun 2010 22:01:13 -0400 Subject: Throw an error if queueing is disable when using an IM plugin --- lib/implugin.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/implugin.php b/lib/implugin.php index 7125aaee8..dafb8a416 100644 --- a/lib/implugin.php +++ b/lib/implugin.php @@ -619,8 +619,13 @@ abstract class ImPlugin extends Plugin function initialize() { + if( ! common_config('queue', 'enabled')) + { + throw new ServerException("Queueing must be enabled to use IM plugins"); + } + if(is_null($this->transport)){ - throw new Exception('transport cannot be null'); + throw new ServerException('transport cannot be null'); } } } -- cgit v1.2.3-54-g00ecf From 9eb5a976b03fae6bd1e1fce6abfe4a6c7964d1ae Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 24 Jun 2010 18:11:50 -0700 Subject: Have API methods for search subclass ApiPrivateAuthAction --- actions/apisearchatom.php | 408 ++++++++++++++++++++++++++++++++++++++++++ actions/apisearchjson.php | 154 ++++++++++++++++ actions/apitrends.php | 90 ++++++++++ actions/twitapisearchatom.php | 402 ----------------------------------------- actions/twitapisearchjson.php | 151 ---------------- actions/twitapitrends.php | 88 --------- lib/router.php | 6 +- 7 files changed, 655 insertions(+), 644 deletions(-) create mode 100644 actions/apisearchatom.php create mode 100644 actions/apisearchjson.php create mode 100644 actions/apitrends.php delete mode 100644 actions/twitapisearchatom.php delete mode 100644 actions/twitapisearchjson.php delete mode 100644 actions/twitapitrends.php (limited to 'lib') diff --git a/actions/apisearchatom.php b/actions/apisearchatom.php new file mode 100644 index 000000000..60bb8b040 --- /dev/null +++ b/actions/apisearchatom.php @@ -0,0 +1,408 @@ +. + * + * @category Search + * @package StatusNet + * @author Zach Copley + * @copyright 2008-2010 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/apiprivateauth.php'; + +/** + * Action for outputting search results in Twitter compatible Atom + * format. + * + * TODO: abstract Atom stuff into a ruseable base class like + * RSS10Action. + * + * @category Search + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + * + * @see ApiPrivateAuthAction + */ + +class ApiSearchAtomAction extends ApiPrivateAuthAction +{ + + var $cnt; + var $query; + var $lang; + var $rpp; + var $page; + var $since_id; + var $geocode; + + /** + * Constructor + * + * Just wraps the Action constructor. + * + * @param string $output URI to output to, default = stdout + * @param boolean $indent Whether to indent output, default true + * + * @see Action::__construct + */ + + function __construct($output='php://output', $indent=null) + { + parent::__construct($output, $indent); + } + + /** + * Do we need to write to the database? + * + * @return boolean true + */ + + function isReadonly() + { + return true; + } + + /** + * Read arguments and initialize members + * + * @param array $args Arguments from $_REQUEST + * + * @return boolean success + * + */ + + function prepare($args) + { + common_debug("in apisearchatom prepare()"); + + parent::prepare($args); + + + $this->query = $this->trimmed('q'); + $this->lang = $this->trimmed('lang'); + $this->rpp = $this->trimmed('rpp'); + + if (!$this->rpp) { + $this->rpp = 15; + } + + if ($this->rpp > 100) { + $this->rpp = 100; + } + + $this->page = $this->trimmed('page'); + + if (!$this->page) { + $this->page = 1; + } + + // TODO: Suppport since_id -- we need to tweak the backend + // Search classes to support it. + + $this->since_id = $this->trimmed('since_id'); + $this->geocode = $this->trimmed('geocode'); + + // TODO: Also, language and geocode + + return true; + } + + /** + * Handle a request + * + * @param array $args Arguments from $_REQUEST + * + * @return void + */ + + function handle($args) + { + parent::handle($args); + common_debug("In apisearchatom handle()"); + $this->showAtom(); + } + + /** + * Get the notices to output as results. This also sets some class + * attrs so we can use them to calculate pagination, and output + * since_id and max_id. + * + * @return array an array of Notice objects sorted in reverse chron + */ + + function getNotices() + { + // TODO: Support search operators like from: and to:, boolean, etc. + + $notices = array(); + $notice = new Notice(); + + // lcase it for comparison + $q = strtolower($this->query); + + $search_engine = $notice->getSearchEngine('notice'); + $search_engine->set_sort_mode('chron'); + $search_engine->limit(($this->page - 1) * $this->rpp, + $this->rpp + 1, true); + if (false === $search_engine->query($q)) { + $this->cnt = 0; + } else { + $this->cnt = $notice->find(); + } + + $cnt = 0; + $this->max_id = 0; + + if ($this->cnt > 0) { + while ($notice->fetch()) { + + ++$cnt; + + if (!$this->max_id) { + $this->max_id = $notice->id; + } + + if ($cnt > $this->rpp) { + break; + } + + $notices[] = clone($notice); + } + } + + return $notices; + } + + /** + * Output search results as an Atom feed + * + * @return void + */ + + function showAtom() + { + $notices = $this->getNotices(); + + $this->initAtom(); + $this->showFeed(); + + foreach ($notices as $n) { + + $profile = $n->getProfile(); + + // Don't show notices from deleted users + + if (!empty($profile)) { + $this->showEntry($n); + } + } + + $this->endAtom(); + } + + /** + * Show feed specific Atom elements + * + * @return void + */ + + function showFeed() + { + // TODO: A9 OpenSearch stuff like search.twitter.com? + + $server = common_config('site', 'server'); + $sitename = common_config('site', 'name'); + + // XXX: Use xmlns:statusnet instead? + + $this->elementStart('feed', + array('xmlns' => 'http://www.w3.org/2005/Atom', + + // XXX: xmlns:twitter causes Atom validation to fail + // It's used for the source attr on notices + + 'xmlns:twitter' => 'http://api.twitter.com/', + 'xml:lang' => 'en-US')); // XXX Other locales ? + + $taguribase = TagURI::base(); + $this->element('id', null, "tag:$taguribase:search/$server"); + + $site_uri = common_path(false); + + $search_uri = $site_uri . 'api/search.atom?q=' . urlencode($this->query); + + if ($this->rpp != 15) { + $search_uri .= '&rpp=' . $this->rpp; + } + + // FIXME: this alternate link is not quite right because our + // web-based notice search doesn't support a rpp (responses per + // page) param yet + + $this->element('link', array('type' => 'text/html', + 'rel' => 'alternate', + 'href' => $site_uri . 'search/notice?q=' . + urlencode($this->query))); + + // self link + + $self_uri = $search_uri; + $self_uri .= ($this->page > 1) ? '&page=' . $this->page : ''; + + $this->element('link', array('type' => 'application/atom+xml', + 'rel' => 'self', + 'href' => $self_uri)); + + $this->element('title', null, "$this->query - $sitename Search"); + $this->element('updated', null, common_date_iso8601('now')); + + // XXX: The below "rel" links are not valid Atom, but it's what + // Twitter does... + + // refresh link + + $refresh_uri = $search_uri . "&since_id=" . $this->max_id; + + $this->element('link', array('type' => 'application/atom+xml', + 'rel' => 'refresh', + 'href' => $refresh_uri)); + + // pagination links + + if ($this->cnt > $this->rpp) { + + $next_uri = $search_uri . "&max_id=" . $this->max_id . + '&page=' . ($this->page + 1); + + $this->element('link', array('type' => 'application/atom+xml', + 'rel' => 'next', + 'href' => $next_uri)); + } + + if ($this->page > 1) { + + $previous_uri = $search_uri . "&max_id=" . $this->max_id . + '&page=' . ($this->page - 1); + + $this->element('link', array('type' => 'application/atom+xml', + 'rel' => 'previous', + 'href' => $previous_uri)); + } + + } + + /** + * Build an Atom entry similar to search.twitter.com's based on + * a given notice + * + * @param Notice $notice the notice to use + * + * @return void + */ + + function showEntry($notice) + { + $server = common_config('site', 'server'); + $profile = $notice->getProfile(); + $nurl = common_local_url('shownotice', array('notice' => $notice->id)); + + $this->elementStart('entry'); + + $taguribase = TagURI::base(); + + $this->element('id', null, "tag:$taguribase:$notice->id"); + $this->element('published', null, common_date_w3dtf($notice->created)); + $this->element('link', array('type' => 'text/html', + 'rel' => 'alternate', + 'href' => $nurl)); + $this->element('title', null, common_xml_safe_str(trim($notice->content))); + $this->element('content', array('type' => 'html'), $notice->rendered); + $this->element('updated', null, common_date_w3dtf($notice->created)); + $this->element('link', array('type' => 'image/png', + // XXX: Twitter uses rel="image" (not valid) + 'rel' => 'related', + 'href' => $profile->avatarUrl())); + + // @todo: Here is where we'd put in a link to an atom feed for threads + + $source = null; + + $ns = $notice->getSource(); + if ($ns) { + if (!empty($ns->name) && !empty($ns->url)) { + $source = '' + . htmlspecialchars($ns->name) + . ''; + } else { + $source = $ns->code; + } + } + + $this->element("twitter:source", null, $source); + + $this->elementStart('author'); + + $name = $profile->nickname; + + if ($profile->fullname) { + $name .= ' (' . $profile->fullname . ')'; + } + + $this->element('name', null, $name); + $this->element('uri', null, common_profile_uri($profile)); + $this->elementEnd('author'); + + $this->elementEnd('entry'); + } + + /** + * Initialize the Atom output, send headers + * + * @return void + */ + + function initAtom() + { + header('Content-Type: application/atom+xml; charset=utf-8'); + $this->startXml(); + } + + /** + * End the Atom feed + * + * @return void + */ + + function endAtom() + { + $this->elementEnd('feed'); + } + +} diff --git a/actions/apisearchjson.php b/actions/apisearchjson.php new file mode 100644 index 000000000..e44634684 --- /dev/null +++ b/actions/apisearchjson.php @@ -0,0 +1,154 @@ +. + * + * @category Search + * @package StatusNet + * @author Zach Copley + * @copyright 2008-2010 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/apiprivateauth.php'; +require_once INSTALLDIR.'/lib/jsonsearchresultslist.php'; + +/** + * Action handler for Twitter-compatible API search + * + * @category Search + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + * @see ApiAction + */ + +class ApiSearchJSONAction extends ApiPrivateAuthAction +{ + var $query; + var $lang; + var $rpp; + var $page; + var $since_id; + var $limit; + var $geocode; + + /** + * Initialization. + * + * @param array $args Web and URL arguments + * + * @return boolean true if nothing goes wrong + */ + + function prepare($args) + { + common_debug("apisearchjson prepare()"); + + parent::prepare($args); + + $this->query = $this->trimmed('q'); + $this->lang = $this->trimmed('lang'); + $this->rpp = $this->trimmed('rpp'); + + if (!$this->rpp) { + $this->rpp = 15; + } + + if ($this->rpp > 100) { + $this->rpp = 100; + } + + $this->page = $this->trimmed('page'); + + if (!$this->page) { + $this->page = 1; + } + + $this->since_id = $this->trimmed('since_id'); + $this->geocode = $this->trimmed('geocode'); + + return true; + } + + /** + * Handle a request + * + * @param array $args Arguments from $_REQUEST + * + * @return void + */ + + function handle($args) + { + parent::handle($args); + $this->showResults(); + } + + /** + * Show search results + * + * @return void + */ + + function showResults() + { + + // TODO: Support search operators like from: and to:, boolean, etc. + + $notice = new Notice(); + + // lcase it for comparison + $q = strtolower($this->query); + + $search_engine = $notice->getSearchEngine('notice'); + $search_engine->set_sort_mode('chron'); + $search_engine->limit(($this->page - 1) * $this->rpp, $this->rpp + 1, true); + if (false === $search_engine->query($q)) { + $cnt = 0; + } else { + $cnt = $notice->find(); + } + + // TODO: since_id, lang, geocode + + $results = new JSONSearchResultsList($notice, $q, $this->rpp, $this->page); + + $this->initDocument('json'); + $results->show(); + $this->endDocument('json'); + } + + /** + * Do we need to write to the database? + * + * @return boolean true + */ + + function isReadOnly($args) + { + return true; + } +} diff --git a/actions/apitrends.php b/actions/apitrends.php new file mode 100644 index 000000000..5b74636c6 --- /dev/null +++ b/actions/apitrends.php @@ -0,0 +1,90 @@ +. + * + * @category Search + * @package StatusNet + * @author Zach Copley + * @copyright 2008-2010 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/apiprivateauth.php'; + +/** + * Returns the top ten queries that are currently trending + * + * @category Search + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + * + * @see ApiAction + */ + +class ApiTrendsAction extends ApiPrivateAuthAction +{ + + var $callback; + + /** + * Initialization. + * + * @param array $args Web and URL arguments + * + * @return boolean false if user doesn't exist + */ + function prepare($args) + { + parent::prepare($args); + return true; + } + + /** + * Handle a request + * + * @param array $args Arguments from $_REQUEST + * + * @return void + */ + + function handle($args) + { + parent::handle($args); + $this->showTrends(); + } + + /** + * Output the trends + * + * @return void + */ + function showTrends() + { + $this->serverError(_('API method under construction.'), 501); + } + +} \ No newline at end of file diff --git a/actions/twitapisearchatom.php b/actions/twitapisearchatom.php deleted file mode 100644 index 51e8a8881..000000000 --- a/actions/twitapisearchatom.php +++ /dev/null @@ -1,402 +0,0 @@ -. - * - * @category Search - * @package StatusNet - * @author Zach Copley - * @copyright 2008-2009 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -/** - * Action for outputting search results in Twitter compatible Atom - * format. - * - * TODO: abstract Atom stuff into a ruseable base class like - * RSS10Action. - * - * @category Search - * @package StatusNet - * @author Zach Copley - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - * - * @see ApiAction - */ - -class TwitapisearchatomAction extends ApiAction -{ - - var $cnt; - var $query; - var $lang; - var $rpp; - var $page; - var $since_id; - var $geocode; - - /** - * Constructor - * - * Just wraps the Action constructor. - * - * @param string $output URI to output to, default = stdout - * @param boolean $indent Whether to indent output, default true - * - * @see Action::__construct - */ - - function __construct($output='php://output', $indent=null) - { - parent::__construct($output, $indent); - } - - /** - * Do we need to write to the database? - * - * @return boolean true - */ - - function isReadonly() - { - return true; - } - - /** - * Read arguments and initialize members - * - * @param array $args Arguments from $_REQUEST - * - * @return boolean success - * - */ - - function prepare($args) - { - parent::prepare($args); - - $this->query = $this->trimmed('q'); - $this->lang = $this->trimmed('lang'); - $this->rpp = $this->trimmed('rpp'); - - if (!$this->rpp) { - $this->rpp = 15; - } - - if ($this->rpp > 100) { - $this->rpp = 100; - } - - $this->page = $this->trimmed('page'); - - if (!$this->page) { - $this->page = 1; - } - - // TODO: Suppport since_id -- we need to tweak the backend - // Search classes to support it. - - $this->since_id = $this->trimmed('since_id'); - $this->geocode = $this->trimmed('geocode'); - - // TODO: Also, language and geocode - - return true; - } - - /** - * Handle a request - * - * @param array $args Arguments from $_REQUEST - * - * @return void - */ - - function handle($args) - { - parent::handle($args); - $this->showAtom(); - } - - /** - * Get the notices to output as results. This also sets some class - * attrs so we can use them to calculate pagination, and output - * since_id and max_id. - * - * @return array an array of Notice objects sorted in reverse chron - */ - - function getNotices() - { - // TODO: Support search operators like from: and to:, boolean, etc. - - $notices = array(); - $notice = new Notice(); - - // lcase it for comparison - $q = strtolower($this->query); - - $search_engine = $notice->getSearchEngine('notice'); - $search_engine->set_sort_mode('chron'); - $search_engine->limit(($this->page - 1) * $this->rpp, - $this->rpp + 1, true); - if (false === $search_engine->query($q)) { - $this->cnt = 0; - } else { - $this->cnt = $notice->find(); - } - - $cnt = 0; - $this->max_id = 0; - - if ($this->cnt > 0) { - while ($notice->fetch()) { - - ++$cnt; - - if (!$this->max_id) { - $this->max_id = $notice->id; - } - - if ($cnt > $this->rpp) { - break; - } - - $notices[] = clone($notice); - } - } - - return $notices; - } - - /** - * Output search results as an Atom feed - * - * @return void - */ - - function showAtom() - { - $notices = $this->getNotices(); - - $this->initAtom(); - $this->showFeed(); - - foreach ($notices as $n) { - - $profile = $n->getProfile(); - - // Don't show notices from deleted users - - if (!empty($profile)) { - $this->showEntry($n); - } - } - - $this->endAtom(); - } - - /** - * Show feed specific Atom elements - * - * @return void - */ - - function showFeed() - { - // TODO: A9 OpenSearch stuff like search.twitter.com? - - $server = common_config('site', 'server'); - $sitename = common_config('site', 'name'); - - // XXX: Use xmlns:statusnet instead? - - $this->elementStart('feed', - array('xmlns' => 'http://www.w3.org/2005/Atom', - - // XXX: xmlns:twitter causes Atom validation to fail - // It's used for the source attr on notices - - 'xmlns:twitter' => 'http://api.twitter.com/', - 'xml:lang' => 'en-US')); // XXX Other locales ? - - $taguribase = TagURI::base(); - $this->element('id', null, "tag:$taguribase:search/$server"); - - $site_uri = common_path(false); - - $search_uri = $site_uri . 'api/search.atom?q=' . urlencode($this->query); - - if ($this->rpp != 15) { - $search_uri .= '&rpp=' . $this->rpp; - } - - // FIXME: this alternate link is not quite right because our - // web-based notice search doesn't support a rpp (responses per - // page) param yet - - $this->element('link', array('type' => 'text/html', - 'rel' => 'alternate', - 'href' => $site_uri . 'search/notice?q=' . - urlencode($this->query))); - - // self link - - $self_uri = $search_uri; - $self_uri .= ($this->page > 1) ? '&page=' . $this->page : ''; - - $this->element('link', array('type' => 'application/atom+xml', - 'rel' => 'self', - 'href' => $self_uri)); - - $this->element('title', null, "$this->query - $sitename Search"); - $this->element('updated', null, common_date_iso8601('now')); - - // XXX: The below "rel" links are not valid Atom, but it's what - // Twitter does... - - // refresh link - - $refresh_uri = $search_uri . "&since_id=" . $this->max_id; - - $this->element('link', array('type' => 'application/atom+xml', - 'rel' => 'refresh', - 'href' => $refresh_uri)); - - // pagination links - - if ($this->cnt > $this->rpp) { - - $next_uri = $search_uri . "&max_id=" . $this->max_id . - '&page=' . ($this->page + 1); - - $this->element('link', array('type' => 'application/atom+xml', - 'rel' => 'next', - 'href' => $next_uri)); - } - - if ($this->page > 1) { - - $previous_uri = $search_uri . "&max_id=" . $this->max_id . - '&page=' . ($this->page - 1); - - $this->element('link', array('type' => 'application/atom+xml', - 'rel' => 'previous', - 'href' => $previous_uri)); - } - - } - - /** - * Build an Atom entry similar to search.twitter.com's based on - * a given notice - * - * @param Notice $notice the notice to use - * - * @return void - */ - - function showEntry($notice) - { - $server = common_config('site', 'server'); - $profile = $notice->getProfile(); - $nurl = common_local_url('shownotice', array('notice' => $notice->id)); - - $this->elementStart('entry'); - - $taguribase = TagURI::base(); - - $this->element('id', null, "tag:$taguribase:$notice->id"); - $this->element('published', null, common_date_w3dtf($notice->created)); - $this->element('link', array('type' => 'text/html', - 'rel' => 'alternate', - 'href' => $nurl)); - $this->element('title', null, common_xml_safe_str(trim($notice->content))); - $this->element('content', array('type' => 'html'), $notice->rendered); - $this->element('updated', null, common_date_w3dtf($notice->created)); - $this->element('link', array('type' => 'image/png', - // XXX: Twitter uses rel="image" (not valid) - 'rel' => 'related', - 'href' => $profile->avatarUrl())); - - // @todo: Here is where we'd put in a link to an atom feed for threads - - $source = null; - - $ns = $notice->getSource(); - if ($ns) { - if (!empty($ns->name) && !empty($ns->url)) { - $source = '' - . htmlspecialchars($ns->name) - . ''; - } else { - $source = $ns->code; - } - } - - $this->element("twitter:source", null, $source); - - $this->elementStart('author'); - - $name = $profile->nickname; - - if ($profile->fullname) { - $name .= ' (' . $profile->fullname . ')'; - } - - $this->element('name', null, $name); - $this->element('uri', null, common_profile_uri($profile)); - $this->elementEnd('author'); - - $this->elementEnd('entry'); - } - - /** - * Initialize the Atom output, send headers - * - * @return void - */ - - function initAtom() - { - header('Content-Type: application/atom+xml; charset=utf-8'); - $this->startXml(); - } - - /** - * End the Atom feed - * - * @return void - */ - - function endAtom() - { - $this->elementEnd('feed'); - } - -} diff --git a/actions/twitapisearchjson.php b/actions/twitapisearchjson.php deleted file mode 100644 index b5c006aa7..000000000 --- a/actions/twitapisearchjson.php +++ /dev/null @@ -1,151 +0,0 @@ -. - * - * @category Search - * @package StatusNet - * @author Zach Copley - * @copyright 2008-2009 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR.'/lib/jsonsearchresultslist.php'; - -/** - * Action handler for Twitter-compatible API search - * - * @category Search - * @package StatusNet - * @author Zach Copley - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - * @see ApiAction - */ - -class TwitapisearchjsonAction extends ApiAction -{ - var $query; - var $lang; - var $rpp; - var $page; - var $since_id; - var $limit; - var $geocode; - - /** - * Initialization. - * - * @param array $args Web and URL arguments - * - * @return boolean true if nothing goes wrong - */ - - function prepare($args) - { - parent::prepare($args); - - $this->query = $this->trimmed('q'); - $this->lang = $this->trimmed('lang'); - $this->rpp = $this->trimmed('rpp'); - - if (!$this->rpp) { - $this->rpp = 15; - } - - if ($this->rpp > 100) { - $this->rpp = 100; - } - - $this->page = $this->trimmed('page'); - - if (!$this->page) { - $this->page = 1; - } - - $this->since_id = $this->trimmed('since_id'); - $this->geocode = $this->trimmed('geocode'); - - return true; - } - - /** - * Handle a request - * - * @param array $args Arguments from $_REQUEST - * - * @return void - */ - - function handle($args) - { - parent::handle($args); - $this->showResults(); - } - - /** - * Show search results - * - * @return void - */ - - function showResults() - { - - // TODO: Support search operators like from: and to:, boolean, etc. - - $notice = new Notice(); - - // lcase it for comparison - $q = strtolower($this->query); - - $search_engine = $notice->getSearchEngine('notice'); - $search_engine->set_sort_mode('chron'); - $search_engine->limit(($this->page - 1) * $this->rpp, $this->rpp + 1, true); - if (false === $search_engine->query($q)) { - $cnt = 0; - } else { - $cnt = $notice->find(); - } - - // TODO: since_id, lang, geocode - - $results = new JSONSearchResultsList($notice, $q, $this->rpp, $this->page); - - $this->initDocument('json'); - $results->show(); - $this->endDocument('json'); - } - - /** - * Do we need to write to the database? - * - * @return boolean true - */ - - function isReadOnly($args) - { - return true; - } -} diff --git a/actions/twitapitrends.php b/actions/twitapitrends.php deleted file mode 100644 index 5a04569a2..000000000 --- a/actions/twitapitrends.php +++ /dev/null @@ -1,88 +0,0 @@ -. - * - * @category Search - * @package StatusNet - * @author Zach Copley - * @copyright 2008-2009 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -/** - * Returns the top ten queries that are currently trending - * - * @category Search - * @package StatusNet - * @author Zach Copley - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - * - * @see ApiAction - */ - -class TwitapitrendsAction extends ApiAction -{ - - var $callback; - - /** - * Initialization. - * - * @param array $args Web and URL arguments - * - * @return boolean false if user doesn't exist - */ - function prepare($args) - { - parent::prepare($args); - return true; - } - - /** - * Handle a request - * - * @param array $args Arguments from $_REQUEST - * - * @return void - */ - - function handle($args) - { - parent::handle($args); - $this->showTrends(); - } - - /** - * Output the trends - * - * @return void - */ - function showTrends() - { - $this->serverError(_('API method under construction.'), $code = 501); - } - -} \ No newline at end of file diff --git a/lib/router.php b/lib/router.php index fec229c9b..7e1e6a2a4 100644 --- a/lib/router.php +++ b/lib/router.php @@ -667,9 +667,9 @@ class Router ); // 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('api/search.atom', array('action' => 'ApiSearchAtom')); + $m->connect('api/search.json', array('action' => 'ApiSearchJSON')); + $m->connect('api/trends.json', array('action' => 'ApiTrends')); $m->connect('api/oauth/request_token', array('action' => 'apioauthrequesttoken')); -- cgit v1.2.3-54-g00ecf From f0c5e7eca3842411d4e3ee6efb3fd6ac0ad85f4a Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Sat, 26 Jun 2010 15:07:32 -0400 Subject: Fix for bug #2382: releasing claim on failed queue item works again with DB-based queues. Warning: DB-based queue doesn't currently implement discarding of items after a retry limit. Failed items will be retried until they succeed. --- classes/Queue_item.php | 13 +++++++++++++ lib/dbqueuemanager.php | 4 +--- 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/classes/Queue_item.php b/classes/Queue_item.php index f83c2cef1..c7e17be6e 100644 --- a/classes/Queue_item.php +++ b/classes/Queue_item.php @@ -64,4 +64,17 @@ class Queue_item extends Memcached_DataObject $qi = null; return null; } + + /** + * Release a claimed item. + */ + function releaseCLaim() + { + // DB_DataObject doesn't let us save nulls right now + $sql = sprintf("UPDATE queue_item SET claimed=NULL WHERE id=%d", $this->id); + $this->query($sql); + + $this->claimed = null; + $this->encache(); + } } diff --git a/lib/dbqueuemanager.php b/lib/dbqueuemanager.php index 3032e4ec7..3dda9fd1a 100644 --- a/lib/dbqueuemanager.php +++ b/lib/dbqueuemanager.php @@ -135,9 +135,7 @@ class DBQueueManager extends QueueManager if (empty($qi->claimed)) { $this->_log(LOG_WARNING, "[$queue:item $qi->id] Ignoring failure for unclaimed queue item"); } else { - $orig = clone($qi); - $qi->claimed = null; - $qi->update($orig); + $qi->releaseClaim(); } $this->stats('error', $queue); -- cgit v1.2.3-54-g00ecf From 9c7b66984c46668f314f93337d28c62854b6d134 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Mon, 10 May 2010 16:18:29 -0700 Subject: Enhanced upload file type detection. If given an original filename, we'll attempt to detect type from the extension if we were unable to make a definitive match from content. Generic octet-stream, zip, and MS Office type are explicitly singled out for re-checks, which fixes OpenOffice and MS Office documents to come up with the proper types when misdetected. File extensions can also be added to the upload type whitelist; they'll be normalized to types for the actual comparison, so only known extensions will work. --- lib/mediafile.php | 54 +++++++++++++++++++++++++++-- tests/MediaFileTest.php | 73 +++++++++++++++++++++++++--------------- tests/sample-uploads/image.gif | Bin 0 -> 35 bytes tests/sample-uploads/image.jpeg | Bin 0 -> 306 bytes tests/sample-uploads/image.jpg | Bin 0 -> 306 bytes tests/sample-uploads/image.png | Bin 0 -> 159 bytes 6 files changed, 97 insertions(+), 30 deletions(-) create mode 100644 tests/sample-uploads/image.gif create mode 100644 tests/sample-uploads/image.jpeg create mode 100644 tests/sample-uploads/image.jpg create mode 100644 tests/sample-uploads/image.png (limited to 'lib') diff --git a/lib/mediafile.php b/lib/mediafile.php index 10d90d008..85d673d92 100644 --- a/lib/mediafile.php +++ b/lib/mediafile.php @@ -180,7 +180,8 @@ class MediaFile return; } - $mimetype = MediaFile::getUploadedFileType($_FILES[$param]['tmp_name']); + $mimetype = MediaFile::getUploadedFileType($_FILES[$param]['tmp_name'], + $_FILES[$param]['name']); $filename = null; @@ -241,19 +242,41 @@ class MediaFile return new MediaFile($user, $filename, $mimetype); } - static function getUploadedFileType($f) { + /** + * Attempt to identify the content type of a given file. + * + * @param mixed $f file handle resource, or filesystem path as string + * @param string $originalFilename (optional) for extension-based detection + * @return string + * + * @fixme is this an internal or public method? It's called from GetFileAction + * @fixme this seems to tie a front-end error message in, kinda confusing + * @fixme this looks like it could return a PEAR_Error in some cases, if + * type can't be identified and $config['attachments']['supported'] is true + * + * @throws ClientException if type is known, but not supported for local uploads + */ + static function getUploadedFileType($f, $originalFilename=false) { require_once 'MIME/Type.php'; + require_once 'MIME/Type/Extension.php'; + $mte = new MIME_Type_Extension(); $cmd = &PEAR::getStaticProperty('MIME_Type', 'fileCmd'); $cmd = common_config('attachments', 'filecommand'); $filetype = null; + // If we couldn't get a clear type from the file extension, + // we'll go ahead and try checking the content. Content checks + // are unambiguous for most image files, but nearly useless + // for office document formats. + if (is_string($f)) { // assuming a filename $filetype = MIME_Type::autoDetect($f); + } else { // assuming a filehandle @@ -262,7 +285,32 @@ class MediaFile $filetype = MIME_Type::autoDetect($stream['uri']); } - if (common_config('attachments', 'supported') === true || in_array($filetype, common_config('attachments', 'supported'))) { + // The content-based sources for MIME_Type::autoDetect() + // are wildly unreliable for office-type documents. If we've + // gotten an unclear reponse back or just couldn't identify it, + // we'll try detecting a type from its extension... + $unclearTypes = array('application/octet-stream', + 'application/vnd.ms-office', + 'application/zip'); + + if ($originalFilename && (!$filetype || in_array($filetype, $unclearTypes))) { + $type = $mte->getMIMEType($originalFilename); + if (is_string($type)) { + $filetype = $type; + } + } + + $supported = common_config('attachments', 'supported'); + if (is_array($supported)) { + // Normalize extensions to mime types + foreach ($supported as $i => $entry) { + if (strpos($entry, '/') === false) { + common_log(LOG_INFO, "sample.$entry"); + $supported[$i] = $mte->getMIMEType("sample.$entry"); + } + } + } + if ($supported === true || in_array($filetype, $supported)) { return $filetype; } $media = MIME_Type::getMedia($filetype); diff --git a/tests/MediaFileTest.php b/tests/MediaFileTest.php index 6fe995621..a76a4f45e 100644 --- a/tests/MediaFileTest.php +++ b/tests/MediaFileTest.php @@ -34,43 +34,62 @@ class MediaFileTest extends PHPUnit_Framework_TestCase if (!file_exists($filename)) { throw new Exception("WTF? $filename test file missing"); } - $this->assertEquals($expectedType, MediaFile::getUploadedFileType($filename)); + + $type = MediaFile::getUploadedFileType($filename, basename($filename)); + $this->assertEquals($expectedType, $type); + } + + /** + * @dataProvider fileTypeCases + * + */ + public function testUploadedFileType($filename, $expectedType) + { + if (!file_exists($filename)) { + throw new Exception("WTF? $filename test file missing"); + } + $tmp = tmpfile(); + fwrite($tmp, file_get_contents($filename)); + + $type = MediaFile::getUploadedFileType($tmp, basename($filename)); + $this->assertEquals($expectedType, $type); } static public function fileTypeCases() { $base = dirname(__FILE__); $dir = "$base/sample-uploads"; - return array( - array("$dir/office.pdf", "application/pdf"), + $files = array( + "image.png" => "image/png", + "image.gif" => "image/gif", + "image.jpg" => "image/jpeg", + "image.jpeg" => "image/jpeg", + + "office.pdf" => "application/pdf", - array("$dir/wordproc.odt", "application/vnd.oasis.opendocument.text"), - array("$dir/wordproc.ott", "application/vnd.oasis.opendocument.text-template"), - array("$dir/wordproc.doc", "application/msword"), - array("$dir/wordproc.docx", - "application/vnd.openxmlformats-officedocument.wordprocessingml.document"), - array("$dir/wordproc.rtf", "text/rtf"), + "wordproc.odt" => "application/vnd.oasis.opendocument.text", + "wordproc.ott" => "application/vnd.oasis.opendocument.text-template", + "wordproc.doc" => "application/msword", + "wordproc.docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + "wordproc.rtf" => "text/rtf", - array("$dir/spreadsheet.ods", - "application/vnd.oasis.opendocument.spreadsheet"), - array("$dir/spreadsheet.ots", - "application/vnd.oasis.opendocument.spreadsheet-template"), - array("$dir/spreadsheet.xls", "application/vnd.ms-excel"), - array("$dir/spreadsheet.xlt", "application/vnd.ms-excel"), - array("$dir/spreadsheet.xlsx", - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"), + "spreadsheet.ods" => "application/vnd.oasis.opendocument.spreadsheet", + "spreadsheet.ots" => "application/vnd.oasis.opendocument.spreadsheet-template", + "spreadsheet.xls" => "application/vnd.ms-excel", + "spreadsheet.xlt" => "application/vnd.ms-excel", + "spreadsheet.xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - array("$dir/presentation.odp", - "application/vnd.oasis-opendocument.presentation"), - array("$dir/presentation.otp", - "application/vnd.oasis-opendocument.presentation-template"), - array("$dir/presentation.ppt", - "application/vnd.ms-powerpoint"), - array("$dir/presentation.pot", - "application/vnd.ms-powerpoint"), - array("$dir/presentation.pptx", - "application/vnd.openxmlformats-officedocument.presentationml.presentation"), + "presentation.odp" => "application/vnd.oasis.opendocument.presentation", + "presentation.otp" => "application/vnd.oasis.opendocument.presentation-template", + "presentation.ppt" => "application/vnd.ms-powerpoint", + "presentation.pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation", ); + + $dataset = array(); + foreach ($files as $file => $type) { + $dataset[] = array("$dir/$file", $type); + } + return $dataset; } } diff --git a/tests/sample-uploads/image.gif b/tests/sample-uploads/image.gif new file mode 100644 index 000000000..b636f4b8d Binary files /dev/null and b/tests/sample-uploads/image.gif differ diff --git a/tests/sample-uploads/image.jpeg b/tests/sample-uploads/image.jpeg new file mode 100644 index 000000000..21fcb5aef Binary files /dev/null and b/tests/sample-uploads/image.jpeg differ diff --git a/tests/sample-uploads/image.jpg b/tests/sample-uploads/image.jpg new file mode 100644 index 000000000..21fcb5aef Binary files /dev/null and b/tests/sample-uploads/image.jpg differ diff --git a/tests/sample-uploads/image.png b/tests/sample-uploads/image.png new file mode 100644 index 000000000..60cbcfd17 Binary files /dev/null and b/tests/sample-uploads/image.png differ -- cgit v1.2.3-54-g00ecf