aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/account.php38
-rw-r--r--include/acl_selectors.php2
-rw-r--r--include/api_zot.php22
-rw-r--r--include/attach.php43
-rw-r--r--include/bbcode.php57
-rw-r--r--include/channel.php116
-rw-r--r--include/connections.php33
-rwxr-xr-xinclude/dba/dba_driver.php25
-rwxr-xr-xinclude/dba/dba_pdo.php20
-rw-r--r--include/event.php15
-rw-r--r--include/features.php18
-rw-r--r--include/follow.php16
-rw-r--r--include/html2bbcode.php3
-rw-r--r--include/hubloc.php38
-rw-r--r--include/import.php142
-rwxr-xr-xinclude/items.php38
-rw-r--r--include/js_strings.php1
-rw-r--r--include/message.php4
-rw-r--r--include/nav.php12
-rw-r--r--include/network.php20
-rwxr-xr-xinclude/oembed.php31
-rw-r--r--include/permissions.php22
-rw-r--r--include/photos.php9
-rw-r--r--include/security.php278
-rw-r--r--include/taxonomy.php2
-rw-r--r--include/text.php60
-rw-r--r--include/xchan.php1
-rw-r--r--include/zid.php90
-rw-r--r--include/zot.php112
29 files changed, 950 insertions, 318 deletions
diff --git a/include/account.php b/include/account.php
index 2ab99ce19..5f0c8737f 100644
--- a/include/account.php
+++ b/include/account.php
@@ -142,12 +142,10 @@ function create_account($arr) {
$invite_code = ((x($arr,'invite_code')) ? notags(trim($arr['invite_code'])) : '');
$email = ((x($arr,'email')) ? notags(punify(trim($arr['email']))) : '');
$password = ((x($arr,'password')) ? trim($arr['password']) : '');
- $password2 = ((x($arr,'password2')) ? trim($arr['password2']) : '');
$parent = ((x($arr,'parent')) ? intval($arr['parent']) : 0 );
$flags = ((x($arr,'account_flags')) ? intval($arr['account_flags']) : ACCOUNT_OK);
$roles = ((x($arr,'account_roles')) ? intval($arr['account_roles']) : 0 );
$expires = ((x($arr,'expires')) ? intval($arr['expires']) : NULL_DATE);
- $techlevel = ((array_key_exists('techlevel',$arr)) ? intval($arr['techlevel']) : intval(get_config('system','techlevel')));
$default_service_class = get_config('system','default_service_class');
@@ -264,9 +262,8 @@ function create_account($arr) {
function verify_email_address($arr) {
if(array_key_exists('resend',$arr)) {
- $email = $arr['email'];
$a = q("select * from account where account_email = '%s' limit 1",
- dbesc($arr['email'])
+ dbesc($arr['email'])
);
if(! ($a && ($a[0]['account_flags'] & ACCOUNT_UNVERIFIED))) {
return false;
@@ -285,7 +282,7 @@ function verify_email_address($arr) {
else {
$hash = random_string(24);
- $r = q("INSERT INTO register ( hash, created, uid, password, lang ) VALUES ( '%s', '%s', %d, '%s', '%s' ) ",
+ q("INSERT INTO register ( hash, created, uid, password, lang ) VALUES ( '%s', '%s', %d, '%s', '%s' ) ",
dbesc($hash),
dbesc(datetime_convert()),
intval($arr['account']['account_id']),
@@ -304,7 +301,7 @@ function verify_email_address($arr) {
'$email' => $arr['email'],
'$uid' => $account['account_id'],
'$hash' => $hash,
- '$details' => $details
+ '$details' => ''
]
);
@@ -318,9 +315,7 @@ function verify_email_address($arr) {
pop_lang();
- if($res)
- $delivered ++;
- else
+ if(! $res)
logger('send_reg_approval_email: failed to account_id: ' . $arr['account']['account_id']);
return $res;
@@ -442,16 +437,17 @@ function account_allow($hash) {
if(! $account)
return $ret;
- $r = q("DELETE FROM register WHERE hash = '%s'",
+ q("DELETE FROM register WHERE hash = '%s'",
dbesc($register[0]['hash'])
);
- $r = q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
+ q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
intval(ACCOUNT_BLOCKED),
intval(ACCOUNT_BLOCKED),
intval($register[0]['uid'])
);
- $r = q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
+
+ q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
intval(ACCOUNT_PENDING),
intval(ACCOUNT_PENDING),
intval($register[0]['uid'])
@@ -516,11 +512,11 @@ function account_deny($hash) {
if(! $account)
return false;
- $r = q("DELETE FROM account WHERE account_id = %d",
+ q("DELETE FROM account WHERE account_id = %d",
intval($register[0]['uid'])
);
- $r = q("DELETE FROM register WHERE id = %d",
+ q("DELETE FROM register WHERE id = %d",
dbesc($register[0]['id'])
);
notice( sprintf(t('Registration revoked for %s'), $account[0]['account_email']) . EOL);
@@ -551,21 +547,23 @@ function account_approve($hash) {
if(! $account)
return $ret;
- $r = q("DELETE FROM register WHERE hash = '%s' and password = 'verify'",
+ q("DELETE FROM register WHERE hash = '%s' and password = 'verify'",
dbesc($register[0]['hash'])
);
- $r = q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
+ q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
intval(ACCOUNT_BLOCKED),
intval(ACCOUNT_BLOCKED),
intval($register[0]['uid'])
);
- $r = q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
+
+ q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
intval(ACCOUNT_PENDING),
intval(ACCOUNT_PENDING),
intval($register[0]['uid'])
);
- $r = q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
+
+ q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
intval(ACCOUNT_UNVERIFIED),
intval(ACCOUNT_UNVERIFIED),
intval($register[0]['uid'])
@@ -620,7 +618,7 @@ function downgrade_accounts() {
foreach($r as $rr) {
if(($basic) && ($rr['account_service_class']) && ($rr['account_service_class'] != $basic)) {
- $x = q("UPDATE account set account_service_class = '%s', account_expires = '%s'
+ q("UPDATE account set account_service_class = '%s', account_expires = '%s'
where account_id = %d",
dbesc($basic),
dbesc(NULL_DATE),
@@ -631,7 +629,7 @@ function downgrade_accounts() {
logger('downgrade_accounts: Account id ' . $rr['account_id'] . ' downgraded.');
}
else {
- $x = q("UPDATE account SET account_flags = (account_flags | %d) where account_id = %d",
+ q("UPDATE account SET account_flags = (account_flags | %d) where account_id = %d",
intval(ACCOUNT_EXPIRED),
intval($rr['account_id'])
);
diff --git a/include/acl_selectors.php b/include/acl_selectors.php
index c7a87afee..35e385058 100644
--- a/include/acl_selectors.php
+++ b/include/acl_selectors.php
@@ -84,7 +84,7 @@ function populate_acl($defaults = null,$show_jotnets = true, $emptyACL_descripti
);
if($r) {
foreach($r as $rv) {
- $selected = (($single_group && 'vp.' . $rr['hash'] === $allow_gid[0]) ? ' selected = "selected" ' : '');
+ $selected = (($single_group && 'vp.' . $rv['profile_guid'] === $allow_gid[0]) ? ' selected = "selected" ' : '');
$groups .= '<option id="' . 'vp' . $rv['id'] . '" value="' . 'vp.' . $rv['profile_guid'] . '"' . $selected . '>' . t('Profile','acl') . ' ' . $rv['profile_name'] . '</option>' . "\r\n";
}
}
diff --git a/include/api_zot.php b/include/api_zot.php
index 6a5b9a268..b332aea71 100644
--- a/include/api_zot.php
+++ b/include/api_zot.php
@@ -6,6 +6,8 @@
api_register_func('api/export/basic','api_export_basic', true);
api_register_func('api/red/channel/export/basic','api_export_basic', true);
api_register_func('api/z/1.0/channel/export/basic','api_export_basic', true);
+ api_register_func('api/red/item/export/page','api_item_export_page', true);
+ api_register_func('api/z/1.0/item/export/page','api_item_export_page', true);
api_register_func('api/red/channel/list','api_channel_list', true);
api_register_func('api/z/1.0/channel/list','api_channel_list', true);
api_register_func('api/red/channel/stream','api_channel_stream', true);
@@ -80,6 +82,26 @@
json_return_and_die(identity_basic_export(api_user(),$sections));
}
+ function api_item_export_page($type) {
+ if(api_user() === false) {
+ logger('api_item_export_page: no user');
+ return false;
+ }
+ $page = intval($_REQUEST['page']);
+ $records = intval($_REQUEST['records']);
+ if(! $records) {
+ $records = 50;
+ }
+ if(! $_REQUEST['since'])
+ $start = NULL_DATE;
+ else {
+ $start = datetime_convert(date_default_timezone_get(),'UTC', $_REQUEST['since']);
+ }
+ $finish = datetime_convert(date_default_timezone_get(),'UTC', (($_REQUEST['until']) ? $_REQUEST['until'] : 'now'));
+
+ json_return_and_die(channel_export_items_page(api_user(),$start,$finish,$page,$records));
+ }
+
function api_network_stream($type) {
if(api_user() === false) {
diff --git a/include/attach.php b/include/attach.php
index 17a47d9ac..f169e0669 100644
--- a/include/attach.php
+++ b/include/attach.php
@@ -321,7 +321,6 @@ function attach_can_view_folder($uid,$ob_hash,$folder_hash) {
$sql_extra = permissions_sql($uid,$ob_hash);
$hash = $folder_hash;
- $result = false;
if(! $folder_hash) {
return perm_is_allowed($uid,$ob_hash,'view_storage');
@@ -352,7 +351,7 @@ function attach_can_view_folder($uid,$ob_hash,$folder_hash) {
* @param string $hash
* @param string $observer_hash
* @param int $rev (optional) revision default 0
- * @return associative array with everything except data
+ * @return array (associative) with everything except data
* * \e boolean \b success boolean true or false
* * \e string \b message (optional) only when success is false
* * \e array \b data array of attach DB entry without data component
@@ -1224,7 +1223,7 @@ function attach_mkdir($channel, $observer_hash, $arr = null) {
$ret['success'] = true;
// update the parent folder's lastmodified timestamp
- $e = q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d",
+ q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d",
dbesc($created),
dbesc($arr['folder']),
intval($channel_id)
@@ -1270,8 +1269,6 @@ function attach_mkdirp($channel, $observer_hash, $arr = null) {
$ret = array('success' => false);
$channel_id = $channel['channel_id'];
- $sql_options = '';
-
$basepath = 'store/' . $channel['channel_address'];
logger('basepath: ' . $basepath);
@@ -1374,7 +1371,7 @@ function attach_change_permissions($channel_id, $resource, $allow_cid, $allow_gi
}
}
- $x = q("update attach set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where hash = '%s' and uid = %d",
+ q("update attach set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where hash = '%s' and uid = %d",
dbesc($allow_cid),
dbesc($allow_gid),
dbesc($deny_cid),
@@ -1383,7 +1380,7 @@ function attach_change_permissions($channel_id, $resource, $allow_cid, $allow_gi
intval($channel_id)
);
if($r[0]['is_photo']) {
- $x = q("update photo set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where resource_id = '%s' and uid = %d",
+ q("update photo set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where resource_id = '%s' and uid = %d",
dbesc($allow_cid),
dbesc($allow_gid),
dbesc($deny_cid),
@@ -1482,7 +1479,7 @@ function attach_delete($channel_id, $resource, $is_photo = 0) {
}
// delete from database
- $z = q("DELETE FROM attach WHERE hash = '%s' AND uid = %d",
+ q("DELETE FROM attach WHERE hash = '%s' AND uid = %d",
dbesc($resource),
intval($channel_id)
);
@@ -1493,7 +1490,7 @@ function attach_delete($channel_id, $resource, $is_photo = 0) {
// update the parent folder's lastmodified timestamp
- $e = q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d",
+ q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d",
dbesc(datetime_convert()),
dbesc($r[0]['folder']),
intval($channel_id)
@@ -1524,6 +1521,17 @@ function attach_drop_photo($channel_id,$resource) {
if($x) {
drop_item($x[0]['id'],false,(($x[0]['item_hidden']) ? DROPITEM_NORMAL : DROPITEM_PHASE1),true);
}
+
+ $r = q("SELECT content FROM photo WHERE resource_id = '%s' AND uid = %d AND os_storage = 1",
+ dbesc($resource),
+ intval($channel_id)
+ );
+ if($r) {
+ foreach($r as $i) {
+ @unlink(dbunescbin($i['content']));
+ }
+ }
+
q("DELETE FROM photo WHERE uid = %d AND resource_id = '%s'",
intval($channel_id),
dbesc($resource)
@@ -1815,7 +1823,7 @@ function file_activity($channel_id, $object, $allow_cid, $allow_gid, $deny_cid,
$u_jsonobject = json_encode($object);
//we have got the relevant info - delete the old item before we create the new one
- $z = q("DELETE FROM item WHERE obj_type = '%s' AND verb = '%s' AND mid = '%s'",
+ q("DELETE FROM item WHERE obj_type = '%s' AND verb = '%s' AND mid = '%s'",
dbesc(ACTIVITY_OBJ_FILE),
dbesc(ACTIVITY_POST),
dbesc($y[0]['mid'])
@@ -1946,7 +1954,6 @@ function attach_recursive_perms($arr_allow_cid, $arr_allow_gid, $arr_deny_cid, $
$ret = array();
$parent_arr = array();
$count_values = array();
- $poster = App::get_observer();
//lookup all channels in sharee group and add them to sharee $arr_allow_cid
if($arr_allow_gid) {
@@ -2351,7 +2358,6 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
if(! $n)
return false;
- $newdirname = $n[0]['filename'];
$newalbumname = $n[0]['display_path'];
$newstorepath = dbunescbin($n[0]['content']) . '/' . $resource_id;
}
@@ -2359,7 +2365,6 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
// root directory
- $newdirname = EMPTY_STR;
$newalbumname = EMPTY_STR;
$newstorepath = 'store/' . $c['channel_address'] . '/' . $resource_id;
}
@@ -2428,7 +2433,7 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
}
}
- $t = q("update attach set content = '%s', folder = '%s', filename = '%s' where id = %d",
+ q("update attach set content = '%s', folder = '%s', filename = '%s' where id = %d",
dbescbin($newstorepath),
dbesc($new_folder_hash),
dbesc($filename),
@@ -2438,7 +2443,7 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
$x = attach_syspaths($channel_id,$resource_id);
- $t1 = q("update attach set os_path = '%s', display_path = '%s' where id = %d",
+ q("update attach set os_path = '%s', display_path = '%s' where id = %d",
dbesc($x['os_path']),
dbesc($x['path']),
intval($r[0]['id'])
@@ -2446,7 +2451,7 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
if($r[0]['is_photo']) {
- $t = q("update photo set album = '%s', filename = '%s', os_path = '%s', display_path = '%s'
+ q("update photo set album = '%s', filename = '%s', os_path = '%s', display_path = '%s'
where resource_id = '%s' and uid = %d",
dbesc($newalbumname),
dbesc($filename),
@@ -2456,7 +2461,7 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
intval($channel_id)
);
- $t = q("update photo set content = '%s' where resource_id = '%s' and uid = %d and imgscale = 0",
+ q("update photo set content = '%s' where resource_id = '%s' and uid = %d and imgscale = 0",
dbescbin($newstorepath),
dbesc($resource_id),
intval($channel_id)
@@ -2587,12 +2592,12 @@ function attach_upgrade() {
foreach($r as $rv) {
$x = attach_syspaths($rv['uid'],$rv['hash']);
if($x) {
- $w = q("update attach set os_path = '%s', display_path = '%s' where id = %d",
+ q("update attach set os_path = '%s', display_path = '%s' where id = %d",
dbesc($x['os_path']),
dbesc($x['path']),
intval($rv['id'])
);
- $y = q("update photo set os_path = '%s', display_path = '%s' where uid = %d and resource_id = '%s'",
+ q("update photo set os_path = '%s', display_path = '%s' where uid = %d and resource_id = '%s'",
dbesc($x['os_path']),
dbesc($x['path']),
intval($rv['uid']),
diff --git a/include/bbcode.php b/include/bbcode.php
index 7531bd774..485a1f5b2 100644
--- a/include/bbcode.php
+++ b/include/bbcode.php
@@ -87,12 +87,11 @@ function nakedoembed($match) {
$strip_url = strip_escaped_zids($url);
- $o = oembed_fetch_url($strip_url);
-
- if ($o['type'] == 'error')
- return str_replace($url,$strip_url,$match[0]);
-
- return '[embed]' . $strip_url . '[/embed]';
+ // this function no longer performs oembed on naked links
+ // because they author may have created naked links intentionally.
+ // Now it just strips zids on naked links.
+
+ return str_replace($url,$strip_url,$match[0]);
}
function tryzrlaudio($match) {
@@ -117,6 +116,26 @@ function tryzrlvideo($match) {
return '<video ' . $poster . ' controls="controls" preload="none" src="' . str_replace(' ','%20',$link) . '" style="width:100%; max-width:' . App::$videowidth . 'px"><a href="' . str_replace(' ','%20',$link) . '">' . $link . '</a></video>';
}
+function videowithopts($match) {
+ $link = $match[2];
+ $zrl = is_matrix_url($link);
+ if($zrl)
+ $link = zid($link);
+
+ $attributes = $match[1];
+
+ $poster = "";
+
+ preg_match("/poster='(.*?)'/ism", $attributes, $matches);
+ if ($matches[1] != "")
+ $poster = 'poster="' . (($zrl) ? zid($matches[1]) : $matches[1]) . '"';
+
+ return '<video ' . $poster . ' controls="controls" preload="none" src="' . str_replace(' ','%20',$link) . '" style="width:100%; max-width:' . App::$videowidth . 'px"><a href="' . str_replace(' ','%20',$link) . '">' . $link . '</a></video>';
+}
+
+
+
+
// [noparse][i]italic[/i][/noparse] turns into
// [noparse][ i ]italic[ /i ][/noparse],
// to hide them from parser.
@@ -966,17 +985,22 @@ function bbcode($Text, $options = []) {
// leave open the posibility of [map=something]
// this is replaced in prepare_body() which has knowledge of the item location
-
- if (strpos($Text,'[/map]') !== false) {
- $Text = preg_replace_callback("/\[map\](.*?)\[\/map\]/ism", 'bb_map_location', $Text);
- }
- if (strpos($Text,'[map=') !== false) {
- $Text = preg_replace_callback("/\[map=(.*?)\]/ism", 'bb_map_coords', $Text);
+ if ($cache) {
+ $Text = str_replace([ '[map]','[/map]' ], [ '','' ], $Text);
+ $Text = preg_replace('/\[map=(.*?)\]/ism','$1',$Text);
}
- if (strpos($Text,'[map]') !== false) {
- $Text = preg_replace("/\[map\]/", '<div class="map"></div>', $Text);
+ else {
+ if (strpos($Text,'[/map]') !== false) {
+ $Text = preg_replace_callback("/\[map\](.*?)\[\/map\]/ism", 'bb_map_location', $Text);
+ }
+ if (strpos($Text,'[map=') !== false) {
+ $Text = preg_replace_callback("/\[map=(.*?)\]/ism", 'bb_map_coords', $Text);
+ }
+ if (strpos($Text,'[map]') !== false) {
+ $Text = preg_replace("/\[map\]/", '<div class="map"></div>', $Text);
+ }
}
-
+
// Check for bold text
if (strpos($Text,'[b]') !== false) {
$Text = preg_replace("(\[b\](.*?)\[\/b\])ism", '<strong>$1</strong>', $Text);
@@ -1251,12 +1275,14 @@ function bbcode($Text, $options = []) {
// html5 video and audio
if (strpos($Text,'[/video]') !== false) {
+ $Text = preg_replace_callback("/\[video (.*?)\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mpeg|mpg))\[\/video\]/ism", 'videowithopts', $Text);
$Text = preg_replace_callback("/\[video\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mpeg|mpg))\[\/video\]/ism", 'tryzrlvideo', $Text);
}
if (strpos($Text,'[/audio]') !== false) {
$Text = preg_replace_callback("/\[audio\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mp3|opus|m4a))\[\/audio\]/ism", 'tryzrlaudio', $Text);
}
if (strpos($Text,'[/zvideo]') !== false) {
+ $Text = preg_replace_callback("/\[zvideo (.*?)\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mpeg|mpg))\[\/zvideo\]/ism", 'videowithopts', $Text);
$Text = preg_replace_callback("/\[zvideo\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mpeg|mpg))\[\/zvideo\]/ism", 'tryzrlvideo', $Text);
}
if (strpos($Text,'[/zaudio]') !== false) {
@@ -1360,4 +1386,3 @@ function bbcode($Text, $options = []) {
return $Text;
}
-
diff --git a/include/channel.php b/include/channel.php
index 95a3f96cf..e4b6df47b 100644
--- a/include/channel.php
+++ b/include/channel.php
@@ -873,6 +873,13 @@ function identity_basic_export($channel_id, $sections = null) {
$ret['abook'][$x]['abconfig'] = $abconfig;
translate_abook_perms_outbound($ret['abook'][$x]);
}
+
+ // pick up the zot6 xchan and hublocs also
+
+ if($ret['channel']['channel_portable_id']) {
+ $xchans[] = $ret['channel']['channel_portable_id'];
+ }
+
stringify_array_elms($xchans);
}
@@ -948,6 +955,18 @@ function identity_basic_export($channel_id, $sections = null) {
}
$ret['app'] = $r;
}
+ $r = q("select * from app where app_channel = %d and app_system = 1",
+ intval($channel_id)
+ );
+ if($r) {
+ for($x = 0; $x < count($r); $x ++) {
+ $r[$x]['term'] = q("select * from term where otype = %d and oid = %d",
+ intval(TERM_OBJ_APP),
+ intval($r[$x]['id'])
+ );
+ }
+ $ret['sysapp'] = $r;
+ }
}
if(in_array('chatrooms',$sections)) {
@@ -1080,6 +1099,7 @@ function identity_basic_export($channel_id, $sections = null) {
return $ret;
}
+
/**
* @brief Export items for a year, or a month of a year.
*
@@ -1102,23 +1122,50 @@ function identity_export_year($channel_id, $year, $month = 0) {
else
$target_month = '01';
+ $mindate = datetime_convert('UTC', 'UTC', $year . '-' . $target_month . '-01 00:00:00');
+ if($month && $month < 12)
+ $maxdate = datetime_convert('UTC', 'UTC', $year . '-' . $target_month_plus . '-01 00:00:00');
+ else
+ $maxdate = datetime_convert('UTC', 'UTC', $year+1 . '-01-01 00:00:00');
+
+ return channel_export_items_date($channel_id,$mindate,$maxdate);
+
+}
+
+/**
+ * @brief Export items within an arbitrary date range.
+ *
+ * Date/time is in UTC.
+ *
+ * @param int $channel_id The channel ID
+ * @param string $start
+ * @param string $finish
+ * @return array
+ */
+
+function channel_export_items_date($channel_id, $start, $finish) {
+
+ if(! $start)
+ return array();
+ else
+ $start = datetime_convert('UTC', 'UTC', $start);
+
+ $finish = datetime_convert('UTC', 'UTC', (($finish) ? $finish : 'now'));
+ if($finish < $start)
+ return array();
+
$ret = array();
$ch = channelx_by_n($channel_id);
if($ch) {
$ret['relocate'] = [ 'channel_address' => $ch['channel_address'], 'url' => z_root()];
}
- $mindate = datetime_convert('UTC', 'UTC', $year . '-' . $target_month . '-01 00:00:00');
- if($month && $month < 12)
- $maxdate = datetime_convert('UTC', 'UTC', $year . '-' . $target_month_plus . '-01 00:00:00');
- else
- $maxdate = datetime_convert('UTC', 'UTC', $year+1 . '-01-01 00:00:00');
- $r = q("select * from item where ( item_wall = 1 or item_type != %d ) and item_deleted = 0 and uid = %d and created >= '%s' and created < '%s' and resource_type = '' order by created",
+ $r = q("select * from item where ( item_wall = 1 or item_type != %d ) and item_deleted = 0 and uid = %d and created >= '%s' and created <= '%s' and resource_type = '' order by created",
intval(ITEM_TYPE_POST),
intval($channel_id),
- dbesc($mindate),
- dbesc($maxdate)
+ dbesc($start),
+ dbesc($finish)
);
if($r) {
@@ -1132,39 +1179,57 @@ function identity_export_year($channel_id, $year, $month = 0) {
return $ret;
}
+
+
/**
- * @brief Export items within an arbitrary date range.
+ * @brief Export items with pagination
*
- * Date/time is in UTC.
*
* @param int $channel_id The channel ID
- * @param string $start
- * @param string $finish
+ * @param int $page
+ * @param int $limit (default 50)
* @return array
*/
-function channel_export_items($channel_id, $start, $finish) {
+
+function channel_export_items_page($channel_id, $start, $finish, $page = 0, $limit = 50) {
+
+ if(intval($page) < 1) {
+ $page = 0;
+ }
+
+ if(intval($limit) < 1) {
+ $limit = 1;
+ }
+
+ if(intval($limit) > 5000) {
+ $limit = 5000;
+ }
if(! $start)
- return array();
+ $start = NULL_DATE;
else
$start = datetime_convert('UTC', 'UTC', $start);
$finish = datetime_convert('UTC', 'UTC', (($finish) ? $finish : 'now'));
if($finish < $start)
- return array();
+ return [];
- $ret = array();
+ $offset = intval($limit) * intval($page);
+
+ $ret = [];
$ch = channelx_by_n($channel_id);
if($ch) {
$ret['relocate'] = [ 'channel_address' => $ch['channel_address'], 'url' => z_root()];
}
- $r = q("select * from item where ( item_wall = 1 or item_type != %d ) and item_deleted = 0 and uid = %d and created >= '%s' and created <= '%s' and resource_type = '' order by created",
+ $r = q("select * from item where ( item_wall = 1 or item_type != %d ) and item_deleted = 0 and uid = %d and resource_type = '' and created >= '%s' and created <= '%s' order by created limit %d offset %d",
intval(ITEM_TYPE_POST),
intval($channel_id),
dbesc($start),
- dbesc($finish)
+ dbesc($finish),
+ intval($limit),
+ intval($offset)
);
if($r) {
@@ -1179,6 +1244,7 @@ function channel_export_items($channel_id, $start, $finish) {
}
+
/**
* @brief Loads a profile into the App structure.
*
@@ -1392,7 +1458,7 @@ function profile_edit_menu($uid) {
* @param boolean $show_connect (optional) default true
* @param mixed $zcard (optional) default false
*
- * @return HTML string suitable for sidebar inclusion
+ * @return string (HTML) suitable for sidebar inclusion
* Exceptions: Returns empty string if passed $profile is wrong type or not populated
*/
function profile_sidebar($profile, $block = 0, $show_connect = true, $zcard = false) {
@@ -1753,13 +1819,16 @@ function zid_init() {
call_hooks('zid_init', $arr);
if(! local_channel()) {
- $r = q("select * from hubloc where hubloc_addr = '%s' order by hubloc_connected desc limit 1",
+ $r = q("select * from hubloc where hubloc_addr = '%s' order by hubloc_connected desc",
dbesc($tmp_str)
);
if(! $r) {
Master::Summon(array('Gprobe',bin2hex($tmp_str)));
}
- if($r && remote_channel() && remote_channel() === $r[0]['hubloc_hash'])
+ if($r) {
+ $r = zot_record_preferred($r);
+ }
+ if($r && remote_channel() && remote_channel() === $r['hubloc_hash'])
return;
logger('Not authenticated. Invoking reverse magic-auth for ' . $tmp_str);
@@ -1767,8 +1836,8 @@ function zid_init() {
$query = App::$query_string;
$query = str_replace(array('?zid=','&zid='),array('?rzid=','&rzid='),$query);
$dest = '/' . $query;
- if($r && ($r[0]['hubloc_url'] != z_root()) && (! strstr($dest,'/magic')) && (! strstr($dest,'/rmagic'))) {
- goaway($r[0]['hubloc_url'] . '/magic' . '?f=&rev=1&owa=1&bdest=' . bin2hex(z_root() . $dest));
+ if($r && ($r['hubloc_url'] != z_root()) && (! strstr($dest,'/magic')) && (! strstr($dest,'/rmagic'))) {
+ goaway($r['hubloc_url'] . '/magic' . '?f=&rev=1&owa=1&bdest=' . bin2hex(z_root() . $dest));
}
else
logger('No hubloc found.');
@@ -1789,6 +1858,7 @@ function zat_init() {
);
if($r) {
$xchan = atoken_xchan($r[0]);
+ atoken_create_xchan($xchan);
atoken_login($xchan);
}
}
diff --git a/include/connections.php b/include/connections.php
index d97ea3887..e942503f0 100644
--- a/include/connections.php
+++ b/include/connections.php
@@ -373,19 +373,46 @@ function contact_remove($channel_id, $abook_id) {
if(intval($abook['abook_self']))
return false;
- $r = q("select id from item where (owner_xchan = '%s' or author_xchan = '%s') and uid = %d and item_retained = 0 and item_starred = 0",
+ $r = q("select id, parent from item where (owner_xchan = '%s' or author_xchan = '%s') and uid = %d and item_retained = 0 and item_starred = 0",
dbesc($abook['abook_xchan']),
dbesc($abook['abook_xchan']),
intval($channel_id)
);
if($r) {
+ $already_saved = [];
foreach($r as $rr) {
- $x = q("select uid from term where otype = %d and oid = %d and ttype = %d limit 1",
+ $w = $x = $y = null;
+
+ // optimise so we only process newly seen parent items
+ if (in_array($rr['parent'],$already_saved)) {
+ continue;
+ }
+ // if this isn't the parent, fetch the parent's item_retained and item_starred to see if the conversation
+ // should be retained
+ if($rr['id'] != $rr['parent']) {
+ $w = q("select id, item_retained, item_starred from item where id = %d",
+ intval($rr['parent'])
+ );
+ if($w) {
+ // see if the conversation was filed
+ $x = q("select uid from term where otype = %d and oid = %d and ttype = %d limit 1",
+ intval(TERM_OBJ_POST),
+ intval($w[0]['id']),
+ intval(TERM_FILE)
+ );
+ if (intval($w[0]['item_retained']) || intval($w[0]['item_starred']) || $x) {
+ $already_saved[] = $rr['parent'];
+ continue;
+ }
+ }
+ }
+ // see if this item was filed
+ $y = q("select uid from term where otype = %d and oid = %d and ttype = %d limit 1",
intval(TERM_OBJ_POST),
intval($rr['id']),
intval(TERM_FILE)
);
- if($x) {
+ if ($y) {
continue;
}
drop_item($rr['id'],false);
diff --git a/include/dba/dba_driver.php b/include/dba/dba_driver.php
index ee0e06a91..cfb208e2d 100755
--- a/include/dba/dba_driver.php
+++ b/include/dba/dba_driver.php
@@ -485,3 +485,28 @@ function db_columns($table) {
return [];
}
+
+
+function db_indexes($table) {
+
+ if($table) {
+ if(ACTIVE_DBTYPE === DBTYPE_POSTGRES) {
+ $r = q("SELECT indexname from pg_indexes where tablename = '%s'",
+ dbesc($table)
+ );
+ if($r) {
+ return ids_to_array($r,'indexname');
+ }
+ }
+ else {
+ $r = q("show index from %s",
+ dbesc($table)
+ );
+ if($r) {
+ return ids_to_array($r,'Key_name');
+ }
+ }
+ }
+
+ return [];
+}
diff --git a/include/dba/dba_pdo.php b/include/dba/dba_pdo.php
index 5002f53e7..0279342ec 100755
--- a/include/dba/dba_pdo.php
+++ b/include/dba/dba_pdo.php
@@ -19,7 +19,7 @@ class dba_pdo extends dba_driver {
$this->driver_dbtype = $scheme;
if(strpbrk($server,':;')) {
- $dsn = $server;
+ $dsn = $this->driver_dbtype . ':unix_socket=' . trim($server, ':;');
}
else {
$dsn = $this->driver_dbtype . ':host=' . $server . (intval($port) ? ';port=' . $port : '');
@@ -161,23 +161,17 @@ class dba_pdo extends dba_driver {
}
function unescapebin($str) {
- if($this->driver_dbtype === 'pgsql' && (! is_null($str))) {
- $x = '';
- while(! feof($str)) {
- $x .= fread($str,8192);
+ if($this->driver_dbtype === 'pgsql') {
+ if(gettype($str) === 'resource') {
+ $str = stream_get_contents($str);
}
- if(substr($x,0,2) === '\\x') {
- $x = hex2bin(substr($x,2));
+ if(substr($str,0,2) === '\\x') {
+ $str = hex2bin(substr($str,2));
}
- return $x;
-
- }
- else {
- return $str;
}
+ return $str;
}
-
function getdriver() {
return 'pdo';
}
diff --git a/include/event.php b/include/event.php
index fdb9e1415..471fb7afa 100644
--- a/include/event.php
+++ b/include/event.php
@@ -4,8 +4,11 @@
* @brief Event related functions.
*/
+
use Sabre\VObject;
+use Zotlabs\Lib\Activity;
+
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
@@ -65,7 +68,7 @@ function format_event_html($ev) {
}
function format_event_obj($jobject) {
- $event = array();
+ $event = [];
$object = json_decode($jobject,true);
@@ -1046,6 +1049,7 @@ function event_store_item($arr, $event) {
'location' => $arr['location'],
'adjust' => $arr['adjust'],
'content' => format_event_bbcode($arr),
+ 'attachment' => Activity::encode_attachment($r[0]),
'author' => array(
'name' => $r[0]['xchan_name'],
'address' => $r[0]['xchan_addr'],
@@ -1159,7 +1163,7 @@ function event_store_item($arr, $event) {
$item_arr['item_thread_top'] = $item_thread_top;
$attach = array(array(
- 'href' => z_root() . '/events/ical/' . urlencode($event['event_hash']),
+ 'href' => z_root() . '/channel_calendar/ical/' . urlencode($event['event_hash']),
'length' => 0,
'type' => 'text/calendar',
'title' => t('event') . '-' . $event['event_hash'],
@@ -1181,7 +1185,7 @@ function event_store_item($arr, $event) {
// otherwise we'll fallback to /display/$message_id
if($wall)
- $item_arr['plink'] = z_root() . '/channel/' . $z[0]['channel_address'] . '/?f=&mid=' . urlencode($item_arr['mid']);
+ $item_arr['plink'] = z_root() . '/channel/' . $z[0]['channel_address'] . '/?f=&mid=' . gen_link_id($item_arr['mid']);
else
$item_arr['plink'] = z_root() . '/display/' . gen_link_id($item_arr['mid']);
@@ -1200,6 +1204,7 @@ function event_store_item($arr, $event) {
'location' => $arr['location'],
'adjust' => $arr['adjust'],
'content' => format_event_bbcode($arr),
+ 'attachment' => Activity::encode_attachment($item_arr),
'author' => array(
'name' => $x[0]['xchan_name'],
'address' => $x[0]['xchan_addr'],
@@ -1279,6 +1284,10 @@ function cdav_principal($uri) {
}
function cdav_perms($needle, $haystack, $check_rw = false) {
+
+ if($needle == 'channel_calendar')
+ return true;
+
foreach ($haystack as $item) {
if($check_rw) {
if(is_array($item['id'])) {
diff --git a/include/features.php b/include/features.php
index 35a4c0dd4..d8607f447 100644
--- a/include/features.php
+++ b/include/features.php
@@ -79,7 +79,7 @@ function get_features($filtered = true, $level = (-1)) {
'calendar' => [
- t('CalDAV'),
+ t('Calendar'),
[
'cal_first_day',
@@ -167,6 +167,14 @@ function get_features($filtered = true, $level = (-1)) {
t('Ability to mark special posts with a star indicator'),
false,
get_config('feature_lock','star_posts'),
+ ],
+
+ [
+ 'reply_to',
+ t('Reply on comment'),
+ t('Ability to reply on selected comment'),
+ false,
+ get_config('feature_lock','reply_to'),
]
],
@@ -361,14 +369,6 @@ function get_features($filtered = true, $level = (-1)) {
],
[
- 'suggest',
- t('Suggest Channels'),
- t('Show friend and connection suggestions'),
- false,
- get_config('feature_lock','suggest')
- ],
-
- [
'network_list_mode',
t('Use blog/list mode'),
t('Comments will be displayed separately'),
diff --git a/include/follow.php b/include/follow.php
index db77a0160..50b952881 100644
--- a/include/follow.php
+++ b/include/follow.php
@@ -119,6 +119,7 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
if( array_key_exists('permissions',$j) && array_key_exists('data',$j['permissions'])) {
$permissions = crypto_unencapsulate(array(
'data' => $j['permissions']['data'],
+ 'alg' => $j['permissions']['alg'],
'key' => $j['permissions']['key'],
'iv' => $j['permissions']['iv']),
$channel['channel_prvkey']);
@@ -141,7 +142,7 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
$sql_options = (($protocol) ? " and xchan_network = '" . dbesc($protocol) . "' " : '');
- $r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s' $sql_options limit 1",
+ $r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s' $sql_options ",
dbesc($url),
dbesc($url)
);
@@ -168,18 +169,19 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
}
if($wf || $d) {
- $r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s' limit 1",
+ $r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s'",
dbesc(($wf) ? $wf : $url),
dbesc($url)
);
}
}
+ $xchan = zot_record_preferred($r,'xchan_network');
+
// if discovery was a success we should have an xchan record in $r
- if($r) {
- $xchan = $r[0];
- $xchan_hash = $r[0]['xchan_hash'];
+ if($xchan) {
+ $xchan_hash = $xchan['xchan_hash'];
$their_perms = 0;
}
}
@@ -190,9 +192,9 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
return $result;
}
- $allowed = (($is_zot || in_array($r[0]['xchan_network'],['rss','zot6'])) ? 1 : 0);
+ $allowed = (($is_zot || in_array($xchan['xchan_network'],['rss','zot6'])) ? 1 : 0);
- $x = array('channel_id' => $uid, 'follow_address' => $url, 'xchan' => $r[0], 'allowed' => $allowed, 'singleton' => 0);
+ $x = array('channel_id' => $uid, 'follow_address' => $url, 'xchan' => $xchan, 'allowed' => $allowed, 'singleton' => 0);
call_hooks('follow_allow',$x);
diff --git a/include/html2bbcode.php b/include/html2bbcode.php
index 1a03fbdaf..c916421b8 100644
--- a/include/html2bbcode.php
+++ b/include/html2bbcode.php
@@ -219,8 +219,7 @@ function html2bbcode($message)
$message = $doc->saveHTML();
- // I'm removing something really disturbing
- // Don't know exactly what it is
+ // I'm removing the UTF-8 encoding of a NO-BREAK SPACE codepoint
$message = str_replace(chr(194).chr(160), ' ', $message);
$message = str_replace("&nbsp;", " ", $message);
diff --git a/include/hubloc.php b/include/hubloc.php
index b2903b0ee..4a1f77733 100644
--- a/include/hubloc.php
+++ b/include/hubloc.php
@@ -305,3 +305,41 @@ function ping_site($url) {
return $ret;
}
+
+
+function z6_discover() {
+
+ // find unregistered zot6 clone hublocs
+
+ $c = q("select channel_hash, channel_portable_id from channel where channel_deleted = '%s'",
+ dbesc(NULL_DATE)
+ );
+ if ($c) {
+ foreach ($c as $entry) {
+ $q1 = q("select * from hubloc left join site on hubloc_url = site_url where hubloc_deleted = 0 and site_dead = 0 and hubloc_hash = '%s' and hubloc_url != '%s'",
+ dbesc($entry['channel_hash']),
+ dbesc(z_root())
+ );
+ if (! $q1) {
+ // channel has no zot clones
+ continue;
+ }
+ // does this particular server have a zot6 clone registered on our site for this channel?
+ foreach ($q1 as $q) {
+ $q2 = q("select * from hubloc left join site on hubloc_url = site_url where hubloc_deleted = 0 and site_dead = 0 and hubloc_hash = '%s' and hubloc_url = '%s'",
+ dbesc($entry['channel_portable_id']),
+ dbesc($q['hubloc_url'])
+ );
+ if ($q2) {
+ continue;
+ }
+ // zot6 hubloc not found.
+ if(strpos($q['site_project'],'hubzilla') !== false && version_compare($q['site_version'],'4.0') >= 0) {
+ // probe and store results - only for zot6 (over-ride the zot default)
+ discover_by_webbie($q['hubloc_addr'],'zot6');
+ }
+ }
+ }
+ }
+
+}
diff --git a/include/import.php b/include/import.php
index f391400bd..92ba014d8 100644
--- a/include/import.php
+++ b/include/import.php
@@ -94,7 +94,8 @@ function import_channel($channel, $account_id, $seize, $newname = '') {
'channel_w_comment', 'channel_w_mail', 'channel_w_like', 'channel_w_tagwall',
'channel_w_chat', 'channel_w_storage', 'channel_w_pages', 'channel_a_republish',
'channel_a_delegate', 'perm_limits', 'channel_password', 'channel_salt',
- 'channel_moved', 'channel_removed', 'channel_deleted', 'channel_system'
+ 'channel_moved', 'channel_removed', 'channel_deleted', 'channel_system',
+ 'channel_r_photos', 'channel_w_photos'
];
$clean = array();
@@ -147,7 +148,9 @@ function import_config($channel, $configs) {
foreach($configs as $config) {
unset($config['id']);
$config['uid'] = $channel['channel_id'];
-
+ if($config['cat'] === 'system' && $config['k'] === 'import_system_apps') {
+ continue;
+ }
create_table_from_array('pconfig', $config);
}
@@ -364,6 +367,9 @@ function import_apps($channel, $apps) {
if($channel && $apps) {
foreach($apps as $app) {
+ if(array_key_exists('app_system',$app) && intval($app['app_system']))
+ continue;
+
$term = ((array_key_exists('term',$app) && is_array($app['term'])) ? $app['term'] : null);
unset($app['id']);
@@ -413,6 +419,9 @@ function sync_apps($channel, $apps) {
$exists = false;
$term = ((array_key_exists('term',$app)) ? $app['term'] : null);
+ if(array_key_exists('app_system',$app) && intval($app['app_system']))
+ continue;
+
$x = q("select * from app where app_id = '%s' and app_channel = %d limit 1",
dbesc($app['app_id']),
intval($channel['channel_id'])
@@ -504,6 +513,84 @@ function sync_apps($channel, $apps) {
}
}
+
+
+/**
+ * @brief Import system apps.
+ * System apps from the original server may not exist on this system
+ * (e.g. apps associated with addons that are not installed here).
+ * Check the system apps that were provided in the import file to see if they
+ * exist here and if so, install them locally. Preserve categories that
+ * might have been added by this channel on the other server.
+ * Do not use any paths from the original as they will point to a different server.
+ * @param array $channel
+ * @param array $apps
+ */
+function import_sysapps($channel, $apps) {
+
+ if($channel && $apps) {
+
+ $sysapps = \Zotlabs\Lib\Apps::get_system_apps(false);
+
+ foreach($apps as $app) {
+
+ if(array_key_exists('app_system',$app) && (! intval($app['app_system'])))
+ continue;
+
+ $term = ((array_key_exists('term',$app) && is_array($app['term'])) ? $app['term'] : null);
+
+ foreach($sysapps as $sysapp) {
+ if($app['app_id'] === hash('whirlpool',$sysapp['app_name'])) {
+ // install this app on this server
+ $newapp = $sysapp;
+ $newapp['uid'] = $channel['channel_id'];
+ $newapp['guid'] = hash('whirlpool',$newapp['name']);
+
+ $installed = q("select id from app where app_id = '%s' and app_channel = %d limit 1",
+ dbesc($newapp['guid']),
+ intval($channel['channel_id'])
+ );
+ if($installed) {
+ break;
+ }
+
+ $newapp['system'] = 1;
+ if($term) {
+ $s = EMPTY_STR;
+ foreach($term as $t) {
+ if($s) {
+ $s .= ',';
+ }
+ $s .= $t['term'];
+ }
+ $newapp['categories'] = $s;
+ }
+ \Zotlabs\Lib\Apps::app_install($channel['channel_id'],$newapp);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * @brief Sync system apps.
+ *
+ * @param array $channel
+ * @param array $apps
+ */
+function sync_sysapps($channel, $apps) {
+
+ if($channel && $apps) {
+
+ // we do not currently sync system apps
+
+ }
+}
+
+
+
+
+
/**
* @brief Import chatrooms.
*
@@ -1069,6 +1156,9 @@ function sync_files($channel, $files) {
require_once('include/attach.php');
if($channel && $files) {
+
+ $limit = service_class_fetch($channel['channel_id'], 'attach_upload_limit');
+
foreach($files as $f) {
if(! $f)
continue;
@@ -1189,6 +1279,17 @@ function sync_files($channel, $files) {
}
else {
logger('sync_files attach does not exists: ' . print_r($att,true), LOGGER_DEBUG);
+
+ if($limit !== false) {
+ $r = q("select sum(filesize) as total from attach where aid = %d ",
+ intval($channel['channel_account_id'])
+ );
+ if(($r) && (($r[0]['total'] + $att['filesize']) > $limit)) {
+ logger('service class limit exceeded');
+ continue;
+ }
+ }
+
create_table_from_array('attach',$att);
}
@@ -1245,6 +1346,7 @@ function sync_files($channel, $files) {
logger('attachment store failed',LOGGER_NORMAL,LOG_ERR);
}
if($f['photo']) {
+
foreach($f['photo'] as $p) {
unset($p['id']);
$p['aid'] = $channel['channel_account_id'];
@@ -1266,6 +1368,7 @@ function sync_files($channel, $files) {
dbesc($p['resource_id']),
intval($channel['channel_id'])
);
+ $update_xchan = $p['edited'];
}
// same for cover photos
@@ -1285,19 +1388,20 @@ function sync_files($channel, $files) {
else
$p['content'] = (($p['content'])? base64_decode($p['content']) : '');
- if(intval($p['imgscale']) && (! $p['content'])) {
+ if(intval($p['imgscale']) && (! empty($p['content']))) {
$time = datetime_convert();
- $parr = array('hash' => $channel['channel_hash'],
+ $parr = array(
+ 'hash' => $channel['channel_hash'],
'time' => $time,
- 'resource' => $att['hash'],
+ 'resource' => $p['resource_id'],
'revision' => 0,
'signature' => base64url_encode(rsa_sign($channel['channel_hash'] . '.' . $time, $channel['channel_prvkey'])),
- 'resolution' => $p['imgscale']
+ 'resolution' => intval($p['imgscale'])
);
- $stored_image = $newfname . '-' . intval($p['imgscale']);
+ $stored_image = $newfname . '-' . $p['imgscale'];
$fp = fopen($stored_image,'w');
if(! $fp) {
@@ -1306,7 +1410,6 @@ function sync_files($channel, $files) {
}
$redirects = 0;
-
$headers = [];
$headers['Accept'] = 'application/x-zot+json' ;
$headers['Sigtoken'] = random_string();
@@ -1314,8 +1417,17 @@ function sync_files($channel, $files) {
$x = z_post_url($fetch_url,$parr,$redirects,[ 'filep' => $fp, 'headers' => $headers]);
fclose($fp);
- $p['content'] = file_get_contents($stored_image);
- unlink($stored_image);
+
+ // Override remote hub thumbnails storage settings
+ if(! boolval(get_config('system','filesystem_storage_thumbnails', 0))) {
+ $p['os_storage'] = 0;
+ $p['content'] = file_get_contents($stored_image);
+ @unlink($stored_image);
+ }
+ else {
+ $p['os_storage'] = 1;
+ $p['content'] = $stored_image;
+ }
}
if(!isset($p['display_path']))
@@ -1347,6 +1459,16 @@ function sync_files($channel, $files) {
create_table_from_array('photo',$p, [ 'content' ] );
}
}
+
+ }
+
+ // Set xchan photo date to prevent thumbnails fetch for clones on profile update packet recieve
+ if(isset($update_xchan)) {
+
+ $x = q("UPDATE xchan SET xchan_photo_date = '%s' WHERE xchan_hash = '%s'",
+ dbescdate($update_xchan),
+ dbesc($channel['channel_hash'])
+ );
}
\Zotlabs\Daemon\Master::Summon([ 'Thumbnail' , $att['hash'] ]);
diff --git a/include/items.php b/include/items.php
index 30e758add..95b696034 100755
--- a/include/items.php
+++ b/include/items.php
@@ -763,11 +763,11 @@ function get_item_elements($x,$allow_code = false) {
// check the supplied signature against the supplied content.
// Note that we will purify the content which could change it.
- $r = q("select xchan_pubkey from xchan where xchan_hash = '%s' limit 1",
+ $r = q("select xchan_pubkey, xchan_network from xchan where xchan_hash = '%s' limit 1",
dbesc($arr['author_xchan'])
);
if($r) {
- if($r[0]['xchan_pubkey']) {
+ if($r[0]['xchan_pubkey'] && $r[0]['xchan_network'] === 'zot') {
if(rsa_verify($x['body'],base64url_decode($arr['sig']),$r[0]['xchan_pubkey'])) {
$arr['item_verified'] = 1;
}
@@ -914,6 +914,16 @@ function import_author_xchan($x) {
if(array_key_exists('network',$x) && $x['network'] === 'zot')
return $y;
+ // perform zot6 discovery
+
+ if($x['url']) {
+ $y = discover_by_webbie($x['url'],'zot6');
+
+ if($y) {
+ return $y;
+ }
+ }
+
if($x['network'] === 'rss') {
$y = import_author_rss($x);
}
@@ -1920,11 +1930,21 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
if($parent_deleted)
$arr['item_deleted'] = 1;
- $r = q("SELECT id FROM item WHERE mid = '%s' AND uid = %d and revision = %d LIMIT 1",
- dbesc($arr['mid']),
- intval($arr['uid']),
- intval($arr['revision'])
- );
+ if($arr['uuid']) {
+ $r = q("SELECT id FROM item WHERE uuid = '%s' AND uid = %d and revision = %d LIMIT 1",
+ dbesc($arr['uuid']),
+ intval($arr['uid']),
+ intval($arr['revision'])
+ );
+ }
+ else {
+ $r = q("SELECT id FROM item WHERE mid = '%s' AND uid = %d and revision = %d LIMIT 1",
+ dbesc($arr['mid']),
+ intval($arr['uid']),
+ intval($arr['revision'])
+ );
+ }
+
if($r) {
logger('duplicate item ignored. ' . print_r($arr,true));
$ret['message'] = 'duplicate post.';
@@ -4258,7 +4278,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
if($arr['mid'])
$sql_options .= " and parent_mid = '" . dbesc($arr['mid']) . "' ";
- $sql_extra = " AND item.parent IN ( SELECT parent FROM item WHERE item_thread_top = 1 $sql_options $item_normal ) ";
+ $sql_extra = " AND item.parent IN ( SELECT parent FROM item WHERE $item_uids and item_thread_top = 1 $sql_options $item_normal ) ";
if($arr['since_id'])
$sql_extra .= " and item.id > " . $since_id . " ";
@@ -4688,7 +4708,7 @@ function sync_an_item($channel_id,$item_id) {
if($r) {
xchan_query($r);
$sync_item = fetch_post_tags($r);
- build_sync_packet($channel_d,array('item' => array(encode_item($sync_item[0],true))));
+ build_sync_packet($channel_id, array('item' => array(encode_item($sync_item[0],true))));
}
}
diff --git a/include/js_strings.php b/include/js_strings.php
index c053e5666..f01fa87ae 100644
--- a/include/js_strings.php
+++ b/include/js_strings.php
@@ -33,6 +33,7 @@ function js_strings() {
'$name_empty' => t('A channel name is required.'),
'$name_ok1' => t('This is a '),
'$name_ok2' => t(' channel name'),
+ '$to_reply' => t('Back to reply'),
// translatable prefix and suffix strings for jquery.timeago -
// using the defaults set below if left untranslated, empty strings if
diff --git a/include/message.php b/include/message.php
index 037c59c60..2486beb83 100644
--- a/include/message.php
+++ b/include/message.php
@@ -220,8 +220,8 @@ function send_message($uid = 0, $recipient = '', $body = '', $subject = '', $rep
foreach($images as $image) {
if(! stristr($image,z_root() . '/photo/'))
continue;
- $image_uri = substr($image,strrpos($image,'/') + 1);
- $image_uri = substr($image_uri,0, strpos($image_uri,'-'));
+ $image_uri = substr($image, strrpos($image, '/') + 1);
+ $image_uri = substr($image_uri, 0, strpos($image_uri, '.') - 2);
$r = q("UPDATE photo SET allow_cid = '%s' WHERE resource_id = '%s' AND uid = %d and allow_cid = '%s'",
dbesc('<' . $recipient . '>'),
dbesc($image_uri),
diff --git a/include/nav.php b/include/nav.php
index 58e13dd93..3e1acd306 100644
--- a/include/nav.php
+++ b/include/nav.php
@@ -42,6 +42,10 @@ function nav($template = 'default') {
require_once('include/conversation.php');
+ $nav_apps = [];
+ $navbar_apps = [];
+ $channel_apps = [];
+
$channel_apps[] = channel_apps($is_owner, App::$profile['channel_address']);
@@ -179,7 +183,6 @@ function nav($template = 'default') {
$search_form_action = 'search';
}
-
$nav['search'] = ['search', t('Search'), "", t('Search site @name, !forum, #tag, ?docs, content'), $search_form_action];
/**
@@ -378,16 +381,15 @@ function channel_apps($is_owner = false, $nickname = null) {
if(App::$is_sys)
return '';
- if(! get_pconfig($uid, 'system', 'channelapps','1'))
- return '';
-
$channel = App::get_channel();
if($channel && is_null($nickname))
$nickname = $channel['channel_address'];
$uid = ((App::$profile['profile_uid']) ? App::$profile['profile_uid'] : local_channel());
- $account_id = ((App::$profile['profile_uid']) ? App::$profile['channel_account_id'] : App::$channel['channel_account_id']);
+
+ if(! get_pconfig($uid, 'system', 'channelapps','1'))
+ return;
if($uid == local_channel()) {
return;
diff --git a/include/network.php b/include/network.php
index 8ac71011e..c754625cd 100644
--- a/include/network.php
+++ b/include/network.php
@@ -114,6 +114,13 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) {
@curl_setopt($ch, CURLOPT_TIMEOUT, (($curl_time !== false) ? $curl_time : 60));
}
+ if(x($opts,'connecttimeout') && intval($opts['connecttimeout'])) {
+ @curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, intval($opts['connecttimeout']));
+ }
+ else {
+ $curl_contime = intval(@get_config('system','curl_connecttimeout'));
+ @curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, (($curl_contime !== false) ? $curl_contime : 30));
+ }
if(x($opts,'http_auth')) {
// "username" . ':' . "password"
@@ -867,13 +874,16 @@ function xml2array($contents, $namespaces = true, $get_attributes=1, $priority =
}
-function email_header_encode($in_str, $charset = 'UTF-8') {
+function email_header_encode($in_str, $charset = 'UTF-8', $header = 'Subject') {
+
+
$out_str = $in_str;
$need_to_convert = false;
for($x = 0; $x < strlen($in_str); $x ++) {
if((ord($in_str[$x]) == 0) || ((ord($in_str[$x]) > 128))) {
$need_to_convert = true;
+ break;
}
}
@@ -885,11 +895,11 @@ function email_header_encode($in_str, $charset = 'UTF-8') {
// define start delimimter, end delimiter and spacer
$end = "?=";
$start = "=?" . $charset . "?B?";
- $spacer = $end . "\r\n " . $start;
+ $spacer = $end . PHP_EOL . " " . $start;
// determine length of encoded text within chunks
// and ensure length is even
- $length = 75 - strlen($start) - strlen($end);
+ $length = 75 - strlen($start) - strlen($end) - (strlen($header) + 2);
/*
[EDIT BY danbrown AT php DOT net: The following
@@ -1789,8 +1799,8 @@ function z_mail($params) {
$messageHeader =
$params['additionalMailHeader'] .
- "From: $fromName <{$params['fromEmail']}>\n" .
- "Reply-To: $fromName <{$params['replyTo']}>\n" .
+ "From: $fromName <{$params['fromEmail']}>" . PHP_EOL .
+ "Reply-To: $fromName <{$params['replyTo']}>" . PHP_EOL .
"Content-Type: text/plain; charset=UTF-8";
// send the message
diff --git a/include/oembed.php b/include/oembed.php
index 426197c5f..ee9e57c3f 100755
--- a/include/oembed.php
+++ b/include/oembed.php
@@ -1,6 +1,6 @@
<?php /** @file */
-use Zotlabs\Lib as Zlib;
+use Zotlabs\Lib\Cache;
function oembed_replacecb($matches){
@@ -133,7 +133,6 @@ function oembed_fetch_url($embedurl){
}
}
-
$txt = null;
// we should try to cache this and avoid a lookup on each render
@@ -143,10 +142,22 @@ function oembed_fetch_url($embedurl){
$furl = ((local_channel() && $zrl) ? zid($embedurl) : $embedurl);
- if($action !== 'block') {
- $txt = Zlib\Cache::get('[' . App::$videowidth . '] ' . $furl);
+ if($action !== 'block' && (! get_config('system','oembed_cache_disable'))) {
+ $txt = Cache::get('[' . App::$videowidth . '] ' . $furl);
}
+
+ if(strpos(strtolower($embedurl),'.pdf') !== false) {
+ $action = 'allow';
+ $j = [
+ 'html' => '<object data="' . $embedurl . '" type="application/pdf" style="width: 100%; height: 300px;"></object>',
+ 'title' => t('View PDF'),
+ 'type' => 'pdf'
+ ];
+ // set $txt to something so that we don't attempt to fetch what could be a lengthy pdf.
+ $txt = EMPTY_STR;
+ }
+
if(is_null($txt)) {
$txt = "";
@@ -215,20 +226,10 @@ function oembed_fetch_url($embedurl){
// save in cache
if(! get_config('system','oembed_cache_disable'))
- Zlib\Cache::set('[' . App::$videowidth . '] ' . $furl, $txt);
+ Cache::set('[' . App::$videowidth . '] ' . $furl, $txt);
}
- if(strpos(strtolower($embedurl),'.pdf') !== false) {
- $action = 'allow';
- $j = [
- 'html' => '<object data="' . $embedurl . '" type="application/pdf" style="width: 100%; height: 300px;"></object>',
- 'title' => t('View PDF'),
- 'type' => 'pdf'
- ];
-
- }
-
if(! $j) {
$j = json_decode($txt,true);
}
diff --git a/include/permissions.php b/include/permissions.php
index 115d96eca..501b2cc77 100644
--- a/include/permissions.php
+++ b/include/permissions.php
@@ -157,7 +157,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
// If we're still here, we have an observer, check the network.
if($channel_perm & PERMS_NETWORK) {
- if($x && $x[0]['xchan_network'] === 'zot') {
+ if($x && in_array($x[0]['xchan_network'],[ 'zot','zot6'])) {
$ret[$perm_name] = true;
continue;
}
@@ -192,7 +192,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
// They are in your address book, but haven't been approved
- if($channel_perm & PERMS_PENDING) {
+ if($channel_perm & PERMS_PENDING && (! intval($x[0]['abook_pseudo']))) {
$ret[$perm_name] = true;
continue;
}
@@ -316,10 +316,19 @@ function perm_is_allowed($uid, $observer_xchan, $permission, $check_siteblock =
if(! $x) {
// not in address book and no guest token, see if they've got an xchan
+
$y = q("select xchan_network from xchan where xchan_hash = '%s' limit 1",
dbesc($observer_xchan)
);
if($y) {
+
+ // This requires an explanation and the effects are subtle.
+ // The following line creates a fake connection, and this allows
+ // access tokens to have specific permissions even though they are
+ // not actual connections.
+ // The existence of this fake entry must be checked when dealing
+ // with connection related permissions.
+
$x = array(pseudo_abook($y[0]));
}
}
@@ -327,7 +336,6 @@ function perm_is_allowed($uid, $observer_xchan, $permission, $check_siteblock =
}
$abperms = load_abconfig($uid,$observer_xchan,'my_perms');
}
-
// system is blocked to anybody who is not authenticated
@@ -349,6 +357,7 @@ function perm_is_allowed($uid, $observer_xchan, $permission, $check_siteblock =
return true;
// If it's an unauthenticated observer, we only need to see if PERMS_PUBLIC is set
+ // We just did that.
if(! $observer_xchan) {
return false;
@@ -357,7 +366,7 @@ function perm_is_allowed($uid, $observer_xchan, $permission, $check_siteblock =
// If we're still here, we have an observer, check the network.
if($channel_perm & PERMS_NETWORK) {
- if (($x && $x[0]['xchan_network'] === 'zot') || ($y && $y[0]['xchan_network'] === 'zot'))
+ if ($x && in_array($x[0]['xchan_network'], ['zot','zot6']))
return true;
}
@@ -373,8 +382,7 @@ function perm_is_allowed($uid, $observer_xchan, $permission, $check_siteblock =
return false;
}
- // From here on we require that the observer be a connection and
- // handle whether we're allowing any, approved or specific ones
+ // From here on we require that the observer be a connection or pseudo connection
if(! $x) {
return false;
@@ -382,7 +390,7 @@ function perm_is_allowed($uid, $observer_xchan, $permission, $check_siteblock =
// They are in your address book, but haven't been approved
- if($channel_perm & PERMS_PENDING) {
+ if($channel_perm & PERMS_PENDING && (! intval($x[0]['abook_pseudo']))) {
return true;
}
diff --git a/include/photos.php b/include/photos.php
index 44406e0b0..7ea2729ae 100644
--- a/include/photos.php
+++ b/include/photos.php
@@ -277,8 +277,7 @@ function photo_upload($channel, $observer, $args) {
if(($width > 1024 || $height > 1024) && (! $errors))
$ph->scaleImage(1024);
- $p['imgscale'] = 1;
- $r1 = $ph->save($p);
+ $r1 = $ph->storeThumbnail($p, PHOTO_RES_1024);
$link[1] = array(
'rel' => 'alternate',
'type' => 'text/html',
@@ -292,8 +291,7 @@ function photo_upload($channel, $observer, $args) {
if(($width > 640 || $height > 640) && (! $errors))
$ph->scaleImage(640);
- $p['imgscale'] = 2;
- $r2 = $ph->save($p);
+ $r2 = $ph->storeThumbnail($p, PHOTO_RES_640);
$link[2] = array(
'rel' => 'alternate',
'type' => 'text/html',
@@ -307,8 +305,7 @@ function photo_upload($channel, $observer, $args) {
if(($width > 320 || $height > 320) && (! $errors))
$ph->scaleImage(320);
- $p['imgscale'] = 3;
- $r3 = $ph->save($p);
+ $r3 = $ph->storeThumbnail($p, PHOTO_RES_320);
$link[3] = array(
'rel' => 'alternate',
'type' => 'text/html',
diff --git a/include/security.php b/include/security.php
index 493d34699..38cb72263 100644
--- a/include/security.php
+++ b/include/security.php
@@ -306,6 +306,7 @@ function change_channel($change_channel) {
*
* @return string additional SQL where statement
*/
+
function permissions_sql($owner_id, $remote_observer = null, $table = '') {
$local_channel = local_channel();
@@ -316,7 +317,7 @@ function permissions_sql($owner_id, $remote_observer = null, $table = '') {
* default permissions - anonymous user
*/
- if($table)
+ if ($table)
$table .= '.';
$sql = " AND {$table}allow_cid = ''
@@ -329,38 +330,63 @@ function permissions_sql($owner_id, $remote_observer = null, $table = '') {
* Profile owner - everything is visible
*/
- if(($local_channel) && ($local_channel == $owner_id)) {
- $sql = '';
+ if (($local_channel) && ($local_channel == $owner_id)) {
+ return EMPTY_STR;
}
/**
- * Authenticated visitor. Unless pre-verified,
- * check that the contact belongs to this $owner_id
- * and load the groups the visitor belongs to.
- * If pre-verified, the caller is expected to have already
- * done this and passed the groups into this function.
+ * Authenticated visitor.
*/
else {
+
$observer = ((! is_null($remote_observer)) ? $remote_observer : get_observer_hash());
- if($observer) {
- $groups = init_groups_visitor($observer);
- $gs = '<<>>'; // should be impossible to match
+ if ($observer) {
+
+ $sec = get_security_ids($owner_id,$observer);
- if(is_array($groups) && count($groups)) {
- foreach($groups as $g)
- $gs .= '|<' . $g . '>';
+ // always allow the channel owner, even if authenticated as a visitor
+
+ if ($sec['channel_id']) {
+ foreach ($sec['channel_id'] as $ch) {
+ if ($observer === $ch) {
+ return EMPTY_STR;
+ }
+ }
+ }
+
+ if (is_array($sec['allow_cid']) && count($sec['allow_cid'])) {
+ $ca = [];
+ foreach ($sec['allow_cid'] as $c) {
+ $ca[] = '<' . $c . '>';
+ }
+ $cs = implode('|',$ca);
+ }
+ else {
+ $cs = '<<>>'; // should be impossible to match
}
+
+ if (is_array($sec['allow_gid']) && count($sec['allow_gid'])) {
+ $ga = [];
+ foreach ($sec['allow_gid'] as $g) {
+ $ga[] = '<' . $g . '>';
+ }
+ $gs = implode('|',$ga);
+ }
+ else {
+ $gs = '<<>>'; // should be impossible to match
+ }
+
$regexop = db_getfunc('REGEXP');
$sql = sprintf(
- " AND ( NOT ({$table}deny_cid like '%s' OR {$table}deny_gid $regexop '%s')
- AND ( {$table}allow_cid like '%s' OR {$table}allow_gid $regexop '%s' OR ( {$table}allow_cid = '' AND {$table}allow_gid = '') )
+ " AND ( NOT ({$table}deny_cid $regexop '%s' OR {$table}deny_gid $regexop '%s')
+ AND ( {$table}allow_cid $regexop '%s' OR {$table}allow_gid $regexop '%s' OR ( {$table}allow_cid = '' AND {$table}allow_gid = '') )
)
",
- dbesc(protect_sprintf( '%<' . $observer . '>%')),
+ dbesc($cs),
dbesc($gs),
- dbesc(protect_sprintf( '%<' . $observer . '>%')),
+ dbesc($cs),
dbesc($gs)
);
}
@@ -377,6 +403,7 @@ function permissions_sql($owner_id, $remote_observer = null, $table = '') {
*
* @return string additional SQL where statement
*/
+
function item_permissions_sql($owner_id, $remote_observer = null) {
$local_channel = local_channel();
@@ -398,37 +425,59 @@ function item_permissions_sql($owner_id, $remote_observer = null) {
}
/**
- * Authenticated visitor. Unless pre-verified,
- * check that the contact belongs to this $owner_id
- * and load the groups the visitor belongs to.
- * If pre-verified, the caller is expected to have already
- * done this and passed the groups into this function.
+ * Authenticated visitor.
*/
else {
- $observer = (($remote_observer) ? $remote_observer : get_observer_hash());
- if($observer) {
+ $observer = (($remote_observer) ? $remote_observer : get_observer_hash());
- $s = scopes_sql($owner_id,$observer);
+ if($observer) {
- $groups = init_groups_visitor($observer);
+ $scope = scopes_sql($owner_id,$observer);
+ $sec = get_security_ids($owner_id,$observer);
- $gs = '<<>>'; // should be impossible to match
+ // always allow the channel owner, even if authenticated as a visitor
+
+ if($sec['channel_id']) {
+ foreach($sec['channel_id'] as $ch) {
+ if($observer === $ch) {
+ return EMPTY_STR;
+ }
+ }
+ }
+
+ if (is_array($sec['allow_cid']) && count($sec['allow_cid'])) {
+ $ca = [];
+ foreach ($sec['allow_cid'] as $c) {
+ $ca[] = '<' . $c . '>';
+ }
+ $cs = implode('|',$ca);
+ }
+ else {
+ $cs = '<<>>'; // should be impossible to match
+ }
- if(is_array($groups) && count($groups)) {
- foreach($groups as $g)
- $gs .= '|<' . $g . '>';
+ if (is_array($sec['allow_gid']) && count($sec['allow_gid'])) {
+ $ga = [];
+ foreach ($sec['allow_gid'] as $g) {
+ $ga[] = '<' . $g . '>';
+ }
+ $gs = implode('|',$ga);
+ }
+ else {
+ $gs = '<<>>'; // should be impossible to match
}
+
$regexop = db_getfunc('REGEXP');
$sql = sprintf(
- " AND (( NOT (deny_cid like '%s' OR deny_gid $regexop '%s')
- AND ( allow_cid like '%s' OR allow_gid $regexop '%s' OR ( allow_cid = '' AND allow_gid = '' AND item_private = 0 ))
- ) OR ( item_private = 1 $s ))
+ " AND (( NOT (deny_cid $regexop '%s' OR deny_gid $regexop '%s')
+ AND ( allow_cid $regexop '%s' OR allow_gid $regexop '%s' OR ( allow_cid = '' AND allow_gid = '' AND item_private = 0 ))
+ ) OR ( item_private = 1 $scope ))
",
- dbesc(protect_sprintf( '%<' . $observer . '>%')),
+ dbesc($cs),
dbesc($gs),
- dbesc(protect_sprintf( '%<' . $observer . '>%')),
+ dbesc($cs),
dbesc($gs)
);
}
@@ -465,40 +514,57 @@ function scopes_sql($uid,$observer) {
}
-
-
-
-
-
/**
* @param string $observer_hash
*
* @return string additional SQL where statement
*/
+
function public_permissions_sql($observer_hash) {
- $groups = init_groups_visitor($observer_hash);
+ $owner_id = 0;
- $gs = '<<>>'; // should be impossible to match
+ if ($observer_hash) {
+
+ $sec = get_security_ids($owner_id,$observer_hash);
+
+ if (is_array($sec['allow_cid']) && count($sec['allow_cid'])) {
+ $ca = [];
+ foreach ($sec['allow_cid'] as $c) {
+ $ca[] = '<' . $c . '>';
+ }
+ $cs = implode('|',$ca);
+ }
+ else {
+ $cs = '<<>>'; // should be impossible to match
+ }
+
+ if (is_array($sec['allow_gid']) && count($sec['allow_gid'])) {
+ $ga = [];
+ foreach ($sec['allow_gid'] as $g) {
+ $ga[] = '<' . $g . '>';
+ }
+ $gs = implode('|',$ga);
+ }
+ else {
+ $gs = '<<>>'; // should be impossible to match
+ }
- if(is_array($groups) && count($groups)) {
- foreach($groups as $g)
- $gs .= '|<' . $g . '>';
- }
- $sql = '';
- if($observer_hash) {
$regexop = db_getfunc('REGEXP');
$sql = sprintf(
- " OR (( NOT (deny_cid like '%s' OR deny_gid $regexop '%s')
- AND ( allow_cid like '%s' OR allow_gid $regexop '%s' OR ( allow_cid = '' AND allow_gid = '' AND item_private = 0 ) )
- ))
+ " AND ( NOT (deny_cid $regexop '%s' OR deny_gid $regexop '%s')
+ AND ( allow_cid $regexop '%s' OR allow_gid $regexop '%s' OR ( allow_cid = '' AND allow_gid = '' AND item_private = 0) )
+ )
",
- dbesc(protect_sprintf( '%<' . $observer_hash . '>%')),
+ dbesc($cs),
dbesc($gs),
- dbesc(protect_sprintf( '%<' . $observer_hash . '>%')),
+ dbesc($cs),
dbesc($gs)
);
}
+ else {
+ $sql = EMPTY_STR;
+ }
return $sql;
}
@@ -510,7 +576,7 @@ function public_permissions_sql($observer_hash) {
* In this implementation, a security token is reusable (if the user submits a form, goes back and resubmits the form, maybe with small changes;
* or if the security token is used for ajax-calls that happen several times), but only valid for a certain amout of time (3hours).
* The "typename" seperates the security tokens of different types of forms. This could be relevant in the following case:
- * A security token is used to protekt a link from CSRF (e.g. the "delete this profile"-link).
+ * A security token is used to protect a link from CSRF (e.g. the "delete this profile"-link).
* If the new page contains by any chance external elements, then the used security token is exposed by the referrer.
* Actually, important actions should not be triggered by Links / GET-Requests at all, but somethimes they still are,
* so this mechanism brings in some damage control (the attacker would be able to forge a request to a form of this type, but not to forms of other types).
@@ -564,24 +630,40 @@ function check_form_security_token_ForbiddenOnErr($typename = '', $formname = 'f
function init_groups_visitor($contact_id) {
$groups = [];
- // private profiles are treated as a virtual group
-
- $r = q("SELECT abook_profile from abook where abook_xchan = '%s' and abook_profile != '' ",
+ $x = q("select * from xchan where xchan_hash = '%s'",
dbesc($contact_id)
);
- if($r) {
- foreach($r as $rv) {
+
+ if (! $x) {
+ return $groups;
+ }
+
+ // include xchans for all zot-like networks
+
+ $xchans = q("select xchan_hash from xchan where xchan_hash = '%s' OR ( xchan_guid = '%s' AND xchan_pubkey = '%s' ) ",
+ dbesc($contact_id),
+ dbesc($x[0]['xchan_guid']),
+ dbesc($x[0]['xchan_pubkey'])
+ );
+
+ if($xchans) {
+ $hashes = ids_to_querystr($xchans,'xchan_hash',true);
+ }
+
+ // private profiles are treated as a virtual group
+
+ $r = q("SELECT abook_profile from abook where abook_xchan in ( " . protect_sprintf($hashes) . " ) and abook_profile != '' ");
+ if ($r) {
+ foreach ($r as $rv) {
$groups[] = 'vp.' . $rv['abook_profile'];
}
}
- // physical groups this channel is a member of
+ // physical groups this identity is a member of
- $r = q("SELECT hash FROM pgrp left join pgrp_member on pgrp.id = pgrp_member.gid WHERE xchan = '%s' ",
- dbesc($contact_id)
- );
- if($r) {
- foreach($r as $rr)
+ $r = q("SELECT hash FROM pgrp left join pgrp_member on pgrp.id = pgrp_member.gid WHERE xchan in ( " . protect_sprintf($hashes) . " ) ");
+ if ($r) {
+ foreach ($r as $rr)
$groups[] = $rr['hash'];
}
return $groups;
@@ -589,6 +671,70 @@ function init_groups_visitor($contact_id) {
+
+function get_security_ids($channel_id, $ob_hash) {
+
+ $ret = [
+ 'channel_id' => [],
+ 'allow_cid' => [],
+ 'allow_gid' => []
+ ];
+
+ if($channel_id) {
+ $ch = q("select channel_hash, channel_portable_id from channel where channel_id = %d",
+ intval($channel_id)
+ );
+ if($ch) {
+ $ret['channel_id'][] = $ch[0]['channel_hash'];
+ $ret['channel_id'][] = $ch[0]['channel_portable_id'];
+ }
+ }
+
+ $groups = [];
+
+ $x = q("select * from xchan where xchan_hash = '%s'",
+ dbesc($ob_hash)
+ );
+
+ if ($x) {
+
+ // include xchans for all zot-like networks
+
+ $xchans = q("select xchan_hash from xchan where xchan_hash = '%s' OR ( xchan_guid = '%s' AND xchan_pubkey = '%s' ) ",
+ dbesc($ob_hash),
+ dbesc($x[0]['xchan_guid']),
+ dbesc($x[0]['xchan_pubkey'])
+ );
+
+ if ($xchans) {
+ $ret['allow_cid'] = ids_to_array($xchans,'xchan_hash');
+ $hashes = ids_to_querystr($xchans,'xchan_hash',true);
+
+ // private profiles are treated as a virtual group
+
+ $r = q("SELECT abook_profile from abook where abook_xchan in ( " . protect_sprintf($hashes) . " ) and abook_profile != '' ");
+ if($r) {
+ foreach ($r as $rv) {
+ $groups[] = 'vp.' . $rv['abook_profile'];
+ }
+ }
+
+ // physical groups this identity is a member of
+
+ $r = q("SELECT hash FROM pgrp left join pgrp_member on pgrp.id = pgrp_member.gid WHERE xchan in ( " . protect_sprintf($hashes) . " ) ");
+ if($r) {
+ foreach ($r as $rv) {
+ $groups[] = $rv['hash'];
+ }
+ }
+ $ret['allow_gid'] = $groups;
+ }
+ }
+
+ return $ret;
+}
+
+
// This is used to determine which uid have posts which are visible to the logged in user (from the API) for the
// public_timeline, and we can use this in a community page by making
// $perms = (PERMS_NETWORK|PERMS_PUBLIC) unless logged in.
diff --git a/include/taxonomy.php b/include/taxonomy.php
index 46d95458c..b0304de5b 100644
--- a/include/taxonomy.php
+++ b/include/taxonomy.php
@@ -543,8 +543,6 @@ function article_catblock($uid,$count = 0,$authors = '',$owner = '', $flags = 0,
function dir_tagblock($link,$r) {
$o = '';
- $observer = get_observer_hash();
-
if(! $r)
$r = App::$data['directory_keywords'];
diff --git a/include/text.php b/include/text.php
index b017b038a..6a2a9e427 100644
--- a/include/text.php
+++ b/include/text.php
@@ -20,7 +20,7 @@ define('RANDOM_STRING_TEXT', 0x01 );
/**
* @brief This is our template processor.
*
- * @param string|SmartyEngine $s the string requiring macro substitution,
+ * @param string SmartyEngine $s the string requiring macro substitution,
* or an instance of SmartyEngine
* @param array $r key value pairs (search => replace)
*
@@ -409,7 +409,8 @@ function autoname($len) {
* @return string Escaped text.
*/
function xmlify($str) {
- $buffer = '';
+
+ //$buffer = '';
if(is_array($str)) {
@@ -418,7 +419,7 @@ function xmlify($str) {
btlogger('xmlify called with array: ' . print_r($str,true), LOGGER_NORMAL, LOG_WARNING);
}
-
+/*
$len = mb_strlen($str);
for($x = 0; $x < $len; $x ++) {
$char = mb_substr($str,$x,1);
@@ -452,6 +453,11 @@ function xmlify($str) {
$buffer = trim($buffer);
return($buffer);
+*/
+ $buffer = htmlspecialchars($str, ENT_QUOTES, "UTF-8");
+ $buffer = trim($buffer);
+ return $buffer;
+
}
/**
@@ -464,10 +470,23 @@ function xmlify($str) {
* @return string
*/
function unxmlify($s) {
+/*
$ret = str_replace('&amp;', '&', $s);
$ret = str_replace(array('&lt;', '&gt;', '&quot;', '&apos;'), array('<', '>', '"', "'"), $ret);
return $ret;
+*/
+
+ if(is_array($s)) {
+
+ // allow to fall through so we ge a PHP error, as the log statement will
+ // probably get lost in the noise unless we're specifically looking for it.
+
+ btlogger('unxmlify called with array: ' . print_r($s,true), LOGGER_NORMAL, LOG_WARNING);
+ }
+
+ $ret = htmlspecialchars_decode($s, ENT_QUOTES);
+ return $ret;
}
/**
@@ -1682,7 +1701,12 @@ function prepare_body(&$item,$attach = false,$opts = false) {
$s .= prepare_binary($item);
}
else {
- $s .= prepare_text($item['body'],$item['mimetype'], $opts);
+ if($item['summary']) {
+ $s .= prepare_text('[summary]' . $item['summary'] . '[/summary]' . $item['body'],$item['mimetype'],$opts);
+ }
+ else {
+ $s .= prepare_text($item['body'],$item['mimetype'], $opts);
+ }
}
$event = (($item['obj_type'] === ACTIVITY_OBJ_EVENT) ? format_event_obj($item['obj']) : false);
@@ -2545,15 +2569,6 @@ function design_tools() {
*/
function website_portation_tools() {
- $channel = App::get_channel();
- $sys = false;
-
- if(App::$is_sys && is_site_admin()) {
- require_once('include/channel.php');
- $channel = get_sys_channel();
- $sys = true;
- }
-
return replace_macros(get_markup_template('website_portation_tools.tpl'), [
'$title' => t('Import'),
'$import_label' => t('Import website...'),
@@ -2721,7 +2736,6 @@ function handle_tag(&$body, &$str_tags, $profile_uid, $tag, $in_network = true)
$name = substr($tag,(($exclusive) ? 2 : 1));
$newname = $name; // make a copy that we can mess with
- $tagcid = 0;
$r = null;
@@ -2780,14 +2794,9 @@ function handle_tag(&$body, &$str_tags, $profile_uid, $tag, $in_network = true)
}
-
-
-
-
$fn_results = [];
$access_tag = EMPTY_STR;
-
// $r is set if we found something
if($r) {
@@ -3081,13 +3090,12 @@ function item_url_replace($channel,&$item,$old,$new,$oldnick = '') {
if($oldnick)
json_url_replace('/' . $oldnick . '/' ,'/' . $channel['channel_address'] . '/' ,$item['target']);
}
+
+ $item['body'] = preg_replace("/(\[zrl=".preg_quote($old,'/')."\/(photos|gallery)\/".$channel['channel_address'].".+\]\[zmg=\d+x\d+\])".preg_quote($old,'/')."\/(.+\[\/zmg\])/", '${1}'.$new.'/${3}', $item['body']);
+ $item['body'] = preg_replace("/".preg_quote($old,'/')."\/(search|\w+\/".$channel['channel_address'].")/", $new.'/${1}', $item['body']);
- $x = preg_replace("/".preg_quote($old,'/')."\/(search|\w+\/".$channel['channel_address'].")/", $new.'/${1}', $item['body']);
- if($x) {
- $item['body'] = $x;
- $item['sig'] = base64url_encode(rsa_sign($item['body'],$channel['channel_prvkey']));
- $item['item_verified'] = 1;
- }
+ $item['sig'] = base64url_encode(rsa_sign($item['body'],$channel['channel_prvkey']));
+ $item['item_verified'] = 1;
$item['plink'] = str_replace($old,$new,$item['plink']);
if($oldnick)
@@ -3241,7 +3249,7 @@ function flatten_array_recursive($arr) {
$ret = array_merge($ret, $tmp);
}
}
- elseif($a) {
+ elseif(isset($a)) {
$ret[] = $a;
}
}
diff --git a/include/xchan.php b/include/xchan.php
index 4cbfb42c5..4fcdf9fce 100644
--- a/include/xchan.php
+++ b/include/xchan.php
@@ -1,6 +1,7 @@
<?php
use Zotlabs\Zot6\HTTPSig;
+use Zotlabs\Lib\Libzot;
function xchan_store_lowlevel($arr) {
diff --git a/include/zid.php b/include/zid.php
index a37ebe1f6..ed79de76a 100644
--- a/include/zid.php
+++ b/include/zid.php
@@ -1,5 +1,6 @@
<?php
+use Zotlabs\Lib\Verify;
function is_matrix_url($url) {
@@ -270,34 +271,45 @@ function red_zrlify_img_callback($matches) {
*/
function owt_init($token) {
- \Zotlabs\Lib\Verify::purge('owt', '3 MINUTE');
+ Verify::purge('owt', '3 MINUTE');
- $ob_hash = \Zotlabs\Lib\Verify::get_meta('owt', 0, $token);
+ $key = Verify::get_meta('owt', 0, $token);
- if($ob_hash === false) {
+ if($key === false) {
+ return;
+ }
+
+ $parts = explode(',',$key,2);
+ if(count($parts) < 2) {
return;
}
$r = q("select * from hubloc left join xchan on xchan_hash = hubloc_hash
- where hubloc_addr = '%s' order by hubloc_id desc",
- dbesc($ob_hash)
+ where hubloc_network = '%s' and hubloc_addr = '%s' order by hubloc_id desc",
+ dbesc($parts[0]),
+ dbesc($parts[1])
);
if(! $r) {
+
// finger them if they can't be found.
- $j = \Zotlabs\Zot\Finger::run($ob_hash, null);
+ // @todo check that this is still needed. Discovery should have been performed in the Owa module.
+
+ $j = \Zotlabs\Zot\Finger::run($parts[1], null);
if ($j['success']) {
import_xchan($j);
$r = q("select * from hubloc left join xchan on xchan_hash = hubloc_hash
- where hubloc_addr = '%s' order by hubloc_id desc",
- dbesc($ob_hash)
+ where hubloc_network = '%s' and hubloc_addr = '%s' order by hubloc_id desc",
+ dbesc($parts[0]),
+ dbesc($parts[1])
);
}
}
if(! $r) {
- logger('owt: unable to finger ' . $ob_hash);
+ logger('owt: unable to finger ' . $key);
return;
}
+
$hubloc = $r[0];
$_SESSION['authenticated'] = 1;
@@ -324,7 +336,7 @@ function owt_init($token) {
if (! $delegate_success) {
// normal visitor (remote_channel) login session credentials
$_SESSION['visitor_id'] = $hubloc['xchan_hash'];
- $_SESSION['my_url'] = $hubloc['xchan_url'];
+ $_SESSION['my_url'] = $hubloc['xchan_url'];
$_SESSION['my_address'] = $hubloc['hubloc_addr'];
$_SESSION['remote_hub'] = $hubloc['hubloc_url'];
$_SESSION['DNT'] = 1;
@@ -332,7 +344,7 @@ function owt_init($token) {
$arr = [
'xchan' => $hubloc,
- 'url' => \App::$query_string,
+ 'url' => App::$query_string,
'session' => $_SESSION
];
/**
@@ -344,11 +356,61 @@ function owt_init($token) {
*/
call_hooks('magic_auth_success', $arr);
- \App::set_observer($hubloc);
+ App::set_observer($hubloc);
require_once('include/security.php');
- \App::set_groups(init_groups_visitor($_SESSION['visitor_id']));
+ App::set_groups(init_groups_visitor($_SESSION['visitor_id']));
if(! get_config('system', 'hide_owa_greeting'))
- info(sprintf( t('OpenWebAuth: %1$s welcomes %2$s'),\App::get_hostname(), $hubloc['xchan_name']));
+ info(sprintf( t('OpenWebAuth: %1$s welcomes %2$s'),App::get_hostname(), $hubloc['xchan_name']));
logger('OpenWebAuth: auth success from ' . $hubloc['xchan_addr']);
}
+
+
+function observer_auth($ob_hash) {
+
+ if($ob_hash === false) {
+ return;
+ }
+
+ $r = q("select * from hubloc left join xchan on xchan_hash = hubloc_hash
+ where hubloc_addr = '%s' or hubloc_id_url = '%s' or hubloc_hash = '%s' order by hubloc_id desc",
+ dbesc($ob_hash),
+ dbesc($ob_hash),
+ dbesc($ob_hash)
+ );
+
+ if(! $r) {
+ // finger them if they can't be found.
+ $wf = discover_by_webbie($ob_hash);
+ if($wf) {
+ $r = q("select * from hubloc left join xchan on xchan_hash = hubloc_hash
+ where hubloc_addr = '%s' or hubloc_id_url = '%s' or hubloc_hash = '%s' order by hubloc_id desc",
+ dbesc($ob_hash),
+ dbesc($ob_hash),
+ dbesc($ob_hash)
+ );
+ }
+ }
+ if(! $r) {
+ logger('unable to finger ' . $ob_hash);
+ return;
+ }
+
+ // Note: this has no Libzot namespace so prefers zot over zot6
+
+ $hubloc = zot_record_preferred($r);
+
+ $_SESSION['authenticated'] = 1;
+
+ // normal visitor (remote_channel) login session credentials
+ $_SESSION['visitor_id'] = $hubloc['xchan_hash'];
+ $_SESSION['my_url'] = $hubloc['xchan_url'];
+ $_SESSION['my_address'] = $hubloc['hubloc_addr'];
+ $_SESSION['remote_hub'] = $hubloc['hubloc_url'];
+ $_SESSION['DNT'] = 1;
+
+ App::set_observer($hubloc);
+ require_once('include/security.php');
+ App::set_groups(init_groups_visitor($_SESSION['visitor_id']));
+
+}
diff --git a/include/zot.php b/include/zot.php
index 3b089831b..b99eeb1ec 100644
--- a/include/zot.php
+++ b/include/zot.php
@@ -925,46 +925,62 @@ 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) {
+ // @FIXME This should be removed in future when profile photo update by file sync procedure will be applied
+ // on most hubs in the network
+ // <---
$ph = z_fetch_url($arr['photo'], true);
+
if($ph['success']) {
+
+ // Do not fetch already received thumbnails
+ $x = q("SELECT resource_id FROM photo WHERE uid = %d AND imgscale = %d AND filesize = %d LIMIT 1",
+ intval($local[0]['channel_id']),
+ intval(PHOTO_RES_PROFILE_300),
+ strlen($ph['body'])
+ );
+
+ if($x)
+ $hash = $x[0]['resource_id'];
+ else
+ $hash = import_channel_photo($ph['body'], $arr['photo_mimetype'], $local[0]['channel_account_id'], $local[0]['channel_id']);
+ }
+
+ if($hash) {
+ // unless proven otherwise
+ $is_default_profile = 1;
+
+ $profile = q("select is_default from profile where aid = %d and uid = %d limit 1",
+ intval($local[0]['channel_account_id']),
+ intval($local[0]['channel_id'])
+ );
+ if($profile) {
+ if(! intval($profile[0]['is_default']))
+ $is_default_profile = 0;
+ }
- $hash = import_channel_photo($ph['body'], $arr['photo_mimetype'], $local[0]['channel_account_id'], $local[0]['channel_id']);
-
- if($hash) {
- // unless proven otherwise
- $is_default_profile = 1;
-
- $profile = q("select is_default from profile where aid = %d and uid = %d limit 1",
+ // If setting for the default profile, unset the profile photo flag from any other photos I own
+ if($is_default_profile) {
+ q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND resource_id != '%s' AND aid = %d AND uid = %d",
+ intval(PHOTO_NORMAL),
+ intval(PHOTO_PROFILE),
+ dbesc($hash),
intval($local[0]['channel_account_id']),
intval($local[0]['channel_id'])
);
- if($profile) {
- if(! intval($profile[0]['is_default']))
- $is_default_profile = 0;
- }
-
- // If setting for the default profile, unset the profile photo flag from any other photos I own
- if($is_default_profile) {
- q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND resource_id != '%s' AND aid = %d AND uid = %d",
- intval(PHOTO_NORMAL),
- intval(PHOTO_PROFILE),
- dbesc($hash),
- intval($local[0]['channel_account_id']),
- intval($local[0]['channel_id'])
- );
- }
}
-
- // reset the names in case they got messed up when we had a bug in this function
- $photos = array(
- z_root() . '/photo/profile/l/' . $local[0]['channel_id'],
- z_root() . '/photo/profile/m/' . $local[0]['channel_id'],
- z_root() . '/photo/profile/s/' . $local[0]['channel_id'],
- $arr['photo_mimetype'],
- false
- );
}
+ // --->
+
+ // reset the names in case they got messed up when we had a bug in this function
+ $photos = array(
+ z_root() . '/photo/profile/l/' . $local[0]['channel_id'],
+ z_root() . '/photo/profile/m/' . $local[0]['channel_id'],
+ z_root() . '/photo/profile/s/' . $local[0]['channel_id'],
+ $arr['photo_mimetype'],
+ false
+ );
}
else {
$photos = import_xchan_photo($arr['photo'], $xchan_hash);
@@ -1712,13 +1728,17 @@ function allowed_public_recips($msg) {
$condensed_recips[] = $rr['hash'];
$results = array();
- $r = q("select channel_hash as hash from channel left join abook on abook_channel = channel_id where abook_xchan = '%s' and channel_removed = 0 ",
+ $r = q("select channel_hash as hash, channel_id from channel left join abook on abook_channel = channel_id where abook_xchan = '%s' and channel_removed = 0 ",
dbesc($hash)
);
if($r) {
- foreach($r as $rr)
+ foreach($r as $rr) {
+ $cfg = get_abconfig($rr['channel_id'],$rr['hash'],'their_perms','view_stream');
+ if((! $cfg) && $scope !== 'any connections')
+ continue;
if(in_array($rr['hash'],$condensed_recips))
$results[] = array('hash' => $rr['hash']);
+ }
}
return $results;
}
@@ -1840,7 +1860,7 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $
intval($channel['channel_id'])
);
if ($parent) {
- $allowed = can_comment_on_post($d['hash'],$parent[0]);
+ $allowed = can_comment_on_post($sender['hash'],$parent[0]);
}
}
@@ -3630,7 +3650,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
'channel_r_storage', 'channel_r_pages', 'channel_w_stream', 'channel_w_wall',
'channel_w_comment', 'channel_w_mail', 'channel_w_like', 'channel_w_tagwall',
'channel_w_chat', 'channel_w_storage', 'channel_w_pages', 'channel_a_republish',
- 'channel_a_delegate', 'channel_moved'
+ 'channel_a_delegate', 'channel_moved', 'channel_r_photos', 'channel_w_photos'
];
$clean = array();
@@ -5266,3 +5286,25 @@ function zot_reply_notify($data) {
$ret['success'] = true;
json_return_and_die($ret);
}
+
+
+function zot_record_preferred($arr, $check = 'hubloc_network') {
+
+ if(! $arr) {
+ return $arr;
+ }
+
+ foreach($arr as $v) {
+ if($v[$check] === 'zot') {
+ return $v;
+ }
+ }
+ foreach($arr as $v) {
+ if($v[$check] === 'zot6') {
+ return $v;
+ }
+ }
+
+ return $arr[0];
+
+}