aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/api_zot.php136
-rw-r--r--include/attach.php6
-rw-r--r--include/bb2diaspora.php18
-rw-r--r--include/bbcode.php133
-rw-r--r--include/channel.php2
-rw-r--r--include/config.php24
-rw-r--r--include/connections.php270
-rw-r--r--include/conversation.php261
-rw-r--r--include/crypto.php117
-rwxr-xr-xinclude/dba/dba_driver.php4
-rwxr-xr-xinclude/dba/dba_pdo.php2
-rw-r--r--include/dir_fns.php10
-rw-r--r--include/event.php77
-rw-r--r--include/features.php9
-rw-r--r--include/feedutils.php122
-rw-r--r--include/help.php9
-rw-r--r--include/html2plain.php2
-rw-r--r--include/hubloc.php8
-rw-r--r--include/import.php4
-rwxr-xr-xinclude/items.php78
-rw-r--r--include/menu.php2
-rw-r--r--include/message.php80
-rw-r--r--include/nav.php20
-rw-r--r--include/network.php10
-rwxr-xr-xinclude/oembed.php17
-rw-r--r--include/queue_fn.php2
-rw-r--r--include/taxonomy.php2
-rw-r--r--include/text.php75
-rw-r--r--include/widgets.php122
-rw-r--r--include/wiki.php181
-rw-r--r--include/zot.php360
31 files changed, 1541 insertions, 622 deletions
diff --git a/include/api_zot.php b/include/api_zot.php
index 60cb288af..0881211d0 100644
--- a/include/api_zot.php
+++ b/include/api_zot.php
@@ -1,6 +1,8 @@
<?php
function zot_api_init() {
+ api_register_func('api/red/version','api_zot_version',false);
+ api_register_func('api/z/1.0/version','api_zot_version',false);
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);
@@ -28,11 +30,12 @@
api_register_func('api/z/1.0/group','api_group', true);
api_register_func('api/red/xchan','api_red_xchan',true);
api_register_func('api/z/1.0/xchan','api_red_xchan',true);
- api_register_func('api/red/item/new','red_item_new', true);
- api_register_func('api/z/1.0/item/new','red_item_new', true);
+ api_register_func('api/red/item/update','zot_item_update', true);
+ api_register_func('api/z/1.0/item/update','zot_item_update', true);
api_register_func('api/red/item/full','red_item', true);
api_register_func('api/z/1.0/item/full','red_item', true);
+ api_register_func('api/z/1.0/network/stream','api_network_stream', true);
api_register_func('api/z/1.0/abook','api_zot_abook_xchan',true);
api_register_func('api/z/1.0/abconfig','api_zot_abconfig',true);
api_register_func('api/z/1.0/perm_allowed','api_zot_perm_allowed',true);
@@ -41,6 +44,22 @@
}
+ function api_zot_version($type) {
+
+ if($type === 'xml') {
+ header('Content-type: application/xml');
+ echo '<?xml version="1.0" encoding="UTF-8"?>' . "\r\n" . '<version>' . Zotlabs\Lib\System::get_project_version() . '</version>' . "\r\n";
+ killme();
+ }
+ elseif($type === 'json') {
+ header('Content-type: application/json');
+ echo '"' . Zotlabs\Lib\System::get_project_version() . '"';
+ killme();
+ }
+ }
+
+
+
/*
* Red basic channel export
*/
@@ -55,29 +74,90 @@
}
+ function api_network_stream($type) {
+ if(api_user() === false) {
+ logger('api_channel_stream: no user');
+ return false;
+ }
+
+ $channel = channelx_by_n(api_user());
+ if(! $channel)
+ return false;
+
+
+ if($_SERVER['REQUEST_METHOD'] == 'POST') {
+ // json_return_and_die(post_activity_item($_REQUEST));
+ }
+ else {
+ $mindate = (($_REQUEST['mindate']) ? datetime_convert('UTC','UTC',$_REQUEST['mindate']) : '');
+ if(! $mindate)
+ $mindate = datetime_convert('UTC','UTC', 'now - 14 days');
+
+ $arr = $_REQUEST;
+ $ret = [];
+ $i = items_fetch($arr,App::get_channel(),get_observer_hash());
+ if($i) {
+ foreach($i as $iv) {
+ $ret[] = encode_item($iv);
+ }
+ }
+
+ json_return_and_die($ret);
+ }
+ }
+
+
+
+
+
+
function api_channel_stream($type) {
if(api_user() === false) {
logger('api_channel_stream: no user');
return false;
}
+ $channel = channelx_by_n(api_user());
+ if(! $channel)
+ return false;
+
+
if($_SERVER['REQUEST_METHOD'] == 'POST') {
json_return_and_die(post_activity_item($_REQUEST));
}
else {
- // fetch stream
+ $mindate = (($_REQUEST['mindate']) ? datetime_convert('UTC','UTC',$_REQUEST['mindate']) : '');
+ if(! $mindate)
+ $mindate = datetime_convert('UTC','UTC', 'now - 14 days');
+ json_return_and_die(zot_feed($channel['channel_id'],$channel['channel_hash'],[ 'mindate' => $mindate ]));
}
}
function api_attach_list($type) {
+ if(api_user() === false)
+ return false;
+
logger('api_user: ' . api_user());
- json_return_and_die(attach_list_files(api_user(),get_observer_hash(),'','','','created asc'));
+ $hash = ((array_key_exists('filehash',$_REQUEST)) ? $_REQUEST['filehash'] : '');
+ $filename = ((array_key_exists('filename',$_REQUEST)) ? $_REQUEST['filename'] : '');
+ $filetype = ((array_key_exists('filetype',$_REQUEST)) ? $_REQUEST['filetype'] : '');
+ $start = ((array_key_exists('start',$_REQUEST)) ? intval($_REQUEST['start']) : 0);
+ $records = ((array_key_exists('records',$_REQUEST)) ? intval($_REQUEST['records']) : 0);
+
+ $x = attach_list_files(api_user(),get_observer_hash(),$hash,$filename,$filetype,'created asc',$start,$records);
+ if($start || $records) {
+ $x['start'] = $start;
+ $x['records'] = count($x['results']);
+ }
+
+ json_return_and_die($x);
}
function api_file_meta($type) {
- if (api_user()===false) return false;
+ if(api_user() === false)
+ return false;
if(! $_REQUEST['file_id']) return false;
$r = q("select * from attach where uid = %d and hash = '%s' limit 1",
intval(api_user()),
@@ -94,14 +174,15 @@
function api_file_data($type) {
- if (api_user()===false) return false;
+ if(api_user() === false)
+ return false;
if(! $_REQUEST['file_id']) return false;
$start = (($_REQUEST['start']) ? intval($_REQUEST['start']) : 0);
$length = (($_REQUEST['length']) ? intval($_REQUEST['length']) : 0);
- $r = q("select * from attach where uid = %d and hash = '%s' limit 1",
+ $r = q("select * from attach where uid = %d and hash like '%s' limit 1",
intval(api_user()),
- dbesc($_REQUEST['file_id'])
+ dbesc($_REQUEST['file_id'] . '%')
);
if($r) {
$ptr = $r[0];
@@ -135,8 +216,10 @@
function api_file_export($type) {
- if (api_user()===false) return false;
- if(! $_REQUEST['file_id']) return false;
+ if(api_user() === false)
+ return false;
+ if(! $_REQUEST['file_id'])
+ return false;
$ret = attach_export_data(api_user(),$_REQUEST['file_id']);
if($ret) {
@@ -147,7 +230,8 @@
function api_file_detail($type) {
- if (api_user()===false) return false;
+ if(api_user() === false)
+ return false;
if(! $_REQUEST['file_id']) return false;
$r = q("select * from attach where uid = %d and hash = '%s' limit 1",
intval(api_user()),
@@ -170,16 +254,21 @@
function api_albums($type) {
+ if(api_user() === false)
+ return false;
json_return_and_die(photos_albums_list(App::get_channel(),App::get_observer()));
}
function api_photos($type) {
+ if(api_user() === false)
+ return false;
$album = $_REQUEST['album'];
json_return_and_die(photos_list_photos(App::get_channel(),App::get_observer(),$album));
}
function api_photo_detail($type) {
- if (api_user()===false) return false;
+ if(api_user() === false)
+ return false;
if(! $_REQUEST['photo_id']) return false;
$scale = ((array_key_exists('scale',$_REQUEST)) ? intval($_REQUEST['scale']) : 0);
$r = q("select * from photo where uid = %d and resource_id = '%s' and imgscale = %d limit 1",
@@ -237,8 +326,8 @@
}
if($r) {
- $x = q("select * from group_member left join xchan on group_member.xchan = xchan.xchan_hash
- left join abook on abook_xchan = xchan_hash where gid = %d",
+ $x = q("select * from group_member left join abook on abook_xchan = xchan and abook_channel = group_member.uid left join xchan on group_member.xchan = xchan.xchan_hash
+ where gid = %d",
intval($r[0]['id'])
);
json_return_and_die($x);
@@ -258,14 +347,12 @@
function api_red_xchan($type) {
- logger('api_xchan');
-
if(api_user() === false)
return false;
logger('api_xchan');
require_once('include/hubloc.php');
- if($_SERVER['REQUEST_METHOD'] === 'POST') {
+ if($_SERVER['REQUEST_METHOD'] === 'POST') {
$r = xchan_store($_REQUEST);
}
$r = xchan_fetch($_REQUEST);
@@ -341,15 +428,15 @@
}
- function red_item_new($type) {
+ function zot_item_update($type) {
if (api_user() === false) {
- logger('api_red_item_new: no user');
+ logger('api_red_item_store: no user');
return false;
}
- logger('api_red_item_new: REQUEST ' . print_r($_REQUEST,true));
- logger('api_red_item_new: FILES ' . print_r($_FILES,true));
+ logger('api_red_item_store: REQUEST ' . print_r($_REQUEST,true));
+ logger('api_red_item_store: FILES ' . print_r($_FILES,true));
// set this so that the item_post() function is quiet and doesn't redirect or emit json
@@ -360,11 +447,10 @@
if(x($_FILES,'media')) {
$_FILES['userfile'] = $_FILES['media'];
// upload the image if we have one
- $_REQUEST['silent']='1'; //tell wall_upload function to return img info instead of echo
- $mod = new Zotlabs\Module\Wall_upload();
+ $mod = new Zotlabs\Module\Wall_attach();
$media = $mod->post();
- if(strlen($media)>0)
- $_REQUEST['body'] .= "\n\n".$media;
+ if($media)
+ $_REQUEST['body'] .= "\n\n" . $media;
}
$mod = new Zotlabs\Module\Item();
diff --git a/include/attach.php b/include/attach.php
index ac0185f5d..ba2f60a90 100644
--- a/include/attach.php
+++ b/include/attach.php
@@ -197,13 +197,13 @@ function attach_list_files($channel_id, $observer, $hash = '', $filename = '', $
$sql_extra .= protect_sprintf(" and hash = '" . dbesc($hash) . "' ");
if($filename)
- $sql_extra .= protect_sprintf(" and filename like '@" . dbesc($filename) . "@' ");
+ $sql_extra .= protect_sprintf(" and filename like '%" . dbesc($filename) . "%' ");
if($filetype)
- $sql_extra .= protect_sprintf(" and filetype like '@" . dbesc($filetype) . "@' ");
+ $sql_extra .= protect_sprintf(" and filetype like '%" . dbesc($filetype) . "%' ");
if($entries)
- $limit = " limit " . intval($start) . ", " . intval(entries) . " ";
+ $limit = " limit " . intval($start) . ", " . intval($entries) . " ";
// Retrieve all columns except 'data'
diff --git a/include/bb2diaspora.php b/include/bb2diaspora.php
index da02d6cac..1759154f0 100644
--- a/include/bb2diaspora.php
+++ b/include/bb2diaspora.php
@@ -128,8 +128,16 @@ function markdown_to_bb($s, $use_zrl = false) {
$s = str_replace("&#xD;","\r",$s);
$s = str_replace("&#xD;\n&gt;","",$s);
+ if(is_array($s)) {
+ btlogger('markdown_to_bb called with array. ' . print_r($s,true), LOGGER_NORMAL, LOG_WARNING);
+ return '';
+ }
+
$s = html_entity_decode($s,ENT_COMPAT,'UTF-8');
+ // if empty link text replace with the url
+ $s = preg_replace("/\[\]\((.*?)\)/ism",'[$1]($1)',$s);
+
// first try plustags
$s = preg_replace_callback('/\@\{(.+?)\; (.+?)\@(.+?)\}\+/','diaspora_mention_callback',$s);
@@ -155,10 +163,10 @@ function markdown_to_bb($s, $use_zrl = false) {
// Convert everything that looks like a link to a link
if($use_zrl) {
$s = str_replace(array('[img','/img]'),array('[zmg','/zmg]'),$s);
- $s = preg_replace("/([^\]\=]|^)(https?\:\/\/)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[zrl=$2$3]$2$3[/zrl]',$s);
+ $s = preg_replace("/([^\]\=]|^)(https?\:\/\/)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\(\)]+)/ism", '$1[zrl=$2$3]$2$3[/zrl]',$s);
}
else {
- $s = preg_replace("/([^\]\=]|^)(https?\:\/\/)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url=$2$3]$2$3[/url]',$s);
+ $s = preg_replace("/([^\]\=]|^)(https?\:\/\/)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\(\)]+)/ism", '$1[url=$2$3]$2$3[/url]',$s);
}
// remove duplicate adjacent code tags
@@ -427,6 +435,12 @@ function bb2diaspora($Text,$preserve_nl = false, $fordiaspora = true) {
$Text = preg_replace_callback('/\@\!?\[([zu])rl\=(\w+.*?)\](\w+.*?)\[\/([zu])rl\]/i', 'bb2dmention_callback', $Text);
+ // strip map tags, as the rendering is performed in bbcode() and the resulting output
+ // is not compatible with Diaspora (at least in the case of openstreetmap and probably
+ // due to the inclusion of an html iframe)
+
+ $Text = preg_replace("/\[map\=(.*?)\]/ism", '$1', $Text);
+ $Text = preg_replace("/\[map\](.*?)\[\/map\]/ism", '$1', $Text);
// Converting images with size parameters to simple images. Markdown doesn't know it.
$Text = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $Text);
diff --git a/include/bbcode.php b/include/bbcode.php
index 21bc6de77..00d22d26d 100644
--- a/include/bbcode.php
+++ b/include/bbcode.php
@@ -511,11 +511,25 @@ function bb_code($match) {
return '<code class="inline-code">' . trim($match[1]) . '</code>';
}
+function bb_code_options($match) {
+ if(strpos($match[0], "<br />")) {
+ $class = "";
+ } else {
+ $class = "inline-code";
+ }
+ if(strpos($match[1], 'nowrap')) {
+ $style = "overflow-x: auto; white-space: pre;";
+ } else {
+ $style = "";
+ }
+ return '<code class="'. $class .'" style="'. $style .'">' . trim($match[2]) . '</code>';
+}
+
function bb_highlight($match) {
- if(in_array(strtolower($match[1]),['php','css','mysql','sql','abap','diff','html','perl','ruby',
+ $lang = ((in_array(strtolower($match[1]),['php','css','mysql','sql','abap','diff','html','perl','ruby',
'vbscript','avrc','dtd','java','xml','cpp','python','javascript','js','json','sh']))
- return text_highlight($match[2],strtolower($match[1]));
- return $match[0];
+ ? strtolower($match[1]) : 'php' );
+ return text_highlight($match[2],$lang);
}
function bb_fixtable_lf($match) {
@@ -529,7 +543,71 @@ function bb_fixtable_lf($match) {
}
+function parseIdentityAwareHTML($Text) {
+ // Hide all [noparse] contained bbtags by spacefying them
+ if (strpos($Text,'[noparse]') !== false) {
+ $Text = preg_replace_callback("/\[noparse\](.*?)\[\/noparse\]/ism", 'bb_spacefy',$Text);
+ }
+ if (strpos($Text,'[nobb]') !== false) {
+ $Text = preg_replace_callback("/\[nobb\](.*?)\[\/nobb\]/ism", 'bb_spacefy',$Text);
+ }
+ if (strpos($Text,'[pre]') !== false) {
+ $Text = preg_replace_callback("/\[pre\](.*?)\[\/pre\]/ism", 'bb_spacefy',$Text);
+ }
+ // process [observer] tags before we do anything else because we might
+ // be stripping away stuff that then doesn't need to be worked on anymore
+
+ $observer = App::get_observer();
+
+ if ((strpos($Text,'[/observer]') !== false) || (strpos($Text,'[/rpost]') !== false)) {
+ if ($observer) {
+ $Text = preg_replace("/\[observer\=1\](.*?)\[\/observer\]/ism", '$1', $Text);
+ $Text = preg_replace("/\[observer\=0\].*?\[\/observer\]/ism", '', $Text);
+ $Text = preg_replace_callback("/\[rpost(=(.*?))?\](.*?)\[\/rpost\]/ism", 'rpost_callback', $Text);
+ } else {
+ $Text = preg_replace("/\[observer\=1\].*?\[\/observer\]/ism", '', $Text);
+ $Text = preg_replace("/\[observer\=0\](.*?)\[\/observer\]/ism", '$1', $Text);
+ $Text = preg_replace("/\[rpost(=.*?)?\](.*?)\[\/rpost\]/ism", '', $Text);
+ }
+ }
+ // replace [observer.baseurl]
+ if ($observer) {
+ $s1 = '<span class="bb_observer" title="' . t('Different viewers will see this text differently') . '">';
+ $s2 = '</span>';
+ $obsBaseURL = $observer['xchan_connurl'];
+ $obsBaseURL = preg_replace("/\/poco\/.*$/", '', $obsBaseURL);
+ $Text = str_replace('[observer.baseurl]', $obsBaseURL, $Text);
+ $Text = str_replace('[observer.url]',$observer['xchan_url'], $Text);
+ $Text = str_replace('[observer.name]',$s1 . $observer['xchan_name'] . $s2, $Text);
+ $Text = str_replace('[observer.address]',$s1 . $observer['xchan_addr'] . $s2, $Text);
+ $Text = str_replace('[observer.webname]', substr($observer['xchan_addr'],0,strpos($observer['xchan_addr'],'@')), $Text);
+ $Text = str_replace('[observer.photo]',$s1 . '[zmg]'.$observer['xchan_photo_l'].'[/zmg]' . $s2, $Text);
+ } else {
+ $Text = str_replace('[observer.baseurl]', '', $Text);
+ $Text = str_replace('[observer.url]','', $Text);
+ $Text = str_replace('[observer.name]','', $Text);
+ $Text = str_replace('[observer.address]','', $Text);
+ $Text = str_replace('[observer.webname]','',$Text);
+ $Text = str_replace('[observer.photo]','', $Text);
+ }
+
+ $Text = str_replace(array('[baseurl]','[sitename]'),array(z_root(),get_config('system','sitename')),$Text);
+
+
+ // Unhide all [noparse] contained bbtags unspacefying them
+ // and triming the [noparse] tag.
+ if (strpos($Text,'[noparse]') !== false) {
+ $Text = preg_replace_callback("/\[noparse\](.*?)\[\/noparse\]/ism", 'bb_unspacefy_and_trim', $Text);
+ }
+ if (strpos($Text,'[nobb]') !== false) {
+ $Text = preg_replace_callback("/\[nobb\](.*?)\[\/nobb\]/ism", 'bb_unspacefy_and_trim', $Text);
+ }
+ if (strpos($Text,'[pre]') !== false) {
+ $Text = preg_replace_callback("/\[pre\](.*?)\[\/pre\]/ism", 'bb_unspacefy_and_trim', $Text);
+ }
+ return $Text;
+}
// BBcode 2 HTML was written by WAY2WEB.net
// extended to work with Mistpark/Friendica/Redmatrix/Hubzilla - Mike Macgirvin
@@ -661,7 +739,7 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false)
// Perform URL Search
- $urlchars = '[a-zA-Z0-9\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\+\,\@]';
+ $urlchars = '[a-zA-Z0-9\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\+\,\@\(\)]';
if (strpos($Text,'http') !== false) {
if($tryoembed) {
@@ -745,6 +823,12 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false)
if (strpos($Text,'[/color]') !== false) {
$Text = preg_replace("(\[color=(.*?)\](.*?)\[\/color\])ism", "<span style=\"color: $1;\">$2</span>", $Text);
}
+ // Check for colored text
+ if (strpos($Text,'[/hl]') !== false) {
+ $Text = preg_replace("(\[hl\](.*?)\[\/hl\])ism", "<span style=\"background-color: yellow;\">$1</span>", $Text);
+ $Text = preg_replace("(\[hl=(.*?)\](.*?)\[\/hl\])ism", "<span style=\"background-color: $1;\">$2</span>", $Text);
+ }
+
// Check for sized text
// [size=50] --> font-size: 50px (with the unit).
if (strpos($Text,'[/size]') !== false) {
@@ -776,12 +860,14 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false)
$Text = preg_replace("(\[h6\](.*?)\[\/h6\])ism",'<h6>$1</h6>',$Text);
}
// Check for table of content without params
- if (strpos($Text,'[toc]') !== false) {
- $Text = preg_replace("/\[toc\]/ism",'<ul id="toc"></ul>',$Text);
+ while(strpos($Text,'[toc]') !== false) {
+ $toc_id = 'toc-' . random_string(10);
+ $Text = preg_replace("/\[toc\]/ism", '<ul id="' . $toc_id . '" class="toc" data-toc=".section-content-wrapper"></ul><script>$("#' . $toc_id . '").toc();</script>', $Text, 1);
}
// Check for table of content with params
- if (strpos($Text,'[toc') !== false) {
- $Text = preg_replace("/\[toc([^\]]+?)\]/ism",'<ul$1></ul>',$Text);
+ while(strpos($Text,'[toc') !== false) {
+ $toc_id = 'toc-' . random_string(10);
+ $Text = preg_replace("/\[toc([^\]]+?)\]/ism", '<ul id="' . $toc_id . '" class="toc"$1></ul><script>$("#' . $toc_id . '").toc();</script>', $Text, 1);
}
// Check for centered text
if (strpos($Text,'[/center]') !== false) {
@@ -841,8 +927,8 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false)
}
if (strpos($Text,'[/table]') !== false) {
$Text = preg_replace("/\[table\](.*?)\[\/table\]/sm", '<table>$1</table>', $Text);
- $Text = preg_replace("/\[table border=1\](.*?)\[\/table\]/sm", '<table border="1" >$1</table>', $Text);
- $Text = preg_replace("/\[table border=0\](.*?)\[\/table\]/sm", '<table border="0" >$1</table>', $Text);
+ $Text = preg_replace("/\[table border=1\](.*?)\[\/table\]/sm", '<table class="table table-responsive table-bordered" >$1</table>', $Text);
+ $Text = preg_replace("/\[table border=0\](.*?)\[\/table\]/sm", '<table class="table table-responsive" >$1</table>', $Text);
}
$Text = str_replace('</tr><br /><tr>', "</tr>\n<tr>", $Text);
$Text = str_replace('[hr]', '<hr />', $Text);
@@ -861,6 +947,11 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = 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);
+ }
+
// Check for [spoiler] text
$endlessloop = 0;
while ((strpos($Text, "[/spoiler]")!== false) and (strpos($Text, "[spoiler]") !== false) and (++$endlessloop < 20)) {
@@ -1017,15 +1108,15 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false)
$Text = preg_replace("/\[zaudio\](.*?)\[\/zaudio\]/", '<a class="zid" href="$1" target="_blank" >$1</a>', $Text);
}
- if ($tryoembed){
- if (strpos($Text,'[/iframe]') !== false) {
- $Text = preg_replace_callback("/\[iframe\](.*?)\[\/iframe\]/ism", 'bb_iframe', $Text);
- }
- } else {
- if (strpos($Text,'[/iframe]') !== false) {
- $Text = preg_replace("/\[iframe\](.*?)\[\/iframe\]/ism", '<a href="$1" target="_blank" >$1</a>', $Text);
- }
- }
+// if ($tryoembed){
+// if (strpos($Text,'[/iframe]') !== false) {
+// $Text = preg_replace_callback("/\[iframe\](.*?)\[\/iframe\]/ism", 'bb_iframe', $Text);
+// }
+// } else {
+// if (strpos($Text,'[/iframe]') !== false) {
+// $Text = preg_replace("/\[iframe\](.*?)\[\/iframe\]/ism", '<a href="$1" target="_blank" >$1</a>', $Text);
+// }
+// }
// oembed tag
$Text = oembed_bbcode2html($Text);
@@ -1077,9 +1168,9 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false)
$Text = preg_replace("/\<(.*?)(src|href)=(.*?)\&amp\;(.*?)\>/ism", '<$1$2=$3&$4>', $Text);
// This is subtle - it's an XSS filter. It only accepts links with a protocol scheme and where
- // the scheme begins with z (zhttp), h (http(s)), f (ftp), m (mailto), and named anchors.
+ // the scheme begins with z (zhttp), h (http(s)), f (ftp(s)), m (mailto), t (tel) and named anchors.
- $Text = preg_replace("/\<(.*?)(src|href)=\"[^zhfm#](.*?)\>/ism", '<$1$2="">', $Text);
+ $Text = preg_replace("/\<(.*?)(src|href)=\"[^zhfmt#](.*?)\>/ism", '<$1$2="">', $Text);
$Text = bb_replace_images($Text, $saved_images);
diff --git a/include/channel.php b/include/channel.php
index 4fc873402..caf3ded71 100644
--- a/include/channel.php
+++ b/include/channel.php
@@ -1218,7 +1218,7 @@ function advanced_profile(&$a) {
$profile['marital'] = array( t('Status:'), App::$profile['marital']);
if(App::$profile['partner'])
- $profile['marital']['partner'] = bbcode(App::$profile['partner']);
+ $profile['marital']['partner'] = zidify_links(bbcode(App::$profile['partner']));
if(strlen(App::$profile['howlong']) && App::$profile['howlong'] > NULL_DATE) {
$profile['howlong'] = relative_date(App::$profile['howlong'], t('for %1$d %2$s'));
diff --git a/include/config.php b/include/config.php
index 44ef29614..0b0e639ab 100644
--- a/include/config.php
+++ b/include/config.php
@@ -35,8 +35,8 @@ function load_config($family) {
Zlib\Config::Load($family);
}
-function get_config($family, $key) {
- return Zlib\Config::Get($family,$key);
+function get_config($family, $key, $default = false) {
+ return Zlib\Config::Get($family,$key,$default);
}
function set_config($family, $key, $value) {
@@ -51,8 +51,8 @@ function load_pconfig($uid) {
Zlib\PConfig::Load($uid);
}
-function get_pconfig($uid, $family, $key, $instore = false) {
- return Zlib\PConfig::Get($uid,$family,$key,$instore = false);
+function get_pconfig($uid, $family, $key, $default = false) {
+ return Zlib\PConfig::Get($uid,$family,$key,$default);
}
function set_pconfig($uid, $family, $key, $value) {
@@ -67,8 +67,8 @@ function load_xconfig($xchan) {
Zlib\XConfig::Load($xchan);
}
-function get_xconfig($xchan, $family, $key) {
- return Zlib\XConfig::Get($xchan,$family,$key);
+function get_xconfig($xchan, $family, $key, $default = false) {
+ return Zlib\XConfig::Get($xchan,$family,$key, $default);
}
function set_xconfig($xchan, $family, $key, $value) {
@@ -83,8 +83,8 @@ function load_aconfig($account_id) {
Zlib\AConfig::Load($account_id);
}
-function get_aconfig($account_id, $family, $key) {
- return Zlib\AConfig::Get($account_id, $family, $key);
+function get_aconfig($account_id, $family, $key, $default = false) {
+ return Zlib\AConfig::Get($account_id, $family, $key, $default);
}
function set_aconfig($account_id, $family, $key, $value) {
@@ -99,8 +99,8 @@ function load_abconfig($chan, $xhash, $family = '') {
return Zlib\AbConfig::Load($chan,$xhash,$family);
}
-function get_abconfig($chan,$xhash,$family,$key) {
- return Zlib\AbConfig::Get($chan,$xhash,$family,$key);
+function get_abconfig($chan,$xhash,$family,$key, $default = false) {
+ return Zlib\AbConfig::Get($chan,$xhash,$family,$key, $default);
}
function set_abconfig($chan,$xhash,$family,$key,$value) {
@@ -115,8 +115,8 @@ function load_iconfig(&$item) {
Zlib\IConfig::Load($item);
}
-function get_iconfig(&$item, $family, $key) {
- return Zlib\IConfig::Get($item, $family, $key);
+function get_iconfig(&$item, $family, $key, $default = false) {
+ return Zlib\IConfig::Get($item, $family, $key, $default);
}
function set_iconfig(&$item, $family, $key, $value, $sharing = false) {
diff --git a/include/connections.php b/include/connections.php
index b08d046b3..31e941e95 100644
--- a/include/connections.php
+++ b/include/connections.php
@@ -630,3 +630,273 @@ function random_profile() {
return '';
}
+function update_vcard($arr,$vcard = null) {
+
+ $fn = $arr['fn'];
+
+
+ // This isn't strictly correct and could be a cause for concern.
+ // 'N' => array_reverse(explode(' ', $fn))
+
+
+ // What we really want is
+ // 'N' => Adams;John;Quincy;Reverend,Dr.;III
+ // which is a very difficult parsing problem especially if you allow
+ // the surname to contain spaces. The only way to be sure to get it
+ // right is to provide a form to input all the various fields and not
+ // try to extract it from the FN.
+
+ if(! $vcard) {
+ $vcard = new \Sabre\VObject\Component\VCard([
+ 'FN' => $fn,
+ 'N' => array_reverse(explode(' ', $fn))
+ ]);
+ }
+ else {
+ $vcard->FN = $fn;
+ $vcard->N = array_reverse(explode(' ', $fn));
+ }
+
+ $org = $arr['org'];
+ if($org) {
+ $vcard->ORG = $org;
+ }
+
+ $title = $arr['title'];
+ if($title) {
+ $vcard->TITLE = $title;
+ }
+
+ $tel = $arr['tel'];
+ $tel_type = $arr['tel_type'];
+ if($tel) {
+ $i = 0;
+ foreach($tel as $item) {
+ if($item) {
+ $vcard->add('TEL', $item, ['type' => $tel_type[$i]]);
+ }
+ $i++;
+ }
+ }
+
+ $email = $arr['email'];
+ $email_type = $arr['email_type'];
+ if($email) {
+ $i = 0;
+ foreach($email as $item) {
+ if($item) {
+ $vcard->add('EMAIL', $item, ['type' => $email_type[$i]]);
+ }
+ $i++;
+ }
+ }
+
+ $impp = $arr['impp'];
+ $impp_type = $arr['impp_type'];
+ if($impp) {
+ $i = 0;
+ foreach($impp as $item) {
+ if($item) {
+ $vcard->add('IMPP', $item, ['type' => $impp_type[$i]]);
+ }
+ $i++;
+ }
+ }
+
+ $url = $arr['url'];
+ $url_type = $arr['url_type'];
+ if($url) {
+ $i = 0;
+ foreach($url as $item) {
+ if($item) {
+ $vcard->add('URL', $item, ['type' => $url_type[$i]]);
+ }
+ $i++;
+ }
+ }
+
+ $adr = $arr['adr'];
+ $adr_type = $arr['adr_type'];
+
+ if($adr) {
+ $i = 0;
+ foreach($adr as $item) {
+ if($item) {
+ $vcard->add('ADR', $item, ['type' => $adr_type[$i]]);
+ }
+ $i++;
+ }
+ }
+
+ $note = $arr['note'];
+ if($note) {
+ $vcard->NOTE = $note;
+ }
+
+ return $vcard->serialize();
+
+}
+
+function get_vcard_array($vc,$id) {
+
+ $photo = '';
+ if($vc->PHOTO) {
+ $photo_value = strtolower($vc->PHOTO->getValueType()); // binary or uri
+ if($photo_value === 'binary') {
+ $photo_type = strtolower($vc->PHOTO['TYPE']); // mime jpeg, png or gif
+ $photo = 'data:image/' . $photo_type . ';base64,' . base64_encode((string)$vc->PHOTO);
+ }
+ else {
+ $url = parse_url((string)$vc->PHOTO);
+ $photo = 'data:' . $url['path'];
+ }
+ }
+
+ $fn = '';
+ if($vc->FN) {
+ $fn = (string) escape_tags($vc->FN);
+ }
+
+ $org = '';
+ if($vc->ORG) {
+ $org = (string) escape_tags($vc->ORG);
+ }
+
+ $title = '';
+ if($vc->TITLE) {
+ $title = (string) escape_tags($vc->TITLE);
+ }
+
+ $tels = [];
+ if($vc->TEL) {
+ foreach($vc->TEL as $tel) {
+ $type = (($tel['TYPE']) ? vcard_translate_type((string)$tel['TYPE']) : '');
+ $tels[] = [
+ 'type' => $type,
+ 'nr' => (string) escape_tags($tel)
+ ];
+ }
+ }
+ $emails = [];
+ if($vc->EMAIL) {
+ foreach($vc->EMAIL as $email) {
+ $type = (($email['TYPE']) ? vcard_translate_type((string)$email['TYPE']) : '');
+ $emails[] = [
+ 'type' => $type,
+ 'address' => (string) escape_tags($email)
+ ];
+ }
+ }
+
+ $impps = [];
+ if($vc->IMPP) {
+ foreach($vc->IMPP as $impp) {
+ $type = (($impp['TYPE']) ? vcard_translate_type((string)$impp['TYPE']) : '');
+ $impps[] = [
+ 'type' => $type,
+ 'address' => (string) escape_tags($impp)
+ ];
+ }
+ }
+
+ $urls = [];
+ if($vc->URL) {
+ foreach($vc->URL as $url) {
+ $type = (($url['TYPE']) ? vcard_translate_type((string)$url['TYPE']) : '');
+ $urls[] = [
+ 'type' => $type,
+ 'address' => (string) escape_tags($url)
+ ];
+ }
+ }
+
+ $adrs = [];
+ if($vc->ADR) {
+ foreach($vc->ADR as $adr) {
+ $type = (($adr['TYPE']) ? vcard_translate_type((string)$adr['TYPE']) : '');
+ $adrs[] = [
+ 'type' => $type,
+ 'address' => escape_tags($adr->getParts())
+ ];
+ }
+ }
+
+ $note = '';
+ if($vc->NOTE) {
+ $note = (string) escape_tags($vc->NOTE);
+ }
+
+ $card = [
+ 'id' => $id,
+ 'photo' => $photo,
+ 'fn' => $fn,
+ 'org' => $org,
+ 'title' => $title,
+ 'tels' => $tels,
+ 'emails' => $emails,
+ 'impps' => $impps,
+ 'urls' => $urls,
+ 'adrs' => $adrs,
+ 'note' => $note
+ ];
+
+ return $card;
+
+}
+
+
+function vcard_translate_type($type) {
+
+ if(!$type)
+ return;
+
+ $type = strtoupper($type);
+
+ $map = [
+ 'CELL' => t('Mobile'),
+ 'HOME' => t('Home'),
+ 'HOME,VOICE' => t('Home, Voice'),
+ 'HOME,FAX' => t('Home, Fax'),
+ 'WORK' => t('Work'),
+ 'WORK,VOICE' => t('Work, Voice'),
+ 'WORK,FAX' => t('Work, Fax'),
+ 'OTHER' => t('Other')
+ ];
+
+ if (array_key_exists($type, $map)) {
+ return [$type, $map[$type]];
+ }
+ else {
+ return [$type, t('Other') . ' (' . $type . ')'];
+ }
+}
+
+
+function vcard_query(&$r) {
+
+ $arr = [];
+
+ if($r && is_array($r) && count($r)) {
+ $uid = $r[0]['abook_channel'];
+ foreach($r as $rv) {
+ if($rv['abook_xchan'] && (! in_array("'" . dbesc($rv['abook_xchan']) . "'",$arr)))
+ $arr[] = "'" . dbesc($rv['abook_xchan']) . "'";
+ }
+ }
+
+ if($arr) {
+ $a = q("select * from abconfig where chan = %d and xchan in (" . protect_sprintf(implode(',', $arr)) . ") and cat = 'system' and k = 'vcard'",
+ intval($uid)
+ );
+ if($a) {
+ foreach($a as $av) {
+ for($x = 0; $x < count($r); $x ++) {
+ if($r[$x]['abook_xchan'] == $av['xchan']) {
+ $vctmp = \Sabre\VObject\Reader::read($av['v']);
+ $r[$x]['vcard'] = (($vctmp) ? get_vcard_array($vctmp,$r[$x]['abook_id']) : [] );
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/include/conversation.php b/include/conversation.php
index c260eb4a0..0ff368e6e 100644
--- a/include/conversation.php
+++ b/include/conversation.php
@@ -363,7 +363,7 @@ function localize_item(&$item){
if(intval($item['item_obscured'])
&& strlen($item['body']) && (! strpos($item['body'],'data'))) {
- $item['body'] = json_encode(crypto_encapsulate($item['body'],get_config('system','pubkey')));
+ $item['body'] = z_obscure($item['body']);
}
}
@@ -473,22 +473,6 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $
if (local_channel())
load_pconfig(local_channel(),'');
- $arr_blocked = null;
-
- if (local_channel())
- $str_blocked = get_pconfig(local_channel(),'system','blocked');
- if (! local_channel() && ($mode == 'network')) {
- $sys = get_sys_channel();
- $id = $sys['channel_id'];
- $str_blocked = get_pconfig($id,'system','blocked');
- }
-
- if ($str_blocked) {
- $arr_blocked = explode(',',$str_blocked);
- for ($x = 0; $x < count($arr_blocked); $x ++)
- $arr_blocked[$x] = trim($arr_blocked[$x]);
- }
-
$profile_owner = 0;
$page_writeable = false;
$live_update_div = '';
@@ -615,17 +599,13 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $
foreach($items as $item) {
- if($arr_blocked) {
- $blocked = false;
- foreach($arr_blocked as $b) {
- if(($b) && (($item['author_xchan'] == $b) || ($item['owner_xchan'] == $b))) {
- $blocked = true;
- break;
- }
- }
- if($blocked)
- continue;
- }
+ $x = [ 'mode' => $mode, 'item' => $item ];
+ call_hooks('stream_item',$x);
+
+ if($x['item']['blocked'])
+ continue;
+
+ $item = $x['item'];
$threadsid++;
@@ -709,7 +689,8 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $
'id' => (($preview) ? 'P0' : $item['item_id']),
'linktitle' => sprintf( t('View %s\'s profile @ %s'), $profile_name, $profile_url),
'profile_url' => $profile_link,
- 'item_photo_menu' => item_photo_menu($item),
+ 'thread_action_menu' => thread_action_menu($item,$mode),
+ 'thread_author_menu' => thread_author_menu($item,$mode),
'name' => $profile_name,
'sparkle' => $sparkle,
'lock' => $lock,
@@ -787,28 +768,14 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $
// Check for any blocked authors
- if($arr_blocked) {
- $blocked = false;
- foreach($arr_blocked as $b) {
- if(($b) && ($item['author_xchan'] == $b)) {
- $blocked = true;
- break;
- }
- }
- if($blocked)
- continue;
- }
- // Check all the kids too
+ $x = [ 'mode' => $mode, 'item' => $item ];
+ call_hooks('stream_item',$x);
+
+ if($x['item']['blocked'])
+ continue;
- if($arr_blocked && $item['children']) {
- for($d = 0; $d < count($item['children']); $d ++) {
- foreach($arr_blocked as $b) {
- if(($b) && ($item['children'][$d]['author_xchan'] == $b))
- $item['children'][$d]['author_blocked'] = true;
- }
- }
- }
+ $item = $x['item'];
builtin_activity_puller($item, $conv_responses);
@@ -994,6 +961,169 @@ function item_photo_menu($item){
return $o;
}
+
+function thread_action_menu($item,$mode = '') {
+
+ $menu = [];
+
+ if((local_channel()) && local_channel() == $item['uid']) {
+ $menu[] = [
+ 'menu' => 'view_source',
+ 'title' => t('View Source'),
+ 'icon' => 'eye',
+ 'action' => 'viewsrc(' . $item['id'] . '); return false;',
+ 'href' => '#'
+ ];
+
+ if(! in_array($mode, [ 'network-new', 'search', 'community'])) {
+ if($item['parent'] == $item['id'] && (get_observer_hash() != $item['author_xchan'])) {
+ $menu[] = [
+ 'menu' => 'follow_thread',
+ 'title' => t('Follow Thread'),
+ 'icon' => 'plus',
+ 'action' => 'dosubthread(' . $item['id'] . '); return false;',
+ 'href' => '#'
+ ];
+ }
+
+ $menu[] = [
+ 'menu' => 'unfollow_thread',
+ 'title' => t('Unfollow Thread'),
+ 'icon' => 'minus',
+ 'action' => 'dounsubthread(' . $item['id'] . '); return false;',
+ 'href' => '#'
+ ];
+ }
+
+ }
+
+
+
+
+ $args = [ 'item' => $item, 'mode' => $mode, 'menu' => $menu ];
+ call_hooks('thread_action_menu', $args);
+
+ return $args['menu'];
+
+}
+
+function thread_author_menu($item, $mode = '') {
+
+ $menu = [];
+
+ $local_channel = local_channel();
+
+ if($local_channel) {
+ if(! count(App::$contacts))
+ load_contact_links($local_channel);
+ $channel = App::get_channel();
+ $channel_hash = (($channel) ? $channel['channel_hash'] : '');
+ }
+
+ $profile_link = chanlink_hash($item['author_xchan']);
+ if($item['uid'] > 0)
+ $pm_url = z_root() . '/mail/new/?f=&hash=' . $item['author_xchan'];
+
+ if(App::$contacts && array_key_exists($item['author_xchan'],App::$contacts))
+ $contact = App::$contacts[$item['author_xchan']];
+ else
+ if($local_channel && $item['author']['xchan_addr'])
+ $follow_url = z_root() . '/follow/?f=&url=' . $item['author']['xchan_addr'];
+
+ if($contact) {
+ $poke_link = z_root() . '/poke/?f=&c=' . $contact['abook_id'];
+ if (! intval($contact['abook_self']))
+ $contact_url = z_root() . '/connedit/' . $contact['abook_id'];
+ $posts_link = z_root() . '/network/?cid=' . $contact['abook_id'];
+
+ $clean_url = normalise_link($item['author-link']);
+ }
+
+ $rating_enabled = get_config('system','rating_enabled');
+
+ $ratings_url = (($rating_enabled) ? z_root() . '/ratings/' . urlencode($item['author_xchan']) : '');
+
+ if($profile_link) {
+ $menu[] = [
+ 'menu' => 'view_profile',
+ 'title' => t('View Profile'),
+ 'icon' => 'fw',
+ 'action' => '',
+ 'href' => $profile_link
+ ];
+ }
+
+ if($posts_link) {
+ $menu[] = [
+ 'menu' => 'view_posts',
+ 'title' => t('Activity/Posts'),
+ 'icon' => 'fw',
+ 'action' => '',
+ 'href' => $posts_link
+ ];
+ }
+
+ if($follow_url) {
+ $menu[] = [
+ 'menu' => 'follow',
+ 'title' => t('Connect'),
+ 'icon' => 'fw',
+ 'action' => '',
+ 'href' => $follow_url
+ ];
+ }
+
+ if($contact_url) {
+ $menu[] = [
+ 'menu' => 'connedit',
+ 'title' => t('Edit Connection'),
+ 'icon' => 'fw',
+ 'action' => '',
+ 'href' => $contact_url
+ ];
+ }
+
+ if($pm_url) {
+ $menu[] = [
+ 'menu' => 'prv_message',
+ 'title' => t('Message'),
+ 'icon' => 'fw',
+ 'action' => '',
+ 'href' => $pm_url
+ ];
+ }
+
+ if($ratings_url) {
+ $menu[] = [
+ 'menu' => 'ratings',
+ 'title' => t('Ratings'),
+ 'icon' => 'fw',
+ 'action' => '',
+ 'href' => $ratings_url
+ ];
+ }
+
+ if($poke_link) {
+ $menu[] = [
+ 'menu' => 'poke',
+ 'title' => t('Poke'),
+ 'icon' => 'fw',
+ 'action' => '',
+ 'href' => $poke_link
+ ];
+ }
+
+ $args = [ 'item' => $item, 'mode' => $mode, 'menu' => $menu ];
+ call_hooks('thread_author_menu', $args);
+
+ return $args['menu'];
+
+}
+
+
+
+
+
/**
* @brief Checks item to see if it is one of the builtin activities (like/dislike, event attendance, consensus items, etc.)
*
@@ -1266,11 +1396,11 @@ function status_editor($a, $x, $popup = false) {
'$setloc' => $setloc,
'$voting' => t('Toggle voting'),
'$feature_voting' => $feature_voting,
- '$consensus' => 0,
+ '$consensus' => ((array_key_exists('item',$x)) ? $x['item']['item_consensus'] : 0),
'$nocommenttitle' => t('Disable comments'),
'$nocommenttitlesub' => t('Toggle comments'),
'$feature_nocomment' => $feature_nocomment,
- '$nocomment' => 0,
+ '$nocomment' => ((array_key_exists('item',$x)) ? $x['item']['item_nocomment'] : 0),
'$clearloc' => $clearloc,
'$title' => ((x($x, 'title')) ? htmlspecialchars($x['title'], ENT_COMPAT,'UTF-8') : ''),
'$placeholdertitle' => ((x($x, 'placeholdertitle')) ? $x['placeholdertitle'] : t('Title (optional)')),
@@ -1434,7 +1564,7 @@ function format_location($item) {
if(strpos($item['location'],'#') === 0) {
$location = substr($item['location'],1);
- $location = ((strpos($location,'[') !== false) ? bbcode($location) : $location);
+ $location = ((strpos($location,'[') !== false) ? zidify_links(bbcode($location)) : $location);
}
else {
$locate = array('location' => $item['location'], 'coord' => $item['coord'], 'html' => '');
@@ -1486,7 +1616,7 @@ function prepare_page($item) {
'$author' => (($naked) ? '' : $item['author']['xchan_name']),
'$auth_url' => (($naked) ? '' : zid($item['author']['xchan_url'])),
'$date' => (($naked) ? '' : datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'Y-m-d H:i')),
- '$title' => smilies(bbcode($item['title'])),
+ '$title' => zidify_links(smilies(bbcode($item['title']))),
'$body' => $body['html'],
'$preview' => $preview,
'$link' => $link,
@@ -1656,6 +1786,20 @@ function profile_tabs($a, $is_owner = false, $nickname = null){
$cal_link = '/cal/' . $nickname;
}
+ require_once('include/security.php');
+ $sql_options = item_permissions_sql($uid);
+
+ $r = q("select item.* from item left join iconfig on item.id = iconfig.iid
+ where item.uid = %d and iconfig.cat = 'system' and iconfig.v = '%s'
+ and item.item_delayed = 0 and item.item_deleted = 0
+ and ( iconfig.k = 'WEBPAGE' and item_type = %d )
+ $sql_options limit 1",
+ intval($uid),
+ dbesc('home'),
+ intval(ITEM_TYPE_WEBPAGE)
+ );
+
+ $has_webpages = (($r) ? true : false);
if (get_pconfig($uid, 'system', 'noprofiletabs'))
return;
@@ -1740,19 +1884,20 @@ function profile_tabs($a, $is_owner = false, $nickname = null){
);
}
- if ($p['write_pages'] && feature_enabled($uid,'webpages')) {
+ if($has_webpages && feature_enabled($uid,'webpages')) {
$tabs[] = array(
'label' => t('Webpages'),
- 'url' => z_root() . '/webpages/' . $nickname,
+ 'url' => z_root() . '/page/' . $nickname . '/home',
'sel' => ((argv(0) == 'webpages') ? 'active' : ''),
- 'title' => t('Manage Webpages'),
+ 'title' => t('View Webpages'),
'id' => 'webpages-tab',
);
- }
+ }
+
if(feature_enabled($uid,'wiki') && (get_account_techlevel($account_id) > 3)) {
$tabs[] = array(
- 'label' => t('Wiki'),
+ 'label' => t('Wikis'),
'url' => z_root() . '/wiki/' . $nickname,
'sel' => ((argv(0) == 'wiki') ? 'active' : ''),
'title' => t('Wiki'),
diff --git a/include/crypto.php b/include/crypto.php
index bc798d919..f75390985 100644
--- a/include/crypto.php
+++ b/include/crypto.php
@@ -48,27 +48,122 @@ function pkcs5_unpad($text)
function AES256CBC_encrypt($data,$key,$iv) {
return openssl_encrypt($data,'aes-256-cbc',str_pad($key,32,"\0"),OPENSSL_RAW_DATA,str_pad($iv,16,"\0"));
-
}
function AES256CBC_decrypt($data,$key,$iv) {
return openssl_decrypt($data,'aes-256-cbc',str_pad($key,32,"\0"),OPENSSL_RAW_DATA,str_pad($iv,16,"\0"));
+}
+
+function AES128CBC_encrypt($data,$key,$iv) {
+ $key = substr($key,0,16);
+ $iv = substr($iv,0,16);
+ return openssl_encrypt($data,'aes-128-cbc',str_pad($key,16,"\0"),OPENSSL_RAW_DATA,str_pad($iv,16,"\0"));
+}
+
+function AES128CBC_decrypt($data,$key,$iv) {
+ $key = substr($key,0,16);
+ $iv = substr($iv,0,16);
+ return openssl_decrypt($data,'aes-128-cbc',str_pad($key,16,"\0"),OPENSSL_RAW_DATA,str_pad($iv,16,"\0"));
+}
+
+function STD_encrypt($data,$key,$iv) {
+ $key = substr($key,0,32);
+ $iv = substr($iv,0,16);
+ return openssl_encrypt($data,'aes-256-cbc',str_pad($key,32,"\0"),OPENSSL_RAW_DATA,str_pad($iv,16,"\0"));
+}
+
+function STD_decrypt($data,$key,$iv) {
+ $key = substr($key,0,32);
+ $iv = substr($iv,0,16);
+ return openssl_decrypt($data,'aes-256-cbc',str_pad($key,32,"\0"),OPENSSL_RAW_DATA,str_pad($iv,16,"\0"));
+}
+function CAST5CBC_encrypt($data,$key,$iv) {
+ $key = substr($key,0,16);
+ $iv = substr($iv,0,8);
+ return openssl_encrypt($data,'cast5-cbc',str_pad($key,16,"\0"),OPENSSL_RAW_DATA,str_pad($iv,8,"\0"));
+}
+
+function CAST5CBC_decrypt($data,$key,$iv) {
+ $key = substr($key,0,16);
+ $iv = substr($iv,0,8);
+ return openssl_decrypt($data,'cast5-cbc',str_pad($key,16,"\0"),OPENSSL_RAW_DATA,str_pad($iv,8,"\0"));
}
function crypto_encapsulate($data,$pubkey,$alg='aes256cbc') {
+ $fn = strtoupper($alg) . '_encrypt';
+
if($alg === 'aes256cbc')
return aes_encapsulate($data,$pubkey);
+ return other_encapsulate($data,$pubkey,$alg);
+
+}
+
+function other_encapsulate($data,$pubkey,$alg) {
+ if(! $pubkey)
+ logger('no key. data: ' . $data);
+
+ $fn = strtoupper($alg) . '_encrypt';
+ if(function_exists($fn)) {
+
+ // A bit hesitant to use openssl_random_pseudo_bytes() as we know
+ // it has been historically targeted by US agencies for 'weakening'.
+ // It is still arguably better than trying to come up with an
+ // alternative cryptographically secure random generator.
+ // There is little point in using the optional second arg to flag the
+ // assurance of security since it is meaningless if the source algorithms
+ // have been compromised. Also none of this matters if RSA has been
+ // compromised by state actors and evidence is mounting that this has
+ // already happened.
+
+ $key = openssl_random_pseudo_bytes(256);
+ $iv = openssl_random_pseudo_bytes(256);
+ $result['data'] = base64url_encode($fn($data,$key,$iv),true);
+ // log the offending call so we can track it down
+ if(! openssl_public_encrypt($key,$k,$pubkey)) {
+ $x = debug_backtrace();
+ logger('RSA failed. ' . print_r($x[0],true));
+ }
+
+ $result['alg'] = $alg;
+ $result['key'] = base64url_encode($k,true);
+ openssl_public_encrypt($iv,$i,$pubkey);
+ $result['iv'] = base64url_encode($i,true);
+ return $result;
+ }
+ else {
+ $x = [ 'data' => $data, 'pubkey' => $pubkey, 'alg' => $alg, 'result' => $data ];
+ call_hooks('other_encapsulate', $x);
+ return $x['result'];
+ }
+}
+
+function crypto_methods() {
+
+ if(\Zotlabs\Lib\System::get_server_role() !== 'pro')
+ return [ 'aes256cbc' ];
+
+ // 'std' is the new project standard which is aes256cbc but transmits/receives 256-byte key and iv.
+ // aes256cbc is provided for compatibility with earlier zot implementations which assume 32-byte key and 16-byte iv.
+ // other_encapsulate() now produces these longer keys/ivs by default so that it is difficult to guess a
+ // particular implementation or choice of underlying implementations based on the key/iv length.
+ // The actual methods are responsible for deriving the actual key/iv from the provided parameters;
+ // possibly by truncation or segmentation - though many other methods could be used.
+
+ $r = [ 'std', 'aes256cbc', 'aes128cbc', 'cast5cbc' ];
+ call_hooks('crypto_methods',$r);
+ return $r;
+
}
function aes_encapsulate($data,$pubkey) {
if(! $pubkey)
logger('aes_encapsulate: no key. data: ' . $data);
- $key = random_string(32,RANDOM_STRING_TEXT);
- $iv = random_string(16,RANDOM_STRING_TEXT);
+ $key = openssl_random_pseudo_bytes(32);
+ $iv = openssl_random_pseudo_bytes(16);
$result['data'] = base64url_encode(AES256CBC_encrypt($data,$key,$iv),true);
// log the offending call so we can track it down
if(! openssl_public_encrypt($key,$k,$pubkey)) {
@@ -89,6 +184,22 @@ function crypto_unencapsulate($data,$prvkey) {
if($alg === 'aes256cbc')
return aes_unencapsulate($data,$prvkey);
+ return other_unencapsulate($data,$prvkey,$alg);
+
+}
+
+function other_unencapsulate($data,$prvkey,$alg) {
+ $fn = strtoupper($alg) . '_decrypt';
+ if(function_exists($fn)) {
+ openssl_private_decrypt(base64url_decode($data['key']),$k,$prvkey);
+ openssl_private_decrypt(base64url_decode($data['iv']),$i,$prvkey);
+ return $fn(base64url_decode($data['data']),$k,$i);
+ }
+ else {
+ $x = [ 'data' => $data, 'prvkey' => $prvkey, 'alg' => $alg, 'result' => $data ];
+ call_hooks('other_unencapsulate',$x);
+ return $x['result'];
+ }
}
diff --git a/include/dba/dba_driver.php b/include/dba/dba_driver.php
index 0b5f085af..e47f97387 100755
--- a/include/dba/dba_driver.php
+++ b/include/dba/dba_driver.php
@@ -98,7 +98,7 @@ class DBA {
abstract class dba_driver {
// legacy behavior
- protected $db;
+ public $db;
protected $pdo = array();
public $debug = 0;
@@ -337,7 +337,7 @@ function db_concat($fld, $sep) {
function q($sql) {
$args = func_get_args();
- unset($args[0]);
+ array_shift($args);
if(\DBA::$dba && \DBA::$dba->connected) {
$stmt = vsprintf($sql, $args);
diff --git a/include/dba/dba_pdo.php b/include/dba/dba_pdo.php
index e235c467b..f76e6cdd7 100755
--- a/include/dba/dba_pdo.php
+++ b/include/dba/dba_pdo.php
@@ -133,7 +133,7 @@ class dba_pdo extends dba_driver {
}
function unescapebin($str) {
- if($this->driver_dbtype === 'pgsql') {
+ if($this->driver_dbtype === 'pgsql' && (! is_null($str))) {
$x = '';
while(! feof($str)) {
$x .= fread($str,8192);
diff --git a/include/dir_fns.php b/include/dir_fns.php
index 03cc2706a..3922730fc 100644
--- a/include/dir_fns.php
+++ b/include/dir_fns.php
@@ -192,17 +192,19 @@ function sync_directories($dirmode) {
'site_update' => NULL_DATE,
'site_directory' => DIRECTORY_FALLBACK_MASTER . '/dirsearch',
'site_realm' => DIRECTORY_REALM,
- 'site_valid' => 1
+ 'site_valid' => 1,
+ 'site_crypto' => 'aes256cbc'
);
- $x = q("insert into site ( site_url, site_flags, site_update, site_directory, site_realm, site_valid )
- values ( '%s', %d, '%s', '%s', '%s', %d ) ",
+ $x = q("insert into site ( site_url, site_flags, site_update, site_directory, site_realm, site_valid, site_crypto )
+ values ( '%s', %d, '%s', '%s', '%s', %d, '%s' ) ",
dbesc($r[0]['site_url']),
intval($r[0]['site_flags']),
dbesc($r[0]['site_update']),
dbesc($r[0]['site_directory']),
dbesc($r[0]['site_realm']),
- intval($r[0]['site_valid'])
+ intval($r[0]['site_valid']),
+ dbesc($r[0]['site_crypto'])
);
$r = q("select * from site where site_flags in (%d, %d) and site_url != '%s' and site_type = %d ",
diff --git a/include/event.php b/include/event.php
index cbee2b759..f3366fb69 100644
--- a/include/event.php
+++ b/include/event.php
@@ -25,7 +25,7 @@ function format_event_html($ev) {
$o = '<div class="vevent">' . "\r\n";
- $o .= '<div class="event-title"><h3><i class="fa fa-calendar"></i>&nbsp;' . bbcode($ev['summary']) . '</h3></div>' . "\r\n";
+ $o .= '<div class="event-title"><h3><i class="fa fa-calendar"></i>&nbsp;' . zidify_links(smilies(bbcode($ev['summary']))) . '</h3></div>' . "\r\n";
$o .= '<div class="event-start"><span class="event-label">' . t('Starts:') . '</span>&nbsp;<span class="dtstart" title="'
. datetime_convert('UTC', 'UTC', $ev['dtstart'], (($ev['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' ))
@@ -46,11 +46,11 @@ function format_event_html($ev) {
$ev['dtend'] , $bd_format )))
. '</span></div>' . "\r\n";
- $o .= '<div class="event-description">' . bbcode($ev['description']) . '</div>' . "\r\n";
+ $o .= '<div class="event-description">' . zidify_links(smilies(bbcode($ev['description']))) . '</div>' . "\r\n";
if(strlen($ev['location']))
$o .= '<div class="event-location"><span class="event-label"> ' . t('Location:') . '</span>&nbsp;<span class="location">'
- . bbcode($ev['location'])
+ . zidify_links(smilies(bbcode($ev['location'])))
. '</span></div>' . "\r\n";
$o .= '</div>' . "\r\n";
@@ -69,7 +69,7 @@ function format_event_obj($jobject) {
$bd_format = t('l F d, Y \@ g:i A'); // Friday January 18, 2011 @ 8:01 AM
$event['header'] = replace_macros(get_markup_template('event_item_header.tpl'),array(
- '$title' => bbcode($object['title']),
+ '$title' => zidify_links(smilies(bbcode($object['title']))),
'$dtstart_label' => t('Starts:'),
'$dtstart_title' => datetime_convert('UTC', 'UTC', $object['dtstart'], (($object['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' )),
'$dtstart_dt' => (($object['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(), $object['dtstart'] , $bd_format )) : day_translate(datetime_convert('UTC', 'UTC', $object['dtstart'] , $bd_format))),
@@ -80,9 +80,9 @@ function format_event_obj($jobject) {
));
$event['content'] = replace_macros(get_markup_template('event_item_content.tpl'),array(
- '$description' => bbcode($object['description']),
+ '$description' => zidify_links(smilies(bbcode($object['description']))),
'$location_label' => t('Location:'),
- '$location' => bbcode($object['location'])
+ '$location' => zidify_links(smilies(bbcode($object['location'])))
));
}
@@ -127,12 +127,18 @@ function format_event_ical($ev) {
$o .= "\r\nDTSTART:" . datetime_convert('UTC','UTC', $ev['dtstart'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : ''));
if($ev['dtend'] && ! $ev['nofinish'])
$o .= "\r\nDTEND:" . datetime_convert('UTC','UTC', $ev['dtend'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : ''));
- if($ev['summary'])
+ if($ev['summary']) {
$o .= "\r\nSUMMARY:" . format_ical_text($ev['summary']);
- if($ev['location'])
+ $o .= "\r\nX-ZOT-SUMMARY:" . format_ical_sourcetext($ev['summary']);
+ }
+ if($ev['location']) {
$o .= "\r\nLOCATION:" . format_ical_text($ev['location']);
- if($ev['description'])
+ $o .= "\r\nX-ZOT-LOCATION:" . format_ical_sourcetext($ev['location']);
+ }
+ if($ev['description']) {
$o .= "\r\nDESCRIPTION:" . format_ical_text($ev['description']);
+ $o .= "\r\nX-ZOT-DESCRIPTION:" . format_ical_sourcetext($ev['description']);
+ }
if($ev['event_priority'])
$o .= "\r\nPRIORITY:" . intval($ev['event_priority']);
$o .= "\r\nUID:" . $ev['event_hash'] ;
@@ -154,8 +160,10 @@ function format_todo_ical($ev) {
$o .= "\r\nDTSTART:" . datetime_convert('UTC','UTC', $ev['dtstart'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : ''));
if($ev['dtend'] && ! $ev['nofinish'])
$o .= "\r\nDUE:" . datetime_convert('UTC','UTC', $ev['dtend'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : ''));
- if($ev['summary'])
+ if($ev['summary']) {
$o .= "\r\nSUMMARY:" . format_ical_text($ev['summary']);
+ $o .= "\r\nX-ZOT-SUMMARY:" . format_ical_sourcetext($ev['summary']);
+ }
if($ev['event_status']) {
$o .= "\r\nSTATUS:" . $ev['event_status'];
if($ev['event_status'] === 'COMPLETED')
@@ -165,10 +173,14 @@ function format_todo_ical($ev) {
$o .= "\r\nPERCENT-COMPLETE:" . $ev['event_percent'];
if(intval($ev['event_sequence']))
$o .= "\r\nSEQUENCE:" . $ev['event_sequence'];
- if($ev['location'])
+ if($ev['location']) {
$o .= "\r\nLOCATION:" . format_ical_text($ev['location']);
- if($ev['description'])
+ $o .= "\r\nX-ZOT-LOCATION:" . format_ical_sourcetext($ev['location']);
+ }
+ if($ev['description']) {
$o .= "\r\nDESCRIPTION:" . format_ical_text($ev['description']);
+ $o .= "\r\nX-ZOT-DESCRIPTION:" . format_ical_sourcetext($ev['description']);
+ }
$o .= "\r\nUID:" . $ev['event_hash'] ;
if($ev['event_priority'])
$o .= "\r\nPRIORITY:" . intval($ev['event_priority']);
@@ -178,7 +190,6 @@ function format_todo_ical($ev) {
}
-
function format_ical_text($s) {
require_once('include/bbcode.php');
require_once('include/html2plain.php');
@@ -186,6 +197,12 @@ function format_ical_text($s) {
$s = html2plain(bbcode($s));
$s = str_replace(["\r\n","\n"],["",""],$s);
return(wordwrap(str_replace(['\\',',',';'],['\\\\','\\,','\\;'],$s),72,"\r\n ",true));
+
+}
+
+function format_ical_sourcetext($s) {
+ $s = base64_encode($s);
+ return(wordwrap(str_replace(['\\',',',';'],['\\\\','\\,','\\;'],$s),72,"\r\n ",true));
}
@@ -623,12 +640,21 @@ function event_import_ical($ical, $uid) {
$ev['edited'] = datetime_convert('UTC','UTC',$edited->format(\DateTime::W3C));
}
- if(isset($ical->LOCATION))
+ if(isset($ical->{'X-ZOT-LOCATION'}))
+ $ev['location'] = event_ical_get_sourcetext( (string) $ical->{'X-ZOT-LOCATION'});
+ elseif(isset($ical->LOCATION))
$ev['location'] = (string) $ical->LOCATION;
- if(isset($ical->DESCRIPTION))
+
+ if(isset($ical->{'X-ZOT-DESCRIPTION'}))
+ $ev['description'] = event_ical_get_sourcetext( (string) $ical->{'X-ZOT-DESCRIPTION'});
+ elseif(isset($ical->DESCRIPTION))
$ev['description'] = (string) $ical->DESCRIPTION;
- if(isset($ical->SUMMARY))
+
+ if(isset($ical->{'X-ZOT-SUMMARY'}))
+ $ev['summary'] = event_ical_get_sourcetext( (string) $ical->{'X-ZOT-SUMMARY'});
+ elseif(isset($ical->SUMMARY))
$ev['summary'] = (string) $ical->SUMMARY;
+
if(isset($ical->PRIORITY))
$ev['event_priority'] = intval((string) $ical->PRIORITY);
@@ -663,6 +689,10 @@ function event_import_ical($ical, $uid) {
}
+function event_ical_get_sourcetext($s) {
+ return base64_decode($s);
+}
+
function event_import_ical_task($ical, $uid) {
$c = q("select * from channel where channel_id = %d limit 1",
@@ -718,12 +748,21 @@ function event_import_ical_task($ical, $uid) {
$ev['edited'] = datetime_convert('UTC','UTC',$edited->format(\DateTime::W3C));
}
- if(isset($ical->LOCATION))
+ if(isset($ical->{'X-ZOT-LOCATION'}))
+ $ev['location'] = event_ical_get_sourcetext( (string) $ical->{'X-ZOT-LOCATION'});
+ elseif(isset($ical->LOCATION))
$ev['location'] = (string) $ical->LOCATION;
- if(isset($ical->DESCRIPTION))
+
+ if(isset($ical->{'X-ZOT-DESCRIPTION'}))
+ $ev['description'] = event_ical_get_sourcetext( (string) $ical->{'X-ZOT-DESCRIPTION'});
+ elseif(isset($ical->DESCRIPTION))
$ev['description'] = (string) $ical->DESCRIPTION;
- if(isset($ical->SUMMARY))
+
+ if(isset($ical->{'X-ZOT-SUMMARY'}))
+ $ev['summary'] = event_ical_get_sourcetext( (string) $ical->{'X-ZOT-SUMMARY'});
+ elseif(isset($ical->SUMMARY))
$ev['summary'] = (string) $ical->SUMMARY;
+
if(isset($ical->PRIORITY))
$ev['event_priority'] = intval((string) $ical->PRIORITY);
diff --git a/include/features.php b/include/features.php
index 1ccdbf015..8ff0d2d21 100644
--- a/include/features.php
+++ b/include/features.php
@@ -157,6 +157,15 @@ function get_features($filtered = true) {
feature_level('smart_birthdays',2),
],
+ [
+ 'event_tz_select',
+ t('Event Timezone Selection'),
+ t('Allow event creation in timezones other than your own.'),
+ false,
+ get_config('feature_lock','event_tz_select'),
+ feature_level('event_tz_select',2),
+ ],
+
[
'advanced_dirsearch',
t('Advanced Directory Search'),
diff --git a/include/feedutils.php b/include/feedutils.php
index 1d58ec317..68ac20782 100644
--- a/include/feedutils.php
+++ b/include/feedutils.php
@@ -236,7 +236,7 @@ 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'] = base64url_encode(unxmlify($item->get_id()));
+ $res['mid'] = unxmlify($item->get_id());
$res['title'] = unxmlify($item->get_title());
$res['body'] = unxmlify($item->get_content());
$res['plink'] = unxmlify($item->get_link(0));
@@ -331,6 +331,8 @@ function get_atom_elements($feed, $item, &$author) {
}
}
+ $ostatus_protocol = (($item->get_item_tags(NAMESPACE_OSTATUS,'conversation')) ? true : false);
+
$apps = $item->get_item_tags(NAMESPACE_STATUSNET,'notice_info');
if($apps && $apps[0]['attribs']['']['source']) {
$res['app'] = strip_tags(unxmlify($apps[0]['attribs']['']['source']));
@@ -343,6 +345,8 @@ function get_atom_elements($feed, $item, &$author) {
$have_real_body = false;
$rawenv = $item->get_item_tags(NAMESPACE_DFRN, 'env');
+ if(! $rawenv)
+ $rawenv = $item->get_item_tags(NAMESPACE_ZOT,'source');
if($rawenv) {
$have_real_body = true;
$res['body'] = $rawenv[0]['data'];
@@ -388,7 +392,15 @@ function get_atom_elements($feed, $item, &$author) {
$res['body'] = escape_tags($res['body']);
}
- if($res['plink'] && $res['title']) {
+
+ // strip title and don't apply "title-in-body" if the feed involved
+ // uses the OStatus stack. We need a more generalised way for the calling
+ // function to specify this behaviour or for plugins to alter it.
+
+ if($ostatus_protocol) {
+ $res['title'] = '';
+ }
+ elseif($res['plink'] && $res['title']) {
$res['body'] = '#^[url=' . $res['plink'] . ']' . $res['title'] . '[/url]' . "\n\n" . $res['body'];
$terms = array();
$terms[] = array(
@@ -623,14 +635,15 @@ function get_atom_elements($feed, $item, &$author) {
$res['target'] = $obj;
}
- $arr = array('feed' => $feed, 'item' => $item, 'result' => $res);
+ $arr = array('feed' => $feed, 'item' => $item, 'author' => $author, 'result' => $res);
call_hooks('parse_atom', $arr);
- logger('get_atom_elements: author: ' . print_r($author,true),LOGGER_DATA);
- logger('get_atom_elements: ' . print_r($res,true),LOGGER_DATA);
+ logger('get_atom_elements: author: ' . print_r($arr['author'],true),LOGGER_DATA);
+
+ logger('get_atom_elements: ' . print_r($arr['result'],true),LOGGER_DATA);
- return $res;
+ return $arr['result'];
}
function encode_rel_links($links) {
@@ -730,7 +743,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
if($deleted && is_array($contact)) {
$r = q("SELECT * from item where mid = '%s' and author_xchan = '%s' and uid = %d limit 1",
- dbesc(base64url_encode($mid)),
+ dbesc($mid),
dbesc($contact['xchan_hash']),
intval($importer['channel_id'])
);
@@ -739,7 +752,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
$item = $r[0];
if(! intval($item['item_deleted'])) {
- logger('consume_feed: deleting item ' . $item['id'] . ' mid=' . base64url_decode($item['mid']), LOGGER_DEBUG);
+ logger('consume_feed: deleting item ' . $item['id'] . ' mid=' . $item['mid'], LOGGER_DEBUG);
drop_item($item['id'],false);
}
}
@@ -758,14 +771,14 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
foreach($items as $item) {
$is_reply = false;
- $item_id = base64url_encode($item->get_id());
+ $item_id = $item->get_id();
- logger('consume_feed: processing ' . $item_id, LOGGER_DEBUG);
+ logger('consume_feed: processing ' . $raw_item_id, LOGGER_DEBUG);
$rawthread = $item->get_item_tags( NAMESPACE_THREAD,'in-reply-to');
if(isset($rawthread[0]['attribs']['']['ref'])) {
$is_reply = true;
- $parent_mid = base64url_encode($rawthread[0]['attribs']['']['ref']);
+ $parent_mid = $rawthread[0]['attribs']['']['ref'];
}
if($is_reply) {
@@ -775,7 +788,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
// Have we seen it? If not, import it.
- $item_id = base64url_encode($item->get_id());
+ $item_id = $item->get_id();
$author = array();
$datarray = get_atom_elements($feed,$item,$author);
@@ -824,7 +837,16 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
continue;
}
+ $x = q("select mid from item where mid = '%s' and uid = %d limit 1",
+ dbesc($parent_mid),
+ intval($importer['channel_id'])
+ );
+ if($x)
+ $parent_mid = $x[0]['mid'];
+
$datarray['parent_mid'] = $parent_mid;
+
+
$datarray['aid'] = $importer['channel_account_id'];
$datarray['uid'] = $importer['channel_id'];
@@ -838,7 +860,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
// Head post of a conversation. Have we seen it? If not, import it.
- $item_id = base64url_encode($item->get_id());
+ $item_id = $item->get_id();
$author = array();
$datarray = get_atom_elements($feed,$item,$author);
@@ -983,14 +1005,14 @@ function process_salmon_feed($xml, $importer) {
foreach($items as $item) {
- $item_id = base64url_encode($item->get_id());
+ $item_id = $item->get_id();
logger('processing ' . $item_id, LOGGER_DEBUG);
$rawthread = $item->get_item_tags( NAMESPACE_THREAD,'in-reply-to');
if(isset($rawthread[0]['attribs']['']['ref'])) {
$is_reply = true;
- $parent_mid = base64url_encode($rawthread[0]['attribs']['']['ref']);
+ $parent_mid = $rawthread[0]['attribs']['']['ref'];
}
if($is_reply)
@@ -1160,6 +1182,7 @@ function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) {
if(($item['parent'] != $item['id']) || ($item['parent_mid'] !== $item['mid']) || (($item['thr_parent'] !== '') && ($item['thr_parent'] !== $item['mid']))) {
$parent_item = (($item['thr_parent']) ? $item['thr_parent'] : $item['parent_mid']);
$o .= '<thr:in-reply-to ref="' . z_root() . '/display/' . xmlify($parent_item) . '" type="text/html" href="' . xmlify($item['plink']) . '" />' . "\r\n";
+
}
if(activity_match($item['obj_type'],ACTIVITY_OBJ_EVENT) && activity_match($item['verb'],ACTIVITY_POST)) {
@@ -1206,26 +1229,67 @@ function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) {
if(strlen($actarg))
$o .= $actarg;
- // FIXME
-// $tags = item_getfeedtags($item);
-// if(count($tags)) {
-// foreach($tags as $t) {
-// $o .= '<category scheme="X-DFRN:' . xmlify($t[0]) . ':' . xmlify($t[1]) . '" term="' . xmlify($t[2]) . '" />' . "\r\n";
-// }
-// }
-// FIXME
-// $o .= item_getfeedattach($item);
+ if($item['attach']) {
+ $enclosures = json_decode($item['attach'],true);
+ if($enclosures) {
+ foreach($enclosures as $enc) {
+ $o .= '<link rel="enclosure" '
+ . (($enc['href']) ? 'href="' . $enc['href'] . '" ' : '')
+ . (($enc['length']) ? 'length="' . $enc['length'] . '" ' : '')
+ . (($enc['type']) ? 'type="' . $enc['type'] . '" ' : '')
+ . ' />';
+ }
+ }
+ }
-// $mentioned = get_mentions($item,$tags);
-// if($mentioned)
-// $o .= $mentioned;
+ if($item['term']) {
+ foreach($item['term'] as $term) {
+ $scheme = '';
+ $label = '';
+ switch($term['ttype']) {
+ case TERM_UNKNOWN:
+ $scheme = NAMESPACE_ZOT . '/term/unknown';
+ $label = $term['term'];
+ break;
+ case TERM_HASHTAG:
+ case TERM_COMMUNITYTAG:
+ $scheme = NAMESPACE_ZOT . '/term/hashtag';
+ $label = '#' . $term['term'];
+ break;
+ case TERM_MENTION:
+ $scheme = NAMESPACE_ZOT . '/term/mention';
+ $label = '@' . $term['term'];
+ break;
+ case TERM_CATEGORY:
+ $scheme = NAMESPACE_ZOT . '/term/category';
+ $label = $term['term'];
+ break;
+ default:
+ break;
+ }
+ if(! $scheme)
+ continue;
- call_hooks('atom_entry', $o);
+ $o .= '<category scheme="' . $scheme . '" term="' . $term['term'] . '" label="' . $label . '" />' . "\r\n";
+ }
+ }
$o .= '</entry>' . "\r\n";
- return $o;
+ $x = [
+ 'item' => $item,
+ 'type' => $type,
+ 'author' => $author,
+ 'owner' => $owner,
+ 'comment' => $comment,
+ 'abook_id' => $cid,
+ 'entry' => $o
+ ];
+
+ call_hooks('atom_entry', $x);
+
+ return $x['entry'];
}
diff --git a/include/help.php b/include/help.php
index f7fffc4d4..6e779f000 100644
--- a/include/help.php
+++ b/include/help.php
@@ -15,7 +15,7 @@ function get_help_content($tocpath = false) {
$text = '';
$path = (($tocpath !== false) ? $tocpath : '');
-
+
if($tocpath === false && argc() > 1) {
$path = '';
for($x = 1; $x < argc(); $x ++) {
@@ -55,6 +55,7 @@ function get_help_content($tocpath = false) {
if(! $text) {
$doctype = 'bbcode';
$text = load_doc_file('doc/main.bb');
+ goaway('/help/about/about_hubzilla');
\App::$page['title'] = t('Help');
}
@@ -68,7 +69,7 @@ function get_help_content($tocpath = false) {
}
if($doctype === 'html')
- $content = $text;
+ $content = parseIdentityAwareHTML($text);
if($doctype === 'markdown') {
require_once('library/markdown.php');
# escape #include tags
@@ -78,7 +79,7 @@ function get_help_content($tocpath = false) {
}
if($doctype === 'bbcode') {
require_once('include/bbcode.php');
- $content = bbcode($text);
+ $content = zidify_links(bbcode($text));
// bbcode retargets external content to new windows. This content is internal.
$content = str_replace(' target="_blank"', '', $content);
}
@@ -94,7 +95,7 @@ function preg_callback_help_include($matches) {
$include = str_replace($matches[0],load_doc_file($matches[1]),$matches[0]);
if(preg_match('/\.bb$/', $matches[1]) || preg_match('/\.txt$/', $matches[1])) {
require_once('include/bbcode.php');
- $include = bbcode($include);
+ $include = zidify_links(bbcode($include));
$include = str_replace(' target="_blank"','',$include);
}
elseif(preg_match('/\.md$/', $matches[1])) {
diff --git a/include/html2plain.php b/include/html2plain.php
index 2f5be7f69..979354079 100644
--- a/include/html2plain.php
+++ b/include/html2plain.php
@@ -113,7 +113,7 @@ function html2plain($html, $wraplength = 75, $compact = false)
$xpath = new DomXPath($doc);
$list = $xpath->query("//pre");
foreach ($list as $node) {
- $node->nodeValue = str_replace("\n", "\r", $node->nodeValue);
+ $node->nodeValue = str_replace("\n", "\r", htmlspecialchars($node->nodeValue));
}
$message = $doc->saveHTML();
diff --git a/include/hubloc.php b/include/hubloc.php
index 17f921f67..6f81ea31f 100644
--- a/include/hubloc.php
+++ b/include/hubloc.php
@@ -200,6 +200,14 @@ function xchan_store($arr) {
if(! $arr['photo'])
$arr['photo'] = z_root() . '/' . get_default_profile_photo();
+
+ if($arr['network'] === 'zot') {
+ if((! $arr['key']) || (! rsa_verify($arr['guid'],base64url_decode($arr['guid_sig']),$arr['key']))) {
+ logger('Unable to verify signature for ' . $arr['hash']);
+ return false;
+ }
+ }
+
$r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_guid_sig, xchan_pubkey, xchan_addr, xchan_url, xchan_connurl, xchan_follow, xchan_connpage, xchan_name, xchan_network, xchan_instance_url, xchan_hidden, xchan_orphan, xchan_censored, xchan_selfcensored, xchan_system, xchan_pubforum, xchan_deleted, xchan_name_date ) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s','%s','%s','%s',%d, %d, %d, %d, %d, %d, %d, '%s') ",
dbesc($arr['hash']),
dbesc($arr['guid']),
diff --git a/include/import.php b/include/import.php
index 0d8398acb..e3d3e7e81 100644
--- a/include/import.php
+++ b/include/import.php
@@ -86,7 +86,7 @@ function import_channel($channel, $account_id, $seize) {
}
if(! $r) {
- logger('mod_import: channel clone failed. ', print_r($channel,true));
+ logger('mod_import: channel clone failed. ' . print_r($channel,true));
notice( t('Channel clone failed. Import failed.') . EOL);
return false;
}
@@ -96,7 +96,7 @@ function import_channel($channel, $account_id, $seize) {
$channel['channel_guid'] // Already dbesc'd
);
if(! $r) {
- logger('mod_import: channel not found. ', print_r($channel,true));
+ logger('mod_import: channel not found. ' . print_r($channel,true));
notice( t('Cloned channel not found. Import failed.') . EOL);
return false;
}
diff --git a/include/items.php b/include/items.php
index 4ac4d6049..57a9022da 100755
--- a/include/items.php
+++ b/include/items.php
@@ -1463,6 +1463,11 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
$ret = array('success' => false, 'item_id' => 0);
+ if(array_key_exists('cancel',$arr) && $arr['cancel']) {
+ logger('cancelled by plugin');
+ return $ret;
+ }
+
if(! $arr['uid']) {
logger('item_store: no uid');
$ret['message'] = 'No uid.';
@@ -1522,7 +1527,7 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
// 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']));
- if(local_channel() && (! $arr['sig'])) {
+ 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']));
@@ -1808,6 +1813,7 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
$x = q("update item set parent = id where id = %d",
intval($r[0]['id'])
);
+ $arr['parent'] = $r[0]['id'];
}
@@ -1841,18 +1847,22 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
call_hooks('post_remote_end',$arr);
- // update the commented timestamp on the parent
+ // 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.
- $z = q("select max(created) as commented from item where parent_mid = '%s' and uid = %d and item_delayed = 0 ",
- dbesc($arr['parent_mid']),
- intval($arr['uid'])
- );
+ 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 ",
+ dbesc($arr['parent_mid']),
+ intval($arr['uid'])
+ );
- q("UPDATE item set commented = '%s', changed = '%s' WHERE id = %d",
- dbesc(($z) ? $z[0]['commented'] : (datetime_convert())),
- dbesc(datetime_convert()),
- intval($parent_id)
- );
+ q("UPDATE item set commented = '%s', changed = '%s' WHERE id = %d",
+ dbesc(($z) ? $z[0]['commented'] : (datetime_convert())),
+ dbesc(datetime_convert()),
+ intval($parent_id)
+ );
+ }
// If _creating_ a deleted item, don't propagate it further or send out notifications.
@@ -1881,6 +1891,12 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
$allow_exec = $d['allow_exec'];
$ret = array('success' => false, 'item_id' => 0);
+
+ if(array_key_exists('cancel',$arr) && $arr['cancel']) {
+ logger('cancelled by plugin');
+ return $ret;
+ }
+
if(! intval($arr['uid'])) {
logger('item_store_update: no uid');
$ret['message'] = 'no uid.';
@@ -1928,7 +1944,7 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
// 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']));
- if(local_channel() && (! $arr['sig'])) {
+ 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']));
@@ -1987,20 +2003,8 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
$arr['commented'] = $orig[0]['commented'];
- if($deliver) {
- $arr['received'] = datetime_convert();
- $arr['changed'] = datetime_convert();
- }
- else {
-
- // When deliver flag is false, we are *probably* performing an import or bulk migration.
- // If one updates the changed timestamp it will be made available to zotfeed and delivery
- // will still take place through backdoor methods. Since these fields are rarely used
- // otherwise, just preserve the original timestamp.
-
- $arr['received'] = $orig[0]['received'];
- $arr['changed'] = $orig[0]['changed'];
- }
+ $arr['received'] = $orig[0]['received'];
+ $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']);
@@ -3968,8 +3972,8 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
$sql_nets .= "( abook.abook_closeness >= " . intval($arr['cmin']) . " ";
$sql_nets .= " AND abook.abook_closeness <= " . intval($arr['cmax']) . " ) ";
- /** @fixme dead code, $cmax is undefined */
- if ($cmax == 99)
+
+ if ($arr['cmax'] == 99)
$sql_nets .= " OR abook.abook_closeness IS NULL ) ";
}
}
@@ -4104,25 +4108,21 @@ function webpage_to_namespace($webpage) {
function update_remote_id($channel,$post_id,$webpage,$pagetitle,$namespace,$remote_id,$mid) {
- $page_type = '';
-
if(! $post_id)
return;
- if($webpage == ITEM_TYPE_WEBPAGE)
- $page_type = 'WEBPAGE';
- elseif($webpage == ITEM_TYPE_BLOCK)
- $page_type = 'BUILDBLOCK';
- elseif($webpage == ITEM_TYPE_PDL)
- $page_type = 'PDL';
- elseif($webpage == ITEM_TYPE_DOC)
- $page_type = 'docfile';
- elseif($namespace && $remote_id) {
+ $page_type = webpage_to_namespace($webpage);
+
+ if($page_type == 'unknown' && $namespace && $remote_id) {
$page_type = $namespace;
$pagetitle = $remote_id;
}
+ else {
+ $page_type = '';
+ }
if($page_type) {
+
// store page info as an alternate message_id so we can access it via
// https://sitename/page/$channelname/$pagetitle
// if no pagetitle was given or it couldn't be transliterated into a url, use the first
diff --git a/include/menu.php b/include/menu.php
index b54ff7f9e..4add78c39 100644
--- a/include/menu.php
+++ b/include/menu.php
@@ -102,7 +102,7 @@ function menu_render($menu, $class='', $edit = false, $var = array()) {
if($menu['items'][$x]['mitem_flags'] & MENU_ITEM_NEWWIN)
$menu['items'][$x]['newwin'] = '1';
- $menu['items'][$x]['mitem_desc'] = bbcode($menu['items'][$x]['mitem_desc']);
+ $menu['items'][$x]['mitem_desc'] = zidify_links(smilies(bbcode($menu['items'][$x]['mitem_desc'])));
}
$wrap = (($var['wrap'] === 'none') ? false : true);
diff --git a/include/message.php b/include/message.php
index 7cbea3c6b..bde07afd8 100644
--- a/include/message.php
+++ b/include/message.php
@@ -8,7 +8,7 @@ require_once('include/attach.php');
// send a private message
-function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto='',$expires = ''){
+function send_message($uid = 0, $recipient = '', $body = '', $subject = '', $replyto = '', $expires = NULL_DATE) {
$ret = array('success' => false);
$is_reply = false;
@@ -16,19 +16,6 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto='
$a = get_app();
$observer_hash = get_observer_hash();
- if(! $recipient) {
- $ret['message'] = t('No recipient provided.');
- return $ret;
- }
-
- if(! strlen($subject))
- $subject = t('[no subject]');
-
-// if(! $expires)
-// $expires = NULL_DATE;
-// else
-// $expires = datetime_convert(date_default_timezone_get(),'UTC',$expires);
-
if($uid) {
$r = q("select * from channel where channel_id = %d limit 1",
@@ -47,6 +34,46 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto='
}
+ $body = cleanup_bbcode($body);
+ $results = linkify_tags($a, $body, $uid);
+
+
+ if(preg_match_all("/\[attachment\](.*?)\[\/attachment\]/",((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$match))
+ $attaches = $match[1];
+
+ $attachments = '';
+
+ if(preg_match_all('/(\[attachment\](.*?)\[\/attachment\])/',$body,$match)) {
+ $attachments = array();
+ foreach($match[2] as $mtch) {
+ $hash = substr($mtch,0,strpos($mtch,','));
+ $rev = intval(substr($mtch,strpos($mtch,',')));
+ $r = attach_by_hash_nodata($hash,get_observer_hash(),$rev);
+ if($r['success']) {
+ $attachments[] = array(
+ 'href' => z_root() . '/attach/' . $r['data']['hash'],
+ 'length' => $r['data']['filesize'],
+ 'type' => $r['data']['filetype'],
+ 'title' => urlencode($r['data']['filename']),
+ 'revision' => $r['data']['revision']
+ );
+ }
+ $body = trim(str_replace($match[1],'',$body));
+ }
+ }
+
+ $jattach = (($attachments) ? json_encode($attachments) : '');
+
+
+ if(! $recipient) {
+ $ret['message'] = t('No recipient provided.');
+ return $ret;
+ }
+
+ if(! strlen($subject))
+ $subject = t('[no subject]');
+
+
// look for any existing conversation structure
$conv_guid = '';
@@ -156,31 +183,6 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto='
$match = false;
- if(preg_match_all("/\[attachment\](.*?)\[\/attachment\]/",((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$match))
- $attaches = $match[1];
-
- $attachments = '';
-
- if(preg_match_all('/(\[attachment\](.*?)\[\/attachment\])/',$body,$match)) {
- $attachments = array();
- foreach($match[2] as $mtch) {
- $hash = substr($mtch,0,strpos($mtch,','));
- $rev = intval(substr($mtch,strpos($mtch,',')));
- $r = attach_by_hash_nodata($hash,get_observer_hash(),$rev);
- if($r['success']) {
- $attachments[] = array(
- 'href' => z_root() . '/attach/' . $r['data']['hash'],
- 'length' => $r['data']['filesize'],
- 'type' => $r['data']['filetype'],
- 'title' => urlencode($r['data']['filename']),
- 'revision' => $r['data']['revision']
- );
- }
- $body = trim(str_replace($match[1],'',$body));
- }
- }
-
- $jattach = (($attachments) ? json_encode($attachments) : '');
if($subject)
$subject = str_rot47(base64url_encode($subject));
diff --git a/include/nav.php b/include/nav.php
index c2a058457..2762e2a14 100644
--- a/include/nav.php
+++ b/include/nav.php
@@ -108,7 +108,7 @@ EOT;
if(feature_enabled($channel['channel_id'],'webpages') && (! $basic))
$nav['usermenu'][] = Array('webpages/' . $channel['channel_address'],t('Webpages'),"",t('Your webpages'),'webpages_nav_btn');
if(feature_enabled($channel['channel_id'],'wiki') && (! $basic))
- $nav['usermenu'][] = Array('wiki/' . $channel['channel_address'],t('Wiki'),"",t('Your wiki'),'wiki_nav_btn');
+ $nav['usermenu'][] = Array('wiki/' . $channel['channel_address'],t('Wikis'),"",t('Your wikis'),'wiki_nav_btn');
}
else {
if(! get_account_id()) {
@@ -127,26 +127,24 @@ EOT;
);
}
- if($observer) {
- $nav['lock'] = array('logout','','lock',
- sprintf( t('%s - click to logout'), $observer['xchan_addr']));
- }
elseif(! $_SESSION['authenticated']) {
$nav['loginmenu'][] = Array('rmagic',t('Remote authentication'),'',t('Click to authenticate to your home hub'),'rmagic_nav_btn');
}
- /**
- * "Home" should also take you home from an authenticated remote profile connection
- */
-
$homelink = get_my_url();
if(! $homelink) {
$observer = App::get_observer();
$homelink = (($observer) ? $observer['xchan_url'] : '');
}
- if(! local_channel())
- $nav['home'] = array($homelink, t('Home'), "", t('Home Page'),'home_nav_btn');
+ if(! local_channel()) {
+ $nav['rusermenu'] = array(
+ $homelink,
+ t('Get me home'),
+ 'logout',
+ t('Log me out of this site')
+ );
+ }
if(((get_config('system','register_policy') == REGISTER_OPEN) || (get_config('system','register_policy') == REGISTER_APPROVE)) && (! $_SESSION['authenticated']))
$nav['register'] = array('register',t('Register'), "", t('Create an account'),'register_nav_btn');
diff --git a/include/network.php b/include/network.php
index fe360c425..451ce12a1 100644
--- a/include/network.php
+++ b/include/network.php
@@ -59,7 +59,7 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) {
if(x($opts,'filep')) {
@curl_setopt($ch, CURLOPT_FILE, $opts['filep']);
- @curl_setopt($ch, CURLOPT_HEADER, $false);
+ @curl_setopt($ch, CURLOPT_HEADER, false);
}
if(x($opts,'upload'))
@@ -87,7 +87,7 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) {
@curl_setopt($ch, CURLOPT_TIMEOUT, $opts['timeout']);
}
else {
- $curl_time = intval(get_config('system','curl_timeout'));
+ $curl_time = intval(@get_config('system','curl_timeout'));
@curl_setopt($ch, CURLOPT_TIMEOUT, (($curl_time !== false) ? $curl_time : 60));
}
@@ -107,7 +107,7 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) {
@curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,
((x($opts,'novalidate') && intval($opts['novalidate'])) ? false : true));
- $prx = get_config('system','proxy');
+ $prx = @get_config('system','proxy');
if(strlen($prx)) {
@curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
@curl_setopt($ch, CURLOPT_PROXY, $prx);
@@ -226,7 +226,7 @@ function z_post_url($url,$params, $redirects = 0, $opts = array()) {
if(x($opts,'filep')) {
@curl_setopt($ch, CURLOPT_FILE, $opts['filep']);
- @curl_setopt($ch, CURLOPT_HEADER, $false);
+ @curl_setopt($ch, CURLOPT_HEADER, false);
}
if(x($opts,'headers')) {
@@ -246,7 +246,7 @@ function z_post_url($url,$params, $redirects = 0, $opts = array()) {
@curl_setopt($ch, CURLOPT_TIMEOUT, $opts['timeout']);
}
else {
- $curl_time = intval(get_config('system','curl_timeout'));
+ $curl_time = intval(@get_config('system','curl_timeout'));
@curl_setopt($ch, CURLOPT_TIMEOUT, (($curl_time !== false) ? $curl_time : 60));
}
diff --git a/include/oembed.php b/include/oembed.php
index 52fb04058..36395cfbc 100755
--- a/include/oembed.php
+++ b/include/oembed.php
@@ -104,7 +104,7 @@ function oembed_action($embedurl) {
function oembed_process($url) {
$j = oembed_fetch_url($url);
- logger('oembed_process: ' . print_r($j,true));
+ logger('oembed_process: ' . print_r($j,true), LOGGER_DATA, LOG_DEBUG);
if($j && $j['type'] !== 'error')
return '[embed]' . $url . '[/embed]';
return false;
@@ -135,19 +135,15 @@ function oembed_fetch_url($embedurl){
// we should try to cache this and avoid a lookup on each render
$zrl = is_matrix_url($embedurl);
+ $furl = ((local_channel() && $zrl) ? zid($embedurl) : $embedurl);
+
if($action !== 'block') {
- $txt = Zlib\Cache::get('[' . App::$videowidth . '] ' . $embedurl);
+ $txt = Zlib\Cache::get('[' . App::$videowidth . '] ' . $furl);
}
if(is_null($txt)) {
$txt = "";
- $furl = $embedurl;
-
- logger('local_channel: ' . local_channel());
-
- if(local_channel() && $zrl)
- $furl = zid($furl);
if ($action !== 'block') {
// try oembed autodiscovery
@@ -206,11 +202,10 @@ function oembed_fetch_url($embedurl){
//save in cache
if(! get_config('system','oembed_cache_disable'))
- Zlib\Cache::set('[' . App::$videowidth . '] ' . $embedurl,$txt);
+ Zlib\Cache::set('[' . App::$videowidth . '] ' . $furl, $txt);
}
-
$j = json_decode($txt,true);
if(! $j)
@@ -338,7 +333,7 @@ function oembed_iframe($src,$width,$height) {
// Make sure any children are sandboxed within their own iframe.
- return '<iframe ' . $scroll . 'height="' . $height . '" width="' . $width . '" src="' . $s . '" frameborder="no" >'
+ return '<iframe ' . $scroll . 'height="' . $height . '" width="' . $width . '" src="' . $s . '" allowfullscreen frameborder="no" >'
. t('Embedded content') . '</iframe>';
}
diff --git a/include/queue_fn.php b/include/queue_fn.php
index 1e3126f77..0950faf85 100644
--- a/include/queue_fn.php
+++ b/include/queue_fn.php
@@ -93,7 +93,7 @@ function queue_deliver($outq, $immediate = false) {
// your site has existed. Since we don't know for sure what these sites are,
// call them unknown
- q("insert into site (site_url, site_update, site_dead, site_type) values ('%s','%s',0,%d) ",
+ q("insert into site (site_url, site_update, site_dead, site_type, site_crypto) values ('%s','%s',0,%d,'') ",
dbesc($base),
dbesc(datetime_convert()),
intval(($outq['outq_driver'] === 'post') ? SITE_TYPE_NOTZOT : SITE_TYPE_UNKNOWN)
diff --git a/include/taxonomy.php b/include/taxonomy.php
index 067bd3246..0b4b2aa9a 100644
--- a/include/taxonomy.php
+++ b/include/taxonomy.php
@@ -386,7 +386,7 @@ function get_things($profile_hash,$uid) {
$things[$k] = null;
foreach($r as $rr) {
- $l = q("select xchan_name, xchan_photo_s, xchan_url from likes left join xchan on likee = xchan_hash where
+ $l = q("select xchan_name, xchan_photo_s, xchan_url from likes left join xchan on liker = xchan_hash where
target_type = '%s' and target_id = '%s' and channel_id = %d",
dbesc(ACTIVITY_OBJ_THING),
dbesc($rr['obj_obj']),
diff --git a/include/text.php b/include/text.php
index 12b37222b..fbf6df49e 100644
--- a/include/text.php
+++ b/include/text.php
@@ -656,11 +656,24 @@ function logger($msg, $level = LOGGER_NORMAL, $priority = LOG_INFO) {
function btlogger($msg, $level = LOGGER_NORMAL, $priority = LOG_INFO) {
logger($msg, $level, $priority);
+
+ if(file_exists('btlogger.log') && is_writable('btlogger.log')) {
+ $stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
+ $where = basename($stack[0]['file']) . ':' . $stack[0]['line'] . ':' . $stack[1]['function'] . ': ';
+ $s = datetime_convert() . ':' . log_priority_str($priority) . ':' . session_id() . ':' . $where . $msg . PHP_EOL;
+ @file_put_contents('btlogger.log', $s, FILE_APPEND);
+ }
+
if(version_compare(PHP_VERSION, '5.4.0') >= 0) {
$stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
if($stack) {
for($x = 1; $x < count($stack); $x ++) {
- logger('stack: ' . basename($stack[$x]['file']) . ':' . $stack[$x]['line'] . ':' . $stack[$x]['function'] . '()',$level, $priority);
+ $s = 'stack: ' . basename($stack[$x]['file']) . ':' . $stack[$x]['line'] . ':' . $stack[$x]['function'] . '()';
+ logger($s,$level, $priority);
+
+ if(file_exists('btlogger.log') && is_writable('btlogger.log')) {
+ @file_put_contents('btlogger.log', $s, FILE_APPEND);
+ }
}
}
}
@@ -2049,7 +2062,7 @@ function ids_to_array($arr,$idx = 'id') {
$t = array();
if($arr) {
foreach($arr as $x) {
- if(array_key_exists($idx,$x) && strlen($x[$idx]) && (! in_array($x[$idx],$t))) {
+ if(array_key_exists($idx,$x) && strlen($x[$idx]) && (! in_array($x[$idx],$t))) {
$t[] = $x[$idx];
}
}
@@ -2060,12 +2073,15 @@ function ids_to_array($arr,$idx = 'id') {
-function ids_to_querystr($arr,$idx = 'id') {
+function ids_to_querystr($arr,$idx = 'id',$quote = false) {
$t = array();
if($arr) {
foreach($arr as $x) {
if(! in_array($x[$idx],$t)) {
- $t[] = $x[$idx];
+ if($quote)
+ $t[] = "'" . dbesc($x[$idx]) . "'";
+ else
+ $t[] = $x[$idx];
}
}
}
@@ -3058,4 +3074,55 @@ function create_table_from_array($table, $arr) {
}
return $r;
+}
+
+
+
+function cleanup_bbcode($body) {
+
+
+ /**
+ * fix naked links by passing through a callback to see if this is a hubzilla site
+ * (already known to us) which will get a zrl, otherwise link with url, add bookmark tag to both.
+ * First protect any url inside certain bbcode tags so we don't double link it.
+ */
+
+ $body = preg_replace_callback('/\[code(.*?)\[\/(code)\]/ism','\red_escape_codeblock',$body);
+ $body = preg_replace_callback('/\[url(.*?)\[\/(url)\]/ism','\red_escape_codeblock',$body);
+ $body = preg_replace_callback('/\[zrl(.*?)\[\/(zrl)\]/ism','\red_escape_codeblock',$body);
+
+
+ $body = preg_replace_callback("/([^\]\='".'"'."\/]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\\
++\,\(\)]+)/ism", '\nakedoembed', $body);
+ $body = preg_replace_callback("/([^\]\='".'"'."\/]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\\
++\,\(\)]+)/ism", '\red_zrl_callback', $body);
+
+ $body = preg_replace_callback('/\[\$b64zrl(.*?)\[\/(zrl)\]/ism','\red_unescape_codeblock',$body);
+ $body = preg_replace_callback('/\[\$b64url(.*?)\[\/(url)\]/ism','\red_unescape_codeblock',$body);
+ $body = preg_replace_callback('/\[\$b64code(.*?)\[\/(code)\]/ism','\red_unescape_codeblock',$body);
+
+ // fix any img tags that should be zmg
+
+ $body = preg_replace_callback('/\[img(.*?)\](.*?)\[\/img\]/ism','\red_zrlify_img_callback',$body);
+
+
+ $body = bb_translate_video($body);
+
+ /**
+ * Fold multi-line [code] sequences
+ */
+
+ $body = preg_replace('/\[\/code\]\s*\[code\]/ism',"\n",$body);
+
+ $body = scale_external_images($body,false);
+
+
+ return $body;
+
+}
+
+// callback for array_walk
+
+function array_trim(&$v,$k) {
+ $v = trim($v);
} \ No newline at end of file
diff --git a/include/widgets.php b/include/widgets.php
index 3dc555b46..dde8e7cd0 100644
--- a/include/widgets.php
+++ b/include/widgets.php
@@ -778,7 +778,7 @@ function widget_conversations($arr) {
'$messages' => $messages
));
- $o .= alt_pager($a,count($r));
+ //$o .= alt_pager($a,count($r));
}
@@ -898,87 +898,17 @@ function widget_chatroom_members() {
}
function widget_wiki_list($arr) {
-
- require_once("include/wiki.php");
- $channel = null;
- if (argc() < 2 && local_channel()) {
- // This should not occur because /wiki should redirect to /wiki/channel ...
- $channel = \App::get_channel();
- } else {
- $channel = channelx_by_nick(argv(1)); // Channel being viewed by observer
- }
- if (!$channel) {
- return '';
- }
- // init() should have forced the URL to redirect to /wiki/channel so assume argc() > 1
- $nick = argv(1);
- $owner = channelx_by_nick($nick); // The channel who owns the wikis being viewed
- // Determine if the observer is the channel owner so the ACL dialog can be populated
- if (local_channel() === intval($owner['channel_id'])) {
-
- // Obtain the default permission settings of the channel
- $owner_acl = array(
- 'allow_cid' => $owner['channel_allow_cid'],
- 'allow_gid' => $owner['channel_allow_gid'],
- 'deny_cid' => $owner['channel_deny_cid'],
- 'deny_gid' => $owner['channel_deny_gid']
- );
- // Initialize the ACL to the channel default permissions
- $x = array(
- 'lockstate' => (( $owner['channel_allow_cid'] ||
- $owner['channel_allow_gid'] ||
- $owner['channel_deny_cid'] ||
- $owner['channel_deny_gid']) ? 'lock' : 'unlock'
- ),
- 'acl' => populate_acl($owner_acl),
- 'allow_cid' => acl2json($owner_acl['allow_cid']),
- 'allow_gid' => acl2json($owner_acl['allow_gid']),
- 'deny_cid' => acl2json($owner_acl['deny_cid']),
- 'deny_gid' => acl2json($owner_acl['deny_gid']),
- 'bang' => ''
- );
- } else {
- // Not the channel owner
- $owner_acl = $x = array();
- }
- if(argc()>1) {
- $activeWikiURLname = argv(2);
- } else {
- $activeWikiURLname = '';
- }
- logger($activeWikiURLname, LOGGER_DEBUG);
- $wikis = wiki_list($channel, get_observer_hash());
- foreach($wikis['wikis'] as &$w) {
- if($w['urlName'] === $activeWikiURLname) {
- $w['active'] = true;
- } else {
- $w['active'] = false;
- }
- }
- if ($wikis) {
- return replace_macros(get_markup_template('wikilist.tpl'), array(
- '$header' => t('Wiki List'),
- '$channel' => $channel['channel_address'],
- '$wikis' => $wikis['wikis'],
- // If the observer is the local channel owner, show the wiki controls
- '$owner' => ((local_channel() && local_channel() === intval(\App::$profile['uid'])) ? true : false),
- '$edit' => t('Edit'),
- '$download' => t('Download'),
- '$view' => t('View'),
- '$addnew' => t('Create new wiki'),
- '$create' => t('Create'),
- '$wikiName' => array('wikiName', t('Wiki name'), '', ''),
- '$lockstate' => $x['lockstate'],
- '$acl' => $x['acl'],
- '$allow_cid' => $x['allow_cid'],
- '$allow_gid' => $x['allow_gid'],
- '$deny_cid' => $x['deny_cid'],
- '$deny_gid' => $x['deny_gid'],
- '$bang' => $x['bang'],
- '$notify' => t('Send notification')
- ));
- }
- return '';
+ require_once("include/wiki.php");
+ $channel = channelx_by_n(App::$profile_uid);
+ $wikis = wiki_list($channel, get_observer_hash());
+ if($wikis) {
+ return replace_macros(get_markup_template('wikilist_widget.tpl'), array(
+ '$header' => t('Wiki List'),
+ '$channel' => $channel['channel_address'],
+ '$wikis' => $wikis['wikis']
+ ));
+ }
+ return '';
}
function widget_wiki_pages($arr) {
@@ -1017,6 +947,7 @@ function widget_wiki_pages($arr) {
'$pages' => $pages,
'$canadd' => $can_create,
'$addnew' => t('Add new page'),
+ '$pageName' => array('pageName', t('Page name')),
));
}
@@ -1027,7 +958,8 @@ function widget_wiki_page_history($arr) {
$pageHistory = wiki_page_history(array('resource_id' => $resource_id, 'pageUrlName' => $pageUrlName));
return replace_macros(get_markup_template('wiki_page_history.tpl'), array(
- '$pageHistory' => $pageHistory['history']
+ '$pageHistory' => $pageHistory['history'],
+ '$permsWrite' => $arr['permsWrite']
));
}
@@ -1472,14 +1404,23 @@ function widget_forums($arr) {
$perms_sql = item_permissions_sql(local_channel()) . item_normal();
- /**
- * We used to try and find public forums with custom permissions by checking to see if
- * send_stream was false and tag_deliver was true. However with the newer extensible
- * permissions infrastructure this makes for a very complicated query. Now we're only
- * checking channels that report themselves specifically as pubforums
- */
+ $xf = false;
+
+ $x1 = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'send_stream' and v = '0'",
+ intval(local_channel())
+ );
+ if($x1) {
+ $xc = ids_to_querystr($x1,'xchan',true);
+ $x2 = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'tag_deliver' and v = '1' and xchan in (" . $xc . ") ",
+ intval(local_channel())
+ );
+ if($x2)
+ $xf = ids_to_querystr($x2,'xchan',true);
+ }
+
+ $sql_extra = (($xf) ? " and ( xchan_hash in (" . $xf . ") or xchan_pubforum = 1 ) " : " and xchan_pubforum = 1 ");
- $r1 = q("select abook_id, xchan_hash, xchan_name, xchan_url, xchan_photo_s from abook left join xchan on abook_xchan = xchan_hash where xchan_pubforum = 1 and xchan_deleted = 0 and abook_channel = %d order by xchan_name $limit ",
+ $r1 = q("select abook_id, xchan_hash, xchan_name, xchan_url, xchan_photo_s from abook left join xchan on abook_xchan = xchan_hash where xchan_deleted = 0 and abook_channel = %d $sql_extra order by xchan_name $limit ",
intval(local_channel())
);
if(! $r1)
@@ -1563,7 +1504,6 @@ function widget_tasklist($arr) {
function widget_helpindex($arr) {
$o .= '<div class="widget">';
- $o .= '<h3>' . t('Documentation') . '</h3>';
$level_0 = get_help_content('sitetoc');
if(! $level_0)
diff --git a/include/wiki.php b/include/wiki.php
index bcdf9d7d8..922be6924 100644
--- a/include/wiki.php
+++ b/include/wiki.php
@@ -14,11 +14,13 @@ function wiki_list($channel, $observer_hash) {
intval($channel['channel_id'])
);
if($wikis) {
- foreach($wikis as &$w) {
+ foreach($wikis as &$w) {
$w['rawName'] = get_iconfig($w, 'wiki', 'rawName');
$w['htmlName'] = get_iconfig($w, 'wiki', 'htmlName');
$w['urlName'] = get_iconfig($w, 'wiki', 'urlName');
$w['path'] = get_iconfig($w, 'wiki', 'path');
+ $w['mimeType'] = get_iconfig($w, 'wiki', 'mimeType');
+ $w['lock'] = (($w['allow_cid'] || $w['allow_gid'] || $w['deny_cid'] || $w['deny_gid']) ? true : false);
}
}
// TODO: query db for wikis the observer can access. Return with two lists, for read and write access
@@ -31,14 +33,30 @@ function wiki_page_list($resource_id) {
if (!$w['path']) {
return array('pages' => null, 'wiki' => null);
}
- $pages = array();
+
+ $pages[] = [
+ 'resource_id' => '',
+ 'title' => 'Home',
+ 'url' => 'Home',
+ 'link_id' => 'id_wiki_home_0'
+ ];
+
if (is_dir($w['path']) === true) {
$files = array_diff(scandir($w['path']), array('.', '..', '.git'));
// TODO: Check that the files are all text files
-
+ $i = 1;
foreach($files as $file) {
- // strip the .md file extension and unwrap URL encoding to leave HTML encoded name
- $pages[] = array('title' => urldecode(substr($file, 0, -3)), 'url' => urlencode(substr($file, 0, -3)));
+ // strip the file extension and unwrap URL encoding to leave HTML encoded name
+ $title = substr($file, 0, strrpos($file,'.'));
+ if(urldecode($title) !== 'Home') {
+ $pages[] = [
+ 'resource_id' => $resource_id,
+ 'title' => urldecode($title),
+ 'url' => $title,
+ 'link_id' => 'id_' . substr($resource_id, 0, 10) . '_' . $i
+ ];
+ $i++;
+ }
}
}
@@ -75,7 +93,7 @@ function wiki_create_wiki($channel, $observer_hash, $wiki, $acl) {
$resource_id = random_string();
$r = q("SELECT mid FROM item WHERE resource_id = '%s' AND resource_type = '%s' AND uid = %d LIMIT 1",
dbesc($resource_id),
- dbesc(WIKI_ITEM_RESOURCE_TYPE),
+ dbesc(WIKI_ITEM_RESOURCE_TYPE),
intval($channel['channel_id'])
);
if (count($r))
@@ -123,11 +141,14 @@ function wiki_create_wiki($channel, $observer_hash, $wiki, $acl) {
if (!set_iconfig($arr, 'wiki', 'urlName', $wiki['urlName'], true)) {
return array('item' => null, 'success' => false);
}
+ if (!set_iconfig($arr, 'wiki', 'mimeType', $wiki['mimeType'], true)) {
+ return array('item' => null, 'success' => false);
+ }
$post = item_store($arr);
$item_id = $post['item_id'];
if ($item_id) {
- \Zotlabs\Daemon\Master::Summon(array('Notifier', 'activity', $item_id));
+ \Zotlabs\Daemon\Master::Summon(array('Notifier', 'activity', $item_id));
return array('item' => $post['item'], 'success' => true);
} else {
return array('item' => null, 'success' => false);
@@ -152,8 +173,8 @@ function wiki_delete_wiki($resource_id) {
function wiki_get_wiki($resource_id) {
$item = q("SELECT * FROM item WHERE resource_type = '%s' AND resource_id = '%s' AND item_deleted = 0 limit 1",
- dbesc(WIKI_ITEM_RESOURCE_TYPE),
- dbesc($resource_id)
+ dbesc(WIKI_ITEM_RESOURCE_TYPE),
+ dbesc($resource_id)
);
if (!$item) {
return array('wiki' => null, 'path' => null);
@@ -163,17 +184,21 @@ function wiki_get_wiki($resource_id) {
$rawName = get_iconfig($w, 'wiki', 'rawName');
$htmlName = get_iconfig($w, 'wiki', 'htmlName');
$urlName = get_iconfig($w, 'wiki', 'urlName');
+ $mimeType = get_iconfig($w, 'wiki', 'mimeType');
+
$path = get_iconfig($w, 'wiki', 'path');
if (!realpath(__DIR__ . '/../' . $path)) {
return array('wiki' => null, 'path' => null);
}
// Path to wiki exists
$abs_path = realpath(__DIR__ . '/../' . $path);
- return array( 'wiki' => $w,
- 'path' => $abs_path,
- 'rawName' => $rawName,
- 'htmlName' => $htmlName,
- 'urlName' => $urlName
+ return array(
+ 'wiki' => $w,
+ 'path' => $abs_path,
+ 'rawName' => $rawName,
+ 'htmlName' => $htmlName,
+ 'urlName' => $urlName,
+ 'mimeType' => $mimeType
);
}
}
@@ -202,8 +227,8 @@ function wiki_get_permissions($resource_id, $owner_id, $observer_hash) {
$r = q("SELECT * FROM item WHERE uid = %d and resource_type = '%s' AND resource_id = '%s' $sql_extra LIMIT 1",
intval($owner_id),
dbesc(WIKI_ITEM_RESOURCE_TYPE),
- dbesc($resource_id)
- );
+ dbesc($resource_id)
+ );
if (!$r) {
return array('read' => false, 'write' => false, 'success' => true);
@@ -220,7 +245,8 @@ function wiki_create_page($name, $resource_id) {
if (!$w['path']) {
return array('page' => null, 'wiki' => null, 'message' => 'Wiki not found.', 'success' => false);
}
- $page = array('rawName' => $name, 'htmlName' => escape_tags($name), 'urlName' => urlencode(escape_tags($name)), 'fileName' => urlencode(escape_tags($name)).'.md');
+
+ $page = array('rawName' => $name, 'htmlName' => escape_tags($name), 'urlName' => urlencode(escape_tags($name)), 'fileName' => urlencode(escape_tags($name)) . wiki_get_file_ext($w));
$page_path = $w['path'] . '/' . $page['fileName'];
if (is_file($page_path)) {
return array('page' => null, 'wiki' => null, 'message' => 'Page already exists.', 'success' => false);
@@ -242,11 +268,11 @@ function wiki_rename_page($arr) {
if (!$w['path']) {
return array('message' => 'Wiki not found.', 'success' => false);
}
- $page_path_old = $w['path'].'/'.$pageUrlName.'.md';
+ $page_path_old = $w['path'] . '/' . $pageUrlName . wiki_get_file_ext($w);
if (!is_readable($page_path_old) === true) {
return array('message' => 'Cannot read wiki page: ' . $page_path_old, 'success' => false);
}
- $page = array('rawName' => $pageNewName, 'htmlName' => escape_tags($pageNewName), 'urlName' => urlencode(escape_tags($pageNewName)), 'fileName' => urlencode(escape_tags($pageNewName)).'.md');
+ $page = array('rawName' => $pageNewName, 'htmlName' => escape_tags($pageNewName), 'urlName' => urlencode(escape_tags($pageNewName)), 'fileName' => urlencode(escape_tags($pageNewName)) . wiki_get_file_ext($w));
$page_path_new = $w['path'] . '/' . $page['fileName'] ;
if (is_file($page_path_new)) {
return array('message' => 'Page already exists.', 'success' => false);
@@ -267,7 +293,7 @@ function wiki_get_page_content($arr) {
if (!$w['path']) {
return array('content' => null, 'message' => 'Error reading wiki', 'success' => false);
}
- $page_path = $w['path'].'/'.$pageUrlName.'.md';
+ $page_path = $w['path'] . '/' . $pageUrlName . wiki_get_file_ext($w);
if (is_readable($page_path) === true) {
if(filesize($page_path) === 0) {
$content = '';
@@ -278,7 +304,7 @@ function wiki_get_page_content($arr) {
}
}
// TODO: Check that the files are all text files
- return array('content' => json_encode($content), 'message' => '', 'success' => true);
+ return array('content' => json_encode($content), 'mimeType' => $w['mimeType'], 'message' => '', 'success' => true);
}
}
@@ -289,7 +315,7 @@ function wiki_page_history($arr) {
if (!$w['path']) {
return array('history' => null, 'message' => 'Error reading wiki', 'success' => false);
}
- $page_path = $w['path'].'/'.$pageUrlName.'.md';
+ $page_path = $w['path'] . '/' . $pageUrlName . wiki_get_file_ext($w);
if (!is_readable($page_path) === true) {
return array('history' => null, 'message' => 'Cannot read wiki page: ' . $page_path, 'success' => false);
}
@@ -306,20 +332,48 @@ function wiki_page_history($arr) {
}
}
+function wiki_prepare_content($s) {
+
+ $text = preg_replace_callback('{
+ (?:\n\n|\A\n?)
+ ( # $1 = the code block -- one or more lines, starting with a space/tab
+ (?>
+ [ ]{'.'4'.'} # Lines must start with a tab or a tab-width of spaces
+ .*\n+
+ )+
+ )
+ ((?=^[ ]{0,'.'4'.'}\S)|\Z) # Lookahead for non-space at line-start, or end of doc
+ }xm',
+ 'wiki_prepare_content_callback', $s);
+
+ return $text;
+}
+
+function wiki_prepare_content_callback($matches) {
+ $codeblock = $matches[1];
+
+ $codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES, UTF8, false);
+ return "\n\n" . $codeblock ;
+}
+
+
+
function wiki_save_page($arr) {
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
- $content = ((array_key_exists('content',$arr)) ? purify_html($arr['content']) : '');
+ $content = ((array_key_exists('content',$arr)) ? purify_html(wiki_prepare_content($arr['content'])) : '');
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
$w = wiki_get_wiki($resource_id);
if (!$w['path']) {
return array('message' => 'Error reading wiki', 'success' => false);
}
- $page_path = $w['path'].'/'.$pageUrlName.'.md';
+
+ $fileName = $pageUrlName . wiki_get_file_ext($w);
+ $page_path = $w['path'] . '/' . $fileName;
if (is_writable($page_path) === true) {
if(!file_put_contents($page_path, $content)) {
return array('message' => 'Error writing to page file', 'success' => false);
}
- return array('message' => '', 'success' => true);
+ return array('message' => '', 'filename' => $filename, 'success' => true);
} else {
return array('message' => 'Page file not writable', 'success' => false);
}
@@ -332,7 +386,7 @@ function wiki_delete_page($arr) {
if (!$w['path']) {
return array('message' => 'Error reading wiki', 'success' => false);
}
- $page_path = $w['path'].'/'.$pageUrlName.'.md';
+ $page_path = $w['path'] . '/' . $pageUrlName . wiki_get_file_ext($w);
if (is_writable($page_path) === true) {
if(!unlink($page_path)) {
return array('message' => 'Error deleting page file', 'success' => false);
@@ -354,7 +408,7 @@ function wiki_revert_page($arr) {
if (!$w['path']) {
return array('content' => $content, 'message' => 'Error reading wiki', 'success' => false);
}
- $page_path = $w['path'].'/'.$pageUrlName.'.md';
+ $page_path = $w['path'] . '/' . $pageUrlName . wiki_get_file_ext($w);
if (is_writable($page_path) === true) {
$reponame = ((array_key_exists('title', $w['wiki'])) ? urlencode($w['wiki']['title']) : 'repo');
@@ -366,7 +420,7 @@ function wiki_revert_page($arr) {
try {
$git->setIdentity($observer['xchan_name'], $observer['xchan_addr']);
foreach ($git->git->tree($commitHash) as $object) {
- if ($object['type'] == 'blob' && $object['file'] === $pageUrlName.'.md' ) {
+ if ($object['type'] == 'blob' && $object['file'] === $pageUrlName . wiki_get_file_ext($w)) {
$content = $git->git->cat->blob($object['hash']);
}
}
@@ -391,7 +445,7 @@ function wiki_compare_page($arr) {
if (!$w['path']) {
return array('message' => 'Error reading wiki', 'success' => false);
}
- $page_path = $w['path'].'/'.$pageUrlName.'.md';
+ $page_path = $w['path'] . '/' . $pageUrlName . wiki_get_file_ext($w);
if (is_readable($page_path) === true) {
$reponame = ((array_key_exists('title', $w['wiki'])) ? urlencode($w['wiki']['title']) : 'repo');
if($reponame === '') {
@@ -401,12 +455,12 @@ function wiki_compare_page($arr) {
$compareContent = $currentContent = '';
try {
foreach ($git->git->tree($currentCommit) as $object) {
- if ($object['type'] == 'blob' && $object['file'] === $pageUrlName.'.md' ) {
+ if ($object['type'] == 'blob' && $object['file'] === $pageUrlName . wiki_get_file_ext($w)) {
$currentContent = $git->git->cat->blob($object['hash']);
}
}
foreach ($git->git->tree($compareCommit) as $object) {
- if ($object['type'] == 'blob' && $object['file'] === $pageUrlName.'.md' ) {
+ if ($object['type'] == 'blob' && $object['file'] === $pageUrlName . wiki_get_file_ext($w)) {
$compareContent = $git->git->cat->blob($object['hash']);
}
}
@@ -469,15 +523,6 @@ function wiki_git_commit($arr) {
}
}
-function wiki_generate_page_filename($name) {
- $file = urlencode(escape_tags($name));
- if( $file === '') {
- return null;
- } else {
- return $file . '.md';
- }
-}
-
function wiki_convert_links($s, $wikiURL) {
if (strpos($s,'[[') !== false) {
@@ -505,7 +550,6 @@ function wiki_convert_links($s, $wikiURL) {
* @return string
*/
function wiki_generate_toc($s) {
-
if (strpos($s,'[toc]') !== false) {
//$toc_md = wiki_toc($s); // Generate Markdown-formatted list prior to HTML render
$toc_md = '<ul id="wiki-toc"></ul>'; // use the available jQuery plugin http://ndabas.github.io/toc/
@@ -547,6 +591,13 @@ function wiki_bbcode($s) {
return $s;
}
+function wiki_get_file_ext($arr) {
+ if($arr['mimeType'] == 'text/bbcode')
+ return '.bb';
+ else
+ return '.md';
+}
+
// This function is derived from
// http://stackoverflow.com/questions/32068537/generate-table-of-contents-from-markdown-in-php
function wiki_toc($content) {
@@ -555,36 +606,36 @@ function wiki_toc($content) {
// look for markdown TOC items
preg_match_all(
- '/^(?:=|-|#).*$/m',
- $source,
- $matches,
- PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE
+ '/^(?:=|-|#).*$/m',
+ $source,
+ $matches,
+ PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE
);
// preprocess: iterate matched lines to create an array of items
// where each item is an array(level, text)
$file_size = strlen($source);
foreach ($matches[0] as $item) {
- $found_mark = substr($item[0], 0, 1);
- if ($found_mark == '#') {
- // text is the found item
- $item_text = $item[0];
- $item_level = strrpos($item_text, '#') + 1;
- $item_text = substr($item_text, $item_level);
- } else {
- // text is the previous line (empty if <hr>)
- $item_offset = $item[1];
- $prev_line_offset = strrpos($source, "\n", -($file_size - $item_offset + 2));
- $item_text =
- substr($source, $prev_line_offset, $item_offset - $prev_line_offset - 1);
- $item_text = trim($item_text);
- $item_level = $found_mark == '=' ? 1 : 2;
- }
- if (!trim($item_text) OR strpos($item_text, '|') !== FALSE) {
- // item is an horizontal separator or a table header, don't mind
- continue;
- }
- $raw_toc[] = ['level' => $item_level, 'text' => trim($item_text)];
+ $found_mark = substr($item[0], 0, 1);
+ if ($found_mark == '#') {
+ // text is the found item
+ $item_text = $item[0];
+ $item_level = strrpos($item_text, '#') + 1;
+ $item_text = substr($item_text, $item_level);
+ } else {
+ // text is the previous line (empty if <hr>)
+ $item_offset = $item[1];
+ $prev_line_offset = strrpos($source, "\n", -($file_size - $item_offset + 2));
+ $item_text =
+ substr($source, $prev_line_offset, $item_offset - $prev_line_offset - 1);
+ $item_text = trim($item_text);
+ $item_level = $found_mark == '=' ? 1 : 2;
+ }
+ if (!trim($item_text) OR strpos($item_text, '|') !== FALSE) {
+ // item is an horizontal separator or a table header, don't mind
+ continue;
+ }
+ $raw_toc[] = ['level' => $item_level, 'text' => trim($item_text)];
}
$o = '';
foreach($raw_toc as $t) {
diff --git a/include/zot.php b/include/zot.php
index 5c9fb4e82..96ec71112 100644
--- a/include/zot.php
+++ b/include/zot.php
@@ -110,20 +110,21 @@ function zot_get_hublocs($hash) {
* @param string $extra
* @returns string json encoded zot packet
*/
-function zot_build_packet($channel, $type = 'notify', $recipients = null, $remote_key = null, $secret = null, $extra = null) {
+function zot_build_packet($channel, $type = 'notify', $recipients = null, $remote_key = null, $methods = '', $secret = null, $extra = null) {
- $data = array(
+ $data = [
'type' => $type,
- 'sender' => array(
+ 'sender' => [
'guid' => $channel['channel_guid'],
'guid_sig' => base64url_encode(rsa_sign($channel['channel_guid'],$channel['channel_prvkey'])),
'url' => z_root(),
'url_sig' => base64url_encode(rsa_sign(z_root(),$channel['channel_prvkey'])),
'sitekey' => get_config('system','pubkey')
- ),
+ ],
'callback' => '/post',
- 'version' => ZOT_REVISION
- );
+ 'version' => ZOT_REVISION,
+ 'encryption' => crypto_methods()
+ ];
if ($recipients) {
for ($x = 0; $x < count($recipients); $x ++)
@@ -146,14 +147,54 @@ function zot_build_packet($channel, $type = 'notify', $recipients = null, $remot
// Hush-hush ultra top-secret mode
- if ($remote_key) {
- $data = crypto_encapsulate(json_encode($data),$remote_key);
+ if($remote_key) {
+ $algorithm = zot_best_algorithm($methods);
+ $data = crypto_encapsulate(json_encode($data),$remote_key, $algorithm);
}
return json_encode($data);
}
/**
+ * @brief choose best encryption function from those available on both sites
+ *
+ * @param string $methods
+ * comma separated list of encryption methods
+ * @return string first match from our site method preferences crypto_methods() array
+ * of a method which is common to both sites; or 'aes256cbc' if no matches are found.
+ */
+
+function zot_best_algorithm($methods) {
+
+ if(\Zotlabs\Lib\System::get_server_role() !== 'pro')
+ return 'aes256cbc';
+
+ $x = [ 'methods' => $methods, 'result' => '' ];
+ call_hooks('zot_best_algorithm',$x);
+ if($x['result'])
+ return $x['result'];
+
+ if($methods) {
+ $x = explode(',',$methods);
+ if($x) {
+ $y = crypto_methods();
+ if($y) {
+ foreach($y as $yv) {
+ $yv = trim($yv);
+ if(in_array($yv,$x)) {
+ return($yv);
+ }
+ }
+ }
+ }
+ }
+
+ return 'aes256cbc';
+}
+
+
+
+/**
* @brief
*
* @see z_post_url()
@@ -167,101 +208,11 @@ function zot_zot($url, $data) {
}
/**
- * @brief Look up information about channel.
- *
- * @param string $webbie
- * does not have to be host qualified e.g. 'foo' is treated as 'foo\@thishub'
- * @param array $channel
- * (optional), if supplied permissions will be enumerated specifically for $channel
- * @param boolean $autofallback
- * fallback/failover to http if https connection cannot be established. Default is true.
- *
- * @return array see z_post_url() and \ref Zotlabs::Zot::Finger "\\Zotlabs\\Zot\\Finger"
- */
-function zot_finger($webbie, $channel = null, $autofallback = true) {
-
- if (strpos($webbie,'@') === false) {
- $address = $webbie;
- $host = App::get_hostname();
- } else {
- $address = substr($webbie,0,strpos($webbie,'@'));
- $host = substr($webbie,strpos($webbie,'@')+1);
- if(strpos($host,'/'))
- $host = substr($host,0,strpos($host,'/'));
- }
-
- $xchan_addr = $address . '@' . $host;
-
- if ((! $address) || (! $xchan_addr)) {
- logger('zot_finger: no address :' . $webbie);
- return array('success' => false);
- }
- logger('using xchan_addr: ' . $xchan_addr, LOGGER_DATA, LOG_DEBUG);
-
- // potential issue here; the xchan_addr points to the primary hub.
- // The webbie we were called with may not, so it might not be found
- // unless we query for hubloc_addr instead of xchan_addr
-
- $r = q("select xchan.*, hubloc.* from xchan
- left join hubloc on xchan_hash = hubloc_hash
- where xchan_addr = '%s' and hubloc_primary = 1 limit 1",
- dbesc($xchan_addr)
- );
-
- if ($r) {
- $url = $r[0]['hubloc_url'];
-
- if ($r[0]['hubloc_network'] && $r[0]['hubloc_network'] !== 'zot') {
- logger('zot_finger: alternate network: ' . $webbie);
- logger('url: '.$url.', net: '.var_export($r[0]['hubloc_network'],true), LOGGER_DATA, LOG_DEBUG);
- return array('success' => false);
- }
- } else {
- $url = 'https://' . $host;
- }
-
- $rhs = '/.well-known/zot-info';
- $https = ((strpos($url,'https://') === 0) ? true : false);
-
- logger('zot_finger: ' . $address . ' at ' . $url, LOGGER_DEBUG);
-
- if ($channel) {
- $postvars = array(
- 'address' => $address,
- 'target' => $channel['channel_guid'],
- 'target_sig' => $channel['channel_guid_sig'],
- 'key' => $channel['channel_pubkey']
- );
-
- $result = z_post_url($url . $rhs,$postvars);
-
- if ((! $result['success']) && ($autofallback)) {
- if ($https) {
- logger('zot_finger: https failed. falling back to http');
- $result = z_post_url('http://' . $host . $rhs,$postvars);
- }
- }
- } else {
- $rhs .= '?f=&address=' . urlencode($address);
-
- $result = z_fetch_url($url . $rhs);
- if ((! $result['success']) && ($autofallback)) {
- if ($https) {
- logger('zot_finger: https failed. falling back to http');
- $result = z_fetch_url('http://' . $host . $rhs);
- }
- }
- }
-
- if (! $result['success'])
- logger('zot_finger: no results');
-
- return $result;
-}
-
-/**
* @brief Refreshes after permission changed or friending, etc.
*
+ * The top half of this function is similar to \Zotlabs\Zot\Finger::run() and could potentially be
+ * consolidated.
+ *
* zot_refresh is typically invoked when somebody has changed permissions of a channel and they are notified
* to fetch new permissions via a finger/discovery operation. This may result in a new connection
* (abook entry) being added to a local channel and it may result in auto-permissions being granted.
@@ -283,6 +234,7 @@ function zot_finger($webbie, $channel = null, $autofallback = true) {
*
* @returns boolean true if successful, else false
*/
+
function zot_refresh($them, $channel = null, $force = false) {
if (array_key_exists('xchan_network', $them) && ($them['xchan_network'] !== 'zot')) {
@@ -298,7 +250,8 @@ function zot_refresh($them, $channel = null, $force = false) {
if ($them['hubloc_url']) {
$url = $them['hubloc_url'];
- } else {
+ }
+ else {
$r = null;
// if they re-installed the server we could end up with the wrong record - pointing to the old install.
@@ -334,7 +287,7 @@ function zot_refresh($them, $channel = null, $force = false) {
$token = random_string();
- $postvars = array();
+ $postvars = [];
$postvars['token'] = $token;
@@ -395,10 +348,13 @@ function zot_refresh($them, $channel = null, $force = false) {
if($channel) {
if($j['permissions']['data']) {
- $permissions = crypto_unencapsulate(array(
+ $permissions = crypto_unencapsulate(
+ [
'data' => $j['permissions']['data'],
'key' => $j['permissions']['key'],
- 'iv' => $j['permissions']['iv']),
+ 'iv' => $j['permissions']['iv'],
+ 'alg' => $j['permissions']['alg']
+ ],
$channel['channel_prvkey']);
if($permissions)
$permissions = json_decode($permissions,true);
@@ -424,6 +380,10 @@ function zot_refresh($them, $channel = null, $force = false) {
$next_birthday = NULL_DATE;
}
+
+ // Keep original perms to check if we need to notify them
+ $previous_perms = get_all_perms($channel['channel_id'],$x['hash']);
+
$r = q("select * from abook where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 limit 1",
dbesc($x['hash']),
intval($channel['channel_id'])
@@ -487,10 +447,6 @@ function zot_refresh($them, $channel = null, $force = false) {
}
}
- // Keep original perms to check if we need to notify them
- $previous_perms = get_all_perms($channel['channel_id'],$x['hash']);
-
-
$closeness = get_pconfig($channel['channel_id'],'system','new_abook_closeness');
if($closeness === false)
$closeness = 80;
@@ -520,12 +476,14 @@ function zot_refresh($them, $channel = null, $force = false) {
if($new_connection) {
if(! \Zotlabs\Access\Permissions::PermsCompare($new_perms,$previous_perms))
Zotlabs\Daemon\Master::Summon(array('Notifier','permission_create',$new_connection[0]['abook_id']));
- Zotlabs\Lib\Enotify::submit(array(
+ Zotlabs\Lib\Enotify::submit(
+ [
'type' => NOTIFY_INTRO,
'from_xchan' => $x['hash'],
'to_xchan' => $channel['channel_hash'],
- 'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id'],
- ));
+ 'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id']
+ ]
+ );
if(intval($permissions['view_stream'])) {
if(intval(get_pconfig($channel['channel_id'],'perm_limits','send_stream') & PERMS_PENDING)
@@ -535,6 +493,7 @@ function zot_refresh($them, $channel = null, $force = false) {
/** If there is a default group for this channel, add this connection to it */
+
$default_group = $channel['channel_default_group'];
if($default_group) {
require_once('include/group.php');
@@ -580,6 +539,7 @@ function zot_refresh($them, $channel = null, $force = false) {
* @returns array|null null if site is blacklisted or not found, otherwise an
* array with an hubloc record
*/
+
function zot_gethub($arr, $multiple = false) {
if($arr['guid'] && $arr['guid_sig'] && $arr['url'] && $arr['url_sig']) {
@@ -592,7 +552,7 @@ function zot_gethub($arr, $multiple = false) {
$limit = (($multiple) ? '' : ' limit 1 ');
$sitekey = ((array_key_exists('sitekey',$arr) && $arr['sitekey']) ? " and hubloc_sitekey = '" . protect_sprintf($arr['sitekey']) . "' " : '');
- $r = q("select * from hubloc
+ $r = q("select hubloc.*, site.site_crypto from hubloc left join site on hubloc_url = site_url
where hubloc_guid = '%s' and hubloc_guid_sig = '%s'
and hubloc_url = '%s' and hubloc_url_sig = '%s'
$sitekey $limit",
@@ -629,9 +589,10 @@ function zot_gethub($arr, $multiple = false) {
* * \b success boolean true or false
* * \b message (optional) error string only if success is false
*/
+
function zot_register_hub($arr) {
- $result = array('success' => false);
+ $result = [ 'success' => false ];
if($arr['url'] && $arr['url_sig'] && $arr['guid'] && $arr['guid_sig']) {
@@ -690,6 +651,7 @@ function zot_register_hub($arr) {
* * \e boolean \b success boolean true or false
* * \e string \b message (optional) error string only if success is false
*/
+
function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) {
call_hooks('import_xchan', $arr);
@@ -788,7 +750,8 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) {
$what .= 'xchan ';
$changed = true;
}
- } else {
+ }
+ else {
$import_photos = true;
if((($arr['site']['directory_mode'] === 'standalone')
@@ -824,7 +787,7 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) {
$changed = true;
}
- if ($import_photos) {
+ if($import_photos) {
require_once('include/photo/photo_driver.php');
@@ -833,9 +796,9 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) {
$local = q("select channel_account_id, channel_id from channel where channel_hash = '%s' limit 1",
dbesc($xchan_hash)
);
- if ($local) {
+ if($local) {
$ph = z_fetch_url($arr['photo'], true);
- if ($ph['success']) {
+ if($ph['success']) {
$hash = import_channel_photo($ph['body'], $arr['photo_mimetype'], $local[0]['channel_account_id'], $local[0]['channel_id']);
@@ -873,11 +836,12 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) {
false
);
}
- } else {
+ }
+ else {
$photos = import_xchan_photo($arr['photo'], $xchan_hash);
}
- if ($photos) {
- if ($photos[4]) {
+ if($photos) {
+ if($photos[4]) {
// importing the photo failed somehow. Leave the photo_date alone so we can try again at a later date.
// This often happens when somebody joins the matrix with a bad cert.
$r = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s'
@@ -888,7 +852,8 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) {
dbesc($photos[3]),
dbesc($xchan_hash)
);
- } else {
+ }
+ else {
$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'",
dbescdate(datetime_convert('UTC','UTC',$arr['photo_updated'])),
@@ -945,7 +910,8 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) {
$what .= 'profile ';
$changed = true;
}
- } else {
+ }
+ else {
logger('import_xchan: profile not available - hiding');
// they may have made it private
$r = q("delete from xprof where xprof_hash = '%s'",
@@ -998,16 +964,17 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) {
* @param array $arr - output of z_post_url()
* @param array $outq - The queue structure attached to this request
*/
+
function zot_process_response($hub, $arr, $outq) {
- if (! $arr['success']) {
+ if(! $arr['success']) {
logger('zot_process_response: failed: ' . $hub);
return;
}
$x = json_decode($arr['body'], true);
- if (! $x) {
+ if(! $x) {
logger('zot_process_response: No json from ' . $hub);
logger('zot_process_response: headers: ' . print_r($arr['header'],true), LOGGER_DATA, LOG_DEBUG);
}
@@ -1065,6 +1032,7 @@ function zot_process_response($hub, $arr, $outq) {
* decrypted and json decoded notify packet from remote site
* @return array from zot_import()
*/
+
function zot_fetch($arr) {
logger('zot_fetch: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG);
@@ -1082,16 +1050,18 @@ function zot_fetch($arr) {
}
foreach($ret_hubs as $ret_hub) {
- $data = array(
- 'type' => 'pickup',
- 'url' => z_root(),
- 'callback_sig' => base64url_encode(rsa_sign(z_root() . '/post',get_config('system','prvkey'))),
- 'callback' => z_root() . '/post',
- 'secret' => $arr['secret'],
- 'secret_sig' => base64url_encode(rsa_sign($arr['secret'],get_config('system','prvkey')))
- );
- $datatosend = json_encode(crypto_encapsulate(json_encode($data),$ret_hub['hubloc_sitekey']));
+ $data = [
+ 'type' => 'pickup',
+ 'url' => z_root(),
+ 'callback_sig' => base64url_encode(rsa_sign(z_root() . '/post', get_config('system','prvkey'))),
+ 'callback' => z_root() . '/post',
+ 'secret' => $arr['secret'],
+ 'secret_sig' => base64url_encode(rsa_sign($arr['secret'], get_config('system','prvkey')))
+ ];
+
+ $algorithm = zot_best_algorithm($ret_hub['site_crypto']);
+ $datatosend = json_encode(crypto_encapsulate(json_encode($data),$ret_hub['hubloc_sitekey'], $algorithm));
$fetch = zot_zot($url,$datatosend);
@@ -1142,6 +1112,11 @@ function zot_import($arr, $sender_url) {
$data = json_decode(crypto_unencapsulate($data,get_config('system','prvkey')),true);
}
+ if(! is_array($data)) {
+ logger('decode error');
+ return array();
+ }
+
if(! $data['success']) {
if($data['message'])
logger('remote pickup failed: ' . $data['message']);
@@ -1167,6 +1142,12 @@ function zot_import($arr, $sender_url) {
logger('zot_import: notify: ' . print_r($i['notify'],true), LOGGER_DATA, LOG_DEBUG);
+ if(! is_array($i['notify'])) {
+ logger('decode error');
+ continue;
+ }
+
+
$hub = zot_gethub($i['notify']['sender']);
if((! $hub) || ($hub['hubloc_url'] != $sender_url)) {
logger('zot_import: potential forgery: wrong site for sender: ' . $sender_url . ' != ' . print_r($i['notify'],true));
@@ -1357,6 +1338,7 @@ function zot_import($arr, $sender_url) {
* @param array $msg
* @return NULL|array
*/
+
function public_recips($msg) {
require_once('include/channel.php');
@@ -1566,6 +1548,7 @@ function allowed_public_recips($msg) {
* @param boolean $request (optional) default false
* @return array
*/
+
function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $request = false) {
$result = array();
@@ -1799,7 +1782,7 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $
$result[] = $DR->get();
}
else {
- update_imported_item($sender,$arr,$r[0],$channel['channel_id']);
+ update_imported_item($sender,$arr,$r[0],$channel['channel_id'],$tag_delivery);
$DR->update('updated');
$result[] = $DR->get();
if(! $relay)
@@ -1875,6 +1858,7 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $
* * \e int \b mid
* @param int $uid
*/
+
function remove_community_tag($sender, $arr, $uid) {
if(! (activity_match($arr['verb'], ACTIVITY_TAG) && ($arr['obj_type'] == ACTIVITY_OBJ_TAGTERM)))
@@ -1945,7 +1929,8 @@ function remove_community_tag($sender, $arr, $uid) {
* @param array $orig
* @param int $uid
*/
-function update_imported_item($sender, $item, $orig, $uid) {
+
+function update_imported_item($sender, $item, $orig, $uid, $tag_delivery) {
// If this is a comment being updated, remove any privacy information
// so that item_store_update will set it from the original.
@@ -1958,6 +1943,15 @@ function update_imported_item($sender, $item, $orig, $uid) {
unset($item['item_private']);
}
+ // we need the tag_delivery check for downstream flowing posts as the stored post
+ // may have a different owner than the one being transmitted.
+
+ if(($sender['hash'] != $orig['owner_xchan'] && $sender['hash'] != $orig['author_xchan']) && (! $tag_delivery)) {
+ notice('sender is not owner or author');
+ return;
+ }
+
+
$x = item_store_update($item);
// If we're updating an event that we've saved locally, we store the item info first
@@ -1985,6 +1979,7 @@ function update_imported_item($sender, $item, $orig, $uid) {
* @param boolean $relay
* @return boolean|int post_id
*/
+
function delete_imported_item($sender, $item, $uid, $relay) {
logger('delete_imported_item invoked', LOGGER_DEBUG);
@@ -2002,13 +1997,14 @@ function delete_imported_item($sender, $item, $uid, $relay) {
intval($uid)
);
- if ($r) {
- if ($r[0]['author_xchan'] === $sender['hash'] || $r[0]['owner_xchan'] === $sender['hash'] || $r[0]['source_xchan'] === $sender['hash'])
+ if($r) {
+ if($r[0]['author_xchan'] === $sender['hash'] || $r[0]['owner_xchan'] === $sender['hash'] || $r[0]['source_xchan'] === $sender['hash'])
$ownership_valid = true;
$post_id = $r[0]['id'];
$item_found = true;
- } else {
+ }
+ else {
// perhaps the item is still in transit and the delete notification got here before the actual item did. Store it with the deleted flag set.
// item_store() won't try to deliver any notifications or start delivery chains if this flag is set.
@@ -2017,25 +2013,24 @@ function delete_imported_item($sender, $item, $uid, $relay) {
logger('delete received for non-existent item - storing item data.');
- /** @BUG $arr is undefined here, so this is dead code */
- if ($arr['author_xchan'] === $sender['hash'] || $arr['owner_xchan'] === $sender['hash'] || $arr['source_xchan'] === $sender['hash']) {
+ if($item['author_xchan'] === $sender['hash'] || $item['owner_xchan'] === $sender['hash'] || $item['source_xchan'] === $sender['hash']) {
$ownership_valid = true;
- $item_result = item_store($arr);
+ $item_result = item_store($item);
$post_id = $item_result['item_id'];
}
}
- if ($ownership_valid === false) {
+ if($ownership_valid === false) {
logger('delete_imported_item: failed: ownership issue');
return false;
}
require_once('include/items.php');
- if ($item_found) {
- if (intval($r[0]['item_deleted'])) {
+ if($item_found) {
+ if(intval($r[0]['item_deleted'])) {
logger('delete_imported_item: item was already deleted');
- if (! $relay)
+ if(! $relay)
return false;
// This is a bit hackish, but may have to suffice until the notification/delivery loop is optimised
@@ -2146,6 +2141,7 @@ function process_mail_delivery($sender, $arr, $deliveries) {
* * \e string \b hash a xchan_hash
* @param array $arr
*/
+
function process_rating_delivery($sender, $arr) {
logger('process_rating_delivery: ' . print_r($arr,true));
@@ -2205,6 +2201,7 @@ function process_rating_delivery($sender, $arr) {
* @param array $arr
* @param array $deliveries (unused)
*/
+
function process_profile_delivery($sender, $arr, $deliveries) {
logger('process_profile_delivery', LOGGER_DEBUG);
@@ -2301,6 +2298,7 @@ function check_location_move($sender_hash,$locations) {
* @param boolean $absolute (optional) default false
* @return array
*/
+
function sync_locations($sender, $arr, $absolute = false) {
$ret = array();
@@ -2548,7 +2546,7 @@ function zot_encode_locations($channel) {
if(intval($channel['channel_removed']) && $hub['hubloc_url'] === z_root())
$hub['hubloc_deleted'] = 1;
- $ret[] = array(
+ $ret[] = [
'host' => $hub['hubloc_host'],
'address' => $hub['hubloc_addr'],
'primary' => (intval($hub['hubloc_primary']) ? true : false),
@@ -2557,7 +2555,7 @@ function zot_encode_locations($channel) {
'callback' => $hub['hubloc_callback'],
'sitekey' => $hub['hubloc_sitekey'],
'deleted' => (intval($hub['hubloc_deleted']) ? true : false)
- );
+ ];
}
}
@@ -2574,6 +2572,7 @@ function zot_encode_locations($channel) {
* @param number $suppress_update default 0
* @return boolean $updated if something changed
*/
+
function import_directory_profile($hash, $profile, $addr, $ud_flags = UPDATE_FLAGS_UPDATED, $suppress_update = 0) {
logger('import_directory_profile', LOGGER_DEBUG);
@@ -2708,6 +2707,7 @@ function import_directory_profile($hash, $profile, $addr, $ud_flags = UPDATE_FLA
* @param string $hash
* @param array $keywords
*/
+
function import_directory_keywords($hash, $keywords) {
$existing = array();
@@ -2752,6 +2752,7 @@ function import_directory_keywords($hash, $keywords) {
* @param string $addr
* @param int $flags (optional) default 0
*/
+
function update_modtime($hash, $guid, $addr, $flags = 0) {
$dirmode = intval(get_config('system', 'directory_mode'));
@@ -2784,6 +2785,7 @@ function update_modtime($hash, $guid, $addr, $flags = 0) {
* @param string $pubkey
* @return boolean true if updated or inserted
*/
+
function import_site($arr, $pubkey) {
if( (! is_array($arr)) || (! $arr['url']) || (! $arr['url_sig']))
return false;
@@ -2851,6 +2853,7 @@ function import_site($arr, $pubkey) {
$site_location = htmlspecialchars($arr['location'],ENT_COMPAT,'UTF-8',false);
$site_realm = htmlspecialchars($arr['realm'],ENT_COMPAT,'UTF-8',false);
$site_project = htmlspecialchars($arr['project'],ENT_COMPAT,'UTF-8',false);
+ $site_crypto = ((array_key_exists('encryption',$arr) && is_array($arr['encryption'])) ? htmlspecialchars(implode(',',$arr['encryption']),ENT_COMPAT,'UTF-8',false) : '');
$site_version = ((array_key_exists('version',$arr)) ? htmlspecialchars($arr['version'],ENT_COMPAT,'UTF-8',false) : '');
// You can have one and only one primary directory per realm.
@@ -2872,6 +2875,7 @@ function import_site($arr, $pubkey) {
|| ($siterecord['site_register'] != $register_policy)
|| ($siterecord['site_project'] != $site_project)
|| ($siterecord['site_realm'] != $site_realm)
+ || ($siterecord['site_crypto'] != $site_crypto)
|| ($siterecord['site_version'] != $site_version) ) {
$update = true;
@@ -2880,7 +2884,7 @@ function import_site($arr, $pubkey) {
// logger('import_site: stored: ' . print_r($siterecord,true));
- $r = q("update site set site_dead = 0, site_location = '%s', site_flags = %d, site_access = %d, site_directory = '%s', site_register = %d, site_update = '%s', site_sellpage = '%s', site_realm = '%s', site_type = %d, site_project = '%s', site_version = '%s'
+ $r = q("update site set site_dead = 0, site_location = '%s', site_flags = %d, site_access = %d, site_directory = '%s', site_register = %d, site_update = '%s', site_sellpage = '%s', site_realm = '%s', site_type = %d, site_project = '%s', site_version = '%s', site_crypto = '%s'
where site_url = '%s'",
dbesc($site_location),
intval($site_directory),
@@ -2893,6 +2897,7 @@ function import_site($arr, $pubkey) {
intval(SITE_TYPE_ZOT),
dbesc($site_project),
dbesc($site_version),
+ dbesc($site_crypto),
dbesc($url)
);
if(! $r) {
@@ -2910,8 +2915,8 @@ function import_site($arr, $pubkey) {
else {
$update = true;
- $r = q("insert into site ( site_location, site_url, site_access, site_flags, site_update, site_directory, site_register, site_sellpage, site_realm, site_type, site_project, site_version )
- values ( '%s', '%s', %d, %d, '%s', '%s', %d, '%s', '%s', %d, '%s', '%s' )",
+ $r = q("insert into site ( site_location, site_url, site_access, site_flags, site_update, site_directory, site_register, site_sellpage, site_realm, site_type, site_project, site_version, site_crypto )
+ values ( '%s', '%s', %d, %d, '%s', '%s', %d, '%s', '%s', %d, '%s', '%s', '%s' )",
dbesc($site_location),
dbesc($url),
intval($access_policy),
@@ -2923,7 +2928,8 @@ function import_site($arr, $pubkey) {
dbesc($site_realm),
intval(SITE_TYPE_ZOT),
dbesc($site_project),
- dbesc($site_version)
+ dbesc($site_version),
+ dbesc($site_crypto)
);
if(! $r) {
logger('import_site: record create failed. ' . print_r($arr,true));
@@ -2942,6 +2948,7 @@ function import_site($arr, $pubkey) {
* @param array $packet (optional) default null
* @param boolean $groups_changed (optional) default false
*/
+
function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) {
if(get_config('system','server_role') === 'basic')
@@ -2977,7 +2984,7 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) {
if(intval($channel['channel_removed']))
return;
- $h = q("select * from hubloc where hubloc_hash = '%s' and hubloc_deleted = 0",
+ $h = q("select hubloc.*, site.site_crypto from hubloc left join site on site_url = hubloc_url where hubloc_hash = '%s' and hubloc_deleted = 0",
dbesc($channel['channel_hash'])
);
@@ -3064,7 +3071,7 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) {
foreach($synchubs as $hub) {
$hash = random_string();
- $n = zot_build_packet($channel,'notify',$env_recips,$hub['hubloc_sitekey'],$hash);
+ $n = zot_build_packet($channel,'notify',$env_recips,$hub['hubloc_sitekey'],$hub['site_crypto'],$hash);
queue_insert(array(
'hash' => $hash,
'account_id' => $channel['channel_account_id'],
@@ -3090,6 +3097,7 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) {
* @param array $deliveries
* @return array
*/
+
function process_channel_sync_delivery($sender, $arr, $deliveries) {
if(get_config('system','server_role') === 'basic')
@@ -3564,6 +3572,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
* * \e string \b xchan_url
* @return string
*/
+
function get_rpost_path($observer) {
if(! $observer)
return '';
@@ -3579,6 +3588,7 @@ function get_rpost_path($observer) {
* @param array $x
* @return boolean|string return false or a hash
*/
+
function import_author_zot($x) {
$hash = make_xchan_hash($x['guid'],$x['guid_sig']);
@@ -3618,6 +3628,7 @@ function import_author_zot($x) {
* @param array $data
* @return array
*/
+
function zot_reply_message_request($data) {
$ret = array('success' => false);
@@ -3654,7 +3665,7 @@ function zot_reply_message_request($data) {
if ($messages) {
$env_recips = null;
- $r = q("select * from hubloc where hubloc_hash = '%s' and hubloc_error = 0 and hubloc_deleted = 0",
+ $r = q("select hubloc.*, site.site_crypto from hubloc left join site on hubloc_url = site_url where hubloc_hash = '%s' and hubloc_error = 0 and hubloc_deleted = 0",
dbesc($sender_hash)
);
if (! $r) {
@@ -3676,7 +3687,7 @@ function zot_reply_message_request($data) {
* create a notify packet and drop the actual message packet in the queue for pickup
*/
- $n = zot_build_packet($c[0],'notify',$env_recips,(($private) ? $hub['hubloc_sitekey'] : null),$hash,array('message_id' => $data['message_id']));
+ $n = zot_build_packet($c[0],'notify',$env_recips,(($private) ? $hub['hubloc_sitekey'] : null),$hub['site_crypto'],$hash,array('message_id' => $data['message_id']));
queue_insert(array(
'hash' => $hash,
@@ -3913,6 +3924,11 @@ function zotinfo($arr) {
$permissions['connected'] = true;
}
+ // encrypt this with the default aes256cbc since we cannot be sure at this point which
+ // algorithms are preferred for communications with the remote site; notably
+ // because ztarget refers to an xchan and we don't necessarily know the origination
+ // location.
+
$ret['permissions'] = (($ztarget && $zkey) ? crypto_encapsulate(json_encode($permissions),$zkey) : $permissions);
if($permissions['view_profile'])
@@ -3943,6 +3959,8 @@ function zotinfo($arr) {
$ret['site']['directory_url'] = z_root() . '/dirsearch';
+ $ret['site']['encryption'] = crypto_methods();
+
// hide detailed site information if you're off the grid
if($dirmode != DIRECTORY_MODE_STANDALONE) {
@@ -3980,17 +3998,17 @@ function zotinfo($arr) {
$r = q("select * from addon where hidden = 0");
if($r)
foreach($r as $rr)
- $visible_plugins[] = $rr['name'];
+ $visible_plugins[] = $rr['aname'];
}
- $ret['site']['plugins'] = $visible_plugins;
- $ret['site']['sitehash'] = get_config('system','location_hash');
- $ret['site']['sitename'] = get_config('system','sitename');
- $ret['site']['sellpage'] = get_config('system','sellpage');
- $ret['site']['location'] = get_config('system','site_location');
- $ret['site']['realm'] = get_directory_realm();
- $ret['site']['project'] = Zotlabs\Lib\System::get_platform_name() . ' ' . Zotlabs\Lib\System::get_server_role();
- $ret['site']['version'] = Zotlabs\Lib\System::get_project_version();
+ $ret['site']['plugins'] = $visible_plugins;
+ $ret['site']['sitehash'] = get_config('system','location_hash');
+ $ret['site']['sitename'] = get_config('system','sitename');
+ $ret['site']['sellpage'] = get_config('system','sellpage');
+ $ret['site']['location'] = get_config('system','site_location');
+ $ret['site']['realm'] = get_directory_realm();
+ $ret['site']['project'] = Zotlabs\Lib\System::get_platform_name() . ' ' . Zotlabs\Lib\System::get_server_role();
+ $ret['site']['version'] = Zotlabs\Lib\System::get_project_version();
}
@@ -4175,7 +4193,7 @@ function update_hub_connected($hub,$sitekey = '') {
dbesc($sitekey)
);
if(intval($hub['hubloc_orphancheck'])) {
- q("update hubloc set hubloc_orhpancheck = 0 where hubloc_id = %d and hubloc_sitekey = '%s' ",
+ q("update hubloc set hubloc_orphancheck = 0 where hubloc_id = %d and hubloc_sitekey = '%s' ",
intval($hub['hubloc_id']),
dbesc($sitekey)
);
@@ -4317,7 +4335,15 @@ function zot_reply_pickup($data) {
}
}
- $encrypted = crypto_encapsulate(json_encode($ret),$sitekey);
+ // this is a bit of a hack because we don't have the hubloc_url here, only the callback url.
+ // worst case is we'll end up using aes256cbc if they've got a different post endpoint
+
+ $x = q("select site_crypto from site where site_url = '%s' limit 1",
+ dbesc(str_replace('/post','',$data['callback']))
+ );
+ $algorithm = zot_best_algorithm(($x) ? $x[0]['site_crypto'] : '');
+
+ $encrypted = crypto_encapsulate(json_encode($ret),$sitekey,$algorithm);
json_return_and_die($encrypted);
/* pickup: end */