]> git.mxchange.org Git - friendica.git/blob - include/dfrn.php
New routines are now enabled
[friendica.git] / include / dfrn.php
1 <?php
2 require_once('include/items.php');
3 require_once('include/ostatus.php');
4
5 /**
6  * @brief Adds the header elements for the DFRN protocol
7  *
8  * @param array $items Item elements
9  * @param array $owner Owner record
10  *
11  * @return string DFRN entries
12  */
13 function dfrn_entries($items,$owner) {
14
15         $doc = new DOMDocument('1.0', 'utf-8');
16         $doc->formatOutput = true;
17
18         $root = dfrn_add_header($doc, $owner, "dfrn:owner", "", false);
19
20         if(! count($items))
21                 return trim($doc->saveXML());
22
23         foreach($items as $item) {
24                 $entry = dfrn_entry($doc, "text", $item, $owner, $item["entry:comment-allow"], $item["entry:cid"]);
25                 $root->appendChild($entry);
26         }
27
28         return(trim($doc->saveXML()));
29 }
30
31 /**
32  * @brief Adds the header elements for the DFRN protocol
33  *
34  * @param App $a
35  * @param string $dfrn_id
36  * @param string $owner_nick Owner nick name
37  * @param string $last_update Date of the last update
38  * @param int $direction
39  *
40  * @return string DFRN feed entries
41  */
42 function dfrn_feed(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0) {
43
44         $sitefeed    = ((strlen($owner_nick)) ? false : true); // not yet implemented, need to rewrite huge chunks of following logic
45         $public_feed = (($dfrn_id) ? false : true);
46         $starred     = false;   // not yet implemented, possible security issues
47         $converse    = false;
48
49         if($public_feed && $a->argc > 2) {
50                 for($x = 2; $x < $a->argc; $x++) {
51                         if($a->argv[$x] == 'converse')
52                                 $converse = true;
53                         if($a->argv[$x] == 'starred')
54                                 $starred = true;
55                         if($a->argv[$x] === 'category' && $a->argc > ($x + 1) && strlen($a->argv[$x+1]))
56                                 $category = $a->argv[$x+1];
57                 }
58         }
59
60
61
62         // default permissions - anonymous user
63
64         $sql_extra = " AND `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid`  = '' AND `item`.`deny_gid`  = '' ";
65
66         $r = q("SELECT `contact`.*, `user`.`uid` AS `user_uid`, `user`.`nickname`, `user`.`timezone`, `user`.`page-flags`
67                 FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid`
68                 WHERE `contact`.`self` = 1 AND `user`.`nickname` = '%s' LIMIT 1",
69                 dbesc($owner_nick)
70         );
71
72         if(! count($r))
73                 killme();
74
75         $owner = $r[0];
76         $owner_id = $owner['user_uid'];
77         $owner_nick = $owner['nickname'];
78
79         $sql_post_table = "";
80         $visibility = "";
81
82         if(! $public_feed) {
83
84                 $sql_extra = '';
85                 switch($direction) {
86                         case (-1):
87                                 $sql_extra = sprintf(" AND `issued-id` = '%s' ", dbesc($dfrn_id));
88                                 $my_id = $dfrn_id;
89                                 break;
90                         case 0:
91                                 $sql_extra = sprintf(" AND `issued-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id));
92                                 $my_id = '1:' . $dfrn_id;
93                                 break;
94                         case 1:
95                                 $sql_extra = sprintf(" AND `dfrn-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id));
96                                 $my_id = '0:' . $dfrn_id;
97                                 break;
98                         default:
99                                 return false;
100                                 break; // NOTREACHED
101                 }
102
103                 $r = q("SELECT * FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `contact`.`uid` = %d $sql_extra LIMIT 1",
104                         intval($owner_id)
105                 );
106
107                 if(! count($r))
108                         killme();
109
110                 $contact = $r[0];
111                 require_once('include/security.php');
112                 $groups = init_groups_visitor($contact['id']);
113
114                 if(count($groups)) {
115                         for($x = 0; $x < count($groups); $x ++)
116                                 $groups[$x] = '<' . intval($groups[$x]) . '>' ;
117                         $gs = implode('|', $groups);
118                 }
119                 else
120                         $gs = '<<>>' ; // Impossible to match
121
122                 $sql_extra = sprintf("
123                         AND ( `allow_cid` = '' OR     `allow_cid` REGEXP '<%d>' )
124                         AND ( `deny_cid`  = '' OR NOT `deny_cid`  REGEXP '<%d>' )
125                         AND ( `allow_gid` = '' OR     `allow_gid` REGEXP '%s' )
126                         AND ( `deny_gid`  = '' OR NOT `deny_gid`  REGEXP '%s')
127                 ",
128                         intval($contact['id']),
129                         intval($contact['id']),
130                         dbesc($gs),
131                         dbesc($gs)
132                 );
133         }
134
135         if($public_feed)
136                 $sort = 'DESC';
137         else
138                 $sort = 'ASC';
139
140         $date_field = "`changed`";
141         $sql_order = "`item`.`parent` ".$sort.", `item`.`created` ASC";
142
143         if(! strlen($last_update))
144                 $last_update = 'now -30 days';
145
146         if(isset($category)) {
147                 $sql_post_table = sprintf("INNER JOIN (SELECT `oid` FROM `term` WHERE `term` = '%s' AND `otype` = %d AND `type` = %d AND `uid` = %d ORDER BY `tid` DESC) AS `term` ON `item`.`id` = `term`.`oid` ",
148                                 dbesc(protect_sprintf($category)), intval(TERM_OBJ_POST), intval(TERM_CATEGORY), intval($owner_id));
149                 //$sql_extra .= file_tag_file_query('item',$category,'category');
150         }
151
152         if($public_feed) {
153                 if(! $converse)
154                         $sql_extra .= " AND `contact`.`self` = 1 ";
155         }
156
157         $check_date = datetime_convert('UTC','UTC',$last_update,'Y-m-d H:i:s');
158
159         //      AND ( `item`.`edited` > '%s' OR `item`.`changed` > '%s' )
160         //      dbesc($check_date),
161
162         $r = q("SELECT STRAIGHT_JOIN `item`.*, `item`.`id` AS `item_id`,
163                 `contact`.`name`, `contact`.`network`, `contact`.`photo`, `contact`.`url`,
164                 `contact`.`name-date`, `contact`.`uri-date`, `contact`.`avatar-date`,
165                 `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`,
166                 `contact`.`id` AS `contact-id`, `contact`.`uid` AS `contact-uid`,
167                 `sign`.`signed_text`, `sign`.`signature`, `sign`.`signer`
168                 FROM `item` $sql_post_table
169                 INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
170                 AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0
171                 LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id`
172                 WHERE `item`.`uid` = %d AND `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`parent` != 0
173                 AND ((`item`.`wall` = 1) $visibility) AND `item`.$date_field > '%s'
174                 $sql_extra
175                 ORDER BY $sql_order LIMIT 0, 300",
176                 intval($owner_id),
177                 dbesc($check_date),
178                 dbesc($sort)
179         );
180
181         // Will check further below if this actually returned results.
182         // We will provide an empty feed if that is the case.
183
184         $items = $r;
185
186         $doc = new DOMDocument('1.0', 'utf-8');
187         $doc->formatOutput = true;
188
189         $alternatelink = $owner['url'];
190
191         if(isset($category))
192                 $alternatelink .= "/category/".$category;
193
194         if ($public_feed)
195                 $author = "dfrn:owner";
196         else
197                 $author = "author";
198
199         $root = dfrn_add_header($doc, $owner, $author, $alternatelink, true);
200
201         // This hook can't work anymore
202         //      call_hooks('atom_feed', $atom);
203
204         if(! count($items)) {
205                 $atom = trim($doc->saveXML());
206
207                 call_hooks('atom_feed_end', $atom);
208
209                 return $atom;
210         }
211
212         foreach($items as $item) {
213
214                 // prevent private email from leaking.
215                 if($item['network'] === NETWORK_MAIL)
216                         continue;
217
218                 // public feeds get html, our own nodes use bbcode
219
220                 if($public_feed) {
221                         $type = 'html';
222                         // catch any email that's in a public conversation and make sure it doesn't leak
223                         if($item['private'])
224                                 continue;
225                 }
226                 else {
227                         $type = 'text';
228                 }
229
230                 $entry = dfrn_entry($doc, $type, $item, $owner, true);
231                 $root->appendChild($entry);
232
233         }
234
235         $atom = trim($doc->saveXML());
236
237         call_hooks('atom_feed_end', $atom);
238
239         return $atom;
240 }
241
242 /**
243  * @brief Create XML text for DFRN mail
244  *
245  * @param array $item message elements
246  * @param array $owner Owner record
247  *
248  * @return string DFRN mail
249  */
250 function dfrn_mail($item, $owner) {
251         $doc = new DOMDocument('1.0', 'utf-8');
252         $doc->formatOutput = true;
253
254         $root = dfrn_add_header($doc, $owner, "dfrn:owner", "", false);
255
256         $mail = $doc->createElement("dfrn:mail");
257         $sender = $doc->createElement("dfrn:sender");
258
259         xml_add_element($doc, $sender, "dfrn:name", $owner['name']);
260         xml_add_element($doc, $sender, "dfrn:uri", $owner['url']);
261         xml_add_element($doc, $sender, "dfrn:avatar", $owner['thumb']);
262
263         $mail->appendChild($sender);
264
265         xml_add_element($doc, $mail, "dfrn:id", $item['uri']);
266         xml_add_element($doc, $mail, "dfrn:in-reply-to", $item['parent-uri']);
267         xml_add_element($doc, $mail, "dfrn:sentdate", datetime_convert('UTC', 'UTC', $item['created'] . '+00:00' , ATOM_TIME));
268         xml_add_element($doc, $mail, "dfrn:subject", $item['title']);
269         xml_add_element($doc, $mail, "dfrn:content", $item['body']);
270
271         $root->appendChild($mail);
272
273         return(trim($doc->saveXML()));
274 }
275
276 /**
277  * @brief Create XML text for DFRN suggestions
278  *
279  * @param array $item suggestion elements
280  * @param array $owner Owner record
281  *
282  * @return string DFRN suggestions
283  */
284 function dfrn_fsuggest($item, $owner) {
285         $doc = new DOMDocument('1.0', 'utf-8');
286         $doc->formatOutput = true;
287
288         $root = dfrn_add_header($doc, $owner, "dfrn:owner", "", false);
289
290         $suggest = $doc->createElement("dfrn:suggest");
291
292         xml_add_element($doc, $suggest, "dfrn:url", $item['url']);
293         xml_add_element($doc, $suggest, "dfrn:name", $item['name']);
294         xml_add_element($doc, $suggest, "dfrn:photo", $item['photo']);
295         xml_add_element($doc, $suggest, "dfrn:request", $item['request']);
296         xml_add_element($doc, $suggest, "dfrn:note", $item['note']);
297
298         $root->appendChild($suggest);
299
300         return(trim($doc->saveXML()));
301 }
302
303 /**
304  * @brief Create XML text for DFRN relocations
305  *
306  * @param array $owner Owner record
307  * @param int $uid User ID
308  *
309  * @return string DFRN relocations
310  */
311 function dfrn_relocate($owner, $uid) {
312
313         $a = get_app();
314
315         /* get site pubkey. this could be a new installation with no site keys*/
316         $pubkey = get_config('system','site_pubkey');
317         if(! $pubkey) {
318                 $res = new_keypair(1024);
319                 set_config('system','site_prvkey', $res['prvkey']);
320                 set_config('system','site_pubkey', $res['pubkey']);
321         }
322
323         $rp = q("SELECT `resource-id` , `scale`, type FROM `photo`
324                         WHERE `profile` = 1 AND `uid` = %d ORDER BY scale;", $uid);
325         $photos = array();
326         $ext = Photo::supportedTypes();
327         foreach($rp as $p){
328                 $photos[$p['scale']] = $a->get_baseurl().'/photo/'.$p['resource-id'].'-'.$p['scale'].'.'.$ext[$p['type']];
329         }
330         unset($rp, $ext);
331
332         $doc = new DOMDocument('1.0', 'utf-8');
333         $doc->formatOutput = true;
334
335         $root = dfrn_add_header($doc, $owner, "dfrn:owner", "", false);
336
337         $relocate = $doc->createElement("dfrn:relocate");
338
339         xml_add_element($doc, $relocate, "dfrn:url", $owner['url']);
340         xml_add_element($doc, $relocate, "dfrn:name", $owner['name']);
341         xml_add_element($doc, $relocate, "dfrn:photo", $photos[4]);
342         xml_add_element($doc, $relocate, "dfrn:thumb", $photos[5]);
343         xml_add_element($doc, $relocate, "dfrn:micro", $photos[6]);
344         xml_add_element($doc, $relocate, "dfrn:request", $owner['request']);
345         xml_add_element($doc, $relocate, "dfrn:confirm", $owner['confirm']);
346         xml_add_element($doc, $relocate, "dfrn:notify", $owner['notify']);
347         xml_add_element($doc, $relocate, "dfrn:poll", $owner['poll']);
348         xml_add_element($doc, $relocate, "dfrn:sitepubkey", get_config('system','site_pubkey'));
349
350         $root->appendChild($relocate);
351
352         return(trim($doc->saveXML()));
353 }
354
355 /**
356  * @brief Adds the header elements for the DFRN protocol
357  *
358  * @param object $doc XML document
359  * @param array $owner Owner record
360  * @param string $authorelement Element name for the author
361  * @param string $alternatelink link to profile or category
362  * @param bool $public Is it a header for public posts?
363  *
364  * @return object XML root object
365  */
366 function dfrn_add_header($doc, $owner, $authorelement, $alternatelink = "", $public = false) {
367         $a = get_app();
368
369         if ($alternatelink == "")
370                 $alternatelink = $owner['url'];
371
372         $root = $doc->createElementNS(NS_ATOM, 'feed');
373         $doc->appendChild($root);
374
375         $root->setAttribute("xmlns:thr", NS_THR);
376         $root->setAttribute("xmlns:at", "http://purl.org/atompub/tombstones/1.0");
377         $root->setAttribute("xmlns:media", NS_MEDIA);
378         $root->setAttribute("xmlns:dfrn", "http://purl.org/macgirvin/dfrn/1.0");
379         $root->setAttribute("xmlns:activity", NS_ACTIVITY);
380         $root->setAttribute("xmlns:georss", NS_GEORSS);
381         $root->setAttribute("xmlns:poco", NS_POCO);
382         $root->setAttribute("xmlns:ostatus", NS_OSTATUS);
383         $root->setAttribute("xmlns:statusnet", NS_STATUSNET);
384
385         xml_add_element($doc, $root, "id", $a->get_baseurl()."/profile/".$owner["nick"]);
386         xml_add_element($doc, $root, "title", $owner["name"]);
387
388         $attributes = array("uri" => "https://friendi.ca", "version" => FRIENDICA_VERSION."-".DB_UPDATE_VERSION);
389         xml_add_element($doc, $root, "generator", FRIENDICA_PLATFORM, $attributes);
390
391         $attributes = array("rel" => "license", "href" => "http://creativecommons.org/licenses/by/3.0/");
392         xml_add_element($doc, $root, "link", "", $attributes);
393
394         $attributes = array("rel" => "alternate", "type" => "text/html", "href" => $alternatelink);
395         xml_add_element($doc, $root, "link", "", $attributes);
396
397         ostatus_hublinks($doc, $root);
398
399         if ($public) {
400                 $attributes = array("rel" => "salmon", "href" => $a->get_baseurl()."/salmon/".$owner["nick"]);
401                 xml_add_element($doc, $root, "link", "", $attributes);
402
403                 $attributes = array("rel" => "http://salmon-protocol.org/ns/salmon-replies", "href" => $a->get_baseurl()."/salmon/".$owner["nick"]);
404                 xml_add_element($doc, $root, "link", "", $attributes);
405
406                 $attributes = array("rel" => "http://salmon-protocol.org/ns/salmon-mention", "href" => $a->get_baseurl()."/salmon/".$owner["nick"]);
407                 xml_add_element($doc, $root, "link", "", $attributes);
408         }
409
410         if ($owner['page-flags'] == PAGE_COMMUNITY)
411                 xml_add_element($doc, $root, "dfrn:community", 1);
412
413         xml_add_element($doc, $root, "updated", datetime_convert("UTC", "UTC", "now", ATOM_TIME));
414
415         $author = dfrn_add_author($doc, $owner, $authorelement);
416         $root->appendChild($author);
417
418         return $root;
419 }
420
421 /**
422  * @brief Adds the author elements for the DFRN protocol
423  *
424  * @param object $doc XML document
425  * @param array $owner Owner record
426  * @param string $authorelement Element name for the author
427  *
428  * @return object XML author object
429  */
430 function dfrn_add_author($doc, $owner, $authorelement) {
431         $a = get_app();
432
433         $author = $doc->createElement($authorelement);
434
435         $namdate = datetime_convert('UTC', 'UTC', $owner['name-date'].'+00:00' , ATOM_TIME);
436         $uridate = datetime_convert('UTC', 'UTC', $owner['uri-date'].'+00:00', ATOM_TIME);
437         $picdate = datetime_convert('UTC', 'UTC', $owner['avatar-date'].'+00:00', ATOM_TIME);
438
439         $attributes = array("dfrn:updated" => $namdate);
440         xml_add_element($doc, $author, "name", $owner["name"], $attributes);
441
442         $attributes = array("dfrn:updated" => $namdate);
443         xml_add_element($doc, $author, "uri", $a->get_baseurl().'/profile/'.$owner["nickname"], $attributes);
444
445         $attributes = array("rel" => "photo", "type" => "image/jpeg", "dfrn:updated" => $picdate,
446                                 "media:width" => 175, "media:height" => 175, "href" => $owner['photo']);
447         xml_add_element($doc, $author, "link", "", $attributes);
448
449         $attributes = array("rel" => "avatar", "type" => "image/jpeg", "dfrn:updated" => $picdate,
450                                 "media:width" => 175, "media:height" => 175, "href" => $owner['photo']);
451         xml_add_element($doc, $author, "link", "", $attributes);
452
453         $birthday = feed_birthday($owner['user_uid'], $owner['timezone']);
454
455         if ($birthday)
456                 xml_add_element($doc, $author, "dfrn:birthday", $birthday);
457
458         return $author;
459 }
460
461 /**
462  * @brief Adds the author elements for the item entries of the DFRN protocol
463  *
464  * @param object $doc XML document
465  * @param string $element Element name for the author
466  * @param string $contact_url Link of the contact
467  * @param array $items Item elements
468  *
469  * @return object XML author object
470  */
471 function dfrn_add_entry_author($doc, $element, $contact_url, $item) {
472         $a = get_app();
473
474         $contact = get_contact_details_by_url($contact_url, $item["uid"]);
475
476         $r = q("SELECT `profile`.`about`, `profile`.`name`, `profile`.`homepage`, `contact`.`nick`, `contact`.`location` FROM `profile`
477                         INNER JOIN `contact` ON `contact`.`uid` = `profile`.`uid`
478                         INNER JOIN `user` ON `user`.`uid` = `profile`.`uid`
479                         WHERE `contact`.`self` AND `profile`.`is-default` AND NOT `user`.`hidewall` AND `contact`.`nurl`='%s'",
480                 dbesc(normalise_link($contact_url)));
481         if ($r)
482                 $profile = $r[0];
483
484         $author = $doc->createElement($element);
485         xml_add_element($doc, $author, "name", $contact["name"]);
486         xml_add_element($doc, $author, "uri", $contact["url"]);
487
488         /// @Todo
489         /// - Check real image type and image size
490         /// - Check which of these boths elements we really use
491         $attributes = array(
492                         "rel" => "photo",
493                         "type" => "image/jpeg",
494                         "media:width" => 80,
495                         "media:height" => 80,
496                         "href" => $contact["photo"]);
497         xml_add_element($doc, $author, "link", "", $attributes);
498
499         $attributes = array(
500                         "rel" => "avatar",
501                         "type" => "image/jpeg",
502                         "media:width" => 80,
503                         "media:height" => 80,
504                         "href" => $contact["photo"]);
505         xml_add_element($doc, $author, "link", "", $attributes);
506
507         // Only show contact details when it is a user from our system and we are allowed to
508         if ($profile) {
509                 xml_add_element($doc, $author, "poco:preferredUsername", $profile["nick"]);
510                 xml_add_element($doc, $author, "poco:displayName", $profile["name"]);
511                 xml_add_element($doc, $author, "poco:note", $profile["about"]);
512
513                 if (trim($contact["location"]) != "") {
514                         $element = $doc->createElement("poco:address");
515                         xml_add_element($doc, $element, "poco:formatted", $profile["location"]);
516                         $author->appendChild($element);
517                 }
518
519                 if (trim($profile["homepage"]) != "") {
520                         $urls = $doc->createElement("poco:urls");
521                         xml_add_element($doc, $urls, "poco:type", "homepage");
522                         xml_add_element($doc, $urls, "poco:value", $profile["homepage"]);
523                         xml_add_element($doc, $urls, "poco:primary", "true");
524                         $author->appendChild($urls);
525                 }
526         }
527
528         return $author;
529 }
530
531 /**
532  * @brief Adds the activity elements
533  *
534  * @param object $doc XML document
535  * @param string $element Element name for the activity
536  * @param string $activity activity value
537  *
538  * @return object XML activity object
539  */
540 function dfrn_create_activity($doc, $element, $activity) {
541
542         if($activity) {
543                 $entry = $doc->createElement($element);
544
545                 $r = parse_xml_string($activity, false);
546                 if(!$r)
547                         return false;
548                 if($r->type)
549                         xml_add_element($doc, $entry, "activity:object-type", $r->type);
550                 if($r->id)
551                         xml_add_element($doc, $entry, "id", $r->id);
552                 if($r->title)
553                         xml_add_element($doc, $entry, "title", $r->title);
554                 if($r->link) {
555                         if(substr($r->link,0,1) === '<') {
556                                 if(strstr($r->link,'&') && (! strstr($r->link,'&amp;')))
557                                         $r->link = str_replace('&','&amp;', $r->link);
558
559                                 $r->link = preg_replace('/\<link(.*?)\"\>/','<link$1"/>',$r->link);
560
561                                 $data = parse_xml_string($r->link, false);
562                                 foreach ($data->attributes() AS $parameter => $value)
563                                         $attributes[$parameter] = $value;
564                         } else
565                                 $attributes = array("rel" => "alternate", "type" => "text/html", "href" => $r->link);
566
567                         xml_add_element($doc, $entry, "link", "", $attributes);
568                 }
569                 if($r->content)
570                         xml_add_element($doc, $entry, "content", bbcode($r->content), array("type" => "html"));
571
572                 return $entry;
573         }
574
575         return false;
576 }
577
578 /**
579  * @brief Adds the attachments elements
580  *
581  * @param object $doc XML document
582  * @param object $root XML root
583  * @param array $item Item element
584  *
585  * @return object XML attachment object
586  */
587 function dfrn_get_attachment($doc, $root, $item) {
588         $arr = explode('[/attach],',$item['attach']);
589         if(count($arr)) {
590                 foreach($arr as $r) {
591                         $matches = false;
592                         $cnt = preg_match('|\[attach\]href=\"(.*?)\" length=\"(.*?)\" type=\"(.*?)\" title=\"(.*?)\"|',$r,$matches);
593                         if($cnt) {
594                                 $attributes = array("rel" => "enclosure",
595                                                 "href" => $matches[1],
596                                                 "type" => $matches[3]);
597
598                                 if(intval($matches[2]))
599                                         $attributes["length"] = intval($matches[2]);
600
601                                 if(trim($matches[4]) != "")
602                                         $attributes["title"] = trim($matches[4]);
603
604                                 xml_add_element($doc, $root, "link", "", $attributes);
605                         }
606                 }
607         }
608 }
609
610 /**
611  * @brief Adds the header elements for the DFRN protocol
612  *
613  * @param object $doc XML document
614  * @param string $type "text" or "html"
615  * @param array $item Item element
616  * @param array $owner Owner record
617  * @param bool $comment Trigger the sending of the "comment" element
618  * @param int $cid
619  *
620  * @return object XML entry object
621  */
622 function dfrn_entry($doc, $type, $item, $owner, $comment = false, $cid = 0) {
623         $a = get_app();
624
625         $mentioned = array();
626
627         if(!$item['parent'])
628                 return;
629
630         if($item['deleted']) {
631                 $attributes = array("ref" => $item['uri'], "when" => datetime_convert('UTC','UTC',$item['edited'] . '+00:00',ATOM_TIME));
632                 return xml_create_element($doc, "at:deleted-entry", "", $attributes);
633         }
634
635         $entry = $doc->createElement("entry");
636
637         if($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid'])
638                 $body = fix_private_photos($item['body'],$owner['uid'],$item,$cid);
639         else
640                 $body = $item['body'];
641
642         if ($type == 'html') {
643                 $htmlbody = $body;
644
645                 if ($item['title'] != "")
646                         $htmlbody = "[b]".$item['title']."[/b]\n\n".$htmlbody;
647
648                 $htmlbody = bbcode($htmlbody, false, false, 7);
649         }
650
651         $author = dfrn_add_entry_author($doc, "author", $item["author-link"], $item);
652         $entry->appendChild($author);
653
654         $dfrnowner = dfrn_add_entry_author($doc, "dfrn:owner", $item["owner-link"], $item);
655         $entry->appendChild($dfrnowner);
656
657         if(($item['parent'] != $item['id']) || ($item['parent-uri'] !== $item['uri']) || (($item['thr-parent'] !== '') && ($item['thr-parent'] !== $item['uri']))) {
658                 $parent = q("SELECT `guid` FROM `item` WHERE `id` = %d", intval($item["parent"]));
659                 $parent_item = (($item['thr-parent']) ? $item['thr-parent'] : $item['parent-uri']);
660                 $attributes = array("ref" => $parent_item, "type" => "text/html", "href" => $a->get_baseurl().'/display/'.$parent[0]['guid']);
661                 xml_add_element($doc, $entry, "thr:in-reply-to", "", $attributes);
662         }
663
664         xml_add_element($doc, $entry, "id", $item["uri"]);
665         xml_add_element($doc, $entry, "title", $item["title"]);
666
667         xml_add_element($doc, $entry, "published", datetime_convert("UTC","UTC",$item["created"]."+00:00",ATOM_TIME));
668         xml_add_element($doc, $entry, "updated", datetime_convert("UTC","UTC",$item["edited"]."+00:00",ATOM_TIME));
669
670         xml_add_element($doc, $entry, "dfrn:env", base64url_encode($body, true));
671         xml_add_element($doc, $entry, "content", (($type === 'html') ? $htmlbody : $body), array("type" => $type));
672
673         xml_add_element($doc, $entry, "link", "", array("rel" => "alternate", "type" => "text/html",
674                                                         "href" => $a->get_baseurl()."/display/".$item["guid"]));
675
676         if ($comment)
677                 xml_add_element($doc, $entry, "dfrn:comment-allow", intval($item['last-child']));
678
679         if($item['location'])
680                 xml_add_element($doc, $entry, "dfrn:location", $item['location']);
681
682         if($item['coord'])
683                 xml_add_element($doc, $entry, "georss:point", $item['coord']);
684
685         if(($item['private']) || strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid']))
686                 xml_add_element($doc, $entry, "dfrn:private", (($item['private']) ? $item['private'] : 1));
687
688         if($item['extid'])
689                 xml_add_element($doc, $entry, "dfrn:extid", $item['extid']);
690
691         if($item['bookmark'])
692                 xml_add_element($doc, $entry, "dfrn:bookmark", "true");
693
694         if($item['app'])
695                 xml_add_element($doc, $entry, "statusnet:notice_info", "", array("local_id" => $item['id'], "source" => $item['app']));
696
697         xml_add_element($doc, $entry, "dfrn:diaspora_guid", $item["guid"]);
698
699         if($item['signed_text']) {
700                 $sign = base64_encode(json_encode(array('signed_text' => $item['signed_text'],'signature' => $item['signature'],'signer' => $item['signer'])));
701                 xml_add_element($doc, $entry, "dfrn:diaspora_signature", $sign);
702         }
703
704         xml_add_element($doc, $entry, "activity:verb", construct_verb($item));
705
706         $actobj = dfrn_create_activity($doc, "activity:object", $item['object']);
707         if ($actobj)
708                 $entry->appendChild($actobj);
709
710         $actarg = dfrn_create_activity($doc, "activity:target", $item['target']);
711         if ($actarg)
712                 $entry->appendChild($actarg);
713
714         $tags = item_getfeedtags($item);
715
716         if(count($tags)) {
717                 foreach($tags as $t)
718                         if (($type != 'html') OR ($t[0] != "@"))
719                                 xml_add_element($doc, $entry, "category", "", array("scheme" => "X-DFRN:".$t[0].":".$t[1], "term" => $t[2]));
720         }
721
722         if(count($tags))
723                 foreach($tags as $t)
724                         if ($t[0] == "@")
725                                 $mentioned[$t[1]] = $t[1];
726
727         foreach ($mentioned AS $mention) {
728                 $r = q("SELECT `forum`, `prv` FROM `contact` WHERE `uid` = %d AND `nurl` = '%s'",
729                         intval($owner["uid"]),
730                         dbesc(normalise_link($mention)));
731                 if ($r[0]["forum"] OR $r[0]["prv"])
732                         xml_add_element($doc, $entry, "link", "", array("rel" => "mentioned",
733                                                                                 "ostatus:object-type" => ACTIVITY_OBJ_GROUP,
734                                                                                 "href" => $mention));
735                 else
736                         xml_add_element($doc, $entry, "link", "", array("rel" => "mentioned",
737                                                                                 "ostatus:object-type" => ACTIVITY_OBJ_PERSON,
738                                                                                 "href" => $mention));
739         }
740
741         dfrn_get_attachment($doc, $entry, $item);
742
743         return $entry;
744 }