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