parent::prepare($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
- $this->clientError(_('This method requires a POST.'));
+ $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') {
+ $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.");
+ $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");
$this->clientError(_m('Salmon post must be an Atom entry.'));
}
- // XXX: check the signature
$this->act = 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->act->verb);
if (Event::handle('StartHandleSalmon', array($this->activity))) {
switch ($this->act->verb)
{
case ActivityVerb::JOIN:
$this->handleJoin();
break;
+ case ActivityVerb::LEAVE:
+ $this->handleLeave();
+ break;
+ case ActivityVerb::UPDATE_PROFILE:
+ $this->handleUpdateProfile();
+ break;
default:
- throw new ClientException(_("Unimplemented."));
+ throw new ClientException(_m("Unrecognized activity type."));
}
Event::handle('EndHandleSalmon', array($this->activity));
}
function handlePost()
{
- throw new ClientException(_("Unimplemented!"));
+ throw new ClientException(_m("This target doesn't understand posts."));
}
function handleFollow()
{
- throw new ClientException(_("Unimplemented!"));
+ throw new ClientException(_m("This target doesn't understand follows."));
}
function handleUnfollow()
{
- throw new ClientException(_("Unimplemented!"));
+ throw new ClientException(_m("This target doesn't understand unfollows."));
}
function handleFavorite()
{
- throw new ClientException(_("Unimplemented!"));
+ 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!"));
+ throw new ClientException(_m("This target doesn't understand unfavorites."));
}
- /**
- * Hmmmm
- */
function handleShare()
{
- throw new ClientException(_("Unimplemented!"));
+ throw new ClientException(_m("This target doesn't understand share events."));
}
- /**
- * Hmmmm
- */
function handleJoin()
{
- throw new ClientException(_("Unimplemented!"));
+ throw new ClientException(_m("This target doesn't understand joins."));
+ }
+
+ function handleLeave()
+ {
+ throw new ClientException(_m("This target doesn't understand leave events."));
}
/**
- * @return Ostatus_profile
+ * Remote user sent us an update to their profile.
+ * If we already know them, accept the updates.
*/
- function ensureProfile()
+ function handleUpdateProfile()
{
- $actor = $this->act->actor;
- if (empty($actor->id)) {
- common_log(LOG_ERR, "broken actor: " . var_export($actor, true));
- throw new Exception("Received a salmon slap from unidentified actor.");
+ $oprofile = Ostatus_profile::getActorProfile($this->act);
+ if ($oprofile) {
+ common_log(LOG_INFO, "Got a profile-update ping from $oprofile->uri");
+ $oprofile->updateFromActivityObject($this->act->actor);
+ } else {
+ common_log(LOG_INFO, "Ignoring profile-update ping from unknown " . $this->act->actor->id);
}
-
- return Ostatus_profile::ensureActorProfile($this->act);
}
/**
- * @fixme merge into Ostatus_profile::ensureActorProfile and friends
+ * @return Ostatus_profile
*/
- function createProfile()
+ function ensureProfile()
{
$actor = $this->act->actor;
-
- $profile = new Profile();
-
- $profile->nickname = $this->nicknameFromURI($actor->id);
-
- if (empty($profile->nickname)) {
- $profile->nickname = common_nicknamize($actor->title);
- }
-
- $profile->fullname = $actor->title;
- $profile->bio = $actor->summary; // XXX: is that right?
- $profile->profileurl = $actor->link; // XXX: is that right?
- $profile->created = common_sql_now();
-
- $id = $profile->insert();
-
- if (empty($id)) {
- common_log_db_error($profile, 'INSERT', __FILE__);
- throw new Exception("Couldn't save new profile for $actor->id\n");
- }
-
- // XXX: add avatars
-
- $op = new Ostatus_profile();
-
- $op->profile_id = $id;
- $op->homeuri = $actor->id;
- $op->created = $profile->created;
-
- // XXX: determine feed URI from source or Webfinger or whatever
-
- $id = $op->insert();
-
- if (empty($id)) {
- common_log_db_error($op, 'INSERT', __FILE__);
- throw new Exception("Couldn't save new ostatus profile for $actor->id\n");
+ 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.");
}
- return $profile;
+ return Ostatus_profile::ensureActivityObjectProfile($actor);
}
- /**
- * @fixme should be merged into Ostatus_profile
- */
- function nicknameFromURI($uri)
+ function saveNotice()
{
- preg_match('/(\w+):/', $uri, $matches);
-
- $protocol = $matches[1];
-
- switch ($protocol) {
- case 'acct':
- case 'mailto':
- if (preg_match("/^$protocol:(.*)?@.*\$/", $uri, $matches)) {
- return common_canonical_nickname($matches[1]);
- }
- return null;
- case 'http':
- return common_url_to_nickname($uri);
- break;
- default:
- return null;
- }
+ $oprofile = $this->ensureProfile();
+ return $oprofile->processPost($this->act, 'salmon');
}
}