diff options
author | zotlabs <mike@macgirvin.com> | 2018-02-05 15:58:28 -0800 |
---|---|---|
committer | zotlabs <mike@macgirvin.com> | 2018-02-05 15:58:28 -0800 |
commit | b41c5f349715abc6ca7db563e3938336bc75974e (patch) | |
tree | 31a1ee5a74227c30239bb9d2a10341bbacb8ecec /include | |
parent | 05de59d4ad174cb106c3a5b5890732af51730384 (diff) | |
parent | 930e1fdbdc798868760f8a4e03f32fc3f42e8bc9 (diff) | |
download | volse-hubzilla-b41c5f349715abc6ca7db563e3938336bc75974e.tar.gz volse-hubzilla-b41c5f349715abc6ca7db563e3938336bc75974e.tar.bz2 volse-hubzilla-b41c5f349715abc6ca7db563e3938336bc75974e.zip |
Merge branch 'master' into z6
Diffstat (limited to 'include')
-rw-r--r-- | include/Import/Importer.php | 81 | ||||
-rw-r--r-- | include/Import/refimport.php | 284 | ||||
-rw-r--r-- | include/account.php | 44 | ||||
-rw-r--r-- | include/api_zot.php | 24 | ||||
-rw-r--r-- | include/auth.php | 1 | ||||
-rw-r--r-- | include/bbcode.php | 48 | ||||
-rwxr-xr-x | include/dba/dba_driver.php | 4 | ||||
-rwxr-xr-x | include/dba/dba_pdo.php | 13 | ||||
-rw-r--r-- | include/features.php | 26 | ||||
-rw-r--r-- | include/feedutils.php | 277 | ||||
-rw-r--r-- | include/hubloc.php | 18 | ||||
-rw-r--r-- | include/import.php | 3 | ||||
-rwxr-xr-x | include/items.php | 13 | ||||
-rw-r--r-- | include/language.php | 35 | ||||
-rw-r--r-- | include/nav.php | 32 | ||||
-rw-r--r-- | include/network.php | 4 | ||||
-rwxr-xr-x | include/plugin.php | 60 | ||||
-rw-r--r-- | include/taxonomy.php | 22 | ||||
-rw-r--r-- | include/text.php | 40 | ||||
-rw-r--r-- | include/zid.php | 14 |
20 files changed, 452 insertions, 591 deletions
diff --git a/include/Import/Importer.php b/include/Import/Importer.php deleted file mode 100644 index 1fa677db0..000000000 --- a/include/Import/Importer.php +++ /dev/null @@ -1,81 +0,0 @@ -<?php /** @file */ - -namespace Hubzilla\Import; - -/** - * @brief Class Import - * - */ -class Import { - - private $credentials = null; - - protected $itemlist = null; - protected $src_items = null; - protected $items = null; - - function get_credentials() { - return $this->credentials; - } - - function get_itemlist() { - return $this->itemlist; - } - - function get_item_ident($item) { - - } - - function get_item($item_ident) { - - } - - function get_taxonomy($item_ident) { - - } - - function get_children($item_ident) { - - } - - function convert_item($item_ident) { - - } - - function convert_taxonomy($item_ident) { - - } - - function convert_child($child) { - - } - - function store($item, $update = false) { - - } - - function run() { - $this->credentials = $this->get_credentials(); - $this->itemlist = $this->get_itemlist(); - if($this->itemlist) { - $this->src_items = array(); - $this->items = array(); - $cnt = 0; - foreach($this->itemlist as $item) { - $ident = $item->get_item_ident($item); - $this->src_items[$ident]['item'] = $this->get_item($ident); - $this->src_items[$ident]['taxonomy'] = $this->get_taxonomy($ident); - $this->src_items[$ident]['children'] = $this->get_children($ident); - $this->items[$cnt]['item'] = $this->convert_item($ident); - $this->items[$cnt]['item']['term'] = $this->convert_taxonomy($ident); - if($this->src_items[$ident]['children']) { - $this->items[$cnt]['children'] = array(); - foreach($this->src_items[$ident]['children'] as $child) { - $this[$cnt]['children'][] = $this->convert_child($child); - } - } - $cnt ++; - } - } - } -}
\ No newline at end of file diff --git a/include/Import/refimport.php b/include/Import/refimport.php deleted file mode 100644 index 04540a9bd..000000000 --- a/include/Import/refimport.php +++ /dev/null @@ -1,284 +0,0 @@ -<?php - -require_once('include/html2bbcode.php'); - -// Sample module for importing conversation data from Reflection CMS. Some preparation was used to -// dump relevant posts, categories and comments into individual JSON files, and also JSON dump of -// the user table to search for avatars. Importation was also batched in sets of 20 posts per page -// visit so as to survive shared hosting process limits. This provides some clues as how to handle -// WordPress imports, which use a somewhat similar DB structure. The batching and individual files -// might not be needed in VPS environments. As such this could be considered an extreme test case, but -// the importation was successful in all regards using this code. The module URL was visited repeatedly -// with a browser until all the posts had been imported. - - -define('REDMATRIX_IMPORTCHANNEL','mike'); -define('REFLECT_EXPORTUSERNAME','mike'); -define('REFLECT_BLOGNAME','Diary and Other Rantings'); -define('REFLECT_BASEURL','http://example.com/'); -define('REFLECT_USERFILE','user.json'); - -// set to true if you need to process everything again -define('REFLECT_OVERWRITE',false); - -// we'll only process a small number of posts at a time on a shared host. - -define('REFLECT_MAXPERRUN',30); - -function reflect_get_channel() { - - // this will be the channel_address or nickname of the red channel - - $c = q("select * from channel left join xchan on channel_hash = xchan_hash - where channel_address = '%s' limit 1", - dbesc(REDMATRIX_IMPORTCHANNEL) - ); - return $c[0]; -} - - -function refimport_content(&$a) { - - $channel = reflect_get_channel(); - - // load the user file. We need that to find the commenter's avatars - - $u = file_get_contents(REFLECT_USERFILE); - if($u) { - $users = json_decode($u,true); - } - - $ignored = 0; - $processed = 0; - - $files = glob('article/*'); - if(! $files) - return; - - foreach($files as $f) { - $s = file_get_contents($f); - $j = json_decode($s,true); - - if(! $j) - continue; - - $arr = array(); - - // see if this article was already processed - $r = q("select * from item where mid = '%s' and uid = %d limit 1", - dbesc($j['guid']), - intval($channel['channel_id']) - ); - if($r) { - if(REFLECT_OVERWRITE) - $arr['id'] = $r[0]['id']; - else { - $ignored ++; - rename($f,str_replace('article','done',$f)); - continue; - } - } - - $arr['uid'] = $channel['channel_account_id']; - $arr['aid'] = $channel['channel_id']; - $arr['mid'] = $arr['parent_mid'] = $j['guid']; - $arr['created'] = $j['created']; - $arr['edited'] = $j['edited']; - $arr['author_xchan'] = $channel['channel_hash']; - $arr['owner_xchan'] = $channel['channel_hash']; - $arr['app'] = REFLECT_BLOGNAME; - - $arr['item_origin'] = 1; - $arr['item_wall'] = 1; - $arr['item_thread_top'] = 1; - - $arr['verb'] = ACTIVITY_POST; - - // this is an assumption - $arr['comment_policy'] = 'contacts'; - - - // import content. In this case the content is XHTML. - - $arr['title'] = html2bbcode($j['title']); - $arr['title'] = htmlspecialchars($arr['title'],ENT_COMPAT,'UTF-8',false); - - - $arr['body'] = html2bbcode($j['body']); - $arr['body'] = htmlspecialchars($arr['body'],ENT_COMPAT,'UTF-8',false); - - - // convert relative urls to other posts on that service to absolute url on our service. - $arr['body'] = preg_replace_callback("/\[url\=\/+article\/(.*?)\](.*?)\[url\]/",'reflect_article_callback',$arr['body']); - - // also import any photos - $arr['body'] = preg_replace_callback("/\[img(.*?)\](.*?)\[\/img\]/",'reflect_photo_callback',$arr['body']); - - - // add categories - - if($j['taxonomy'] && is_array($j['taxonomy']) && count($j['taxonomy'])) { - $arr['term'] = array(); - foreach($j['taxonomy'] as $tax) { - $arr['term'][] = array( - 'uid' => $channel['channel_id'], - 'type' => TERM_CATEGORY, - 'otype' => TERM_OBJ_POST, - 'term' => trim($tax['name']), - 'url' => $channel['xchan_url'] . '?f=&cat=' . urlencode(trim($tax['name'])) - ); - } - } - - // store the item - - if($arr['id']) - item_store_update($arr); - else - item_store($arr); - - // if there are any comments, process them - // $comment['registered'] is somebody with an account on the system. Others are mostly anonymous - - if($j['comments']) { - foreach($j['comments'] as $comment) { - $user = (($comment['registered']) ? reflect_find_user($users,$comment['author']) : null); - reflect_comment_store($channel,$arr,$comment,$user); - } - } - $processed ++; - - if(REFLECT_MAXPERRUN && $processed > REFLECT_MAXPERRUN) - break; - } - return 'processed: ' . $processed . EOL . 'completed: ' . $ignored . EOL; - -} - -function reflect_article_callback($matches) { - return '[zrl=' . z_root() . '/display/'. $matches[1] . ']' . $matches[2] . '[/zrl]'; -} - -function reflect_photo_callback($matches) { - - if(strpos($matches[2],'http') !== false) - return $matches[0]; - - $prefix = REFLECT_BASEURL; - $x = z_fetch_url($prefix.$matches[2],true); - - $hash = basename($matches[2]); - - if($x['success']) { - $channel = reflect_get_channel(); - require_once('include/photos.php'); - $p = photo_upload($channel,$channel, - array('data' => $x['body'], - 'resource_id' => str_replace('-','',$hash), - 'filename' => $hash . '.jpg', - 'type' => 'image/jpeg', - 'visible' => false - ) - ); - - if($p['success']) - $newlink = $p['resource_id'] . '-0.jpg'; - - - // import photo and locate the link for it. - return '[zmg]' . z_root() . '/photo/' . $newlink . '[/zmg]'; - - } - // no replacement. Leave it alone. - return $matches[0]; -} - -function reflect_find_user($users,$name) { - if($users) { - foreach($users as $x) { - if($x['name'] === $name) { - return $x; - } - } - } - - return false; - -} - -function reflect_comment_store($channel,$post,$comment,$user) { - - // if the commenter was the channel owner, use their hubzilla xchan - - if($comment['author'] === REFLECT_EXPORTUSERNAME && $comment['registered']) - $hash = $channel['xchan_hash']; - else { - // we need a unique hash for the commenter. We don't know how many may have supplied - // http://yahoo.com as their URL, so we'll use their avatar guid if they have one. - // anonymous folks may get more than one xchan_hash if they commented more than once. - - $hash = (($comment['registered'] && $user) ? $user['avatar'] : ''); - if(! $hash) - $hash = random_string() . '.unknown'; - - // create an xchan for them which will also import their profile photo - // they will have a network type 'unknown'. - - $x = array( - 'hash' => $hash, - 'guid' => $hash, - 'url' => (($comment['url']) ? $comment['url'] : z_root()), - 'photo' => (($user) ? REFLECT_BASEURL . $user['avatar'] : z_root() . '/' . get_default_profile_photo()), - 'name' => $comment['author'] - ); - xchan_store($x); - - } - - $arr = array(); - - $r = q("select * from item where mid = '%s' and uid = %d limit 1", - dbesc($comment['guid']), - intval($channel['channel_id']) - ); - if($r) { - if(REFLECT_OVERWRITE) - $arr['id'] = $r[0]['id']; - else - return; - } - - // this is a lot like storing the post except for subtle differences, like parent_mid, flags, author_xchan, - // and we don't have a comment edited field so use creation date - - $arr['uid'] = $channel['channel_account_id']; - $arr['aid'] = $channel['channel_id']; - $arr['mid'] = $comment['guid']; - $arr['parent_mid'] = $post['mid']; - $arr['created'] = $comment['created']; - $arr['edited'] = $comment['created']; - $arr['author_xchan'] = $hash; - $arr['owner_xchan'] = $channel['channel_hash']; - $arr['item_origin'] = 1; - $arr['item_wall'] = 1; - $arr['verb'] = ACTIVITY_POST; - $arr['comment_policy'] = 'contacts'; - - - $arr['title'] = html2bbcode($comment['title']); - $arr['title'] = htmlspecialchars($arr['title'],ENT_COMPAT,'UTF-8',false); - - - $arr['body'] = html2bbcode($comment['body']); - $arr['body'] = htmlspecialchars($arr['body'],ENT_COMPAT,'UTF-8',false); - $arr['body'] = preg_replace_callback("/\[url\=\/+article\/(.*?)\](.*?)\[url\]/",'reflect_article_callback',$arr['body']); - $arr['body'] = preg_replace_callback("/\[img(.*?)\](.*?)\[\/img\]/",'reflect_photo_callback',$arr['body']); - - // logger('comment: ' . print_r($arr,true)); - - if($arr['id']) - item_store_update($arr); - else - item_store($arr); - -} diff --git a/include/account.php b/include/account.php index 6c6fdece4..3ac485974 100644 --- a/include/account.php +++ b/include/account.php @@ -262,24 +262,46 @@ function create_account($arr) { function verify_email_address($arr) { - $hash = random_string(); - - $r = q("INSERT INTO register ( hash, created, uid, password, lang ) VALUES ( '%s', '%s', %d, '%s', '%s' ) ", - dbesc($hash), - dbesc(datetime_convert()), - intval($arr['account']['account_id']), - dbesc('verify'), - dbesc($arr['account']['account_language']) - ); + if(array_key_exists('resend',$arr)) { + $email = $arr['email']; + $a = q("select * from account where account_email = '%s' limit 1", + dbesc($arr['email']) + ); + if(! ($a && ($a[0]['account_flags'] & ACCOUNT_UNVERIFIED))) { + return false; + } + $account = $a[0]; + $v = q("select * from register where uid = %d and password = 'verify' limit 1", + intval($account['account_id']) + ); + if($v) { + $hash = $v[0]['hash']; + } + else { + return false; + } + } + else { + $hash = random_string(24); + + $r = q("INSERT INTO register ( hash, created, uid, password, lang ) VALUES ( '%s', '%s', %d, '%s', '%s' ) ", + dbesc($hash), + dbesc(datetime_convert()), + intval($arr['account']['account_id']), + dbesc('verify'), + dbesc($arr['account']['account_language']) + ); + $account = $arr['account']; + } - push_lang(($arr['account']['account_language']) ? $arr['account']['account_language'] : 'en'); + push_lang(($account['account_language']) ? $account['account_language'] : 'en'); $email_msg = replace_macros(get_intltext_template('register_verify_member.tpl'), [ '$sitename' => get_config('system','sitename'), '$siteurl' => z_root(), '$email' => $arr['email'], - '$uid' => $arr['account']['account_id'], + '$uid' => $account['account_id'], '$hash' => $hash, '$details' => $details ] diff --git a/include/api_zot.php b/include/api_zot.php index 54f905b4c..1d30a0845 100644 --- a/include/api_zot.php +++ b/include/api_zot.php @@ -6,6 +6,8 @@ api_register_func('api/export/basic','api_export_basic', true); api_register_func('api/red/channel/export/basic','api_export_basic', true); api_register_func('api/z/1.0/channel/export/basic','api_export_basic', true); + api_register_func('api/red/channel/list','api_channel_list', true); + api_register_func('api/z/1.0/channel/list','api_channel_list', true); api_register_func('api/red/channel/stream','api_channel_stream', true); api_register_func('api/z/1.0/channel/stream','api_channel_stream', true); api_register_func('api/red/files','api_attach_list', true); @@ -111,9 +113,31 @@ } } + function api_channel_list($type) { + if(api_user() === false) { + logger('api_channel_stream: no user'); + return false; + } + + $channel = channelx_by_n(api_user()); + if(! $channel) + return false; + $ret = []; + $r = q("select channel_address from channel where channel_account_id = %d", + intval($channel['channel_account_id']) + ); + + if($r) { + foreach($r as $rv) { + $ret[] = $rv['channel_address']; + } + } + + json_return_and_die($ret); + } function api_channel_stream($type) { diff --git a/include/auth.php b/include/auth.php index 78be32bf4..6f5e58361 100644 --- a/include/auth.php +++ b/include/auth.php @@ -261,6 +261,7 @@ else { $verify = account_verify_password($_POST['username'], $_POST['password']); if($verify && array_key_exists('reason',$verify) && $verify['reason'] === 'unvalidated') { notice( t('Email validation is incomplete. Please check your email.')); + goaway(z_root() . '/email_validation/' . bin2hex(trim(escape_tags($_POST['username'])))); } elseif($verify) { $atoken = $verify['xchan']; diff --git a/include/bbcode.php b/include/bbcode.php index de32bd57a..0c85a0a4e 100644 --- a/include/bbcode.php +++ b/include/bbcode.php @@ -108,7 +108,11 @@ function tryzrlvideo($match) { if($zrl) $link = zid($link); - return '<video controls="controls" preload="none" src="' . str_replace(' ','%20',$link) . '" style="width:100%; max-width:' . App::$videowidth . 'px"><a href="' . str_replace(' ','%20',$link) . '">' . $link . '</a></video>'; + $static_link = get_config('system','video_default_poster','images/video_poster.jpg'); + if($static_link) + $poster = 'poster="' . escape_tags($static_link) . '" ' ; + + return '<video ' . $poster . ' controls="controls" preload="none" src="' . str_replace(' ','%20',$link) . '" style="width:100%; max-width:' . App::$videowidth . 'px"><a href="' . str_replace(' ','%20',$link) . '">' . $link . '</a></video>'; } // [noparse][i]italic[/i][/noparse] turns into @@ -610,11 +614,23 @@ function bb_observer($Text) { return $Text; } +function bb_code_protect($s) { + return 'b64.^9e%.' . base64_encode($s) . '.b64.$9e%'; +} + +function bb_code_unprotect($s) { + return preg_replace_callback('|b64\.\^9e\%\.(.*?)\.b64\.\$9e\%|ism','bb_code_unprotect_sub',$s); +} + +function bb_code_unprotect_sub($match) { + return base64_decode($match[1]); +} + function bb_code($match) { if(strpos($match[0], "<br />")) - return '<code>' . trim($match[1]) . '</code>'; + return '<code>' . bb_code_protect(trim($match[1])) . '</code>'; else - return '<code class="inline-code">' . trim($match[1]) . '</code>'; + return '<code class="inline-code">' . bb_code_protect(trim($match[1])) . '</code>'; } function bb_code_options($match) { @@ -628,11 +644,11 @@ function bb_code_options($match) { } else { $style = ""; } - return '<code class="'. $class .'" style="'. $style .'">' . trim($match[2]) . '</code>'; + return '<code class="'. $class .'" style="'. $style .'">' . bb_code_protect(trim($match[2])) . '</code>'; } function bb_highlight($match) { - return text_highlight($match[2],strtolower($match[1])); + return bb_code_protect(text_highlight($match[2],strtolower($match[1]))); } function bb_fixtable_lf($match) { @@ -822,6 +838,17 @@ function bbcode($Text, $options = []) { $Text = str_replace(array("\t", " "), array(" ", " "), $Text); + + // Check for [code] text + if (strpos($Text,'[code]') !== false) { + $Text = preg_replace_callback("/\[code\](.*?)\[\/code\]/ism", 'bb_code', $Text); + } + + // Check for [code options] text + if (strpos($Text,'[code ') !== false) { + $Text = preg_replace_callback("/\[code(.*?)\](.*?)\[\/code\]/ism", 'bb_code_options', $Text); + } + // Set up the parameters for a URL search string $URLSearchString = "^\[\]"; // Set up the parameters for a MAIL search string @@ -1062,16 +1089,6 @@ function bbcode($Text, $options = []) { $Text = preg_replace("/\[font=(.*?)\](.*?)\[\/font\]/sm", "<span style=\"font-family: $1;\">$2</span>", $Text); } - // Check for [code] text - if (strpos($Text,'[code]') !== false) { - $Text = preg_replace_callback("/\[code\](.*?)\[\/code\]/ism", 'bb_code', $Text); - } - - // Check for [code options] text - if (strpos($Text,'[code ') !== false) { - $Text = preg_replace_callback("/\[code(.*?)\](.*?)\[\/code\]/ism", 'bb_code_options', $Text); - } - if(strpos($Text,'[/summary]') !== false) { $Text = preg_replace_callback("/^(.*?)\[summary\](.*?)\[\/summary\](.*?)$/ism", 'bb_summary', $Text); @@ -1288,6 +1305,7 @@ function bbcode($Text, $options = []) { // replace escaped links in code= blocks $Text = str_replace('%eY9-!','http', $Text); + $Text = bb_code_unprotect($Text); $Text = preg_replace('/\[\&\;([#a-z0-9]+)\;\]/', '&$1;', $Text); diff --git a/include/dba/dba_driver.php b/include/dba/dba_driver.php index 7e925a106..deec9adfd 100755 --- a/include/dba/dba_driver.php +++ b/include/dba/dba_driver.php @@ -321,6 +321,10 @@ function db_concat($fld, $sep) { return \DBA::$dba->concat($fld, $sep); } +function db_use_index($str) { + return \DBA::$dba->use_index($str); +} + /** * @brief Execute a SQL query with printf style args. * diff --git a/include/dba/dba_pdo.php b/include/dba/dba_pdo.php index f119d8926..a9d824a50 100755 --- a/include/dba/dba_pdo.php +++ b/include/dba/dba_pdo.php @@ -15,7 +15,7 @@ class dba_pdo extends dba_driver { $dsn = $server; } else { - $dsn = $this->driver_dbtype . ':host=' . $server . (intval($port) ? '' : ';port=' . $port); + $dsn = $this->driver_dbtype . ':host=' . $server . (intval($port) ? ';port=' . $port : ''); } $dsn .= ';dbname=' . $db; @@ -111,6 +111,15 @@ class dba_pdo extends dba_driver { } } + function use_index($str) { + if($this->driver_dbtype === 'pgsql') { + return ''; + } + else { + return 'USE INDEX( ' . $str . ')'; + } + } + function quote_interval($txt) { if($this->driver_dbtype === 'pgsql') { return "'$txt'"; @@ -154,4 +163,4 @@ class dba_pdo extends dba_driver { return 'pdo'; } -}
\ No newline at end of file +} diff --git a/include/features.php b/include/features.php index 36eb74a9d..839faff67 100644 --- a/include/features.php +++ b/include/features.php @@ -190,6 +190,16 @@ function get_features($filtered = true) { feature_level('event_tz_select',2), ], + + [ + 'premium_channel', + t('Premium Channel'), + t('Allows you to set restrictions and terms on those that connect with your channel'), + false, + get_config('feature_lock','premium_channel'), + feature_level('premium_channel',4), + ], + [ 'advanced_dirsearch', t('Advanced Directory Search'), @@ -438,16 +448,10 @@ function get_features($filtered = true) { ], ]; + $x = [ 'features' => $arr, ]; + call_hooks('get_features',$x); - $arr['general'][] = [ - 'premium_channel', - t('Premium Channel'), - t('Allows you to set restrictions and terms on those that connect with your channel'), - false, - get_config('feature_lock','premium_channel'), - feature_level('premium_channel',4), - ]; - + $arr = $x['features']; $techlevel = get_account_techlevel(); @@ -482,7 +486,5 @@ function get_features($filtered = true) { $narr = $arr; } - $x = [ 'features' => $narr, 'filtered' => $filtered, 'techlevel' => $techlevel ]; - call_hooks('get_features',$x); - return $x['features']; + return $narr; } diff --git a/include/feedutils.php b/include/feedutils.php index 5e48cb1ee..504f65092 100644 --- a/include/feedutils.php +++ b/include/feedutils.php @@ -15,15 +15,6 @@ */ function get_public_feed($channel, $params) { -/* $type = 'xml'; - $begin = NULL_DATE; - $end = ''; - $start = 0; - $records = 40; - $direction = 'desc'; - $pages = 0; -*/ - if(! $params) $params = []; @@ -106,23 +97,15 @@ function get_feed_for($channel, $observer_hash, $params) { $owner = atom_render_author('zot:owner',$channel); $atom .= replace_macros($feed_template, array( - '$version' => xmlify(Zotlabs\Lib\System::get_project_version()), - '$red' => xmlify(Zotlabs\Lib\System::get_platform_name()), - '$feed_id' => xmlify($channel['xchan_url']), - '$feed_title' => xmlify($channel['channel_name']), - '$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', 'now', ATOM_TIME)), - '$author' => $feed_author, - '$owner' => $owner, - '$name' => xmlify($channel['channel_name']), - '$profile_page' => xmlify($channel['xchan_url']), - '$mimephoto' => xmlify($channel['xchan_photo_mimetype']), - '$photo' => xmlify($channel['xchan_photo_l']), - '$thumb' => xmlify($channel['xchan_photo_m']), - '$picdate' => '', - '$uridate' => '', - '$namdate' => '', - '$birthday' => '', - '$community' => '', + '$version' => xmlify(Zotlabs\Lib\System::get_project_version()), + '$generator' => xmlify(Zotlabs\Lib\System::get_platform_name()), + '$generator_uri' => 'https://hubzilla.org', + '$feed_id' => xmlify($channel['xchan_url']), + '$feed_title' => xmlify($channel['channel_name']), + '$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', 'now', ATOM_TIME)), + '$author' => $feed_author, + '$owner' => $owner, + '$profile_page' => xmlify($channel['xchan_url']), )); @@ -270,19 +253,18 @@ function construct_activity_target($item) { return ''; } + /** - * @brief Return an array with a parsed atom item. + * @brief Return an array with a parsed atom author. * * @param SimplePie $feed - * @param array $item - * @param[out] array $author - * @return array Associative array with the parsed item data + * @param SimplePie $item + * @return array $author */ -function get_atom_elements($feed, $item, &$author) { - require_once('include/html2bbcode.php'); +function get_atom_author($feed, $item) { - $res = array(); + $author = []; $found_author = $item->get_author(); if($found_author) { @@ -307,52 +289,6 @@ function get_atom_elements($feed, $item, &$author) { if(substr($author['author_link'],-1,1) == '/') $author['author_link'] = substr($author['author_link'],0,-1); - $res['mid'] = normalise_id(unxmlify($item->get_id())); - $res['title'] = unxmlify($item->get_title()); - $res['body'] = unxmlify($item->get_content()); - $res['plink'] = unxmlify($item->get_link(0)); - $res['item_rss'] = 1; - - - $summary = unxmlify($item->get_description(true)); - - // removing the content of the title if its identically to the body - // This helps with auto generated titles e.g. from tumblr - - if (title_is_body($res['title'], $res['body'])) - $res['title'] = ""; - - if($res['plink']) - $base_url = implode('/', array_slice(explode('/',$res['plink']),0,3)); - else - $base_url = ''; - - - $rawcreated = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published'); - if($rawcreated) - $res['created'] = unxmlify($rawcreated[0]['data']); - - $rawedited = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'); - if($rawedited) - $res['edited'] = unxmlify($rawedited[0]['data']); - - if((x($res,'edited')) && (! (x($res,'created')))) - $res['created'] = $res['edited']; - - if(! $res['created']) - $res['created'] = $item->get_date('c'); - - if(! $res['edited']) - $res['edited'] = $item->get_date('c'); - - $rawverb = $item->get_item_tags(NAMESPACE_ACTIVITY, 'verb'); - - // select between supported verbs - - if($rawverb) { - $res['verb'] = unxmlify($rawverb[0]['data']); - } - // look for a photo. We should check media size and find the best one, // but for now let's just find any author photo @@ -431,6 +367,112 @@ function get_atom_elements($feed, $item, &$author) { } } + $rawowner = $item->get_item_tags(NAMESPACE_DFRN, 'owner'); + if(! $rawowner) + $rawowner = $item->get_item_tags(NAMESPACE_ZOT, 'owner'); + + if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']) + $author['owner_name'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']); + elseif($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data']) + $author['owner_name'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data']); + if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']) + $author['owner_link'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']); + elseif($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data']) + $author['owner_link'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data']); + + if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) { + $base = $rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']; + + foreach($base as $link) { + if(!x($author, 'owner_photo') || ! $author['owner_photo']) { + if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar') + $author['owner_photo'] = unxmlify($link['attribs']['']['href']); + } + } + } + + // build array to pass to hook + $arr = [ + 'feed' => $feed, + 'item' => $item, + 'author' => $author + ]; + /** + * @hooks parse_atom + * * \e SimplePie \b feed - The original SimplePie feed + * * \e SimplePie \b item + * * \e array \b result - the result array that will also get returned + */ + call_hooks('parse_atom_author', $arr); + + logger('author: ' . print_r($arr['author'], true), LOGGER_DATA); + + return $arr['author']; +} + + +/** + * @brief Return an array with a parsed atom item. + * + * @param SimplePie $feed + * @param SimplePie $item + * @param[out] array $author + * @return array Associative array with the parsed item data + */ + +function get_atom_elements($feed, $item) { + + require_once('include/html2bbcode.php'); + + $res = array(); + + + $res['mid'] = normalise_id(unxmlify($item->get_id())); + $res['title'] = unxmlify($item->get_title()); + $res['body'] = unxmlify($item->get_content()); + $res['plink'] = unxmlify($item->get_link(0)); + $res['item_rss'] = 1; + + + $summary = unxmlify($item->get_description(true)); + + // removing the content of the title if its identically to the body + // This helps with auto generated titles e.g. from tumblr + + if (title_is_body($res['title'], $res['body'])) + $res['title'] = ""; + + if($res['plink']) + $base_url = implode('/', array_slice(explode('/',$res['plink']),0,3)); + else + $base_url = ''; + + + $rawcreated = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published'); + if($rawcreated) + $res['created'] = unxmlify($rawcreated[0]['data']); + + $rawedited = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'); + if($rawedited) + $res['edited'] = unxmlify($rawedited[0]['data']); + + if((x($res,'edited')) && (! (x($res,'created')))) + $res['created'] = $res['edited']; + + if(! $res['created']) + $res['created'] = $item->get_date('c'); + + if(! $res['edited']) + $res['edited'] = $item->get_date('c'); + + $rawverb = $item->get_item_tags(NAMESPACE_ACTIVITY, 'verb'); + + // select between supported verbs + + if($rawverb) { + $res['verb'] = unxmlify($rawverb[0]['data']); + } + $rawcnv = $item->get_item_tags(NAMESPACE_OSTATUS, 'conversation'); if($rawcnv) { // new style @@ -588,29 +630,6 @@ function get_atom_elements($feed, $item, &$author) { $res['created'] = datetime_convert('UTC','UTC',$res['created']); $res['edited'] = datetime_convert('UTC','UTC',$res['edited']); - $rawowner = $item->get_item_tags(NAMESPACE_DFRN, 'owner'); - if(! $rawowner) - $rawowner = $item->get_item_tags(NAMESPACE_ZOT, 'owner'); - - if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']) - $author['owner_name'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']); - elseif($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data']) - $author['owner_name'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data']); - if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']) - $author['owner_link'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']); - elseif($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data']) - $author['owner_link'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data']); - - if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) { - $base = $rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']; - - foreach($base as $link) { - if(!x($author, 'owner_photo') || ! $author['owner_photo']) { - if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar') - $author['owner_photo'] = unxmlify($link['attribs']['']['href']); - } - } - } $rawgeo = $item->get_item_tags(NAMESPACE_GEORSS, 'point'); if($rawgeo) @@ -773,19 +792,16 @@ function get_atom_elements($feed, $item, &$author) { $arr = [ 'feed' => $feed, 'item' => $item, - 'author' => $author, 'result' => $res ]; /** * @hooks parse_atom * * \e SimplePie \b feed - The original SimplePie feed - * * \e array \b item - * * \e array \b author + * * \e SimplePie \b item * * \e array \b result - the result array that will also get returned */ call_hooks('parse_atom', $arr); - logger('author: ' .print_r($arr['author'], true), LOGGER_DATA); logger('result: ' .print_r($arr['result'], true), LOGGER_DATA); return $arr['result']; @@ -1074,8 +1090,8 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { // Have we seen it? If not, import it. - $author = array(); - $datarray = get_atom_elements($feed,$item,$author); + $author = get_atom_author($feed,$item); + $datarray = get_atom_elements($feed,$item); if(! $datarray['mid']) continue; @@ -1327,8 +1343,8 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { // Head post of a conversation. Have we seen it? If not, import it. - $author = array(); - $datarray = get_atom_elements($feed,$item,$author); + $author = get_atom_author($feed,$item); + $datarray = get_atom_elements($feed,$item); if(! $datarray['mid']) continue; @@ -1530,11 +1546,11 @@ function normalise_id($id) { */ function process_salmon_feed($xml, $importer) { - $ret = array(); + $ret = []; if(! strlen($xml)) { logger('process_feed: empty input'); - return; + return $ret; } $feed = new SimplePie(); @@ -1548,8 +1564,10 @@ function process_salmon_feed($xml, $importer) { $feed->init(); - if($feed->error()) + if($feed->error()) { logger('Error parsing XML: ' . $feed->error()); + return $ret; + } $permalink = $feed->get_permalink(); @@ -1576,16 +1594,13 @@ function process_salmon_feed($xml, $importer) { if($is_reply) $ret['parent_mid'] = $parent_mid; - $ret['author'] = array(); - - $datarray = get_atom_elements($feed, $item, $ret['author']); + $ret['author'] = get_atom_author($feed,$item); + $ret['item'] = get_atom_elements($feed,$item); // reset policies which are restricted by default for RSS connections // This item is likely coming from GNU-social via salmon and allows public interaction - $datarray['public_policy'] = ''; - $datarray['comment_policy'] = 'authenticated'; - - $ret['item'] = $datarray; + $ret['item']['public_policy'] = ''; + $ret['item']['comment_policy'] = 'authenticated'; } } @@ -1843,10 +1858,24 @@ function atom_entry($item, $type, $author, $owner, $comment = false, $cid = 0, $ create_export_photo_body($item); - if($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid']) - $body = fix_private_photos($item['body'],$owner['uid'],$item,$cid); + // provide separate summary and content unless compat is true; as summary represents a content-warning on some networks + + $matches = false; + if(preg_match('|\[summary\](.*?)\[/summary\]|ism',$item['body'],$matches)) + $summary = $matches[1]; else - $body = $item['body']; + $summary = ''; + + $body = $item['body']; + + if($summary) + $body = preg_replace('|^(.*?)\[summary\](.*?)\[/summary\](.*?)$|ism','$1$3',$item['body']); + + if($compat) + $summary = ''; + + if($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid']) + $body = fix_private_photos($body,$owner['uid'],$item,$cid); if($compat) { $compat_photos = compat_photos_list($body); @@ -1887,6 +1916,8 @@ function atom_entry($item, $type, $author, $owner, $comment = false, $cid = 0, $ } else { $o .= '<title>' . xmlify($item['title']) . '</title>' . "\r\n"; + if($summary) + $o .= '<summary type="' . $type . '" >' . xmlify(prepare_text($summary,$item['mimetype'])) . '</summary>' . "\r\n"; $o .= '<content type="' . $type . '" >' . xmlify(prepare_text($body,$item['mimetype'])) . '</content>' . "\r\n"; } diff --git a/include/hubloc.php b/include/hubloc.php index 0daa5908c..0d1a2e560 100644 --- a/include/hubloc.php +++ b/include/hubloc.php @@ -257,6 +257,24 @@ function hubloc_mark_as_down($posturl) { } +/** + * @brief return comma separated string of non-dead clone locations (net addresses) for a given netid + * + * @param string $netid network identity (typically xchan_hash or hubloc_hash) + * @return string + */ + +function locations_by_netid($netid) { + + $locs = q("select hubloc_addr as location from hubloc left join site on hubloc_url = site_url where hubloc_hash = '%s' and hubloc_deleted = 0 and site_dead = 0", + dbesc($netid) + ); + + return array_elm_to_str($locs,'location',', '); + +} + + function ping_site($url) { diff --git a/include/import.php b/include/import.php index 51791347a..9920df8be 100644 --- a/include/import.php +++ b/include/import.php @@ -82,7 +82,8 @@ function import_channel($channel, $account_id, $seize) { 'channel_r_storage', 'channel_r_pages', 'channel_w_stream', 'channel_w_wall', 'channel_w_comment', 'channel_w_mail', 'channel_w_like', 'channel_w_tagwall', 'channel_w_chat', 'channel_w_storage', 'channel_w_pages', 'channel_a_republish', - 'channel_a_delegate', 'perm_limits', 'channel_password', 'channel_salt' + 'channel_a_delegate', 'perm_limits', 'channel_password', 'channel_salt', + 'channel_moved' ]; $clean = array(); diff --git a/include/items.php b/include/items.php index d0b9cffc9..c7206458e 100755 --- a/include/items.php +++ b/include/items.php @@ -390,7 +390,7 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) { $arr['comment_policy'] = map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'post_comments')); if ((! $arr['plink']) && (intval($arr['item_thread_top']))) { - $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . urlencode($arr['mid']); + $arr['plink'] = substr(z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . urlencode($arr['mid']),0,190); } @@ -3009,14 +3009,17 @@ function check_item_source($uid, $item) { $words = explode("\n",$r[0]['src_patt']); if($words) { foreach($words as $word) { - if(substr($word,0,1) === '#' && $tags) { + $w = trim($word); + if(! $w) + continue; + if(substr($w,0,1) === '#' && $tags) { foreach($tags as $t) - if((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*'))) + if((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($w,1)) || (substr($w,1) === '*'))) return true; } - elseif((strpos($word,'/') === 0) && preg_match($word,$text)) + elseif((strpos($w,'/') === 0) && preg_match($w,$text)) return true; - elseif(stristr($text,$word) !== false) + elseif(stristr($text,$w) !== false) return true; } } diff --git a/include/language.php b/include/language.php index f6f266685..d0ecd3a85 100644 --- a/include/language.php +++ b/include/language.php @@ -73,8 +73,35 @@ function get_best_language() { } } - if(! isset($preferred)) + + if(! isset($preferred)) { + + /* + * We could find no perfect match for any of the preferred languages. + * For cases where the preference is fr-fr and we have fr but *not* fr-fr + * run the test again and only look for the language base + * which should provide an interface they can sort of understand + */ + + if(isset($langs) && count($langs)) { + foreach ($langs as $lang => $v) { + if(strlen($lang) === 2) { + /* we have already checked this language */ + continue; + } + /* Check the base */ + $lang = strtolower(substr($lang,0,2)); + if(is_dir("view/$lang")) { + $preferred = $lang; + break; + } + } + } + } + + if(! isset($preferred)) { $preferred = 'unset'; + } $arr = array('langs' => $langs, 'preferred' => $preferred); @@ -86,6 +113,12 @@ function get_best_language() { return ((isset(App::$config['system']['language'])) ? App::$config['system']['language'] : 'en'); } +/* + * push_lang and pop_lang let you temporarily override the default language. + * Often used to email the administrator during a session created in another language. + * The stack is one level deep - so you must pop after every push. + */ + function push_lang($language) { diff --git a/include/nav.php b/include/nav.php index 8566cc58c..9c88541d1 100644 --- a/include/nav.php +++ b/include/nav.php @@ -100,38 +100,6 @@ EOT; if(local_channel()) { - - - $nav['network'] = array('network', t('Activity'), "", t('Network Activity'),'network_nav_btn'); - $nav['network']['all'] = [ 'network', t('View your network activity'), '','' ]; - $nav['network']['mark'] = array('', t('Mark all activity notifications seen'), '',''); - - $nav['home'] = array('channel/' . $channel['channel_address'], t('Channel Home'), "", t('Channel home'),'home_nav_btn'); - $nav['home']['all'] = [ 'channel/' . $channel['channel_address'], t('View your channel home'), '' , '' ]; - $nav['home']['mark'] = array('', t('Mark all channel notifications seen'), '',''); - - - $nav['intros'] = array('connections/ifpending', t('Connections'), "", t('Connections'),'connections_nav_btn'); - if(is_site_admin()) - $nav['registrations'] = array('admin/accounts', t('Registrations'), "", t('Registrations'),'registrations_nav_btn'); - - - $nav['notifications'] = array('notifications/system', t('Notices'), "", t('Notifications'),'notifications_nav_btn'); - $nav['notifications']['all']=array('notifications/system', t('View all notifications'), "", ""); - $nav['notifications']['mark'] = array('', t('Mark all system notifications seen'), '',''); - - $nav['messages'] = array('mail/combined', t('Mail'), "", t('Private mail'),'mail_nav_btn'); - $nav['messages']['all']=array('mail/combined', t('View your private messages'), "", ""); - $nav['messages']['mark'] = array('', t('Mark all private messages seen'), '',''); - $nav['messages']['inbox'] = array('mail/inbox', t('Inbox'), "", t('Inbox')); - $nav['messages']['outbox']= array('mail/outbox', t('Outbox'), "", t('Outbox')); - $nav['messages']['new'] = array('mail/new', t('New Message'), "", t('New Message')); - - - $nav['all_events'] = array('events', t('Events'), "", t('Event Calendar'),'events_nav_btn'); - $nav['all_events']['all']=array('events', t('View events'), "", ""); - $nav['all_events']['mark'] = array('', t('Mark all events seen'), '',''); - if(! $_SESSION['delegate']) { $nav['manage'] = array('manage', t('Channel Manager'), "", t('Manage Your Channels'),'manage_nav_btn'); } diff --git a/include/network.php b/include/network.php index 79a8c6578..2ac430e82 100644 --- a/include/network.php +++ b/include/network.php @@ -1579,6 +1579,7 @@ function get_site_info() { $channels_active_halfyear_stat = intval(get_config('system','channels_active_halfyear_stat')); $channels_active_monthly_stat = intval(get_config('system','channels_active_monthly_stat')); $local_posts_stat = intval(get_config('system','local_posts_stat')); + $local_comments_stat = intval(get_config('system','local_comments_stat')); $hide_in_statistics = intval(get_config('system','hide_in_statistics')); $site_expire = intval(get_config('system', 'default_expire_days')); @@ -1612,13 +1613,14 @@ function get_site_info() { 'default_service_restrictions' => $service_class, 'locked_features' => $locked_features, 'admin' => $admin, - 'dbdriver' => DBA::$dba->getdriver(), + 'dbdriver' => DBA::$dba->getdriver() . ' ' . ((ACTIVE_DBTYPE == DBTYPE_POSTGRES) ? 'postgres' : 'mysql'), 'lastpoll' => get_config('system','lastpoll'), 'info' => (($site_info) ? $site_info : ''), 'channels_total' => $channels_total_stat, 'channels_active_halfyear' => $channels_active_halfyear_stat, 'channels_active_monthly' => $channels_active_monthly_stat, 'local_posts' => $local_posts_stat, + 'local_comments' => $local_comments_stat, 'hide_in_statistics' => $hide_in_statistics ]; diff --git a/include/plugin.php b/include/plugin.php index 67157dee7..f452d8342 100755 --- a/include/plugin.php +++ b/include/plugin.php @@ -179,6 +179,66 @@ function reload_plugins() { } +function plugins_installed_list() { + + $r = q("select * from addon where installed = 1 order by aname asc"); + return(($r) ? ids_to_array($r,'aname') : []); +} + + +function plugins_sync() { + + /** + * + * Synchronise plugins: + * + * App::$config['system']['addon'] contains a comma-separated list of names + * of plugins/addons which are used on this system. + * Go through the database list of already installed addons, and if we have + * an entry, but it isn't in the config list, call the unload procedure + * and mark it uninstalled in the database (for now we'll remove it). + * Then go through the config list and if we have a plugin that isn't installed, + * call the install procedure and add it to the database. + * + */ + + $installed = plugins_installed_list(); + + $plugins = get_config('system', 'addon', ''); + + $plugins_arr = explode(',', $plugins); + + // array_trim is in include/text.php + + if(! array_walk($plugins_arr,'array_trim')) + return; + + App::$plugins = $plugins_arr; + + $installed_arr = []; + + if(count($installed)) { + foreach($installed as $i) { + if(! in_array($i, $plugins_arr)) { + unload_plugin($i); + } + else { + $installed_arr[] = $i; + } + } + } + + if(count($plugins_arr)) { + foreach($plugins_arr as $p) { + if(! in_array($p, $installed_arr)) { + load_plugin($p); + } + } + } + +} + + /** * @brief Get a list of non hidden addons. * diff --git a/include/taxonomy.php b/include/taxonomy.php index 278925391..393b8718e 100644 --- a/include/taxonomy.php +++ b/include/taxonomy.php @@ -313,39 +313,25 @@ function dir_tagadelic($count = 0, $hub = '') { $count = intval($count); - $dirmode = get_config('system','directory_mode'); - - if(($dirmode == DIRECTORY_MODE_STANDALONE) && (! $hub)) { - $hub = \App::get_hostname(); - } - - if($hub) - $hub_query = " and xtag_hash in (select hubloc_hash from hubloc where hubloc_host = '" . protect_sprintf(dbesc($hub)) . "') "; - else - $hub_query = ''; - - if($hub_query) { - // Fetch tags + if($hub) { $r = q("select xtag_term as term, count(xtag_term) as total from xtag left join hubloc on xtag_hash = hubloc_hash - where xtag_flags = 0 $hub_query + where xtag_flags = 0 and xtag_hash in (select hubloc_hash from hubloc where hubloc_host = '%s' ) group by xtag_term order by total desc %s", + dbesc($hub), ((intval($count)) ? "limit $count" : '') ); } else { - // Fetch tags $r = q("select xtag_term as term, count(xtag_term) as total from xtag where xtag_flags = 0 group by xtag_term order by total desc %s", ((intval($count)) ? "limit $count" : '') ); } if(! $r) - return array(); - + return []; return Zotlabs\Text\Tagadelic::calc($r); - } diff --git a/include/text.php b/include/text.php index 956f42f7d..35a367d43 100644 --- a/include/text.php +++ b/include/text.php @@ -973,7 +973,14 @@ function contact_block() { $contacts = t('Connections'); $micropro = Array(); foreach($r as $rr) { - $rr['archived'] = (intval($rr['abook_archived']) ? true : false); + + // There is no setting to discover if you are bi-directionally connected + // Use the ability to post comments as an indication that this relationship is more + // than wishful thinking; even though soapbox channels and feeds will disable it. + + if(! intval(get_abconfig(App::$profile['uid'],$rr['xchan_hash'],'their_perms','post_comments'))) { + $rr['archived'] = true; + } $micropro[] = micropro($rr,true,'mpfriend'); } } @@ -2153,6 +2160,35 @@ function ids_to_querystr($arr,$idx = 'id',$quote = false) { } /** + * @brief array_elm_to_str($arr,$elm,$delim = ',') extract unique individual elements from an array of arrays and return them as a string separated by a delimiter + * similar to ids_to_querystr, but allows a different delimiter instead of a db-quote option + * empty elements (evaluated after trim()) are ignored. + * @param $arr array + * @param $elm array key to extract from sub-array + * @param $delim string default ',' + * @returns string + */ + +function array_elm_to_str($arr,$elm,$delim = ',') { + + $tmp = []; + if($arr && is_array($arr)) { + foreach($arr as $x) { + if(is_array($x) && array_key_exists($elm,$x)) { + $z = trim($x[$elm]); + if(($z) && (! in_array($z,$tmp))) { + $tmp[] = $z; + } + } + } + } + return implode($delim,$tmp); +} + + + + +/** * @brief Fetches xchan and hubloc data for an array of items with only an * author_xchan and owner_xchan. * @@ -3254,3 +3290,5 @@ function purify_filename($s) { return ''; return $s; } + + diff --git a/include/zid.php b/include/zid.php index 6ebc9a6ab..b3a7d1e6a 100644 --- a/include/zid.php +++ b/include/zid.php @@ -127,8 +127,11 @@ function clean_query_string($s = '') { * @return string */ function zidify_callback($match) { - $is_zid = ((feature_enabled(local_channel(), 'sendzid')) || (strpos($match[1], 'zrl')) ? true : false); - $replace = '<a' . $match[1] . ' href="' . (($is_zid) ? zid($match[2]) : $match[2]) . '"'; + + $arr = [ 'zid' => ((strpos($match[1],'zrl')) ? true : false), 'url' => $match[2] ]; + call_hooks('zidify', $arr); + + $replace = '<a' . $match[1] . ' href="' . (intval($arr['zid']) ? zid($arr['url']) : $arr['url']) . '"'; $x = str_replace($match[0], $replace, $match[0]); @@ -136,8 +139,11 @@ function zidify_callback($match) { } function zidify_img_callback($match) { - $is_zid = ((feature_enabled(local_channel(), 'sendzid')) || (strpos($match[1], 'zrl')) ? true : false); - $replace = '<img' . $match[1] . ' src="' . (($is_zid) ? zid($match[2]) : $match[2]) . '"'; + + $arr = [ 'zid' => ((strpos($match[1],'zrl')) ? true : false), 'url' => $match[2] ]; + call_hooks('zidify', $arr); + + $replace = '<img' . $match[1] . ' src="' . (intval($arr['zid']) ? zid($arr['url']) : $arr['url']) . '"'; $x = str_replace($match[0], $replace, $match[0]); |