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");
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");
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/");
32 * @brief Add new birthday event for this person
34 * @param array $contact Contact record
35 * @param string $birthday Birthday of the contact
38 private function birthday_event($contact, $birthday) {
40 logger('updating birthday: '.$birthday.' for contact '.$contact['id']);
42 $bdtext = sprintf(t('%s\'s birthday'), $contact['name']);
43 $bdtext2 = sprintf(t('Happy Birthday %s'), ' [url=' . $contact['url'].']'.$contact['name'].'[/url]' ) ;
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 ')),
61 * @brief Fetch the author data from head or entry items
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
70 * @return Returns an array with relevant data of the author
72 private function fetchauthor($xpath, $context, $importer, $element, &$contact, $onlyfetch) {
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;
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));
85 $author["contact-id"] = $r[0]["id"];
86 $author["network"] = $r[0]["network"];
88 $author["contact-id"] = $contact["id"];
89 $author["network"] = $contact["network"];
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) {
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;
107 if (($width > 0) AND ($href != ""))
108 $avatarlist[$width] = $href;
110 if (count($avatarlist) > 0) {
112 $author["avatar"] = current($avatarlist);
115 //$onlyfetch = true; // Test
117 if ($r AND !$onlyfetch) {
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;
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;
130 // Update contact data
131 $value = $xpath->evaluate($element.'/dfrn:handle/text()', $context)->item(0)->nodeValue;
133 $contact["addr"] = $value;
135 $value = $xpath->evaluate($element.'/poco:displayName/text()', $context)->item(0)->nodeValue;
137 $contact["name"] = $value;
139 $value = $xpath->evaluate($element.'/poco:preferredUsername/text()', $context)->item(0)->nodeValue;
141 $contact["nick"] = $value;
143 $value = $xpath->evaluate($element.'/poco:note/text()', $context)->item(0)->nodeValue;
145 $contact["about"] = $value;
147 $value = $xpath->evaluate($element.'/poco:address/poco:formatted/text()', $context)->item(0)->nodeValue;
149 $contact["location"] = $value;
151 /// @todo Add support for the following fields that we don't support by now in the contact table:
159 // Save the keywords into the contact table
161 $tagelements = $xpath->evaluate($element.'/poco:tags/text()', $context);
162 foreach($tagelements AS $tag)
163 $tags[$tag->nodeValue] = $tag->nodeValue;
166 $contact["keywords"] = implode(", ", $tags);
168 // "dfrn:birthday" contains the birthday converted to UTC
169 $old_bdyear = $contact["bdyear"];
171 $birthday = $xpath->evaluate($element.'/dfrn:birthday/text()', $context)->item(0)->nodeValue;
173 if (strtotime($birthday) > time()) {
174 $bd_timestamp = strtotime($birthday);
176 $contact["bdyear"] = date("Y", $bd_timestamp);
179 // "poco:birthday" is the birthday in the format "yyyy-mm-dd"
180 $value = $xpath->evaluate($element.'/poco:birthday/text()', $context)->item(0)->nodeValue;
182 if (!in_array($value, array("", "0000-00-00"))) {
184 $value = str_replace("0000", $bdyear, $value);
186 if (strtotime($value) < time()) {
187 $value = str_replace($bdyear, $bdyear + 1, $value);
188 $bdyear = $bdyear + 1;
191 $contact["bd"] = $value;
194 if ($old_bdyear != $contact["bdyear"])
195 self::birthday_event($contact, $birthday);
197 // Get all field names
199 foreach ($r[0] AS $field => $data)
200 $fields[$field] = $data;
202 unset($fields["id"]);
203 unset($fields["uid"]);
205 foreach ($fields AS $field => $data)
206 if ($contact[$field] != $r[0][$field])
210 logger("Update contact data for contact ".$contact["id"], LOGGER_DEBUG);
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"]));
222 update_contact_avatar($author["avatar"], $importer["uid"], $contact["id"], ($contact["avatar-date"] != $r[0]["avatar-date"]));
224 $contact["generation"] = 2;
225 $contact["photo"] = $author["avatar"];
226 update_gcontact($contact);
232 private function transform_activity($xpath, $activity, $element) {
233 if (!is_object($activity))
236 $obj_doc = new DOMDocument('1.0', 'utf-8');
237 $obj_doc->formatOutput = true;
239 $obj_element = $obj_doc->createElementNS(NS_ATOM, $element);
241 $activity_type = $xpath->query('activity:object-type/text()', $activity)->item(0)->nodeValue;
242 xml_add_element($obj_doc, $obj_element, "type", $activity_type);
244 $id = $xpath->query('atom:id', $activity)->item(0);
246 $obj_element->appendChild($obj_doc->importNode($id, true));
248 $title = $xpath->query('atom:title', $activity)->item(0);
249 if (is_object($title))
250 $obj_element->appendChild($obj_doc->importNode($title, true));
252 $link = $xpath->query('atom:link', $activity)->item(0);
253 if (is_object($link))
254 $obj_element->appendChild($obj_doc->importNode($link, true));
256 $content = $xpath->query('atom:content', $activity)->item(0);
257 if (is_object($content))
258 $obj_element->appendChild($obj_doc->importNode($content, true));
260 $obj_doc->appendChild($obj_element);
262 $objxml = $obj_doc->saveXML($obj_element);
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);
269 private function process_mail($xpath, $mail, $importer) {
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;
287 $r = dbq("INSERT INTO `mail` (`".implode("`, `", array_keys($msg))."`) VALUES ('".implode("', '", array_values($msg))."')");
289 // send notifications.
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'],
299 'source_name' => $msg['from-name'],
300 'source_link' => $importer['url'],
301 'source_photo' => $importer['thumb'],
302 'verb' => ACTIVITY_POST,
306 notification($notif_params);
309 private function process_suggestion($xpath, $suggestion, $importer) {
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;
320 // Does our member already have a friend matching this description?
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"])
330 // Do we already have an fcontact record for this person?
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"])
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"]),
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"])
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"])
364 // database record did not get created. Quietly give up.
368 $hash = random_string();
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"]),
374 intval($suggest["cid"]),
375 dbesc($suggest["body"]),
377 dbesc(datetime_convert()),
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"],
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,
401 private function process_relocation($xpath, $relocation, $importer) {
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;
418 $r = q("SELECT `photo`, `url` FROM `contact` WHERE `id` = %d AND `uid` = %d;",
419 intval($importer["id"]),
420 intval($importer["importer_uid"]));
426 $x = q("UPDATE `contact` SET
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"]));
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"]),
463 foreach ($fields as $n=>$f){
464 $x = q("UPDATE `item` SET `%s` = '%s' WHERE `%s` = '%s' AND `uid` = %d",
467 intval($importer["importer_uid"]));
473 /// merge with current record, current contents have priority
474 /// update record, set url-updated
475 /// update profile photos
480 private function process_entry($header, $xpath, $entry, $importer, $contact) {
484 $owner = self::fetchauthor($xpath, $entry, $importer, "dfrn:owner", $contact, true);
486 $item["owner-name"] = $owner["name"];
487 $item["owner-link"] = $owner["link"];
488 $item["owner-avatar"] = $owner["avatar"];
490 if ($header["contact-id"] != $owner["contact-id"])
491 $item["contact-id"] = $owner["contact-id"];
493 if (($header["network"] != $owner["network"]) AND ($owner["network"] != ""))
494 $item["network"] = $owner["network"];
497 $author = self::fetchauthor($xpath, $entry, $importer, "atom:author", $contact, true);
499 $item["author-name"] = $author["name"];
500 $item["author-link"] = $author["link"];
501 $item["author-avatar"] = $author["avatar"];
503 if ($header["contact-id"] != $author["contact-id"])
504 $item["contact-id"] = $author["contact-id"];
506 if (($header["network"] != $author["network"]) AND ($author["network"] != ""))
507 $item["network"] = $author["network"];
510 $item["uri"] = $xpath->query('atom:id/text()', $entry)->item(0)->nodeValue;
512 $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s'",
513 intval($importer["uid"]), dbesc($item["uri"]));
515 //logger("Item with uri ".$item["uri"]." for user ".$importer["uid"]." already existed under id ".$r[0]["id"], LOGGER_DEBUG);
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;
526 foreach($inreplyto->item(0)->attributes AS $attributes) {
527 if ($attributes->name == "ref")
528 $item["parent-uri"] = $attributes->textContent;
531 $objecttype = ACTIVITY_OBJ_NOTE;
532 $item["parent-uri"] = $item["uri"];
535 $item["title"] = $xpath->query('atom:title/text()', $entry)->item(0)->nodeValue;
537 $item["created"] = $xpath->query('atom:published/text()', $entry)->item(0)->nodeValue;
538 $item["edited"] = $xpath->query('atom:updated/text()', $entry)->item(0)->nodeValue;
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"]));
545 $item["body"] = limit_body_size($item["body"]);
547 /// @todo Do we need the old check for HTML elements?
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;
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;
555 $georsspoint = $xpath->query('georss:point', $entry);
557 $item["coord"] = $georsspoint->item(0)->nodeValue;
559 $item["private"] = $xpath->query('dfrn:private/text()', $entry)->item(0)->nodeValue;
561 $item["extid"] = $xpath->query('dfrn:extid/text()', $entry)->item(0)->nodeValue;
563 if ($xpath->query('dfrn:extid/text()', $entry)->item(0)->nodeValue == "true")
564 $item["bookmark"] = true;
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);
574 $item["guid"] = $xpath->query('dfrn:diaspora_guid/text()', $entry)->item(0)->nodeValue;
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;
579 $item["verb"] = $xpath->query('activity:verb/text()', $entry)->item(0)->nodeValue;
581 if ($xpath->query('activity:object-type/text()', $entry)->item(0)->nodeValue != "")
582 $objecttype = $xpath->query('activity:object-type/text()', $entry)->item(0)->nodeValue;
584 $item["object-type"] = $objecttype;
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");
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");
594 $categories = $xpath->query('atom:category', $entry);
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"]))
603 $item["tag"] .= "#[url=".$a->get_baseurl()."/search?tag=".$term."]".$term."[/url]";
610 $links = $xpath->query('atom:link', $entry);
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;
630 if (($rel != "") AND ($href != ""))
633 $item["plink"] = $href;
637 if(strlen($item["attach"]))
638 $item["attach"] .= ',';
640 $item["attach"] .= '[attach]href="'.$href.'" length="'.$length.'" type="'.$type.'" title="'.$title.'"[/attach]';
647 $item_id = item_store($item);
652 logger("Error storing item", LOGGER_DEBUG);
655 logger("Item was stored with id ".$item_id, LOGGER_DEBUG);
658 $signature = json_decode(base64_decode($signature));
660 // Check for falsely double encoded signatures
661 $signature->signature = diaspora_repair_signature($signature->signature, $signature->signer);
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')",
666 dbesc($signature->signed_text),
667 dbesc($signature->signature),
668 dbesc($signature->signer)
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;
683 $when = datetime_convert('UTC','UTC', $when, 'Y-m-d H:i:s');
685 $when = datetime_convert('UTC','UTC','now','Y-m-d H:i:s');
687 if (!$uri OR !is_array($contact))
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",
693 intval($importer["uid"]),
694 intval($contact["id"])
699 if(!$item["deleted"])
700 logger('deleting item '.$item["id"].' uri='.$item['uri'], LOGGER_DEBUG);
702 if($item["object-type"] === ACTIVITY_OBJ_EVENT) {
703 logger("Deleting event ".$item["event-id"], LOGGER_DEBUG);
704 event_delete($item["event-id"]);
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",
713 intval($importer["importer_uid"])
717 // For tags, the owner cannot remove the tag on the author's copy of the post.
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);
723 if($owner_remove && $author_copy)
725 if($author_remove || $owner_remove) {
726 $tags = explode(',',$i[0]['tag']);
729 foreach($tags as $tag)
730 if(trim($tag) !== trim($xo->body))
731 $newtags[] = trim($tag);
733 q("UPDATE `item` SET `tag` = '%s' WHERE `id` = %d",
734 dbesc(implode(',',$newtags)),
737 create_tags_from_item($i[0]['id']);
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",
748 dbesc(datetime_convert()),
750 intval($importer['uid'])
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']);
756 $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s',
757 `body` = '', `title` = ''
758 WHERE `uri` = '%s' AND `uid` = %d",
760 dbesc(datetime_convert()),
762 intval($importer['uid'])
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']),
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'])
780 q("UPDATE `item` SET `last-child` = 1 WHERE `id` = %d",
789 function import($xml,$importer, &$contact) {
793 logger("Import DFRN message", LOGGER_DEBUG);
798 $doc = new DOMDocument();
799 @$doc->loadXML($xml);
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);
814 $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `self`", intval($importer["uid"]));
819 $header["uid"] = $importer["uid"];
820 $header["network"] = NETWORK_DFRN;
821 $header["type"] = "remote";
823 $header["origin"] = 0;
824 $header["gravity"] = GRAVITY_PARENT;
825 $header["contact-id"] = $importer["id"];
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);
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);
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"])
840 $mails = $xpath->query('/atom:feed/dfrn:mail');
841 foreach ($mails AS $mail)
842 self::process_mail($xpath, $mail, $importer);
844 $suggestions = $xpath->query('/atom:feed/dfrn:suggest');
845 foreach ($suggestions AS $suggestion)
846 self::process_suggestion($xpath, $suggestion, $importer);
848 $relocations = $xpath->query('/atom:feed/dfrn:relocate');
849 foreach ($relocations AS $relocation)
850 self::process_relocation($xpath, $relocation, $importer);
852 $deletions = $xpath->query('/atom:feed/at:deleted-entry');
853 foreach ($deletions AS $deletion)
854 self::process_deletion($header, $xpath, $deletion, $importer, $contact);
856 $entries = $xpath->query('/atom:feed/atom:entry');
857 foreach ($entries AS $entry)
858 self::process_entry($header, $xpath, $entry, $importer, $contact);