From 1e8e1e836d53b357eb1ddd538c0ceb4d8b289f59 Mon Sep 17 00:00:00 2001 From: Christopher Vollick Date: Mon, 22 Feb 2010 11:19:16 -0500 Subject: Rewrote How Blogspam Plugin Made HTTP Requests. The old way didn't seem to work anymore. It was just sending empty requests. --- plugins/BlogspamNetPlugin.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'plugins') diff --git a/plugins/BlogspamNetPlugin.php b/plugins/BlogspamNetPlugin.php index 51236001a..9b7ed1c12 100644 --- a/plugins/BlogspamNetPlugin.php +++ b/plugins/BlogspamNetPlugin.php @@ -72,8 +72,10 @@ class BlogspamNetPlugin extends Plugin common_debug("Blogspamnet args = " . print_r($args, TRUE)); $requestBody = xmlrpc_encode_request('testComment', array($args)); - $request = HTTPClient::start(); - $httpResponse = $request->post($this->baseUrl, array('Content-Type: text/xml'), $requestBody); + $request = new HTTPClient($this->baseUrl, HTTPClient::METHOD_POST); + $request->setHeader('Content-Type', 'text/xml'); + $request->setBody($requestBody); + $httpResponse = $request->send(); $response = xmlrpc_decode($httpResponse->getBody()); if (xmlrpc_is_fault($response)) { -- cgit v1.2.3-54-g00ecf From a6afc1cfd6e99d83322910d4c1dafb16b1c4ae90 Mon Sep 17 00:00:00 2001 From: Christopher Vollick Date: Mon, 22 Feb 2010 11:20:44 -0500 Subject: Made Blogspam Plugin Respect textlimit Setting. The Blogspam plugin was setting a max-size to 140. It was therefore rejecting posts with more characters as spam. This kind of defeated the purpose of setting a higher limit... --- plugins/BlogspamNetPlugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'plugins') diff --git a/plugins/BlogspamNetPlugin.php b/plugins/BlogspamNetPlugin.php index 9b7ed1c12..d52e6006a 100644 --- a/plugins/BlogspamNetPlugin.php +++ b/plugins/BlogspamNetPlugin.php @@ -120,7 +120,7 @@ class BlogspamNetPlugin extends Plugin $args['site'] = common_root_url(); $args['version'] = $this->userAgent(); - $args['options'] = "max-size=140,min-size=0,min-words=0,exclude=bayasian"; + $args['options'] = "max-size=" . common_config('site','textlimit') . ",min-size=0,min-words=0,exclude=bayasian"; return $args; } -- cgit v1.2.3-54-g00ecf From 543ff40ef62f2587cde084b03bcf2e956f52ce2f Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 24 Feb 2010 16:51:24 -0800 Subject: Populate more profile information when doing a remote subscribe --- lib/activity.php | 56 +++++++++++++++++------ plugins/OStatus/classes/Ostatus_profile.php | 71 +++++++++++++++++++++++++++-- tests/ActivityParseTests.php | 2 + 3 files changed, 113 insertions(+), 16 deletions(-) (limited to 'plugins') diff --git a/lib/activity.php b/lib/activity.php index 33932ad0e..eace672a5 100644 --- a/lib/activity.php +++ b/lib/activity.php @@ -154,7 +154,15 @@ class PoCo PoCo::NS ); - array_push($urls, new PoCoURL($type, $value, $primary)); + $isPrimary = false; + + if (isset($primary) && $primary == 'true') { + $isPrimary = true; + } + + // @todo check to make sure a primary hasn't already been added + + array_push($urls, new PoCoURL($type, $value, $isPrimary)); } return $urls; } @@ -213,6 +221,15 @@ class PoCo return $poco; } + function getPrimaryURL() + { + foreach ($this->urls as $url) { + if ($url->primary) { + return $url; + } + } + } + function asString() { $xs = new XMLStringer(true); @@ -494,6 +511,12 @@ class ActivityObject $this->element = $element; + $this->geopoint = $this->_childContent( + $element, + ActivityContext::POINT, + ActivityContext::GEORSS + ); + if ($element->tagName == 'author') { $this->type = self::PERSON; // XXX: is this fair? @@ -759,22 +782,29 @@ class ActivityContext for ($i = 0; $i < $points->length; $i++) { $point = $points->item($i)->textContent; - $point = str_replace(',', ' ', $point); // per spec "treat commas as whitespace" - $point = preg_replace('/\s+/', ' ', $point); - $point = trim($point); - $coords = explode(' ', $point); - if (count($coords) == 2) { - list($lat, $lon) = $coords; - if (is_numeric($lat) && is_numeric($lon)) { - common_log(LOG_INFO, "Looking up location for $lat $lon from georss"); - return Location::fromLatLon($lat, $lon); - } - } - common_log(LOG_ERR, "Ignoring bogus georss:point value $point"); + return self::locationFromPoint($point); } return null; } + + // XXX: Move to ActivityUtils or Location? + static function locationFromPoint($point) + { + $point = str_replace(',', ' ', $point); // per spec "treat commas as whitespace" + $point = preg_replace('/\s+/', ' ', $point); + $point = trim($point); + $coords = explode(' ', $point); + if (count($coords) == 2) { + list($lat, $lon) = $coords; + if (is_numeric($lat) && is_numeric($lon)) { + common_log(LOG_INFO, "Looking up location for $lat $lon from georss point"); + return Location::fromLatLon($lat, $lon); + } + } + common_log(LOG_ERR, "Ignoring bogus georss:point value $point"); + return null; + } } /** diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 5e38a523e..144fdfa8b 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -1118,11 +1118,20 @@ class Ostatus_profile extends Memcached_DataObject $profile->profileurl = $hints['profileurl']; } - // @fixme bio + $profile->bio = self::getActivityObjectBio($object, $hints); + $profile->location = self::getActivityObjectLocation($object, $hints); + $profile->homepage = self::getActivityObjectHomepage($object, $hints); + + if (!empty($object->geopoint)) { + $location = ActivityContext::locationFromPoint($object->geopoint); + if (!empty($location)) { + $profile->lat = $location->lat; + $profile->lon = $location->lon; + } + } + // @fixme tags/categories - // @fixme location? // @todo tags from categories - // @todo lat/lon/location? if ($profile->id) { common_log(LOG_DEBUG, "Updating OStatus profile $profile->id from remote info $object->id: " . var_export($object, true) . var_export($hints, true)); @@ -1154,6 +1163,62 @@ class Ostatus_profile extends Memcached_DataObject } } + protected static function getActivityObjectHomepage($object, $hints=array()) + { + $homepage = null; + $poco = $object->poco; + + if (!empty($poco)) { + $url = $poco->getPrimaryURL(); + if ($url->type == 'homepage') { + $homepage = $url->value; + } + } + + // @todo Try for a another PoCo URL? + + return $homepage; + } + + protected static function getActivityObjectLocation($object, $hints=array()) + { + $location = null; + + if (!empty($object->poco)) { + if (isset($object->poco->address->formatted)) { + $location = $object->poco->address->formatted; + if (mb_strlen($location) > 255) { + $location = mb_substr($note, 0, 255 - 3) . ' … '; + } + } + } + + // @todo Try to find location some othe way? Via goerss point? + + return $location; + } + + protected static function getActivityObjectBio($object, $hints=array()) + { + $bio = null; + + if (!empty($object->poco)) { + $note = $object->poco->note; + if (!empty($note)) { + if (mb_strlen($note) > Profile::maxBio()) { + // XXX: truncate ok? + $bio = mb_substr($note, 0, Profile::maxBio() - 3) . ' … '; + } else { + $bio = $note; + } + } + } + + // @todo Try to get bio info some other way? + + return $bio; + } + protected static function getActivityObjectNickname($object, $hints=array()) { if ($object->poco) { diff --git a/tests/ActivityParseTests.php b/tests/ActivityParseTests.php index 5de97d2e2..d1d871734 100644 --- a/tests/ActivityParseTests.php +++ b/tests/ActivityParseTests.php @@ -133,6 +133,8 @@ class ActivityParseTests extends PHPUnit_Framework_TestCase $this->assertEquals($poco->urls[0]->type, 'homepage'); $this->assertEquals($poco->urls[0]->value, 'http://example.com/blog.html'); $this->assertEquals($poco->urls[0]->primary, 'true'); + $this->assertEquals($act->actor->geopoint, '37.7749295 -122.4194155'); + } } -- cgit v1.2.3-54-g00ecf From b798faf9ea67c5e02ee515fb8e344132f8edd6be Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 25 Feb 2010 02:43:20 +0000 Subject: OStatus: abort processing of this PuSH in item if we got an exception, rather than letting it be re-run. --- plugins/OStatus/lib/pushinqueuehandler.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'plugins') diff --git a/plugins/OStatus/lib/pushinqueuehandler.php b/plugins/OStatus/lib/pushinqueuehandler.php index a90f52df2..1fd29ae30 100644 --- a/plugins/OStatus/lib/pushinqueuehandler.php +++ b/plugins/OStatus/lib/pushinqueuehandler.php @@ -40,7 +40,11 @@ class PushInQueueHandler extends QueueHandler $feedsub = FeedSub::staticGet('id', $feedsub_id); if ($feedsub) { - $feedsub->receive($post, $hmac); + try { + $feedsub->receive($post, $hmac); + } catch(Exception $e) { + common_log(LOG_ERR, "Exception during PuSH input processing for $feedsub->uri: " . $e->getMessage()); + } } else { common_log(LOG_ERR, "Discarding POST to unknown feed subscription id $feedsub_id"); } -- cgit v1.2.3-54-g00ecf From 58e232a10ad45808caeb1bbd72641aea535e00e8 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 25 Feb 2010 02:43:55 +0000 Subject: OStatus: when finding webfinger @-replies, override a local profile match if found at the same location (eg @someguy vs @someguy@example.org) Fixes inconsistent application of webfinger @-mentions in OStatus; once a local profile is set up the local name would often match first and ended up overriding in output. --- plugins/OStatus/OStatusPlugin.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'plugins') diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 5feb53b26..7f75b7b2b 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -210,7 +210,7 @@ class OStatusPlugin extends Plugin * */ - function onStartFindMentions($sender, $text, &$mentions) + function onEndFindMentions($sender, $text, &$mentions) { preg_match_all('/(?:^|\s+)@((?:\w+\.)*\w+@(?:\w+\.)*\w+(?:\w+\-\w+)*\.\w+)/', $text, @@ -233,11 +233,21 @@ class OStatusPlugin extends Plugin $this->log(LOG_INFO, "Ostatus_profile found for address '$webfinger'"); + if ($oprofile->isGroup()) { + continue; + } $profile = $oprofile->localProfile(); + $pos = $wmatch[1]; + foreach ($mentions as $i => $other) { + // If we share a common prefix with a local user, override it! + if ($other['position'] == $pos) { + unset($mentions[$i]); + } + } $mentions[] = array('mentioned' => array($profile), 'text' => $wmatch[0], - 'position' => $wmatch[1], + 'position' => $pos, 'url' => $profile->profileurl); } } -- cgit v1.2.3-54-g00ecf From 942521ef3058ee4416d737a144f7e48d9f0f342c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 24 Feb 2010 22:02:43 -0500 Subject: if OStatus post is too long, show the summary and save it as an HTML attachment --- plugins/OStatus/classes/Ostatus_profile.php | 60 +++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'plugins') diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 4f73fd65b..10c2ff87c 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -607,6 +607,32 @@ class Ostatus_profile extends Memcached_DataObject $rendered = $this->purify($activity->object->content); $content = html_entity_decode(strip_tags($rendered)); + $shortened = content_shorten_links($content); + + // If it's too long, try using the summary, and make the + // HTML an attachment. + + $attachment = null; + + if (Notice::contentTooLong($shortened)) { + $attachment = $this->saveHTMLFile($activity->object->title, $rendered); + $summary = $activity->object->summary; + if (empty($summary)) { + $summary = $content; + } + $shortSummary = content_shorten_links($summary); + if (Notice::contentTooLong($shortSummary)) { + $url = common_shorten_url(common_local_url('attachment', + array('attachment' => $attachment->id))); + $shortSummary = substr($shortSummary, + 0, + Notice::maxContent() - (mb_strlen($url) + 2)); + $shortSummary .= '… ' . $url; + $content = $shortSummary; + $rendered = common_render_text($content); + } + } + $options = array('is_local' => Notice::REMOTE_OMB, 'url' => $sourceUrl, 'uri' => $sourceUri, @@ -654,6 +680,9 @@ class Ostatus_profile extends Memcached_DataObject $options); if ($saved) { Ostatus_source::saveNew($saved, $this, $method); + if (!empty($attachment)) { + File_to_post::processNew($attachment->id, $saved->id); + } } } catch (Exception $e) { common_log(LOG_ERR, "OStatus save of remote message $sourceUri failed: " . $e->getMessage()); @@ -1386,4 +1415,35 @@ class Ostatus_profile extends Memcached_DataObject return null; } + + function saveHTMLFile($title, $rendered) + { + $final = sprintf("\n%s". + '
%s
', + htmlspecialchars($title), + $rendered); + + $filename = File::filename($this->localProfile(), + 'ostatus', // ignored? + 'text/html'); + + $filepath = File::path($filename); + + file_put_contents($filepath, $final); + + $file = new File; + + $file->filename = $filename; + $file->url = File::url($filename); + $file->size = filesize($filepath); + $file->date = time(); + $file->mimetype = 'text/html'; + + $file_id = $file->insert(); + + if ($file_id === false) { + common_log_db_error($file, "INSERT", __FILE__); + throw new ServerException(_('Could not store HTML content of long post as file.')); + } + } } -- cgit v1.2.3-54-g00ecf From b08a5271395b92e01a17f7298cad7bb203149a7b Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 24 Feb 2010 22:22:42 -0500 Subject: content_* to common_* --- plugins/OStatus/classes/Ostatus_profile.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'plugins') diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 10c2ff87c..e9c77654d 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -607,7 +607,7 @@ class Ostatus_profile extends Memcached_DataObject $rendered = $this->purify($activity->object->content); $content = html_entity_decode(strip_tags($rendered)); - $shortened = content_shorten_links($content); + $shortened = common_shorten_links($content); // If it's too long, try using the summary, and make the // HTML an attachment. @@ -620,7 +620,7 @@ class Ostatus_profile extends Memcached_DataObject if (empty($summary)) { $summary = $content; } - $shortSummary = content_shorten_links($summary); + $shortSummary = common_shorten_links($summary); if (Notice::contentTooLong($shortSummary)) { $url = common_shorten_url(common_local_url('attachment', array('attachment' => $attachment->id))); -- cgit v1.2.3-54-g00ecf From 374c488cf136b378d4fb47c4a6add309694e9146 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 24 Feb 2010 22:26:40 -0500 Subject: return attachement from saveHTMLFile() --- plugins/OStatus/classes/Ostatus_profile.php | 2 ++ 1 file changed, 2 insertions(+) (limited to 'plugins') diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index e9c77654d..300e38c05 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -1445,5 +1445,7 @@ class Ostatus_profile extends Memcached_DataObject common_log_db_error($file, "INSERT", __FILE__); throw new ServerException(_('Could not store HTML content of long post as file.')); } + + return $file; } } -- cgit v1.2.3-54-g00ecf From 9ef7eb036ce795fafe422096f5e1fb9f70fb05d0 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 25 Feb 2010 10:38:55 +0000 Subject: Moved common icons from Realtime plugin to core icons file --- plugins/Realtime/realtimeupdate.css | 9 --------- theme/default/css/display.css | 15 ++++++++++++++- theme/identica/css/display.css | 17 +++++++++++++++-- 3 files changed, 29 insertions(+), 12 deletions(-) (limited to 'plugins') diff --git a/plugins/Realtime/realtimeupdate.css b/plugins/Realtime/realtimeupdate.css index 31e7c2ae6..f43c97de5 100644 --- a/plugins/Realtime/realtimeupdate.css +++ b/plugins/Realtime/realtimeupdate.css @@ -64,18 +64,9 @@ float: left; } #realtime_play { -background: url(icon_play.gif) no-repeat 47% 47%; margin-left: 4px; } -#realtime_pause { -background: url(icon_pause.gif) no-repeat 47% 47%; -} - -#realtime_popup { -background: url(icon_external.gif) no-repeat 0 30%; -} - #queued_counter { float:left; line-height:1.2; diff --git a/theme/default/css/display.css b/theme/default/css/display.css index deb985909..8ae2b4014 100644 --- a/theme/default/css/display.css +++ b/theme/default/css/display.css @@ -197,7 +197,10 @@ button.minimize, .entity_clear input.submit, .entity_flag input.submit, .entity_flag p, -.entity_subscribe input.submit { +.entity_subscribe input.submit, +#realtime_play, +#realtime_pause, +#realtime_popup { background-image:url(../../base/images/icons/icons-01.gif); background-repeat:no-repeat; background-color:transparent; @@ -363,6 +366,16 @@ background-position: 5px -2171px; .entity_subscribe input.reject { background-position: 5px -2237px; } +#realtime_play { +background-position: 0 -2308px; +} +#realtime_pause { +background-position: 0 -2374px; +} +#realtime_popup { +background-position: 0 -1714px; +} + /* NOTICES */ .notice .attachment { diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css index 0e54d82e2..737e3a103 100644 --- a/theme/identica/css/display.css +++ b/theme/identica/css/display.css @@ -81,7 +81,8 @@ background-color:transparent; input:focus, textarea:focus, select:focus, .form_notice.warning #notice_data-text, .form_notice.warning #notice_text-count, -.form_settings .form_note { +.form_settings .form_note, +.entity_actions .dialogbox .form_data input:focus { border-color:#9BB43E; } input.submit { @@ -197,7 +198,10 @@ button.minimize, .entity_clear input.submit, .entity_flag input.submit, .entity_flag p, -.entity_subscribe input.submit { +.entity_subscribe input.submit, +#realtime_play, +#realtime_pause, +#realtime_popup { background-image:url(../../base/images/icons/icons-01.gif); background-repeat:no-repeat; background-color:transparent; @@ -362,6 +366,15 @@ background-position: 5px -2171px; .entity_subscribe input.reject { background-position: 5px -2237px; } +#realtime_play { +background-position: 0 -2308px; +} +#realtime_pause { +background-position: 0 -2374px; +} +#realtime_popup { +background-position: 0 -1714px; +} /* NOTICES */ .notice .attachment { -- cgit v1.2.3-54-g00ecf From ffdcdbc1985f0df02358efcb252cf9b52ad62cfd Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 25 Feb 2010 13:55:06 +0000 Subject: Removed dangling icons in Realtime plugin --- plugins/Realtime/icon_external.gif | Bin 90 -> 0 bytes plugins/Realtime/icon_pause.gif | Bin 75 -> 0 bytes plugins/Realtime/icon_play.gif | Bin 75 -> 0 bytes 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 plugins/Realtime/icon_external.gif delete mode 100644 plugins/Realtime/icon_pause.gif delete mode 100644 plugins/Realtime/icon_play.gif (limited to 'plugins') diff --git a/plugins/Realtime/icon_external.gif b/plugins/Realtime/icon_external.gif deleted file mode 100644 index c4118d53b..000000000 Binary files a/plugins/Realtime/icon_external.gif and /dev/null differ diff --git a/plugins/Realtime/icon_pause.gif b/plugins/Realtime/icon_pause.gif deleted file mode 100644 index ced0b6440..000000000 Binary files a/plugins/Realtime/icon_pause.gif and /dev/null differ diff --git a/plugins/Realtime/icon_play.gif b/plugins/Realtime/icon_play.gif deleted file mode 100644 index 794ec85b6..000000000 Binary files a/plugins/Realtime/icon_play.gif and /dev/null differ -- cgit v1.2.3-54-g00ecf From 79c0d52daa92b60e8eed80fa9459367c26f97122 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 25 Feb 2010 11:26:33 -0800 Subject: OStatus: save categories from the Atom entry as hashtags. --- classes/Notice.php | 37 +++++++++++++++-- lib/activity.php | 61 ++++++++++++++++++++++++++++- lib/distribqueuehandler.php | 12 ------ plugins/OStatus/classes/Ostatus_profile.php | 14 ++++++- 4 files changed, 106 insertions(+), 18 deletions(-) (limited to 'plugins') diff --git a/classes/Notice.php b/classes/Notice.php index e8d5c45cb..46c5ebb37 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -121,6 +121,9 @@ class Notice extends Memcached_DataObject $result = parent::delete(); } + /** + * Extract #hashtags from this notice's content and save them to the database. + */ function saveTags() { /* extract all #hastags */ @@ -129,14 +132,22 @@ class Notice extends Memcached_DataObject return true; } + /* Add them to the database */ + return $this->saveKnownTags($match[1]); + } + + /** + * Record the given set of hash tags in the db for this notice. + * Given tag strings will be normalized and checked for dupes. + */ + function saveKnownTags($hashtags) + { //turn each into their canonical tag //this is needed to remove dupes before saving e.g. #hash.tag = #hashtag - $hashtags = array(); - for($i=0; $isaveTag($hashtag); @@ -145,6 +156,10 @@ class Notice extends Memcached_DataObject return true; } + /** + * Record a single hash tag as associated with this notice. + * Tag format and uniqueness must be validated by caller. + */ function saveTag($hashtag) { $tag = new Notice_tag(); @@ -194,6 +209,8 @@ class Notice extends Memcached_DataObject * place of extracting @-replies from content. * array 'groups' list of group IDs to deliver to, in place of * extracting ! tags from content + * array 'tags' list of hashtag strings to save with the notice + * in place of extracting # tags from content * @fixme tag override * * @return Notice @@ -343,6 +360,8 @@ class Notice extends Memcached_DataObject $notice->blowOnInsert(); + // Save per-notice metadata... + if (isset($replies)) { $notice->saveKnownReplies($replies); } else { @@ -355,6 +374,16 @@ class Notice extends Memcached_DataObject $notice->saveGroups(); } + if (isset($tags)) { + $notice->saveKnownTags($tags); + } else { + $notice->saveTags(); + } + + // @fixme pass in data for URLs too? + $notice->saveUrls(); + + // Prepare inbox delivery, may be queued to background. $notice->distribute(); return $notice; diff --git a/lib/activity.php b/lib/activity.php index 3de5f62c7..e592aad6f 100644 --- a/lib/activity.php +++ b/lib/activity.php @@ -859,6 +859,7 @@ class Activity public $content; // HTML content of activity public $id; // ID of the activity public $title; // title of the activity + public $categories = array(); // list of AtomCategory objects /** * Turns a regular old Atom into a magical activity @@ -947,6 +948,14 @@ class Activity $this->summary = ActivityUtils::childContent($entry, 'summary'); $this->id = ActivityUtils::childContent($entry, 'id'); $this->content = ActivityUtils::getContent($entry); + + $catEls = $entry->getElementsByTagNameNS(self::ATOM, 'category'); + if ($catEls) { + for ($i = 0; $i < $catEls->length; $i++) { + $catEl = $catEls->item($i); + $this->categories[] = new AtomCategory($catEl); + } + } } /** @@ -1011,6 +1020,10 @@ class Activity $xs->raw($this->target->asString('activity:target')); } + foreach ($this->categories as $cat) { + $xs->raw($cat->asString()); + } + $xs->elementEnd('entry'); return $xs->getString(); @@ -1020,4 +1033,50 @@ class Activity { return ActivityUtils::child($element, $tag, $namespace); } -} \ No newline at end of file +} + +class AtomCategory +{ + public $term; + public $scheme; + public $label; + + function __construct($element=null) + { + if ($element && $element->attributes) { + $this->term = $this->extract($element, 'term'); + $this->scheme = $this->extract($element, 'scheme'); + $this->label = $this->extract($element, 'label'); + } + } + + protected function extract($element, $attrib) + { + $node = $element->attributes->getNamedItemNS(Activity::ATOM, $attrib); + if ($node) { + return trim($node->textContent); + } + $node = $element->attributes->getNamedItem($attrib); + if ($node) { + return trim($node->textContent); + } + return null; + } + + function asString() + { + $attribs = array(); + if ($this->term !== null) { + $attribs['term'] = $this->term; + } + if ($this->scheme !== null) { + $attribs['scheme'] = $this->scheme; + } + if ($this->label !== null) { + $attribs['label'] = $this->label; + } + $xs = new XMLStringer(); + $xs->element('category', $attribs); + return $xs->asString(); + } +} diff --git a/lib/distribqueuehandler.php b/lib/distribqueuehandler.php index dc183fb36..d2be7a92c 100644 --- a/lib/distribqueuehandler.php +++ b/lib/distribqueuehandler.php @@ -62,24 +62,12 @@ class DistribQueueHandler { // XXX: do we need to change this for remote users? - try { - $notice->saveTags(); - } catch (Exception $e) { - $this->logit($notice, $e); - } - try { $notice->addToInboxes(); } catch (Exception $e) { $this->logit($notice, $e); } - try { - $notice->saveUrls(); - } catch (Exception $e) { - $this->logit($notice, $e); - } - try { Event::handle('EndNoticeSave', array($notice)); // Enqueue for other handlers diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 300e38c05..d66939399 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -638,7 +638,9 @@ class Ostatus_profile extends Memcached_DataObject 'uri' => $sourceUri, 'rendered' => $rendered, 'replies' => array(), - 'groups' => array()); + 'groups' => array(), + 'tags' => array()); + // Check for optional attributes... @@ -673,6 +675,16 @@ class Ostatus_profile extends Memcached_DataObject } } + // Atom categories <-> hashtags + foreach ($activity->categories as $cat) { + if ($cat->term) { + $term = common_canonical_tag($cat->term); + if ($term) { + $options['tags'][] = $term; + } + } + } + try { $saved = Notice::saveNew($oprofile->profile_id, $content, -- cgit v1.2.3-54-g00ecf From b5b5184c885e74d9532409a5962f851c4baf41c4 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 25 Feb 2010 13:02:08 -0800 Subject: OStatus: fix remote groups to work with new user_groups/local_groups split. - fix generation so we get the profile info (what's available so far) - use id instead of nickname for group join/leave forms so we can join/leave remote groups while the rest of the groups UI remains limited to local groups (plugins are responsible for making sure remote notifications and permission checks are done) - fix remote notification when joining group through OStatus's remote subscribe form --- actions/joingroup.php | 39 ++++++++++++++++------------- actions/leavegroup.php | 39 ++++++++++++++++------------- classes/User_group.php | 2 +- lib/activity.php | 7 ++++-- lib/joinform.php | 2 +- lib/leaveform.php | 2 +- lib/router.php | 3 +++ plugins/OStatus/actions/ostatussub.php | 14 ++++++++--- plugins/OStatus/classes/Ostatus_profile.php | 26 +++++++++++-------- 9 files changed, 79 insertions(+), 55 deletions(-) (limited to 'plugins') diff --git a/actions/joingroup.php b/actions/joingroup.php index ba642f712..f87e5dae2 100644 --- a/actions/joingroup.php +++ b/actions/joingroup.php @@ -62,30 +62,33 @@ class JoingroupAction extends Action } $nickname_arg = $this->trimmed('nickname'); - $nickname = common_canonical_nickname($nickname_arg); - - // Permanent redirect on non-canonical nickname + $id = intval($this->arg('id')); + if ($id) { + $this->group = User_group::staticGet('id', $id); + } else if ($nickname_arg) { + $nickname = common_canonical_nickname($nickname_arg); + + // Permanent redirect on non-canonical nickname + + if ($nickname_arg != $nickname) { + $args = array('nickname' => $nickname); + common_redirect(common_local_url('leavegroup', $args), 301); + return false; + } - if ($nickname_arg != $nickname) { - $args = array('nickname' => $nickname); - common_redirect(common_local_url('joingroup', $args), 301); - return false; - } + $local = Local_group::staticGet('nickname', $nickname); - if (!$nickname) { - $this->clientError(_('No nickname.'), 404); - return false; - } - - $local = Local_group::staticGet('nickname', $nickname); + if (!$local) { + $this->clientError(_('No such group.'), 404); + return false; + } - if (!$local) { - $this->clientError(_('No such group.'), 404); + $this->group = User_group::staticGet('id', $local->group_id); + } else { + $this->clientError(_('No nickname or ID.'), 404); return false; } - $this->group = User_group::staticGet('id', $local->group_id); - if (!$this->group) { $this->clientError(_('No such group.'), 404); return false; diff --git a/actions/leavegroup.php b/actions/leavegroup.php index 222d4c1b4..329b5aafe 100644 --- a/actions/leavegroup.php +++ b/actions/leavegroup.php @@ -62,30 +62,33 @@ class LeavegroupAction extends Action } $nickname_arg = $this->trimmed('nickname'); - $nickname = common_canonical_nickname($nickname_arg); - - // Permanent redirect on non-canonical nickname + $id = intval($this->arg('id')); + if ($id) { + $this->group = User_group::staticGet('id', $id); + } else if ($nickname_arg) { + $nickname = common_canonical_nickname($nickname_arg); + + // Permanent redirect on non-canonical nickname + + if ($nickname_arg != $nickname) { + $args = array('nickname' => $nickname); + common_redirect(common_local_url('leavegroup', $args), 301); + return false; + } - if ($nickname_arg != $nickname) { - $args = array('nickname' => $nickname); - common_redirect(common_local_url('leavegroup', $args), 301); - return false; - } + $local = Local_group::staticGet('nickname', $nickname); - if (!$nickname) { - $this->clientError(_('No nickname.'), 404); - return false; - } - - $local = Local_group::staticGet('nickname', $nickname); + if (!$local) { + $this->clientError(_('No such group.'), 404); + return false; + } - if (!$local) { - $this->clientError(_('No such group.'), 404); + $this->group = User_group::staticGet('id', $local->group_id); + } else { + $this->clientError(_('No nickname or ID.'), 404); return false; } - $this->group = User_group::staticGet('id', $local->group_id); - if (!$this->group) { $this->clientError(_('No such group.'), 404); return false; diff --git a/classes/User_group.php b/classes/User_group.php index f24bef764..2a58d8895 100644 --- a/classes/User_group.php +++ b/classes/User_group.php @@ -404,7 +404,7 @@ class User_group extends Memcached_DataObject $xs = new XMLStringer(true); $xs->elementStart('activity:subject'); - $xs->element('activity:object', null, 'http://activitystrea.ms/schema/1.0/group'); + $xs->element('activity:object-type', null, 'http://activitystrea.ms/schema/1.0/group'); $xs->element('id', null, $this->permalink()); $xs->element('title', null, $this->getBestName()); $xs->element( diff --git a/lib/activity.php b/lib/activity.php index e592aad6f..4e7ff5336 100644 --- a/lib/activity.php +++ b/lib/activity.php @@ -610,7 +610,10 @@ class ActivityObject $object->id = $profile->getUri(); $object->title = $profile->getBestName(); $object->link = $profile->profileurl; - $object->avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE); + $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE); + if ($avatar) { + $object->avatar = $avatar->displayUrl(); + } if (isset($profile->lat) && isset($profile->lon)) { $object->geopoint = (float)$profile->lat . ' ' . (float)$profile->lon; @@ -664,7 +667,7 @@ class ActivityObject 'rel' => 'avatar', 'href' => empty($this->avatar) ? Avatar::defaultImage(AVATAR_PROFILE_SIZE) - : $this->avatar->displayUrl() + : $this->avatar ), null ); diff --git a/lib/joinform.php b/lib/joinform.php index aefb553aa..aa8bc20e2 100644 --- a/lib/joinform.php +++ b/lib/joinform.php @@ -100,7 +100,7 @@ class JoinForm extends Form function action() { return common_local_url('joingroup', - array('nickname' => $this->group->nickname)); + array('id' => $this->group->id)); } /** diff --git a/lib/leaveform.php b/lib/leaveform.php index e63d96ee8..5469b5704 100644 --- a/lib/leaveform.php +++ b/lib/leaveform.php @@ -100,7 +100,7 @@ class LeaveForm extends Form function action() { return common_local_url('leavegroup', - array('nickname' => $this->group->nickname)); + array('id' => $this->group->id)); } /** diff --git a/lib/router.php b/lib/router.php index 987d0152e..0e15d83b9 100644 --- a/lib/router.php +++ b/lib/router.php @@ -247,6 +247,9 @@ class Router $m->connect('group/:nickname/'.$v, array('action' => $v.'group'), array('nickname' => '[a-zA-Z0-9]+')); + $m->connect('group/:id/id/'.$v, + array('action' => $v.'group'), + array('id' => '[0-9]+')); } foreach (array('members', 'logo', 'rss', 'designsettings') as $n) { diff --git a/plugins/OStatus/actions/ostatussub.php b/plugins/OStatus/actions/ostatussub.php index 12832cdcf..aae22f868 100644 --- a/plugins/OStatus/actions/ostatussub.php +++ b/plugins/OStatus/actions/ostatussub.php @@ -333,10 +333,18 @@ class OStatusSubAction extends Action $group = $this->oprofile->localGroup(); if ($user->isMember($group)) { $this->showForm(_m('Already a member!')); - } elseif (Group_member::join($this->oprofile->group_id, $user->id)) { - $this->successGroup(); + return; + } + if (Event::handle('StartJoinGroup', array($group, $user))) { + $ok = Group_member::join($this->oprofile->group_id, $user->id); + if ($ok) { + Event::handle('EndJoinGroup', array($group, $user)); + $this->successGroup(); + } else { + $this->showForm(_m('Remote group join failed!')); + } } else { - $this->showForm(_m('Remote group join failed!')); + $this->showForm(_m('Remote group join aborted!')); } } else { $local = $this->oprofile->localProfile(); diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index d66939399..f23017077 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -162,7 +162,7 @@ class Ostatus_profile extends Memcached_DataObject 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'gif' => 'image/gif'); - $extension = pathinfo(parse_url($avatarHref, PHP_URL_PATH), PATHINFO_EXTENSION); + $extension = pathinfo(parse_url($object->avatar, PHP_URL_PATH), PATHINFO_EXTENSION); if (isset($map[$extension])) { // @fixme this ain't used/saved yet $object->avatarType = $map[$extension]; @@ -332,6 +332,9 @@ class Ostatus_profile extends Memcached_DataObject */ public function unsubscribe() { $feedsub = FeedSub::staticGet('uri', $this->feeduri); + if (!$feedsub) { + return true; + } if ($feedsub->sub_state == 'active') { return $feedsub->unsubscribe(); } else if ($feedsub->sub_state == '' || $feedsub->sub_state == 'inactive' || $feedsub->sub_state == 'unsubscribe') { @@ -356,7 +359,7 @@ class Ostatus_profile extends Memcached_DataObject $count = $this->localProfile()->subscriberCount(); } if ($count == 0) { - common_log(LOG_INFO, "Unsubscribing from now-unused remote feed $oprofile->feeduri"); + common_log(LOG_INFO, "Unsubscribing from now-unused remote feed $this->feeduri"); $this->unsubscribe(); return true; } else { @@ -1095,8 +1098,8 @@ class Ostatus_profile extends Memcached_DataObject if ($object->type == ActivityObject::PERSON) { $profile = new Profile(); + $profile->created = common_sql_now(); self::updateProfile($profile, $object, $hints); - $profile->created = common_sql_now(); $oprofile->profile_id = $profile->insert(); if (!$oprofile->profile_id) { @@ -1104,6 +1107,7 @@ class Ostatus_profile extends Memcached_DataObject } } else { $group = new User_group(); + $group->uri = $homeuri; $group->created = common_sql_now(); self::updateGroup($group, $object, $hints); @@ -1183,19 +1187,19 @@ class Ostatus_profile extends Memcached_DataObject { $orig = clone($group); - // @fixme need to make nick unique etc *hack hack* $group->nickname = self::getActivityObjectNickname($object, $hints); $group->fullname = $object->title; - // @fixme no canonical profileurl; using homepage instead for now - $group->homepage = $object->id; + if (!empty($object->link)) { + $group->mainpage = $object->link; + } else if (array_key_exists('profileurl', $hints)) { + $group->mainpage = $hints['profileurl']; + } - // @fixme homepage - // @fixme bio - // @fixme tags/categories - // @fixme location? // @todo tags from categories - // @todo lat/lon/location? + $group->description = self::getActivityObjectBio($object, $hints); + $group->location = self::getActivityObjectLocation($object, $hints); + $group->homepage = self::getActivityObjectHomepage($object, $hints); if ($group->id) { common_log(LOG_DEBUG, "Updating OStatus group $group->id from remote info $object->id: " . var_export($object, true) . var_export($hints, true)); -- cgit v1.2.3-54-g00ecf From e62e49ed3be08e30ab5ea6a5a46e1f90d4715182 Mon Sep 17 00:00:00 2001 From: James Walker Date: Thu, 25 Feb 2010 09:39:16 -0500 Subject: adding some exception handling for magicenv parsing --- plugins/OStatus/lib/magicenvelope.php | 2 +- plugins/OStatus/lib/salmon.php | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'plugins') diff --git a/plugins/OStatus/lib/magicenvelope.php b/plugins/OStatus/lib/magicenvelope.php index 81f4609c5..4a9efe93d 100644 --- a/plugins/OStatus/lib/magicenvelope.php +++ b/plugins/OStatus/lib/magicenvelope.php @@ -59,7 +59,7 @@ class MagicEnvelope $signer_uri = $this->normalizeUser($signer_uri); if (!$this->checkAuthor($text, $signer_uri)) { - return false; + throw new Exception("Unable to determine entry author."); } $signature_alg = Magicsig::fromString($this->getKeyPair($signer_uri)); diff --git a/plugins/OStatus/lib/salmon.php b/plugins/OStatus/lib/salmon.php index b5f178cc6..9d4359f74 100644 --- a/plugins/OStatus/lib/salmon.php +++ b/plugins/OStatus/lib/salmon.php @@ -72,8 +72,12 @@ class Salmon // TODO: Should probably be getting the signer uri as an argument? $signer_uri = $magic_env->getAuthor($text); - $env = $magic_env->signMessage($text, 'application/atom+xml', $signer_uri); - + try { + $env = $magic_env->signMessage($text, 'application/atom+xml', $signer_uri); + } catch (Exception $e) { + common_log(LOG_ERR, "Salmon signing failed: ". $e->getMessage()); + return $text; + } return $magic_env->unfold($env); } -- cgit v1.2.3-54-g00ecf From 5cb6e54bedd6aa7dda14bb43fd29d8c119fe6d4c Mon Sep 17 00:00:00 2001 From: James Walker Date: Thu, 25 Feb 2010 14:59:15 -0500 Subject: call-time pass by reference --- plugins/OStatus/OStatusPlugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'plugins') diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 7f75b7b2b..9a543df3b 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -644,7 +644,7 @@ class OStatusPlugin extends Plugin function onStartUserGroupHomeUrl($group, &$url) { - return $this->onStartUserGroupPermalink($group, &$url); + return $this->onStartUserGroupPermalink($group, $url); } function onStartUserGroupPermalink($group, &$url) -- cgit v1.2.3-54-g00ecf From 3d0ba3efc84a78a24d4a3a60472e47aef92546dd Mon Sep 17 00:00:00 2001 From: James Walker Date: Thu, 25 Feb 2010 17:08:50 -0500 Subject: adding a new, more generic "discovery" class that does LRDD disco (rather than webfinger specific) --- plugins/OStatus/lib/discovery.php | 303 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 plugins/OStatus/lib/discovery.php (limited to 'plugins') diff --git a/plugins/OStatus/lib/discovery.php b/plugins/OStatus/lib/discovery.php new file mode 100644 index 000000000..1159f2151 --- /dev/null +++ b/plugins/OStatus/lib/discovery.php @@ -0,0 +1,303 @@ +. + * + * @package StatusNet + * @author James Walker + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ + +/** + * This class implements LRDD-based service discovery based on the "Hammer Draft" + * (including webfinger) + * + * @see http://groups.google.com/group/webfinger/browse_thread/thread/9f3d93a479e91bbf + */ +class Discovery +{ + + const LRDD_REL = 'lrdd'; + const PROFILEPAGE = 'http://webfinger.net/rel/profile-page'; + const UPDATESFROM = 'http://schemas.google.com/g/2010#updates-from'; + + public $methods = array(); + + public function __construct() + { + $this->registerMethod('Discovery_LRDD_Host_Meta'); + $this->registerMethod('Discovery_LRDD_Link_Header'); + $this->registerMethod('Discovery_LRDD_Link_HTML'); + } + + + public function registerMethod($class) + { + $this->methods[] = $class; + } + + /** + * Given a "user id" make sure it's normalized to either a webfinger + * acct: uri or a profile HTTP URL. + */ + public static function normalize($user_id) + { + if (substr($user_id, 0, 5) == 'http:' || + substr($user_id, 0, 6) == 'https:' || + substr($user_id, 0, 5) == 'acct:') { + return $user_id; + } + + if (strpos($user_id, '@') !== FALSE) { + return 'acct:' . $user_id; + } + + return 'http://' . $user_id; + } + + public static function isWebfinger($user_id) + { + $uri = Discovery::normalize($user_id); + + return (substr($uri, 0, 5) == 'acct:'); + } + + /** + * This implements the actual lookup procedure + */ + public function lookup($id) + { + // Normalize the incoming $id to make sure we have a uri + $uri = $this->normalize($id); + + foreach ($this->methods as $class) { + $links = call_user_func(array($class, 'discover'), $uri); + + if ($link = Discovery::getService($links, Discovery::LRDD_REL)) { + // Load the LRDD XRD + if ($link['template']) { + $xrd_uri = Discovery::applyTemplate($link['template'], $uri); + } else { + $xrd_uri = $link['href']; + } + + $xrd = $this->fetchXrd($xrd_uri); + if ($xrd) { + return $xrd; + } + } + } + + throw new Exception('Unable to find services for '. $id); + } + + public static function getService($links, $service) { + foreach ($links as $link) { + if ($link['rel'] == $service) { + return $link; + } + } + } + + + public static function applyTemplate($template, $id) + { + $template = str_replace('{uri}', urlencode($id), $template); + + return $template; + } + + + public static function fetchXrd($url) + { + try { + $client = new HTTPClient(); + $response = $client->get($url); + } catch (HTTP_Request2_Exception $e) { + return false; + } + + if ($response->getStatus() != 200) { + return false; + } + + return XRD::parse($response->getBody()); + } +} + +interface Discovery_LRDD +{ + public function discovery($uri); +} + +class Discovery_LRDD_Host_Meta implements Discovery_LRDD +{ + function discover($uri) + { + if (Discovery::isWebfinger($uri)) { + // We have a webfinger acct: - start with host-meta + list($name, $domain) = explode('@', $id); + } else { + $domain = @parse_url($uri, PHP_URL_HOST); + } + + $url = 'http://'. $domain .'/.well-known/host-meta'; + + $xrd = Discovery::fetchXrd($url); + + if ($xrd) { + if ($xrd->host != $domain) { + return false; + } + + return $xrd->links; + } + } +} + +class Discovery_LRDD_Link_Header implements Discovery_LRDD +{ + public function discover($uri) + { + try { + $client = new HTTPClient(); + $response = $client->get($url); + } catch (HTTP_Request2_Exception $e) { + return false; + } + + if ($response->getStatus() != 200) { + return false; + } + + $link_header = $response->getHeader('Link'); + if (!$link_header) { + return false; + } + + return Discovery_LRDD_Link_Header::parseHeader($header); + } + + protected static function parseHeader($header) + { + preg_match('/^<[^>]+>/', $header, $uri_reference); + if (empty($uri_reference)) return; + + $link_uri = trim($uri_reference[0], '<>'); + $link_rel = array(); + $link_type = null; + + // remove uri-reference from header + $header = substr($header, strlen($uri_reference[0])); + + // parse link-params + $params = explode($header, ';'); + + foreach ($params as $param) { + if (empty($param)) continue; + list($param_name, $param_value) = explode('=', $param, 2); + $param_name = trim($param_name); + $param_value = preg_replace('(^"|"$)', '', trim($param_value)); + + // for now we only care about 'rel' and 'type' link params + // TODO do something with the other links-params + switch ($param_name) { + case 'rel': + $link_rel = trim($param_value); + break; + + case 'type': + $link_type = trim($param_value); + } + } + + return array( + 'href' => $link_uri, + 'rel' => $link_rel, + 'type' => $link_type); + } +} + +class Discovery_LRDD_Link_HTML implements Discovery_LRDD +{ + public function discover($uri) + { + try { + $client = new HTTPClient(); + $response = $client->get($url); + } catch (HTTP_Request2_Exception $e) { + return false; + } + + if ($response->getStatus() != 200) { + return false; + } + + return Discovery_LRDD_Link_HTML::parse($response->getBody()); + } + + + public function parse($html) + { + $links = array(); + + preg_match('/]*)?>(.*?)<\/head>/is', $html, $head_matches); + $head_html = $head_matches[2]; + + preg_match_all('/]*>/i', $head_html, $link_matches); + + foreach ($link_matches[0] as $link_html) { + $link_url = null; + $link_rel = null; + $link_type = null; + + preg_match('/\srel=(("|\')([^\\2]*?)\\2|[^"\'\s]+)/i', $link_html, $rel_matches); + if ( isset($rel_matches[3]) ) { + $link_rel = $rel_matches[3]; + } else if ( isset($rel_matches[1]) ) { + $link_rel = $rel_matches[1]; + } + + preg_match('/\shref=(("|\')([^\\2]*?)\\2|[^"\'\s]+)/i', $link_html, $href_matches); + if ( isset($href_matches[3]) ) { + $link_uri = $href_matches[3]; + } else if ( isset($href_matches[1]) ) { + $link_uri = $href_matches[1]; + } + + preg_match('/\stype=(("|\')([^\\2]*?)\\2|[^"\'\s]+)/i', $link_html, $type_matches); + if ( isset($type_matches[3]) ) { + $link_type = $type_matches[3]; + } else if ( isset($type_matches[1]) ) { + $link_type = $type_matches[1]; + } + + $links[] = array( + 'href' => $link_url, + 'rel' => $link_rel, + 'type' => $link_type, + ); + } + + return $links; + } +} -- cgit v1.2.3-54-g00ecf From b2dabe6a48392cc65ec691ab5a52696994233dd5 Mon Sep 17 00:00:00 2001 From: James Walker Date: Thu, 25 Feb 2010 17:12:46 -0500 Subject: removing the webfinger lib --- plugins/OStatus/lib/webfinger.php | 151 -------------------------------------- 1 file changed, 151 deletions(-) delete mode 100644 plugins/OStatus/lib/webfinger.php (limited to 'plugins') diff --git a/plugins/OStatus/lib/webfinger.php b/plugins/OStatus/lib/webfinger.php deleted file mode 100644 index 8a5037629..000000000 --- a/plugins/OStatus/lib/webfinger.php +++ /dev/null @@ -1,151 +0,0 @@ -. - * - * @package StatusNet - * @author James Walker - * @copyright 2010 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 - * @link http://status.net/ - */ - -define('WEBFINGER_SERVICE_REL_VALUE', 'lrdd'); - -/** - * Implement the webfinger protocol. - */ - -class Webfinger -{ - const PROFILEPAGE = 'http://webfinger.net/rel/profile-page'; - const UPDATESFROM = 'http://schemas.google.com/g/2010#updates-from'; - - /** - * Perform a webfinger lookup given an account. - */ - - public function lookup($id) - { - $id = $this->normalize($id); - list($name, $domain) = explode('@', $id); - - $links = $this->getServiceLinks($domain); - if (!$links) { - return false; - } - - $services = array(); - foreach ($links as $link) { - if ($link['template']) { - return $this->getServiceDescription($link['template'], $id); - } - if ($link['href']) { - return $this->getServiceDescription($link['href'], $id); - } - } - } - - /** - * Normalize an account ID - */ - function normalize($id) - { - if (substr($id, 0, 7) == 'acct://') { - return substr($id, 7); - } else if (substr($id, 0, 5) == 'acct:') { - return substr($id, 5); - } - - return $id; - } - - function getServiceLinks($domain) - { - $url = 'http://'. $domain .'/.well-known/host-meta'; - $content = $this->fetchURL($url); - if (empty($content)) { - common_log(LOG_DEBUG, 'Error fetching host-meta'); - return false; - } - $result = XRD::parse($content); - - // Ensure that the host == domain (spec may include signing later) - if ($result->host != $domain) { - return false; - } - - $links = array(); - foreach ($result->links as $link) { - if ($link['rel'] == WEBFINGER_SERVICE_REL_VALUE) { - $links[] = $link; - } - - } - return $links; - } - - function getServiceDescription($template, $id) - { - $url = $this->applyTemplate($template, 'acct:' . $id); - - $content = $this->fetchURL($url); - - if (!$content) { - return false; - } - - return XRD::parse($content); - } - - function fetchURL($url) - { - try { - $client = new HTTPClient(); - $response = $client->get($url); - } catch (HTTP_Request2_Exception $e) { - return false; - } - - if ($response->getStatus() != 200) { - return false; - } - - return $response->getBody(); - } - - function applyTemplate($template, $id) - { - $template = str_replace('{uri}', urlencode($id), $template); - - return $template; - } - - function getHostMeta($domain, $template) { - $xrd = new XRD(); - $xrd->host = $domain; - $xrd->links[] = array('rel' => 'lrdd', - 'template' => $template, - 'title' => array('Resource Descriptor')); - - return $xrd->toXML(); - } -} - -- cgit v1.2.3-54-g00ecf From bd90ef9f66ce281c4ef9af724d574a5ead156310 Mon Sep 17 00:00:00 2001 From: James Walker Date: Thu, 25 Feb 2010 17:26:10 -0500 Subject: replace webfinger usage in hostmeta.php --- plugins/OStatus/actions/hostmeta.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'plugins') diff --git a/plugins/OStatus/actions/hostmeta.php b/plugins/OStatus/actions/hostmeta.php index 850b8a0fe..85715ecf4 100644 --- a/plugins/OStatus/actions/hostmeta.php +++ b/plugins/OStatus/actions/hostmeta.php @@ -31,12 +31,18 @@ class HostMetaAction extends Action { parent::handle(); - $w = new Webfinger(); - - $domain = common_config('site', 'server'); $url = common_local_url('webfinger'); $url.= '?uri={uri}'; - print $w->getHostMeta($domain, $url); + + $xrd = new XRD(); + + $xrd = new XRD(); + $xrd->host = $domain; + $xrd->links[] = array('rel' => Discovery::LRDD_REL, + 'template' => $url, + 'title' => array('Resource Descriptor')); + + print $xrd->toXML(); } } -- cgit v1.2.3-54-g00ecf From 5ae64a7adbe7631be918f25eeda383f77b42b758 Mon Sep 17 00:00:00 2001 From: James Walker Date: Thu, 25 Feb 2010 17:34:56 -0500 Subject: moving references to Webfinger to Discovery --- plugins/OStatus/actions/ostatusinit.php | 4 ++-- plugins/OStatus/actions/webfinger.php | 6 +++--- plugins/OStatus/classes/Ostatus_profile.php | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'plugins') diff --git a/plugins/OStatus/actions/ostatusinit.php b/plugins/OStatus/actions/ostatusinit.php index 3f2f6368f..5c8575595 100644 --- a/plugins/OStatus/actions/ostatusinit.php +++ b/plugins/OStatus/actions/ostatusinit.php @@ -131,9 +131,9 @@ class OStatusInitAction extends Action function connectWebfinger($acct) { - $w = new Webfinger; + $disco = new Discovery; - $result = $w->lookup($acct); + $result = $disco->lookup($acct); if (!$result) { $this->clientError(_m("Couldn't look up OStatus account profile.")); } diff --git a/plugins/OStatus/actions/webfinger.php b/plugins/OStatus/actions/webfinger.php index 34336a903..fa41b2444 100644 --- a/plugins/OStatus/actions/webfinger.php +++ b/plugins/OStatus/actions/webfinger.php @@ -40,7 +40,7 @@ class WebfingerAction extends Action function handle() { - $acct = Webfinger::normalize($this->uri); + $acct = Discovery::normalize($this->uri); $xrd = new XRD(); @@ -55,11 +55,11 @@ class WebfingerAction extends Action $xrd->subject = $this->uri; $xrd->alias[] = common_profile_url($nick); - $xrd->links[] = array('rel' => Webfinger::PROFILEPAGE, + $xrd->links[] = array('rel' => Discovery::PROFILEPAGE, 'type' => 'text/html', 'href' => common_profile_url($nick)); - $xrd->links[] = array('rel' => Webfinger::UPDATESFROM, + $xrd->links[] = array('rel' => Discovery::UPDATESFROM, 'href' => common_local_url('ApiTimelineUser', array('id' => $this->user->id, 'format' => 'atom')), diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index f23017077..0fec8fc43 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -1328,9 +1328,9 @@ class Ostatus_profile extends Memcached_DataObject // Now, try some discovery - $wf = new Webfinger(); + $disco = new Discovery(); - $result = $wf->lookup($addr); + $result = $disco->lookup($addr); if (!$result) { return null; @@ -1338,13 +1338,13 @@ class Ostatus_profile extends Memcached_DataObject foreach ($result->links as $link) { switch ($link['rel']) { - case Webfinger::PROFILEPAGE: + case Discovery::PROFILEPAGE: $profileUrl = $link['href']; break; case 'salmon': $salmonEndpoint = $link['href']; break; - case Webfinger::UPDATESFROM: + case Discovery::UPDATESFROM: $feedUrl = $link['href']; break; default: -- cgit v1.2.3-54-g00ecf From 93f4f07c122613c0afd2257bd9e898629124178a Mon Sep 17 00:00:00 2001 From: James Walker Date: Thu, 25 Feb 2010 17:52:18 -0500 Subject: moving webfinger action to xrdaction --- plugins/OStatus/OStatusPlugin.php | 4 +- plugins/OStatus/actions/hostmeta.php | 2 +- plugins/OStatus/actions/webfinger.php | 109 ---------------------------------- plugins/OStatus/actions/xrd.php | 109 ++++++++++++++++++++++++++++++++++ 4 files changed, 112 insertions(+), 112 deletions(-) delete mode 100644 plugins/OStatus/actions/webfinger.php create mode 100644 plugins/OStatus/actions/xrd.php (limited to 'plugins') diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 9a543df3b..91d055498 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -43,8 +43,8 @@ class OStatusPlugin extends Plugin // Discovery actions $m->connect('.well-known/host-meta', array('action' => 'hostmeta')); - $m->connect('main/webfinger', - array('action' => 'webfinger')); + $m->connect('main/xrd', + array('action' => 'xrd')); $m->connect('main/ostatus', array('action' => 'ostatusinit')); $m->connect('main/ostatus?nickname=:nickname', diff --git a/plugins/OStatus/actions/hostmeta.php b/plugins/OStatus/actions/hostmeta.php index 85715ecf4..3d00b98ae 100644 --- a/plugins/OStatus/actions/hostmeta.php +++ b/plugins/OStatus/actions/hostmeta.php @@ -32,7 +32,7 @@ class HostMetaAction extends Action parent::handle(); $domain = common_config('site', 'server'); - $url = common_local_url('webfinger'); + $url = common_local_url('xrd'); $url.= '?uri={uri}'; $xrd = new XRD(); diff --git a/plugins/OStatus/actions/webfinger.php b/plugins/OStatus/actions/webfinger.php deleted file mode 100644 index fa41b2444..000000000 --- a/plugins/OStatus/actions/webfinger.php +++ /dev/null @@ -1,109 +0,0 @@ -. - */ - -/** - * @package OStatusPlugin - * @maintainer James Walker - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } - -class WebfingerAction extends Action -{ - - public $uri; - - function prepare($args) - { - parent::prepare($args); - - $this->uri = $this->trimmed('uri'); - - return true; - } - - function handle() - { - $acct = Discovery::normalize($this->uri); - - $xrd = new XRD(); - - list($nick, $domain) = explode('@', urldecode($acct)); - $nick = common_canonical_nickname($nick); - - $this->user = User::staticGet('nickname', $nick); - if (!$this->user) { - $this->clientError(_('No such user.'), 404); - return false; - } - - $xrd->subject = $this->uri; - $xrd->alias[] = common_profile_url($nick); - $xrd->links[] = array('rel' => Discovery::PROFILEPAGE, - 'type' => 'text/html', - 'href' => common_profile_url($nick)); - - $xrd->links[] = array('rel' => Discovery::UPDATESFROM, - 'href' => common_local_url('ApiTimelineUser', - array('id' => $this->user->id, - 'format' => 'atom')), - 'type' => 'application/atom+xml'); - - // hCard - $xrd->links[] = array('rel' => 'http://microformats.org/profile/hcard', - 'type' => 'text/html', - 'href' => common_profile_url($nick)); - - // XFN - $xrd->links[] = array('rel' => 'http://gmpg.org/xfn/11', - 'type' => 'text/html', - 'href' => common_profile_url($nick)); - // FOAF - $xrd->links[] = array('rel' => 'describedby', - 'type' => 'application/rdf+xml', - 'href' => common_local_url('foaf', - array('nickname' => $nick))); - - $salmon_url = common_local_url('salmon', - array('id' => $this->user->id)); - - $xrd->links[] = array('rel' => 'salmon', - 'href' => $salmon_url); - - // Get this user's keypair - $magickey = Magicsig::staticGet('user_id', $this->user->id); - if (!$magickey) { - // No keypair yet, let's generate one. - $magickey = new Magicsig(); - $magickey->generate(); - } - - $xrd->links[] = array('rel' => Magicsig::PUBLICKEYREL, - 'href' => 'data:application/magic-public-key;'. $magickey->keypair); - - // TODO - finalize where the redirect should go on the publisher - $url = common_local_url('ostatussub') . '?profile={uri}'; - $xrd->links[] = array('rel' => 'http://ostatus.org/schema/1.0/subscribe', - 'template' => $url ); - - header('Content-type: text/xml'); - print $xrd->toXML(); - } - -} diff --git a/plugins/OStatus/actions/xrd.php b/plugins/OStatus/actions/xrd.php new file mode 100644 index 000000000..cc5c70b08 --- /dev/null +++ b/plugins/OStatus/actions/xrd.php @@ -0,0 +1,109 @@ +. + */ + +/** + * @package OStatusPlugin + * @maintainer James Walker + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } + +class XrdAction extends Action +{ + + public $uri; + + function prepare($args) + { + parent::prepare($args); + + $this->uri = $this->trimmed('uri'); + + return true; + } + + function handle() + { + $acct = Discovery::normalize($this->uri); + + $xrd = new XRD(); + + list($nick, $domain) = explode('@', substr(urldecode($acct), 5)); + $nick = common_canonical_nickname($nick); + + $this->user = User::staticGet('nickname', $nick); + if (!$this->user) { + $this->clientError(_('No such user.'), 404); + return false; + } + + $xrd->subject = $this->uri; + $xrd->alias[] = common_profile_url($nick); + $xrd->links[] = array('rel' => Discovery::PROFILEPAGE, + 'type' => 'text/html', + 'href' => common_profile_url($nick)); + + $xrd->links[] = array('rel' => Discovery::UPDATESFROM, + 'href' => common_local_url('ApiTimelineUser', + array('id' => $this->user->id, + 'format' => 'atom')), + 'type' => 'application/atom+xml'); + + // hCard + $xrd->links[] = array('rel' => 'http://microformats.org/profile/hcard', + 'type' => 'text/html', + 'href' => common_profile_url($nick)); + + // XFN + $xrd->links[] = array('rel' => 'http://gmpg.org/xfn/11', + 'type' => 'text/html', + 'href' => common_profile_url($nick)); + // FOAF + $xrd->links[] = array('rel' => 'describedby', + 'type' => 'application/rdf+xml', + 'href' => common_local_url('foaf', + array('nickname' => $nick))); + + $salmon_url = common_local_url('salmon', + array('id' => $this->user->id)); + + $xrd->links[] = array('rel' => 'salmon', + 'href' => $salmon_url); + + // Get this user's keypair + $magickey = Magicsig::staticGet('user_id', $this->user->id); + if (!$magickey) { + // No keypair yet, let's generate one. + $magickey = new Magicsig(); + $magickey->generate($this->user->id); + } + + $xrd->links[] = array('rel' => Magicsig::PUBLICKEYREL, + 'href' => 'data:application/magic-public-key;'. $magickey->keypair); + + // TODO - finalize where the redirect should go on the publisher + $url = common_local_url('ostatussub') . '?profile={uri}'; + $xrd->links[] = array('rel' => 'http://ostatus.org/schema/1.0/subscribe', + 'template' => $url ); + + header('Content-type: text/xml'); + print $xrd->toXML(); + } + +} -- cgit v1.2.3-54-g00ecf From 08413428a7f4613649be3d80fd393a12e33ffbc8 Mon Sep 17 00:00:00 2001 From: James Walker Date: Thu, 25 Feb 2010 17:52:56 -0500 Subject: typo --- plugins/OStatus/lib/discovery.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'plugins') diff --git a/plugins/OStatus/lib/discovery.php b/plugins/OStatus/lib/discovery.php index 1159f2151..8aba31328 100644 --- a/plugins/OStatus/lib/discovery.php +++ b/plugins/OStatus/lib/discovery.php @@ -146,12 +146,12 @@ class Discovery interface Discovery_LRDD { - public function discovery($uri); + public function discover($uri); } class Discovery_LRDD_Host_Meta implements Discovery_LRDD { - function discover($uri) + public function discover($uri) { if (Discovery::isWebfinger($uri)) { // We have a webfinger acct: - start with host-meta -- cgit v1.2.3-54-g00ecf From 6578e0e1afed8e8738bbcb31d200927e10074f11 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 25 Feb 2010 18:45:08 -0500 Subject: use new dedicated hcard method for Webfinger profile --- plugins/OStatus/actions/webfinger.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'plugins') diff --git a/plugins/OStatus/actions/webfinger.php b/plugins/OStatus/actions/webfinger.php index 34336a903..d3671962b 100644 --- a/plugins/OStatus/actions/webfinger.php +++ b/plugins/OStatus/actions/webfinger.php @@ -68,7 +68,7 @@ class WebfingerAction extends Action // hCard $xrd->links[] = array('rel' => 'http://microformats.org/profile/hcard', 'type' => 'text/html', - 'href' => common_profile_url($nick)); + 'href' => common_local_url('hcard', array('nickname' => $nick))); // XFN $xrd->links[] = array('rel' => 'http://gmpg.org/xfn/11', @@ -78,8 +78,8 @@ class WebfingerAction extends Action $xrd->links[] = array('rel' => 'describedby', 'type' => 'application/rdf+xml', 'href' => common_local_url('foaf', - array('nickname' => $nick))); - + array('nickname' => $nick))); + $salmon_url = common_local_url('salmon', array('id' => $this->user->id)); @@ -93,10 +93,10 @@ class WebfingerAction extends Action $magickey = new Magicsig(); $magickey->generate(); } - + $xrd->links[] = array('rel' => Magicsig::PUBLICKEYREL, 'href' => 'data:application/magic-public-key;'. $magickey->keypair); - + // TODO - finalize where the redirect should go on the publisher $url = common_local_url('ostatussub') . '?profile={uri}'; $xrd->links[] = array('rel' => 'http://ostatus.org/schema/1.0/subscribe', -- cgit v1.2.3-54-g00ecf From 45435a7c033d9c5acf0352bc44408667c5690198 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 26 Feb 2010 00:01:22 +0000 Subject: OStatus: if no available and no profileurl hint passed in, use object id if it's an HTTP(S) URL. Fixes profile link for Google accounts. --- plugins/OStatus/classes/Ostatus_profile.php | 2 ++ 1 file changed, 2 insertions(+) (limited to 'plugins') diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index f23017077..86a3c9354 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -1160,6 +1160,8 @@ class Ostatus_profile extends Memcached_DataObject $profile->profileurl = $object->link; } else if (array_key_exists('profileurl', $hints)) { $profile->profileurl = $hints['profileurl']; + } else if (Validate::uri($object->id, array('allowed_schemes' => array('http', 'https')))) { + $profile->profileurl = $object->id; } $profile->bio = self::getActivityObjectBio($object, $hints); -- cgit v1.2.3-54-g00ecf From 7922edb5b6c4ad55a1b81fa16c93e5656b676b26 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 25 Feb 2010 16:06:49 -0800 Subject: Add lots of fun avatars to our Atom output --- classes/Notice.php | 1 + lib/activity.php | 146 ++++++++++++++++++++++------ lib/atomnoticefeed.php | 5 + plugins/OStatus/classes/Ostatus_profile.php | 3 +- 4 files changed, 124 insertions(+), 31 deletions(-) (limited to 'plugins') diff --git a/classes/Notice.php b/classes/Notice.php index 46c5ebb37..ac4640534 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1096,6 +1096,7 @@ class Notice extends Memcached_DataObject 'xmlns:thr' => 'http://purl.org/syndication/thread/1.0', 'xmlns:georss' => 'http://www.georss.org/georss', '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'); } else { diff --git a/lib/activity.php b/lib/activity.php index 30cdc5a56..0f30e8bf5 100644 --- a/lib/activity.php +++ b/lib/activity.php @@ -465,6 +465,57 @@ class ActivityUtils } } +// XXX: Arg! This wouldn't be necessary if we used Avatars conistently +class AvatarLink +{ + public $url; + public $type; + public $size; + public $width; + + static function fromAvatar($avatar) + { + if (empty($avatar)) { + return null; + } + $alink = new AvatarLink(); + $alink->type = $avatar->mediatype; + $alink->height = $avatar->mediatype; + $alink->width = $avatar->width; + $alink->url = $avatar->displayUrl(); + return $alink; + } + + static function fromFilename($filename, $size) + { + $alink = new AvatarLink(); + $alink->url = $filename; + $alink->height = $size; + if (!empty($filename)) { + $alink->width = $size; + $alink->type = self::mediatype($filename); + } else { + $alink->url = User_group::defaultLogo($size); + $alink->type = 'image/png'; + } + return $alink; + } + + // yuck! + static function mediatype($filename) { + $ext = strtolower(end(explode('.', $filename))); + if ($ext == 'jpeg') { + $ext = 'jpg'; + } + // hope we don't support any others + $types = array('png', 'gif', 'jpg', 'jpeg'); + if (in_array($ext, $types)) { + return 'image/' . $ext; + } + return null; + } +} + /** * A noun-ish thing in the activity universe * @@ -521,7 +572,7 @@ class ActivityObject public $content; public $link; public $source; - public $avatar; + public $avatarLinks = array(); public $geopoint; public $poco; public $displayName; @@ -641,13 +692,40 @@ class ActivityObject $object->id = $profile->getUri(); $object->title = $profile->getBestName(); $object->link = $profile->profileurl; - $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE); - if ($avatar) { - $object->avatar = $avatar->displayUrl(); + + $orig = $profile->getOriginalAvatar(); + + if (!empty($orig)) { + $object->avatarLinks[] = AvatarLink::fromAvatar($orig); + } + + $sizes = array( + AVATAR_PROFILE_SIZE, + AVATAR_STREAM_SIZE, + AVATAR_MINI_SIZE + ); + + foreach ($sizes as $size) { + + $alink = null; + $avatar = $profile->getAvatar($size); + + if (!empty($avatar)) { + $alink = AvatarLink::fromAvatar($avatar); + } else { + $alink = new AvatarLink(); + $alink->type = 'image/png'; + $alink->height = $size; + $alink->width = $size; + $alink->url = Avatar::defaultImage($size); + } + + $object->avatarLinks[] = $alink; } if (isset($profile->lat) && isset($profile->lon)) { - $object->geopoint = (float)$profile->lat . ' ' . (float)$profile->lon; + $object->geopoint = (float)$profile->lat + . ' ' . (float)$profile->lon; } $object->poco = PoCo::fromProfile($profile); @@ -663,13 +741,28 @@ class ActivityObject $object->id = $group->getUri(); $object->title = $group->getBestName(); $object->link = $group->getUri(); - $object->avatar = $group->getAvatar(); + + $object->avatarLinks[] = AvatarLink::fromFilename( + $group->homepage_logo, + AVATAR_PROFILE_SIZE + ); + + $object->avatarLinks[] = AvatarLink::fromFilename( + $group->stream_logo, + AVATAR_STREAM_SIZE + ); + + $object->avatarLinks[] = AvatarLink::fromFilename( + $group->mini_logo, + AVATAR_MINI_SIZE + ); $object->poco = PoCo::fromGroup($group); return $object; } + function asString($tag='activity:object') { $xs = new XMLStringer(true); @@ -705,29 +798,21 @@ class ActivityObject ); } - if ($this->type == ActivityObject::PERSON) { - $xs->element( - 'link', array( - 'type' => empty($this->avatar) ? 'image/png' : $this->avatar->mediatype, - 'rel' => 'avatar', - 'href' => empty($this->avatar) - ? Avatar::defaultImage(AVATAR_PROFILE_SIZE) - : $this->avatar - ), - null - ); - } - - // XXX: Gotta figure out mime-type! Gar. - - if ($this->type == ActivityObject::GROUP) { - $xs->element( - 'link', array( - 'rel' => 'avatar', - 'href' => $this->avatar - ), - null - ); + if ($this->type == ActivityObject::PERSON + || $this->type == ActivityObject::GROUP) { + + foreach ($this->avatarLinks as $avatar) { + $xs->element( + 'link', array( + 'rel' => 'avatar', + 'type' => $avatar->type, + 'media:width' => $avatar->width, + 'media:height' => $avatar->height, + 'href' => $avatar->url + ), + null + ); + } } if (!empty($this->geopoint)) { @@ -1038,7 +1123,8 @@ class Activity 'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/', 'xmlns:georss' => 'http://www.georss.org/georss', 'xmlns:ostatus' => 'http://ostatus.org/schema/1.0', - 'xmlns:poco' => 'http://portablecontacts.net/spec/1.0'); + 'xmlns:poco' => 'http://portablecontacts.net/spec/1.0', + 'xmlns:media' => 'http://purl.org/syndication/atommedia'); } else { $attrs = array(); } diff --git a/lib/atomnoticefeed.php b/lib/atomnoticefeed.php index d2bf2a416..3c3556cb9 100644 --- a/lib/atomnoticefeed.php +++ b/lib/atomnoticefeed.php @@ -64,6 +64,11 @@ class AtomNoticeFeed extends Atom10Feed 'http://activitystrea.ms/spec/1.0/' ); + $this->addNamespace( + 'media', + 'http://purl.org/syndication/atommedia' + ); + $this->addNamespace( 'poco', 'http://portablecontacts.net/spec/1.0' diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index f23017077..7026d82f2 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -401,7 +401,8 @@ class Ostatus_profile extends Memcached_DataObject 'xmlns:thr' => 'http://purl.org/syndication/thread/1.0', 'xmlns:georss' => 'http://www.georss.org/georss', 'xmlns:ostatus' => 'http://ostatus.org/schema/1.0', - 'xmlns:poco' => 'http://portablecontacts.net/spec/1.0'); + 'xmlns:poco' => 'http://portablecontacts.net/spec/1.0', + 'xmlns:media' => 'http://purl.org/syndication/atommedia'); $entry = new XMLStringer(); $entry->elementStart('entry', $attributes); -- cgit v1.2.3-54-g00ecf From 36f02f459b27a81e7017e3bb60b201677fd15a30 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 25 Feb 2010 19:11:39 -0500 Subject: add hkit for hCard parsing --- plugins/OStatus/extlib/hkit/hcard.profile.php | 105 ++++++ plugins/OStatus/extlib/hkit/hkit.class.php | 475 ++++++++++++++++++++++++++ 2 files changed, 580 insertions(+) create mode 100644 plugins/OStatus/extlib/hkit/hcard.profile.php create mode 100644 plugins/OStatus/extlib/hkit/hkit.class.php (limited to 'plugins') diff --git a/plugins/OStatus/extlib/hkit/hcard.profile.php b/plugins/OStatus/extlib/hkit/hcard.profile.php new file mode 100644 index 000000000..6ec0dc890 --- /dev/null +++ b/plugins/OStatus/extlib/hkit/hcard.profile.php @@ -0,0 +1,105 @@ +root_class = 'vcard'; + + $this->classes = array( + 'fn', array('honorific-prefix', 'given-name', 'additional-name', 'family-name', 'honorific-suffix'), + 'n', array('honorific-prefix', 'given-name', 'additional-name', 'family-name', 'honorific-suffix'), + 'adr', array('post-office-box', 'extended-address', 'street-address', 'postal-code', 'country-name', 'type', 'region', 'locality'), + 'label', 'bday', 'agent', 'nickname', 'photo', 'class', + 'email', array('type', 'value'), + 'category', 'key', 'logo', 'mailer', 'note', + 'org', array('organization-name', 'organization-unit'), + 'tel', array('type', 'value'), + 'geo', array('latitude', 'longitude'), + 'tz', 'uid', 'url', 'rev', 'role', 'sort-string', 'sound', 'title' + ); + + // classes that must only appear once per card + $this->singles = array( + 'fn' + ); + + // classes that are required (not strictly enforced - give at least one!) + $this->required = array( + 'fn' + ); + + $this->att_map = array( + 'fn' => array('IMG|alt'), + 'url' => array('A|href', 'IMG|src', 'AREA|href'), + 'photo' => array('IMG|src'), + 'bday' => array('ABBR|title'), + 'logo' => array('IMG|src'), + 'email' => array('A|href'), + 'geo' => array('ABBR|title') + ); + + + $this->callbacks = array( + 'url' => array($this, 'resolvePath'), + 'photo' => array($this, 'resolvePath'), + 'logo' => array($this, 'resolvePath'), + 'email' => array($this, 'resolveEmail') + ); + + + + function hKit_hcard_post($a) + { + + foreach ($a as &$vcard){ + + hKit_implied_n_optimization($vcard); + hKit_implied_n_from_fn($vcard); + + } + + return $a; + + } + + + function hKit_implied_n_optimization(&$vcard) + { + if (array_key_exists('fn', $vcard) && !is_array($vcard['fn']) && + !array_key_exists('n', $vcard) && (!array_key_exists('org', $vcard) || $vcard['fn'] != $vcard['org'])){ + + if (sizeof(explode(' ', $vcard['fn'])) == 2){ + $patterns = array(); + $patterns[] = array('/^(\S+),\s*(\S{1})$/', 2, 1); // Lastname, Initial + $patterns[] = array('/^(\S+)\s*(\S{1})\.*$/', 2, 1); // Lastname Initial(.) + $patterns[] = array('/^(\S+),\s*(\S+)$/', 2, 1); // Lastname, Firstname + $patterns[] = array('/^(\S+)\s*(\S+)$/', 1, 2); // Firstname Lastname + + foreach ($patterns as $pattern){ + if (preg_match($pattern[0], $vcard['fn'], $matches) === 1){ + $n = array(); + $n['given-name'] = $matches[$pattern[1]]; + $n['family-name'] = $matches[$pattern[2]]; + $vcard['n'] = $n; + + + break; + } + } + } + } + } + + + function hKit_implied_n_from_fn(&$vcard) + { + if (array_key_exists('fn', $vcard) && is_array($vcard['fn']) + && !array_key_exists('n', $vcard) && (!array_key_exists('org', $vcard) || $vcard['fn'] != $vcard['org'])){ + + $vcard['n'] = $vcard['fn']; + } + + if (array_key_exists('fn', $vcard) && is_array($vcard['fn'])){ + $vcard['fn'] = $vcard['fn']['text']; + } + } + +?> \ No newline at end of file diff --git a/plugins/OStatus/extlib/hkit/hkit.class.php b/plugins/OStatus/extlib/hkit/hkit.class.php new file mode 100644 index 000000000..c3a54cff6 --- /dev/null +++ b/plugins/OStatus/extlib/hkit/hkit.class.php @@ -0,0 +1,475 @@ +' . implode(', ', $missing) . ''); + + } + + + public function getByURL($profile='', $url='') + { + + if ($profile=='' || $url == '') return false; + + $this->loadProfile($profile); + + $source = $this->loadURL($url); + + if ($source){ + $tidy_xhtml = $this->tidyThis($source); + + $fragment = false; + + if (strrchr($url, '#')) + $fragment = array_pop(explode('#', $url)); + + $doc = $this->loadDoc($tidy_xhtml, $fragment); + $s = $this->processNodes($doc, $this->classes); + $s = $this->postProcess($profile, $s); + + return $s; + }else{ + return false; + } + } + + public function getByString($profile='', $input_xml='') + { + if ($profile=='' || $input_xml == '') return false; + + $this->loadProfile($profile); + + $doc = $this->loadDoc($input_xml); + $s = $this->processNodes($doc, $this->classes); + $s = $this->postProcess($profile, $s); + + return $s; + + } + + private function processNodes($items, $classes, $allow_includes=true){ + + $out = array(); + + foreach($items as $item){ + $data = array(); + + for ($i=0; $ixpath($xpath); + + if ($results){ + foreach ($results as $result){ + if (isset($classes[$i+1]) && is_array($classes[$i+1])){ + $nodes = $this->processNodes($results, $classes[$i+1]); + if (sizeof($nodes) > 0){ + $nodes = array_merge(array('text'=>$this->getNodeValue($result, $classes[$i])), $nodes); + $data[$classes[$i]] = $nodes; + }else{ + $data[$classes[$i]] = $this->getNodeValue($result, $classes[$i]); + } + + }else{ + if (isset($data[$classes[$i]])){ + if (is_array($data[$classes[$i]])){ + // is already an array - append + $data[$classes[$i]][] = $this->getNodeValue($result, $classes[$i]); + + }else{ + // make it an array + if ($classes[$i] == 'value'){ // unless it's the 'value' of a type/value pattern + $data[$classes[$i]] .= $this->getNodeValue($result, $classes[$i]); + }else{ + $old_val = $data[$classes[$i]]; + $data[$classes[$i]] = array($old_val, $this->getNodeValue($result, $classes[$i])); + $old_val = false; + } + } + }else{ + // set as normal value + $data[$classes[$i]] = $this->getNodeValue($result, $classes[$i]); + + } + } + + // td@headers pattern + if (strtoupper(dom_import_simplexml($result)->tagName)== "TD" && $result['headers']){ + $include_ids = explode(' ', $result['headers']); + $doc = $this->doc; + foreach ($include_ids as $id){ + $xpath = "//*[@id='$id']/.."; + $includes = $doc->xpath($xpath); + foreach ($includes as $include){ + $tmp = $this->processNodes($include, $this->classes); + if (is_array($tmp)) $data = array_merge($data, $tmp); + } + } + } + } + } + } + $result = false; + } + + // include-pattern + if ($allow_includes){ + $xpath = ".//*[contains(concat(' ',normalize-space(@class),' '),' include ')]"; + $results = $item->xpath($xpath); + + if ($results){ + foreach ($results as $result){ + $tagName = strtoupper(dom_import_simplexml($result)->tagName); + if ((($tagName == "OBJECT" && $result['data']) || ($tagName == "A" && $result['href'])) + && preg_match('/\binclude\b/', $result['class'])){ + $att = ($tagName == "OBJECT" ? 'data' : 'href'); + $id = str_replace('#', '', $result[$att]); + $doc = $this->doc; + $xpath = "//*[@id='$id']"; + $includes = $doc->xpath($xpath); + foreach ($includes as $include){ + $include = simplexml_load_string(''.$include->asXML().''); // don't ask. + $tmp = $this->processNodes($include, $this->classes, false); + if (is_array($tmp)) $data = array_merge($data, $tmp); + } + } + } + } + } + $out[] = $data; + } + + if (sizeof($out) > 1){ + return $out; + }else if (isset($data)){ + return $data; + }else{ + return array(); + } + } + + + private function getNodeValue($node, $className) + { + + $tag_name = strtoupper(dom_import_simplexml($node)->tagName); + $s = false; + + // ignore DEL tags + if ($tag_name == 'DEL') return $s; + + // look up att map values + if (array_key_exists($className, $this->att_map)){ + + foreach ($this->att_map[$className] as $map){ + if (preg_match("/$tag_name\|/", $map)){ + $s = ''.$node[array_pop($foo = explode('|', $map))]; + } + } + } + + // if nothing and OBJ, try data. + if (!$s && $tag_name=='OBJECT' && $node['data']) $s = ''.$node['data']; + + // if nothing and IMG, try alt. + if (!$s && $tag_name=='IMG' && $node['alt']) $s = ''.$node['alt']; + + // if nothing and AREA, try alt. + if (!$s && $tag_name=='AREA' && $node['alt']) $s = ''.$node['alt']; + + //if nothing and not A, try title. + if (!$s && $tag_name!='A' && $node['title']) $s = ''.$node['title']; + + + // if nothing found, go with node text + $s = ($s ? $s : implode(array_filter($node->xpath('child::node()'), array(&$this, "filterBlankValues")), ' ')); + + // callbacks + if (array_key_exists($className, $this->callbacks)){ + $s = preg_replace_callback('/.*/', $this->callbacks[$className], $s, 1); + } + + // trim and remove line breaks + if ($tag_name != 'PRE'){ + $s = trim(preg_replace('/[\r\n\t]+/', '', $s)); + $s = trim(preg_replace('/(\s{2})+/', ' ', $s)); + } + + return $s; + } + + private function filterBlankValues($s){ + return preg_match("/\w+/", $s); + } + + + private function tidyThis($source) + { + switch ( $this->tidy_mode ) + { + case 'exec': + $tmp_file = $this->tmp_dir.md5($source).'.txt'; + file_put_contents($tmp_file, $source); + exec("tidy -utf8 -indent -asxhtml -numeric -bare -quiet $tmp_file", $tidy); + unlink($tmp_file); + return implode("\n", $tidy); + break; + + case 'php': + $tidy = tidy_parse_string($source); + return tidy_clean_repair($tidy); + break; + + default: + return $source; + break; + } + + } + + + private function loadProfile($profile) + { + require_once("$profile.profile.php"); + } + + + private function loadDoc($input_xml, $fragment=false) + { + $xml = simplexml_load_string($input_xml); + + $this->doc = $xml; + + if ($fragment){ + $doc = $xml->xpath("//*[@id='$fragment']"); + $xml = simplexml_load_string($doc[0]->asXML()); + $doc = null; + } + + // base tag + if ($xml->head->base['href']) $this->base = $xml->head->base['href']; + + // xml:base attribute - PITA with SimpleXML + preg_match('/xml:base="(.*)"/', $xml->asXML(), $matches); + if (is_array($matches) && sizeof($matches)>1) $this->base = $matches[1]; + + return $xml->xpath("//*[contains(concat(' ',normalize-space(@class),' '),' $this->root_class ')]"); + + } + + + private function loadURL($url) + { + $this->url = $url; + + if ($this->tidy_mode == 'proxy' && $this->tidy_proxy != ''){ + $url = $this->tidy_proxy . $url; + } + + return @file_get_contents($url); + + } + + + private function postProcess($profile, $s) + { + $required = $this->required; + + if (is_array($s) && array_key_exists($required[0], $s)){ + $s = array($s); + } + + $s = $this->dedupeSingles($s); + + if (function_exists('hKit_'.$profile.'_post')){ + $s = call_user_func('hKit_'.$profile.'_post', $s); + } + + $s = $this->removeTextVals($s); + + return $s; + } + + + private function resolvePath($filepath) + { // ugly code ahoy: needs a serious tidy up + + $filepath = $filepath[0]; + + $base = $this->base; + $url = $this->url; + + if ($base != '' && strpos($base, '://') !== false) + $url = $base; + + $r = parse_url($url); + $domain = $r['scheme'] . '://' . $r['host']; + + if (!isset($r['path'])) $r['path'] = '/'; + $path = explode('/', $r['path']); + $file = explode('/', $filepath); + $new = array(''); + + if (strpos($filepath, '://') !== false || strpos($filepath, 'data:') !== false){ + return $filepath; + } + + if ($file[0] == ''){ + // absolute path + return ''.$domain . implode('/', $file); + }else{ + // relative path + if ($path[sizeof($path)-1] == '') array_pop($path); + if (strpos($path[sizeof($path)-1], '.') !== false) array_pop($path); + + foreach ($file as $segment){ + if ($segment == '..'){ + array_pop($path); + }else{ + $new[] = $segment; + } + } + return ''.$domain . implode('/', $path) . implode('/', $new); + } + } + + private function resolveEmail($v) + { + $parts = parse_url($v[0]); + return ($parts['path']); + } + + + private function dedupeSingles($s) + { + $singles = $this->singles; + + foreach ($s as &$item){ + foreach ($singles as $classname){ + if (array_key_exists($classname, $item) && is_array($item[$classname])){ + if (isset($item[$classname][0])) $item[$classname] = $item[$classname][0]; + } + } + } + + return $s; + } + + private function removeTextVals($s) + { + foreach ($s as $key => &$val){ + if ($key){ + $k = $key; + }else{ + $k = ''; + } + + if (is_array($val)){ + $val = $this->removeTextVals($val); + }else{ + if ($k == 'text'){ + $val = ''; + } + } + } + + return array_filter($s); + } + + } + + +?> \ No newline at end of file -- cgit v1.2.3-54-g00ecf From cc0670791ef07826055b461e10e64d65ec9e6547 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 25 Feb 2010 19:58:18 -0500 Subject: use new hcard method for webfinger --- plugins/OStatus/actions/webfinger.php | 2 +- plugins/OStatus/lib/webfinger.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'plugins') diff --git a/plugins/OStatus/actions/webfinger.php b/plugins/OStatus/actions/webfinger.php index d3671962b..e292ccec9 100644 --- a/plugins/OStatus/actions/webfinger.php +++ b/plugins/OStatus/actions/webfinger.php @@ -66,7 +66,7 @@ class WebfingerAction extends Action 'type' => 'application/atom+xml'); // hCard - $xrd->links[] = array('rel' => 'http://microformats.org/profile/hcard', + $xrd->links[] = array('rel' => Webfinger::HCARD, 'type' => 'text/html', 'href' => common_local_url('hcard', array('nickname' => $nick))); diff --git a/plugins/OStatus/lib/webfinger.php b/plugins/OStatus/lib/webfinger.php index 8a5037629..8d7040310 100644 --- a/plugins/OStatus/lib/webfinger.php +++ b/plugins/OStatus/lib/webfinger.php @@ -37,6 +37,7 @@ class Webfinger { const PROFILEPAGE = 'http://webfinger.net/rel/profile-page'; const UPDATESFROM = 'http://schemas.google.com/g/2010#updates-from'; + const HCARD = 'http://microformats.org/profile/hcard'; /** * Perform a webfinger lookup given an account. -- cgit v1.2.3-54-g00ecf From 894b221e8aec57768d6804ee3bf53c85196e09bf Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 25 Feb 2010 19:58:51 -0500 Subject: Parse an hcard for hints, if available --- plugins/OStatus/classes/Ostatus_profile.php | 119 ++++++++++++++++++++++++---- 1 file changed, 104 insertions(+), 15 deletions(-) (limited to 'plugins') diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index f23017077..2d517ed22 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -644,7 +644,6 @@ class Ostatus_profile extends Memcached_DataObject 'groups' => array(), 'tags' => array()); - // Check for optional attributes... if (!empty($activity->time)) { @@ -1155,7 +1154,13 @@ class Ostatus_profile extends Memcached_DataObject $orig = clone($profile); $profile->nickname = self::getActivityObjectNickname($object, $hints); - $profile->fullname = $object->title; + + if (!empty($object->title)) { + $profile->fullname = $object->title; + } else if (array_key_exists('fullname', $hints)) { + $profile->fullname = $hints['fullname']; + } + if (!empty($object->link)) { $profile->profileurl = $object->link; } else if (array_key_exists('profileurl', $hints)) { @@ -1228,12 +1233,16 @@ class Ostatus_profile extends Memcached_DataObject { $location = null; - if (!empty($object->poco)) { - if (isset($object->poco->address->formatted)) { - $location = $object->poco->address->formatted; - if (mb_strlen($location) > 255) { - $location = mb_substr($note, 0, 255 - 3) . ' … '; - } + if (!empty($object->poco) && + isset($object->poco->address->formatted)) { + $location = $object->poco->address->formatted; + } else if (array_key_exists('location', $hints)) { + $location = $hints['location']; + } + + if (!empty($location)) { + if (mb_strlen($location) > 255) { + $location = mb_substr($note, 0, 255 - 3) . ' … '; } } @@ -1248,13 +1257,16 @@ class Ostatus_profile extends Memcached_DataObject if (!empty($object->poco)) { $note = $object->poco->note; - if (!empty($note)) { - if (mb_strlen($note) > Profile::maxBio()) { - // XXX: truncate ok? - $bio = mb_substr($note, 0, Profile::maxBio() - 3) . ' … '; - } else { - $bio = $note; - } + } else if (array_key_exists('bio', $hints)) { + $note = $hints['bio']; + } + + if (!empty($note)) { + if (Profile::bioTooLong($note)) { + // XXX: truncate ok? + $bio = mb_substr($note, 0, Profile::maxBio() - 3) . ' … '; + } else { + $bio = $note; } } @@ -1270,10 +1282,15 @@ class Ostatus_profile extends Memcached_DataObject return common_nicknamize($object->poco->preferredUsername); } } + if (!empty($object->nickname)) { return common_nicknamize($object->nickname); } + if (array_key_exists('nickname', $hints)) { + return $hints['nickname']; + } + // Try the definitive ID $nickname = self::nicknameFromURI($object->id); @@ -1347,6 +1364,9 @@ class Ostatus_profile extends Memcached_DataObject case Webfinger::UPDATESFROM: $feedUrl = $link['href']; break; + case Webfinger::HCARD: + $hcardUrl = $link['href']; + break; default: common_log(LOG_NOTICE, "Don't know what to do with rel = '{$link['rel']}'"); break; @@ -1358,6 +1378,12 @@ class Ostatus_profile extends Memcached_DataObject 'feedurl' => $feedUrl, 'salmon' => $salmonEndpoint); + if (isset($hcardUrl)) { + $hcardHints = self::slurpHcard($hcardUrl); + // Note: Webfinger > hcard + $hints = array_merge($hcardHints, $hints); + } + // If we got a feed URL, try that if (isset($feedUrl)) { @@ -1464,4 +1490,67 @@ class Ostatus_profile extends Memcached_DataObject return $file; } + + protected static function slurpHcard($url) + { + set_include_path(get_include_path() . PATH_SEPARATOR . INSTALLDIR . '/plugins/OStatus/extlib/hkit/'); + require_once('hkit.class.php'); + + $h = new hKit; + + // Google Buzz hcards need to be tidied. Probably others too. + + $h->tidy_mode = 'proxy'; // 'proxy', 'exec', 'php' or 'none' + + // Get by URL + $hcards = $h->getByURL('hcard', $url); + + if (empty($hcards)) { + return array(); + } + + // @fixme more intelligent guess on multi-hcard pages + $hcard = $hcards[0]; + + $hints = array(); + + $hints['profileurl'] = $url; + + if (array_key_exists('nickname', $hcard)) { + $hints['nickname'] = $hcard['nickname']; + } + + if (array_key_exists('fn', $hcard)) { + $hints['fullname'] = $hcard['fn']; + } else if (array_key_exists('n', $hcard)) { + $hints['fullname'] = implode(' ', $hcard['n']); + } + + if (array_key_exists('photo', $hcard)) { + $hints['avatar'] = $hcard['photo']; + } + + if (array_key_exists('note', $hcard)) { + $hints['bio'] = $hcard['note']; + } + + if (array_key_exists('adr', $hcard)) { + if (is_string($hcard['adr'])) { + $hints['location'] = $hcard['adr']; + } else if (is_array($hcard['adr'])) { + $hints['location'] = implode(' ', $hcard['adr']); + } + } + + if (array_key_exists('url', $hcard)) { + if (is_string($hcard['url'])) { + $hints['homepage'] = $hcard['url']; + } else if (is_array($hcard['adr'])) { + // HACK get the last one; that's how our hcards look + $hints['homepage'] = $hcard['url'][count($hcard['url'])-1]; + } + } + + return $hints; + } } -- cgit v1.2.3-54-g00ecf From c693365ae7a27f82afef1765610c41a4bff33726 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 25 Feb 2010 20:29:52 -0500 Subject: cache results of webfinger lookups --- plugins/OStatus/classes/Ostatus_profile.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'plugins') diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 8ca28432b..ad9170f5b 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -1338,11 +1338,26 @@ class Ostatus_profile extends Memcached_DataObject public static function ensureWebfinger($addr) { + // First, try the cache + + $uri = self::cacheGet(sprintf('ostatus_profile:webfinger:%s', $addr)); + + if ($uri !== false) { + if (is_null($uri)) { + return null; + } + $oprofile = Ostatus_profile::staticGet('uri', $uri); + if (!empty($oprofile)) { + return $oprofile; + } + } + // First, look it up $oprofile = Ostatus_profile::staticGet('uri', 'acct:'.$addr); if (!empty($oprofile)) { + self::cacheSet(sprintf('ostatus_profile:webfinger:%s', $addr), $oprofile->uri); return $oprofile; } @@ -1353,6 +1368,7 @@ class Ostatus_profile extends Memcached_DataObject $result = $wf->lookup($addr); if (!$result) { + self::cacheSet(sprintf('ostatus_profile:webfinger:%s', $addr), null); return null; } @@ -1392,6 +1408,7 @@ class Ostatus_profile extends Memcached_DataObject if (isset($feedUrl)) { try { $oprofile = self::ensureProfile($feedUrl, $hints); + self::cacheSet(sprintf('ostatus_profile:webfinger:%s', $addr), $oprofile->uri); return $oprofile; } catch (Exception $e) { common_log(LOG_WARNING, "Failed creating profile from feed URL '$feedUrl': " . $e->getMessage()); @@ -1404,6 +1421,7 @@ class Ostatus_profile extends Memcached_DataObject if (isset($profileUrl)) { try { $oprofile = self::ensureProfile($profileUrl, $hints); + self::cacheSet(sprintf('ostatus_profile:webfinger:%s', $addr), $oprofile->uri); return $oprofile; } catch (Exception $e) { common_log(LOG_WARNING, "Failed creating profile from profile URL '$profileUrl': " . $e->getMessage()); @@ -1455,6 +1473,7 @@ class Ostatus_profile extends Memcached_DataObject throw new Exception("Couldn't save ostatus_profile for '$addr'"); } + self::cacheSet(sprintf('ostatus_profile:webfinger:%s', $addr), $oprofile->uri); return $oprofile; } -- cgit v1.2.3-54-g00ecf From a43598c31ecee2ca77d8c686382c29ee5a0d42b1 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 25 Feb 2010 21:07:24 -0500 Subject: cache Web responses in Webfinger library --- plugins/OStatus/lib/webfinger.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'plugins') diff --git a/plugins/OStatus/lib/webfinger.php b/plugins/OStatus/lib/webfinger.php index 8d7040310..4b777c9a0 100644 --- a/plugins/OStatus/lib/webfinger.php +++ b/plugins/OStatus/lib/webfinger.php @@ -81,11 +81,14 @@ class Webfinger function getServiceLinks($domain) { $url = 'http://'. $domain .'/.well-known/host-meta'; + $content = $this->fetchURL($url); + if (empty($content)) { common_log(LOG_DEBUG, 'Error fetching host-meta'); return false; } + $result = XRD::parse($content); // Ensure that the host == domain (spec may include signing later) @@ -119,6 +122,11 @@ class Webfinger function fetchURL($url) { try { + $c = Cache::instance(); + $content = $c->get('webfinger:url:'.$url); + if ($content !== false) { + return $content; + } $client = new HTTPClient(); $response = $client->get($url); } catch (HTTP_Request2_Exception $e) { @@ -129,7 +137,11 @@ class Webfinger return false; } - return $response->getBody(); + $body = $response->getBody(); + + $c->set('webfinger:url:'.$url, $body); + + return $body; } function applyTemplate($template, $id) -- cgit v1.2.3-54-g00ecf From e197208a4a2ab742df481968e30cd99678be96ad Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 25 Feb 2010 21:07:52 -0500 Subject: info about discovery in Ostatus_profile::ensureWebfinger() --- plugins/OStatus/classes/Ostatus_profile.php | 2 ++ 1 file changed, 2 insertions(+) (limited to 'plugins') diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index ad9170f5b..26d776d52 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -1407,6 +1407,7 @@ class Ostatus_profile extends Memcached_DataObject if (isset($feedUrl)) { try { + common_log(LOG_INFO, "Discovery on acct:$addr with feed URL $feedUrl"); $oprofile = self::ensureProfile($feedUrl, $hints); self::cacheSet(sprintf('ostatus_profile:webfinger:%s', $addr), $oprofile->uri); return $oprofile; @@ -1420,6 +1421,7 @@ class Ostatus_profile extends Memcached_DataObject if (isset($profileUrl)) { try { + common_log(LOG_INFO, "Discovery on acct:$addr with profile URL $profileUrl"); $oprofile = self::ensureProfile($profileUrl, $hints); self::cacheSet(sprintf('ostatus_profile:webfinger:%s', $addr), $oprofile->uri); return $oprofile; -- cgit v1.2.3-54-g00ecf From 2feb09f4346e54805f68a9f677f5a94340875d8e Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 25 Feb 2010 18:51:44 -0800 Subject: OStatus: pull best-sized avatar image (96x96 if found, otherwise largest, otherwise if none labeled takes the first) --- lib/activity.php | 43 +++++++++++++++++++++++++++-- plugins/OStatus/classes/Ostatus_profile.php | 16 +++++++++-- 2 files changed, 55 insertions(+), 4 deletions(-) (limited to 'plugins') diff --git a/lib/activity.php b/lib/activity.php index 0f30e8bf5..b64a82f0a 100644 --- a/lib/activity.php +++ b/lib/activity.php @@ -360,6 +360,25 @@ class ActivityUtils return null; } + static function getLinks(DOMNode $element, $rel, $type=null) + { + $links = $element->getElementsByTagnameNS(self::ATOM, self::LINK); + $out = array(); + + foreach ($links as $link) { + + $linkRel = $link->getAttribute(self::REL); + $linkType = $link->getAttribute(self::TYPE); + + if ($linkRel == $rel && + (is_null($type) || $linkType == $type)) { + $out[] = $link; + } + } + + return $out; + } + /** * Gets the first child element with the given tag * @@ -472,6 +491,24 @@ class AvatarLink public $type; public $size; public $width; + public $height; + + function __construct($element=null) + { + if ($element) { + // @fixme use correct namespaces + $this->url = $element->getAttribute('href'); + $this->type = $element->getAttribute('type'); + $width = $element->getAttribute('media:width'); + if ($width != null) { + $this->width = intval($width); + } + $height = $element->getAttribute('media:height'); + if ($height != null) { + $this->height = intval($height); + } + } + } static function fromAvatar($avatar) { @@ -640,8 +677,10 @@ class ActivityObject if ($this->type == self::PERSON || $this->type == self::GROUP) { $this->displayName = $this->title; - // @fixme we may have multiple avatars with different resolutions specified - $this->avatar = ActivityUtils::getLink($element, 'avatar'); + $avatars = ActivityUtils::getLinks($element, 'avatar'); + foreach ($avatars as $link) { + $this->avatarLinks[] = new AvatarLink($link); + } $this->poco = new PoCo($element); } diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index ad9170f5b..9b7be4e9a 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -912,8 +912,20 @@ class Ostatus_profile extends Memcached_DataObject protected static function getActivityObjectAvatar($object, $hints=array()) { - if ($object->avatar) { - return $object->avatar; + if ($object->avatarLinks) { + $best = false; + // Take the exact-size avatar, or the largest avatar, or the first avatar if all sizeless + foreach ($object->avatarLinks as $avatar) { + if ($avatar->width == AVATAR_PROFILE_SIZE && $avatar->height = AVATAR_PROFILE_SIZE) { + // Exact match! + $best = $avatar; + break; + } + if (!$best || $avatar->width > $best->width) { + $best = $avatar; + } + } + return $best->url; } else if (array_key_exists('avatar', $hints)) { return $hints['avatar']; } -- cgit v1.2.3-54-g00ecf From d8d8d59a03ef3fa12a0ea668b4a2f383f80486dc Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 25 Feb 2010 18:55:11 -0800 Subject: - Updates to use new activity object factories - Prune obsolete feed creation method --- plugins/OStatus/classes/Ostatus_profile.php | 104 ++-------------------------- 1 file changed, 5 insertions(+), 99 deletions(-) (limited to 'plugins') diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index ad9170f5b..c3ea042ff 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -150,27 +150,7 @@ class Ostatus_profile extends Memcached_DataObject function asActivityObject() { if ($this->isGroup()) { - $object = new ActivityObject(); - $object->type = 'http://activitystrea.ms/schema/1.0/group'; - $object->id = $this->uri; - $self = $this->localGroup(); - - // @fixme put a standard getAvatar() interface on groups too - if ($self->homepage_logo) { - $object->avatar = $self->homepage_logo; - $map = array('png' => 'image/png', - 'jpg' => 'image/jpeg', - 'jpeg' => 'image/jpeg', - 'gif' => 'image/gif'); - $extension = pathinfo(parse_url($object->avatar, PHP_URL_PATH), PATHINFO_EXTENSION); - if (isset($map[$extension])) { - // @fixme this ain't used/saved yet - $object->avatarType = $map[$extension]; - } - } - - $object->link = $this->uri; // @fixme accurate? - return $object; + return ActivityObject::fromGroup($this->localGroup()); } else { return ActivityObject::fromProfile($this->localProfile()); } @@ -189,57 +169,13 @@ class Ostatus_profile extends Memcached_DataObject */ function asActivityNoun($element) { - $xs = new XMLStringer(true); - $avatarHref = Avatar::defaultImage(AVATAR_PROFILE_SIZE); - $avatarType = 'image/png'; if ($this->isGroup()) { - $type = 'http://activitystrea.ms/schema/1.0/group'; - $self = $this->localGroup(); - - // @fixme put a standard getAvatar() interface on groups too - if ($self->homepage_logo) { - $avatarHref = $self->homepage_logo; - $map = array('png' => 'image/png', - 'jpg' => 'image/jpeg', - 'jpeg' => 'image/jpeg', - 'gif' => 'image/gif'); - $extension = pathinfo(parse_url($avatarHref, PHP_URL_PATH), PATHINFO_EXTENSION); - if (isset($map[$extension])) { - $avatarType = $map[$extension]; - } - } + $noun = ActivityObject::fromGroup($this->localGroup()); + return $noun->asString('activity:' . $element); } else { - $type = 'http://activitystrea.ms/schema/1.0/person'; - $self = $this->localProfile(); - $avatar = $self->getAvatar(AVATAR_PROFILE_SIZE); - if ($avatar) { - $avatarHref = $avatar->url; - $avatarType = $avatar->mediatype; - } + $noun = ActivityObject::fromProfile($this->localProfile()); + return $noun->asString('activity:' . $element); } - $xs->elementStart('activity:' . $element); - $xs->element( - 'activity:object-type', - null, - $type - ); - $xs->element( - 'id', - null, - $this->uri); // ? - $xs->element('title', null, $self->getBestName()); - - $xs->element( - 'link', array( - 'type' => $avatarType, - 'href' => $avatarHref - ), - '' - ); - - $xs->elementEnd('activity:' . $element); - - return $xs->getString(); } /** @@ -486,36 +422,6 @@ class Ostatus_profile extends Memcached_DataObject } } - function atomFeed($actor) - { - $feed = new Atom10Feed(); - // @fixme should these be set up somewhere else? - $feed->addNamespace('activity', 'http://activitystrea.ms/spec/1.0/'); - $feed->addNamespace('thr', 'http://purl.org/syndication/thread/1.0'); - $feed->addNamespace('georss', 'http://www.georss.org/georss'); - $feed->addNamespace('ostatus', 'http://ostatus.org/schema/1.0'); - - $taguribase = common_config('integration', 'taguri'); - $feed->setId("tag:{$taguribase}:UserTimeline:{$actor->id}"); // ??? - - $feed->setTitle($actor->getBestName() . ' timeline'); // @fixme - $feed->setUpdated(time()); - $feed->setPublished(time()); - - $feed->addLink(common_local_url('ApiTimelineUser', - array('id' => $actor->id, - 'type' => 'atom')), - array('rel' => 'self', - 'type' => 'application/atom+xml')); - - $feed->addLink(common_local_url('userbyid', - array('id' => $actor->id)), - array('rel' => 'alternate', - 'type' => 'text/html')); - - return $feed; - } - /** * Read and post notices for updates from the feed. * Currently assumes that all items in the feed are new, -- cgit v1.2.3-54-g00ecf From 2528bb452b4ed27cc8685f5c8d900fe0742ef229 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 25 Feb 2010 19:48:28 -0800 Subject: OStatus: clean up known-URL hinting during profile setup, saves some extra HTTP hits we were getting when mentioning Buzz feeds. --- plugins/OStatus/classes/Ostatus_profile.php | 82 +++++++++++++++-------------- 1 file changed, 43 insertions(+), 39 deletions(-) (limited to 'plugins') diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 75b4bef41..c462fead6 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -791,11 +791,18 @@ class Ostatus_profile extends Memcached_DataObject { // Get the canonical feed URI and check it $discover = new FeedDiscovery(); - $feeduri = $discover->discoverFromURL($profile_uri); + if ($hints['feedurl']) { + $feeduri = $hints['feedurl']; + $feeduri = $discover->discoverFromFeedURL($feeduri); + } else { + $feeduri = $discover->discoverFromURL($profile_uri); + $hints['feedurl'] = $feeduri; + } - //$feedsub = FeedSub::ensureFeed($feeduri, $discover->feed); $huburi = $discover->getAtomLink('hub'); + $hints['hub'] = $huburi; $salmonuri = $discover->getAtomLink('salmon'); + $hints['salmon'] = $salmonuri; if (!$huburi) { // We can only deal with folks with a PuSH hub @@ -810,7 +817,7 @@ class Ostatus_profile extends Memcached_DataObject if (!empty($subject)) { $subjObject = new ActivityObject($subject); - return self::ensureActivityObjectProfile($subjObject, $feeduri, $salmonuri, $hints); + return self::ensureActivityObjectProfile($subjObject, $hints); } // Otherwise, try the feed author @@ -819,7 +826,7 @@ class Ostatus_profile extends Memcached_DataObject if (!empty($author)) { $authorObject = new ActivityObject($author); - return self::ensureActivityObjectProfile($authorObject, $feeduri, $salmonuri, $hints); + return self::ensureActivityObjectProfile($authorObject, $hints); } // Sheesh. Not a very nice feed! Let's try fingerpoken in the @@ -835,7 +842,7 @@ class Ostatus_profile extends Memcached_DataObject if (!empty($actor)) { $actorObject = new ActivityObject($actor); - return self::ensureActivityObjectProfile($actorObject, $feeduri, $salmonuri, $hints); + return self::ensureActivityObjectProfile($actorObject, $hints); } @@ -843,7 +850,7 @@ class Ostatus_profile extends Memcached_DataObject if (!empty($author)) { $authorObject = new ActivityObject($author); - return self::ensureActivityObjectProfile($authorObject, $feeduri, $salmonuri, $hints); + return self::ensureActivityObjectProfile($authorObject, $hints); } } @@ -988,18 +995,18 @@ class Ostatus_profile extends Memcached_DataObject * @return Ostatus_profile */ - public static function ensureActorProfile($activity, $feeduri=null, $salmonuri=null) + public static function ensureActorProfile($activity, $hints=array()) { - return self::ensureActivityObjectProfile($activity->actor, $feeduri, $salmonuri); + return self::ensureActivityObjectProfile($activity->actor, $hints); } - public static function ensureActivityObjectProfile($object, $feeduri=null, $salmonuri=null, $hints=array()) + public static function ensureActivityObjectProfile($object, $hints=array()) { $profile = self::getActivityObjectProfile($object); if ($profile) { $profile->updateFromActivityObject($object, $hints); } else { - $profile = self::createActivityObjectProfile($object, $feeduri, $salmonuri, $hints); + $profile = self::createActivityObjectProfile($object, $hints); } return $profile; } @@ -1045,58 +1052,55 @@ class Ostatus_profile extends Memcached_DataObject * @fixme validate stuff somewhere */ - protected static function createActorProfile($activity, $feeduri=null, $salmonuri=null) - { - $actor = $activity->actor; - - self::createActivityObjectProfile($actor, $feeduri, $salmonuri); - } - /** * Create local ostatus_profile and profile/user_group entries for * the provided remote user or group. * * @param ActivityObject $object - * @param string $feeduri - * @param string $salmonuri * @param array $hints * - * @fixme fold $feeduri/$salmonuri into $hints * @return Ostatus_profile */ - protected static function createActivityObjectProfile($object, $feeduri=null, $salmonuri=null, $hints=array()) + protected static function createActivityObjectProfile($object, $hints=array()) { - $homeuri = $object->id; + $homeuri = $object->id; + $discover = false; if (!$homeuri) { common_log(LOG_DEBUG, __METHOD__ . " empty actor profile URI: " . var_export($activity, true)); throw new ServerException("No profile URI"); } - if (empty($feeduri)) { - if (array_key_exists('feedurl', $hints)) { - $feeduri = $hints['feedurl']; - } + if (array_key_exists('feedurl', $hints)) { + $feeduri = $hints['feedurl']; + } else { + $discover = new FeedDiscovery(); + $feeduri = $discover->discoverFromURL($homeuri); } - if (empty($salmonuri)) { - if (array_key_exists('salmon', $hints)) { - $salmonuri = $hints['salmon']; + if (array_key_exists('salmon', $hints)) { + $salmonuri = $hints['salmon']; + } else { + if (!$discover) { + $discover = new FeedDiscovery(); + $discover->discoverFromFeedURL($hints['feedurl']); } + $salmonuri = $discover->getAtomLink('salmon'); } - if (!$feeduri || !$salmonuri) { - // Get the canonical feed URI and check it - $discover = new FeedDiscovery(); - $feeduri = $discover->discoverFromURL($homeuri); - + if (array_key_exists('hub', $hints)) { + $huburi = $hints['hub']; + } else { + if (!$discover) { + $discover = new FeedDiscovery(); + $discover->discoverFromFeedURL($hints['feedurl']); + } $huburi = $discover->getAtomLink('hub'); - $salmonuri = $discover->getAtomLink('salmon'); + } - if (!$huburi) { - // We can only deal with folks with a PuSH hub - throw new FeedSubNoHubException(); - } + if (!$huburi) { + // We can only deal with folks with a PuSH hub + throw new FeedSubNoHubException(); } $oprofile = new Ostatus_profile(); -- cgit v1.2.3-54-g00ecf From 0afb09ad64bec9ea7f9569c73899b2c3fbc1e5a5 Mon Sep 17 00:00:00 2001 From: James Walker Date: Thu, 25 Feb 2010 23:37:59 -0500 Subject: er. right. --- plugins/OStatus/classes/Magicsig.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'plugins') diff --git a/plugins/OStatus/classes/Magicsig.php b/plugins/OStatus/classes/Magicsig.php index 681aec184..02882d19b 100644 --- a/plugins/OStatus/classes/Magicsig.php +++ b/plugins/OStatus/classes/Magicsig.php @@ -90,7 +90,7 @@ class Magicsig extends Memcached_DataObject return parent::insert(); } - public function generate($key_length = 512) + public function generate($user_id, $key_length = 512) { PEAR::pushErrorHandling(PEAR_ERROR_RETURN); @@ -101,6 +101,7 @@ class Magicsig extends Memcached_DataObject $this->_rsa = new Crypt_RSA($params); PEAR::popErrorHandling(); + $this->user_id = $user_id; $this->insert(); } -- cgit v1.2.3-54-g00ecf From 855692141d531287b179841b8816e90023b6ba7b Mon Sep 17 00:00:00 2001 From: James Walker Date: Thu, 25 Feb 2010 23:38:25 -0500 Subject: use a real keypair from discovery --- plugins/OStatus/lib/magicenvelope.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'plugins') diff --git a/plugins/OStatus/lib/magicenvelope.php b/plugins/OStatus/lib/magicenvelope.php index 4a9efe93d..4f8f88155 100644 --- a/plugins/OStatus/lib/magicenvelope.php +++ b/plugins/OStatus/lib/magicenvelope.php @@ -50,7 +50,16 @@ class MagicEnvelope public function getKeyPair($signer_uri) { - return 'RSA.79_L2gq-TD72Nsb5yGS0r9stLLpJZF5AHXyxzWmQmlqKl276LEJEs8CppcerLcR90MbYQUwt-SX9slx40Yq3vA==.AQAB.AR-jo5KMfSISmDAT2iMs2_vNFgWRjl5rbJVvA0SpGIEWyPdCGxlPtCbTexp8-0ZEIe8a4SyjatBECH5hxgMTpw=='; + $disco = new Discovery(); + + $links = $disco->lookup($signer_uri); + if ($link = Discovery::getService($links, 'magic-public-key')) { + list($type, $keypair) = explode(';', $link['href']); + return $keypair; + } + + throw new Exception('Unable to locate signer public key'); + //return 'RSA.79_L2gq-TD72Nsb5yGS0r9stLLpJZF5AHXyxzWmQmlqKl276LEJEs8CppcerLcR90MbYQUwt-SX9slx40Yq3vA==.AQAB.AR-jo5KMfSISmDAT2iMs2_vNFgWRjl5rbJVvA0SpGIEWyPdCGxlPtCbTexp8-0ZEIe8a4SyjatBECH5hxgMTpw=='; } -- cgit v1.2.3-54-g00ecf From e650794300f48f75cc4a91ac86d7e7dd9e082136 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 25 Feb 2010 22:06:31 -0800 Subject: Remove unnecessary requires --- actions/apistatusnetconfig.php | 2 -- actions/twitapisearchatom.php | 2 -- actions/twitapisearchjson.php | 1 - actions/twitapitrends.php | 2 -- lib/apiauth.php | 1 - plugins/Mapstraction/map.php | 2 -- plugins/Realtime/RealtimePlugin.php | 2 -- 7 files changed, 12 deletions(-) (limited to 'plugins') diff --git a/actions/apistatusnetconfig.php b/actions/apistatusnetconfig.php index dc1ab8685..296376d19 100644 --- a/actions/apistatusnetconfig.php +++ b/actions/apistatusnetconfig.php @@ -32,8 +32,6 @@ if (!defined('STATUSNET')) { exit(1); } -require_once INSTALLDIR . '/lib/api.php'; - /** * Gives a full dump of configuration variables for this instance * of StatusNet, minus variables that may be security-sensitive (like diff --git a/actions/twitapisearchatom.php b/actions/twitapisearchatom.php index e389ddec8..24aa619bd 100644 --- a/actions/twitapisearchatom.php +++ b/actions/twitapisearchatom.php @@ -31,8 +31,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -require_once INSTALLDIR.'/lib/api.php'; - /** * Action for outputting search results in Twitter compatible Atom * format. diff --git a/actions/twitapisearchjson.php b/actions/twitapisearchjson.php index 741ed78d6..b5c006aa7 100644 --- a/actions/twitapisearchjson.php +++ b/actions/twitapisearchjson.php @@ -31,7 +31,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -require_once INSTALLDIR.'/lib/api.php'; require_once INSTALLDIR.'/lib/jsonsearchresultslist.php'; /** diff --git a/actions/twitapitrends.php b/actions/twitapitrends.php index 779405e6d..5a04569a2 100644 --- a/actions/twitapitrends.php +++ b/actions/twitapitrends.php @@ -31,8 +31,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -require_once INSTALLDIR.'/lib/api.php'; - /** * Returns the top ten queries that are currently trending * diff --git a/lib/apiauth.php b/lib/apiauth.php index 25e2196cf..5090871cf 100644 --- a/lib/apiauth.php +++ b/lib/apiauth.php @@ -38,7 +38,6 @@ if (!defined('STATUSNET')) { exit(1); } -require_once INSTALLDIR . '/lib/api.php'; require_once INSTALLDIR . '/lib/apioauth.php'; /** diff --git a/plugins/Mapstraction/map.php b/plugins/Mapstraction/map.php index a33dfc736..b809c1b8e 100644 --- a/plugins/Mapstraction/map.php +++ b/plugins/Mapstraction/map.php @@ -142,8 +142,6 @@ class MapAction extends OwnerDesignAction // of refactoring from within a plugin, so I'm just abusing // the ApiAction method. Don't do this unless you're me! - require_once(INSTALLDIR.'/lib/api.php'); - $act = new ApiAction('/dev/null'); $arr = $act->twitterStatusArray($notice, true); diff --git a/plugins/Realtime/RealtimePlugin.php b/plugins/Realtime/RealtimePlugin.php index 6c212453e..2b3cb35f1 100644 --- a/plugins/Realtime/RealtimePlugin.php +++ b/plugins/Realtime/RealtimePlugin.php @@ -244,8 +244,6 @@ class RealtimePlugin extends Plugin // of refactoring from within a plugin, so I'm just abusing // the ApiAction method. Don't do this unless you're me! - require_once(INSTALLDIR.'/lib/api.php'); - $act = new ApiAction('/dev/null'); $arr = $act->twitterStatusArray($notice, true); -- cgit v1.2.3-54-g00ecf From 84d0c865c4c2dd597e249c76fa1429175f5461a1 Mon Sep 17 00:00:00 2001 From: James Walker Date: Fri, 26 Feb 2010 03:25:51 -0500 Subject: salmon actually fetching remote keypairs --- plugins/OStatus/OStatusPlugin.php | 14 ++++++++++++++ plugins/OStatus/actions/ostatusinit.php | 2 +- plugins/OStatus/lib/discovery.php | 34 +++++++++++++++++---------------- plugins/OStatus/lib/magicenvelope.php | 5 ++--- 4 files changed, 35 insertions(+), 20 deletions(-) (limited to 'plugins') diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 91d055498..46f986682 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -102,6 +102,20 @@ class OStatusPlugin extends Plugin return true; } + /** + * Add a link header for LRDD Discovery + */ + function onStartShowHTML($action) + { + if ($action instanceof ShowstreamAction) { + $acct = 'acct:'. $action->profile->nickname .'@'. common_config('site', 'server'); + $url = common_local_url('xrd'); + $url.= '?uri='. $acct; + + header('Link: <'.$url.'>; rel="'. Discovery::LRDD_REL.'"; type="application/xrd+xml"'); + } + } + /** * Set up a PuSH hub link to our internal link for canonical timeline * Atom feeds for users and groups. diff --git a/plugins/OStatus/actions/ostatusinit.php b/plugins/OStatus/actions/ostatusinit.php index 5c8575595..8ba8dcdcc 100644 --- a/plugins/OStatus/actions/ostatusinit.php +++ b/plugins/OStatus/actions/ostatusinit.php @@ -144,7 +144,7 @@ class OStatusInitAction extends Action $user = User::staticGet('nickname', $this->nickname); $target_profile = common_local_url('userbyid', array('id' => $user->id)); - $url = $w->applyTemplate($link['template'], $target_profile); + $url = Discovery::applyTemplate($link['template'], $target_profile); common_log(LOG_INFO, "Sending remote subscriber $acct to $url"); common_redirect($url, 303); } diff --git a/plugins/OStatus/lib/discovery.php b/plugins/OStatus/lib/discovery.php index 8aba31328..c268ad05c 100644 --- a/plugins/OStatus/lib/discovery.php +++ b/plugins/OStatus/lib/discovery.php @@ -91,7 +91,6 @@ class Discovery foreach ($this->methods as $class) { $links = call_user_func(array($class, 'discover'), $uri); - if ($link = Discovery::getService($links, Discovery::LRDD_REL)) { // Load the LRDD XRD if ($link['template']) { @@ -141,7 +140,7 @@ class Discovery } return XRD::parse($response->getBody()); - } + } } interface Discovery_LRDD @@ -153,13 +152,12 @@ class Discovery_LRDD_Host_Meta implements Discovery_LRDD { public function discover($uri) { - if (Discovery::isWebfinger($uri)) { - // We have a webfinger acct: - start with host-meta - list($name, $domain) = explode('@', $id); - } else { - $domain = @parse_url($uri, PHP_URL_HOST); + if (!Discovery::isWebfinger($uri)) { + return false; } + // We have a webfinger acct: - start with host-meta + list($name, $domain) = explode('@', $uri); $url = 'http://'. $domain .'/.well-known/host-meta'; $xrd = Discovery::fetchXrd($url); @@ -180,27 +178,29 @@ class Discovery_LRDD_Link_Header implements Discovery_LRDD { try { $client = new HTTPClient(); - $response = $client->get($url); + $response = $client->get($uri); } catch (HTTP_Request2_Exception $e) { return false; } - + if ($response->getStatus() != 200) { return false; } $link_header = $response->getHeader('Link'); if (!$link_header) { - return false; + // return false; } - return Discovery_LRDD_Link_Header::parseHeader($header); + return Discovery_LRDD_Link_Header::parseHeader($link_header); } protected static function parseHeader($header) { preg_match('/^<[^>]+>/', $header, $uri_reference); - if (empty($uri_reference)) return; + //if (empty($uri_reference)) return; + + $links = array(); $link_uri = trim($uri_reference[0], '<>'); $link_rel = array(); @@ -210,7 +210,7 @@ class Discovery_LRDD_Link_Header implements Discovery_LRDD $header = substr($header, strlen($uri_reference[0])); // parse link-params - $params = explode($header, ';'); + $params = explode(';', $header); foreach ($params as $param) { if (empty($param)) continue; @@ -229,11 +229,13 @@ class Discovery_LRDD_Link_Header implements Discovery_LRDD $link_type = trim($param_value); } } - - return array( + + $links[] = array( 'href' => $link_uri, 'rel' => $link_rel, 'type' => $link_type); + + return $links; } } @@ -243,7 +245,7 @@ class Discovery_LRDD_Link_HTML implements Discovery_LRDD { try { $client = new HTTPClient(); - $response = $client->get($url); + $response = $client->get($uri); } catch (HTTP_Request2_Exception $e) { return false; } diff --git a/plugins/OStatus/lib/magicenvelope.php b/plugins/OStatus/lib/magicenvelope.php index 4f8f88155..c642af548 100644 --- a/plugins/OStatus/lib/magicenvelope.php +++ b/plugins/OStatus/lib/magicenvelope.php @@ -52,14 +52,13 @@ class MagicEnvelope { $disco = new Discovery(); - $links = $disco->lookup($signer_uri); - if ($link = Discovery::getService($links, 'magic-public-key')) { + $xrd = $disco->lookup($signer_uri); + if ($link = Discovery::getService($xrd->links, Magicsig::PUBLICKEYREL)) { list($type, $keypair) = explode(';', $link['href']); return $keypair; } throw new Exception('Unable to locate signer public key'); - //return 'RSA.79_L2gq-TD72Nsb5yGS0r9stLLpJZF5AHXyxzWmQmlqKl276LEJEs8CppcerLcR90MbYQUwt-SX9slx40Yq3vA==.AQAB.AR-jo5KMfSISmDAT2iMs2_vNFgWRjl5rbJVvA0SpGIEWyPdCGxlPtCbTexp8-0ZEIe8a4SyjatBECH5hxgMTpw=='; } -- cgit v1.2.3-54-g00ecf From 22062b665e6d883f5ddfe590af1b9b22833094b0 Mon Sep 17 00:00:00 2001 From: James Walker Date: Fri, 26 Feb 2010 03:28:29 -0500 Subject: remove webfinger.php --- plugins/OStatus/lib/webfinger.php | 164 -------------------------------------- 1 file changed, 164 deletions(-) delete mode 100644 plugins/OStatus/lib/webfinger.php (limited to 'plugins') diff --git a/plugins/OStatus/lib/webfinger.php b/plugins/OStatus/lib/webfinger.php deleted file mode 100644 index 4b777c9a0..000000000 --- a/plugins/OStatus/lib/webfinger.php +++ /dev/null @@ -1,164 +0,0 @@ -. - * - * @package StatusNet - * @author James Walker - * @copyright 2010 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 - * @link http://status.net/ - */ - -define('WEBFINGER_SERVICE_REL_VALUE', 'lrdd'); - -/** - * Implement the webfinger protocol. - */ - -class Webfinger -{ - const PROFILEPAGE = 'http://webfinger.net/rel/profile-page'; - const UPDATESFROM = 'http://schemas.google.com/g/2010#updates-from'; - const HCARD = 'http://microformats.org/profile/hcard'; - - /** - * Perform a webfinger lookup given an account. - */ - - public function lookup($id) - { - $id = $this->normalize($id); - list($name, $domain) = explode('@', $id); - - $links = $this->getServiceLinks($domain); - if (!$links) { - return false; - } - - $services = array(); - foreach ($links as $link) { - if ($link['template']) { - return $this->getServiceDescription($link['template'], $id); - } - if ($link['href']) { - return $this->getServiceDescription($link['href'], $id); - } - } - } - - /** - * Normalize an account ID - */ - function normalize($id) - { - if (substr($id, 0, 7) == 'acct://') { - return substr($id, 7); - } else if (substr($id, 0, 5) == 'acct:') { - return substr($id, 5); - } - - return $id; - } - - function getServiceLinks($domain) - { - $url = 'http://'. $domain .'/.well-known/host-meta'; - - $content = $this->fetchURL($url); - - if (empty($content)) { - common_log(LOG_DEBUG, 'Error fetching host-meta'); - return false; - } - - $result = XRD::parse($content); - - // Ensure that the host == domain (spec may include signing later) - if ($result->host != $domain) { - return false; - } - - $links = array(); - foreach ($result->links as $link) { - if ($link['rel'] == WEBFINGER_SERVICE_REL_VALUE) { - $links[] = $link; - } - - } - return $links; - } - - function getServiceDescription($template, $id) - { - $url = $this->applyTemplate($template, 'acct:' . $id); - - $content = $this->fetchURL($url); - - if (!$content) { - return false; - } - - return XRD::parse($content); - } - - function fetchURL($url) - { - try { - $c = Cache::instance(); - $content = $c->get('webfinger:url:'.$url); - if ($content !== false) { - return $content; - } - $client = new HTTPClient(); - $response = $client->get($url); - } catch (HTTP_Request2_Exception $e) { - return false; - } - - if ($response->getStatus() != 200) { - return false; - } - - $body = $response->getBody(); - - $c->set('webfinger:url:'.$url, $body); - - return $body; - } - - function applyTemplate($template, $id) - { - $template = str_replace('{uri}', urlencode($id), $template); - - return $template; - } - - function getHostMeta($domain, $template) { - $xrd = new XRD(); - $xrd->host = $domain; - $xrd->links[] = array('rel' => 'lrdd', - 'template' => $template, - 'title' => array('Resource Descriptor')); - - return $xrd->toXML(); - } -} - -- cgit v1.2.3-54-g00ecf From d1256b547f5f4f02ddc51a5fe2146dbde52aac53 Mon Sep 17 00:00:00 2001 From: James Walker Date: Fri, 26 Feb 2010 03:43:35 -0500 Subject: bad merge.. cleaning up missing webfinger bits --- plugins/OStatus/actions/xrd.php | 2 +- plugins/OStatus/lib/discovery.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'plugins') diff --git a/plugins/OStatus/actions/xrd.php b/plugins/OStatus/actions/xrd.php index 2a754dcfe..e6b694d61 100644 --- a/plugins/OStatus/actions/xrd.php +++ b/plugins/OStatus/actions/xrd.php @@ -66,7 +66,7 @@ class XrdAction extends Action 'type' => 'application/atom+xml'); // hCard - $xrd->links[] = array('rel' => Webfinger::HCARD, + $xrd->links[] = array('rel' => Discovery::HCARD, 'type' => 'text/html', 'href' => common_local_url('hcard', array('nickname' => $nick))); diff --git a/plugins/OStatus/lib/discovery.php b/plugins/OStatus/lib/discovery.php index c268ad05c..1ab6e51bd 100644 --- a/plugins/OStatus/lib/discovery.php +++ b/plugins/OStatus/lib/discovery.php @@ -39,7 +39,8 @@ class Discovery const LRDD_REL = 'lrdd'; const PROFILEPAGE = 'http://webfinger.net/rel/profile-page'; const UPDATESFROM = 'http://schemas.google.com/g/2010#updates-from'; - + const HCARD = 'http://microformats.org/profile/hcard'; + public $methods = array(); public function __construct() -- cgit v1.2.3-54-g00ecf From ab8bb4d79e5f267323440b8cee01458b393ce2d1 Mon Sep 17 00:00:00 2001 From: James Walker Date: Fri, 26 Feb 2010 04:07:58 -0500 Subject: more cleanup --- plugins/OStatus/classes/Ostatus_profile.php | 2 +- plugins/OStatus/lib/discovery.php | 4 ++++ plugins/OStatus/lib/magicenvelope.php | 21 +++++++++++++++------ 3 files changed, 20 insertions(+), 7 deletions(-) (limited to 'plugins') diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 4a9aafce1..091056c54 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -1305,7 +1305,7 @@ class Ostatus_profile extends Memcached_DataObject case Discovery::UPDATESFROM: $feedUrl = $link['href']; break; - case Webfinger::HCARD: + case Discovery::HCARD: $hcardUrl = $link['href']; break; default: diff --git a/plugins/OStatus/lib/discovery.php b/plugins/OStatus/lib/discovery.php index 1ab6e51bd..388df0a28 100644 --- a/plugins/OStatus/lib/discovery.php +++ b/plugins/OStatus/lib/discovery.php @@ -111,6 +111,10 @@ class Discovery } public static function getService($links, $service) { + if (!is_array($links)) { + return false; + } + foreach ($links as $link) { if ($link['rel'] == $service) { return $link; diff --git a/plugins/OStatus/lib/magicenvelope.php b/plugins/OStatus/lib/magicenvelope.php index c642af548..457c0fba2 100644 --- a/plugins/OStatus/lib/magicenvelope.php +++ b/plugins/OStatus/lib/magicenvelope.php @@ -52,12 +52,17 @@ class MagicEnvelope { $disco = new Discovery(); - $xrd = $disco->lookup($signer_uri); - if ($link = Discovery::getService($xrd->links, Magicsig::PUBLICKEYREL)) { - list($type, $keypair) = explode(';', $link['href']); - return $keypair; + try { + $xrd = $disco->lookup($signer_uri); + } catch (Exception $e) { + return false; + } + if ($xrd->links) { + if ($link = Discovery::getService($xrd->links, Magicsig::PUBLICKEYREL)) { + list($type, $keypair) = explode(';', $link['href']); + return $keypair; + } } - throw new Exception('Unable to locate signer public key'); } @@ -70,7 +75,11 @@ class MagicEnvelope throw new Exception("Unable to determine entry author."); } - $signature_alg = Magicsig::fromString($this->getKeyPair($signer_uri)); + $keypair = $this->getKeyPair($signer_uri); + if (!$keypair) { + throw new Exception("Unable to retrive keypair for ". $signer_uri); + } + $signature_alg = Magicsig::fromString($keypair); $armored_text = base64_encode($text); return array( -- cgit v1.2.3-54-g00ecf