superblock EN-GB translation THX AndyH3
[friendica-addons.git/.git] / diaspora / Diaspora_Connection.php
1 <?php
2 /**
3  * Super-skeletal class to interact with Diaspora.
4  *
5  * @author Meitar Moscovitz <meitarm@gmail.com>
6  * Modifications by Michael Vogel <heluecht@pirati.ca>
7  */
8
9 class Diaspora_Connection {
10         private $user;
11         private $host;
12         private $password;
13         private $tls = true; //< Whether to use an SSL/TLS connection or not.
14
15         private $last_http_result; //< Result of last cURL transaction.
16         private $csrf_token; //< Authenticity token retrieved from last HTTP response.
17         private $http_method; //< Which HTTP verb to use for the next HTTP request.
18         private $cookiejar;
19
20         private $debug_log;
21
22         public $provider = '*Diaspora Connection';
23
24         public function __construct($diaspora_handle = '', $password = '') {
25                 if (!empty($diaspora_handle)) {
26                         $this->setDiasporaID($diaspora_handle);
27                 }
28                 if (!empty($password)) {
29                         $this->setPassword($password);
30                 }
31
32                 $this->cookiejar = tempnam(get_temppath(), 'cookies');
33                 return $this;
34         }
35
36         public function __destruct() {
37                 if (file_exists($this->cookiejar)) {
38                         unlink($this->cookiejar);
39                 }
40         }
41
42         public function setDebugLog($log_file) {
43                 $this->debug_log = $log_file;
44         }
45
46         public function setDiasporaID($id) {
47                 $parts = explode('@', $id);
48                 $this->user = $parts[0];
49                 if (count($parts) > 1) {
50                         $this->host = $parts[1];
51                 } else {
52                         $this->host = '';
53                 }
54         }
55
56         public function getDiasporaID() {
57                 return $this->user . '@' . $this->host;
58         }
59
60         public function getPodURL() {
61                 return $this->getScheme() . '://' . $this->host;
62         }
63
64         public function setPassword($passwd) {
65                 $this->password = $passwd;
66         }
67
68         public function setSecureTransport($is_secure) {
69                 $this->tls = (bool) $is_secure;
70         }
71
72         private function getScheme() {
73                 return ($this->tls) ? 'https' : 'http';
74         }
75
76         private function doHttpRequest($url, $data = [], $headers = []) {
77                 if (0 === strpos($url, '/')) {
78                         $url = $this->getScheme() . '://' . $this->host . $url;
79                 }
80
81                 $ch = curl_init($url);
82
83                 if ($this->debug_log) {
84                         curl_setopt($ch, CURLOPT_VERBOSE, true);
85                         $fh = fopen($this->debug_log, 'a');
86                         curl_setopt($ch, CURLOPT_STDERR, $fh);
87                 }
88
89                 curl_setopt($ch, CURLOPT_HEADER, true);
90                 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
91
92                 if (!empty($data)) {
93                         curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
94                 }
95                 if (!empty($headers)) {
96                         curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
97                 }
98
99                 curl_setopt($ch, CURLOPT_COOKIEJAR, $this->cookiejar);
100                 curl_setopt($ch, CURLOPT_COOKIEFILE, $this->cookiejar);
101
102                 // Are we doing a special kind of HTTP request?
103                 switch ($this->http_method) {
104                         case 'DELETE':
105                                 curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->http_method);
106                                 break;
107                         case 'POST':
108                                 curl_setopt($ch, CURLOPT_POST, true);
109                                 break;
110                 }
111
112                 $this->last_http_result = new stdClass();
113                 $this->last_http_result->response = curl_exec($ch);
114                 $this->last_http_result->info = curl_getinfo($ch);
115                 curl_close($ch);
116                 if (isset($fh)) {
117                         fclose($fh);
118                 }
119
120                 // Maybe update CSRF token
121                 $token = $this->parseAuthenticityToken($this->last_http_result->response);
122                 if ($token) {
123                         $this->csrf_token = $token;
124                 }
125
126                 return $this->last_http_result;
127         }
128
129         private function doHttpDelete($url, $data = [], $headers = []) {
130                 $this->http_method = 'DELETE';
131                 $this->doHttpRequest($url, $data, $headers);
132                 $this->http_method = null; // reset for next request
133         }
134
135         private function parseAuthenticityToken($str) {
136                 $m = [];
137                 preg_match('/<meta (?:name="csrf-token" content="(.*?)"|content="(.*?)" name="csrf-token")/', $str, $m);
138                 if (empty($m[1]) && !empty($m[2])) {
139                         $token = $m[2];
140                 } elseif (!empty($m[1])) {
141                         $token = $m[1];
142                 }
143                 return !empty($token) ? $token : false;
144         }
145
146         private function readJsonResponse($response) {
147                 $lines = explode("\r\n", $response);
148                 $x = array_splice(
149                         $lines, array_search('', $lines) + 1 // empty, as "\r\n" was explode()'d
150                 );
151                 $http_body = array_pop($x);
152                 return json_decode($http_body);
153         }
154
155         public function logIn() {
156                 $this->doHttpRequest('/users/sign_in');
157
158                 $params = [
159                         'user[username]' => $this->user,
160                         'user[password]' => $this->password,
161                         'authenticity_token' => $this->csrf_token
162                 ];
163                 $this->doHttpRequest('/users/sign_in', $params);
164                 $this->doHttpRequest('/stream');
165                 return (200 === $this->last_http_result->info['http_code']) ? true : false;
166         }
167
168         public function getAspects() {
169                 $this->doHttpRequest('/bookmarklet');
170                 $m = [];
171                 preg_match('/"aspects"\:(\[.+?\])/', $this->last_http_result->response, $m);
172                 return !empty($m[1]) ? json_decode($m[1]) : false;
173         }
174
175         public function getServices() {
176                 $this->doHttpRequest('/bookmarklet');
177                 $m = [];
178                 preg_match('/"configured_services"\:(\[.+?\])/', $this->last_http_result->response, $m);
179                 return !empty($m[1]) ? json_decode($m[1]) : false;
180         }
181
182         public function getNotifications($notification_type = '', $show = '') {
183                 $url = '/notifications?format=json';
184
185                 if (!empty($notification_type)) {
186                         $url .= "&type=$notification_type";
187                 }
188
189                 if ('unread' === $show) {
190                         $url .= '&show=unread';
191                 }
192
193                 $this->doHttpRequest($url);
194                 return $this->readJsonResponse($this->last_http_result->response);
195         }
196
197         public function getComments($post_id) {
198                 $url = "/posts/$post_id/comments?format=json";
199                 $this->doHttpRequest($url);
200                 return $this->readJsonResponse($this->last_http_result->response);
201         }
202
203         public function postStatusMessage($msg, $aspect_ids = 'all_aspects', $additional_data = []) {
204                 $data = [
205                         'aspect_ids' => $aspect_ids,
206                         'status_message' => [
207                                 'text' => $msg,
208                                 'provider_display_name' => $this->provider
209                         ]
210                 ];
211
212                 if (!empty($additional_data)) {
213                         $data += $additional_data;
214                 }
215
216                 $headers = [
217                         'Content-Type: application/json',
218                         'Accept: application/json',
219                         'X-CSRF-Token: ' . $this->csrf_token
220                 ];
221
222                 $this->http_method = 'POST';
223                 $this->doHttpRequest('/status_messages', json_encode($data), $headers);
224                 $this->http_method = null; // reset for next request
225                 if (201 !== $this->last_http_result->info['http_code']) {
226                         // TODO: Handle error.
227                         return false;
228                 } elseif (200 !== $this->last_http_result->info['http_code']) {
229                         $resp = $this->readJsonResponse($this->last_http_result->response);
230                         return $resp->id;
231                 }
232         }
233
234         public function postPhoto($file) {
235                 $params = [
236                         'photo[pending]' => 'true',
237                         'qqfile' => basename($file)
238                 ];
239                 $query_string = '?' . http_build_query($params);
240                 $headers = [
241                         'Accept: application/json',
242                         'X-Requested-With: XMLHttpRequest',
243                         'X-CSRF-Token: ' . $this->csrf_token,
244                         'X-File-Name: ' . basename($file),
245                         'Content-Type: application/octet-stream',
246                 ];
247                 if ($size = @filesize($file)) {
248                         $headers[] = "Content-Length: $size";
249                 }
250                 $data = file_get_contents($file);
251                 $this->doHttpRequest('/photos' . $query_string, $data, $headers);
252                 return $this->readJsonResponse($this->last_http_result->response);
253         }
254
255         public function deletePost($id) {
256                 $headers = ['X-CSRF-Token: ' . $this->csrf_token];
257                 $this->doHttpDelete("/posts/$id", [], $headers);
258                 return (204 === $this->last_http_result->info['http_code']) ? true : false;
259         }
260
261         public function deleteComment($id) {
262                 $headers = ['X-CSRF-Token: ' . $this->csrf_token];
263                 $this->doHttpDelete("/comments/$id", [], $headers);
264                 return (204 === $this->last_http_result->info['http_code']) ? true : false;
265         }
266
267 }