*/
use Friendica\App;
+use Friendica\Core\System;
require_once("include/Contact.php");
require_once("include/ostatus.php");
* @brief Generate an atom entry for a given item id
*
* @param int $item_id The item id
+ * @param boolean $conversation Show the conversation. If false show the single post.
*
* @return string DFRN feed entry
*/
- public static function itemFeed($item_id) {
+ public static function itemFeed($item_id, $conversation = false) {
+ if ($conversation) {
+ $condition = '`item`.`parent`';
+ } else {
+ $condition = '`item`.`id`';
+ }
+
$r = q("SELECT `item`.*, `item`.`id` AS `item_id`,
`contact`.`name`, `contact`.`network`, `contact`.`photo`, `contact`.`url`,
`contact`.`name-date`, `contact`.`uri-date`, `contact`.`avatar-date`,
STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
AND (NOT `contact`.`blocked` OR `contact`.`pending`)
LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id`
- WHERE `item`.`id` = %d AND `item`.`visible` AND NOT `item`.`moderated` AND `item`.`parent` != 0
- AND `item`.`wall` AND NOT `item`.`private`",
+ WHERE %s = %d AND `item`.`visible` AND NOT `item`.`moderated` AND `item`.`parent` != 0
+ AND NOT `item`.`private`",
+ $condition,
intval($item_id)
);
killme();
}
+ $items = $r;
$item = $r[0];
$r = q("SELECT `contact`.*, `user`.`nickname`, `user`.`timezone`, `user`.`page-flags`, `user`.`account-type`
$doc = new DOMDocument('1.0', 'utf-8');
$doc->formatOutput = true;
+ $type = 'html';
- $alternatelink = $owner['url'];
+ if ($conversation) {
+ $root = $doc->createElementNS(NAMESPACE_ATOM1, 'feed');
+ $doc->appendChild($root);
- $root = self::add_header($doc, $owner, 'dfrn:owner', $alternatelink, true);
+ $root->setAttribute("xmlns:thr", NAMESPACE_THREAD);
+ $root->setAttribute("xmlns:at", NAMESPACE_TOMB);
+ $root->setAttribute("xmlns:media", NAMESPACE_MEDIA);
+ $root->setAttribute("xmlns:dfrn", NAMESPACE_DFRN);
+ $root->setAttribute("xmlns:activity", NAMESPACE_ACTIVITY);
+ $root->setAttribute("xmlns:georss", NAMESPACE_GEORSS);
+ $root->setAttribute("xmlns:poco", NAMESPACE_POCO);
+ $root->setAttribute("xmlns:ostatus", NAMESPACE_OSTATUS);
+ $root->setAttribute("xmlns:statusnet", NAMESPACE_STATUSNET);
- $type = 'html';
+ //$root = self::add_header($doc, $owner, "dfrn:owner", "", false);
- $entry = self::entry($doc, $type, $item, $owner, true);
- $root->appendChild($entry);
+ foreach ($items as $item) {
+ $entry = self::entry($doc, $type, $item, $owner, true, 0);
+ $root->appendChild($entry);
+ }
+ } else {
+ $root = self::entry($doc, $type, $item, $owner, true, 0, true);
+ }
$atom = trim($doc->saveXML());
return $atom;
$ext = Photo::supportedTypes();
foreach ($rp as $p) {
- $photos[$p['scale']] = App::get_baseurl().'/photo/'.$p['resource-id'].'-'.$p['scale'].'.'.$ext[$p['type']];
+ $photos[$p['scale']] = System::baseUrl().'/photo/'.$p['resource-id'].'-'.$p['scale'].'.'.$ext[$p['type']];
}
unset($rp, $ext);
$root->setAttribute("xmlns:ostatus", NAMESPACE_OSTATUS);
$root->setAttribute("xmlns:statusnet", NAMESPACE_STATUSNET);
- xml::add_element($doc, $root, "id", App::get_baseurl()."/profile/".$owner["nick"]);
+ xml::add_element($doc, $root, "id", System::baseUrl()."/profile/".$owner["nick"]);
xml::add_element($doc, $root, "title", $owner["name"]);
$attributes = array("uri" => "https://friendi.ca", "version" => FRIENDICA_VERSION."-".DB_UPDATE_VERSION);
if ($public) {
// DFRN itself doesn't uses this. But maybe someone else wants to subscribe to the public feed.
- ostatus::hublinks($doc, $root);
+ ostatus::hublinks($doc, $root, $owner["nick"]);
- $attributes = array("rel" => "salmon", "href" => App::get_baseurl()."/salmon/".$owner["nick"]);
+ $attributes = array("rel" => "salmon", "href" => System::baseUrl()."/salmon/".$owner["nick"]);
xml::add_element($doc, $root, "link", "", $attributes);
- $attributes = array("rel" => "http://salmon-protocol.org/ns/salmon-replies", "href" => App::get_baseurl()."/salmon/".$owner["nick"]);
+ $attributes = array("rel" => "http://salmon-protocol.org/ns/salmon-replies", "href" => System::baseUrl()."/salmon/".$owner["nick"]);
xml::add_element($doc, $root, "link", "", $attributes);
- $attributes = array("rel" => "http://salmon-protocol.org/ns/salmon-mention", "href" => App::get_baseurl()."/salmon/".$owner["nick"]);
+ $attributes = array("rel" => "http://salmon-protocol.org/ns/salmon-mention", "href" => System::baseUrl()."/salmon/".$owner["nick"]);
xml::add_element($doc, $root, "link", "", $attributes);
}
}
xml::add_element($doc, $author, "name", $owner["name"], $attributes);
- xml::add_element($doc, $author, "uri", App::get_baseurl().'/profile/'.$owner["nickname"], $attributes);
+ xml::add_element($doc, $author, "uri", System::baseUrl().'/profile/'.$owner["nickname"], $attributes);
xml::add_element($doc, $author, "dfrn:handle", $owner["addr"], $attributes);
$attributes = array("rel" => "photo", "type" => "image/jpeg",
* @param array $owner Owner record
* @param bool $comment Trigger the sending of the "comment" element
* @param int $cid Contact ID of the recipient
+ * @param bool $single If set, the entry is created as an XML document with a single "entry" element
*
* @return object XML entry object
* @todo Add type-hints
*/
- private static function entry($doc, $type, $item, $owner, $comment = false, $cid = 0) {
+ private static function entry($doc, $type, $item, $owner, $comment = false, $cid = 0, $single = false) {
$mentioned = array();
return xml::create_element($doc, "at:deleted-entry", "", $attributes);
}
- $entry = $doc->createElement("entry");
+ if (!$single) {
+ $entry = $doc->createElement("entry");
+ } else {
+ $entry = $doc->createElementNS(NAMESPACE_ATOM1, 'entry');
+ $doc->appendChild($entry);
+
+ $entry->setAttribute("xmlns:thr", NAMESPACE_THREAD);
+ $entry->setAttribute("xmlns:at", NAMESPACE_TOMB);
+ $entry->setAttribute("xmlns:media", NAMESPACE_MEDIA);
+ $entry->setAttribute("xmlns:dfrn", NAMESPACE_DFRN);
+ $entry->setAttribute("xmlns:activity", NAMESPACE_ACTIVITY);
+ $entry->setAttribute("xmlns:georss", NAMESPACE_GEORSS);
+ $entry->setAttribute("xmlns:poco", NAMESPACE_POCO);
+ $entry->setAttribute("xmlns:ostatus", NAMESPACE_OSTATUS);
+ $entry->setAttribute("xmlns:statusnet", NAMESPACE_STATUSNET);
+ }
if ($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid']) {
$body = fix_private_photos($item['body'],$owner['uid'],$item,$cid);
$entry->appendChild($dfrnowner);
if (($item['parent'] != $item['id']) || ($item['parent-uri'] !== $item['uri']) || (($item['thr-parent'] !== '') && ($item['thr-parent'] !== $item['uri']))) {
- $parent = q("SELECT `guid` FROM `item` WHERE `id` = %d", intval($item["parent"]));
$parent_item = (($item['thr-parent']) ? $item['thr-parent'] : $item['parent-uri']);
+ $parent = q("SELECT `guid`,`plink` FROM `item` WHERE `uri` = '%s' AND `uid` = %d", dbesc($parent_item), intval($item['uid']));
$attributes = array("ref" => $parent_item, "type" => "text/html",
- "href" => App::get_baseurl().'/display/'.$parent[0]['guid'],
+ "href" => $parent[0]['plink'],
"dfrn:diaspora_guid" => $parent[0]['guid']);
xml::add_element($doc, $entry, "thr:in-reply-to", "", $attributes);
}
// Add conversation data. This is used for OStatus
- $conversation_href = App::get_baseurl()."/display/".$owner["nick"]."/".$item["parent"];
+ $conversation_href = System::baseUrl()."/display/".$owner["nick"]."/".$item["parent"];
$conversation_uri = $conversation_href;
if (isset($parent_item)) {
// We save this value in "plink". Maybe we should read it from there as well?
xml::add_element($doc, $entry, "link", "", array("rel" => "alternate", "type" => "text/html",
- "href" => App::get_baseurl()."/display/".$item["guid"]));
+ "href" => System::baseUrl()."/display/".$item["guid"]));
// "comment-allow" is some old fashioned stuff for old Friendica versions.
// It is included in the rewritten code for completeness
$res = parse_xml_string($xml);
- return $res->status;
+ if (!isset($res->status)) {
+ return -11;
+ }
+
+ if (!empty($res->message)) {
+ logger('Delivery returned status '.$res->status.' - '.$res->message, LOGGER_DEBUG);
+ }
+
+ return intval($res->status);
}
/**
$msg["seen"] = 0;
$msg["replied"] = 0;
- dbm::esc_array($msg, true);
-
- $r = dbq("INSERT INTO `mail` (`".implode("`, `", array_keys($msg))."`) VALUES (".implode(", ", array_values($msg)).")");
+ dba::insert('mail', $msg);
// send notifications.
/// @TODO Arange this mess
"to_email" => $importer["email"],
"uid" => $importer["importer_uid"],
"item" => $suggest,
- "link" => App::get_baseurl()."/notifications/intros",
+ "link" => System::baseUrl()."/notifications/intros",
"source_name" => $importer["name"],
"source_link" => $importer["url"],
"source_photo" => $importer["photo"],
return true;
}
+ /**
+ * @brief Check and possibly rewrite a post if it was a dedicated forum post
+ *
+ * @param array $item the new item record
+ *
+ * @return boolean Was the post be rewritten?
+ */
+ private static function rewriteDedicatedForumPost($item) {
+ $fields = array('author-link', 'allow_cid', 'contact-id', 'private', 'wall', 'id', 'parent');
+ $condition = array('uri' => $item['uri'], 'uid' => $item['uid']);
+ $existing = dba::select('item', $fields, $condition, array('limit' => 1));
+ if (!dbm::is_result($existing)) {
+ return false;
+ }
+
+ // Only rewrite if the former post was a private starting post
+ if (!$existing['wall'] || !$existing['private'] || ($existing['id'] != $existing['parent'])) {
+ return false;
+ }
+
+ // Is the post only directed to a single forum?
+ if ($existing['allow_cid'] != '<'.$item['contact-id'].'>') {
+ return false;
+ }
+
+ $fields = array('id');
+ $condition = array('uid' => $item['uid'], 'self' => true);
+ $self = dba::select('contact', $fields, $condition, array('limit' => 1));
+ if (!dbm::is_result($self)) {
+ return false;
+ }
+
+ // is the original item created by the "self" user.
+ if ($self['id'] != $existing['contact-id']) {
+ return false;
+ }
+
+ $fields = array('forum', 'prv');
+ $condition = array('id' => $item['contact-id']);
+ $contact = dba::select('contact', $fields, $condition, array('limit' => 1));
+ if (!dbm::is_result($contact)) {
+ return false;
+ }
+
+ // Is the post from a forum?
+ if (!$contact['forum'] && !$contact['prv']) {
+ return false;
+ }
+
+ /// @todo There is an ugly downside of this whole rewrite process: These items loose the ability to be edited by the user.
+ logger('Item '.$item['uri'].' will be rewritten.', LOGGER_DEBUG);
+
+ $item = store_conversation($item);
+ unset($fields['dsprsig']);
+
+ // Rewrite to a public post if it comes from a public forum
+ if ($contact['forum']) {
+ $item['allow_cid'] = '';
+ $item['allow_gid'] = '';
+ $item['deny_cid'] = '';
+ $item['deny_gid'] = '';
+ $item['private'] = false;
+ }
+
+ $item['wall'] = false;
+
+ $item["owner-id"] = get_contact($item["owner-link"], 0);
+
+ $condition = array('uri' => $item["uri"], 'uid' => $item["uid"]);
+ dba::update('item', $item, $condition);
+
+ add_shadow_thread($existing['id']);
+ return true;
+ }
+
/**
* @brief Updates an item
*
return false;
}
- $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d",
- dbesc($item["title"]),
- dbesc($item["body"]),
- dbesc($item["tag"]),
- dbesc(datetime_convert("UTC","UTC",$item["edited"])),
- dbesc(datetime_convert()),
- dbesc($item["uri"]),
- intval($importer["importer_uid"])
- );
+ if (!self::rewriteDedicatedForumPost($item)) {
+ $fields = array('title' => $item["title"], 'body' => $item["body"],
+ 'tag' => $item["tag"], 'changed' => datetime_convert(),
+ 'edited' => datetime_convert("UTC", "UTC", $item["edited"]));
+
+ $condition = array("`uri` = ? AND `uid` IN (0, ?)", $item["uri"], $importer["importer_uid"]);
+ dba::update('item', $fields, $condition);
+ }
+
create_tags_from_itemuri($item["uri"], $importer["importer_uid"]);
update_thread_uri($item["uri"], $importer["importer_uid"]);
// update last-child if it changes
if ($item["last-child"] && ($item["last-child"] != $current["last-child"])) {
- $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d",
+ $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` IN (0, %d)",
dbesc(datetime_convert()),
dbesc($item["parent-uri"]),
intval($importer["importer_uid"])
);
- $r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d",
+ $r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s' WHERE `uri` = '%s' AND `uid` IN (0, %d)",
intval($item["last-child"]),
dbesc(datetime_convert()),
dbesc($item["uri"]),
}
}
- if ($Blink && link_compare($Blink, App::get_baseurl() . "/profile/" . $importer["nickname"])) {
+ if ($Blink && link_compare($Blink, System::baseUrl() . "/profile/" . $importer["nickname"])) {
// send a notification
notification(array(
"to_email" => $importer["email"],
"uid" => $importer["importer_uid"],
"item" => $item,
- "link" => App::get_baseurl()."/display/".urlencode(get_item_guid($posted_id)),
+ "link" => System::baseUrl()."/display/".urlencode(get_item_guid($posted_id)),
"source_name" => stripslashes($item["author-name"]),
"source_link" => $item["author-link"],
"source_photo" => ((link_compare($item["author-link"],$importer["url"]))
if ($entrytype == DFRN_TOP_LEVEL) {
$r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s',
`body` = '', `title` = ''
- WHERE `parent-uri` = '%s' AND `uid` = %d",
+ WHERE `parent-uri` = '%s' AND `uid` IN (0, %d)",
dbesc($when),
dbesc(datetime_convert()),
dbesc($uri),
} else {
$r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s',
`body` = '', `title` = ''
- WHERE `uri` = '%s' AND `uid` = %d",
+ WHERE `uri` = '%s' AND `uid` IN (0, %d)",
dbesc($when),
dbesc(datetime_convert()),
dbesc($uri),
update_thread_uri($uri, $importer["importer_uid"]);
if ($item["last-child"]) {
// ensure that last-child is set in case the comment that had it just got wiped.
- q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d ",
+ q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` IN (0, %d)",
dbesc(datetime_convert()),
dbesc($item["parent-uri"]),
intval($item["uid"])
* @param text $xml The DFRN message
* @param array $importer Record of the importer user mixed with contact of the content
* @param bool $sort_by_date Is used when feeds are polled
+ * @return integer Import status
* @todo set proper type-hints
*/
- public static function import($xml,$importer, $sort_by_date = false) {
+ public static function import($xml, $importer, $sort_by_date = false) {
if ($xml == "") {
- return;
- }
-
- if ($importer["readonly"]) {
- // We aren't receiving stuff from this person. But we will quietly ignore them
- // rather than a blatant "go away" message.
- logger('ignoring contact '.$importer["id"]);
- return;
+ return 400;
}
$doc = new DOMDocument();
$accounttype = intval($xpath->evaluate("/atom:feed/dfrn:account_type/text()", $context)->item(0)->nodeValue);
if ($accounttype != $importer["contact-type"]) {
- /// @TODO this way is the norm or putting ); at the end of the line?
- q("UPDATE `contact` SET `contact-type` = %d WHERE `id` = %d",
- intval($accounttype),
- intval($importer["id"])
- );
+ dba::update('contact', array('contact-type' => $accounttype), array('id' => $importer["id"]));
}
}
$forum = intval($xpath->evaluate("/atom:feed/dfrn:community/text()", $context)->item(0)->nodeValue);
if ($forum != $importer["forum"]) {
- q("UPDATE `contact` SET `forum` = %d WHERE `forum` != %d AND `id` = %d",
- intval($forum), intval($forum),
- intval($importer["id"])
- );
+ $condition = array('`forum` != ? AND `id` = ?', $forum, $importer["id"]);
+ dba::update('contact', array('forum' => $forum), $condition);
+ }
+
+ // We are processing relocations even if we are ignoring a contact
+ $relocations = $xpath->query("/atom:feed/dfrn:relocate");
+ foreach ($relocations AS $relocation) {
+ self::process_relocation($xpath, $relocation, $importer);
+ }
+
+ if ($importer["readonly"]) {
+ // We aren't receiving stuff from this person. But we will quietly ignore them
+ // rather than a blatant "go away" message.
+ logger('ignoring contact '.$importer["id"]);
+ return 403;
}
$mails = $xpath->query("/atom:feed/dfrn:mail");
self::process_suggestion($xpath, $suggestion, $importer);
}
- $relocations = $xpath->query("/atom:feed/dfrn:relocate");
- foreach ($relocations AS $relocation) {
- self::process_relocation($xpath, $relocation, $importer);
- }
-
$deletions = $xpath->query("/atom:feed/at:deleted-entry");
foreach ($deletions AS $deletion) {
self::process_deletion($xpath, $deletion, $importer);
}
}
logger("Import done for user " . $importer["uid"] . " from contact " . $importer["id"], LOGGER_DEBUG);
+ return 200;
}
}