aboutsummaryrefslogtreecommitdiffstats
path: root/include/items.php
diff options
context:
space:
mode:
Diffstat (limited to 'include/items.php')
-rwxr-xr-xinclude/items.php1244
1 files changed, 749 insertions, 495 deletions
diff --git a/include/items.php b/include/items.php
index 139c637e5..7948a7c22 100755
--- a/include/items.php
+++ b/include/items.php
@@ -1,6 +1,7 @@
<?php
/**
* @file include/items.php
+ * @brief Items related functions.
*/
use Zotlabs\Lib as Zlib;
@@ -8,6 +9,7 @@ use Zotlabs\Lib as Zlib;
require_once('include/bbcode.php');
require_once('include/oembed.php');
require_once('include/crypto.php');
+require_once('include/message.php');
require_once('include/feedutils.php');
require_once('include/photo/photo_driver.php');
require_once('include/permissions.php');
@@ -172,9 +174,22 @@ function comments_are_now_closed($item) {
function item_normal() {
return " and item.item_hidden = 0 and item.item_type = 0 and item.item_deleted = 0
and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
- and item.item_blocked = 0 ";
+ and item.item_blocked = 0 and item.obj_type != '" . ACTIVITY_OBJ_FILE . "' ";
}
+function item_normal_search() {
+ return " and item.item_hidden = 0 and item.item_type in (0,3,6) and item.item_deleted = 0
+ and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
+ and item.item_blocked = 0 and item.obj_type != '" . ACTIVITY_OBJ_FILE . "' ";
+}
+
+function item_normal_update() {
+ return " and item.item_hidden = 0 and item.item_type = 0
+ and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
+ and item.item_blocked = 0 and item.obj_type != '" . ACTIVITY_OBJ_FILE . "' ";
+}
+
+
/**
* @brief
*
@@ -187,14 +202,14 @@ function is_item_normal($item) {
if(intval($item['item_hidden']) || intval($item['item_type']) || intval($item['item_deleted'])
|| intval($item['item_unpublished']) || intval($item['item_delayed']) || intval($item['item_pending_remove'])
- || intval($item['item_blocked']))
+ || intval($item['item_blocked']) || ($item['obj_type'] == ACTIVITY_OBJ_FILE))
return false;
return true;
}
/**
- * @brief
+ * @brief Decide if current observer has sufficient privileges to comment on item.
*
* This function examines the comment_policy attached to an item and decides if the current observer has
* sufficient privileges to comment. This will normally be called on a remote site where perm_is_allowed()
@@ -210,7 +225,23 @@ function is_item_normal($item) {
*/
function can_comment_on_post($observer_xchan, $item) {
-// logger('can_comment_on_post: comment_policy: ' . $item['comment_policy'], LOGGER_DEBUG);
+// logger('Comment_policy: ' . $item['comment_policy'], LOGGER_DEBUG);
+
+ $x = [
+ 'observer_hash' => $observer_xchan,
+ 'item' => $item,
+ 'allowed' => 'unset'
+ ];
+ /**
+ * @hooks can_comment_on_post
+ * Called when deciding whether or not to present a comment box for a post.
+ * * \e string \b observer_hash
+ * * \e array \b item
+ * * \e boolean \b allowed - return value
+ */
+ call_hooks('can_comment_on_post', $x);
+ if($x['allowed'] !== 'unset')
+ return $x['allowed'];
if(! $observer_xchan)
return false;
@@ -248,8 +279,6 @@ function can_comment_on_post($observer_xchan, $item) {
}
if(strstr($item['comment_policy'],'network:') && strstr($item['comment_policy'],'red'))
return true;
- if(strstr($item['comment_policy'],'network:') && strstr($item['comment_policy'],'diaspora'))
- return true;
if(strstr($item['comment_policy'],'site:') && strstr($item['comment_policy'],App::get_hostname()))
return true;
@@ -298,11 +327,13 @@ function add_source_route($iid, $hash) {
* or other processing is performed.
*
* @param array $arr
+ * @param boolean $allow_code (optional) default false
+ * @param boolean $deliver (optional) default true
* @returns array
* * \e boolean \b success true or false
* * \e array \b activity the resulting activity if successful
*/
-function post_activity_item($arr,$allow_code = false,$deliver = true) {
+function post_activity_item($arr, $allow_code = false, $deliver = true) {
$ret = array('success' => false);
@@ -328,25 +359,14 @@ function post_activity_item($arr,$allow_code = false,$deliver = true) {
return $ret;
}
- $arr['public_policy'] = ((x($_REQUEST,'public_policy')) ? escape_tags($_REQUEST['public_policy']) : map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_stream'),true));
+ $arr['public_policy'] = ((array_key_exists('public_policy',$arr)) ? escape_tags($arr['public_policy']) : map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_stream'),true));
+
if($arr['public_policy'])
$arr['item_private'] = 1;
if(! array_key_exists('mimetype',$arr))
$arr['mimetype'] = 'text/bbcode';
- if(array_key_exists('item_private',$arr) && $arr['item_private']) {
-
- $arr['body'] = trim(z_input_filter($arr['uid'],$arr['body'],$arr['mimetype']));
-
- if($channel) {
- if($channel['channel_hash'] === $arr['author_xchan']) {
- $arr['sig'] = base64url_encode(rsa_sign($arr['body'],$channel['channel_prvkey']));
- $arr['item_verified'] = 1;
- }
- }
- }
-
$arr['mid'] = ((x($arr,'mid')) ? $arr['mid'] : item_message_id());
$arr['parent_mid'] = ((x($arr,'parent_mid')) ? $arr['parent_mid'] : $arr['mid']);
$arr['thr_parent'] = ((x($arr,'thr_parent')) ? $arr['thr_parent'] : $arr['mid']);
@@ -359,10 +379,13 @@ function post_activity_item($arr,$allow_code = false,$deliver = true) {
if(($is_comment) && ($arr['obj_type'] === ACTIVITY_OBJ_NOTE))
$arr['obj_type'] = ACTIVITY_OBJ_COMMENT;
- $arr['allow_cid'] = ((x($arr,'allow_cid')) ? $arr['allow_cid'] : $channel['channel_allow_cid']);
- $arr['allow_gid'] = ((x($arr,'allow_gid')) ? $arr['allow_gid'] : $channel['channel_allow_gid']);
- $arr['deny_cid'] = ((x($arr,'deny_cid')) ? $arr['deny_cid'] : $channel['channel_deny_cid']);
- $arr['deny_gid'] = ((x($arr,'deny_gid')) ? $arr['deny_gid'] : $channel['channel_deny_gid']);
+ if(! ( array_key_exists('allow_cid',$arr) || array_key_exists('allow_gid',$arr)
+ || array_key_exists('deny_cid',$arr) || array_key_exists('deny_gid',$arr))) {
+ $arr['allow_cid'] = $channel['channel_allow_cid'];
+ $arr['allow_gid'] = $channel['channel_allow_gid'];
+ $arr['deny_cid'] = $channel['channel_deny_cid'];
+ $arr['deny_gid'] = $channel['channel_deny_gid'];
+ }
$arr['comment_policy'] = map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'post_comments'));
@@ -375,10 +398,14 @@ function post_activity_item($arr,$allow_code = false,$deliver = true) {
$_REQUEST['api_source'] = 1;
- call_hooks('post_local',$arr);
+ /**
+ * @hooks post_local
+ * Called when an item has been posted on this machine via mod/item.php (also via API).
+ */
+ call_hooks('post_local', $arr);
- if(x($arr,'cancel')) {
- logger('post_activity_item: post cancelled by plugin.');
+ if(x($arr, 'cancel')) {
+ logger('Post cancelled by plugin.');
return $ret;
}
@@ -389,6 +416,12 @@ function post_activity_item($arr,$allow_code = false,$deliver = true) {
$ret['success'] = true;
$ret['item_id'] = $post_id;
$ret['activity'] = $post['item'];
+
+ /**
+ * @hooks post_local_end
+ * Called after a local post operation has completed.
+ * * \e array - the item returned from item_store()
+ */
call_hooks('post_local_end', $ret['activity']);
}
@@ -396,8 +429,8 @@ function post_activity_item($arr,$allow_code = false,$deliver = true) {
Zotlabs\Daemon\Master::Summon(array('Notifier','activity',$post_id));
}
-
$ret['success'] = true;
+
return $ret;
}
@@ -419,12 +452,11 @@ function validate_item_elements($message,$arr) {
$result['success'] = true;
return $result;
-
}
/**
- * @brief Limit lenght on imported system messages.
+ * @brief Limit length on imported system messages.
*
* The purpose of this function is to apply system message length limits to
* imported messages without including any embedded photos in the length.
@@ -458,7 +490,7 @@ function limit_body_size($body) {
if( ($textlen + $img_start) > $maxlen ) {
if($textlen < $maxlen) {
- logger('limit_body_size: the limit happens before an embedded image', LOGGER_DEBUG);
+ logger('The limit happens before an embedded image', LOGGER_DEBUG);
$new_body = $new_body . substr($orig_body, 0, $maxlen - $textlen);
$textlen = $maxlen;
}
@@ -538,12 +570,7 @@ function get_item_elements($x,$allow_code = false) {
$arr = array();
- if($allow_code)
- $arr['body'] = $x['body'];
- else
- $arr['body'] = (($x['body']) ? htmlspecialchars($x['body'],ENT_COMPAT,'UTF-8',false) : '');
-
- $key = get_config('system','pubkey');
+ $arr['body'] = $x['body'];
$maxlen = get_max_import_size();
@@ -598,11 +625,6 @@ function get_item_elements($x,$allow_code = false) {
$arr['sig'] = (($x['signature']) ? htmlspecialchars($x['signature'], ENT_COMPAT,'UTF-8',false) : '');
- if(array_key_exists('diaspora_signature',$x) && is_array($x['diaspora_signature']))
- $x['diaspora_signature'] = json_encode($x['diaspora_signature']);
-
- $arr['diaspora_meta'] = (($x['diaspora_signature']) ? $x['diaspora_signature'] : '');
-
$arr['obj'] = activity_sanitise($x['object']);
$arr['target'] = activity_sanitise($x['target']);
@@ -625,6 +647,9 @@ function get_item_elements($x,$allow_code = false) {
if(in_array('notshown',$x['flags']))
$arr['item_notshown'] = 1;
+ if(in_array('obscured',$x['flags']))
+ $arr['item_obscured'] = 1;
+
// hidden item are no longer propagated - notshown may be a suitable alternative
if(in_array('hidden',$x['flags']))
@@ -645,26 +670,62 @@ function get_item_elements($x,$allow_code = false) {
return array();
// save a potentially expensive lookup if author == owner
+
if($arr['author_xchan'] === make_xchan_hash($x['owner']['guid'],$x['owner']['guid_sig']))
$arr['owner_xchan'] = $arr['author_xchan'];
else {
$xchan_hash = import_author_xchan($x['owner']);
- if($xchan_hash)
+ if($xchan_hash) {
$arr['owner_xchan'] = $xchan_hash;
- else
+ }
+ else {
return array();
+ }
}
+ // Check signature on the body text received.
+ // This presents an issue that we aren't verifying the text that is actually displayed
+ // on this site. We are however verifying the received text was exactly as received.
+ // We have every right to strip content that poses a security risk. You are welcome to
+ // create a plugin to verify the content after filtering if this offends you.
+
if($arr['sig']) {
+
+ // check the supplied signature against the supplied content.
+ // Note that we will purify the content which could change it.
+
$r = q("select xchan_pubkey from xchan where xchan_hash = '%s' limit 1",
dbesc($arr['author_xchan'])
);
- if($r && rsa_verify($x['body'],base64url_decode($arr['sig']),$r[0]['xchan_pubkey']))
- $arr['item_verified'] = 1;
- else
- logger('get_item_elements: message verification failed.');
+ if($r) {
+ if($r[0]['xchan_pubkey']) {
+ if(rsa_verify($x['body'],base64url_decode($arr['sig']),$r[0]['xchan_pubkey'])) {
+ $arr['item_verified'] = 1;
+ }
+ else {
+ logger('get_item_elements: message verification failed.');
+ }
+ }
+ else {
+
+ // If we don't have a public key, strip the signature so it won't show as invalid.
+ // This won't happen in normal use, but could happen if import_author_xchan()
+ // failed to load the zot-info packet due to a server failure and had
+ // to create an alternate xchan with network 'unknown'
+
+ unset($arr['sig']);
+ }
+ }
}
+ // if the input is markdown, remove one level of html escaping.
+ // It will be re-applied in item_store() and/or item_store_update().
+ // Do this after signature checking as the original signature
+ // was generated on the escaped content.
+
+ if($arr['mimetype'] === 'text/markdown')
+ $arr['body'] = \Zotlabs\Lib\MarkdownSoap::unescape($arr['body']);
+
if(array_key_exists('revision',$x)) {
// extended export encoding
@@ -691,7 +752,7 @@ function get_item_elements($x,$allow_code = false) {
// local only $arr['item_relay'] = $x['item_relay'];
$arr['item_mentionsme'] = $x['item_mentionsme'];
$arr['item_nocomment'] = $x['item_nocomment'];
- // local only $arr['item_obscured'] = $x['item_obscured'];
+ $arr['item_obscured'] = $x['item_obscured'];
// local only $arr['item_verified'] = $x['item_verified'];
$arr['item_retained'] = $x['item_retained'];
$arr['item_rss'] = $x['item_rss'];
@@ -759,56 +820,39 @@ function get_item_elements($x,$allow_code = false) {
function import_author_xchan($x) {
- $arr = array('xchan' => $x, 'xchan_hash' => '');
- call_hooks('import_author_xchan',$arr);
+ $arr = [
+ 'xchan' => $x,
+ 'xchan_hash' => ''
+ ];
+ /**
+ * @hooks import_author_xchan
+ * Called when looking up an author of a post by xchan_hash to ensure they have an xchan record on our site.
+ * * \e array \b xchan
+ * * \e string \b xchan_hash - Thre returned value
+ */
+ call_hooks('import_author_xchan', $arr);
if($arr['xchan_hash'])
return $arr['xchan_hash'];
+ $y = false;
+
if((! array_key_exists('network', $x)) || ($x['network'] === 'zot')) {
$y = import_author_zot($x);
}
- if(! $y)
- $y = import_author_diaspora($x);
+
+ // if we were told that it's a zot connection, don't probe/import anything else
+ if(array_key_exists('network',$x) && $x['network'] === 'zot')
+ return $y;
if($x['network'] === 'rss') {
$y = import_author_rss($x);
}
- if($x['network'] === 'unknown') {
+ if(! $y) {
$y = import_author_unknown($x);
}
- return(($y) ? $y : false);
-}
-
-/**
- * @brief Imports an author from Diaspora.
- *
- * @param array $x an associative array with
- * * \e string \b address
- * @return boolean|string false on error, otherwise xchan_hash of the new entry
- */
-function import_author_diaspora($x) {
- if(! $x['address'])
- return false;
-
- $r = q("select * from xchan where xchan_addr = '%s' limit 1",
- dbesc($x['address'])
- );
- if($r) {
- logger('in_cache: ' . $x['address'], LOGGER_DATA);
- return $r[0]['xchan_hash'];
- }
-
- if(discover_by_webbie($x['address'])) {
- $r = q("select xchan_hash from xchan where xchan_addr = '%s' limit 1",
- dbesc($x['address'])
- );
- if($r)
- return $r[0]['xchan_hash'];
- }
-
- return false;
+ return($y);
}
/**
@@ -828,7 +872,7 @@ function import_author_rss($x) {
dbesc($x['url'])
);
if($r) {
- logger('import_author_rss: in cache' , LOGGER_DEBUG);
+ logger('In cache' , LOGGER_DEBUG);
return $r[0]['xchan_hash'];
}
$name = trim($x['name']);
@@ -867,6 +911,19 @@ function import_author_rss($x) {
function import_author_unknown($x) {
+ $arr = [
+ 'author' => $x,
+ 'result' => false
+ ];
+ /**
+ * @hooks import_author
+ * * \e array \b author
+ * * \e boolean|string \b result - Return value, default false
+ */
+ call_hooks('import_author', $arr);
+ if($arr['result'])
+ return $arr['result'];
+
if(! $x['url'])
return false;
@@ -874,7 +931,7 @@ function import_author_unknown($x) {
dbesc($x['url'])
);
if($r) {
- logger('import_author_unknown: in cache' , LOGGER_DEBUG);
+ logger('In cache' , LOGGER_DEBUG);
return $r[0]['xchan_hash'];
}
@@ -896,7 +953,7 @@ function import_author_unknown($x) {
$photos = import_xchan_photo($x['photo']['src'],$x['url']);
if($photos) {
- $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_url = '%s' and xchan_network = 'unknown'",
+ $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s' and xchan_network = 'unknown'",
dbesc(datetime_convert()),
dbesc($photos[0]),
dbesc($photos[1]),
@@ -936,13 +993,6 @@ function encode_item($item,$mirror = false) {
$key = get_config('system','prvkey');
- if(array_key_exists('item_obscured',$item) && intval($item['item_obscured'])) {
- if($item['title'])
- $item['title'] = crypto_unencapsulate(json_decode($item['title'],true),$key);
- if($item['body'])
- $item['body'] = crypto_unencapsulate(json_decode($item['body'],true),$key);
- }
-
// If we're trying to backup an item so that it's recoverable or for export/imprt,
// add all the attributes we need to recover it
@@ -1033,17 +1083,7 @@ function encode_item($item,$mirror = false) {
if($item['iconfig'])
$x['meta'] = encode_item_meta($item['iconfig'],$mirror);
- if($item['diaspora_meta']) {
- $z = json_decode($item['diaspora_meta'],true);
- if($z) {
- if(is_array($z) && array_key_exists('iv',$z))
- $x['diaspora_signature'] = crypto_unencapsulate($z,$key);
- else
- $x['diaspora_signature'] = $z;
- if(! is_array($z))
- logger('encode_item: diaspora meta is not an array: ' . print_r($z,true));
- }
- }
+
logger('encode_item: ' . print_r($x,true), LOGGER_DATA);
return $x;
@@ -1116,7 +1156,7 @@ function encode_item_xchan($xchan) {
$ret['address'] = $xchan['xchan_addr'];
$ret['url'] = $xchan['xchan_url'];
$ret['network'] = $xchan['xchan_network'];
- $ret['photo'] = array('mimetype' => $xchan['xchan_photo_mimetype'], 'src' => $xchan['xchan_photo_m']);
+ $ret['photo'] = [ 'mimetype' => $xchan['xchan_photo_mimetype'], 'src' => $xchan['xchan_photo_m'] ];
$ret['guid'] = $xchan['xchan_guid'];
$ret['guid_sig'] = $xchan['xchan_guid_sig'];
@@ -1126,7 +1166,7 @@ function encode_item_xchan($xchan) {
function encode_item_terms($terms,$mirror = false) {
$ret = array();
- $allowed_export_terms = array( TERM_UNKNOWN, TERM_HASHTAG, TERM_MENTION, TERM_CATEGORY, TERM_BOOKMARK, TERM_COMMUNITYTAG );
+ $allowed_export_terms = array( TERM_UNKNOWN, TERM_HASHTAG, TERM_MENTION, TERM_CATEGORY, TERM_BOOKMARK, TERM_COMMUNITYTAG, TERM_FORUM );
if($mirror) {
$allowed_export_terms[] = TERM_PCATEGORY;
@@ -1174,7 +1214,7 @@ function decode_item_meta($meta) {
* @return string
*/
function termtype($t) {
- $types = array('unknown','hashtag','mention','category','private_category','file','search','thing','bookmark', 'hierarchy', 'communitytag');
+ $types = array('unknown','hashtag','mention','category','private_category','file','search','thing','bookmark', 'hierarchy', 'communitytag', 'forum');
return(($types[$t]) ? $types[$t] : 'unknown');
}
@@ -1223,6 +1263,9 @@ function decode_tags($t) {
case 'communitytag':
$tag['ttype'] = TERM_COMMUNITYTAG;
break;
+ case 'forum':
+ $tag['ttype'] = TERM_FORUM;
+ break;
default:
case 'unknown':
$tag['ttype'] = TERM_UNKNOWN;
@@ -1300,6 +1343,8 @@ function encode_item_flags($item) {
$ret[] = 'nsfw';
if(intval($item['item_consensus']))
$ret[] = 'consensus';
+ if(intval($item['item_obscured']))
+ $ret[] = 'obscured';
if(intval($item['item_private']))
$ret[] = 'private';
@@ -1322,11 +1367,12 @@ function encode_mail($item,$extended = false) {
$x['message_parent'] = $item['parent_mid'];
$x['created'] = $item['created'];
$x['expires'] = $item['expires'];
- $x['diaspora_meta'] = $item['diaspora_meta'];
$x['title'] = $item['title'];
$x['body'] = $item['body'];
$x['from'] = encode_item_xchan($item['from']);
$x['to'] = encode_item_xchan($item['to']);
+ $x['raw'] = $item['mail_raw'];
+ $x['mimetype'] = $item['mail_mimetype'];
if($item['attach'])
$x['attach'] = json_decode($item['attach'],true);
@@ -1360,9 +1406,16 @@ function get_mail_elements($x) {
$arr = array();
- $arr['body'] = (($x['body']) ? htmlspecialchars($x['body'], ENT_COMPAT,'UTF-8',false) : '');
- $arr['title'] = (($x['title'])? htmlspecialchars($x['title'],ENT_COMPAT,'UTF-8',false) : '');
+ if(intval($x['raw'])) {
+ $arr['mail_raw'] = intval($x['raw']);
+ $arr['body'] = $x['body'];
+ }
+ else {
+ $arr['body'] = (($x['body']) ? htmlspecialchars($x['body'], ENT_COMPAT,'UTF-8',false) : '');
+ }
+ $arr['title'] = (($x['title'])? htmlspecialchars($x['title'],ENT_COMPAT,'UTF-8',false) : '');
+ $arr['mail_mimetype'] = (($x['mimetype']) ? htmlspecialchars($x['mimetype'],ENT_COMPAT,'UTF-8',false) : 'text/bbcode');
$arr['conv_guid'] = (($x['conv_guid'])? htmlspecialchars($x['conv_guid'],ENT_COMPAT,'UTF-8',false) : '');
$arr['created'] = datetime_convert('UTC','UTC',$x['created']);
@@ -1453,7 +1506,29 @@ function get_profile_elements($x) {
/**
- * @brief
+ * @brief Signs an item body.
+ *
+ * @param[in,out] array $item
+ */
+function item_sign(&$item) {
+
+ if(array_key_exists('sig',$item) && $item['sig'])
+ return;
+
+ $r = q("select channel_prvkey from channel where channel_id = %d and channel_hash = '%s' ",
+ intval($item['uid']),
+ dbesc($item['author_xchan'])
+ );
+ if(! $r)
+ return;
+
+ $item['sig'] = base64url_encode(rsa_sign($item['body'], $r[0]['channel_prvkey']));
+ $item['item_verified'] = 1;
+}
+
+
+/**
+ * @brief Stores an item type record.
*
* @param array $arr
* @param boolean $allow_exec (optional) default false
@@ -1465,8 +1540,17 @@ function get_profile_elements($x) {
*/
function item_store($arr, $allow_exec = false, $deliver = true) {
- $d = array('item' => $arr, 'allow_exec' => $allow_exec);
- call_hooks('item_store', $d );
+ $d = [
+ 'item' => $arr,
+ 'allow_exec' => $allow_exec
+ ];
+ /**
+ * @hooks item_store
+ * Called when item_store() stores a record of type item.
+ * * \e array \b item
+ * * \e boolean \b allow_exec
+ */
+ call_hooks('item_store', $d);
$arr = $d['item'];
$allow_exec = $d['allow_exec'];
@@ -1475,7 +1559,7 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
if(array_key_exists('cancel',$arr) && $arr['cancel']) {
logger('cancelled by plugin');
return $ret;
- }
+ }
if(! $arr['uid']) {
logger('item_store: no uid');
@@ -1511,11 +1595,9 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
return $ret;
}
-
$arr['title'] = ((array_key_exists('title',$arr) && strlen($arr['title'])) ? trim($arr['title']) : '');
$arr['body'] = ((array_key_exists('body',$arr) && strlen($arr['body'])) ? trim($arr['body']) : '');
- $arr['diaspora_meta'] = ((x($arr,'diaspora_meta')) ? $arr['diaspora_meta'] : '');
$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']) : '');
@@ -1529,35 +1611,42 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
// obsolete, but needed so as not to throw not-null constraints on some database driveres
$arr['item_flags'] = ((x($arr,'item_flags')) ? intval($arr['item_flags']) : 0 );
- // only detect language if we have text content, and if the post is private but not yet
- // obscured, make it so.
- if((! array_key_exists('item_obscured',$arr)) || $arr['item_obscured'] == 0) {
+ $arr['lang'] = detect_language($arr['body']);
- $arr['lang'] = detect_language($arr['body']);
- // apply the input filter here - if it is obscured it has been filtered already
- $arr['body'] = trim(z_input_filter($arr['uid'],$arr['body'],$arr['mimetype']));
+ // apply the input filter here
- if(local_channel() && (local_channel() == $arr['uid']) && (! $arr['sig'])) {
- $channel = App::get_channel();
- if($channel['channel_hash'] === $arr['author_xchan']) {
- $arr['sig'] = base64url_encode(rsa_sign($arr['body'],$channel['channel_prvkey']));
- $arr['item_verified'] = 1;
- }
- }
+ $arr['body'] = trim(z_input_filter($arr['body'],$arr['mimetype'],$allow_exec));
- $allowed_languages = get_pconfig($arr['uid'],'system','allowed_languages');
+ item_sign($arr);
- if((is_array($allowed_languages)) && ($arr['lang']) && (! array_key_exists($arr['lang'],$allowed_languages))) {
- $translate = array('item' => $arr, 'from' => $arr['lang'], 'to' => $allowed_languages, 'translated' => false);
- call_hooks('item_translate', $translate);
- if((! $translate['translated']) && (intval(get_pconfig($arr['uid'],'system','reject_disallowed_languages')))) {
- logger('item_store: language ' . $arr['lang'] . ' not accepted for uid ' . $arr['uid']);
- $ret['message'] = 'language not accepted';
- return $ret;
- }
- $arr = $translate['item'];
+ if(! array_key_exists('sig',$arr))
+ $arr['sig'] = '';
+
+ $allowed_languages = get_pconfig($arr['uid'],'system','allowed_languages');
+
+ if((is_array($allowed_languages)) && ($arr['lang']) && (! array_key_exists($arr['lang'],$allowed_languages))) {
+ $translate = [
+ 'item' => $arr,
+ 'from' => $arr['lang'],
+ 'to' => $allowed_languages,
+ 'translated' => false
+ ];
+ /**
+ * @hooks item_translate
+ * Called from item_store and item_store_update after the post language has been autodetected.
+ * * \e array \b item
+ * * \e string \b from
+ * * \e string \b to
+ * * \e boolean \b translated
+ */
+ call_hooks('item_translate', $translate);
+ if((! $translate['translated']) && (intval(get_pconfig($arr['uid'],'system','reject_disallowed_languages')))) {
+ logger('language ' . $arr['lang'] . ' not accepted for uid ' . $arr['uid']);
+ $ret['message'] = 'language not accepted';
+ return $ret;
}
+ $arr = $translate['item'];
}
if((x($arr,'obj')) && is_array($arr['obj'])) {
@@ -1578,7 +1667,6 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
$arr['aid'] = ((x($arr,'aid')) ? intval($arr['aid']) : 0);
$arr['mid'] = ((x($arr,'mid')) ? notags(trim($arr['mid'])) : random_string());
$arr['revision'] = ((x($arr,'revision') && intval($arr['revision']) > 0) ? intval($arr['revision']) : 0);
-logger('revision: ' . $arr['revision']);
$arr['author_xchan'] = ((x($arr,'author_xchan')) ? notags(trim($arr['author_xchan'])) : '');
$arr['owner_xchan'] = ((x($arr,'owner_xchan')) ? notags(trim($arr['owner_xchan'])) : '');
@@ -1715,7 +1803,7 @@ logger('revision: ' . $arr['revision']);
if($r[0]['owner_xchan'] !== $arr['owner_xchan']) {
$arr['owner_xchan'] = $r[0]['owner_xchan'];
-// $uplinked_comment = true;
+ // $uplinked_comment = true;
}
// if the parent is private, force privacy for the entire conversation
@@ -1746,18 +1834,26 @@ logger('revision: ' . $arr['revision']);
intval($arr['revision'])
);
if($r) {
- logger('item_store: duplicate item ignored. ' . print_r($arr,true));
+ logger('duplicate item ignored. ' . print_r($arr,true));
$ret['message'] = 'duplicate post.';
return $ret;
}
- call_hooks('item_store',$arr);
+ /**
+ * @hooks item_store
+ * Called when item_store() stores a record of type item.
+ */
+ call_hooks('item_store', $arr);
- // This hook remains for backward compatibility.
- call_hooks('post_remote',$arr);
+ /**
+ * @hooks post_remote
+ * Called when an activity arrives from another site.
+ * This hook remains for backward compatibility.
+ */
+ call_hooks('post_remote', $arr);
- if(x($arr,'cancel')) {
- logger('item_store: post cancelled by plugin.');
+ if(x($arr, 'cancel')) {
+ logger('Post cancelled by plugin.');
$ret['message'] = 'cancelled.';
return $ret;
}
@@ -1804,9 +1900,12 @@ logger('revision: ' . $arr['revision']);
intval($arr['revision'])
);
- if($r && count($r)) {
+ if($r) {
+ // This will gives us a fresh copy of what's now in the DB and undo the db escaping,
+ // which really messes up the notifications
+
$current_post = $r[0]['id'];
- $arr = $r[0]; // This will gives us a fresh copy of what's now in the DB and undo the db escaping, which really messes up the notifications
+ $arr = $r[0];
logger('item_store: created item ' . $current_post, LOGGER_DEBUG);
}
else {
@@ -1861,11 +1960,15 @@ logger('revision: ' . $arr['revision']);
$ret['item'] = $arr;
- call_hooks('post_remote_end',$arr);
+ /**
+ * @hooks post_remote_end
+ * Called after processing a remote post.
+ */
+ call_hooks('post_remote_end', $arr);
// update the commented timestamp on the parent - unless this is potentially a clone of an older item
// which we don't wish to bring to the surface. As the queue only holds deliveries for 3 days, it's
- // suspected of being an older cloned item if the creation time is older than that.
+ // suspected of being an older cloned item if the creation time is older than that.
if($arr['created'] > datetime_convert('','','now - 4 days')) {
$z = q("select max(created) as commented from item where parent_mid = '%s' and uid = %d and item_delayed = 0 ",
@@ -1898,11 +2001,28 @@ logger('revision: ' . $arr['revision']);
}
-
-function item_store_update($arr,$allow_exec = false, $deliver = true) {
-
- $d = array('item' => $arr, 'allow_exec' => $allow_exec);
- call_hooks('item_store_update', $d );
+/**
+ * @brief Update a stored item.
+ *
+ * @param array $arr an item
+ * @param boolean $allow_exec (optional) default false
+ * @param boolean $deliver (optional) default true
+ * @return array
+ */
+function item_store_update($arr, $allow_exec = false, $deliver = true) {
+
+ $d = [
+ 'item' => $arr,
+ 'allow_exec' => $allow_exec
+ ];
+ /**
+ * @hooks item_store_update
+ * Called when item_store_update() is called to update a stored item. It
+ * overwrites the function's parameters $arr and $allow_exec.
+ * * \e array \b item
+ * * \e boolean \b allow_exec
+ */
+ call_hooks('item_store_update', $d);
$arr = $d['item'];
$allow_exec = $d['allow_exec'];
@@ -1911,15 +2031,15 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
if(array_key_exists('cancel',$arr) && $arr['cancel']) {
logger('cancelled by plugin');
return $ret;
- }
+ }
if(! intval($arr['uid'])) {
- logger('item_store_update: no uid');
+ logger('no uid');
$ret['message'] = 'no uid.';
return $ret;
}
if(! intval($arr['id'])) {
- logger('item_store_update: no id');
+ logger('no id');
$ret['message'] = 'no id.';
return $ret;
}
@@ -1932,7 +2052,7 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
intval($uid)
);
if(! $orig) {
- logger('item_store_update: original post not found: ' . $orig_post_id);
+ logger('Original post not found: ' . $orig_post_id);
$ret['message'] = 'no original';
return $ret;
}
@@ -1953,46 +2073,51 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
return $ret;
}
- if((! array_key_exists('item_obscured', $arr)) || $arr['item_obscured'] == 0) {
+ $arr['lang'] = detect_language($arr['body']);
- $arr['lang'] = detect_language($arr['body']);
+ // apply the input filter here
- // apply the input filter here - if it is obscured it has been filtered already
- $arr['body'] = trim(z_input_filter($arr['uid'],$arr['body'],$arr['mimetype']));
+ $arr['body'] = trim(z_input_filter($arr['body'],$arr['mimetype'],$allow_exec));
- if(local_channel() && (local_channel() == $arr['uid']) && (! $arr['sig'])) {
- $channel = App::get_channel();
- if($channel['channel_hash'] === $arr['author_xchan']) {
- $arr['sig'] = base64url_encode(rsa_sign($arr['body'],$channel['channel_prvkey']));
- $arr['item_verified'] = 1;
- }
- }
+ item_sign($arr);
- $allowed_languages = get_pconfig($arr['uid'],'system','allowed_languages');
+ $allowed_languages = get_pconfig($arr['uid'],'system','allowed_languages');
- if((is_array($allowed_languages)) && ($arr['lang']) && (! array_key_exists($arr['lang'],$allowed_languages))) {
- $translate = array('item' => $arr, 'from' => $arr['lang'], 'to' => $allowed_languages, 'translated' => false);
- call_hooks('item_translate', $translate);
- if((! $translate['translated']) && (intval(get_pconfig($arr['uid'],'system','reject_disallowed_languages')))) {
- logger('item_store: language ' . $arr['lang'] . ' not accepted for uid ' . $arr['uid']);
- $ret['message'] = 'language not accepted';
- return $ret;
- }
- $arr = $translate['item'];
+ if((is_array($allowed_languages)) && ($arr['lang']) && (! array_key_exists($arr['lang'],$allowed_languages))) {
+ $translate = [
+ 'item' => $arr,
+ 'from' => $arr['lang'],
+ 'to' => $allowed_languages,
+ 'translated' => false
+ ];
+ /**
+ * @hooks item_translate
+ * Called from item_store() and item_store_update() after the post language has been autodetected.
+ * * \e array \b item - returned value
+ * * \e string \b from
+ * * \e string \b to
+ * * \e boolean \b translated - default false, set true if hook translated it and provide it in item
+ */
+ call_hooks('item_translate', $translate);
+ if((! $translate['translated']) && (intval(get_pconfig($arr['uid'],'system','reject_disallowed_languages')))) {
+ logger('item_store: language ' . $arr['lang'] . ' not accepted for uid ' . $arr['uid']);
+ $ret['message'] = 'language not accepted';
+ return $ret;
}
+ $arr = $translate['item'];
}
- if((x($arr,'obj')) && is_array($arr['obj'])) {
+ if((array_key_exists('obj',$arr)) && is_array($arr['obj'])) {
activity_sanitise($arr['obj']);
$arr['obj'] = json_encode($arr['obj']);
}
- if((x($arr,'target')) && is_array($arr['target'])) {
+ if((array_key_exists('target',$arr)) && is_array($arr['target'])) {
activity_sanitise($arr['target']);
$arr['target'] = json_encode($arr['target']);
}
- if((x($arr,'attach')) && is_array($arr['attach'])) {
+ if((array_key_exists('attach',$arr)) && is_array($arr['attach'])) {
activity_sanitise($arr['attach']);
$arr['attach'] = json_encode($arr['attach']);
}
@@ -2025,7 +2150,7 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
$arr['changed'] = $orig[0]['changed'];
$arr['route'] = ((array_key_exists('route',$arr)) ? trim($arr['route']) : $orig[0]['route']);
- $arr['diaspora_meta'] = ((x($arr,'diaspora_meta')) ? $arr['diaspora_meta'] : $orig[0]['diaspora_meta']);
+
$arr['location'] = ((x($arr,'location')) ? notags(trim($arr['location'])) : $orig[0]['location']);
$arr['coord'] = ((x($arr,'coord')) ? notags(trim($arr['coord'])) : $orig[0]['coord']);
$arr['verb'] = ((x($arr,'verb')) ? notags(trim($arr['verb'])) : $orig[0]['verb']);
@@ -2072,18 +2197,20 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
$arr['item_pending_remove'] = ((array_key_exists('item_pending_remove',$arr)) ? intval($arr['item_pending_remove']) : $orig[0]['item_pending_remove'] );
$arr['item_blocked'] = ((array_key_exists('item_blocked',$arr)) ? intval($arr['item_blocked']) : $orig[0]['item_blocked'] );
-
-
$arr['sig'] = ((x($arr,'sig')) ? $arr['sig'] : '');
$arr['layout_mid'] = ((array_key_exists('layout_mid',$arr)) ? dbesc($arr['layout_mid']) : $orig[0]['layout_mid'] );
$arr['public_policy'] = ((x($arr,'public_policy')) ? notags(trim($arr['public_policy'])) : $orig[0]['public_policy'] );
$arr['comment_policy'] = ((x($arr,'comment_policy')) ? notags(trim($arr['comment_policy'])) : $orig[0]['comment_policy'] );
- call_hooks('post_remote_update',$arr);
+ /**
+ * @hooks post_remote_update
+ * Called when processing a remote post that involved an edit or update.
+ */
+ call_hooks('post_remote_update', $arr);
- if(x($arr,'cancel')) {
- logger('item_store_update: post cancelled by plugin.');
+ if(x($arr, 'cancel')) {
+ logger('Post cancelled by plugin.');
$ret['message'] = 'cancelled.';
return $ret;
}
@@ -2120,9 +2247,9 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
$r = dbq("update item set " . $str . " where id = " . $orig_post_id );
if($r)
- logger('item_store_update: updated item ' . $orig_post_id, LOGGER_DEBUG);
+ logger('Updated item ' . $orig_post_id, LOGGER_DEBUG);
else {
- logger('item_store_update: could not update item');
+ logger('Could not update item');
$ret['message'] = 'DB update failed.';
return $ret;
}
@@ -2169,7 +2296,11 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
$ret['item'] = $arr;
- call_hooks('post_remote_update_end',$arr);
+ /**
+ * @hooks post_remote_update_end
+ * Called after processing a remote post that involved an edit or update.
+ */
+ call_hooks('post_remote_update_end', $arr);
if($deliver) {
send_status_notifications($orig_post_id,$arr);
@@ -2184,55 +2315,6 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
-function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id, $walltowall = false) {
-
- // We won't be able to sign Diaspora comments for authenticated visitors
- // - we don't have their private key
-
- // since Diaspora doesn't handle edits we can only do this for the original text and not update it.
-
- require_once('include/markdown.php');
- $signed_body = bb2diaspora_itembody($datarray,$walltowall);
-
- if($walltowall) {
- logger('wall to wall comment',LOGGER_DEBUG);
- // post will come across with the owner's identity. Throw a preamble onto the post to indicate the true author.
- $signed_body = "\n\n"
- . '![' . $datarray['author']['xchan_name'] . '](' . $datarray['author']['xchan_photo_m'] . ')'
- . '[' . $datarray['author']['xchan_name'] . '](' . $datarray['author']['xchan_url'] . ')' . "\n\n"
- . $signed_body;
- }
-
- logger('storing diaspora comment signature',LOGGER_DEBUG);
-
- $diaspora_handle = channel_reddress($channel);
-
- $signed_text = $datarray['mid'] . ';' . $parent_item['mid'] . ';' . $signed_body . ';' . $diaspora_handle;
-
-
- if( $channel && $channel['channel_prvkey'] )
- $authorsig = base64_encode(rsa_sign($signed_text, $channel['channel_prvkey'], 'sha256'));
- else
- $authorsig = '';
-
- $x = array('signer' => $diaspora_handle, 'body' => $signed_body, 'signed_text' => $signed_text, 'signature' => $authorsig);
-
- $y = json_encode($x);
-
- $r = q("update item set diaspora_meta = '%s' where id = %d",
- dbesc($y),
- intval($post_id)
- );
-
-
- if(! $r)
- logger('store_diaspora_comment_sig: DB write failed');
-
- return;
-}
-
-
-
function send_status_notifications($post_id,$item) {
// only send notifications for comments
@@ -2451,7 +2533,7 @@ function tag_deliver($uid, $item_id) {
}
}
else
- logger('tag_deliver: tag permission denied for ' . $u[0]['channel_address']);
+ logger('Tag permission denied for ' . $u[0]['channel_address']);
}
/*
@@ -2484,126 +2566,166 @@ function tag_deliver($uid, $item_id) {
* Now we've got those out of the way. Let's see if this is a post that's tagged for re-delivery
*/
- $terms = get_terms_oftype($item['term'],TERM_MENTION);
+ $terms = array_merge(get_terms_oftype($item['term'],TERM_MENTION),get_terms_oftype($item['term'],TERM_FORUM));
if($terms)
- logger('tag_deliver: post mentions: ' . print_r($terms,true), LOGGER_DATA);
+ logger('Post mentions: ' . print_r($terms,true), LOGGER_DATA);
+
+
+ $max_forums = get_config('system','max_tagged_forums',2);
+ $matched_forums = 0;
+
$link = normalise_link($u[0]['xchan_url']);
+
if($terms) {
foreach($terms as $term) {
- if(link_compare($term['url'],$link)) {
- $mention = true;
- break;
+ if(! link_compare($term['url'],$link)) {
+ continue;
}
- }
- }
- if($mention) {
- logger('tag_deliver: mention found for ' . $u[0]['channel_name']);
+ $mention = true;
- $r = q("update item set item_mentionsme = 1 where id = %d",
- intval($item_id)
- );
+ logger('Mention found for ' . $u[0]['channel_name']);
- // At this point we've determined that the person receiving this post was mentioned in it or it is a union.
- // Now let's check if this mention was inside a reshare so we don't spam a forum
- // If it's private we may have to unobscure it momentarily so that we can parse it.
+ $r = q("update item set item_mentionsme = 1 where id = %d",
+ intval($item_id)
+ );
- $body = '';
+ // At this point we've determined that the person receiving this post was mentioned in it or it is a union.
+ // Now let's check if this mention was inside a reshare so we don't spam a forum
+ // If it's private we may have to unobscure it momentarily so that we can parse it.
- if(intval($item['item_obscured'])) {
- $key = get_config('system','prvkey');
- if($item['body'])
- $body = crypto_unencapsulate(json_decode($item['body'],true),$key);
- }
- else
- $body = $item['body'];
-
- $body = preg_replace('/\[share(.*?)\[\/share\]/','',$body);
-
- $tagged = false;
- $plustagged = false;
- $matches = array();
-
- $pattern = '/@\!?\[zrl\=' . preg_quote($term['url'],'/') . '\]' . preg_quote($term['term'],'/') . '\[\/zrl\]/';
- if(preg_match($pattern,$body,$matches))
- $tagged = true;
-
- $pattern = '/@\!?\[zrl\=([^\]]*?)\]((?:.(?!\[zrl\=))*?)\+\[\/zrl\]/';
-
- if(preg_match_all($pattern,$body,$matches,PREG_SET_ORDER)) {
- $max_forums = get_config('system','max_tagged_forums');
- if(! $max_forums)
- $max_forums = 2;
- $matched_forums = 0;
- foreach($matches as $match) {
- $matched_forums ++;
- if($term['url'] === $match[1] && $term['term'] === $match[2]) {
- if($matched_forums <= $max_forums) {
- $plustagged = true;
- break;
+ $body = preg_replace('/\[share(.*?)\[\/share\]/','',$item['body']);
+
+ $tagged = false;
+ $plustagged = false;
+ $matches = array();
+
+ $pattern = '/[\!@]\!?\[zrl\=' . preg_quote($term['url'],'/') . '\]' . preg_quote($term['term'],'/') . '\[\/zrl\]/';
+ if(preg_match($pattern,$body,$matches))
+ $tagged = true;
+
+ // original red forum tagging sequence @forumname+
+ // standard forum tagging sequence !forumname
+
+ $pluspattern = '/@\!?\[zrl\=([^\]]*?)\]((?:.(?!\[zrl\=))*?)\+\[\/zrl\]/';
+
+ $forumpattern = '/\!\!?\[zrl\=([^\]]*?)\]((?:.(?!\[zrl\=))*?)\[\/zrl\]/';
+
+ $found = false;
+
+ $matches = array();
+
+ if(preg_match_all($pluspattern,$body,$matches,PREG_SET_ORDER)) {
+ foreach($matches as $match) {
+ $matched_forums ++;
+ if($term['url'] === $match[1] && $term['term'] === $match[2] && intval($term['ttype']) === TERM_MENTION) {
+ if($matched_forums <= $max_forums) {
+ $plustagged = true;
+ $found = true;
+ break;
+ }
+ logger('forum ' . $term['term'] . ' exceeded max_tagged_forums - ignoring');
}
- logger('forum ' . $term['term'] . ' exceeded max_tagged_forums - ignoring');
}
}
- }
- if(! ($tagged || $plustagged)) {
- logger('tag_deliver: mention was in a reshare or exceeded max_tagged_forums - ignoring');
- return;
- }
+ if(preg_match_all($forumpattern,$body,$matches,PREG_SET_ORDER)) {
+ foreach($matches as $match) {
+ $matched_forums ++;
+ if($term['url'] === $match[1] && $term['term'] === $match[2] && intval($term['ttype']) === TERM_FORUM) {
+ if($matched_forums <= $max_forums) {
+ $plustagged = true;
+ $found = true;
+ break;
+ }
+ logger('forum ' . $term['term'] . ' exceeded max_tagged_forums - ignoring');
+ }
+ }
+ }
- $arr = array('channel_id' => $uid, 'item' => $item, 'body' => $body);
- call_hooks('tagged',$arr);
+ if(! ($tagged || $plustagged)) {
+ logger('Mention was in a reshare or exceeded max_tagged_forums - ignoring');
+ continue;
+ }
- /*
- * Kill two birds with one stone. As long as we're here, send a mention notification.
- */
+ $arr = [
+ 'channel_id' => $uid,
+ 'item' => $item,
+ 'body' => $body
+ ];
+ /**
+ * @hooks tagged
+ * Called when a delivery is processed which results in you being tagged.
+ * * \e number \b channel_id
+ * * \e array \b item
+ * * \e string \b body
+ */
+ call_hooks('tagged', $arr);
+
+ /*
+ * Kill two birds with one stone. As long as we're here, send a mention notification.
+ */
- Zlib\Enotify::submit(array(
- 'to_xchan' => $u[0]['channel_hash'],
- 'from_xchan' => $item['author_xchan'],
- 'type' => NOTIFY_TAGSELF,
- 'item' => $item,
- 'link' => $i[0]['llink'],
- 'verb' => ACTIVITY_TAG,
- 'otype' => 'item'
- ));
+ Zlib\Enotify::submit(array(
+ 'to_xchan' => $u[0]['channel_hash'],
+ 'from_xchan' => $item['author_xchan'],
+ 'type' => NOTIFY_TAGSELF,
+ 'item' => $item,
+ 'link' => $i[0]['llink'],
+ 'verb' => ACTIVITY_TAG,
+ 'otype' => 'item'
+ ));
- // Just a normal tag?
+ // Just a normal tag?
- if(! $plustagged) {
- logger('tag_deliver: not a plus tag', LOGGER_DEBUG);
- return;
- }
+ if(! $plustagged) {
+ logger('Not a plus tag', LOGGER_DEBUG);
+ continue;
+ }
- // plustagged - keep going, next check permissions
+ // plustagged - keep going, next check permissions
- if(! perm_is_allowed($uid,$item['author_xchan'],'tag_deliver')) {
- logger('tag_delivery denied for uid ' . $uid . ' and xchan ' . $item['author_xchan']);
- return;
- }
- }
+ if(! perm_is_allowed($uid,$item['author_xchan'],'tag_deliver')) {
+ logger('tag_delivery denied for uid ' . $uid . ' and xchan ' . $item['author_xchan']);
+ continue;
+ }
- if((! $mention) && (! $union)) {
- logger('tag_deliver: no mention for ' . $u[0]['channel_name'] . ' and no union.');
- return;
+
+ if(! $mention) {
+ logger('No mention for ' . $u[0]['channel_name']);
+ continue;
+ }
+
+ // tgroup delivery - setup a second delivery chain
+ // prevent delivery looping - only proceed
+ // if the message originated elsewhere and is a top-level post
+
+
+ if(intval($item['item_wall']) || intval($item['item_origin']) || (! intval($item['item_thread_top'])) || ($item['id'] != $item['parent'])) {
+ logger('Item was local or a comment. rejected.');
+ continue;
+ }
+
+ logger('Creating second delivery chain.');
+ start_delivery_chain($u[0],$item,$item_id,null);
+
+ }
}
- // tgroup delivery - setup a second delivery chain
- // prevent delivery looping - only proceed
- // if the message originated elsewhere and is a top-level post
+ if($union) {
+ if(intval($item['item_wall']) || intval($item['item_origin']) || (! intval($item['item_thread_top'])) || ($item['id'] != $item['parent'])) {
+ logger('Item was local or a comment. rejected.');
+ return;
+ }
+ logger('Creating second delivery chain.');
+ start_delivery_chain($u[0],$item,$item_id,null);
- if(intval($item['item_wall']) || intval($item['item_origin']) || (! intval($item['item_thread_top'])) || ($item['id'] != $item['parent'])) {
- logger('tag_deliver: item was local or a comment. rejected.');
- return;
}
- logger('tag_deliver: creating second delivery chain.');
- start_delivery_chain($u[0],$item,$item_id,null);
}
/**
@@ -2613,8 +2735,12 @@ function tag_deliver($uid, $item_id) {
* This is so that the channel with tag_delivery enabled can receive the post even if they turn off
* permissions for the sender to send their stream. tag_deliver() can't be called until the post is actually stored.
* By then it would be too late to reject it.
+ *
+ * @param number $uid A chnnel_id
+ * @param array $item
+ * @return boolean
*/
-function tgroup_check($uid,$item) {
+function tgroup_check($uid, $item) {
$mention = false;
@@ -2641,72 +2767,79 @@ function tgroup_check($uid,$item) {
if(! $u)
return false;
- $terms = get_terms_oftype($item['term'],TERM_MENTION);
+
+ $terms = array_merge(get_terms_oftype($item['term'],TERM_MENTION),get_terms_oftype($item['term'],TERM_FORUM));
if($terms)
logger('tgroup_check: post mentions: ' . print_r($terms,true), LOGGER_DATA);
+ $max_forums = get_config('system','max_tagged_forums',2);
+ $matched_forums = 0;
+
$link = normalise_link($u[0]['xchan_url']);
if($terms) {
foreach($terms as $term) {
- if(link_compare($term['url'],$link)) {
- $mention = true;
- break;
+ if(! link_compare($term['url'],$link)) {
+ continue;
}
- }
- }
- if($mention) {
- logger('tgroup_check: mention found for ' . $u[0]['channel_name']);
- }
- else
- return false;
+ $mention = true;
+ logger('tgroup_check: mention found for ' . $u[0]['channel_name']);
- // At this point we've determined that the person receiving this post was mentioned in it.
- // Now let's check if this mention was inside a reshare so we don't spam a forum
- // note: $term has been set to the matching term
+ // At this point we've determined that the person receiving this post was mentioned in it.
+ // Now let's check if this mention was inside a reshare so we don't spam a forum
+ // note: $term has been set to the matching term
- $body = $item['body'];
+ $body = preg_replace('/\[share(.*?)\[\/share\]/','',$item['body']);
- if(array_key_exists('item_obscured',$item) && intval($item['item_obscured']) && $body) {
- $key = get_config('system','prvkey');
- $body = crypto_unencapsulate(json_decode($body,true),$key);
- }
- $body = preg_replace('/\[share(.*?)\[\/share\]/','',$body);
+ $pluspattern = '/@\!?\[zrl\=([^\]]*?)\]((?:.(?!\[zrl\=))*?)\+\[\/zrl\]/';
-// $pattern = '/@\!?\[zrl\=' . preg_quote($term['url'],'/') . '\]' . preg_quote($term['term'] . '+','/') . '\[\/zrl\]/';
+ $forumpattern = '/\!\!?\[zrl\=([^\]]*?)\]((?:.(?!\[zrl\=))*?)\[\/zrl\]/';
- $pattern = '/@\!?\[zrl\=([^\]]*?)\]((?:.(?!\[zrl\=))*?)\+\[\/zrl\]/';
+ $found = false;
- $found = false;
- $matches = array();
+ $matches = array();
- if(preg_match_all($pattern,$body,$matches,PREG_SET_ORDER)) {
- $max_forums = get_config('system','max_tagged_forums');
- if(! $max_forums)
- $max_forums = 2;
- $matched_forums = 0;
- foreach($matches as $match) {
- $matched_forums ++;
- if($term['url'] === $match[1] && $term['term'] === $match[2]) {
- if($matched_forums <= $max_forums) {
- $found = true;
- break;
+ if(preg_match_all($pluspattern,$body,$matches,PREG_SET_ORDER)) {
+ foreach($matches as $match) {
+ $matched_forums ++;
+ if($term['url'] === $match[1] && $term['term'] === $match[2] && intval($term['ttype']) === TERM_MENTION) {
+ if($matched_forums <= $max_forums) {
+ $found = true;
+ break;
+ }
+ logger('forum ' . $term['term'] . ' exceeded max_tagged_forums - ignoring');
+ }
+ }
+ }
+
+ if(preg_match_all($forumpattern,$body,$matches,PREG_SET_ORDER)) {
+ foreach($matches as $match) {
+ $matched_forums ++;
+ if($term['url'] === $match[1] && $term['term'] === $match[2] && intval($term['ttype']) === TERM_FORUM) {
+ if($matched_forums <= $max_forums) {
+ $found = true;
+ break;
+ }
+ logger('forum ' . $term['term'] . ' exceeded max_tagged_forums - ignoring');
+ }
}
- logger('forum ' . $term['term'] . ' exceeded max_tagged_forums - ignoring');
}
+
+ if(! $found) {
+ logger('tgroup_check: mention was in a reshare or exceeded max_tagged_forums - ignoring');
+ continue;
+ }
+
+ return true;
}
}
- if(! $found) {
- logger('tgroup_check: mention was in a reshare or exceeded max_tagged_forums - ignoring');
- return false;
- }
+ return false;
- return true;
}
/**
@@ -2727,8 +2860,8 @@ function start_delivery_chain($channel, $item, $item_id, $parent) {
if($sourced) {
$r = q("select * from source where src_channel_id = %d and ( src_xchan = '%s' or src_xchan = '*' ) limit 1",
intval($channel['channel_id']),
- dbesc(($item['source_xchan']) ? $item['source_xchan'] : $item['owner_xchan'])
- );
+ dbesc(($item['source_xchan']) ? $item['source_xchan'] : $item['owner_xchan'])
+ );
if($r) {
$t = trim($r[0]['src_tag']);
if($t) {
@@ -2737,15 +2870,15 @@ function start_delivery_chain($channel, $item, $item_id, $parent) {
foreach($tags as $tt) {
$tt = trim($tt);
if($tt) {
- q("insert into term (uid,oid,otype,ttype,term,url)
- values(%d,%d,%d,%d,'%s','%s') ",
- intval($channel['channel_id']),
- intval($item_id),
- intval(TERM_OBJ_POST),
- intval(TERM_CATEGORY),
- dbesc($tt),
+ q("insert into term (uid,oid,otype,ttype,term,url)
+ values(%d,%d,%d,%d,'%s','%s') ",
+ intval($channel['channel_id']),
+ intval($item_id),
+ intval(TERM_OBJ_POST),
+ intval(TERM_CATEGORY),
+ dbesc($tt),
dbesc(z_root() . '/channel/' . $channel['channel_address'] . '?f=&cat=' . urlencode($tt))
- );
+ );
}
}
}
@@ -2768,7 +2901,6 @@ function start_delivery_chain($channel, $item, $item_id, $parent) {
$item_origin = 1;
$item_uplink = 0;
$item_nocomment = 0;
- $item_obscured = 0;
$flag_bits = $item['item_flags'];
@@ -2791,11 +2923,10 @@ function start_delivery_chain($channel, $item, $item_id, $parent) {
$title = $item['title'];
$body = $item['body'];
- $r = q("update item set item_uplink = %d, item_nocomment = %d, item_obscured = %d, item_flags = %d, owner_xchan = '%s', allow_cid = '%s', allow_gid = '%s',
+ $r = q("update item set item_uplink = %d, item_nocomment = %d, item_flags = %d, owner_xchan = '%s', allow_cid = '%s', allow_gid = '%s',
deny_cid = '%s', deny_gid = '%s', item_private = %d, public_policy = '%s', comment_policy = '%s', title = '%s', body = '%s', item_wall = %d, item_origin = %d where id = %d",
intval($item_uplink),
intval($item_nocomment),
- intval($item_obscured),
intval($flag_bits),
dbesc($channel['channel_hash']),
dbesc($channel['channel_allow_cid']),
@@ -2980,13 +3111,21 @@ function mail_store($arr) {
return 0;
}
+ $channel = channelx_by_n($arr['channel_id']);
+
if(! $arr['mail_obscured']) {
if((strpos($arr['body'],'<') !== false) || (strpos($arr['body'],'>') !== false))
$arr['body'] = escape_tags($arr['body']);
}
- if(array_key_exists('attach',$arr) && is_array($arr['attach']))
- $arr['attach'] = json_encode($arr['attach']);
+ if(array_key_exists('attach',$arr)) {
+ if(is_array($arr['attach'])) {
+ $arr['attach'] = json_encode($arr['attach']);
+ }
+ }
+ else {
+ $arr['attach'] = '';
+ }
$arr['account_id'] = ((x($arr,'account_id')) ? intval($arr['account_id']) : 0);
$arr['mid'] = ((x($arr,'mid')) ? notags(trim($arr['mid'])) : random_string());
@@ -2997,34 +3136,63 @@ function mail_store($arr) {
$arr['title'] = ((x($arr,'title')) ? trim($arr['title']) : '');
$arr['parent_mid'] = ((x($arr,'parent_mid')) ? notags(trim($arr['parent_mid'])) : '');
$arr['body'] = ((x($arr,'body')) ? trim($arr['body']) : '');
+ $arr['sig'] = ((x($arr,'sig')) ? trim($arr['sig']) : '');
$arr['conv_guid'] = ((x($arr,'conv_guid')) ? trim($arr['conv_guid']) : '');
+ $arr['mail_mimetype'] = ((x($arr,'mail_mimetype')) ? trim($arr['mail_mimetype']) : 'text/bbcode');
$arr['mail_flags'] = ((x($arr,'mail_flags')) ? intval($arr['mail_flags']) : 0 );
+ $arr['mail_raw'] = ((x($arr,'mail_raw')) ? intval($arr['mail_raw']) : 0 );
+
- if(! $arr['parent_mid']) {
+ if($arr['parent_mid']) {
+ $parent_item = q("select * from mail where mid = '%s' and channel_id = %d limit 1",
+ dbesc($arr['parent_mid']),
+ intval($arr['channel_id'])
+ );
+ if(($parent_item) && (! $arr['conv_guid'])) {
+ $arr['conv_guid'] = $parent_item[0]['conv_guid'];
+ }
+ }
+ else {
logger('mail_store: missing parent');
$arr['parent_mid'] = $arr['mid'];
}
+ if($arr['from_xchan'] === $channel['channel_hash'])
+ $conversant = $arr['to_xchan'];
+ else
+ $conversant = $arr['from_xchan'];
+
+
+ if(! $arr['conv_guid']) {
+ $x = create_conversation($channel,$conversant,(($arr['title']) ? base64url_decode(str_rot47($arr['title'])) : ''));
+ $arr['conv_guid'] = (($x) ? $x['guid'] : '');
+ }
+
+
$r = q("SELECT id FROM mail WHERE mid = '%s' AND channel_id = %d LIMIT 1",
dbesc($arr['mid']),
intval($arr['channel_id'])
);
if($r) {
- logger('mail_store: duplicate item ignored. ' . print_r($arr,true));
+ logger('Duplicate item ignored. ' . print_r($arr,true));
return 0;
}
if(! $r && $arr['mail_recalled'] == 1) {
- logger('mail_store: recalled item not found. ' . print_r($arr,true));
+ logger('Recalled item not found. ' . print_r($arr,true));
return 0;
}
- call_hooks('post_mail',$arr);
+ /**
+ * @hooks post_mail
+ * Called when a mail message has been composed.
+ */
+ call_hooks('post_mail', $arr);
if(x($arr,'cancel')) {
- logger('mail_store: post cancelled by plugin.');
+ logger('Post cancelled by plugin.');
return 0;
}
@@ -3041,15 +3209,15 @@ function mail_store($arr) {
if($r) {
$current_post = $r[0]['id'];
- logger('mail_store: created item ' . $current_post, LOGGER_DEBUG);
+ logger('Created item ' . $current_post, LOGGER_DEBUG);
$arr['id'] = $current_post; // for notification
}
else {
- logger('mail_store: could not locate created item');
+ logger('Could not locate created item');
return 0;
}
if(count($r) > 1) {
- logger('mail_store: duplicated post occurred. Removing duplicates.');
+ logger('Duplicated post occurred. Removing duplicates.');
q("DELETE FROM mail WHERE mid = '%s' AND channel_id = %d AND id != %d ",
$arr['mid'],
intval($arr['channel_id']),
@@ -3070,7 +3238,19 @@ function mail_store($arr) {
Zlib\Enotify::submit($notif_params);
}
- call_hooks('post_mail_end',$arr);
+ if($arr['conv_guid']) {
+ $c = q("update conv set updated = '%s' where guid = '%s' and uid = %d",
+ dbesc(datetime_convert()),
+ dbesc($arr['conv_guid']),
+ intval($arr['channel_id'])
+ );
+ }
+
+ /**
+ * @hooks post_mail_end
+ * Called when a mail message has been delivered.
+ */
+ call_hooks('post_mail_end', $arr);
return $current_post;
}
@@ -3091,7 +3271,7 @@ function fix_private_photos($s, $uid, $item = null, $cid = 0) {
$img_st_close++; // make it point to AFTER the closing bracket
$image = substr($orig_body, $img_start + $img_st_close, $img_len);
- logger('fix_private_photos: found photo ' . $image, LOGGER_DEBUG);
+ logger('Found photo ' . $image, LOGGER_DEBUG);
if(stristr($image , $site . '/photo/')) {
// Only embed locally hosted photos
@@ -3135,7 +3315,7 @@ function fix_private_photos($s, $uid, $item = null, $cid = 0) {
// If a custom width and height were specified, apply before embedding
if(preg_match("/\[zmg\=([0-9]*)x([0-9]*)\]/is", substr($orig_body, $img_start, $img_st_close), $match)) {
- logger('fix_private_photos: scaling photo', LOGGER_DEBUG);
+ logger('Scaling photo', LOGGER_DEBUG);
$width = intval($match[1]);
$height = intval($match[2]);
@@ -3148,9 +3328,9 @@ function fix_private_photos($s, $uid, $item = null, $cid = 0) {
}
}
- logger('fix_private_photos: replacing photo', LOGGER_DEBUG);
+ logger('Replacing photo', LOGGER_DEBUG);
$image = 'data:' . $type . ';base64,' . base64_encode($data);
- logger('fix_private_photos: replaced: ' . $image, LOGGER_DATA);
+ logger('Replaced: ' . $image, LOGGER_DATA);
}
}
}
@@ -3407,8 +3587,16 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal
);
}
- $arr = array('item' => $item, 'interactive' => $interactive, 'stage' => $stage);
- call_hooks('drop_item', $arr );
+ $arr = [
+ 'item' => $item,
+ 'interactive' => $interactive,
+ 'stage' => $stage
+ ];
+ /**
+ * @hooks drop_item
+ * Called when an 'item' is removed.
+ */
+ call_hooks('drop_item', $arr);
$notify_id = intval($item['id']);
@@ -3558,8 +3746,14 @@ function delete_item_lowlevel($item, $stage = DROPITEM_NORMAL, $force = false) {
return true;
}
-
-function first_post_date($uid,$wall = false) {
+/**
+ * @brief Return the first post date.
+ *
+ * @param int $uid
+ * @param boolean $wall (optional) default false
+ * @return string|boolean date string, otherwise false
+ */
+function first_post_date($uid, $wall = false) {
$wall_sql = (($wall) ? " and item_wall = 1 " : "" );
$item_normal = item_normal();
@@ -3568,7 +3762,6 @@ function first_post_date($uid,$wall = false) {
where uid = %d and id = parent $item_normal $wall_sql
order by created asc limit 1",
intval($uid)
-
);
if($r) {
// logger('first_post_date: ' . $r[0]['id'] . ' ' . $r[0]['created'], LOGGER_DATA);
@@ -3584,8 +3777,8 @@ function first_post_date($uid,$wall = false) {
* current flat list of all representative dates.
*
* @param int $uid
- * @param unknown $wall
- * @param unknown $mindate
+ * @param boolean $wall
+ * @param string $mindate
* @return array
*/
function list_post_dates($uid, $wall, $mindate) {
@@ -3656,8 +3849,14 @@ function posted_dates($uid,$wall) {
return $ret;
}
-
-function fetch_post_tags($items,$link = false) {
+/**
+ * @brief Extend an item array with the associated tags of the posts.
+ *
+ * @param array $items
+ * @param boolean $link (optional) default false
+ * @return array Return the provided $items array after extended the posts with tags
+ */
+function fetch_post_tags($items, $link = false) {
$tag_finder = array();
if($items) {
@@ -3676,7 +3875,6 @@ function fetch_post_tags($items,$link = false) {
}
$tag_finder_str = implode(', ', $tag_finder);
-
if(strlen($tag_finder_str)) {
$tags = q("select * from term where oid in ( %s ) and otype = %d",
dbesc($tag_finder_str),
@@ -3685,7 +3883,6 @@ function fetch_post_tags($items,$link = false) {
$imeta = q("select * from iconfig where iid in ( %s )",
dbesc($tag_finder_str)
);
-
}
for($x = 0; $x < count($items); $x ++) {
@@ -3735,8 +3932,15 @@ function fetch_post_tags($items,$link = false) {
}
-
-function zot_feed($uid,$observer_hash,$arr) {
+/**
+ * @brief
+ *
+ * @param int $uid
+ * @param string $observer_hash
+ * @param array $arr
+ * @return array
+ */
+function zot_feed($uid, $observer_hash, $arr) {
$result = array();
$mindate = null;
@@ -3769,7 +3973,7 @@ function zot_feed($uid,$observer_hash,$arr) {
if(! is_sys_channel($uid))
$sql_extra = item_permissions_sql($uid,$observer_hash);
- $limit = " LIMIT 100 ";
+ $limit = " LIMIT 5000 ";
if($mindate > NULL_DATE) {
$sql_extra .= " and ( created > '$mindate' or changed > '$mindate' ) ";
@@ -3781,15 +3985,7 @@ function zot_feed($uid,$observer_hash,$arr) {
}
- $items = array();
-
- /** @FIXME re-unite these SQL statements. There is no need for them to be separate. The mySQL is convoluted with misuse of group by. As it stands, there is a slight difference where the postgres version doesn't remove the duplicate parents up to 100. In practice this doesn't matter. It could be made to match behavior by adding "distinct on (parent) " to the front of the selection list, at a not-worth-it performance penalty (page temp results to disk). duplicates are still ignored in the in() clause, you just get less than 100 parents if there are many children. */
-
- if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
- $groupby = '';
- } else {
- $groupby = 'GROUP BY parent';
- }
+ $items = [];
$item_normal = item_normal();
@@ -3798,7 +3994,7 @@ function zot_feed($uid,$observer_hash,$arr) {
WHERE uid != %d
$item_normal
AND item_wall = 1
- and item_private = 0 $sql_extra $groupby ORDER BY created ASC $limit",
+ and item_private = 0 $sql_extra ORDER BY created ASC $limit",
intval($uid)
);
}
@@ -3806,19 +4002,25 @@ function zot_feed($uid,$observer_hash,$arr) {
$r = q("SELECT parent, created, postopts from item
WHERE uid = %d $item_normal
AND item_wall = 1
- $sql_extra $groupby ORDER BY created ASC $limit",
+ $sql_extra ORDER BY created ASC $limit",
intval($uid)
);
}
+ $parents = [];
+
if($r) {
- for($x = 0; $x < count($r); $x ++) {
- if(strpos($r[$x]['postopts'],'nodeliver') !== false) {
- unset($r[$x]);
- }
+ foreach($r as $rv) {
+ if(array_key_exists($rv['parent'],$parents))
+ continue;
+ if(strpos($rv['postopts'],'nodeliver') !== false)
+ continue;
+ $parents[$rv['parent']] = $rv;
+ if(count($parents) > 200)
+ break;
}
- $parents_str = ids_to_querystr($r,'parent');
+ $parents_str = ids_to_querystr($parents,'parent');
$sys_query = ((is_sys_channel($uid)) ? $sql_extra : '');
$item_normal = item_normal();
@@ -3936,6 +4138,10 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
}
}
+ if($channel && intval($arr['compat']) === 1) {
+ $sql_extra = " AND author_xchan = '" . $channel['channel_hash'] . "' and item_private = 0 ";
+ }
+
if ($arr['datequery']) {
$sql_extra3 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert('UTC','UTC',$arr['datequery']))));
}
@@ -3943,30 +4149,24 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
$sql_extra3 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert('UTC','UTC',$arr['datequery2']))));
}
- if(! array_key_exists('nouveau',$arr)) {
- $sql_extra2 = " AND item.parent = item.id ";
-// $sql_extra3 = '';
- }
-
if($arr['search']) {
+ if(strpos($arr['search'],'#') === 0)
+ $sql_extra .= term_query('item',substr($arr['search'],1),TERM_HASHTAG,TERM_COMMUNITYTAG);
+ else
+ $sql_extra .= sprintf(" AND item.body like '%s' ",
+ dbesc(protect_sprintf('%' . $arr['search'] . '%'))
+ );
+ }
- if(strpos($arr['search'],'#') === 0)
- $sql_extra .= term_query('item',substr($arr['search'],1),TERM_HASHTAG,TERM_COMMUNITYTAG);
- else
- $sql_extra .= sprintf(" AND item.body like '%s' ",
- dbesc(protect_sprintf('%' . $arr['search'] . '%'))
- );
- }
-
- if(strlen($arr['file'])) {
- $sql_extra .= term_query('item',$arr['files'],TERM_FILE);
- }
+ if(strlen($arr['file'])) {
+ $sql_extra .= term_query('item',$arr['files'],TERM_FILE);
+ }
- if($arr['conv'] && $channel) {
- $sql_extra .= sprintf(" AND parent IN (SELECT distinct parent from item where ( author_xchan like '%s' or item_mentionsme = 1 )) ",
- dbesc(protect_sprintf($uidhash))
- );
- }
+ if($arr['conv'] && $channel) {
+ $sql_extra .= sprintf(" AND parent IN (SELECT distinct parent from item where ( author_xchan like '%s' or item_mentionsme = 1 )) ",
+ dbesc(protect_sprintf($uidhash))
+ );
+ }
if (($client_mode & CLIENT_MODE_UPDATE) && (! ($client_mode & CLIENT_MODE_LOAD))) {
// only setup pagination on initial page view
@@ -4001,9 +4201,9 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
}
}
- $simple_update = (($client_mode & CLIENT_MODE_UPDATE) ? " and item.item_unseen = 1 " : '');
- if($client_mode & CLIENT_MODE_LOAD)
- $simple_update = '';
+ $simple_update = (($client_mode & CLIENT_MODE_UPDATE) ? " and item.item_unseen = 1 " : '');
+ if($client_mode & CLIENT_MODE_LOAD)
+ $simple_update = '';
//$start = dba_timer();
@@ -4019,7 +4219,8 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
if($arr['item_type'] === '*')
$item_restrict = '';
- if ($arr['nouveau'] && ($client_mode & CLIENT_MODE_LOAD) && $channel) {
+ if ((($arr['compat']) || ($arr['nouveau'] && ($client_mode & CLIENT_MODE_LOAD))) && $channel) {
+
// "New Item View" - show all items unthreaded in reverse created date order
$items = q("SELECT item.*, item.id AS item_id FROM item
@@ -4045,27 +4246,26 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
if(($client_mode & CLIENT_MODE_LOAD) || ($client_mode == CLIENT_MODE_NORMAL)) {
- // Fetch a page full of parent items for this page
-
- $r = q("SELECT distinct item.id AS item_id, item.$ordering FROM item
- left join abook on item.author_xchan = abook.abook_xchan
- WHERE $item_uids $item_restrict
- AND item.parent = item.id
- and (abook.abook_blocked = 0 or abook.abook_flags is null)
- $sql_extra3 $sql_extra $sql_nets
- ORDER BY item.$ordering DESC $pager_sql "
- );
-
- }
- else {
- // update
- $r = q("SELECT item.parent AS item_id FROM item
- left join abook on item.author_xchan = abook.abook_xchan
- WHERE $item_uids $item_restrict $simple_update
- and (abook.abook_blocked = 0 or abook.abook_flags is null)
- $sql_extra3 $sql_extra $sql_nets "
- );
- }
+ // Fetch a page full of parent items for this page
+
+ $r = q("SELECT distinct item.id AS item_id, item.$ordering FROM item
+ left join abook on item.author_xchan = abook.abook_xchan
+ WHERE $item_uids $item_restrict
+ AND item.parent = item.id
+ and (abook.abook_blocked = 0 or abook.abook_flags is null)
+ $sql_extra3 $sql_extra $sql_nets
+ ORDER BY item.$ordering DESC $pager_sql "
+ );
+ }
+ else {
+ // update
+ $r = q("SELECT item.parent AS item_id FROM item
+ left join abook on item.author_xchan = abook.abook_xchan
+ WHERE $item_uids $item_restrict $simple_update
+ and (abook.abook_blocked = 0 or abook.abook_flags is null)
+ $sql_extra3 $sql_extra $sql_nets "
+ );
+ }
//$first = dba_timer();
@@ -4091,7 +4291,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
//$third = dba_timer();
- $items = fetch_post_tags($items,true);
+ $items = fetch_post_tags($items,false);
//$fourth = dba_timer();
@@ -4119,16 +4319,19 @@ function webpage_to_namespace($webpage) {
$page_type = 'BUILDBLOCK';
elseif($webpage == ITEM_TYPE_PDL)
$page_type = 'PDL';
+ elseif($webpage == ITEM_TYPE_CARD)
+ $page_type = 'CARD';
+ elseif($webpage == ITEM_TYPE_ARTICLE)
+ $page_type = 'ARTICLE';
elseif($webpage == ITEM_TYPE_DOC)
$page_type = 'docfile';
else
$page_type = 'unknown';
- return $page_type;
+ return $page_type;
}
-
function update_remote_id($channel,$post_id,$webpage,$pagetitle,$namespace,$remote_id,$mid) {
if(! $post_id)
@@ -4252,7 +4455,6 @@ function comment_local_origin($item) {
-
function send_profile_photo_activity($channel,$photo,$profile) {
// for now only create activities for the default profile
@@ -4301,8 +4503,6 @@ function send_profile_photo_activity($channel,$photo,$profile) {
$arr['author_xchan'] = $channel['channel_hash'];
post_activity_item($arr);
-
-
}
@@ -4314,10 +4514,7 @@ function sync_an_item($channel_id,$item_id) {
if($r) {
xchan_query($r);
$sync_item = fetch_post_tags($r);
- $rid = q("select * from item_id where iid = %d",
- intval($item_id)
- );
- build_sync_packet($channel_d,array('item' => array(encode_item($sync_item[0],true)),'item_id' => $rid));
+ build_sync_packet($channel_d,array('item' => array(encode_item($sync_item[0],true))));
}
}
@@ -4475,12 +4672,12 @@ function item_create_edit_activity($post) {
$new_item['id'] = 0;
$new_item['parent'] = 0;
$new_item['mid'] = item_message_id();
-
+
$new_item['body'] = sprintf( t('[Edited %s]'), (($update_item['item_thread_top']) ? t('Post','edit_activity') : t('Comment','edit_activity')));
$new_item['body'] .= "\n\n";
$new_item['body'] .= $update_item['body'];
-
+
$new_item['sig'] = '';
$new_item['verb'] = ACTIVITY_UPDATE;
@@ -4506,10 +4703,9 @@ function item_create_edit_activity($post) {
array('rel' => 'photo', 'type' => $item_author['xchan_photo_mimetype'], 'href' => $item_author['xchan_photo_m'])),
),
));
-
- $x = post_activity_item($new_item);
+ $x = post_activity_item($new_item);
$post_id = $x['id'];
if($post_id) {
@@ -4524,5 +4720,63 @@ function item_create_edit_activity($post) {
}
\Zotlabs\Daemon\Master::Summon(array('Notifier', 'edit_activity', $post_id));
-
+}
+
+/**
+ * @brief copies an entire conversation from the pubstream to this channel's stream
+ * which will allow you to interact with it.
+ */
+
+
+
+function copy_of_pubitem($channel,$mid) {
+
+ $result = null;
+ $syschan = get_sys_channel();
+
+ // logger('copy_of_pubitem: ' . $channel['channel_id'] . ' mid: ' . $mid);
+
+ $r = q("select * from item where mid = '%s' and uid = %d limit 1",
+ dbesc($mid),
+ intval($channel['channel_id'])
+ );
+
+ if($r) {
+ logger('exists');
+ $item = fetch_post_tags($r,true);
+ return $item[0];
+ }
+
+
+ $r = q("select * from item where parent_mid = (select parent_mid from item where mid = '%s' and uid = %d ) order by id ",
+ dbesc($mid),
+ intval($syschan['channel_id'])
+ );
+
+ if($r) {
+ $items = fetch_post_tags($r,true);
+ foreach($items as $rv) {
+ $d = q("select id from item where mid = '%s' and uid = %d limit 1",
+ dbesc($rv['mid']),
+ intval($channel['channel_id'])
+ );
+ if($d) {
+ continue;
+ }
+
+ unset($rv['id']);
+ unset($rv['parent']);
+ $rv['aid'] = $channel['channel_account_id'];
+ $rv['uid'] = $channel['channel_id'];
+ $rv['item_wall'] = 0;
+ $rv['item_origin'] = 0;
+
+ $x = item_store($rv);
+ if($x['item_id'] && $x['item']['mid'] === $mid) {
+ $result = $x['item'];
+ }
+
+ }
+ }
+ return $result;
}