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