3 * StatusNet - the distributed open-source microblogging tool
4 * Copyright (C) 2010, StatusNet, Inc.
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 * @package OStatusPlugin
22 * @author James Walker <james@status.net>
25 if (!defined('STATUSNET')) {
29 class SalmonAction extends Action
35 function prepare($args)
37 StatusNet::setApi(true); // Send smaller error pages
39 parent::prepare($args);
41 if ($_SERVER['REQUEST_METHOD'] != 'POST') {
42 // TRANS: Client error. POST is a HTTP command. It should not be translated.
43 $this->clientError(_m('This method requires a POST.'));
46 if (empty($_SERVER['CONTENT_TYPE']) || $_SERVER['CONTENT_TYPE'] != 'application/magic-envelope+xml') {
47 // TRANS: Client error. Do not translate "application/magic-envelope+xml"
48 $this->clientError(_m('Salmon requires "application/magic-envelope+xml".'));
51 $xml = file_get_contents('php://input');
53 // Check the signature
55 if (!$salmon->verifyMagicEnv($xml)) {
56 common_log(LOG_DEBUG, "Salmon signature verification failed.");
57 // TRANS: Client error.
58 $this->clientError(_m('Salmon signature verification failed.'));
60 $magic_env = new MagicEnvelope();
61 $env = $magic_env->parse($xml);
62 $xml = $magic_env->unfold($env);
65 $dom = DOMDocument::loadXML($xml);
66 if ($dom->documentElement->namespaceURI != Activity::ATOM ||
67 $dom->documentElement->localName != 'entry') {
68 common_log(LOG_DEBUG, "Got invalid Salmon post: $xml");
69 // TRANS: Client error.
70 $this->clientError(_m('Salmon post must be an Atom entry.'));
73 $this->activity = new Activity($dom->documentElement);
78 * Check the posted activity type and break out to appropriate processing.
81 function handle($args)
83 StatusNet::setApi(true); // Send smaller error pages
85 common_log(LOG_DEBUG, "Got a " . $this->activity->verb);
86 if (Event::handle('StartHandleSalmonTarget', array($this->activity, $this->target)) &&
87 Event::handle('StartHandleSalmon', array($this->activity))) {
88 switch ($this->activity->verb)
90 case ActivityVerb::POST:
93 case ActivityVerb::SHARE:
96 case ActivityVerb::FAVORITE:
97 $this->handleFavorite();
99 case ActivityVerb::UNFAVORITE:
100 $this->handleUnfavorite();
102 case ActivityVerb::FOLLOW:
103 case ActivityVerb::FRIEND:
104 $this->handleFollow();
106 case ActivityVerb::UNFOLLOW:
107 $this->handleUnfollow();
109 case ActivityVerb::JOIN:
112 case ActivityVerb::LEAVE:
113 $this->handleLeave();
115 case ActivityVerb::UPDATE_PROFILE:
116 $this->handleUpdateProfile();
119 // TRANS: Client exception.
120 throw new ClientException(_m("Unrecognized activity type."));
122 Event::handle('EndHandleSalmon', array($this->activity));
123 Event::handle('EndHandleSalmonTarget', array($this->activity, $this->target));
127 function handlePost()
129 // TRANS: Client exception.
130 throw new ClientException(_m("This target doesn't understand posts."));
133 function handleFollow()
135 // TRANS: Client exception.
136 throw new ClientException(_m("This target doesn't understand follows."));
139 function handleUnfollow()
141 // TRANS: Client exception.
142 throw new ClientException(_m("This target doesn't understand unfollows."));
145 function handleFavorite()
147 // TRANS: Client exception.
148 throw new ClientException(_m("This target doesn't understand favorites."));
151 function handleUnfavorite()
153 // TRANS: Client exception.
154 throw new ClientException(_m("This target doesn't understand unfavorites."));
157 function handleShare()
159 // TRANS: Client exception.
160 throw new ClientException(_m("This target doesn't understand share events."));
163 function handleJoin()
165 // TRANS: Client exception.
166 throw new ClientException(_m("This target doesn't understand joins."));
169 function handleLeave()
171 // TRANS: Client exception.
172 throw new ClientException(_m("This target doesn't understand leave events."));
176 * Remote user sent us an update to their profile.
177 * If we already know them, accept the updates.
179 function handleUpdateProfile()
181 $oprofile = Ostatus_profile::getActorProfile($this->activity);
183 common_log(LOG_INFO, "Got a profile-update ping from $oprofile->uri");
184 $oprofile->updateFromActivityObject($this->activity->actor);
186 common_log(LOG_INFO, "Ignoring profile-update ping from unknown " . $this->activity->actor->id);
191 * @return Ostatus_profile
193 function ensureProfile()
195 $actor = $this->activity->actor;
196 if (empty($actor->id)) {
197 common_log(LOG_ERR, "broken actor: " . var_export($actor, true));
198 common_log(LOG_ERR, "activity with no actor: " . var_export($this->activity, true));
200 throw new Exception(_m('Received a salmon slap from unidentified actor.'));
203 return Ostatus_profile::ensureActivityObjectProfile($actor);
206 function saveNotice()
208 $oprofile = $this->ensureProfile();
209 return $oprofile->processPost($this->activity, 'salmon');