]> git.mxchange.org Git - friendica.git/blob - include/import-dfrn.php
DFRN Deletions should now work too
[friendica.git] / include / import-dfrn.php
1 <?php
2 /*
3 require_once("include/Contact.php");
4 require_once("include/html2bbcode.php");
5 require_once("include/bbcode.php");
6 require_once("mod/share.php");
7 require_once("include/Photo.php");
8 require_once("include/Scrape.php");
9 require_once("include/follow.php");
10 require_once("include/api.php");
11 require_once("mod/proxy.php");
12 */
13
14 require_once("include/enotify.php");
15 require_once("include/threads.php");
16 require_once("include/socgraph.php");
17 require_once("include/items.php");
18 require_once("include/tags.php");
19 require_once("include/files.php");
20
21 define("NS_ATOM", "http://www.w3.org/2005/Atom");
22 define("NS_THR", "http://purl.org/syndication/thread/1.0");
23 define("NS_GEORSS", "http://www.georss.org/georss");
24 define("NS_ACTIVITY", "http://activitystrea.ms/spec/1.0/");
25 define("NS_MEDIA", "http://purl.org/syndication/atommedia");
26 define("NS_POCO", "http://portablecontacts.net/spec/1.0");
27 define("NS_OSTATUS", "http://ostatus.org/schema/1.0");
28 define("NS_STATUSNET", "http://status.net/schema/api/1/");
29
30 class dfrn2 {
31         /**
32          * @brief Add new birthday event for this person
33          *
34          * @param array $contact Contact record
35          * @param string $birthday Birthday of the contact
36          *
37          */
38         private function birthday_event($contact, $birthday) {
39
40                 logger('updating birthday: '.$birthday.' for contact '.$contact['id']);
41
42                 $bdtext = sprintf(t('%s\'s birthday'), $contact['name']);
43                 $bdtext2 = sprintf(t('Happy Birthday %s'), ' [url=' . $contact['url'].']'.$contact['name'].'[/url]' ) ;
44
45
46                 $r = q("INSERT INTO `event` (`uid`,`cid`,`created`,`edited`,`start`,`finish`,`summary`,`desc`,`type`)
47                         VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ",
48                         intval($contact['uid']),
49                         intval($contact['id']),
50                         dbesc(datetime_convert()),
51                         dbesc(datetime_convert()),
52                         dbesc(datetime_convert('UTC','UTC', $birthday)),
53                         dbesc(datetime_convert('UTC','UTC', $birthday.' + 1 day ')),
54                         dbesc($bdtext),
55                         dbesc($bdtext2),
56                         dbesc('birthday')
57                 );
58         }
59
60         /**
61          * @brief Fetch the author data from head or entry items
62          *
63          * @param object $xpath XPath object
64          * @param object $context In which context should the data be searched
65          * @param array $importer Record of the importer contact
66          * @param string $element Element name from which the data is fetched
67          * @param array $contact The updated contact record of the author
68          * @param bool $onlyfetch Should the data only be fetched or should it update the contact record as well
69          *
70          * @return Returns an array with relevant data of the author
71          */
72         private function fetchauthor($xpath, $context, $importer, $element, &$contact, $onlyfetch) {
73
74                 $author = array();
75                 $author["name"] = $xpath->evaluate($element.'/atom:name/text()', $context)->item(0)->nodeValue;
76                 $author["link"] = $xpath->evaluate($element.'/atom:uri/text()', $context)->item(0)->nodeValue;
77
78                 $r = q("SELECT `id`, `uid`, `network`, `avatar-date`, `name-date`, `uri-date`, `addr`,
79                                 `name`, `nick`, `about`, `location`, `keywords`, `bdyear`, `bd`
80                                 FROM `contact` WHERE `uid` = %d AND `nurl` IN ('%s', '%s') AND `network` != '%s'",
81                         intval($importer["uid"]), dbesc(normalise_link($author["author-link"])),
82                         dbesc(normalise_link($author["link"])), dbesc(NETWORK_STATUSNET));
83                 if ($r) {
84                         $contact = $r[0];
85                         $author["contact-id"] = $r[0]["id"];
86                         $author["network"] = $r[0]["network"];
87                 } else {
88                         $author["contact-id"] = $contact["id"];
89                         $author["network"] = $contact["network"];
90                 }
91
92                 // Until now we aren't serving different sizes - but maybe later
93                 $avatarlist = array();
94                 // @todo check if "avatar" or "photo" would be the best field in the specification
95                 $avatars = $xpath->query($element."/atom:link[@rel='avatar']", $context);
96                 foreach($avatars AS $avatar) {
97                         $href = "";
98                         $width = 0;
99                         foreach($avatar->attributes AS $attributes) {
100                                 if ($attributes->name == "href")
101                                         $href = $attributes->textContent;
102                                 if ($attributes->name == "width")
103                                         $width = $attributes->textContent;
104                                 if ($attributes->name == "updated")
105                                         $contact["avatar-date"] = $attributes->textContent;
106                         }
107                         if (($width > 0) AND ($href != ""))
108                                 $avatarlist[$width] = $href;
109                 }
110                 if (count($avatarlist) > 0) {
111                         krsort($avatarlist);
112                         $author["avatar"] = current($avatarlist);
113                 }
114
115                 //$onlyfetch = true; // Test
116
117                 if ($r AND !$onlyfetch) {
118
119                         // When was the last change to name or uri?
120                         $name_element = $xpath->query($element."/atom:name", $context)->item(0);
121                         foreach($name_element->attributes AS $attributes)
122                                 if ($attributes->name == "updated")
123                                         $contact["name-date"] = $attributes->textContent;
124
125                         $link_element = $xpath->query($element."/atom:link", $context)->item(0);
126                         foreach($link_element->attributes AS $attributes)
127                                 if ($attributes->name == "updated")
128                                         $contact["uri-date"] = $attributes->textContent;
129
130                         // Update contact data
131                         $value = $xpath->evaluate($element.'/dfrn:handle/text()', $context)->item(0)->nodeValue;
132                         if ($value != "")
133                                 $contact["addr"] = $value;
134
135                         $value = $xpath->evaluate($element.'/poco:displayName/text()', $context)->item(0)->nodeValue;
136                         if ($value != "")
137                                 $contact["name"] = $value;
138
139                         $value = $xpath->evaluate($element.'/poco:preferredUsername/text()', $context)->item(0)->nodeValue;
140                         if ($value != "")
141                                 $contact["nick"] = $value;
142
143                         $value = $xpath->evaluate($element.'/poco:note/text()', $context)->item(0)->nodeValue;
144                         if ($value != "")
145                                 $contact["about"] = $value;
146
147                         $value = $xpath->evaluate($element.'/poco:address/poco:formatted/text()', $context)->item(0)->nodeValue;
148                         if ($value != "")
149                                 $contact["location"] = $value;
150
151                         /// @todo Add support for the following fields that we don't support by now in the contact table:
152                         /// - poco:utcOffset
153                         /// - poco:ims
154                         /// - poco:urls
155                         /// - poco:locality
156                         /// - poco:region
157                         /// - poco:country
158
159                         // Save the keywords into the contact table
160                         $tags = array();
161                         $tagelements = $xpath->evaluate($element.'/poco:tags/text()', $context);
162                         foreach($tagelements AS $tag)
163                                 $tags[$tag->nodeValue] = $tag->nodeValue;
164
165                         if (count($tags))
166                                 $contact["keywords"] = implode(", ", $tags);
167
168                         // "dfrn:birthday" contains the birthday converted to UTC
169                         $old_bdyear = $contact["bdyear"];
170
171                         $birthday = $xpath->evaluate($element.'/dfrn:birthday/text()', $context)->item(0)->nodeValue;
172
173                         if (strtotime($birthday) > time()) {
174                                 $bd_timestamp = strtotime($birthday);
175
176                                 $contact["bdyear"] = date("Y", $bd_timestamp);
177                         }
178
179                         // "poco:birthday" is the birthday in the format "yyyy-mm-dd"
180                         $value = $xpath->evaluate($element.'/poco:birthday/text()', $context)->item(0)->nodeValue;
181
182                         if (!in_array($value, array("", "0000-00-00"))) {
183                                 $bdyear = date("Y");
184                                 $value = str_replace("0000", $bdyear, $value);
185
186                                 if (strtotime($value) < time()) {
187                                         $value = str_replace($bdyear, $bdyear + 1, $value);
188                                         $bdyear = $bdyear + 1;
189                                 }
190
191                                 $contact["bd"] = $value;
192                         }
193
194                         if ($old_bdyear != $contact["bdyear"])
195                                 self::birthday_event($contact, $birthday);
196
197                         // Get all field names
198                         $fields = array();
199                         foreach ($r[0] AS $field => $data)
200                                 $fields[$field] = $data;
201
202                         unset($fields["id"]);
203                         unset($fields["uid"]);
204
205                         foreach ($fields AS $field => $data)
206                                 if ($contact[$field] != $r[0][$field])
207                                         $update = true;
208
209                         if ($update) {
210                                 logger("Update contact data for contact ".$contact["id"], LOGGER_DEBUG);
211
212                                 q("UPDATE `contact` SET `name` = '%s', `nick` = '%s', `about` = '%s', `location` = '%s',
213                                         `addr` = '%s', `keywords` = '%s', `bdyear` = '%s', `bd` = '%s'
214                                         `avatar-date`  = '%s', `name-date`  = '%s', `uri-date` = '%s'
215                                         WHERE `id` = %d AND `network` = '%s'",
216                                         dbesc($contact["name"]), dbesc($contact["nick"]), dbesc($contact["about"]), dbesc($contact["location"]),
217                                         dbesc($contact["addr"]), dbesc($contact["keywords"]), dbesc($contact["bdyear"]),
218                                         dbesc($contact["bd"]), dbesc($contact["avatar-date"]), dbesc($contact["name-date"]), dbesc($contact["uri-date"]),
219                                         intval($contact["id"]), dbesc($contact["network"]));
220                         }
221
222                         update_contact_avatar($author["avatar"], $importer["uid"], $contact["id"], ($contact["avatar-date"] != $r[0]["avatar-date"]));
223
224                         $contact["generation"] = 2;
225                         $contact["photo"] = $author["avatar"];
226                         update_gcontact($contact);
227                 }
228
229                 return($author);
230         }
231
232         private function transform_activity($xpath, $activity, $element) {
233                 if (!is_object($activity))
234                         return "";
235
236                 $obj_doc = new DOMDocument('1.0', 'utf-8');
237                 $obj_doc->formatOutput = true;
238
239                 $obj_element = $obj_doc->createElementNS(NS_ATOM, $element);
240
241                 $activity_type = $xpath->query('activity:object-type/text()', $activity)->item(0)->nodeValue;
242                 xml_add_element($obj_doc, $obj_element, "type", $activity_type);
243
244                 $id = $xpath->query('atom:id', $activity)->item(0);
245                 if (is_object($id))
246                         $obj_element->appendChild($obj_doc->importNode($id, true));
247
248                 $title = $xpath->query('atom:title', $activity)->item(0);
249                 if (is_object($title))
250                         $obj_element->appendChild($obj_doc->importNode($title, true));
251
252                 $link = $xpath->query('atom:link', $activity)->item(0);
253                 if (is_object($link))
254                         $obj_element->appendChild($obj_doc->importNode($link, true));
255
256                 $content = $xpath->query('atom:content', $activity)->item(0);
257                 if (is_object($content))
258                         $obj_element->appendChild($obj_doc->importNode($content, true));
259
260                 $obj_doc->appendChild($obj_element);
261
262                 $objxml = $obj_doc->saveXML($obj_element);
263
264                 // @todo This isn't totally clean. We should find a way to transform the namespaces
265                 $objxml = str_replace('<'.$element.' xmlns="http://www.w3.org/2005/Atom">', "<".$element.">", $objxml);
266                 return($objxml);
267         }
268
269         private function process_mail($xpath, $mail, $importer) {
270
271                 $msg = array();
272                 $msg["uid"] = $importer['importer_uid'];
273                 $msg["from-name"] = $xpath->query('dfrn:sender/dfrn:name/text()', $mail)->item(0)->nodeValue;
274                 $msg["from-url"] = $xpath->query('dfrn:sender/dfrn:uri/text()', $mail)->item(0)->nodeValue;
275                 $msg["from-photo"] = $xpath->query('dfrn:sender/dfrn:avatar/text()', $mail)->item(0)->nodeValue;
276                 $msg["contact-id"] = $importer["id"];
277                 $msg["uri"] = $xpath->query('dfrn:id/text()', $mail)->item(0)->nodeValue;
278                 $msg["parent-uri"] = $xpath->query('dfrn:in-reply-to/text()', $mail)->item(0)->nodeValue;
279                 $msg["created"] = $xpath->query('dfrn:sentdate/text()', $mail)->item(0)->nodeValue;
280                 $msg["title"] = $xpath->query('dfrn:subject/text()', $mail)->item(0)->nodeValue;
281                 $msg["body"] = $xpath->query('dfrn:content/text()', $mail)->item(0)->nodeValue;
282                 $msg["seen"] = 0;
283                 $msg["replied"] = 0;
284
285                 dbesc_array($msg);
286
287                 $r = dbq("INSERT INTO `mail` (`".implode("`, `", array_keys($msg))."`) VALUES ('".implode("', '", array_values($msg))."')");
288
289                 // send notifications.
290
291                 $notif_params = array(
292                         'type' => NOTIFY_MAIL,
293                         'notify_flags' => $importer['notify-flags'],
294                         'language' => $importer['language'],
295                         'to_name' => $importer['username'],
296                         'to_email' => $importer['email'],
297                         'uid' => $importer['importer_uid'],
298                         'item' => $msg,
299                         'source_name' => $msg['from-name'],
300                         'source_link' => $importer['url'],
301                         'source_photo' => $importer['thumb'],
302                         'verb' => ACTIVITY_POST,
303                         'otype' => 'mail'
304                 );
305
306                 notification($notif_params);
307         }
308
309         private function process_suggestion($xpath, $suggestion, $importer) {
310
311                 $suggest = array();
312                 $suggest["uid"] = $importer["importer_uid"];
313                 $suggest["cid"] = $importer["id"];
314                 $suggest["url"] = $xpath->query('dfrn:url/text()', $suggestion)->item(0)->nodeValue;
315                 $suggest["name"] = $xpath->query('dfrn:name/text()', $suggestion)->item(0)->nodeValue;
316                 $suggest["photo"] = $xpath->query('dfrn:photo/text()', $suggestion)->item(0)->nodeValue;
317                 $suggest["request"] = $xpath->query('dfrn:request/text()', $suggestion)->item(0)->nodeValue;
318                 $suggest["note"] = $xpath->query('dfrn:note/text()', $suggestion)->item(0)->nodeValue;
319
320                 // Does our member already have a friend matching this description?
321
322                 $r = q("SELECT `id` FROM `contact` WHERE `name` = '%s' AND `nurl` = '%s' AND `uid` = %d LIMIT 1",
323                         dbesc($suggest["name"]),
324                         dbesc(normalise_link($suggest["url"])),
325                         intval($suggest["uid"])
326                 );
327                 if(count($r))
328                         return false;
329
330                 // Do we already have an fcontact record for this person?
331
332                 $fid = 0;
333                 $r = q("SELECT `id` FROM `fcontact` WHERE `url` = '%s' AND `name` = '%s' AND `request` = '%s' LIMIT 1",
334                         dbesc($suggest["url"]),
335                         dbesc($suggest["name"]),
336                         dbesc($suggest["request"])
337                 );
338                 if(count($r)) {
339                         $fid = $r[0]["id"];
340
341                         // OK, we do. Do we already have an introduction for this person ?
342                         $r = q("SELECT `id` FROM `intro` WHERE `uid` = %d AND `fid` = %d LIMIT 1",
343                                 intval($suggest["uid"]),
344                                 intval($fid)
345                         );
346                         if(count($r))
347                                 return false;
348                 }
349                 if(!$fid)
350                         $r = q("INSERT INTO `fcontact` (`name`,`url`,`photo`,`request`) VALUES ('%s', '%s', '%s', '%s')",
351                         dbesc($suggest["name"]),
352                         dbesc($suggest["url"]),
353                         dbesc($suggest["photo"]),
354                         dbesc($suggest["request"])
355                 );
356                 $r = q("SELECT `id` FROM `fcontact` WHERE `url` = '%s' AND `name` = '%s' AND `request` = '%s' LIMIT 1",
357                         dbesc($suggest["url"]),
358                         dbesc($suggest["name"]),
359                         dbesc($suggest["request"])
360                 );
361                 if(count($r))
362                         $fid = $r[0]["id"];
363                 else
364                         // database record did not get created. Quietly give up.
365                         return false;
366
367
368                 $hash = random_string();
369
370                 $r = q("INSERT INTO `intro` (`uid`, `fid`, `contact-id`, `note`, `hash`, `datetime`, `blocked`)
371                         VALUES(%d, %d, %d, '%s', '%s', '%s', %d)",
372                         intval($suggest["uid"]),
373                         intval($fid),
374                         intval($suggest["cid"]),
375                         dbesc($suggest["body"]),
376                         dbesc($hash),
377                         dbesc(datetime_convert()),
378                         intval(0)
379                 );
380
381                 notification(array(
382                         'type'         => NOTIFY_SUGGEST,
383                         'notify_flags' => $importer["notify-flags"],
384                         'language'     => $importer["language"],
385                         'to_name'      => $importer["username"],
386                         'to_email'     => $importer["email"],
387                         'uid'          => $importer["importer_uid"],
388                         'item'         => $suggest,
389                         'link'         => App::get_baseurl()."/notifications/intros",
390                         'source_name'  => $importer["name"],
391                         'source_link'  => $importer["url"],
392                         'source_photo' => $importer["photo"],
393                         'verb'         => ACTIVITY_REQ_FRIEND,
394                         'otype'        => "intro"
395                 ));
396
397                 return true;
398
399         }
400
401         private function process_relocation($xpath, $relocation, $importer) {
402
403                 $relocate = array();
404                 $relocate["uid"] = $importer["importer_uid"];
405                 $relocate["cid"] = $importer["id"];
406                 $relocate["url"] = $xpath->query('dfrn:url/text()', $relocation)->item(0)->nodeValue;
407                 $relocate["name"] = $xpath->query('dfrn:name/text()', $relocation)->item(0)->nodeValue;
408                 $relocate["photo"] = $xpath->query('dfrn:photo/text()', $relocation)->item(0)->nodeValue;
409                 $relocate["thumb"] = $xpath->query('dfrn:thumb/text()', $relocation)->item(0)->nodeValue;
410                 $relocate["micro"] = $xpath->query('dfrn:micro/text()', $relocation)->item(0)->nodeValue;
411                 $relocate["request"] = $xpath->query('dfrn:request/text()', $relocation)->item(0)->nodeValue;
412                 $relocate["confirm"] = $xpath->query('dfrn:confirm/text()', $relocation)->item(0)->nodeValue;
413                 $relocate["notify"] = $xpath->query('dfrn:notify/text()', $relocation)->item(0)->nodeValue;
414                 $relocate["poll"] = $xpath->query('dfrn:poll/text()', $relocation)->item(0)->nodeValue;
415                 $relocate["sitepubkey"] = $xpath->query('dfrn:sitepubkey/text()', $relocation)->item(0)->nodeValue;
416
417                 // update contact
418                 $r = q("SELECT `photo`, `url` FROM `contact` WHERE `id` = %d AND `uid` = %d;",
419                         intval($importer["id"]),
420                         intval($importer["importer_uid"]));
421                 if (!$r)
422                         return false;
423
424                 $old = $r[0];
425
426                 $x = q("UPDATE `contact` SET
427                                         `name` = '%s',
428                                         `photo` = '%s',
429                                         `thumb` = '%s',
430                                         `micro` = '%s',
431                                         `url` = '%s',
432                                         `nurl` = '%s',
433                                         `request` = '%s',
434                                         `confirm` = '%s',
435                                         `notify` = '%s',
436                                         `poll` = '%s',
437                                         `site-pubkey` = '%s'
438                         WHERE `id` = %d AND `uid` = %d;",
439                                         dbesc($relocate["name"]),
440                                         dbesc($relocate["photo"]),
441                                         dbesc($relocate["thumb"]),
442                                         dbesc($relocate["micro"]),
443                                         dbesc($relocate["url"]),
444                                         dbesc(normalise_link($relocate["url"])),
445                                         dbesc($relocate["request"]),
446                                         dbesc($relocate["confirm"]),
447                                         dbesc($relocate["notify"]),
448                                         dbesc($relocate["poll"]),
449                                         dbesc($relocate["sitepubkey"]),
450                                         intval($importer["id"]),
451                                         intval($importer["importer_uid"]));
452
453                 if ($x === false)
454                         return false;
455
456                 // update items
457                 $fields = array(
458                         'owner-link' => array($old["url"], $relocate["url"]),
459                         'author-link' => array($old["url"], $relocate["url"]),
460                         'owner-avatar' => array($old["photo"], $relocate["photo"]),
461                         'author-avatar' => array($old["photo"], $relocate["photo"]),
462                         );
463                 foreach ($fields as $n=>$f){
464                         $x = q("UPDATE `item` SET `%s` = '%s' WHERE `%s` = '%s' AND `uid` = %d",
465                                         $n, dbesc($f[1]),
466                                         $n, dbesc($f[0]),
467                                         intval($importer["importer_uid"]));
468                                 if ($x === false)
469                                         return false;
470                         }
471
472                 /// @TODO
473                 /// merge with current record, current contents have priority
474                 /// update record, set url-updated
475                 /// update profile photos
476                 /// schedule a scan?
477                 return true;
478         }
479
480         private function process_entry($header, $xpath, $entry, $importer, $contact) {
481                 $item = $header;
482
483                 // Fetch the owner
484                 $owner = self::fetchauthor($xpath, $entry, $importer, "dfrn:owner", $contact, true);
485
486                 $item["owner-name"] = $owner["name"];
487                 $item["owner-link"] = $owner["link"];
488                 $item["owner-avatar"] = $owner["avatar"];
489
490                 if ($header["contact-id"] != $owner["contact-id"])
491                         $item["contact-id"] = $owner["contact-id"];
492
493                 if (($header["network"] != $owner["network"]) AND ($owner["network"] != ""))
494                         $item["network"] = $owner["network"];
495
496                 // fetch the author
497                 $author = self::fetchauthor($xpath, $entry, $importer, "atom:author", $contact, true);
498
499                 $item["author-name"] = $author["name"];
500                 $item["author-link"] = $author["link"];
501                 $item["author-avatar"] = $author["avatar"];
502
503                 if ($header["contact-id"] != $author["contact-id"])
504                         $item["contact-id"] = $author["contact-id"];
505
506                 if (($header["network"] != $author["network"]) AND ($author["network"] != ""))
507                         $item["network"] = $author["network"];
508
509                 // Now get the item
510                 $item["uri"] = $xpath->query('atom:id/text()', $entry)->item(0)->nodeValue;
511
512                 $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s'",
513                         intval($importer["uid"]), dbesc($item["uri"]));
514                 if ($r) {
515                         //logger("Item with uri ".$item["uri"]." for user ".$importer["uid"]." already existed under id ".$r[0]["id"], LOGGER_DEBUG);
516                         //return false;
517                 }
518
519                 // Is it a reply?
520                 $inreplyto = $xpath->query('thr:in-reply-to', $entry);
521                 if (is_object($inreplyto->item(0))) {
522                         $objecttype = ACTIVITY_OBJ_COMMENT;
523                         $item["type"] = 'remote-comment';
524                         $item["gravity"] = GRAVITY_COMMENT;
525
526                         foreach($inreplyto->item(0)->attributes AS $attributes) {
527                                 if ($attributes->name == "ref")
528                                         $item["parent-uri"] = $attributes->textContent;
529                         }
530                 } else {
531                         $objecttype = ACTIVITY_OBJ_NOTE;
532                         $item["parent-uri"] = $item["uri"];
533                 }
534
535                 $item["title"] = $xpath->query('atom:title/text()', $entry)->item(0)->nodeValue;
536
537                 $item["created"] = $xpath->query('atom:published/text()', $entry)->item(0)->nodeValue;
538                 $item["edited"] = $xpath->query('atom:updated/text()', $entry)->item(0)->nodeValue;
539
540                 $item["body"] = $xpath->query('dfrn:env/text()', $entry)->item(0)->nodeValue;
541                 $item["body"] = str_replace(array(' ',"\t","\r","\n"), array('','','',''),$item["body"]);
542                 // make sure nobody is trying to sneak some html tags by us
543                 $item["body"] = notags(base64url_decode($item["body"]));
544
545                 $item["body"] = limit_body_size($item["body"]);
546
547                 /// @todo Do we need the old check for HTML elements?
548
549                 // We don't need the content element since "dfrn:env" is always present
550                 //$item["body"] = $xpath->query('atom:content/text()', $entry)->item(0)->nodeValue;
551
552                 $item["last-child"] = $xpath->query('dfrn:comment-allow/text()', $entry)->item(0)->nodeValue;
553                 $item["location"] = $xpath->query('dfrn:location/text()', $entry)->item(0)->nodeValue;
554
555                 $georsspoint = $xpath->query('georss:point', $entry);
556                 if ($georsspoint)
557                         $item["coord"] = $georsspoint->item(0)->nodeValue;
558
559                 $item["private"] = $xpath->query('dfrn:private/text()', $entry)->item(0)->nodeValue;
560
561                 $item["extid"] = $xpath->query('dfrn:extid/text()', $entry)->item(0)->nodeValue;
562
563                 if ($xpath->query('dfrn:extid/text()', $entry)->item(0)->nodeValue == "true")
564                         $item["bookmark"] = true;
565
566                 $notice_info = $xpath->query('statusnet:notice_info', $entry);
567                 if ($notice_info AND ($notice_info->length > 0)) {
568                         foreach($notice_info->item(0)->attributes AS $attributes) {
569                                 if ($attributes->name == "source")
570                                         $item["app"] = strip_tags($attributes->textContent);
571                         }
572                 }
573
574                 $item["guid"] = $xpath->query('dfrn:diaspora_guid/text()', $entry)->item(0)->nodeValue;
575
576                 // We store the data from "dfrn:diaspora_signature" in a later step. See some lines below
577                 $signature = $xpath->query('dfrn:diaspora_signature/text()', $entry)->item(0)->nodeValue;
578
579                 $item["verb"] = $xpath->query('activity:verb/text()', $entry)->item(0)->nodeValue;
580
581                 if ($xpath->query('activity:object-type/text()', $entry)->item(0)->nodeValue != "")
582                         $objecttype = $xpath->query('activity:object-type/text()', $entry)->item(0)->nodeValue;
583
584                 $item["object-type"] = $objecttype;
585
586                 // I have the feeling that we don't do anything with this data
587                 $object = $xpath->query('activity:object', $entry)->item(0);
588                 $item["object"] = self::transform_activity($xpath, $object, "object");
589
590                 // Could someone explain what this is for?
591                 $target = $xpath->query('activity:target', $entry)->item(0);
592                 $item["target"] = self::transform_activity($xpath, $target, "target");
593
594                 $categories = $xpath->query('atom:category', $entry);
595                 if ($categories) {
596                         foreach ($categories AS $category) {
597                                 foreach($category->attributes AS $attributes)
598                                         if ($attributes->name == "term") {
599                                                 $term = $attributes->textContent;
600                                                 if(strlen($item["tag"]))
601                                                         $item["tag"] .= ',';
602
603                                                 $item["tag"] .= "#[url=".$a->get_baseurl()."/search?tag=".$term."]".$term."[/url]";
604                                         }
605                         }
606                 }
607
608                 $enclosure = "";
609
610                 $links = $xpath->query('atom:link', $entry);
611                 if ($links) {
612                         $rel = "";
613                         $href = "";
614                         $type = "";
615                         $length = "0";
616                         $title = "";
617                         foreach ($links AS $link) {
618                                 foreach($link->attributes AS $attributes) {
619                                         if ($attributes->name == "href")
620                                                 $href = $attributes->textContent;
621                                         if ($attributes->name == "rel")
622                                                 $rel = $attributes->textContent;
623                                         if ($attributes->name == "type")
624                                                 $type = $attributes->textContent;
625                                         if ($attributes->name == "length")
626                                                 $length = $attributes->textContent;
627                                         if ($attributes->name == "title")
628                                                 $title = $attributes->textContent;
629                                 }
630                                 if (($rel != "") AND ($href != ""))
631                                         switch($rel) {
632                                                 case "alternate":
633                                                         $item["plink"] = $href;
634                                                         break;
635                                                 case "enclosure":
636                                                         $enclosure = $href;
637                                                         if(strlen($item["attach"]))
638                                                                 $item["attach"] .= ',';
639
640                                                         $item["attach"] .= '[attach]href="'.$href.'" length="'.$length.'" type="'.$type.'" title="'.$title.'"[/attach]';
641                                                         break;
642                                         }
643                         }
644                 }
645
646                 //print_r($item);
647                 $item_id = item_store($item);
648
649                 return;
650
651                 if (!$item_id) {
652                         logger("Error storing item", LOGGER_DEBUG);
653                         return false;
654                 } else {
655                         logger("Item was stored with id ".$item_id, LOGGER_DEBUG);
656
657                         if ($signature) {
658                                 $signature = json_decode(base64_decode($signature));
659
660                                 // Check for falsely double encoded signatures
661                                 $signature->signature = diaspora_repair_signature($signature->signature, $signature->signer);
662
663                                 // Store it in the "sign" table where we will read it for comments that we relay to Diaspora
664                                 q("INSERT INTO `sign` (`iid`,`signed_text`,`signature`,`signer`) VALUES (%d,'%s','%s','%s')",
665                                         intval($item_id),
666                                         dbesc($signature->signed_text),
667                                         dbesc($signature->signature),
668                                         dbesc($signature->signer)
669                                 );
670                         }
671                 }
672                 return $item_id;
673         }
674
675         private function process_deletion($header, $xpath, $deletion, $importer, $contact) {
676                 foreach($deletion->attributes AS $attributes) {
677                         if ($attributes->name == "ref")
678                                 $uri = $attributes->textContent;
679                         if ($attributes->name == "when")
680                                 $when = $attributes->textContent;
681                 }
682                 if ($when)
683                         $when = datetime_convert('UTC','UTC', $when, 'Y-m-d H:i:s');
684                 else
685                         $when = datetime_convert('UTC','UTC','now','Y-m-d H:i:s');
686
687                 if (!$uri OR !is_array($contact))
688                         return false;
689
690                 $r = q("SELECT `item`.*, `contact`.`self` FROM `item` INNER JOIN `contact` on `item`.`contact-id` = `contact`.`id`
691                                 WHERE `uri` = '%s' AND `item`.`uid` = %d AND `contact-id` = %d AND NOT `item`.`file` LIKE '%%[%%' LIMIT 1",
692                                 dbesc($uri),
693                                 intval($importer["uid"]),
694                                 intval($contact["id"])
695                         );
696                 if(count($r)) {
697                         $item = $r[0];
698
699                         if(!$item["deleted"])
700                                 logger('deleting item '.$item["id"].' uri='.$item['uri'], LOGGER_DEBUG);
701
702                         if($item["object-type"] === ACTIVITY_OBJ_EVENT) {
703                                 logger("Deleting event ".$item["event-id"], LOGGER_DEBUG);
704                                 event_delete($item["event-id"]);
705                         }
706
707                         if(($item["verb"] === ACTIVITY_TAG) && ($item["object-type"] === ACTIVITY_OBJ_TAGTERM)) {
708                                 $xo = parse_xml_string($item["object"],false);
709                                 $xt = parse_xml_string($item["target"],false);
710                                 if($xt->type === ACTIVITY_OBJ_NOTE) {
711                                         $i = q("SELECT `id`, `contact-id`, `tag` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
712                                                 dbesc($xt->id),
713                                                 intval($importer["importer_uid"])
714                                         );
715                                         if(count($i)) {
716
717                                                 // For tags, the owner cannot remove the tag on the author's copy of the post.
718
719                                                 $owner_remove = (($item['contact-id'] == $i[0]['contact-id']) ? true: false);
720                                                 $author_remove = (($item['origin'] && $item['self']) ? true : false);
721                                                 $author_copy = (($item['origin']) ? true : false);
722
723                                                 if($owner_remove && $author_copy)
724                                                         continue;
725                                                 if($author_remove || $owner_remove) {
726                                                         $tags = explode(',',$i[0]['tag']);
727                                                         $newtags = array();
728                                                         if(count($tags)) {
729                                                                 foreach($tags as $tag)
730                                                                         if(trim($tag) !== trim($xo->body))
731                                                                                 $newtags[] = trim($tag);
732                                                         }
733                                                         q("UPDATE `item` SET `tag` = '%s' WHERE `id` = %d",
734                                                                 dbesc(implode(',',$newtags)),
735                                                                 intval($i[0]['id'])
736                                                         );
737                                                         create_tags_from_item($i[0]['id']);
738                                                 }
739                                         }
740                                 }
741                         }
742
743                         if($item['uri'] == $item['parent-uri']) {
744                                 $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s',
745                                                 `body` = '', `title` = ''
746                                         WHERE `parent-uri` = '%s' AND `uid` = %d",
747                                                 dbesc($when),
748                                                 dbesc(datetime_convert()),
749                                                 dbesc($item['uri']),
750                                                 intval($importer['uid'])
751                                         );
752                                         create_tags_from_itemuri($item['uri'], $importer['uid']);
753                                         create_files_from_itemuri($item['uri'], $importer['uid']);
754                                         update_thread_uri($item['uri'], $importer['uid']);
755                         } else {
756                                 $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s',
757                                                 `body` = '', `title` = ''
758                                         WHERE `uri` = '%s' AND `uid` = %d",
759                                                 dbesc($when),
760                                                 dbesc(datetime_convert()),
761                                                 dbesc($uri),
762                                                 intval($importer['uid'])
763                                         );
764                                 create_tags_from_itemuri($uri, $importer['uid']);
765                                 create_files_from_itemuri($uri, $importer['uid']);
766                                 if($item['last-child']) {
767                                         // ensure that last-child is set in case the comment that had it just got wiped.
768                                         q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d ",
769                                                 dbesc(datetime_convert()),
770                                                 dbesc($item['parent-uri']),
771                                                 intval($item['uid'])
772                                         );
773                                         // who is the last child now?
774                                         $r = q("SELECT `id` FROM `item` WHERE `parent-uri` = '%s' AND `type` != 'activity' AND `deleted` = 0 AND `moderated` = 0 AND `uid` = %d
775                                                 ORDER BY `created` DESC LIMIT 1",
776                                                         dbesc($item['parent-uri']),
777                                                         intval($importer['uid'])
778                                         );
779                                         if(count($r)) {
780                                                 q("UPDATE `item` SET `last-child` = 1 WHERE `id` = %d",
781                                                         intval($r[0]['id'])
782                                                 );
783                                         }
784                                 }
785                         }
786                 }
787         }
788
789         function import($xml,$importer, &$contact) {
790
791                 $a = get_app();
792
793                 logger("Import DFRN message", LOGGER_DEBUG);
794
795                 if ($xml == "")
796                         return;
797
798                 $doc = new DOMDocument();
799                 @$doc->loadXML($xml);
800
801                 $xpath = new DomXPath($doc);
802                 $xpath->registerNamespace('atom', NAMESPACE_ATOM1);
803                 $xpath->registerNamespace('thr', NAMESPACE_THREAD);
804                 $xpath->registerNamespace('at', NAMESPACE_TOMB);
805                 $xpath->registerNamespace('media', NAMESPACE_MEDIA);
806                 $xpath->registerNamespace('dfrn', NAMESPACE_DFRN);
807                 $xpath->registerNamespace('activity', NAMESPACE_ACTIVITY);
808                 $xpath->registerNamespace('georss', NAMESPACE_GEORSS);
809                 $xpath->registerNamespace('poco', NAMESPACE_POCO);
810                 $xpath->registerNamespace('ostatus', NAMESPACE_OSTATUS);
811                 $xpath->registerNamespace('statusnet', NAMESPACE_STATUSNET);
812
813                 if (!$contact) {
814                         $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `self`", intval($importer["uid"]));
815                         $contact = $r[0];
816                 }
817
818                 $header = array();
819                 $header["uid"] = $importer["uid"];
820                 $header["network"] = NETWORK_DFRN;
821                 $header["type"] = "remote";
822                 $header["wall"] = 0;
823                 $header["origin"] = 0;
824                 $header["gravity"] = GRAVITY_PARENT;
825                 $header["contact-id"] = $importer["id"];
826
827                 // Update the contact table if the data has changed
828                 // Only the "dfrn:owner" in the head section contains all data
829                 $dfrn_owner = self::fetchauthor($xpath, $doc->firstChild, $importer, "dfrn:owner", $contact, false);
830
831                 // is it a public forum? Private forums aren't supported by now with this method
832                 $forum = intval($xpath->evaluate('/atom:feed/dfrn:community/text()', $context)->item(0)->nodeValue);
833
834                 if ($forum AND ($dfrn_owner["contact-id"] != 0))
835                         q("UPDATE `contact` SET `forum` = %d WHERE `forum` != %d AND `id` = %d",
836                                 intval($forum), intval($forum),
837                                 intval($dfrn_owner["contact-id"])
838                         );
839
840                 $mails = $xpath->query('/atom:feed/dfrn:mail');
841                 foreach ($mails AS $mail)
842                         self::process_mail($xpath, $mail, $importer);
843
844                 $suggestions = $xpath->query('/atom:feed/dfrn:suggest');
845                 foreach ($suggestions AS $suggestion)
846                         self::process_suggestion($xpath, $suggestion, $importer);
847
848                 $relocations = $xpath->query('/atom:feed/dfrn:relocate');
849                 foreach ($relocations AS $relocation)
850                         self::process_relocation($xpath, $relocation, $importer);
851
852                 $deletions = $xpath->query('/atom:feed/at:deleted-entry');
853                 foreach ($deletions AS $deletion)
854                         self::process_deletion($header, $xpath, $deletion, $importer, $contact);
855
856                 $entries = $xpath->query('/atom:feed/atom:entry');
857                 foreach ($entries AS $entry)
858                         self::process_entry($header, $xpath, $entry, $importer, $contact);
859         }
860 }
861 ?>