parent::prepare($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
- $this->clientError(_('This method requires a POST.'));
+ // TRANS: Client error. POST is a HTTP command. It should not be translated.
+ $this->clientError(_m('This method requires a POST.'));
}
- if ($_SERVER['CONTENT_TYPE'] != 'application/atom+xml') {
- $this->clientError(_('Salmon requires application/atom+xml'));
+ if (empty($_SERVER['CONTENT_TYPE']) || $_SERVER['CONTENT_TYPE'] != 'application/magic-envelope+xml') {
+ // TRANS: Client error. Do not translate "application/magic-envelope+xml"
+ $this->clientError(_m('Salmon requires "application/magic-envelope+xml".'));
}
$xml = file_get_contents('php://input');
- $dom = DOMDocument::loadXML($xml);
+ // Check the signature
+ $salmon = new Salmon;
+ if (!$salmon->verifyMagicEnv($xml)) {
+ common_log(LOG_DEBUG, "Salmon signature verification failed.");
+ // TRANS: Client error.
+ $this->clientError(_m('Salmon signature verification failed.'));
+ } else {
+ $magic_env = new MagicEnvelope();
+ $env = $magic_env->parse($xml);
+ $xml = $magic_env->unfold($env);
+ }
+ $dom = DOMDocument::loadXML($xml);
if ($dom->documentElement->namespaceURI != Activity::ATOM ||
$dom->documentElement->localName != 'entry') {
common_log(LOG_DEBUG, "Got invalid Salmon post: $xml");
+ // TRANS: Client error.
$this->clientError(_m('Salmon post must be an Atom entry.'));
}
- // XXX: check the signature
- $this->act = new Activity($dom->documentElement);
+ $this->activity = new Activity($dom->documentElement);
return true;
}
{
StatusNet::setApi(true); // Send smaller error pages
- // TODO : Insert new $xml -> notice code
-
+ common_log(LOG_DEBUG, "Got a " . $this->activity->verb);
if (Event::handle('StartHandleSalmon', array($this->activity))) {
- switch ($this->act->verb)
+ switch ($this->activity->verb)
{
case ActivityVerb::POST:
$this->handlePost();
case ActivityVerb::JOIN:
$this->handleJoin();
break;
+ case ActivityVerb::LEAVE:
+ $this->handleLeave();
+ break;
+ case ActivityVerb::UPDATE_PROFILE:
+ $this->handleUpdateProfile();
+ break;
default:
- throw new ClientException(_("Unimplemented."));
+ // TRANS: Client exception.
+ throw new ClientException(_m("Unrecognized activity type."));
}
Event::handle('EndHandleSalmon', array($this->activity));
}
function handlePost()
{
- throw new ClientException(_("Unimplemented!"));
+ // TRANS: Client exception.
+ throw new ClientException(_m("This target doesn't understand posts."));
}
function handleFollow()
{
- throw new ClientException(_("Unimplemented!"));
+ // TRANS: Client exception.
+ throw new ClientException(_m("This target doesn't understand follows."));
}
function handleUnfollow()
{
- throw new ClientException(_("Unimplemented!"));
+ // TRANS: Client exception.
+ throw new ClientException(_m("This target doesn't understand unfollows."));
}
function handleFavorite()
{
- throw new ClientException(_("Unimplemented!"));
+ // TRANS: Client exception.
+ throw new ClientException(_m("This target doesn't understand favorites."));
}
- /**
- * Remote user doesn't like one of our posts after all!
- * Confirm the post is ours, and delete a local favorite event.
- */
-
function handleUnfavorite()
{
- throw new ClientException(_("Unimplemented!"));
+ // TRANS: Client exception.
+ throw new ClientException(_m("This target doesn't understand unfavorites."));
}
- /**
- * Hmmmm
- */
function handleShare()
{
- throw new ClientException(_("Unimplemented!"));
+ // TRANS: Client exception.
+ throw new ClientException(_m("This target doesn't understand share events."));
+ }
+
+ function handleJoin()
+ {
+ // TRANS: Client exception.
+ throw new ClientException(_m("This target doesn't understand joins."));
+ }
+
+ function handleLeave()
+ {
+ // TRANS: Client exception.
+ throw new ClientException(_m("This target doesn't understand leave events."));
}
/**
- * Hmmmm
+ * Remote user sent us an update to their profile.
+ * If we already know them, accept the updates.
*/
- function handleJoin()
+ function handleUpdateProfile()
{
- throw new ClientException(_("Unimplemented!"));
+ $oprofile = Ostatus_profile::getActorProfile($this->activity);
+ if ($oprofile) {
+ common_log(LOG_INFO, "Got a profile-update ping from $oprofile->uri");
+ $oprofile->updateFromActivityObject($this->activity->actor);
+ } else {
+ common_log(LOG_INFO, "Ignoring profile-update ping from unknown " . $this->activity->actor->id);
+ }
}
/**
*/
function ensureProfile()
{
- $actor = $this->act->actor;
+ $actor = $this->activity->actor;
if (empty($actor->id)) {
common_log(LOG_ERR, "broken actor: " . var_export($actor, true));
- common_log(LOG_ERR, "activity with no actor: " . var_export($this->act, true));
- throw new Exception("Received a salmon slap from unidentified actor.");
+ common_log(LOG_ERR, "activity with no actor: " . var_export($this->activity, true));
+ // TRANS: Exception.
+ throw new Exception(_m('Received a salmon slap from unidentified actor.'));
}
return Ostatus_profile::ensureActivityObjectProfile($actor);
function saveNotice()
{
$oprofile = $this->ensureProfile();
-
- // Get (safe!) HTML and text versions of the content
-
- require_once(INSTALLDIR.'/extlib/HTMLPurifier/HTMLPurifier.auto.php');
-
- $html = $this->act->object->content;
-
- $purifier = new HTMLPurifier();
-
- $rendered = $purifier->purify($html);
-
- $content = html_entity_decode(strip_tags($rendered));
-
- $options = array('is_local' => Notice::REMOTE_OMB,
- 'uri' => $this->act->object->id,
- 'url' => $this->act->object->link,
- 'rendered' => $rendered,
- 'replies' => $this->act->context->attention);
-
- if (!empty($this->act->context->location)) {
- $options['lat'] = $location->lat;
- $options['lon'] = $location->lon;
- if ($location->location_id) {
- $options['location_ns'] = $location->location_ns;
- $options['location_id'] = $location->location_id;
- }
- }
-
- if (!empty($this->act->context->replyToID)) {
- $orig = Notice::staticGet('uri',
- $this->act->context->replyToID);
- if (!empty($orig)) {
- $options['reply_to'] = $orig->id;
- }
- }
-
- if (!empty($this->act->time)) {
- $options['created'] = common_sql_date($this->act->time);
- }
-
- $saved = Notice::saveNew($oprofile->profile_id,
- $content,
- 'ostatus+salmon',
- $options);
-
- // Record that this was saved through a validated Salmon source
- // @fixme actually do the signature validation!
- Ostatus_source::saveNew($saved, $oprofile, 'salmon');
- return $saved;
+ return $oprofile->processPost($this->activity, 'salmon');
}
}