]> git.mxchange.org Git - friendica.git/blob - mod/dfrn_notify.php
Merge branch 'fabrixxm-master'
[friendica.git] / mod / dfrn_notify.php
1 <?php
2
3 require_once('simplepie/simplepie.inc');
4 require_once('include/items.php');
5
6
7 function dfrn_notify_post(&$a) {
8
9         $dfrn_id      = ((x($_POST,'dfrn_id'))      ? notags(trim($_POST['dfrn_id']))   : '');
10         $dfrn_version = ((x($_POST,'dfrn_version')) ? (float) $_POST['dfrn_version']    : 2.0);
11         $challenge    = ((x($_POST,'challenge'))    ? notags(trim($_POST['challenge'])) : '');
12         $data         = ((x($_POST,'data'))         ? $_POST['data']                    : '');
13         $key          = ((x($_POST,'key'))          ? $_POST['key']                     : '');
14         $dissolve     = ((x($_POST,'dissolve'))     ? intval($_POST['dissolve'])        :  0);
15
16         $direction = (-1);
17         if(strpos($dfrn_id,':') == 1) {
18                 $direction = intval(substr($dfrn_id,0,1));
19                 $dfrn_id = substr($dfrn_id,2);
20         }
21
22         $r = q("SELECT * FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s' LIMIT 1",
23                 dbesc($dfrn_id),
24                 dbesc($challenge)
25         );
26         if(! count($r)) {
27                 logger('dfrn_notify: could not match challenge to dfrn_id ' . $dfrn_id . ' challenge=' . $challenge);
28                 xml_status(3);
29         }
30
31         $r = q("DELETE FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s' LIMIT 1",
32                 dbesc($dfrn_id),
33                 dbesc($challenge)
34         );
35
36         // find the local user who owns this relationship.
37
38         $sql_extra = '';
39         switch($direction) {
40                 case (-1):
41                         $sql_extra = sprintf(" AND ( `issued-id` = '%s' OR `dfrn-id` = '%s' ) ", dbesc($dfrn_id), dbesc($dfrn_id));
42                         break;
43                 case 0:
44                         $sql_extra = sprintf(" AND `issued-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id));
45                         break;
46                 case 1:
47                         $sql_extra = sprintf(" AND `dfrn-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id));
48                         break;
49                 default:
50                         xml_status(3);
51                         break; // NOTREACHED
52         }
53                  
54
55         $r = q("SELECT `contact`.*, `contact`.`uid` AS `importer_uid`, 
56                 `contact`.`pubkey` AS `cpubkey`, `contact`.`prvkey` AS `cprvkey`, `user`.* FROM `contact` 
57                 LEFT JOIN `user` ON `contact`.`uid` = `user`.`uid` 
58                 WHERE `contact`.`blocked` = 0 AND `contact`.`pending` = 0 
59                 AND `user`.`nickname` = '%s' $sql_extra LIMIT 1",
60                 dbesc($a->argv[1])
61         );
62
63         if(! count($r)) {
64                 logger('dfrn_notify: contact not found for dfrn_id ' . $dfrn_id);
65                 xml_status(3);
66                 //NOTREACHED
67         }
68
69         // $importer in this case contains the contact record for the remote contact joined with the user record of our user. 
70
71         $importer = $r[0];
72
73         logger('dfrn_notify: received notify from ' . $importer['name'] . ' for ' . $importer['username']);
74         logger('dfrn_notify: data: ' . $data, LOGGER_DATA);
75
76         if($dissolve == 1) {
77
78                 /**
79                  * Relationship is dissolved permanently
80                  */
81
82                 require_once('include/Contact.php'); 
83                 contact_remove($importer['id']);
84                 logger('relationship dissolved : ' . $importer['name'] . ' dissolved ' . $importer['username']);
85                 xml_status(0);
86
87         }
88
89         if(strlen($key)) {
90                 $rawkey = hex2bin(trim($key));
91                 logger('rino: md5 raw key: ' . md5($rawkey));
92                 $final_key = '';
93
94                 if($dfrn_version >= 2.1) {
95                         if((($importer['duplex']) && strlen($importer['cprvkey'])) || (! strlen($importer['cpubkey']))) {
96                                 openssl_private_decrypt($rawkey,$final_key,$importer['cprvkey']);
97                         }
98                         else {
99                                 openssl_public_decrypt($rawkey,$final_key,$importer['cpubkey']);
100                         }
101                 }
102                 else {
103                         if((($importer['duplex']) && strlen($importer['cpubkey'])) || (! strlen($importer['cprvkey']))) {
104                                 openssl_public_decrypt($rawkey,$final_key,$importer['cpubkey']);
105                         }
106                         else {
107                                 openssl_private_decrypt($rawkey,$final_key,$importer['cprvkey']);
108                         }
109                 }
110
111                 logger('rino: received key : ' . $final_key);
112                 $data = aes_decrypt(hex2bin($data),$final_key);
113                 logger('rino: decrypted data: ' . $data, LOGGER_DATA);
114         }
115
116
117
118
119         if($importer['readonly']) {
120                 // We aren't receiving stuff from this person. But we will quietly ignore them
121                 // rather than a blatant "go away" message.
122                 logger('dfrn_notify: ignoring');
123                 xml_status(0);
124                 //NOTREACHED
125         }
126
127         // Consume notification feed. This may differ from consuming a public feed in several ways
128         // - might contain email
129         // - might contain remote followup to our message
130         //              - in which case we need to accept it and then notify other conversants
131         // - we may need to send various email notifications
132
133         $feed = new SimplePie();
134         $feed->set_raw_data($data);
135         $feed->enable_order_by_date(false);
136         $feed->init();
137
138         $ismail = false;
139
140         $rawmail = $feed->get_feed_tags( NAMESPACE_DFRN, 'mail' );
141         if(isset($rawmail[0]['child'][NAMESPACE_DFRN])) {
142
143                 logger('dfrn_notify: private message received');
144
145                 $ismail = true;
146                 $base = $rawmail[0]['child'][NAMESPACE_DFRN];
147
148                 $msg = array();
149                 $msg['uid'] = $importer['importer_uid'];
150                 $msg['from-name'] = notags(unxmlify($base['sender'][0]['child'][NAMESPACE_DFRN]['name'][0]['data']));
151                 $msg['from-photo'] = notags(unxmlify($base['sender'][0]['child'][NAMESPACE_DFRN]['avatar'][0]['data']));
152                 $msg['from-url'] = notags(unxmlify($base['sender'][0]['child'][NAMESPACE_DFRN]['uri'][0]['data']));
153                 $msg['contact-id'] = $importer['id'];
154                 $msg['title'] = notags(unxmlify($base['subject'][0]['data']));
155                 $msg['body'] = escape_tags(unxmlify($base['content'][0]['data']));
156                 $msg['seen'] = 0;
157                 $msg['replied'] = 0;
158                 $msg['uri'] = notags(unxmlify($base['id'][0]['data']));
159                 $msg['parent-uri'] = notags(unxmlify($base['in-reply-to'][0]['data']));
160                 $msg['created'] = datetime_convert(notags(unxmlify('UTC','UTC',$base['sentdate'][0]['data'])));
161                 
162                 dbesc_array($msg);
163
164                 $r = dbq("INSERT INTO `mail` (`" . implode("`, `", array_keys($msg)) 
165                         . "`) VALUES ('" . implode("', '", array_values($msg)) . "')" );
166
167                 // send email notification if requested.
168
169                 require_once('bbcode.php');
170                 if($importer['notify-flags'] & NOTIFY_MAIL) {
171
172                         $body = html_entity_decode(strip_tags(bbcode(stripslashes($msg['body']))),ENT_QUOTES,'UTF-8');
173
174                         if(function_exists('quoted_printable_encode'))
175                                 $body = quoted_printable_encode($body);
176                         else
177                                 $body = qp($body);
178
179                         $tpl = load_view_file('view/mail_received_eml.tpl');                    
180                         $email_tpl = replace_macros($tpl, array(
181                                 '$sitename' => $a->config['sitename'],
182                                 '$siteurl' =>  $a->get_baseurl(),
183                                 '$username' => $importer['username'],
184                                 '$email' => $importer['email'],
185                                 '$from' => $msg['from-name'],
186                                 '$title' => stripslashes($msg['title']),
187                                 '$body' => $body
188                         ));
189
190                         $res = mail($importer['email'], t('New mail received at ') . $a->config['sitename'],
191                                 $email_tpl, 'From: ' . t('Administrator') . '@' . $a->get_hostname() . "\r\n"
192                                         . 'MIME-Version: 1.0' . "\r\n"
193                                         . 'Content-type: text/plain; charset=UTF-8' . "\r\n" 
194                                         . 'Content-transfer-encoding: quoted-printable' . "\r\n"
195                         );
196                 }
197                 xml_status(0);
198                 // NOTREACHED
199         }       
200         
201         logger('dfrn_notify: feed item count = ' . $feed->get_item_quantity());
202
203         foreach($feed->get_items() as $item) {
204
205                 $deleted = false;
206
207                 $rawdelete = $item->get_item_tags( NAMESPACE_TOMB , 'deleted-entry');
208                 if(isset($rawdelete[0]['attribs']['']['ref'])) {
209                         $uri = $rawthread[0]['attribs']['']['ref'];
210                         $deleted = true;
211                         if(isset($rawdelete[0]['attribs']['']['when'])) {
212                                 $when = $rawthread[0]['attribs']['']['when'];
213                                 $when = datetime_convert('UTC','UTC', $when, 'Y-m-d H:i:s');
214                         }
215                         else
216                                 $when = datetime_convert('UTC','UTC','now','Y-m-d H:i:s');
217                 }
218                 if($deleted) {
219                         $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
220                                 dbesc($uri),
221                                 intval($importer['importer_uid'])
222                         );
223                         if(count($r)) {
224                                 $item = $r[0];
225                                 if($item['uri'] == $item['parent-uri']) {
226                                         $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s'
227                                                 WHERE `parent-uri` = '%s' AND `uid` = %d",
228                                                 dbesc($when),
229                                                 dbesc(datetime_convert()),
230                                                 dbesc($item['uri']),
231                                                 intval($importer['importer_uid'])
232                                         );
233                                 }
234                                 else {
235                                         $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s' 
236                                                 WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
237                                                 dbesc($when),
238                                                 dbesc(datetime_convert()),
239                                                 dbesc($uri),
240                                                 intval($importer['importer_uid'])
241                                         );
242                                         if($item['last-child']) {
243                                                 // ensure that last-child is set in case the comment that had it just got wiped.
244                                                 $q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d ",
245                                                         dbesc(datetime_convert()),
246                                                         dbesc($item['parent-uri']),
247                                                         intval($item['uid'])
248                                                 );
249                                                 // who is the last child now? 
250                                                 $r = q("SELECT `id` FROM `item` WHERE `parent-uri` = '%s' AND `type` != 'activity' AND `deleted` = 0 AND `uid` = %d
251                                                         ORDER BY `created` DESC LIMIT 1",
252                                                                 dbesc($item['parent-uri']),
253                                                                 intval($importer['importer_uid'])
254                                                 );
255                                                 if(count($r)) {
256                                                         q("UPDATE `item` SET `last-child` = 1 WHERE `id` = %d LIMIT 1",
257                                                                 intval($r[0]['id'])
258                                                         );
259                                                 }       
260                                         }
261                                 }
262                         }       
263                         continue;
264                 }
265
266                 $is_reply = false;              
267                 $item_id = $item->get_id();
268                 $rawthread = $item->get_item_tags( NAMESPACE_THREAD, 'in-reply-to');
269                 if(isset($rawthread[0]['attribs']['']['ref'])) {
270                         $is_reply = true;
271                         $parent_uri = $rawthread[0]['attribs']['']['ref'];
272                 }
273
274                 if($is_reply) {
275                         if($feed->get_item_quantity() == 1) {
276                                 logger('dfrn_notify: received remote comment');
277                                 $is_like = false;
278                                 // remote reply to our post. Import and then notify everybody else.
279                                 $datarray = get_atom_elements($feed,$item);
280                                 $datarray['type'] = 'remote-comment';
281                                 $datarray['wall'] = 1;
282                                 $datarray['parent-uri'] = $parent_uri;
283                                 $datarray['uid'] = $importer['importer_uid'];
284                                 $datarray['contact-id'] = $importer['id'];
285                                 if(($datarray['verb'] == ACTIVITY_LIKE) || ($datarray['verb'] == ACTIVITY_DISLIKE)) {
286                                         $is_like = true;
287                                         $datarray['type'] = 'activity';
288                                         $datarray['gravity'] = GRAVITY_LIKE;
289                                         $datarray['last-child'] = 0;
290                                 }
291                                 $posted_id = item_store($datarray);
292                                 $parent = 0;
293
294                                 if($posted_id) {
295                                         $r = q("SELECT `parent` FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1",
296                                                 intval($posted_id),
297                                                 intval($importer['importer_uid'])
298                                         );
299                                         if(count($r))
300                                                 $parent = $r[0]['parent'];
301                                 
302                                         if(! $is_like) {
303                                                 $r1 = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `uid` = %d AND `parent` = %d",
304                                                         dbesc(datetime_convert()),
305                                                         intval($importer['importer_uid']),
306                                                         intval($r[0]['parent'])
307                                                 );
308
309                                                 $r2 = q("UPDATE `item` SET `last-child` = 1, `changed` = '%s' WHERE `uid` = %d AND `id` = %d LIMIT 1",
310                                                         dbesc(datetime_convert()),
311                                                         intval($importer['importer_uid']),
312                                                         intval($posted_id)
313                                                 );
314                                         }
315
316                                         if($posted_id && $parent) {
317                                 
318                                                 $php_path = ((strlen($a->config['php_path'])) ? $a->config['php_path'] : 'php');
319
320                                                 proc_run($php_path,"include/notifier.php","comment-import","$posted_id");
321                                         
322                                                 if((! $is_like) && ($importer['notify-flags'] & NOTIFY_COMMENT) && (! $importer['self'])) {
323                                                         require_once('bbcode.php');
324                                                         $from = stripslashes($datarray['author-name']);
325                                                         $tpl = load_view_file('view/cmnt_received_eml.tpl');                    
326                                                         $email_tpl = replace_macros($tpl, array(
327                                                                 '$sitename' => $a->config['sitename'],
328                                                                 '$siteurl' =>  $a->get_baseurl(),
329                                                                 '$username' => $importer['username'],
330                                                                 '$email' => $importer['email'],
331                                                                 '$display' => $a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $posted_id, 
332                                                                 '$from' => $from,
333                                                                 '$body' => strip_tags(bbcode(stripslashes($datarray['body'])))
334                                                         ));
335                 
336                                                         $res = mail($importer['email'], $from . t(' commented on an item at ') . $a->config['sitename'],
337                                                                 $email_tpl, "From: " . t('Administrator') . '@' . $a->get_hostname() );
338                                                 }
339                                         }
340
341                                         xml_status(0);
342                                         // NOTREACHED
343                                 }
344                         }
345                         else {
346                                 // regular comment that is part of this total conversation. Have we seen it? If not, import it.
347
348                                 $item_id = $item->get_id();
349
350                                 $r = q("SELECT `uid`, `last-child`, `edited` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
351                                         dbesc($item_id),
352                                         intval($importer['importer_uid'])
353                                 );
354                                 // FIXME update content if 'updated' changes
355                                 if(count($r)) {
356                                         $allow = $item->get_item_tags( NAMESPACE_DFRN, 'comment-allow');
357                                         if($allow && $allow[0]['data'] != $r[0]['last-child']) {
358                                                 $r = q("UPDATE `item` SET `last-child` = %d, `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
359                                                         intval($allow[0]['data']),
360                                                         dbesc(datetime_convert()),
361                                                         dbesc($item_id),
362                                                         intval($importer['importer_uid'])
363                                                 );
364                                         }
365                                         continue;
366                                 }
367                                 $datarray = get_atom_elements($feed,$item);
368                                 $datarray['parent-uri'] = $parent_uri;
369                                 $datarray['uid'] = $importer['importer_uid'];
370                                 $datarray['contact-id'] = $importer['id'];
371                                 if(($datarray['verb'] == ACTIVITY_LIKE) || ($datarray['verb'] == ACTIVITY_DISLIKE)) {
372                                         $datarray['type'] = 'activity';
373                                         $datarray['gravity'] = GRAVITY_LIKE;
374                                 }
375
376                                 $r = item_store($datarray);
377
378                                 // find out if our user is involved in this conversation and wants to be notified.
379                         
380                                 if(($datarray['type'] != 'activity') && ($importer['notify-flags'] & NOTIFY_COMMENT)) {
381
382                                         $myconv = q("SELECT `author-link` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d AND `parent` != 0 ",
383                                                 dbesc($parent_uri),
384                                                 intval($importer['importer_uid'])
385                                         );
386                                         if(count($myconv)) {
387                                                 foreach($myconv as $conv) {
388                                                         if(! link_compare($conv['author-link'],$importer['url']))
389                                                                 continue;
390                                                         require_once('bbcode.php');
391                                                         $from = stripslashes($datarray['author-name']);
392                                                         $tpl = load_view_file('view/cmnt_received_eml.tpl');                    
393                                                         $email_tpl = replace_macros($tpl, array(
394                                                                 '$sitename' => $a->config['sitename'],
395                                                                 '$siteurl' =>  $a->get_baseurl(),
396                                                                 '$username' => $importer['username'],
397                                                                 '$email' => $importer['email'],
398                                                                 '$from' => $from,
399                                                                 '$display' => $a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $r,
400                                                                 '$body' => strip_tags(bbcode(stripslashes($datarray['body'])))
401                                                         ));
402
403                                                         $res = mail($importer['email'], $from . t(" commented on an item at ") 
404                                                                 . $a->config['sitename'],
405                                                                 $email_tpl,t("From: Administrator@") . $a->get_hostname() );
406                                                         break;
407                                                 }
408                                         }
409                                 }
410                                 continue;
411                         }
412                 }
413                 else {
414                         // Head post of a conversation. Have we seen it? If not, import it.
415
416                         $item_id = $item->get_id();
417                         $r = q("SELECT `uid`, `last-child`, `edited` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
418                                 dbesc($item_id),
419                                 intval($importer['importer_uid'])
420                         );
421                         if(count($r)) {
422                                 $allow = $item->get_item_tags( NAMESPACE_DFRN, 'comment-allow');
423                                 if($allow && $allow[0]['data'] != $r[0]['last-child']) {
424                                         $r = q("UPDATE `item` SET `last-child` = %d, `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
425                                                 intval($allow[0]['data']),
426                                                 dbesc(datetime_convert()),
427                                                 dbesc($item_id),
428                                                 intval($importer['importer_uid'])
429                                         );
430                                 }
431                                 continue;
432                         }
433
434
435                         $datarray = get_atom_elements($feed,$item);
436                         $datarray['parent-uri'] = $item_id;
437                         $datarray['uid'] = $importer['importer_uid'];
438                         $datarray['contact-id'] = $importer['id'];
439                         $r = item_store($datarray);
440                         continue;
441                 }
442         }
443
444         xml_status(0);
445         // NOTREACHED
446
447 }
448
449
450 function dfrn_notify_content(&$a) {
451
452         if(x($_GET,'dfrn_id')) {
453
454                 // initial communication from external contact, $direction is their direction.
455                 // If this is a duplex communication, ours will be the opposite.
456
457                 $dfrn_id = notags(trim($_GET['dfrn_id']));
458                 $dfrn_version = (float) $_GET['dfrn_version'];
459
460                 logger('dfrn_notify: new notification dfrn_id=' . $dfrn_id);
461
462                 $direction = (-1);
463                 if(strpos($dfrn_id,':') == 1) {
464                         $direction = intval(substr($dfrn_id,0,1));
465                         $dfrn_id = substr($dfrn_id,2);
466                 }
467
468                 $hash = random_string();
469
470                 $status = 0;
471
472                 $r = q("DELETE FROM `challenge` WHERE `expire` < " . intval(time()));
473
474                 $r = q("INSERT INTO `challenge` ( `challenge`, `dfrn-id`, `expire` )
475                         VALUES( '%s', '%s', %d ) ",
476                         dbesc($hash),
477                         dbesc($dfrn_id),
478                         intval(time() + 90 )
479                 );
480
481                 logger('dfrn_notify: challenge=' . $hash );
482
483                 $sql_extra = '';
484                 switch($direction) {
485                         case (-1):
486                                 $sql_extra = sprintf(" AND ( `issued-id` = '%s' OR `dfrn-id` = '%s' ) ", dbesc($dfrn_id), dbesc($dfrn_id));
487                                 $my_id = $dfrn_id;
488                                 break;
489                         case 0:
490                                 $sql_extra = sprintf(" AND `issued-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id));
491                                 $my_id = '1:' . $dfrn_id;
492                                 break;
493                         case 1:
494                                 $sql_extra = sprintf(" AND `dfrn-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id));
495                                 $my_id = '0:' . $dfrn_id;
496                                 break;
497                         default:
498                                 $status = 1;
499                                 break; // NOTREACHED
500                 }
501
502                 $r = q("SELECT `contact`.*, `user`.`nickname` FROM `contact` LEFT JOIN `user` ON `user`.`uid` = `contact`.`uid` 
503                                 WHERE `contact`.`blocked` = 0 AND `contact`.`pending` = 0 AND `user`.`nickname` = '%s' $sql_extra LIMIT 1",
504                                 dbesc($a->argv[1])
505                 );
506
507                 if(! count($r))
508                         $status = 1;
509
510                 $challenge = '';
511                 $encrypted_id = '';
512                 $id_str = $my_id . '.' . mt_rand(1000,9999);
513
514                 if((($r[0]['duplex']) && strlen($r[0]['prvkey'])) || (! strlen($r[0]['pubkey']))) {
515                         openssl_private_encrypt($hash,$challenge,$r[0]['prvkey']);
516                         openssl_private_encrypt($id_str,$encrypted_id,$r[0]['prvkey']);
517                 }
518                 else {
519                         openssl_public_encrypt($hash,$challenge,$r[0]['pubkey']);
520                         openssl_public_encrypt($id_str,$encrypted_id,$r[0]['pubkey']);
521                 }
522
523                 $challenge    = bin2hex($challenge);
524                 $encrypted_id = bin2hex($encrypted_id);
525
526                 $rino = ((function_exists('mcrypt_encrypt')) ? 1 : 0);
527
528                 $rino_enable = get_config('system','rino_encrypt');
529
530                 if(! $rino_enable)
531                         $rino = 0;
532
533
534                 header("Content-type: text/xml");
535
536                 echo '<?xml version="1.0" encoding="UTF-8"?>' . "\r\n" 
537                         . '<dfrn_notify>' . "\r\n"
538                         . "\t" . '<status>' . $status . '</status>' . "\r\n"
539                         . "\t" . '<dfrn_version>' . DFRN_PROTOCOL_VERSION . '</dfrn_version>' . "\r\n"
540                         . "\t" . '<rino>' . $rino . '</rino>' . "\r\n" 
541                         . "\t" . '<dfrn_id>' . $encrypted_id . '</dfrn_id>' . "\r\n" 
542                         . "\t" . '<challenge>' . $challenge . '</challenge>' . "\r\n"
543                         . '</dfrn_notify>' . "\r\n" ;
544
545                 killme();
546         }
547
548 }