X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=include%2Fitems.php;h=e8fc739cd0852839c5011cb4ec7a34de2ea25824;hb=e3b6770ad4b452841da25d5275ae8e2fbcb5b148;hp=2f03818a76bae0e2099df620a75016a04ec6f1b5;hpb=6253d6180309d491543814f57b788fe4759736d0;p=friendica.git diff --git a/include/items.php b/include/items.php old mode 100755 new mode 100644 index 2f03818a76..e8fc739cd0 --- a/include/items.php +++ b/include/items.php @@ -11,6 +11,7 @@ require_once('include/text.php'); require_once('include/email.php'); require_once('include/ostatus_conversation.php'); require_once('include/threads.php'); +require_once('include/socgraph.php'); function get_feed_for(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0) { @@ -163,6 +164,11 @@ function get_feed_for(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0) $salmon = feed_salmonlinks($owner_nick); + $alternatelink = $owner['url']; + + if(isset($category)) + $alternatelink .= "/category/".$category; + $atom .= replace_macros($feed_template, array( '$version' => xmlify(FRIENDICA_VERSION), '$feed_id' => xmlify($a->get_baseurl() . '/profile/' . $owner_nick), @@ -170,6 +176,7 @@ function get_feed_for(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0) '$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', 'now' , ATOM_TIME)) , '$hub' => $hubxml, '$salmon' => $salmon, + '$alternatelink' => xmlify($alternatelink), '$name' => xmlify($owner['name']), '$profile_page' => xmlify($owner['url']), '$photo' => xmlify($owner['photo']), @@ -438,6 +445,12 @@ function get_atom_elements($feed, $item, $contact = array()) { $res['body'] = unxmlify($item->get_content()); $res['plink'] = unxmlify($item->get_link(0)); + if (isset($contact["network"]) AND ($contact["network"] == NETWORK_FEED) AND strstr($res['plink'], ".app.net/")) { + logger("get_atom_elements: detected app.net posting: ".print_r($res, true), LOGGER_DEBUG); + $res['title'] = ""; + $res['body'] = nl2br($res['body']); + } + // removing the content of the title if its identically to the body // This helps with auto generated titles e.g. from tumblr if (title_is_body($res["title"], $res["body"])) @@ -672,6 +685,10 @@ function get_atom_elements($feed, $item, $contact = array()) { if($rawgeo) $res['coord'] = unxmlify($rawgeo[0]['data']); + if ($contact["network"] == NETWORK_FEED) { + $res['verb'] = ACTIVITY_POST; + $res['object-type'] = ACTIVITY_OBJ_NOTE; + } $rawverb = $item->get_item_tags(NAMESPACE_ACTIVITY, 'verb'); @@ -856,30 +873,34 @@ function get_atom_elements($feed, $item, $contact = array()) { } if (isset($contact["network"]) AND ($contact["network"] == NETWORK_FEED) AND $contact['fetch_further_information']) { - $res["body"] = $res["title"].add_page_info($res['plink']); + $preview = ""; + + // Handle enclosures and treat them as preview picture + if (isset($attach)) + foreach ($attach AS $attachment) + if ($attachment->type == "image/jpeg") + $preview = $attachment->link; + + $res["body"] = $res["title"].add_page_info($res['plink'], false, $preview, ($contact['fetch_further_information'] == 2), $contact['ffi_keyword_blacklist']); + $res["tag"] = add_page_keywords($res['plink'], false, $preview, ($contact['fetch_further_information'] == 2), $contact['ffi_keyword_blacklist']); $res["title"] = ""; + $res["object-type"] = ACTIVITY_OBJ_BOOKMARK; + unset($res["attach"]); } elseif (isset($contact["network"]) AND ($contact["network"] == NETWORK_OSTATUS)) $res["body"] = add_page_info_to_body($res["body"]); + elseif (isset($contact["network"]) AND ($contact["network"] == NETWORK_FEED) AND strstr($res['plink'], ".app.net/")) { + $res["body"] = add_page_info_to_body($res["body"]); + } $arr = array('feed' => $feed, 'item' => $item, 'result' => $res); call_hooks('parse_atom', $arr); - //if (($res["title"] != "") or (strpos($res["body"], "RT @") > 0)) { - //if (strpos($res["body"], "RT @") !== false) { - /*if (strpos($res["body"], "@") !== false) { - $debugfile = tempnam("/var/www/virtual/pirati.ca/phptmp/", "item-res2-"); - file_put_contents($debugfile, serialize($arr)); - }*/ - return $res; } -function add_page_info($url, $no_photos = false) { - require_once("mod/parse_url.php"); - $data = parseurl_getsiteinfo($url, true); - - logger('add_page_info: fetch page info for '.$url.' '.print_r($data, true), LOGGER_DEBUG); +function add_page_info_data($data) { + call_hooks('page_info_data', $data); // It maybe is a rich content, but if it does have everything that a link has, // then treat it that way @@ -887,51 +908,145 @@ function add_page_info($url, $no_photos = false) { is_string($data["text"]) AND (sizeof($data["images"]) > 0)) $data["type"] = "link"; - if ((($data["type"] != "link") AND ($data["type"] != "video") AND ($data["type"] != "photo")) OR ($data["title"] == $url)) - return(""); + if ((($data["type"] != "link") AND ($data["type"] != "video") AND ($data["type"] != "photo")) OR ($data["title"] == $url)) + return(""); if ($no_photos AND ($data["type"] == "photo")) return(""); - if (($data["type"] != "photo") AND is_string($data["title"])) - $text .= "[bookmark=".$url."]".trim($data["title"])."[/bookmark]"; + // If the link contains BBCode stuff, make a short link out of this to avoid parsing problems + if (strpos($data["url"], '[') OR strpos($data["url"], ']')) { + require_once("include/network.php"); + $data["url"] = short_link($data["url"]); + } - if (($data["type"] != "video") AND (sizeof($data["images"]) > 0)) { - $imagedata = $data["images"][0]; - $text .= '[img]'.$imagedata["src"].'[/img]'; - } + if (($data["type"] != "photo") AND is_string($data["title"])) + $text .= "[bookmark=".$data["url"]."]".trim($data["title"])."[/bookmark]"; - if (($data["type"] != "photo") AND is_string($data["text"])) - $text .= "[quote]".$data["text"]."[/quote]"; + if (($data["type"] != "video") AND ($photo != "")) + $text .= '[img]'.$photo.'[/img]'; + elseif (($data["type"] != "video") AND (sizeof($data["images"]) > 0)) { + $imagedata = $data["images"][0]; + $text .= '[img]'.$imagedata["src"].'[/img]'; + } - return("\n[class=type-".$data["type"]."]".$text."[/class]"); + if (($data["type"] != "photo") AND is_string($data["text"])) + $text .= "[quote]".$data["text"]."[/quote]"; + + $hashtags = ""; + if (isset($data["keywords"]) AND count($data["keywords"])) { + $a = get_app(); + $hashtags = "\n"; + foreach ($data["keywords"] AS $keyword) { + $hashtag = str_replace(array(" ", "+", "/", ".", "#", "'"), + array("","", "", "", "", ""), $keyword); + $hashtags .= "#[url=".$a->get_baseurl()."/search?tag=".rawurlencode($hashtag)."]".$hashtag."[/url] "; + } + } + + return("\n[class=type-".$data["type"]."]".$text."[/class]".$hashtags); +} + +function query_page_info($url, $no_photos = false, $photo = "", $keywords = false, $keyword_blacklist = "") { + require_once("mod/parse_url.php"); + + $data = Cache::get("parse_url:".$url); + if (is_null($data)){ + $data = parseurl_getsiteinfo($url, true); + Cache::set("parse_url:".$url,serialize($data)); + } else + $data = unserialize($data); + + if ($photo != "") + $data["images"][0]["src"] = $photo; + + logger('fetch page info for '.$url.' '.print_r($data, true), LOGGER_DEBUG); + + if (!$keywords AND isset($data["keywords"])) + unset($data["keywords"]); + + if (($keyword_blacklist != "") AND isset($data["keywords"])) { + $list = explode(",", $keyword_blacklist); + foreach ($list AS $keyword) { + $keyword = trim($keyword); + $index = array_search($keyword, $data["keywords"]); + if ($index !== false) + unset($data["keywords"][$index]); + } + } + + return($data); +} + +function add_page_keywords($url, $no_photos = false, $photo = "", $keywords = false, $keyword_blacklist = "") { + $data = query_page_info($url, $no_photos, $photo, $keywords, $keyword_blacklist); + + $tags = ""; + if (isset($data["keywords"]) AND count($data["keywords"])) { + $a = get_app(); + foreach ($data["keywords"] AS $keyword) { + $hashtag = str_replace(array(" ", "+", "/", ".", "#", "'"), + array("","", "", "", "", ""), $keyword); + + if ($tags != "") + $tags .= ","; + + $tags .= "#[url=".$a->get_baseurl()."/search?tag=".rawurlencode($hashtag)."]".$hashtag."[/url]"; + } + } + + return($tags); +} + +function add_page_info($url, $no_photos = false, $photo = "", $keywords = false, $keyword_blacklist = "") { + $data = query_page_info($url, $no_photos, $photo, $keywords, $keyword_blacklist); + + $text = add_page_info_data($data); + + return($text); } function add_page_info_to_body($body, $texturl = false, $no_photos = false) { - logger('add_page_info_to_body: fetch page info for body '.$body, LOGGER_DEBUG); + logger('add_page_info_to_body: fetch page info for body '.$body, LOGGER_DEBUG); - $URLSearchString = "^\[\]"; + $URLSearchString = "^\[\]"; - // Adding these spaces is a quick hack due to my problems with regular expressions :) - preg_match("/[^!#@]\[url\]([$URLSearchString]*)\[\/url\]/ism", " ".$body, $matches); + // Adding these spaces is a quick hack due to my problems with regular expressions :) + preg_match("/[^!#@]\[url\]([$URLSearchString]*)\[\/url\]/ism", " ".$body, $matches); - if (!$matches) - preg_match("/[^!#@]\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", " ".$body, $matches); + if (!$matches) + preg_match("/[^!#@]\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", " ".$body, $matches); // Convert urls without bbcode elements if (!$matches AND $texturl) { preg_match("/([^\]\='".'"'."]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", " ".$body, $matches); // Yeah, a hack. I really hate regular expressions :) - if ($matches) - $matches[1] = $matches[2]; + if ($matches) + $matches[1] = $matches[2]; + } + + if ($matches) + $footer = add_page_info($matches[1], $no_photos); + + // Remove the link from the body if the link is attached at the end of the post + if (isset($footer) AND (trim($footer) != "") AND (strpos($footer, $matches[1]))) { + $removedlink = trim(str_replace($matches[1], "", $body)); + if (($removedlink == "") OR strstr($body, $removedlink)) + $body = $removedlink; + + $url = str_replace(array('/', '.'), array('\/', '\.'), $matches[1]); + $removedlink = preg_replace("/\[url\=".$url."\](.*?)\[\/url\]/ism", '', $body); + if (($removedlink == "") OR strstr($body, $removedlink)) + $body = $removedlink; } - if ($matches) - $body .= add_page_info($matches[1], $no_photos); + // Add the page information to the bottom + if (isset($footer) AND (trim($footer) != "")) + $body .= $footer; - return $body; + return $body; } function encode_rel_links($links) { @@ -957,7 +1072,16 @@ function encode_rel_links($links) { -function item_store($arr,$force_parent = false) { +function item_store($arr,$force_parent = false, $notify = false, $dontcache = false) { + + // If it is a posting where users should get notifications, then define it as wall posting + if ($notify) { + $arr['wall'] = 1; + $arr['type'] = 'wall'; + $arr['origin'] = 1; + $arr['last-child'] = 1; + $arr['network'] = NETWORK_DFRN; + } // If a Diaspora signature structure was passed in, pull it out of the // item array and set it aside for later storage. @@ -974,7 +1098,7 @@ function item_store($arr,$force_parent = false) { if (isset($arr["ostatus_conversation"])) { $ostatus_conversation = $arr["ostatus_conversation"]; - unset($arr["ostatus_conversation"]); + unset($arr["ostatus_conversation"]); } if(x($arr, 'gravity')) @@ -1006,10 +1130,23 @@ function item_store($arr,$force_parent = false) { } } - // Shouldn't happen but we want to make absolutely sure it doesn't leak from a plugin. + // If there is no guid then take the same guid that was taken before for the same uri + if ((trim($arr['guid']) == "") AND (trim($arr['uri']) != "")) { + logger('item_store: checking for an existing guid for uri '.$arr['uri'], LOGGER_DEBUG); + $r = q("SELECT `guid` FROM `item` WHERE `uri` = '%s' AND `guid` != '' LIMIT 1", + dbesc(trim($arr['uri'])) + ); + + if(count($r)) { + $arr['guid'] = $r[0]["guid"]; + logger('item_store: found guid '.$arr['guid'].' for uri '.$arr['uri'], LOGGER_DEBUG); + } + } - if((strpos($arr['body'],'<') !== false) || (strpos($arr['body'],'>') !== false)) - $arr['body'] = strip_tags($arr['body']); + // Shouldn't happen but we want to make absolutely sure it doesn't leak from a plugin. + // Deactivated, since the bbcode parser can handle with it - and it destroys posts with some smileys that contain "<" + //if((strpos($arr['body'],'<') !== false) || (strpos($arr['body'],'>') !== false)) + // $arr['body'] = strip_tags($arr['body']); if (version_compare(PHP_VERSION, '5.3.0', '>=')) { @@ -1073,8 +1210,18 @@ function item_store($arr,$force_parent = false) { $arr['attach'] = ((x($arr,'attach')) ? notags(trim($arr['attach'])) : ''); $arr['app'] = ((x($arr,'app')) ? notags(trim($arr['app'])) : ''); $arr['origin'] = ((x($arr,'origin')) ? intval($arr['origin']) : 0 ); - $arr['guid'] = ((x($arr,'guid')) ? notags(trim($arr['guid'])) : get_guid()); + $arr['guid'] = ((x($arr,'guid')) ? notags(trim($arr['guid'])) : get_guid(30)); $arr['network'] = ((x($arr,'network')) ? trim($arr['network']) : ''); + $arr['postopts'] = ((x($arr,'postopts')) ? trim($arr['postopts']) : ''); + $arr['resource-id'] = ((x($arr,'resource-id')) ? trim($arr['resource-id']) : ''); + $arr['event-id'] = ((x($arr,'event-id')) ? intval($arr['event-id']) : 0 ); + $arr['inform'] = ((x($arr,'inform')) ? trim($arr['inform']) : ''); + $arr['file'] = ((x($arr,'file')) ? trim($arr['file']) : ''); + + if ($arr['plink'] == "") { + $a = get_app(); + $arr['plink'] = $a->get_baseurl().'/display/'.urlencode($arr['guid']); + } if ($arr['network'] == "") { $r = q("SELECT `network` FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", @@ -1100,6 +1247,7 @@ function item_store($arr,$force_parent = false) { $allow_gid = $arr['allow_gid']; $deny_cid = $arr['deny_cid']; $deny_gid = $arr['deny_gid']; + $notify_type = 'wall-new'; } else { @@ -1136,6 +1284,7 @@ function item_store($arr,$force_parent = false) { $deny_cid = $r[0]['deny_cid']; $deny_gid = $r[0]['deny_gid']; $arr['wall'] = $r[0]['wall']; + $notify_type = 'comment-new'; // if the parent is private, force privacy for the entire conversation // This differs from the above settings as it subtly allows comments from @@ -1201,6 +1350,9 @@ function item_store($arr,$force_parent = false) { return 0; } + // Store the unescaped version + $unescaped = $arr; + dbesc_array($arr); logger('item_store: ' . print_r($arr,true), LOGGER_DATA); @@ -1211,10 +1363,12 @@ function item_store($arr,$force_parent = false) { . implode("', '", array_values($arr)) . "')" ); - // find the item we just created + // And restore it + $arr = $unescaped; + // find the item we just created $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' AND `uid` = %d ORDER BY `id` ASC ", - $arr['uri'], // already dbesc'd + dbesc($arr['uri']), intval($arr['uid']) ); @@ -1222,6 +1376,26 @@ function item_store($arr,$force_parent = false) { $current_post = $r[0]['id']; logger('item_store: created item ' . $current_post); + // Add every contact to the global contact table + // Contacts from the statusnet connector are also added since you could add them in OStatus as well. + if (!$arr['private'] AND in_array($arr["network"], + array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS, NETWORK_STATUSNET, ""))) { + poco_check($arr["author-link"], $arr["author-name"], $arr["network"], $arr["author-avatar"], "", "", "", "", "", $arr["received"], $arr["contact-id"], $arr["uid"]); + + // Maybe its a body with a shared item? Then extract a global contact from it. + poco_contact_from_body($arr["body"], $arr["received"], $arr["contact-id"], $arr["uid"]); + } + + // Set "success_update" to the date of the last time we heard from this contact + // This can be used to filter for inactive contacts and poco. + // Only do this for public postings to avoid privacy problems, since poco data is public. + // Don't set this value if it isn't from the owner (could be an author that we don't know) + if (!$arr['private'] AND (($arr["author-link"] === $arr["owner-link"]) OR ($arr["parent-uri"] === $arr["uri"]))) + q("UPDATE `contact` SET `success_update` = '%s' WHERE `id` = %d", + dbesc($arr['received']), + intval($arr['contact-id']) + ); + // Only check for notifications on start posts if ($arr['parent-uri'] === $arr['uri']) { add_thread($r[0]['id']); @@ -1236,7 +1410,7 @@ function item_store($arr,$force_parent = false) { if(count($r)) { logger('item_store: Send notification for contact '.$arr['contact-id'].' and post '.$current_post, LOGGER_DEBUG); $u = q("SELECT * FROM user WHERE uid = %d LIMIT 1", - intval($arr['uid'])); + intval($arr['uid'])); $item = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d", intval($current_post), @@ -1254,7 +1428,7 @@ function item_store($arr,$force_parent = false) { 'to_email' => $u[0]['email'], 'uid' => $u[0]['uid'], 'item' => $item[0], - 'link' => $a->get_baseurl().'/display/'.$u[0]['nickname'].'/'.$current_post, + 'link' => $a->get_baseurl().'/display/'.urlencode($arr['guid']), 'source_name' => $item[0]['author-name'], 'source_link' => $item[0]['author-link'], 'source_photo' => $item[0]['author-avatar'], @@ -1272,7 +1446,7 @@ function item_store($arr,$force_parent = false) { if(count($r) > 1) { logger('item_store: duplicated post occurred. Removing duplicates.'); q("DELETE FROM `item` WHERE `uri` = '%s' AND `uid` = %d AND `id` != %d ", - $arr['uri'], + dbesc($arr['uri']), intval($arr['uid']), intval($current_post) ); @@ -1281,7 +1455,7 @@ function item_store($arr,$force_parent = false) { if((! $parent_id) || ($arr['parent-uri'] === $arr['uri'])) $parent_id = $current_post; - if(strlen($allow_cid) || strlen($allow_gid) || strlen($deny_cid) || strlen($deny_gid)) + if(strlen($allow_cid) || strlen($allow_gid) || strlen($deny_cid) || strlen($deny_gid)) $private = 1; else $private = $arr['private']; @@ -1304,14 +1478,14 @@ function item_store($arr,$force_parent = false) { if ($ostatus_conversation) complete_conversation($current_post, $ostatus_conversation); - $arr['id'] = $current_post; - $arr['parent'] = $parent_id; - $arr['allow_cid'] = $allow_cid; - $arr['allow_gid'] = $allow_gid; - $arr['deny_cid'] = $deny_cid; - $arr['deny_gid'] = $deny_gid; - $arr['private'] = $private; - $arr['deleted'] = $parent_deleted; + $arr['id'] = $current_post; + $arr['parent'] = $parent_id; + $arr['allow_cid'] = $allow_cid; + $arr['allow_gid'] = $allow_gid; + $arr['deny_cid'] = $deny_cid; + $arr['deny_gid'] = $deny_gid; + $arr['private'] = $private; + $arr['deleted'] = $parent_deleted; // update the commented timestamp on the parent @@ -1348,10 +1522,10 @@ function item_store($arr,$force_parent = false) { // current post can be deleted if is for a communuty page and no mention are // in it. - if (!$deleted) { + if (!$deleted AND !$dontcache) { // Store the fresh generated item into the cache - $cachefile = get_cachefile($arr["guid"]."-".hash("md5", $arr['body'])); + $cachefile = get_cachefile(urlencode($arr["guid"])."-".hash("md5", $arr['body'])); if (($cachefile != '') AND !file_exists($cachefile)) { $s = prepare_text($arr['body']); @@ -1370,11 +1544,58 @@ function item_store($arr,$force_parent = false) { } } - create_tags_from_item($current_post); + create_tags_from_item($current_post, $dontcache); create_files_from_item($current_post); + if ($notify) + proc_run('php', "include/notifier.php", $notify_type, $current_post); + return $current_post; } + +function get_item_guid($id) { + $r = q("SELECT `guid` FROM `item` WHERE `id` = %d LIMIT 1", intval($id)); + if (count($r)) + return($r[0]["guid"]); + else + return(""); +} + +function get_item_id($guid, $uid = 0) { + + $nick = ""; + $id = 0; + + if ($uid == 0) + $uid == local_user(); + + // Does the given user have this item? + if ($uid) { + $r = q("SELECT `item`.`id`, `user`.`nickname` FROM `item` INNER JOIN `user` ON `user`.`uid` = `item`.`uid` + WHERE `item`.`visible` = 1 AND `item`.`deleted` = 0 and `item`.`moderated` = 0 + AND `item`.`guid` = '%s' AND `item`.`uid` = %d", dbesc($guid), intval($uid)); + if (count($r)) { + $id = $r[0]["id"]; + $nick = $r[0]["nickname"]; + } + } + + // Or is it anywhere on the server? + if ($nick == "") { + $r = q("SELECT `item`.`id`, `user`.`nickname` FROM `item` INNER JOIN `user` ON `user`.`uid` = `item`.`uid` + WHERE `item`.`visible` = 1 AND `item`.`deleted` = 0 and `item`.`moderated` = 0 + AND `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' + AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = '' + AND `item`.`private` = 0 AND `item`.`wall` = 1 + AND `item`.`guid` = '%s'", dbesc($guid)); + if (count($r)) { + $id = $r[0]["id"]; + $nick = $r[0]["nickname"]; + } + } + return(array("nick" => $nick, "id" => $id)); +} + // return - test function get_item_contact($item,$contacts) { if(! count($contacts) || (! is_array($item))) @@ -1474,12 +1695,13 @@ function tag_deliver($uid,$item_id) { 'to_email' => $u[0]['email'], 'uid' => $u[0]['uid'], 'item' => $item, - 'link' => $a->get_baseurl() . '/display/' . $u[0]['nickname'] . '/' . $item['id'], + 'link' => $a->get_baseurl() . '/display/'.urlencode(get_item_guid($item['id'])), 'source_name' => $item['author-name'], 'source_link' => $item['author-link'], 'source_photo' => $photo, 'verb' => ACTIVITY_TAG, - 'otype' => 'item' + 'otype' => 'item', + 'parent' => $item['parent'] )); @@ -1789,10 +2011,10 @@ function dfrn_deliver($owner,$contact,$atom, $dissolve = false) { */ function edited_timestamp_is_newer($existing, $update) { if (!x($existing,'edited') || !$existing['edited']) { - return true; + return true; } if (!x($update,'edited') || !$update['edited']) { - return false; + return false; } $existing_edited = datetime_convert('UTC', 'UTC', $existing['edited']); $update_edited = datetime_convert('UTC', 'UTC', $update['edited']); @@ -1829,6 +2051,7 @@ function edited_timestamp_is_newer($existing, $update) { function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) { require_once('library/simplepie/simplepie.inc'); + require_once('include/contact_selectors.php'); if(! strlen($xml)) { logger('consume_feed: empty input'); @@ -1870,9 +2093,16 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) if($elems['name'][0]['attribs'][NAMESPACE_DFRN]['updated']) { $name_updated = $elems['name'][0]['attribs'][NAMESPACE_DFRN]['updated']; $new_name = $elems['name'][0]['data']; + + // Manually checking for changed contact names + if (($new_name != $contact['name']) AND ($new_name != "") AND ($name_updated <= $contact['name-date'])) { + $name_updated = date("c"); + $photo_timestamp = date("c"); + } } if((x($elems,'link')) && ($elems['link'][0]['attribs']['']['rel'] === 'photo') && ($elems['link'][0]['attribs'][NAMESPACE_DFRN]['updated'])) { - $photo_timestamp = datetime_convert('UTC','UTC',$elems['link'][0]['attribs'][NAMESPACE_DFRN]['updated']); + if ($photo_timestamp == "") + $photo_timestamp = datetime_convert('UTC','UTC',$elems['link'][0]['attribs'][NAMESPACE_DFRN]['updated']); $photo_url = $elems['link'][0]['attribs']['']['href']; } @@ -1882,7 +2112,7 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) } if((is_array($contact)) && ($photo_timestamp) && (strlen($photo_url)) && ($photo_timestamp > $contact['avatar-date'])) { - logger('consume_feed: Updating photo for ' . $contact['name']); + logger('consume_feed: Updating photo for '.$contact['name'].' from '.$photo_url.' uid: '.$contact['uid']); require_once("include/Photo.php"); $photo_failure = false; $have_photo = false; @@ -1985,7 +2215,7 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) $r = q("INSERT INTO `event` (`uid`,`cid`,`created`,`edited`,`start`,`finish`,`summary`,`desc`,`type`) VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", intval($contact['uid']), - intval($contact['id']), + intval($contact['id']), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc(datetime_convert('UTC','UTC', $birthday)), @@ -2147,7 +2377,7 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) logger('consume_feed: feed item count = ' . $feed->get_item_quantity()); - // in inverse date order + // in inverse date order if ($datedir) $items = array_reverse($feed->get_items()); else @@ -2443,16 +2673,6 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) if($contact['network'] === NETWORK_FEED) $datarray['private'] = 2; - // This is my contact on another system, but it's really me. - // Turn this into a wall post. - - if($contact['remote_self']) { - $datarray['wall'] = 1; - if($contact['network'] === NETWORK_FEED) { - $datarray['private'] = 0; - } - } - $datarray['parent-uri'] = $item_id; $datarray['uid'] = $importer['uid']; $datarray['contact-id'] = $contact['id']; @@ -2475,8 +2695,12 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) if(($contact['rel'] == CONTACT_IS_FOLLOWER) && (! tgroup_check($importer['uid'],$datarray))) continue; + // This is my contact on another system, but it's really me. + // Turn this into a wall post. + $notify = item_is_remote_self($contact, $datarray); - $r = item_store($datarray); + $r = item_store($datarray, false, $notify); + logger('Stored - Contact '.$contact['url'].' Notify '.$notify.' return '.$r.' Item '.print_r($datarray, true), LOGGER_DEBUG); continue; } @@ -2484,10 +2708,73 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) } } +function item_is_remote_self($contact, &$datarray) { + $a = get_app(); + + if (!$contact['remote_self']) + return false; + + // Prevent the forwarding of posts that are forwarded + if ($datarray["extid"] == NETWORK_DFRN) + return false; + + // Prevent to forward already forwarded posts + if ($datarray["app"] == $a->get_hostname()) + return false; + + // Only forward posts + if ($datarray["verb"] != ACTIVITY_POST) + return false; + + if (($contact['network'] != NETWORK_FEED) AND $datarray['private']) + return false; + + $datarray2 = $datarray; + logger('remote-self start - Contact '.$contact['url'].' - '.$contact['remote_self'].' Item '.print_r($datarray, true), LOGGER_DEBUG); + if ($contact['remote_self'] == 2) { + $r = q("SELECT `id`,`url`,`name`,`thumb` FROM `contact` WHERE `uid` = %d AND `self`", + intval($contact['uid'])); + if (count($r)) { + $datarray['contact-id'] = $r[0]["id"]; + + $datarray['owner-name'] = $r[0]["name"]; + $datarray['owner-link'] = $r[0]["url"]; + $datarray['owner-avatar'] = $r[0]["thumb"]; + + $datarray['author-name'] = $datarray['owner-name']; + $datarray['author-link'] = $datarray['owner-link']; + $datarray['author-avatar'] = $datarray['owner-avatar']; + } + + if ($contact['network'] != NETWORK_FEED) { + $datarray["guid"] = get_guid(32); + unset($datarray["plink"]); + $datarray["uri"] = item_new_uri($a->get_hostname(),$contact['uid']); + $datarray["parent-uri"] = $datarray["uri"]; + $datarray["extid"] = $contact['network']; + $urlpart = parse_url($datarray2['author-link']); + $datarray["app"] = $urlpart["host"]; + } else + $datarray['private'] = 0; + } + + //if (!isset($datarray["app"]) OR ($datarray["app"] == "")) + // $datarray["app"] = network_to_name($contact['network']); + + if ($contact['network'] != NETWORK_FEED) { + // Store the original post + $r = item_store($datarray2, false, false); + logger('remote-self post original item - Contact '.$contact['url'].' return '.$r.' Item '.print_r($datarray2, true), LOGGER_DEBUG); + } else + $datarray["app"] = "Feed"; + + return true; +} + function local_delivery($importer,$data) { $a = get_app(); - logger(__function__, LOGGER_TRACE); + logger(__function__, LOGGER_TRACE); if($importer['readonly']) { // We aren't receiving stuff from this person. But we will quietly ignore them @@ -2532,9 +2819,16 @@ function local_delivery($importer,$data) { if($elems['name'][0]['attribs'][NAMESPACE_DFRN]['updated']) { $name_updated = $elems['name'][0]['attribs'][NAMESPACE_DFRN]['updated']; $new_name = $elems['name'][0]['data']; + + // Manually checking for changed contact names + if (($new_name != $importer['name']) AND ($new_name != "") AND ($name_updated <= $importer['name-date'])) { + $name_updated = date("c"); + $photo_timestamp = date("c"); + } } if((x($elems,'link')) && ($elems['link'][0]['attribs']['']['rel'] === 'photo') && ($elems['link'][0]['attribs'][NAMESPACE_DFRN]['updated'])) { - $photo_timestamp = datetime_convert('UTC','UTC',$elems['link'][0]['attribs'][NAMESPACE_DFRN]['updated']); + if ($photo_timestamp == "") + $photo_timestamp = datetime_convert('UTC','UTC',$elems['link'][0]['attribs'][NAMESPACE_DFRN]['updated']); $photo_url = $elems['link'][0]['attribs']['']['href']; } } @@ -2661,6 +2955,7 @@ function local_delivery($importer,$data) { thumb = '%s', micro = '%s', url = '%s', + nurl = '%s', request = '%s', confirm = '%s', notify = '%s', @@ -2672,6 +2967,7 @@ function local_delivery($importer,$data) { dbesc($newloc['thumb']), dbesc($newloc['micro']), dbesc($newloc['url']), + dbesc(normalise_link($newloc['url'])), dbesc($newloc['request']), dbesc($newloc['confirm']), dbesc($newloc['notify']), @@ -3289,7 +3585,7 @@ function local_delivery($importer,$data) { 'to_email' => $importer['email'], 'uid' => $importer['importer_uid'], 'item' => $datarray, - 'link' => $a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $posted_id, + 'link' => $a->get_baseurl().'/display/'.urlencode(get_item_guid($posted_id)), 'source_name' => stripslashes($datarray['author-name']), 'source_link' => $datarray['author-link'], 'source_photo' => ((link_compare($datarray['author-link'],$importer['url'])) @@ -3453,7 +3749,7 @@ function local_delivery($importer,$data) { 'to_email' => $importer['email'], 'uid' => $importer['importer_uid'], 'item' => $datarray, - 'link' => $a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $posted_id, + 'link' => $a->get_baseurl().'/display/'.urlencode(get_item_guid($posted_id)), 'source_name' => stripslashes($datarray['author-name']), 'source_link' => $datarray['author-link'], 'source_photo' => ((link_compare($datarray['author-link'],$importer['url'])) @@ -3544,12 +3840,6 @@ function local_delivery($importer,$data) { continue; } - // This is my contact on another system, but it's really me. - // Turn this into a wall post. - - if($importer['remote_self']) - $datarray['wall'] = 1; - $datarray['parent-uri'] = $item_id; $datarray['uid'] = $importer['importer_uid']; $datarray['contact-id'] = $importer['id']; @@ -3569,7 +3859,11 @@ function local_delivery($importer,$data) { if(($importer['rel'] == CONTACT_IS_FOLLOWER) && (! tgroup_check($importer['importer_uid'],$datarray))) continue; - $posted_id = item_store($datarray); + // This is my contact on another system, but it's really me. + // Turn this into a wall post. + $notify = item_is_remote_self($importer, $datarray); + + $posted_id = item_store($datarray, false, $notify); if(stristr($datarray['verb'],ACTIVITY_POKE)) { $verb = urldecode(substr($datarray['verb'],strpos($datarray['verb'],'#')+1)); @@ -3583,16 +3877,16 @@ function local_delivery($importer,$data) { $links = parse_xml_string("".unxmlify($xo->link)."",false); - foreach($links->link as $l) { - $atts = $l->attributes(); - switch($atts['rel']) { - case "alternate": + foreach($links->link as $l) { + $atts = $l->attributes(); + switch($atts['rel']) { + case "alternate": $Blink = $atts['href']; break; default: break; - } - } + } + } if($Blink && link_compare($Blink,$a->get_baseurl() . '/profile/' . $importer['nickname'])) { // send a notification @@ -3606,7 +3900,7 @@ function local_delivery($importer,$data) { 'to_email' => $importer['email'], 'uid' => $importer['importer_uid'], 'item' => $datarray, - 'link' => $a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $posted_id, + 'link' => $a->get_baseurl().'/display/'.urlencode(get_item_guid($posted_id)), 'source_name' => stripslashes($datarray['author-name']), 'source_link' => $datarray['author-link'], 'source_photo' => ((link_compare($datarray['author-link'],$importer['url'])) @@ -3686,6 +3980,7 @@ function new_follower($importer,$contact,$datarray,$item,$sharing = false) { dbesc(datetime_convert()) ); } + $r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($importer['uid']) ); @@ -3697,21 +3992,26 @@ function new_follower($importer,$contact,$datarray,$item,$sharing = false) { group_add_member($r[0]['uid'],'',$contact_record['id'],$r[0]['def_gid']); } - if(($r[0]['notify-flags'] & NOTIFY_INTRO) && ($r[0]['page-flags'] == PAGE_NORMAL)) { - $email_tpl = get_intltext_template('follow_notify_eml.tpl'); - $email = replace_macros($email_tpl, array( - '$requestor' => ((strlen($name)) ? $name : t('[Name Withheld]')), - '$url' => $url, - '$myname' => $r[0]['username'], - '$siteurl' => $a->get_baseurl(), - '$sitename' => $a->config['sitename'] + if(($r[0]['notify-flags'] & NOTIFY_INTRO) && + (($r[0]['page-flags'] == PAGE_NORMAL) OR ($r[0]['page-flags'] == PAGE_SOAPBOX))) { + + + + notification(array( + 'type' => NOTIFY_INTRO, + 'notify_flags' => $r[0]['notify-flags'], + 'language' => $r[0]['language'], + 'to_name' => $r[0]['username'], + 'to_email' => $r[0]['email'], + 'uid' => $r[0]['uid'], + 'link' => $a->get_baseurl() . '/notifications/intro', + 'source_name' => ((strlen(stripslashes($contact_record['name']))) ? stripslashes($contact_record['name']) : t('[Name Withheld]')), + 'source_link' => $contact_record['url'], + 'source_photo' => $contact_record['photo'], + 'verb' => ($sharing ? ACTIVITY_FRIEND : ACTIVITY_FOLLOW), + 'otype' => 'intro' )); - $res = mail($r[0]['email'], - email_header_encode((($sharing) ? t('A new person is sharing with you at ') : t("You have a new follower at ")) . $a->config['sitename'],'UTF-8'), - $email, - 'From: ' . 'Administrator' . '@' . $_SERVER['SERVER_NAME'] . "\n" - . 'Content-type: text/plain; charset=UTF-8' . "\n" - . 'Content-transfer-encoding: 8bit' ); + } } @@ -3827,6 +4127,7 @@ function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) { else $body = $item['body']; + $o = "\r\n\r\n\r\n"; if(is_array($author)) @@ -3841,13 +4142,22 @@ function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) { $o .= '' . "\r\n"; } + $htmlbody = $body; + + if ($item['title'] != "") + $htmlbody = "[b]".$item['title']."[/b]\n\n".$htmlbody; + + $htmlbody = bbcode(bb_remove_share_information($htmlbody), false, false, 7); + $o .= '' . xmlify($item['uri']) . '' . "\r\n"; $o .= '' . xmlify($item['title']) . '' . "\r\n"; $o .= '' . xmlify(datetime_convert('UTC','UTC',$item['created'] . '+00:00',ATOM_TIME)) . '' . "\r\n"; $o .= '' . xmlify(datetime_convert('UTC','UTC',$item['edited'] . '+00:00',ATOM_TIME)) . '' . "\r\n"; $o .= '' . base64url_encode($body, true) . '' . "\r\n"; - $o .= '' . xmlify((($type === 'html') ? bbcode($body) : $body)) . '' . "\r\n"; + $o .= '' . xmlify((($type === 'html') ? $htmlbody : $body)) . '' . "\r\n"; $o .= '' . "\r\n"; + + if($comment) $o .= '' . intval($item['last-child']) . '' . "\r\n"; @@ -4093,7 +4403,7 @@ function item_getfeedattach($item) { -function item_expire($uid,$days) { +function item_expire($uid, $days, $network = "", $force = false) { if((! $uid) || ($days < 1)) return; @@ -4104,9 +4414,17 @@ function item_expire($uid,$days) { $expire_network_only = get_pconfig($uid,'expire','network_only'); $sql_extra = ((intval($expire_network_only)) ? " AND wall = 0 " : ""); + if ($network != "") { + $sql_extra .= sprintf(" AND network = '%s' ", dbesc($network)); + // There is an index "uid_network_received" but not "uid_network_created" + // This avoids the creation of another index just for one purpose. + // And it doesn't really matter wether to look at "received" or "created" + $range = "AND `received` < UTC_TIMESTAMP() - INTERVAL %d DAY "; + } else + $range = "AND `created` < UTC_TIMESTAMP() - INTERVAL %d DAY "; + $r = q("SELECT * FROM `item` - WHERE `uid` = %d - AND `created` < UTC_TIMESTAMP() - INTERVAL %d DAY + WHERE `uid` = %d $range AND `id` = `parent` $sql_extra AND `deleted` = 0", @@ -4120,6 +4438,10 @@ function item_expire($uid,$days) { $expire_items = get_pconfig($uid, 'expire','items'); $expire_items = (($expire_items===false)?1:intval($expire_items)); // default if not set: 1 + // Forcing expiring of items - but not notes and marked items + if ($force) + $expire_items = true; + $expire_notes = get_pconfig($uid, 'expire','notes'); $expire_notes = (($expire_notes===false)?1:intval($expire_notes)); // default if not set: 1 @@ -4253,7 +4575,7 @@ function drop_item($id,$interactive = true) { ); create_tags_from_item($item['id']); create_files_from_item($item['id']); - delete_thread($item['id']); + delete_thread($item['id'], $item['parent-uri']); // clean up categories and tags so they don't end up as orphans @@ -4417,13 +4739,9 @@ function posted_dates($uid,$wall) { if(! $dthen) return array(); - // If it's near the end of a long month, backup to the 28th so that in - // consecutive loops we'll always get a whole month difference. - - if(intval(substr($dnow,8)) > 28) - $dnow = substr($dnow,0,8) . '28'; - if(intval(substr($dthen,8)) > 28) - $dnow = substr($dthen,0,8) . '28'; + // Set the start and end date to the beginning of the month + $dnow = substr($dnow,0,8).'01'; + $dthen = substr($dthen,0,8).'01'; $ret = array(); // Starting with the current month, get the first and last days of every @@ -4434,7 +4752,7 @@ function posted_dates($uid,$wall) { $start_month = datetime_convert('','',$dstart,'Y-m-d'); $end_month = datetime_convert('','',$dend,'Y-m-d'); $str = day_translate(datetime_convert('','',$dnow,'F Y')); - $ret[] = array($str,$end_month,$start_month); + $ret[] = array($str,$end_month,$start_month); $dnow = datetime_convert('','',$dnow . ' -1 month', 'Y-m-d'); } return $ret;