function item_store($arr, $force_parent = false) { // If a Diaspora signature structure was passed in, pull it out of the // item array and set it aside for later storage. $dsprsig = null; if (x($arr, 'dsprsig')) { $dsprsig = json_decode(base64_decode($arr['dsprsig'])); unset($arr['dsprsig']); } // if an OStatus conversation url was passed in, it is stored and then // removed from the array. $ostatus_conversation = null; if (isset($arr["ostatus_conversation"])) { $ostatus_conversation = $arr["ostatus_conversation"]; unset($arr["ostatus_conversation"]); } if (x($arr, 'gravity')) { $arr['gravity'] = intval($arr['gravity']); } elseif ($arr['parent-uri'] === $arr['uri']) { $arr['gravity'] = 0; } elseif (activity_match($arr['verb'], ACTIVITY_POST)) { $arr['gravity'] = 6; } else { $arr['gravity'] = 6; } // extensible catchall if (!x($arr, 'type')) { $arr['type'] = 'remote'; } // Shouldn't happen but we want to make absolutely sure it doesn't leak from a plugin. if (strpos($arr['body'], '<') !== false || strpos($arr['body'], '>') !== false) { $arr['body'] = strip_tags($arr['body']); } if (version_compare(PHP_VERSION, '5.3.0', '>=')) { require_once 'library/langdet/Text/LanguageDetect.php'; $naked_body = preg_replace('/\\[(.+?)\\]/', '', $arr['body']); $l = new Text_LanguageDetect(); //$lng = $l->detectConfidence($naked_body); //$arr['postopts'] = (($lng['language']) ? 'lang=' . $lng['language'] . ';' . $lng['confidence'] : ''); $lng = $l->detect($naked_body, 3); if (sizeof($lng) > 0) { $postopts = ""; foreach ($lng as $language => $score) { if ($postopts == "") { $postopts = "lang="; } else { $postopts .= ":"; } $postopts .= $language . ";" . $score; } $arr['postopts'] = $postopts; } } $arr['wall'] = x($arr, 'wall') ? intval($arr['wall']) : 0; $arr['uri'] = x($arr, 'uri') ? notags(trim($arr['uri'])) : random_string(); $arr['extid'] = x($arr, 'extid') ? notags(trim($arr['extid'])) : ''; $arr['author-name'] = x($arr, 'author-name') ? notags(trim($arr['author-name'])) : ''; $arr['author-link'] = x($arr, 'author-link') ? notags(trim($arr['author-link'])) : ''; $arr['author-avatar'] = x($arr, 'author-avatar') ? notags(trim($arr['author-avatar'])) : ''; $arr['owner-name'] = x($arr, 'owner-name') ? notags(trim($arr['owner-name'])) : ''; $arr['owner-link'] = x($arr, 'owner-link') ? notags(trim($arr['owner-link'])) : ''; $arr['owner-avatar'] = x($arr, 'owner-avatar') ? notags(trim($arr['owner-avatar'])) : ''; $arr['created'] = x($arr, 'created') !== false ? datetime_convert('UTC', 'UTC', $arr['created']) : datetime_convert(); $arr['edited'] = x($arr, 'edited') !== false ? datetime_convert('UTC', 'UTC', $arr['edited']) : datetime_convert(); $arr['commented'] = datetime_convert(); $arr['received'] = datetime_convert(); $arr['changed'] = datetime_convert(); $arr['title'] = x($arr, 'title') ? notags(trim($arr['title'])) : ''; $arr['location'] = x($arr, 'location') ? notags(trim($arr['location'])) : ''; $arr['coord'] = x($arr, 'coord') ? notags(trim($arr['coord'])) : ''; $arr['last-child'] = x($arr, 'last-child') ? intval($arr['last-child']) : 0; $arr['visible'] = x($arr, 'visible') !== false ? intval($arr['visible']) : 1; $arr['deleted'] = 0; $arr['parent-uri'] = x($arr, 'parent-uri') ? notags(trim($arr['parent-uri'])) : ''; $arr['verb'] = x($arr, 'verb') ? notags(trim($arr['verb'])) : ''; $arr['object-type'] = x($arr, 'object-type') ? notags(trim($arr['object-type'])) : ''; $arr['object'] = x($arr, 'object') ? trim($arr['object']) : ''; $arr['target-type'] = x($arr, 'target-type') ? notags(trim($arr['target-type'])) : ''; $arr['target'] = x($arr, 'target') ? trim($arr['target']) : ''; $arr['plink'] = x($arr, 'plink') ? notags(trim($arr['plink'])) : ''; $arr['allow_cid'] = x($arr, 'allow_cid') ? trim($arr['allow_cid']) : ''; $arr['allow_gid'] = x($arr, 'allow_gid') ? trim($arr['allow_gid']) : ''; $arr['deny_cid'] = x($arr, 'deny_cid') ? trim($arr['deny_cid']) : ''; $arr['deny_gid'] = x($arr, 'deny_gid') ? trim($arr['deny_gid']) : ''; $arr['private'] = x($arr, 'private') ? intval($arr['private']) : 0; $arr['bookmark'] = x($arr, 'bookmark') ? intval($arr['bookmark']) : 0; $arr['body'] = x($arr, 'body') ? trim($arr['body']) : ''; $arr['tag'] = x($arr, 'tag') ? notags(trim($arr['tag'])) : ''; $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['thr-parent'] = $arr['parent-uri']; if ($arr['parent-uri'] === $arr['uri']) { $parent_id = 0; $parent_deleted = 0; $allow_cid = $arr['allow_cid']; $allow_gid = $arr['allow_gid']; $deny_cid = $arr['deny_cid']; $deny_gid = $arr['deny_gid']; } else { // find the parent and snarf the item id and ACLs // and anything else we need to inherit $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d ORDER BY `id` ASC LIMIT 1", dbesc($arr['parent-uri']), intval($arr['uid'])); if (count($r)) { // is the new message multi-level threaded? // even though we don't support it now, preserve the info // and re-attach to the conversation parent. if ($r[0]['uri'] != $r[0]['parent-uri']) { $arr['parent-uri'] = $r[0]['parent-uri']; $z = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `parent-uri` = '%s' AND `uid` = %d \n\t\t\t\t\tORDER BY `id` ASC LIMIT 1", dbesc($r[0]['parent-uri']), dbesc($r[0]['parent-uri']), intval($arr['uid'])); if ($z && count($z)) { $r = $z; } } $parent_id = $r[0]['id']; $parent_deleted = $r[0]['deleted']; $allow_cid = $r[0]['allow_cid']; $allow_gid = $r[0]['allow_gid']; $deny_cid = $r[0]['deny_cid']; $deny_gid = $r[0]['deny_gid']; $arr['wall'] = $r[0]['wall']; // if the parent is private, force privacy for the entire conversation // This differs from the above settings as it subtly allows comments from // email correspondents to be private even if the overall thread is not. if ($r[0]['private']) { $arr['private'] = $r[0]['private']; } // Edge case. We host a public forum that was originally posted to privately. // The original author commented, but as this is a comment, the permissions // weren't fixed up so it will still show the comment as private unless we fix it here. if (intval($r[0]['forum_mode']) == 1 && !$r[0]['private']) { $arr['private'] = 0; } } else { // Allow one to see reply tweets from status.net even when // we don't have or can't see the original post. if ($force_parent) { logger('item_store: $force_parent=true, reply converted to top-level post.'); $parent_id = 0; $arr['parent-uri'] = $arr['uri']; $arr['gravity'] = 0; } else { logger('item_store: item parent was not found - ignoring item'); return 0; } $parent_deleted = 0; } } $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($arr['uri']), intval($arr['uid'])); if ($r && count($r)) { logger('item-store: duplicate item ignored. ' . print_r($arr, true)); return 0; } call_hooks('post_remote', $arr); if (x($arr, 'cancel')) { logger('item_store: post cancelled by plugin.'); return 0; } dbesc_array($arr); logger('item_store: ' . print_r($arr, true), LOGGER_DATA); $r = dbq("INSERT INTO `item` (`" . implode("`, `", array_keys($arr)) . "`) VALUES ('" . implode("', '", array_values($arr)) . "')"); // find the item we just created $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' AND `uid` = %d ORDER BY `id` ASC ", $arr['uri'], intval($arr['uid'])); if (count($r)) { $current_post = $r[0]['id']; logger('item_store: created item ' . $current_post); create_tags_from_item($r[0]['id']); } else { logger('item_store: could not locate created item'); return 0; } 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'], intval($arr['uid']), intval($current_post)); } 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)) { $private = 1; } else { $private = $arr['private']; } // Set parent id - and also make sure to inherit the parent's ACL's. $r = q("UPDATE `item` SET `parent` = %d, `allow_cid` = '%s', `allow_gid` = '%s',\n\t\t`deny_cid` = '%s', `deny_gid` = '%s', `private` = %d, `deleted` = %d WHERE `id` = %d LIMIT 1", intval($parent_id), dbesc($allow_cid), dbesc($allow_gid), dbesc($deny_cid), dbesc($deny_gid), intval($private), intval($parent_deleted), intval($current_post)); create_tags_from_item($current_post); // Complete ostatus threads 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; // update the commented timestamp on the parent q("UPDATE `item` set `commented` = '%s', `changed` = '%s' WHERE `id` = %d LIMIT 1", dbesc(datetime_convert()), dbesc(datetime_convert()), intval($parent_id)); if ($dsprsig) { q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", intval($current_post), dbesc($dsprsig->signed_text), dbesc($dsprsig->signature), dbesc($dsprsig->signer)); } /** * If this is now the last-child, force all _other_ children of this parent to *not* be last-child */ if ($arr['last-child']) { $r = q("UPDATE `item` SET `last-child` = 0 WHERE `parent-uri` = '%s' AND `uid` = %d AND `id` != %d", dbesc($arr['uri']), intval($arr['uid']), intval($current_post)); } tag_deliver($arr['uid'], $current_post); // Store the fresh generated item into the cache $cachefile = get_cachefile($arr["guid"] . "-" . hash("md5", $arr['body'])); if ($cachefile != '' and !file_exists($cachefile)) { $s = prepare_text($arr['body']); $a = get_app(); $stamp1 = microtime(true); file_put_contents($cachefile, $s); $a->save_timestamp($stamp1, "file"); logger('item_store: put item ' . $current_post . ' into cachefile ' . $cachefile); } $r = q('SELECT * FROM `item` WHERE id = %d', intval($current_post)); if (count($r) == 1) { call_hooks('post_remote_end', $r[0]); } else { logger('item_store: new item not found in DB, id ' . $current_post); } return $current_post; }
function complete_conversation($itemid, $conversation_url, $only_add_conversation = false) { global $a; if (intval(get_config('system', 'ostatus_poll_interval')) == -2) { return; } if ($a->last_ostatus_conversation_url == $conversation_url) { return; } $a->last_ostatus_conversation_url = $conversation_url; $messages = q("SELECT `uid`, `parent`, `created`, `received`, `guid` FROM `item` WHERE `id` = %d LIMIT 1", intval($itemid)); if (!$messages) { return; } $message = $messages[0]; // Store conversation url if not done before $conversation = q("SELECT `url` FROM `term` WHERE `uid` = %d AND `oid` = %d AND `otype` = %d AND `type` = %d", intval($message["uid"]), intval($itemid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION)); if (!$conversation) { $r = q("INSERT INTO `term` (`uid`, `oid`, `otype`, `type`, `term`, `url`, `created`, `received`, `guid`) VALUES (%d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s')", intval($message["uid"]), intval($itemid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION), dbesc($message["created"]), dbesc($conversation_url), dbesc($message["created"]), dbesc($message["received"]), dbesc($message["guid"])); logger('complete_conversation: Storing conversation url ' . $conversation_url . ' for id ' . $itemid); } if ($only_add_conversation) { return; } // Get the parent $parents = q("SELECT `id`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($message["uid"]), intval($message["parent"])); if (!$parents) { return; } $parent = $parents[0]; require_once 'include/html2bbcode.php'; require_once 'include/items.php'; $conv = str_replace("/conversation/", "/api/statusnet/conversation/", $conversation_url) . ".as"; $pageno = 1; $items = array(); logger('complete_conversation: fetching conversation url ' . $conv . ' for ' . $itemid); do { $conv_as = fetch_url($conv . "?page=" . $pageno); $conv_as = str_replace(',"statusnet:notice_info":', ',"statusnet_notice_info":', $conv_as); $conv_as = json_decode($conv_as); if (@is_array($conv_as->items)) { $items = array_merge($items, $conv_as->items); } else { break; } $pageno++; } while (true); if (!sizeof($items)) { return; } $items = array_reverse($items); foreach ($items as $single_conv) { // status.net changed the format of the activity streams. This is a quick fix. if (@is_string($single_conv->object->id)) { $single_conv->id = $single_conv->object->id; } if (@(!$single_conv->id) and $single_conv->provider->url and $single_conv->statusnet_notice_info->local_id) { $single_conv->id = $single_conv->provider->url . "notice/" . $single_conv->statusnet_notice_info->local_id; } if (@(!$single_conv->id)) { continue; } if ($first_id == "") { $first_id = $single_conv->id; $new_parents = q("SELECT `id`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `uid` = %d AND `uri` = '%s' LIMIT 1", intval($message["uid"]), dbesc($first_id)); if ($new_parents) { $parent = $new_parents[0]; logger('adopting new parent ' . $parent["id"] . ' for ' . $itemid); } else { $parent["id"] = 0; $parent["uri"] = $first_id; } } if (isset($single_conv->context->inReplyTo->id)) { $parent_uri = $single_conv->context->inReplyTo->id; } else { $parent_uri = $parent["uri"]; } $message_exists = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' LIMIT 1", intval($message["uid"]), dbesc($single_conv->id)); if ($message_exists) { if ($parent["id"] != 0) { $existing_message = $message_exists[0]; // This is partly bad, since the entry in the thread table isn't updated $r = q("UPDATE `item` SET `parent` = %d, `parent-uri` = '%s', `thr-parent` = '%s' WHERE `id` = %d", intval($parent["id"]), dbesc($parent["uri"]), dbesc($parent_uri), intval($existing_message["id"])); } continue; } $contact = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `nurl` = '%s' AND `network` != '%s'", $message["uid"], normalise_link($single_conv->actor->id), NETWORK_STATUSNET); if (count($contact)) { logger("Found contact for url " . $single_conv->actor->id, LOGGER_DEBUG); $contact_id = $contact[0]["id"]; } else { logger("No contact found for url " . $single_conv->actor->id, LOGGER_DEBUG); $contact_id = $parent["contact-id"]; } $arr = array(); $arr["network"] = NETWORK_OSTATUS; $arr["uri"] = $single_conv->id; $arr["plink"] = $single_conv->id; $arr["uid"] = $message["uid"]; $arr["contact-id"] = $contact_id; if ($parent["id"] != 0) { $arr["parent"] = $parent["id"]; } $arr["parent-uri"] = $parent["uri"]; $arr["thr-parent"] = $parent_uri; $arr["created"] = $single_conv->published; $arr["edited"] = $single_conv->published; //$arr["owner-name"] = $single_conv->actor->contact->displayName; $arr["owner-name"] = $single_conv->actor->contact->preferredUsername; if ($arr["owner-name"] == '') { $arr["owner-name"] = $single_conv->actor->portablecontacts_net->preferredUsername; } if ($arr["owner-name"] == '') { $arr["owner-name"] = $single_conv->actor->displayName; } $arr["owner-link"] = $single_conv->actor->id; $arr["owner-avatar"] = $single_conv->actor->image->url; //$arr["author-name"] = $single_conv->actor->contact->displayName; //$arr["author-name"] = $single_conv->actor->contact->preferredUsername; $arr["author-name"] = $arr["owner-name"]; $arr["author-link"] = $single_conv->actor->id; $arr["author-avatar"] = $single_conv->actor->image->url; $arr["body"] = html2bbcode($single_conv->content); $arr["app"] = strip_tags($single_conv->statusnet_notice_info->source); if ($arr["app"] == "") { $arr["app"] = $single_conv->provider->displayName; } $arr["verb"] = $parent["verb"]; $arr["visible"] = $parent["visible"]; $arr["location"] = $single_conv->location->displayName; $arr["coord"] = trim($single_conv->location->lat . " " . $single_conv->location->lon); if ($arr["location"] == "") { unset($arr["location"]); } if ($arr["coord"] == "") { unset($arr["coord"]); } $newitem = item_store($arr); // Add the conversation entry (but don't fetch the whole conversation) complete_conversation($newitem, $conversation_url, true); // If the newly created item is the top item then change the parent settings of the thread if ($newitem and $arr["uri"] == $first_id) { logger('setting new parent to id ' . $newitem); $new_parents = q("SELECT `id`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($message["uid"]), intval($newitem)); if ($new_parents) { $parent = $new_parents[0]; logger('done changing parents to parent ' . $newitem); } } } }
function item_store($arr, $force_parent = false, $notify = 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. $dsprsig = null; if (x($arr, 'dsprsig')) { $dsprsig = json_decode(base64_decode($arr['dsprsig'])); unset($arr['dsprsig']); } // if an OStatus conversation url was passed in, it is stored and then // removed from the array. $ostatus_conversation = null; if (isset($arr["ostatus_conversation"])) { $ostatus_conversation = $arr["ostatus_conversation"]; unset($arr["ostatus_conversation"]); } if (x($arr, 'gravity')) { $arr['gravity'] = intval($arr['gravity']); } elseif ($arr['parent-uri'] === $arr['uri']) { $arr['gravity'] = 0; } elseif (activity_match($arr['verb'], ACTIVITY_POST)) { $arr['gravity'] = 6; } else { $arr['gravity'] = 6; } // extensible catchall if (!x($arr, 'type')) { $arr['type'] = 'remote'; } /* check for create date and expire time */ $uid = intval($arr['uid']); $r = q("SELECT expire FROM user WHERE uid = %d", $uid); if (count($r)) { $expire_interval = $r[0]['expire']; if ($expire_interval > 0) { $expire_date = new DateTime('- ' . $expire_interval . ' days', new DateTimeZone('UTC')); $created_date = new DateTime($arr['created'], new DateTimeZone('UTC')); if ($created_date < $expire_date) { logger('item-store: item created (' . $arr['created'] . ') before expiration time (' . $expire_date->format(DateTime::W3C) . '). ignored. ' . print_r($arr, true), LOGGER_DEBUG); return 0; } } } // 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); } } // 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', '>=')) { require_once 'library/langdet/Text/LanguageDetect.php'; $naked_body = preg_replace('/\\[(.+?)\\]/', '', $arr['body']); $l = new Text_LanguageDetect(); //$lng = $l->detectConfidence($naked_body); //$arr['postopts'] = (($lng['language']) ? 'lang=' . $lng['language'] . ';' . $lng['confidence'] : ''); $lng = $l->detect($naked_body, 3); if (sizeof($lng) > 0) { $postopts = ""; foreach ($lng as $language => $score) { if ($postopts == "") { $postopts = "lang="; } else { $postopts .= ":"; } $postopts .= $language . ";" . $score; } $arr['postopts'] = $postopts; } } $arr['wall'] = x($arr, 'wall') ? intval($arr['wall']) : 0; $arr['uri'] = x($arr, 'uri') ? notags(trim($arr['uri'])) : random_string(); $arr['extid'] = x($arr, 'extid') ? notags(trim($arr['extid'])) : ''; $arr['author-name'] = x($arr, 'author-name') ? notags(trim($arr['author-name'])) : ''; $arr['author-link'] = x($arr, 'author-link') ? notags(trim($arr['author-link'])) : ''; $arr['author-avatar'] = x($arr, 'author-avatar') ? notags(trim($arr['author-avatar'])) : ''; $arr['owner-name'] = x($arr, 'owner-name') ? notags(trim($arr['owner-name'])) : ''; $arr['owner-link'] = x($arr, 'owner-link') ? notags(trim($arr['owner-link'])) : ''; $arr['owner-avatar'] = x($arr, 'owner-avatar') ? notags(trim($arr['owner-avatar'])) : ''; $arr['created'] = x($arr, 'created') !== false ? datetime_convert('UTC', 'UTC', $arr['created']) : datetime_convert(); $arr['edited'] = x($arr, 'edited') !== false ? datetime_convert('UTC', 'UTC', $arr['edited']) : datetime_convert(); $arr['commented'] = datetime_convert(); $arr['received'] = datetime_convert(); $arr['changed'] = datetime_convert(); $arr['title'] = x($arr, 'title') ? notags(trim($arr['title'])) : ''; $arr['location'] = x($arr, 'location') ? notags(trim($arr['location'])) : ''; $arr['coord'] = x($arr, 'coord') ? notags(trim($arr['coord'])) : ''; $arr['last-child'] = x($arr, 'last-child') ? intval($arr['last-child']) : 0; $arr['visible'] = x($arr, 'visible') !== false ? intval($arr['visible']) : 1; $arr['deleted'] = 0; $arr['parent-uri'] = x($arr, 'parent-uri') ? notags(trim($arr['parent-uri'])) : ''; $arr['verb'] = x($arr, 'verb') ? notags(trim($arr['verb'])) : ''; $arr['object-type'] = x($arr, 'object-type') ? notags(trim($arr['object-type'])) : ''; $arr['object'] = x($arr, 'object') ? trim($arr['object']) : ''; $arr['target-type'] = x($arr, 'target-type') ? notags(trim($arr['target-type'])) : ''; $arr['target'] = x($arr, 'target') ? trim($arr['target']) : ''; $arr['plink'] = x($arr, 'plink') ? notags(trim($arr['plink'])) : ''; $arr['allow_cid'] = x($arr, 'allow_cid') ? trim($arr['allow_cid']) : ''; $arr['allow_gid'] = x($arr, 'allow_gid') ? trim($arr['allow_gid']) : ''; $arr['deny_cid'] = x($arr, 'deny_cid') ? trim($arr['deny_cid']) : ''; $arr['deny_gid'] = x($arr, 'deny_gid') ? trim($arr['deny_gid']) : ''; $arr['private'] = x($arr, 'private') ? intval($arr['private']) : 0; $arr['bookmark'] = x($arr, 'bookmark') ? intval($arr['bookmark']) : 0; $arr['body'] = x($arr, 'body') ? trim($arr['body']) : ''; $arr['tag'] = x($arr, 'tag') ? notags(trim($arr['tag'])) : ''; $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(30); $arr['network'] = x($arr, 'network') ? trim($arr['network']) : ''; 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", intval($arr['contact-id']), intval($arr['uid'])); if (count($r)) { $arr['network'] = $r[0]["network"]; } // Fallback to friendica (why is it empty in some cases?) if ($arr['network'] == "") { $arr['network'] = NETWORK_DFRN; } logger("item_store: Set network to " . $arr["network"] . " for " . $arr["uri"], LOGGER_DEBUG); } $arr['thr-parent'] = $arr['parent-uri']; if ($arr['parent-uri'] === $arr['uri']) { $parent_id = 0; $parent_deleted = 0; $allow_cid = $arr['allow_cid']; $allow_gid = $arr['allow_gid']; $deny_cid = $arr['deny_cid']; $deny_gid = $arr['deny_gid']; $notify_type = 'wall-new'; } else { // find the parent and snarf the item id and ACLs // and anything else we need to inherit $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d ORDER BY `id` ASC LIMIT 1", dbesc($arr['parent-uri']), intval($arr['uid'])); if (count($r)) { // is the new message multi-level threaded? // even though we don't support it now, preserve the info // and re-attach to the conversation parent. if ($r[0]['uri'] != $r[0]['parent-uri']) { $arr['parent-uri'] = $r[0]['parent-uri']; $z = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `parent-uri` = '%s' AND `uid` = %d\n\t\t\t\t\tORDER BY `id` ASC LIMIT 1", dbesc($r[0]['parent-uri']), dbesc($r[0]['parent-uri']), intval($arr['uid'])); if ($z && count($z)) { $r = $z; } } $parent_id = $r[0]['id']; $parent_deleted = $r[0]['deleted']; $allow_cid = $r[0]['allow_cid']; $allow_gid = $r[0]['allow_gid']; $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 // email correspondents to be private even if the overall thread is not. if ($r[0]['private']) { $arr['private'] = $r[0]['private']; } // Edge case. We host a public forum that was originally posted to privately. // The original author commented, but as this is a comment, the permissions // weren't fixed up so it will still show the comment as private unless we fix it here. if (intval($r[0]['forum_mode']) == 1 && !$r[0]['private']) { $arr['private'] = 0; } // If its a post from myself then tag the thread as "mention" logger("item_store: Checking if parent " . $parent_id . " has to be tagged as mention for user " . $arr['uid'], LOGGER_DEBUG); $u = q("select * from user where uid = %d limit 1", intval($arr['uid'])); if (count($u)) { $a = get_app(); $self = normalise_link($a->get_baseurl() . '/profile/' . $u[0]['nickname']); logger("item_store: 'myself' is " . $self . " for parent " . $parent_id . " checking against " . $arr['author-link'] . " and " . $arr['owner-link'], LOGGER_DEBUG); if (normalise_link($arr['author-link']) == $self or normalise_link($arr['owner-link']) == $self) { q("UPDATE `thread` SET `mention` = 1 WHERE `iid` = %d", intval($parent_id)); logger("item_store: tagged thread " . $parent_id . " as mention for user " . $self, LOGGER_DEBUG); } } } else { // Allow one to see reply tweets from status.net even when // we don't have or can't see the original post. if ($force_parent) { logger('item_store: $force_parent=true, reply converted to top-level post.'); $parent_id = 0; $arr['parent-uri'] = $arr['uri']; $arr['gravity'] = 0; } else { logger('item_store: item parent was not found - ignoring item'); return 0; } $parent_deleted = 0; } } $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($arr['uri']), intval($arr['uid'])); if ($r && count($r)) { logger('item-store: duplicate item ignored. ' . print_r($arr, true)); return 0; } call_hooks('post_remote', $arr); if (x($arr, 'cancel')) { logger('item_store: post cancelled by plugin.'); return 0; } dbesc_array($arr); logger('item_store: ' . print_r($arr, true), LOGGER_DATA); $r = dbq("INSERT INTO `item` (`" . implode("`, `", array_keys($arr)) . "`) VALUES ('" . implode("', '", array_values($arr)) . "')"); // find the item we just created $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' AND `uid` = %d ORDER BY `id` ASC ", $arr['uri'], intval($arr['uid'])); if (count($r)) { $current_post = $r[0]['id']; logger('item_store: created item ' . $current_post); // Only check for notifications on start posts if ($arr['parent-uri'] === $arr['uri']) { add_thread($r[0]['id']); logger('item_store: Check notification for contact ' . $arr['contact-id'] . ' and post ' . $current_post, LOGGER_DEBUG); // Send a notification for every new post? $r = q("SELECT `notify_new_posts` FROM `contact` WHERE `id` = %d AND `uid` = %d AND `notify_new_posts` LIMIT 1", intval($arr['contact-id']), intval($arr['uid'])); 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'])); $item = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d", intval($current_post), intval($arr['uid'])); $a = get_app(); require_once 'include/enotify.php'; notification(array('type' => NOTIFY_SHARE, 'notify_flags' => $u[0]['notify-flags'], 'language' => $u[0]['language'], 'to_name' => $u[0]['username'], 'to_email' => $u[0]['email'], 'uid' => $u[0]['uid'], 'item' => $item[0], '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'], 'verb' => ACTIVITY_TAG, 'otype' => 'item')); logger('item_store: Notification sent for contact ' . $arr['contact-id'] . ' and post ' . $current_post, LOGGER_DEBUG); } } } else { logger('item_store: could not locate created item'); return 0; } 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'], intval($arr['uid']), intval($current_post)); } 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)) { $private = 1; } else { $private = $arr['private']; } // Set parent id - and also make sure to inherit the parent's ACLs. $r = q("UPDATE `item` SET `parent` = %d, `allow_cid` = '%s', `allow_gid` = '%s',\n\t\t`deny_cid` = '%s', `deny_gid` = '%s', `private` = %d, `deleted` = %d WHERE `id` = %d", intval($parent_id), dbesc($allow_cid), dbesc($allow_gid), dbesc($deny_cid), dbesc($deny_gid), intval($private), intval($parent_deleted), intval($current_post)); // Complete ostatus threads 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; // update the commented timestamp on the parent q("UPDATE `item` set `commented` = '%s', `changed` = '%s' WHERE `id` = %d", dbesc(datetime_convert()), dbesc(datetime_convert()), intval($parent_id)); update_thread($parent_id); if ($dsprsig) { q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", intval($current_post), dbesc($dsprsig->signed_text), dbesc($dsprsig->signature), dbesc($dsprsig->signer)); } /** * If this is now the last-child, force all _other_ children of this parent to *not* be last-child */ if ($arr['last-child']) { $r = q("UPDATE `item` SET `last-child` = 0 WHERE `parent-uri` = '%s' AND `uid` = %d AND `id` != %d", dbesc($arr['uri']), intval($arr['uid']), intval($current_post)); } $deleted = tag_deliver($arr['uid'], $current_post); // current post can be deleted if is for a communuty page and no mention are // in it. if (!$deleted) { // Store the fresh generated item into the cache $cachefile = get_cachefile($arr["guid"] . "-" . hash("md5", $arr['body'])); if ($cachefile != '' and !file_exists($cachefile)) { $s = prepare_text($arr['body']); $a = get_app(); $stamp1 = microtime(true); file_put_contents($cachefile, $s); $a->save_timestamp($stamp1, "file"); logger('item_store: put item ' . $current_post . ' into cachefile ' . $cachefile); } $r = q('SELECT * FROM `item` WHERE id = %d', intval($current_post)); if (count($r) == 1) { call_hooks('post_remote_end', $r[0]); } else { logger('item_store: new item not found in DB, id ' . $current_post); } } create_tags_from_item($current_post); create_files_from_item($current_post); if ($notify) { proc_run('php', "include/notifier.php", $notify_type, $current_post); } return $current_post; }
function complete_conversation($itemid, $conversation_url, $only_add_conversation = false) { global $a; //logger('complete_conversation: completing conversation url '.$conversation_url.' for id '.$itemid); $messages = q("SELECT `uid`, `parent`, `created` FROM `item` WHERE `id` = %d LIMIT 1", intval($itemid)); if (!$messages) { return; } $message = $messages[0]; // Store conversation url if not done before $conversation = q("SELECT `url` FROM `term` WHERE `uid` = %d AND `oid` = %d AND `otype` = %d AND `type` = %d", intval($message["uid"]), intval($itemid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION)); if (!$conversation) { $r = q("INSERT INTO `term` (`uid`, `oid`, `otype`, `type`, `term`, `url`) VALUES (%d, %d, %d, %d, '%s', '%s')", intval($message["uid"]), intval($itemid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION), dbesc($message["created"]), dbesc($conversation_url)); logger('complete_conversation: Storing conversation url ' . $conversation_url . ' for id ' . $itemid); } if ($only_add_conversation) { return; } // Get the parent $parents = q("SELECT `id`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($message["uid"]), intval($message["parent"])); if (!$parents) { return; } $parent = $parents[0]; require_once 'include/html2bbcode.php'; require_once 'include/items.php'; $conv = str_replace("/conversation/", "/api/statusnet/conversation/", $conversation_url) . ".as"; logger('complete_conversation: fetching conversation url ' . $conv . ' for ' . $itemid); $conv_as = fetch_url($conv); if ($conv_as) { $conv_as = str_replace(',"statusnet:notice_info":', ',"statusnet_notice_info":', $conv_as); $conv_as = json_decode($conv_as); $first_id = ""; if (!is_array($conv_as->items)) { return; } $items = array_reverse($conv_as->items); foreach ($items as $single_conv) { if (@(!$single_conv->id) and $single_conv->provider->url and $single_conv->statusnet_notice_info->local_id) { $single_conv->id = $single_conv->provider->url . "notice/" . $single_conv->statusnet_notice_info->local_id; } if (@(!$single_conv->id)) { continue; } if ($first_id == "") { $first_id = $single_conv->id; $new_parents = q("SELECT `id`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `uid` = %d AND `uri` = '%s' LIMIT 1", intval($message["uid"]), dbesc($first_id)); if ($new_parents) { $parent = $new_parents[0]; logger('complete_conversation: adopting new parent ' . $parent["id"] . ' for ' . $itemid); } else { $parent["id"] = 0; $parent["uri"] = $first_id; } } if (isset($single_conv->context->inReplyTo->id)) { $parent_uri = $single_conv->context->inReplyTo->id; } else { $parent_uri = $parent["uri"]; } $message_exists = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' LIMIT 1", intval($message["uid"]), dbesc($single_conv->id)); if ($message_exists) { if ($parent["id"] != 0) { $existing_message = $message_exists[0]; $r = q("UPDATE `item` SET `parent` = %d, `parent-uri` = '%s', `thr-parent` = '%s' WHERE `id` = %d LIMIT 1", intval($parent["id"]), dbesc($parent["uri"]), dbesc($parent_uri), intval($existing_message["id"])); } continue; } $arr = array(); $arr["uri"] = $single_conv->id; $arr["plink"] = $single_conv->id; $arr["uid"] = $message["uid"]; $arr["contact-id"] = $parent["contact-id"]; // To-Do if ($parent["id"] != 0) { $arr["parent"] = $parent["id"]; } $arr["parent-uri"] = $parent["uri"]; $arr["thr-parent"] = $parent_uri; $arr["created"] = $single_conv->published; $arr["edited"] = $single_conv->published; //$arr["owner-name"] = $single_conv->actor->contact->displayName; $arr["owner-name"] = $single_conv->actor->contact->preferredUsername; $arr["owner-link"] = $single_conv->actor->id; $arr["owner-avatar"] = $single_conv->actor->image->url; //$arr["author-name"] = $single_conv->actor->contact->displayName; $arr["author-name"] = $single_conv->actor->contact->preferredUsername; $arr["author-link"] = $single_conv->actor->id; $arr["author-avatar"] = $single_conv->actor->image->url; $arr["body"] = html2bbcode($single_conv->content); $arr["app"] = strip_tags($single_conv->statusnet_notice_info->source); if ($arr["app"] == "") { $arr["app"] = $single_conv->provider->displayName; } $arr["verb"] = $parent["verb"]; $arr["visible"] = $parent["visible"]; $arr["location"] = $single_conv->location->displayName; $arr["coord"] = trim($single_conv->location->lat . " " . $single_conv->location->lon); if ($arr["location"] == "") { unset($arr["location"]); } if ($arr["coord"] == "") { unset($arr["coord"]); } $newitem = item_store($arr); // Add the conversation entry (but don't fetch the whole conversation) complete_conversation($newitem, $conversation_url, true); // If the newly created item is the top item then change the parent settings of the thread if ($newitem and $arr["uri"] == $first_id) { logger('complete_conversation: setting new parent to id ' . $newitem); $new_parents = q("SELECT `id`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($message["uid"]), intval($newitem)); if ($new_parents) { $parent = $new_parents[0]; logger('complete_conversation: done changing parents to parent ' . $newitem); } /*logger('complete_conversation: changing parents to parent '.$newitem.' old parent: '.$parent["id"].' new uri: '.$arr["uri"]); $r = q("UPDATE `item` SET `parent` = %d, `parent-uri` = '%s' WHERE `parent` = %d", intval($newitem), dbesc($arr["uri"]), intval($parent["id"])); logger('complete_conversation: done changing parents to parent '.$newitem.' '.print_r($r, true));*/ } } } }