aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorMario Vavti <mario@mariovavti.com>2018-05-04 09:46:27 +0200
committerMario Vavti <mario@mariovavti.com>2018-05-04 09:46:27 +0200
commitbe4c9a9598350fb4333480f0c7b302acebcddfd4 (patch)
treefb0c2606ad4ca0bc1a710d6fdf82f55c326b3427 /include
parentf15c12376adad6534c8c0ea547a7548697eb8379 (diff)
parentbe852ba857f4cb8e75574a762945b50c8bddcff9 (diff)
downloadvolse-hubzilla-be4c9a9598350fb4333480f0c7b302acebcddfd4.tar.gz
volse-hubzilla-be4c9a9598350fb4333480f0c7b302acebcddfd4.tar.bz2
volse-hubzilla-be4c9a9598350fb4333480f0c7b302acebcddfd4.zip
Merge branch '3.4RC'3.4
Diffstat (limited to 'include')
-rw-r--r--include/account.php3
-rw-r--r--include/api.php30
-rw-r--r--include/api_auth.php57
-rw-r--r--include/attach.php179
-rw-r--r--include/auth.php18
-rw-r--r--include/bbcode.php111
-rw-r--r--include/channel.php31
-rw-r--r--include/connections.php14
-rw-r--r--include/conversation.php15
-rw-r--r--include/datetime.php8
-rwxr-xr-xinclude/dba/dba_driver.php25
-rwxr-xr-xinclude/dba/dba_pdo.php4
-rw-r--r--include/event.php22
-rw-r--r--include/features.php39
-rw-r--r--include/feedutils.php9
-rw-r--r--include/follow.php23
-rw-r--r--include/help.php2
-rw-r--r--include/html2bbcode.php1
-rw-r--r--include/hubloc.php3
-rw-r--r--include/import.php9
-rwxr-xr-xinclude/items.php151
-rw-r--r--include/nav.php4
-rw-r--r--include/network.php58
-rwxr-xr-xinclude/oembed.php7
-rw-r--r--include/permissions.php2
-rw-r--r--include/photo/photo_driver.php7
-rw-r--r--include/photo/photo_gd.php5
-rw-r--r--include/photo/photo_imagick.php13
-rw-r--r--include/photos.php19
-rwxr-xr-xinclude/plugin.php63
-rw-r--r--include/queue_fn.php6
-rw-r--r--include/security.php9
-rw-r--r--include/statistics_fns.php44
-rw-r--r--include/taxonomy.php92
-rw-r--r--include/text.php72
-rw-r--r--include/zid.php21
-rw-r--r--include/zot.php92
37 files changed, 879 insertions, 389 deletions
diff --git a/include/account.php b/include/account.php
index 40cf281c3..2b24364f4 100644
--- a/include/account.php
+++ b/include/account.php
@@ -23,6 +23,7 @@ function get_account_by_id($account_id) {
function check_account_email($email) {
+ $email = punify($email);
$result = array('error' => false, 'message' => '');
// Caution: empty email isn't counted as an error in this function.
@@ -139,7 +140,7 @@ function create_account($arr) {
$result = array('success' => false, 'email' => '', 'password' => '', 'message' => '');
$invite_code = ((x($arr,'invite_code')) ? notags(trim($arr['invite_code'])) : '');
- $email = ((x($arr,'email')) ? notags(trim($arr['email'])) : '');
+ $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 );
diff --git a/include/api.php b/include/api.php
index c91590070..6a05a40a5 100644
--- a/include/api.php
+++ b/include/api.php
@@ -193,26 +193,18 @@ require_once('include/api_zot.php');
$redirect = trim($_REQUEST['redirect_uris'][0]);
else
$redirect = trim($_REQUEST['redirect_uris']);
+ $grant_types = trim($_REQUEST['grant_types']);
+ $scope = trim($_REQUEST['scope']);
$icon = trim($_REQUEST['logo_uri']);
- if($oauth2) {
- $r = q("INSERT INTO oauth_clients (client_id, client_secret, redirect_uri, grant_types, scope, user_id)
- VALUES ( '%s', '%s', '%s', null, null, null ) ",
- dbesc($key),
- dbesc($secret),
- dbesc($redirect)
- );
- }
- else {
- $r = q("INSERT INTO clients (client_id, pw, clname, redirect_uri, icon, uid)
- VALUES ('%s','%s','%s','%s','%s',%d)",
- dbesc($key),
- dbesc($secret),
- dbesc($name),
- dbesc($redirect),
- dbesc($icon),
- intval(0)
- );
- }
+ $r = q("INSERT INTO oauth_clients (client_id, client_secret, redirect_uri, grant_types, scope, user_id)
+ VALUES ( '%s', '%s', '%s', '%s', '%s', '%s' ) ",
+ dbesc($key),
+ dbesc($secret),
+ dbesc($redirect),
+ dbesc($grant_types),
+ dbesc($scope),
+ dbesc((string) api_user())
+ );
$ret['client_id'] = $key;
$ret['client_secret'] = $secret;
diff --git a/include/api_auth.php b/include/api_auth.php
index 5c0bcb317..e2f7ab155 100644
--- a/include/api_auth.php
+++ b/include/api_auth.php
@@ -14,25 +14,58 @@ function api_login(&$a){
// login with oauth
try {
- $oauth = new ZotOAuth1();
- $req = OAuth1Request::from_request();
+ // OAuth 2.0
+ $storage = new \Zotlabs\Identity\OAuth2Storage(\DBA::$dba->db);
+ $server = new \Zotlabs\Identity\OAuth2Server($storage);
+ $request = \OAuth2\Request::createFromGlobals();
+ if ($server->verifyResourceRequest($request)) {
+ $token = $server->getAccessTokenData($request);
+ $uid = $token['user_id'];
+ $r = q("SELECT * FROM channel WHERE channel_id = %d LIMIT 1",
+ intval($uid)
+ );
+ if (count($r)) {
+ $record = $r[0];
+ } else {
+ header('HTTP/1.0 401 Unauthorized');
+ echo('This api requires login');
+ killme();
+ }
+
+ $_SESSION['uid'] = $record['channel_id'];
+ $_SESSION['addr'] = $_SERVER['REMOTE_ADDR'];
+
+ $x = q("select * from account where account_id = %d LIMIT 1",
+ intval($record['channel_account_id'])
+ );
+ if ($x) {
+ require_once('include/security.php');
+ authenticate_success($x[0], null, true, false, true, true);
+ $_SESSION['allow_api'] = true;
+ call_hooks('logged_in', App::$user);
+ return;
+ }
+ } else {
+ // OAuth 1.0
+ $oauth = new ZotOAuth1();
+ $req = OAuth1Request::from_request();
- list($consumer,$token) = $oauth->verify_request($req);
+ list($consumer, $token) = $oauth->verify_request($req);
- if (!is_null($token)){
- $oauth->loginUser($token->uid);
+ if (!is_null($token)) {
+ $oauth->loginUser($token->uid);
- App::set_oauth_key($consumer->key);
+ App::set_oauth_key($consumer->key);
- call_hooks('logged_in', App::$user);
- return;
+ call_hooks('logged_in', App::$user);
+ return;
+ }
+ killme();
}
- killme();
- }
- catch(Exception $e) {
+ } catch (Exception $e) {
logger($e->getMessage());
}
-
+
// workarounds for HTTP-auth in CGI mode
foreach([ 'REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION' ] as $head) {
diff --git a/include/attach.php b/include/attach.php
index 39269eb03..0d2b43b58 100644
--- a/include/attach.php
+++ b/include/attach.php
@@ -266,14 +266,12 @@ function attach_by_hash($hash, $observer_hash, $rev = 0) {
return $ret;
}
- if(! perm_is_allowed($r[0]['uid'], $observer_hash, 'view_storage')) {
+ if(! attach_can_view($r[0]['uid'], $observer_hash, $hash)) {
$ret['message'] = t('Permission denied.');
return $ret;
}
- $sql_extra = permissions_sql($r[0]['uid'],$observer_hash);
-
- // Now we'll see if we can access the attachment
+ // We've already checked for existence and permissions
$r = q("SELECT * FROM attach WHERE hash = '%s' and uid = %d $sql_extra LIMIT 1",
dbesc($hash),
@@ -281,20 +279,12 @@ function attach_by_hash($hash, $observer_hash, $rev = 0) {
);
if(! $r) {
- $ret['message'] = t('Permission denied.');
+ $ret['message'] = t('Unknown error.');
return $ret;
}
$r[0]['content'] = dbunescbin($r[0]['content']);
- if($r[0]['folder']) {
- $x = attach_can_view_folder($r[0]['uid'],$observer_hash,$r[0]['folder']);
- if(! $x) {
- $ret['message'] = t('Permission denied.');
- return $ret;
- }
- }
-
$ret['success'] = true;
$ret['data'] = $r[0];
@@ -302,6 +292,29 @@ function attach_by_hash($hash, $observer_hash, $rev = 0) {
}
+function attach_can_view($uid,$ob_hash,$resource) {
+
+ $sql_extra = permissions_sql($uid,$ob_hash);
+ $hash = $resource;
+
+ if(! perm_is_allowed($uid,$ob_hash,'view_storage')) {
+ return false;
+ }
+
+ $r = q("select folder from attach where hash = '%s' and uid = %d $sql_extra",
+ dbesc($hash),
+ intval($uid)
+ );
+ if(! $r) {
+ return false;
+ }
+
+ return attach_can_view_folder($uid,$ob_hash,$r[0]['folder']);
+
+}
+
+
+
function attach_can_view_folder($uid,$ob_hash,$folder_hash) {
$sql_extra = permissions_sql($uid,$ob_hash);
@@ -948,6 +961,16 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
return $ret;
}
+ // Update the folder timestamp @todo recurse to the storage root folder
+
+ if($folder_hash) {
+ q("UPDATE attach set edited = '%s' where hash = '%s' and uid = %d and is_dir = 1",
+ dbesc($edited),
+ dbesc($folder_hash),
+ intval($channel_id)
+ );
+ }
+
// Caution: This re-uses $sql_options set further above
$r = q("select * from attach where uid = %d and hash = '%s' $sql_options limit 1",
@@ -2276,33 +2299,22 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
if(! ($c && $resource_id))
return false;
+
+ // find the resource to be moved
+
$r = q("select * from attach where hash = '%s' and uid = %d limit 1",
dbesc($resource_id),
intval($channel_id)
);
- if(! $r)
+ if(! $r) {
+ logger('resource_id not found');
return false;
+ }
$oldstorepath = dbunescbin($r[0]['content']);
- if($r[0]['is_dir']) {
- $move_success = true;
- $x = q("select hash from attach where folder = '%s' and uid = %d",
- dbesc($r[0]['hash']),
- intval($channel_id)
- );
- if($x) {
- foreach($x as $xv) {
- $rs = attach_move($channel_id,$xv['hash'],$r[0]['hash']);
- if(! $rs) {
- $move_success = false;
- break;
- }
- }
- }
- return $move_success;
- }
+ // find the resource we are moving to
if($new_folder_hash) {
$n = q("select * from attach where hash = '%s' and uid = %d and is_dir = 1 limit 1",
@@ -2316,6 +2328,10 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
$newstorepath = dbunescbin($n[0]['content']) . '/' . $resource_id;
}
else {
+
+ // root directory
+
+ $newdirname = EMPTY_STR;
$newstorepath = 'store/' . $c['channel_address'] . '/' . $resource_id;
}
@@ -2325,56 +2341,61 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
$filename = $r[0]['filename'];
- $s = q("select filename, id, hash, filesize from attach where filename = '%s' and folder = '%s' ",
- dbesc($filename),
- dbesc($new_folder_hash)
- );
+ // don't do duplicate check unless our parent folder has changed.
- if($s) {
- $overwrite = get_pconfig($channel_id,'system','overwrite_dup_files');
- if($overwrite) {
- /// @fixme
- return;
- }
- else {
- if(strpos($filename,'.') !== false) {
- $basename = substr($filename,0,strrpos($filename,'.'));
- $ext = substr($filename,strrpos($filename,'.'));
+ if($r[0]['folder'] !== $new_folder_hash) {
+
+ $s = q("select filename, id, hash, filesize from attach where filename = '%s' and folder = '%s' ",
+ dbesc($filename),
+ dbesc($new_folder_hash)
+ );
+
+ if($s) {
+ $overwrite = get_pconfig($channel_id,'system','overwrite_dup_files');
+ if($overwrite) {
+ /// @fixme
+ return;
}
else {
- $basename = $filename;
- $ext = '';
- }
+ if(strpos($filename,'.') !== false) {
+ $basename = substr($filename,0,strrpos($filename,'.'));
+ $ext = substr($filename,strrpos($filename,'.'));
+ }
+ else {
+ $basename = $filename;
+ $ext = '';
+ }
- $matches = false;
- if(preg_match('/(.*?)\([0-9]{1,}\)$/',$basename,$matches))
- $basename = $matches[1];
+ $matches = false;
+ if(preg_match('/(.*?)\([0-9]{1,}\)$/',$basename,$matches))
+ $basename = $matches[1];
- $v = q("select filename from attach where ( filename = '%s' OR filename like '%s' ) and folder = '%s' ",
- dbesc($basename . $ext),
- dbesc($basename . '(%)' . $ext),
- dbesc($new_folder_hash)
- );
+ $v = q("select filename from attach where ( filename = '%s' OR filename like '%s' ) and folder = '%s' ",
+ dbesc($basename . $ext),
+ dbesc($basename . '(%)' . $ext),
+ dbesc($new_folder_hash)
+ );
- if($v) {
- $x = 1;
+ if($v) {
+ $x = 1;
- do {
- $found = false;
- foreach($v as $vv) {
- if($vv['filename'] === $basename . '(' . $x . ')' . $ext) {
- $found = true;
- break;
+ do {
+ $found = false;
+ foreach($v as $vv) {
+ if($vv['filename'] === $basename . '(' . $x . ')' . $ext) {
+ $found = true;
+ break;
+ }
}
+ if($found)
+ $x++;
}
- if($found)
- $x++;
+ while($found);
+ $filename = $basename . '(' . $x . ')' . $ext;
}
- while($found);
- $filename = $basename . '(' . $x . ')' . $ext;
+ else
+ $filename = $basename . $ext;
}
- else
- $filename = $basename . $ext;
}
}
@@ -2413,6 +2434,24 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
);
}
+ if($r[0]['is_dir']) {
+ $move_success = true;
+ $x = q("select hash from attach where folder = '%s' and uid = %d",
+ dbesc($r[0]['hash']),
+ intval($channel_id)
+ );
+ if($x) {
+ foreach($x as $xv) {
+ $rs = attach_move($channel_id,$xv['hash'],$r[0]['hash']);
+ if(! $rs) {
+ $move_success = false;
+ break;
+ }
+ }
+ }
+ return $move_success;
+ }
+
return true;
}
diff --git a/include/auth.php b/include/auth.php
index 6f5e58361..c44eeb8fc 100644
--- a/include/auth.php
+++ b/include/auth.php
@@ -37,6 +37,7 @@ require_once('include/security.php');
function account_verify_password($login, $pass) {
$ret = [ 'account' => null, 'channel' => null, 'xchan' => null ];
+ $login = punify($login);
$email_verify = get_config('system', 'verify_email');
$register_policy = get_config('system', 'register_policy');
@@ -144,8 +145,17 @@ if((isset($_SESSION)) && (x($_SESSION, 'authenticated')) &&
// process logout request
$args = array('channel_id' => local_channel());
call_hooks('logging_out', $args);
- App::$session->nuke();
- info( t('Logged out.') . EOL);
+
+
+ if($_SESSION['delegate'] && $_SESSION['delegate_push']) {
+ $_SESSION = $_SESSION['delegate_push'];
+ info( t('Delegation session ended.') . EOL);
+ }
+ else {
+ App::$session->nuke();
+ info( t('Logged out.') . EOL);
+ }
+
goaway(z_root());
}
@@ -235,7 +245,7 @@ else {
$record = null;
$addon_auth = array(
- 'username' => trim($_POST['username']),
+ 'username' => punify(trim($_POST['username'])),
'password' => trim($_POST['password']),
'authenticated' => 0,
'user_record' => null
@@ -261,7 +271,7 @@ else {
$verify = account_verify_password($_POST['username'], $_POST['password']);
if($verify && array_key_exists('reason',$verify) && $verify['reason'] === 'unvalidated') {
notice( t('Email validation is incomplete. Please check your email.'));
- goaway(z_root() . '/email_validation/' . bin2hex(trim(escape_tags($_POST['username']))));
+ goaway(z_root() . '/email_validation/' . bin2hex(punify(trim(escape_tags($_POST['username'])))));
}
elseif($verify) {
$atoken = $verify['xchan'];
diff --git a/include/bbcode.php b/include/bbcode.php
index 03a46444b..345b5b025 100644
--- a/include/bbcode.php
+++ b/include/bbcode.php
@@ -85,12 +85,14 @@ function tryoembed($match) {
function nakedoembed($match) {
$url = ((count($match) == 2) ? $match[1] : $match[2]);
- $o = oembed_fetch_url($url);
+ $strip_url = strip_escaped_zids($url);
+
+ $o = oembed_fetch_url($strip_url);
if ($o['type'] == 'error')
- return $match[0];
+ return str_replace($url,$strip_url,$match[0]);
- return '[embed]' . $url . '[/embed]';
+ return '[embed]' . $strip_url . '[/embed]';
}
function tryzrlaudio($match) {
@@ -311,6 +313,19 @@ function bb_ShareAttributes($match) {
if ($matches[1] != "")
$posted = $matches[1];
+ $auth = "";
+ preg_match("/auth='(.*?)'/ism", $attributes, $matches);
+ if ($matches[1] != "") {
+ if($matches[1] === 'true')
+ $auth = true;
+ else
+ $auth = false;
+ }
+
+ if($auth === EMPTY_STR) {
+ $auth = is_matrix_url($profile);
+ }
+
// message_id is never used, do we still need it?
$message_id = "";
preg_match("/message_id='(.*?)'/ism", $attributes, $matches);
@@ -329,7 +344,7 @@ function bb_ShareAttributes($match) {
$headline = '<div class="shared_container"> <div class="shared_header">';
if ($avatar != "")
- $headline .= '<a href="' . zid($profile) . '" ><img src="' . $avatar . '" alt="' . $author . '" height="32" width="32" /></a>';
+ $headline .= '<a href="' . (($auth) ? zid($profile) : $profile) . '" ><img src="' . $avatar . '" alt="' . $author . '" height="32" width="32" /></a>';
if(strpos($link,'/cards/'))
$type = t('card');
@@ -341,8 +356,8 @@ function bb_ShareAttributes($match) {
// Bob Smith wrote the following post 2 hours ago
$fmt = sprintf( t('%1$s wrote the following %2$s %3$s'),
- '<a href="' . zid($profile) . '" >' . $author . '</a>',
- '<a href="' . zid($link) . '" >' . $type . '</a>',
+ '<a href="' . (($auth) ? zid($profile) : $profile) . '" >' . $author . '</a>',
+ '<a href="' . (($auth) ? zid($link) : $link) . '" >' . $type . '</a>',
$reldate
);
@@ -393,7 +408,7 @@ function bb_ShareAttributesSimple($match) {
if ($matches[1] != "")
$profile = $matches[1];
- $text = html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8') . ' <a href="' . $profile . '">' . $author . '</a>: div class="reshared-content">' . $match[2] . '</div>';
+ $text = html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8') . ' <a href="' . $profile . '">' . $author . '</a>: <div class="reshared-content">' . $match[2] . '</div>';
return($text);
}
@@ -668,6 +683,31 @@ function bb_fixtable_lf($match) {
}
+function bbtopoll($s) {
+
+ $pl = [];
+
+ $match = '';
+ if(! preg_match("/\[poll=(.*?)\](.*?)\[\/poll\]/ism",$s,$match)) {
+ return null;
+ }
+ $pl['poll_id'] = $match[1];
+ $pl['poll_question'] = $match[2];
+
+ $match = '';
+ if(preg_match_all("/\[poll\-answer=(.*?)\](.*?)\[\/poll\-answer\]/is",$s,$match,PREG_SET_ORDER)) {
+ $pl['answer'] = [];
+ foreach($match as $m) {
+ $ans = [ 'answer_id' => $m[1], 'answer_text' => $m[2] ];
+ $pl['answer'][] = $ans;
+ }
+ }
+
+ return $pl;
+
+}
+
+
function parseIdentityAwareHTML($Text) {
// Hide all [noparse] contained bbtags by spacefying them
@@ -742,10 +782,16 @@ function parseIdentityAwareHTML($Text) {
function bbcode($Text, $options = []) {
+ if(! is_array($options)) {
+ $options = [];
+ }
+
$preserve_nl = ((array_key_exists('preserve_nl',$options)) ? $options['preserve_nl'] : false);
$tryoembed = ((array_key_exists('tryoembed',$options)) ? $options['tryoembed'] : true);
$cache = ((array_key_exists('cache',$options)) ? $options['cache'] : false);
+ $newwin = ((array_key_exists('newwin',$options)) ? $options['newwin'] : true);
+ $target = (($newwin) ? ' target="_blank" ' : '');
call_hooks('bbcode_filter', $Text);
@@ -766,6 +812,11 @@ function bbcode($Text, $options = []) {
$ev = bbtoevent($Text);
+ // and the same with polls
+
+ $pl = bbtopoll($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
@@ -891,7 +942,7 @@ function bbcode($Text, $options = []) {
if($tryoembed) {
$Text = preg_replace_callback("/([^\]\='".'"'."\/]|^|\#\^)(https?\:\/\/$urlchars+)/ismu", 'tryoembed', $Text);
}
- $Text = preg_replace("/([^\]\='".'"'."\/]|^|\#\^)(https?\:\/\/$urlchars+)/ismu", '$1<a href="$2" target="_blank" rel="nofollow noopener">$2</a>', $Text);
+ $Text = preg_replace("/([^\]\='".'"'."\/]|^|\#\^)(https?\:\/\/$urlchars+)/ismu", '$1<a href="$2" ' . $target . ' rel="nofollow noopener">$2</a>', $Text);
}
if (strpos($Text,'[/share]') !== false) {
@@ -903,16 +954,16 @@ function bbcode($Text, $options = []) {
}
}
if (strpos($Text,'[/url]') !== false) {
- $Text = preg_replace("/\#\^\[url\]([$URLSearchString]*)\[\/url\]/ism", '<span class="bookmark-identifier">#^</span><a class="bookmark" href="$1" target="_blank" rel="nofollow noopener" >$1</a>', $Text);
- $Text = preg_replace("/\#\^\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '<span class="bookmark-identifier">#^</span><a class="bookmark" href="$1" target="_blank" rel="nofollow noopener" >$2</a>', $Text);
- $Text = preg_replace("/\[url\]([$URLSearchString]*)\[\/url\]/ism", '<a href="$1" target="_blank" rel="nofollow noopener" >$1</a>', $Text);
- $Text = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '<a href="$1" target="_blank" rel="nofollow noopener" >$2</a>', $Text);
+ $Text = preg_replace("/\#\^\[url\]([$URLSearchString]*)\[\/url\]/ism", '<span class="bookmark-identifier">#^</span><a class="bookmark" href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
+ $Text = preg_replace("/\#\^\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '<span class="bookmark-identifier">#^</span><a class="bookmark" href="$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text);
+ $Text = preg_replace("/\[url\]([$URLSearchString]*)\[\/url\]/ism", '<a href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
+ $Text = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '<a href="$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text);
}
if (strpos($Text,'[/zrl]') !== false) {
- $Text = preg_replace("/\#\^\[zrl\]([$URLSearchString]*)\[\/zrl\]/ism", '<span class="bookmark-identifier">#^</span><a class="zrl bookmark" href="$1" target="_blank" rel="nofollow noopener" >$1</a>', $Text);
- $Text = preg_replace("/\#\^\[zrl\=([$URLSearchString]*)\](.*?)\[\/zrl\]/ism", '<span class="bookmark-identifier">#^</span><a class="zrl bookmark" href="$1" target="_blank" rel="nofollow noopener" >$2</a>', $Text);
- $Text = preg_replace("/\[zrl\]([$URLSearchString]*)\[\/zrl\]/ism", '<a class="zrl" href="$1" target="_blank" rel="nofollow noopener" >$1</a>', $Text);
- $Text = preg_replace("/\[zrl\=([$URLSearchString]*)\](.*?)\[\/zrl\]/ism", '<a class="zrl" href="$1" target="_blank" rel="nofollow noopener" >$2</a>', $Text);
+ $Text = preg_replace("/\#\^\[zrl\]([$URLSearchString]*)\[\/zrl\]/ism", '<span class="bookmark-identifier">#^</span><a class="zrl bookmark" href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
+ $Text = preg_replace("/\#\^\[zrl\=([$URLSearchString]*)\](.*?)\[\/zrl\]/ism", '<span class="bookmark-identifier">#^</span><a class="zrl bookmark" href="$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text);
+ $Text = preg_replace("/\[zrl\]([$URLSearchString]*)\[\/zrl\]/ism", '<a class="zrl" href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
+ $Text = preg_replace("/\[zrl\=([$URLSearchString]*)\](.*?)\[\/zrl\]/ism", '<a class="zrl" href="$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text);
}
if (get_account_techlevel() < 2)
@@ -920,8 +971,8 @@ function bbcode($Text, $options = []) {
// Perform MAIL Search
if (strpos($Text,'[/mail]') !== false) {
- $Text = preg_replace("/\[mail\]([$MAILSearchString]*)\[\/mail\]/", '<a href="mailto:$1" target="_blank" rel="nofollow noopener" >$1</a>', $Text);
- $Text = preg_replace("/\[mail\=([$MAILSearchString]*)\](.*?)\[\/mail\]/", '<a href="mailto:$1" target="_blank" rel="nofollow noopener" >$2</a>', $Text);
+ $Text = preg_replace("/\[mail\]([$MAILSearchString]*)\[\/mail\]/", '<a href="mailto:$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
+ $Text = preg_replace("/\[mail\=([$MAILSearchString]*)\](.*?)\[\/mail\]/", '<a href="mailto:$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text);
}
@@ -952,11 +1003,11 @@ function bbcode($Text, $options = []) {
}
// Check for strike-through text
if (strpos($Text,'[s]') !== false) {
- $Text = preg_replace("(\[s\](.*?)\[\/s\])ism", '<strike>$1</strike>', $Text);
+ $Text = preg_replace("(\[s\](.*?)\[\/s\])ism", '<span style="text-decoration: line-through;">$1</span>', $Text);
}
// Check for over-line text
if (strpos($Text,'[o]') !== false) {
- $Text = preg_replace("(\[o\](.*?)\[\/o\])ism", '<span class="overline">$1</span>', $Text);
+ $Text = preg_replace("(\[o\](.*?)\[\/o\])ism", '<span style="text-decoration: overline;">$1</span>', $Text);
}
if (strpos($Text,'[sup]') !== false) {
$Text = preg_replace("(\[sup\](.*?)\[\/sup\])ism", '<sup>$1</sup>', $Text);
@@ -1243,28 +1294,18 @@ function bbcode($Text, $options = []) {
// if video couldn't be embedded, link to it instead.
if (strpos($Text,'[/video]') !== false) {
- $Text = preg_replace("/\[video\](.*?)\[\/video\]/", '<a href="$1" target="_blank" rel="nofollow noopener" >$1</a>', $Text);
+ $Text = preg_replace("/\[video\](.*?)\[\/video\]/", '<a href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
}
if (strpos($Text,'[/audio]') !== false) {
- $Text = preg_replace("/\[audio\](.*?)\[\/audio\]/", '<a href="$1" target="_blank" rel="nofollow noopener" >$1</a>', $Text);
+ $Text = preg_replace("/\[audio\](.*?)\[\/audio\]/", '<a href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
}
if (strpos($Text,'[/zvideo]') !== false) {
- $Text = preg_replace("/\[zvideo\](.*?)\[\/zvideo\]/", '<a class="zid" href="$1" target="_blank" rel="nofollow noopener" >$1</a>', $Text);
+ $Text = preg_replace("/\[zvideo\](.*?)\[\/zvideo\]/", '<a class="zid" href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
}
if (strpos($Text,'[/zaudio]') !== false) {
- $Text = preg_replace("/\[zaudio\](.*?)\[\/zaudio\]/", '<a class="zid" href="$1" target="_blank" rel="nofollow noopener" >$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" rel="nofollow noopener" >$1</a>', $Text);
-// }
-// }
+ $Text = preg_replace("/\[zaudio\](.*?)\[\/zaudio\]/", '<a class="zid" href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
+ }
// oembed tag
$Text = oembed_bbcode2html($Text);
diff --git a/include/channel.php b/include/channel.php
index a754d3504..4bf490bf0 100644
--- a/include/channel.php
+++ b/include/channel.php
@@ -780,7 +780,7 @@ function identity_basic_export($channel_id, $sections = null) {
}
}
- if(in_array('channel',$sections)) {
+ if(in_array('channel',$sections) || in_array('profile',$sections)) {
$r = q("select * from profile where uid = %d",
intval($channel_id)
);
@@ -1234,7 +1234,7 @@ function profile_load($nickname, $profile = '') {
);
if($z) {
$p[0]['picdate'] = $z[0]['xchan_photo_date'];
- $p[0]['reddress'] = str_replace('@','&#x40;',$z[0]['xchan_addr']);
+ $p[0]['reddress'] = str_replace('@','&#x40;',unpunify($z[0]['xchan_addr']));
}
// fetch user tags if this isn't the default profile
@@ -1255,7 +1255,7 @@ function profile_load($nickname, $profile = '') {
App::$profile = $p[0];
App::$profile_uid = $p[0]['profile_uid'];
- App::$page['title'] = App::$profile['channel_name'] . " - " . channel_reddress(App::$profile);
+ App::$page['title'] = App::$profile['channel_name'] . " - " . unpunify(channel_reddress(App::$profile));
App::$profile['permission_to_view'] = $can_view_profile;
@@ -1573,14 +1573,25 @@ function advanced_profile() {
$profile['howlong'] = relative_date(App::$profile['howlong'], t('for %1$d %2$s'));
}
+ if(App::$profile['keywords']) {
+ $keywords = str_replace(',',' ', App::$profile['keywords']);
+ $keywords = str_replace(' ',' ', $keywords);
+ $karr = explode(' ', $keywords);
+ if($karr) {
+ for($cnt = 0; $cnt < count($karr); $cnt ++) {
+ $karr[$cnt] = '<a href="' . z_root() . '/directory/f=&keywords=' . trim($karr[$cnt]) . '">' . $karr[$cnt] . '</a>';
+ }
+ }
+ $profile['keywords'] = array( t('Tags:'), implode(' ', $karr));
+ }
+
+
if(App::$profile['sexual']) $profile['sexual'] = array( t('Sexual Preference:'), App::$profile['sexual'] );
if(App::$profile['homepage']) $profile['homepage'] = array( t('Homepage:'), linkify(App::$profile['homepage']) );
if(App::$profile['hometown']) $profile['hometown'] = array( t('Hometown:'), linkify(App::$profile['hometown']) );
- if(App::$profile['keywords']) $profile['keywords'] = array( t('Tags:'), App::$profile['keywords']);
-
if(App::$profile['politic']) $profile['politic'] = array( t('Political Views:'), App::$profile['politic']);
if(App::$profile['religion']) $profile['religion'] = array( t('Religion:'), App::$profile['religion']);
@@ -2552,7 +2563,7 @@ function channel_remove($channel_id, $local = true, $unset_session = false) {
q("DELETE FROM photo WHERE uid = %d", intval($channel_id));
q("DELETE FROM attach WHERE uid = %d", intval($channel_id));
q("DELETE FROM profile WHERE uid = %d", intval($channel_id));
- q("DELETE FROM src WHERE src_channel_id = %d", intval($channel_id));
+ q("DELETE FROM source WHERE src_channel_id = %d", intval($channel_id));
$r = q("select hash FROM attach WHERE uid = %d", intval($channel_id));
if($r) {
@@ -2714,7 +2725,7 @@ function anon_identity_init($reqvars) {
$hash = hash('md5',$anon_email);
- $x = q("select * from xchan where xchan_guid = '%s' and xchan_hash = '%s' and xchan_network = 'unknown' limit 1",
+ $x = q("select * from xchan where xchan_guid = '%s' and xchan_hash = '%s' and xchan_network = 'anon' limit 1",
dbesc($anon_email),
dbesc($hash)
);
@@ -2725,19 +2736,19 @@ function anon_identity_init($reqvars) {
'xchan_hash' => $hash,
'xchan_name' => $anon_name,
'xchan_url' => $anon_url,
- 'xchan_network' => 'unknown',
+ 'xchan_network' => 'anon',
'xchan_name_date' => datetime_convert()
]);
- $x = q("select * from xchan where xchan_guid = '%s' and xchan_hash = '%s' and xchan_network = 'unknown' limit 1",
+ $x = q("select * from xchan where xchan_guid = '%s' and xchan_hash = '%s' and xchan_network = 'anon' limit 1",
dbesc($anon_email),
dbesc($hash)
);
$photo = z_root() . '/' . get_default_profile_photo(300);
$photos = import_xchan_photo($photo,$hash);
- $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_guid = '%s' and xchan_hash = '%s' and xchan_network = 'unknown' ",
+ $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_guid = '%s' and xchan_hash = '%s' and xchan_network = 'anon' ",
dbesc(datetime_convert()),
dbesc($photos[0]),
dbesc($photos[1]),
diff --git a/include/connections.php b/include/connections.php
index e9d7daa2d..32baa94bd 100644
--- a/include/connections.php
+++ b/include/connections.php
@@ -100,7 +100,6 @@ function vcard_from_xchan($xchan, $observer = null, $mode = '') {
if(! $xchan)
return;
-// FIXME - show connect button to observer if appropriate
$connect = false;
if(local_channel()) {
$r = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1",
@@ -111,6 +110,12 @@ function vcard_from_xchan($xchan, $observer = null, $mode = '') {
$connect = t('Connect');
}
+ // don't provide a connect button for transient or one-way identities
+
+ if(in_array($xchan['xchan_network'],['rss','anon','unknown']) || strpos($xchan['xchan_addr'],'guest:') === 0) {
+ $connect = false;
+ }
+
if(array_key_exists('channel_id',$xchan))
App::$profile_uid = $xchan['channel_id'];
@@ -122,7 +127,7 @@ function vcard_from_xchan($xchan, $observer = null, $mode = '') {
return replace_macros(get_markup_template('xchan_vcard.tpl'),array(
'$name' => $xchan['xchan_name'],
'$photo' => ((is_array(App::$profile) && array_key_exists('photo',App::$profile)) ? App::$profile['photo'] : $xchan['xchan_photo_l']),
- '$follow' => $xchan['xchan_addr'],
+ '$follow' => (($xchan['xchan_addr']) ? $xchan['xchan_addr'] : $xchan['xchan_url']),
'$link' => zid($xchan['xchan_url']),
'$connect' => $connect,
'$newwin' => (($mode === 'chanview') ? t('New window') : ''),
@@ -421,7 +426,10 @@ function random_profile() {
for($i = 0; $i < $retryrandom; $i++) {
- $r = q("select xchan_url, xchan_hash from xchan left join hubloc on hubloc_hash = xchan_hash where xchan_hidden = 0 and xchan_system = 0 and hubloc_connected > %s - interval %s order by $randfunc limit 1",
+ $r = q("select xchan_url, xchan_hash from xchan left join hubloc on hubloc_hash = xchan_hash where
+ xchan_hidden = 0 and xchan_system = 0 and
+ xchan_network = 'zot' and xchan_deleted = 0 and
+ hubloc_connected > %s - interval %s order by $randfunc limit 1",
db_utcnow(),
db_quoteinterval('30 day')
);
diff --git a/include/conversation.php b/include/conversation.php
index 64beb1b0e..97dd402fc 100644
--- a/include/conversation.php
+++ b/include/conversation.php
@@ -404,7 +404,7 @@ function count_descendants($item) {
* @return boolean
*/
function visible_activity($item) {
- $hidden_activities = [ ACTIVITY_LIKE, ACTIVITY_DISLIKE, ACTIVITY_AGREE, ACTIVITY_DISAGREE, ACTIVITY_ABSTAIN, ACTIVITY_ATTEND, ACTIVITY_ATTENDNO, ACTIVITY_ATTENDMAYBE ];
+ $hidden_activities = [ ACTIVITY_LIKE, ACTIVITY_DISLIKE, ACTIVITY_AGREE, ACTIVITY_DISAGREE, ACTIVITY_ABSTAIN, ACTIVITY_ATTEND, ACTIVITY_ATTENDNO, ACTIVITY_ATTENDMAYBE, ACTIVITY_POLLRESPONSE ];
if(intval($item['item_notshown']))
return false;
@@ -930,7 +930,7 @@ function thread_action_menu($item,$mode = '') {
$menu[] = [
'menu' => 'view_source',
'title' => t('View Source'),
- 'icon' => 'eye',
+ 'icon' => 'code',
'action' => 'viewsrc(' . $item['id'] . '); return false;',
'href' => '#'
];
@@ -1039,7 +1039,7 @@ function thread_author_menu($item, $mode = '') {
if($posts_link) {
$menu[] = [
'menu' => 'view_posts',
- 'title' => t('Activity/Posts'),
+ 'title' => t('Recent Activity'),
'icon' => 'fw',
'action' => '',
'href' => $posts_link
@@ -1301,7 +1301,9 @@ function status_editor($a, $x, $popup = false) {
$id_select = '';
$webpage = ((x($x,'webpage')) ? $x['webpage'] : '');
-
+
+ $feature_auto_save_draft = ((feature_enabled($x['profile_uid'], 'auto_save_draft')) ? "true" : "false");
+
$tpl = get_markup_template('jot-header.tpl');
App::$page['htmlhead'] .= replace_macros($tpl, array(
@@ -1323,6 +1325,7 @@ function status_editor($a, $x, $popup = false) {
'$modalerroralbum' => t('Error getting album'),
'$nocomment_enabled' => t('Comments enabled'),
'$nocomment_disabled' => t('Comments disabled'),
+ '$auto_save_draft' => $feature_auto_save_draft,
));
$tpl = get_markup_template('jot.tpl');
@@ -1607,7 +1610,7 @@ function prepare_page($item) {
// prepare_body calls unobscure() as a side effect. Do it here so that
// the template will get passed an unobscured title.
- $body = prepare_body($item, true);
+ $body = prepare_body($item, [ 'newwin' => false ]);
if(App::$page['template'] == 'none') {
$tpl = 'page_display_empty.tpl';
@@ -1721,7 +1724,7 @@ function network_tabs() {
if(feature_enabled(local_channel(),'star_posts')) {
$tabs[] = array(
'label' => t('Starred'),
- 'url'=>z_root() . '/' . $cmd . ((x($_GET,'cid')) ? '/?f=&cid=' . $_GET['cid'] : '') . '&star=1',
+ 'url'=>z_root() . '/' . $cmd . '/?f=' . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : '') . '&star=1',
'sel'=>$starred_active,
'title' => t('Favourite Posts'),
);
diff --git a/include/datetime.php b/include/datetime.php
index 766c90d16..3a07f1ccf 100644
--- a/include/datetime.php
+++ b/include/datetime.php
@@ -125,10 +125,16 @@ function datetime_convert($from = 'UTC', $to = 'UTC', $s = 'now', $fmt = "Y-m-d
*/
function dob($dob) {
+ $y = substr($dob,0,4);
+ if((! ctype_digit($y)) || ($y < 1900))
+ $ignore_year = true;
+ else
+ $ignore_year = false;
+
if ($dob === '0000-00-00' || $dob === '')
$value = '';
else
- $value = (($year) ? datetime_convert('UTC','UTC',$dob,'Y-m-d') : datetime_convert('UTC','UTC',$dob,'m-d'));
+ $value = (($ignore_year) ? datetime_convert('UTC','UTC',$dob,'m-d') : datetime_convert('UTC','UTC',$dob,'Y-m-d'));
$o = replace_macros(get_markup_template("field_input.tpl"), [
'$field' => [ 'dob', t('Birthday'), $value, ((intval($value)) ? t('Age: ') . age($value,App::$user['timezone'],App::$user['timezone']) : ''), '', 'placeholder="' . t('YYYY-MM-DD or MM-DD') .'"' ]
diff --git a/include/dba/dba_driver.php b/include/dba/dba_driver.php
index b3298b673..9e9f24bb3 100755
--- a/include/dba/dba_driver.php
+++ b/include/dba/dba_driver.php
@@ -460,3 +460,28 @@ function db_logger($s,$level = LOGGER_NORMAL,$syslog = LOG_INFO) {
\DBA::$logging = false;
\DBA::$dba->debug = $saved;
}
+
+
+function db_columns($table) {
+
+ if($table) {
+ if(ACTIVE_DBTYPE === DBTYPE_POSTGRES) {
+ $r = q("SELECT column_name as field FROM information_schema.columns WHERE table_schema = 'public' AND table_name = '%s'",
+ dbesc($table)
+ );
+ if($r) {
+ return ids_to_array($r,'field');
+ }
+ }
+ else {
+ $r = q("show columns in %s",
+ dbesc($table)
+ );
+ if($r) {
+ return ids_to_array($r,'Field');
+ }
+ }
+ }
+
+ return [];
+} \ No newline at end of file
diff --git a/include/dba/dba_pdo.php b/include/dba/dba_pdo.php
index f24c5381a..5002f53e7 100755
--- a/include/dba/dba_pdo.php
+++ b/include/dba/dba_pdo.php
@@ -100,7 +100,9 @@ class dba_pdo extends dba_driver {
if($this->debug) {
db_logger('dba_pdo: DEBUG: ' . printable($sql) . ' returned ' . count($r) . ' results.', LOGGER_NORMAL, LOG_INFO);
- db_logger('dba_pdo: ' . printable(print_r($r,true)), LOGGER_NORMAL, LOG_INFO);
+ if(intval($this->debug) > 1) {
+ db_logger('dba_pdo: ' . printable(print_r($r,true)), LOGGER_NORMAL, LOG_INFO);
+ }
}
return (($this->error) ? false : $r);
diff --git a/include/event.php b/include/event.php
index 1077a3c64..84a16e8be 100644
--- a/include/event.php
+++ b/include/event.php
@@ -1322,3 +1322,25 @@ function translate_type($type) {
return [$type, t('Other') . ' (' . $type . ')'];
}
}
+
+
+function cal_store_lowlevel($arr) {
+
+ $store = [
+ 'cal_aid' => ((array_key_exists('cal_aid',$arr)) ? $arr['cal_aid'] : 0),
+ 'cal_uid' => ((array_key_exists('cal_uid',$arr)) ? $arr['cal_uid'] : 0),
+ 'cal_hash' => ((array_key_exists('cal_hash',$arr)) ? $arr['cal_hash'] : ''),
+ 'cal_name' => ((array_key_exists('cal_name',$arr)) ? $arr['cal_name'] : ''),
+ 'uri' => ((array_key_exists('uri',$arr)) ? $arr['uri'] : ''),
+ 'logname' => ((array_key_exists('logname',$arr)) ? $arr['logname'] : ''),
+ 'pass' => ((array_key_exists('pass',$arr)) ? $arr['pass'] : ''),
+ 'ctag' => ((array_key_exists('ctag',$arr)) ? $arr['ctag'] : ''),
+ 'synctoken' => ((array_key_exists('synctoken',$arr)) ? $arr['synctoken'] : ''),
+ 'cal_types' => ((array_key_exists('cal_types',$arr)) ? $arr['cal_types'] : ''),
+ ];
+
+ return create_table_from_array('cal', $store);
+
+}
+
+
diff --git a/include/features.php b/include/features.php
index 993266977..c865f6754 100644
--- a/include/features.php
+++ b/include/features.php
@@ -28,8 +28,9 @@ function get_feature_default($feature) {
$f = get_features(false);
foreach($f as $cat) {
foreach($cat as $feat) {
- if(is_array($feat) && $feat[0] === $feature)
+ if(is_array($feat) && $feat[0] === $feature) {
return $feat[3];
+ }
}
}
return false;
@@ -43,8 +44,9 @@ function feature_level($feature,$def) {
return $def;
}
-function get_features($filtered = true) {
+function get_features($filtered = true, $level = (-1)) {
+ $account = \App::get_account();
$arr = [
@@ -53,7 +55,14 @@ function get_features($filtered = true) {
t('General Features'),
-
+ [
+ 'start_menu',
+ t('New Member Links'),
+ t('Display new member quick links menu'),
+ (($account['account_created'] > datetime_convert('','','now - 60 days')) ? true : false),
+ get_config('feature_lock','start_menu'),
+ feature_level('start_menu',1),
+ ],
[
'advanced_profiles',
@@ -237,14 +246,23 @@ function get_features($filtered = true) {
[
'oauth_clients',
- t('OAuth Clients'),
- t('Manage authenticatication tokens for mobile and remote apps.'),
+ t('OAuth1 Clients'),
+ t('Manage OAuth1 authenticatication tokens for mobile and remote apps.'),
false,
get_config('feature_lock','oauth_clients'),
feature_level('oauth_clients',1),
],
[
+ 'oauth2_clients',
+ t('OAuth2 Clients'),
+ t('Manage OAuth2 authenticatication tokens for mobile and remote apps.'),
+ false,
+ get_config('feature_lock','oauth2_clients'),
+ feature_level('oauth2_clients',1),
+ ],
+
+ [
'access_tokens',
t('Access Tokens'),
t('Create access tokens so that non-members can access private content.'),
@@ -332,6 +350,15 @@ function get_features($filtered = true) {
feature_level('suppress_duplicates',1),
],
+ [
+ 'auto_save_draft',
+ t('Auto-save drafts of posts and comments'),
+ t('Automatically saves post and comment drafts in local browser storage to help prevent accidental loss of compositions'),
+ true,
+ get_config('feature_lock','auto_save_draft'),
+ feature_level('auto_save_draft',1),
+ ],
+
],
// Network Tools
@@ -481,7 +508,7 @@ function get_features($filtered = true) {
$arr = $x['features'];
- $techlevel = get_account_techlevel();
+ $techlevel = (($level >= 0) ? $level : get_account_techlevel());
// removed any locked features and remove the entire category if this makes it empty
diff --git a/include/feedutils.php b/include/feedutils.php
index 369193fce..023caaad6 100644
--- a/include/feedutils.php
+++ b/include/feedutils.php
@@ -668,6 +668,14 @@ function get_atom_elements($feed, $item) {
}
$termterm = notags(trim(unxmlify($term)));
+ // Mastodon auto generates an nsfw category tag for any 'content-warning' message.
+ // Most people use CW and use both summary/content as a spoiler and we honour that
+ // construct so the post will already be collapsed. The generated tag is almost
+ // always wrong and even if it isn't we would already be doing the right thing.
+
+ if($mastodon && $termterm === 'nsfw' && $summary && $res['body'])
+ continue;
+
if($termterm) {
$terms[] = array(
'otype' => TERM_OBJ_POST,
@@ -926,6 +934,7 @@ function feed_get_reshare(&$res,$item) {
"' profile='" . $share['profile'] .
"' avatar='" . $share['avatar'] .
"' link='" . $share['alternate'] .
+ "' auth='" . 'false' .
"' posted='" . $share['created'] .
"' message_id='" . $share['message_id'] . "']";
diff --git a/include/follow.php b/include/follow.php
index 0843802c5..d803afa3f 100644
--- a/include/follow.php
+++ b/include/follow.php
@@ -88,9 +88,18 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
// Premium channel, set confirm before callback to avoid recursion
- if(array_key_exists('connect_url',$j) && ($interactive) && (! $confirm))
- goaway(zid($j['connect_url']));
-
+ if(array_key_exists('connect_url',$j) && (! $confirm)) {
+ if($interactive) {
+ goaway(zid($j['connect_url']));
+ }
+ else {
+ $result['message'] = t('Premium channel - please visit:') . ' ' . zid($j['connect_url']);
+ logger('mod_follow: ' . $result['message']);
+ return $result;
+ }
+ }
+
+
// do we have an xchan and hubloc?
// If not, create them.
@@ -141,9 +150,9 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
// attempt network auto-discovery
- $d = discover_by_webbie($url,$protocol);
+ $wf = discover_by_webbie($url,$protocol);
- if((! $d) && ($is_http)) {
+ if((! $wf) && ($is_http)) {
// try RSS discovery
@@ -158,9 +167,9 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
}
}
- if($d) {
+ if($wf || $d) {
$r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s' limit 1",
- dbesc($url),
+ dbesc(($wf) ? $wf : $url),
dbesc($url)
);
}
diff --git a/include/help.php b/include/help.php
index 0dc37e517..ce389b4db 100644
--- a/include/help.php
+++ b/include/help.php
@@ -306,7 +306,7 @@ function store_doc_file($s) {
require_once('include/html2plain.php');
- $item['body'] = html2plain(prepare_text(file_get_contents($s),$mimetype, true));
+ $item['body'] = html2plain(prepare_text(file_get_contents($s),$mimetype, [ 'cache' => true ]));
$item['mimetype'] = 'text/plain';
$item['plink'] = z_root() . '/' . str_replace('doc','help',$s);
diff --git a/include/html2bbcode.php b/include/html2bbcode.php
index 4166299db..1a03fbdaf 100644
--- a/include/html2bbcode.php
+++ b/include/html2bbcode.php
@@ -164,6 +164,7 @@ function html2bbcode($message)
node2bbcode($doc, 'b', array(), '[b]', '[/b]');
node2bbcode($doc, 'i', array(), '[i]', '[/i]');
node2bbcode($doc, 'u', array(), '[u]', '[/u]');
+ node2bbcode($doc, 's', array(), '[s]', '[/s]');
node2bbcode($doc, 'big', array(), "[size=large]", "[/size]");
node2bbcode($doc, 'small', array(), "[size=small]", "[/size]");
diff --git a/include/hubloc.php b/include/hubloc.php
index 0d1a2e560..33d5dcbb2 100644
--- a/include/hubloc.php
+++ b/include/hubloc.php
@@ -270,7 +270,8 @@ function locations_by_netid($netid) {
dbesc($netid)
);
- return array_elm_to_str($locs,'location',', ');
+
+ return array_elm_to_str($locs,'location',', ','trim_and_unpunify');
}
diff --git a/include/import.php b/include/import.php
index 47808544b..fb7826101 100644
--- a/include/import.php
+++ b/include/import.php
@@ -21,6 +21,11 @@ function import_channel($channel, $account_id, $seize) {
$channel['channel_removed'] = (($channel['channel_pageflags'] & 0x8000) ? 1 : 0);
}
+ if(intval($channel['channel_removed'])) {
+ notice( t('Unable to import a removed channel.') . EOL);
+ return false;
+ }
+
// Ignore the hash provided and re-calculate
$channel['channel_hash'] = make_xchan_hash($channel['channel_guid'],$channel['channel_guid_sig']);
@@ -94,7 +99,7 @@ function import_channel($channel, $account_id, $seize) {
}
if($clean) {
- create_table_from_array('channel',$clean);
+ channel_store_lowlevel($clean);
}
$r = q("select * from channel where channel_account_id = %d and channel_guid = '%s' limit 1",
@@ -176,7 +181,7 @@ function import_profiles($channel, $profiles) {
$profile['thumb'] = z_root() . '/photo/' . basename($profile['thumb']);
}
- create_table_from_array('profile', $profile);
+ profile_store_lowlevel($profile);
}
}
}
diff --git a/include/items.php b/include/items.php
index 7faa1b9ec..8bc4595b6 100755
--- a/include/items.php
+++ b/include/items.php
@@ -1977,23 +1977,7 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
*/
call_hooks('post_remote_end', $arr);
- // update the commented timestamp on the parent - unless this is potentially a clone of an older item
- // which we don't wish to bring to the surface. As the queue only holds deliveries for 3 days, it's
- // suspected of being an older cloned item if the creation time is older than that.
-
- 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)
- );
- }
-
+ item_update_parent_commented($arr);
// If _creating_ a deleted item, don't propagate it further or send out notifications.
// We need to store the item details just in case the delete came in before the original post,
@@ -2324,6 +2308,36 @@ function item_store_update($arr, $allow_exec = false, $deliver = true) {
return $ret;
}
+function item_update_parent_commented($item) {
+
+
+ $update_parent = true;
+
+ // update the commented timestamp on the parent
+ // - unless this is a moderated comment or a potential 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.
+
+ if(intval($item['item_blocked']) === ITEM_MODERATED)
+ $update_parent = false;
+
+ if($item['created'] < datetime_convert('','','now - 4 days'))
+ $update_parent = false;
+
+ if($update_parent) {
+ $z = q("select max(created) as commented from item where parent_mid = '%s' and uid = %d and item_delayed = 0 ",
+ dbesc($item['parent_mid']),
+ intval($item['uid'])
+ );
+
+ q("UPDATE item set commented = '%s', changed = '%s' WHERE id = %d",
+ dbesc(($z) ? $z[0]['commented'] : datetime_convert()),
+ dbesc(datetime_convert()),
+ intval($item['parent'])
+ );
+ }
+}
function send_status_notifications($post_id,$item) {
@@ -2518,43 +2532,7 @@ function tag_deliver($uid, $item_id) {
*/
if($item['obj_type'] === ACTIVITY_OBJ_TAGTERM) {
-
- // We received a community tag activity for a post.
- // See if we are the owner of the parent item and have given permission to tag our posts.
- // If so tag the parent post.
-
- logger('tag_deliver: community tag activity received');
-
- if(($item['owner_xchan'] === $u[0]['channel_hash']) && (! get_pconfig($u[0]['channel_id'],'system','blocktags'))) {
- logger('tag_deliver: community tag recipient: ' . $u[0]['channel_name']);
- $j_tgt = json_decode($item['target'],true);
- if($j_tgt && $j_tgt['id']) {
- $p = q("select * from item where mid = '%s' and uid = %d limit 1",
- dbesc($j_tgt['id']),
- intval($u[0]['channel_id'])
- );
- if($p) {
- $j_obj = json_decode($item['obj'],true);
- logger('tag_deliver: tag object: ' . print_r($j_obj,true), LOGGER_DATA);
- if($j_obj && $j_obj['id'] && $j_obj['title']) {
- if(is_array($j_obj['link']))
- $taglink = get_rel_link($j_obj['link'],'alternate');
-
- store_item_tag($u[0]['channel_id'],$p[0]['id'],TERM_OBJ_POST,TERM_COMMUNITYTAG,$j_obj['title'],$j_obj['id']);
- $x = q("update item set edited = '%s', received = '%s', changed = '%s' where mid = '%s' and uid = %d",
- dbesc(datetime_convert()),
- dbesc(datetime_convert()),
- dbesc(datetime_convert()),
- dbesc($j_tgt['id']),
- intval($u[0]['channel_id'])
- );
- Zotlabs\Daemon\Master::Summon(array('Notifier','edit_post',$p[0]['id']));
- }
- }
- }
- }
- else
- logger('Tag permission denied for ' . $u[0]['channel_address']);
+ item_community_tag($u[0],$item);
}
/*
@@ -2749,6 +2727,61 @@ function tag_deliver($uid, $item_id) {
}
+
+function item_community_tag($channel,$item) {
+
+
+ // We received a community tag activity for a post.
+ // See if we are the owner of the parent item and have given permission to tag our posts.
+ // If so tag the parent post.
+
+ logger('tag_deliver: community tag activity received: channel: ' . $channel['channel_name']);
+
+ $tag_the_post = false;
+ $p = null;
+
+ $j_obj = json_decode($item['obj'],true);
+ $j_tgt = json_decode($item['target'],true);
+ if($j_tgt && $j_tgt['id']) {
+ $p = q("select * from item where mid = '%s' and uid = %d limit 1",
+ dbesc($j_tgt['id']),
+ intval($channel['channel_id'])
+ );
+ }
+ if($p) {
+ xchan_query($p);
+ $items = fetch_post_tags($p,true);
+ $pitem = $items[0];
+ $auth = get_iconfig($item,'system','communitytagauth');
+ if($auth) {
+ if(rsa_verify('tagauth.' . $item['mid'],base64url_decode($auth),$pitem['owner']['xchan_pubkey']) || rsa_verify('tagauth.' . $item['mid'],base64url_decode($auth),$pitem['author']['xchan_pubkey'])) {
+ logger('tag_deliver: tagging the post: ' . $channel['channel_name']);
+ $tag_the_post = true;
+ }
+ }
+ else {
+ if(($pitem['owner_xchan'] === $channel['channel_hash']) && (! intval(get_pconfig($channel['channel_id'],'system','blocktags')))) {
+ logger('tag_deliver: community tag recipient: ' . $channel['channel_name']);
+ $tag_the_post = true;
+ $sig = rsa_sign('tagauth.' . $item['mid'],$channel['channel_prvkey']);
+ logger('tag_deliver: setting iconfig for ' . $item['id']);
+ set_iconfig($item['id'],'system','communitytagauth',base64url_encode($sig),1);
+ }
+ }
+
+ if($tag_the_post) {
+ store_item_tag($channel['channel_id'],$pitem['id'],TERM_OBJ_POST,TERM_COMMUNITYTAG,$j_obj['title'],$j_obj['id']);
+ }
+ else {
+ logger('Tag permission denied for ' . $channel['channel_address']);
+ }
+ }
+
+}
+
+
+
+
/**
* @brief This function is called pre-deliver to see if a post matches the criteria to be tag delivered.
*
@@ -3471,11 +3504,14 @@ function item_getfeedattach($item) {
}
-function item_expire($uid,$days) {
+function item_expire($uid,$days,$comment_days = 7) {
if((! $uid) || ($days < 1))
return;
+ if(! $comment_days)
+ $comment_days = 7;
+
// $expire_network_only = save your own wall posts
// and just expire conversations started by others
// do not enable this until we can pass bulk delete messages through zot
@@ -3494,6 +3530,7 @@ function item_expire($uid,$days) {
$r = q("SELECT id FROM item
WHERE uid = %d
AND created < %s - INTERVAL %s
+ AND commented < %s - INTERVAL %s
AND item_retained = 0
AND item_thread_top = 1
AND resource_type = ''
@@ -3501,7 +3538,9 @@ function item_expire($uid,$days) {
$sql_extra $item_normal LIMIT $expire_limit ",
intval($uid),
db_utcnow(),
- db_quoteinterval(intval($days).' DAY')
+ db_quoteinterval(intval($days) . ' DAY'),
+ db_utcnow(),
+ db_quoteinterval(intval($comment_days) . ' DAY')
);
if(! $r)
diff --git a/include/nav.php b/include/nav.php
index df58ee96f..a443c58ff 100644
--- a/include/nav.php
+++ b/include/nav.php
@@ -176,7 +176,7 @@ EOT;
$nav['help'] = [$help_url, t('Help'), "", t('Help and documentation'), 'help_nav_btn', $context_help, $enable_context_help];
}
- $nav['search'] = ['search', t('Search'), "", t('Search site @name, #tag, ?docs, content')];
+ $nav['search'] = ['search', t('Search'), "", t('Search site @name, !forum, #tag, ?docs, content')];
/**
@@ -287,7 +287,7 @@ EOT;
'$is_owner' => $is_owner,
'$sel' => App::$nav_sel,
'$powered_by' => $powered_by,
- '$help' => t('@name, #tag, ?doc, content'),
+ '$help' => t('@name, !forum, #tag, ?doc, content'),
'$pleasewait' => t('Please wait...'),
'$nav_apps' => $nav_apps,
'$navbar_apps' => $navbar_apps,
diff --git a/include/network.php b/include/network.php
index a49e5920d..8b7490a8a 100644
--- a/include/network.php
+++ b/include/network.php
@@ -368,27 +368,6 @@ function z_post_url($url, $params, $redirects = 0, $opts = array()) {
return($ret);
}
-/**
- * @brief Like z_post_url() but with an application/json HTTP header.
- *
- * Add a "Content-Type: application/json" HTTP-header to $opts and call z_post_url().
- *
- * @see z_post_url()
- *
- * @param string $url
- * @param array $params
- * @param number $redirects default 0
- * @param array $opts (optional) curl options
- * @return z_post_url()
- */
-function z_post_url_json($url, $params, $redirects = 0, $opts = array()) {
-
- $opts = array_merge($opts, array('headers' => array('Content-Type: application/json')));
-
- return z_post_url($url,json_encode($params),$redirects,$opts);
-}
-
-
function json_return_and_die($x, $content_type = 'application/json') {
header("Content-type: $content_type");
echo json_encode($x);
@@ -669,6 +648,7 @@ function parse_xml_string($s, $strict = true) {
libxml_use_internal_errors(true);
+
$x = @simplexml_load_string($s2);
if($x === false) {
logger('libxml: parse: error: ' . $s2, LOGGER_DATA);
@@ -682,6 +662,16 @@ function parse_xml_string($s, $strict = true) {
return $x;
}
+
+function sxml2array ( $xmlObject, $out = array () )
+{
+ foreach ( (array) $xmlObject as $index => $node )
+ $out[$index] = ( is_object ( $node ) ) ? sxml2array ( $node ) : $node;
+
+ return $out;
+}
+
+
/**
* @brief Scales an external image.
*
@@ -779,7 +769,7 @@ function scale_external_images($s, $include_link = true, $scale_replace = false)
* @brief xml2array() will convert the given XML text to an array in the XML structure.
*
* Link: http://www.bin-co.com/php/scripts/xml2array/
- * Portions significantly re-written by mike@macgirvin.com for Friendica
+ * Portions significantly re-written by mike@macgirvin.com
* (namespaces, lowercase tags, get_attribute default changed, more...)
*
* Examples: $array = xml2array(file_get_contents('feed.xml'));
@@ -1160,8 +1150,6 @@ function discover_by_webbie($webbie, $protocol = '') {
$network = null;
-// $webbie = strtolower($webbie);
-
$x = webfinger_rfc7033($webbie, true);
if($x && array_key_exists('links',$x) && $x['links']) {
foreach($x['links'] as $link) {
@@ -1192,9 +1180,10 @@ function discover_by_webbie($webbie, $protocol = '') {
logger('webfinger: ' . print_r($x,true), LOGGER_DATA, LOG_INFO);
$arr = [
- 'address' => $webbie,
- 'protocol' => $protocol,
- 'success' => false,
+ 'address' => $webbie,
+ 'protocol' => $protocol,
+ 'success' => false,
+ 'xchan' => '',
'webfinger' => $x
];
/**
@@ -1207,7 +1196,7 @@ function discover_by_webbie($webbie, $protocol = '') {
*/
call_hooks('discover_channel_webfinger', $arr);
if($arr['success'])
- return true;
+ return $arr['xchan'];
return false;
}
@@ -1240,16 +1229,9 @@ function webfinger_rfc7033($webbie, $zot = false) {
}
logger('fetching url from resource: ' . $rhs . ':' . $webbie);
- // The default curl Accept: header is */*, which is incorrectly handled by Mastodon servers
- // and results in a 406 (Not Acceptable) response, and will also incorrectly produce an XML
- // document if you use 'application/jrd+json, */*'. We could set this to application/jrd+json,
- // but some test webfinger servers may not explicitly set the content type and they would be
- // blocked. The best compromise until Mastodon is fixed is to remove the Accept header which is
- // accomplished by setting it to nothing.
-
$counter = 0;
$s = z_fetch_url('https://' . $rhs . '/.well-known/webfinger?f=&resource=' . $resource . (($zot) ? '&zot=1' : ''),
- false, $counter, [ 'headers' => [ 'Accept:' ] ]);
+ false, $counter, [ 'headers' => [ 'Accept: application/jrd+json, */*' ] ]);
if($s['success']) {
$j = json_decode($s['body'], true);
@@ -1607,6 +1589,7 @@ function get_site_info() {
'register_policy' => $register_policy[get_config('system','register_policy')],
'invitation_only' => (bool) intval(get_config('system','invitation_only')),
'directory_mode' => $directory_mode[get_config('system','directory_mode')],
+ 'directory_server' => get_config('system','directory_server'),
'language' => get_config('system','language'),
'rss_connections' => (bool) intval(get_config('system','feed_contacts')),
'expiration' => $site_expire,
@@ -1844,7 +1827,8 @@ function z_mail($params) {
$messageHeader =
$params['additionalMailHeader'] .
"From: $fromName <{$params['fromEmail']}>\n" .
- "Reply-To: $fromName <{$params['replyTo']}>";
+ "Reply-To: $fromName <{$params['replyTo']}>\n" .
+ "Content-Type: text/plain; charset=UTF-8";
// send the message
$res = mail(
diff --git a/include/oembed.php b/include/oembed.php
index c2bf0a0ed..e677087a2 100755
--- a/include/oembed.php
+++ b/include/oembed.php
@@ -32,6 +32,7 @@ function oembed_action($embedurl) {
$action = 'block';
}
}
+
if(strpos($embedurl,'.well-known') !== false)
$action = 'block';
@@ -233,9 +234,11 @@ function oembed_fetch_url($embedurl){
if(preg_match('#\<iframe(.*?)src\=[\'\"](.*?)[\'\"]#',$j['html'],$matches)) {
$x = z_fetch_url($matches[2]);
- $j['html'] = $x['body'];
+ $orig = $j['html'] = $x['body'];
}
-
+
+ logger('frame src: ' . $j['html'], LOGGER_DATA);
+
$j['html'] = purify_html($j['html'],$allow_position);
if($j['html'] != $orig) {
logger('oembed html was purified. original: ' . $orig . ' purified: ' . $j['html'], LOGGER_DEBUG, LOG_INFO);
diff --git a/include/permissions.php b/include/permissions.php
index f97142fab..185d37b6a 100644
--- a/include/permissions.php
+++ b/include/permissions.php
@@ -46,7 +46,7 @@ function get_all_perms($uid, $observer_xchan, $internal_use = true) {
// First find out what the channel owner declared permissions to be.
- $channel_perm = \Zotlabs\Access\PermissionLimits::Get($uid,$perm_name);
+ $channel_perm = intval(\Zotlabs\Access\PermissionLimits::Get($uid,$perm_name));
if(! $channel_checked) {
$r = q("select * from channel where channel_id = %d limit 1",
diff --git a/include/photo/photo_driver.php b/include/photo/photo_driver.php
index 6af753195..2e2f5a758 100644
--- a/include/photo/photo_driver.php
+++ b/include/photo/photo_driver.php
@@ -75,6 +75,7 @@ abstract class photo_driver {
abstract function imageString();
+ abstract function clearexif();
public function __construct($data, $type='') {
$this->types = $this->supportedTypes();
@@ -273,7 +274,7 @@ abstract class photo_driver {
}
if($f) {
- return @exif_read_data($f);
+ return @exif_read_data($f,null,true);
}
return false;
@@ -289,12 +290,12 @@ abstract class photo_driver {
return false;
}
- $ort = $exif['IFD0']['Orientation'];
+ $ort = ((array_key_exists('IFD0',$exif)) ? $exif['IFD0']['Orientation'] : $exif['Orientation']);
if(! $ort) {
return false;
}
-
+
switch($ort) {
case 1: // nothing
break;
diff --git a/include/photo/photo_gd.php b/include/photo/photo_gd.php
index 24bdc204f..e98ac2827 100644
--- a/include/photo/photo_gd.php
+++ b/include/photo/photo_gd.php
@@ -35,6 +35,11 @@ class photo_gd extends photo_driver {
}
+ public function clearexif() {
+ return;
+ }
+
+
public function destroy() {
if($this->is_valid()) {
imagedestroy($this->image);
diff --git a/include/photo/photo_imagick.php b/include/photo/photo_imagick.php
index 32bb61342..89577e71e 100644
--- a/include/photo/photo_imagick.php
+++ b/include/photo/photo_imagick.php
@@ -96,6 +96,19 @@ class photo_imagick extends photo_driver {
}
+ public function clearexif() {
+
+ $profiles = $this->image->getImageProfiles("icc", true);
+
+ $this->image->stripImage();
+
+ if(!empty($profiles)) {
+ $this->image->profileImage("icc", $profiles['icc']);
+ }
+ }
+
+
+
public function getImage() {
if(!$this->is_valid())
return FALSE;
diff --git a/include/photos.php b/include/photos.php
index b1391f284..9ae0e6874 100644
--- a/include/photos.php
+++ b/include/photos.php
@@ -211,6 +211,10 @@ function photo_upload($channel, $observer, $args) {
$ph->orient($exif);
}
+
+ $ph->clearexif();
+
+
@unlink($src);
$max_length = get_config('system','max_image_length');
@@ -333,10 +337,17 @@ function photo_upload($channel, $observer, $args) {
$lat = $lon = null;
- if($exif && $exif['GPS']) {
- if(feature_enabled($channel_id,'photo_location')) {
- $lat = getGps($exif['GPS']['GPSLatitude'], $exif['GPS']['GPSLatitudeRef']);
- $lon = getGps($exif['GPS']['GPSLongitude'], $exif['GPS']['GPSLongitudeRef']);
+ if($exif && feature_enabled($channel_id,'photo_location')) {
+ $gps = null;
+ if(array_key_exists('GPS',$exif)) {
+ $gps = $exif['GPS'];
+ }
+ elseif(array_key_exists('GPSLatitude',$exif)) {
+ $gps = $exif;
+ }
+ if($gps) {
+ $lat = getGps($gps['GPSLatitude'], $gps['GPSLatitudeRef']);
+ $lon = getGps($gps['GPSLongitude'], $gps['GPSLongitudeRef']);
}
}
diff --git a/include/plugin.php b/include/plugin.php
index 62d443ab8..4545e1e8d 100755
--- a/include/plugin.php
+++ b/include/plugin.php
@@ -7,6 +7,27 @@
/**
+ * @brief Handle errors in plugin calls
+ *
+ * @param string $plugin name of the addon
+ * @param string $error_text text of error
+ * @param bool $uninstall uninstall plugin
+ */
+function handleerrors_plugin($plugin,$notice,$log,$uninstall=false){
+ logger("Addons: [" . $plugin . "] Error: ".$log, LOGGER_ERROR);
+ if ($notice != '') {
+ notice("[" . $plugin . "] Error: ".$notice, LOGGER_ERROR);
+ }
+
+ if ($uninstall) {
+ $idx = array_search($plugin, \App::$plugins);
+ unset(\App::$plugins[$idx]);
+ uninstall_plugin($plugin);
+ set_config("system","addon", implode(", ",\App::$plugins));
+ }
+}
+
+/**
* @brief Unloads an addon.
*
* @param string $plugin name of the addon
@@ -17,7 +38,11 @@ function unload_plugin($plugin){
@include_once('addon/' . $plugin . '/' . $plugin . '.php');
if(function_exists($plugin . '_unload')) {
$func = $plugin . '_unload';
- $func();
+ try {
+ $func();
+ } catch (Exception $e) {
+ handleerrors_plugin($plugin,"Unable to unload.",$e->getMessage());
+ }
}
}
@@ -38,7 +63,11 @@ function uninstall_plugin($plugin) {
@include_once('addon/' . $plugin . '/' . $plugin . '.php');
if(function_exists($plugin . '_uninstall')) {
$func = $plugin . '_uninstall';
- $func();
+ try {
+ $func();
+ } catch (Exception $e) {
+ handleerrors_plugin($plugin,"Unable to uninstall.","Unable to run _uninstall : ".$e->getMessage());
+ }
}
q("DELETE FROM addon WHERE aname = '%s' ",
@@ -64,7 +93,12 @@ function install_plugin($plugin) {
@include_once('addon/' . $plugin . '/' . $plugin . '.php');
if(function_exists($plugin . '_install')) {
$func = $plugin . '_install';
- $func();
+ try {
+ $func();
+ } catch (Exception $e) {
+ handleerrors_plugin($plugin,"Install failed.","Install failed : ".$e->getMessage());
+ return;
+ }
}
$plugin_admin = (function_exists($plugin . '_plugin_admin') ? 1 : 0);
@@ -94,7 +128,12 @@ function load_plugin($plugin) {
@include_once('addon/' . $plugin . '/' . $plugin . '.php');
if(function_exists($plugin . '_load')) {
$func = $plugin . '_load';
- $func();
+ try {
+ $func();
+ } catch (Exception $e) {
+ handleerrors_plugin($plugin,"Unable to load.","FAILED loading : ".$e->getMessage(),true);
+ return;
+ }
// we can add the following with the previous SQL
// once most site tables have been updated.
@@ -108,7 +147,7 @@ function load_plugin($plugin) {
return true;
}
else {
- logger("Addons: FAILED loading " . $plugin);
+ logger("Addons: FAILED loading " . $plugin . " (missing _load function)");
return false;
}
}
@@ -160,11 +199,21 @@ function reload_plugins() {
if(function_exists($pl . '_unload')) {
$func = $pl . '_unload';
- $func();
+ try {
+ $func();
+ } catch (Exception $e) {
+ handleerrors_plugin($plugin,"","UNLOAD FAILED (uninstalling) : ".$e->getMessage(),true);
+ continue;
+ }
}
if(function_exists($pl . '_load')) {
$func = $pl . '_load';
- $func();
+ try {
+ $func();
+ } catch (Exception $e) {
+ handleerrors_plugin($plugin,"","LOAD FAILED (uninstalling): ".$e->getMessage(),true);
+ continue;
+ }
}
q("UPDATE addon SET tstamp = %d WHERE id = %d",
intval($t),
diff --git a/include/queue_fn.php b/include/queue_fn.php
index 798ac36db..f05bac5b0 100644
--- a/include/queue_fn.php
+++ b/include/queue_fn.php
@@ -95,6 +95,12 @@ function queue_set_delivered($id,$channel = 0) {
function queue_insert($arr) {
+ // do not queue anything with no destination
+
+ if(! (array_key_exists('posturl',$arr) && trim($arr['posturl']))) {
+ return false;
+ }
+
$x = q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_priority,
outq_created, outq_updated, outq_scheduled, outq_notify, outq_msg )
values ( '%s', %d, %d, '%s', '%s', %d, %d, '%s', '%s', '%s', '%s', '%s' )",
diff --git a/include/security.php b/include/security.php
index 8b7e7d076..19278d5cb 100644
--- a/include/security.php
+++ b/include/security.php
@@ -266,6 +266,15 @@ function change_channel($change_channel) {
$_SESSION['mobile_theme'] = get_pconfig(local_channel(),'system', 'mobile_theme');
$_SESSION['cloud_tiles'] = get_pconfig(local_channel(),'system', 'cloud_tiles');
date_default_timezone_set($r[0]['channel_timezone']);
+
+ // Update the active timestamp at most once a day
+
+ if(substr($r[0]['channel_active'],0,10) !== substr(datetime_convert(),0,10)) {
+ $z = q("UPDATE channel SET channel_active = '%s' WHERE channel_id = %d",
+ dbesc(datetime_convert()),
+ intval($r[0]['channel_id'])
+ );
+ }
$ret = $r[0];
}
$x = q("select * from xchan where xchan_hash = '%s' limit 1",
diff --git a/include/statistics_fns.php b/include/statistics_fns.php
index d213485bf..98b0efd41 100644
--- a/include/statistics_fns.php
+++ b/include/statistics_fns.php
@@ -17,23 +17,10 @@ function update_channels_active_halfyear_stat() {
db_utcnow(), db_quoteinterval('6 MONTH')
);
if($r) {
- $s = '';
- foreach($r as $rr) {
- if($s)
- $s .= ',';
- $s .= intval($rr['channel_id']);
- }
- $x = q("select uid from item where uid in ( $s ) and item_wall = 1 and created > %s - INTERVAL %s group by uid",
- db_utcnow(), db_quoteinterval('6 MONTH')
- );
- if($x) {
- $channels_active_halfyear_stat = count($x);
- set_config('system','channels_active_halfyear_stat',$channels_active_halfyear_stat);
- } else {
- set_config('system','channels_active_halfyear_stat',0);
- }
- } else {
- set_config('system','channels_active_halfyear_stat',0);
+ set_config('system','channels_active_halfyear_stat',count($r));
+ }
+ else {
+ set_config('system','channels_active_halfyear_stat','0');
}
}
@@ -43,28 +30,15 @@ function update_channels_active_monthly_stat() {
db_utcnow(), db_quoteinterval('1 MONTH')
);
if($r) {
- $s = '';
- foreach($r as $rr) {
- if($s)
- $s .= ',';
- $s .= intval($rr['channel_id']);
- }
- $x = q("select uid from item where uid in ( $s ) and item_wall = 1 and created > %s - INTERVAL %s group by uid",
- db_utcnow(), db_quoteinterval('1 MONTH')
- );
- if($x) {
- $channels_active_monthly_stat = count($x);
- set_config('system','channels_active_monthly_stat',$channels_active_monthly_stat);
- } else {
- set_config('system','channels_active_monthly_stat',0);
- }
- } else {
- set_config('system','channels_active_monthly_stat',0);
+ set_config('system','channels_active_monthly_stat',count($r));
+ }
+ else {
+ set_config('system','channels_active_monthly_stat','0');
}
}
function update_local_posts_stat() {
- $posts = q("SELECT COUNT(*) AS local_posts FROM item WHERE item_wall = 1 ");
+ $posts = q("SELECT COUNT(*) AS local_posts FROM item WHERE item_wall = 1 and id = parent");
if (is_array($posts)) {
$local_posts_stat = intval($posts[0]["local_posts"]);
set_config('system','local_posts_stat',$local_posts_stat);
diff --git a/include/taxonomy.php b/include/taxonomy.php
index 4a3818096..46d95458c 100644
--- a/include/taxonomy.php
+++ b/include/taxonomy.php
@@ -174,8 +174,7 @@ function tagadelic($uid, $count = 0, $authors = '', $owner = '', $flags = 0, $re
if(! is_array($authors))
$authors = array($authors);
- stringify_array_elms($authors,true);
- $sql_options .= " and author_xchan in (" . implode(',',$authors) . ") ";
+ $sql_options .= " and author_xchan in (" . stringify_array($authors,true) . ") ";
}
if($owner) {
@@ -212,8 +211,9 @@ function card_tagadelic($uid, $count = 0, $authors = '', $owner = '', $flags = 0
if(! perm_is_allowed($uid,get_observer_hash(),'view_pages'))
return array();
+ $item_normal = " and item.item_hidden = 0 and item.item_deleted = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
+ and item.item_blocked = 0 and item.obj_type != 'http://purl.org/zot/activity/file' ";
- $item_normal = item_normal();
$sql_options = item_permissions_sql($uid);
$count = intval($count);
@@ -226,8 +226,7 @@ function card_tagadelic($uid, $count = 0, $authors = '', $owner = '', $flags = 0
if(! is_array($authors))
$authors = array($authors);
- stringify_array_elms($authors,true);
- $sql_options .= " and author_xchan in (" . implode(',',$authors) . ") ";
+ $sql_options .= " and author_xchan in (" . stringify_array($authors,true) . ") ";
}
if($owner) {
@@ -236,15 +235,16 @@ function card_tagadelic($uid, $count = 0, $authors = '', $owner = '', $flags = 0
// Fetch tags
+
$r = q("select term, count(term) as total from term left join item on term.oid = item.id
where term.uid = %d and term.ttype = %d
- and otype = %d and item_type = %d and item_private = 0
+ and otype = %d and item_type = %d
$sql_options $item_normal
group by term order by total desc %s",
intval($uid),
intval($type),
intval(TERM_OBJ_POST),
- intval($restrict),
+ intval(ITEM_TYPE_CARD),
((intval($count)) ? "limit $count" : '')
);
@@ -263,7 +263,9 @@ function article_tagadelic($uid, $count = 0, $authors = '', $owner = '', $flags
return array();
- $item_normal = item_normal();
+ $item_normal = " and item.item_hidden = 0 and item.item_deleted = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
+ and item.item_blocked = 0 and item.obj_type != 'http://purl.org/zot/activity/file' ";
+
$sql_options = item_permissions_sql($uid);
$count = intval($count);
@@ -276,8 +278,7 @@ function article_tagadelic($uid, $count = 0, $authors = '', $owner = '', $flags
if(! is_array($authors))
$authors = array($authors);
- stringify_array_elms($authors,true);
- $sql_options .= " and author_xchan in (" . implode(',',$authors) . ") ";
+ $sql_options .= " and author_xchan in (" . stringify_array($authors,true) . ") ";
}
if($owner) {
@@ -288,13 +289,13 @@ function article_tagadelic($uid, $count = 0, $authors = '', $owner = '', $flags
// Fetch tags
$r = q("select term, count(term) as total from term left join item on term.oid = item.id
where term.uid = %d and term.ttype = %d
- and otype = %d and item_type = %d and item_private = 0
+ and otype = %d and item_type = %d
$sql_options $item_normal
group by term order by total desc %s",
intval($uid),
intval($type),
intval(TERM_OBJ_POST),
- intval($restrict),
+ intval(ITEM_TYPE_ARTICLE),
((intval($count)) ? "limit $count" : '')
);
@@ -308,6 +309,70 @@ function article_tagadelic($uid, $count = 0, $authors = '', $owner = '', $flags
+function pubtagblock($net,$site,$limit,$recent = 0,$safemode = 1, $type = TERM_HASHTAG) {
+ $o = '';
+
+ $r = pub_tagadelic($net,$site,$limit,$recent,$safemode,$type);
+
+ $link = z_root() . '/pubstream';
+
+ if($r) {
+ $o = '<div class="tagblock widget"><h3>' . (($recent) ? t('Trending') : t('Tags')) . '</h3><div class="tags" align="center">';
+ foreach($r as $rr) {
+ $o .= '<span class="tag'.$rr[2].'">#</span><a href="'.$link .'/' . '?f=&tag=' . urlencode($rr[0]).'" class="tag'.$rr[2].'">'.$rr[0].'</a> ' . "\r\n";
+ }
+ $o .= '</div></div>';
+ }
+
+ return $o;
+}
+
+function pub_tagadelic($net,$site,$limit,$recent,$safemode,$type) {
+
+
+ $item_normal = item_normal();
+ $count = intval($limit);
+
+ if($site) {
+ $uids = " and item.uid in ( " . stream_perms_api_uids(PERMS_PUBLIC) . " ) and item_private = 0 and item_wall = 1 ";
+ }
+ else {
+ $sys = get_sys_channel();
+ $uids = " and item.uid = " . intval($sys['channel_id']) . " ";
+ $sql_extra = " and item_private = 0 ";
+ }
+
+ if($recent)
+ $sql_extra .= " and item.created > '" . datetime_convert('UTC','UTC', 'now - ' . intval($recent) . ' days ') . "' ";
+
+
+ if($safemode) {
+ $unsafetags = get_config('system','unsafepubtags', [ 'boobs', 'bot', 'rss', 'girl','girls', 'nsfw', 'sexy', 'nude' ]);
+ if($unsafetags) {
+ $sql_extra .= " and not term.term in ( " . stringify_array($unsafetags,true) . ") ";
+ }
+ }
+
+
+ // Fetch tags
+ $r = q("select term, count(term) as total from term left join item on term.oid = item.id
+ where term.ttype = %d
+ and otype = %d and item_type = %d
+ $sql_extra $uids $item_normal
+ group by term order by total desc %s",
+ intval($type),
+ intval(TERM_OBJ_POST),
+ intval(ITEM_TYPE_POST),
+ ((intval($count)) ? "limit $count" : '')
+ );
+
+ if(! $r)
+ return array();
+
+ return Zotlabs\Text\Tagadelic::calc($r);
+
+}
+
function dir_tagadelic($count = 0, $hub = '') {
@@ -553,9 +618,8 @@ function get_things($profile_hash,$uid) {
if(! in_array($rr['obj_obj'],$profile_hashes))
$profile_hashes[] = $rr['obj_obj'];
}
- stringify_array_elms($profile_hashes);
if(! $profile_hash) {
- $exp = explode(',',$profile_hashes);
+ $exp = stringify_array($profile_hashes,true);
$p = q("select profile_guid as hash, profile_name as name from profile where profile_guid in ( $exp ) ");
if($p) {
foreach($r as $rr) {
diff --git a/include/text.php b/include/text.php
index 086d507af..af88c9f9c 100644
--- a/include/text.php
+++ b/include/text.php
@@ -531,7 +531,7 @@ function paginate(&$a) {
}
-function alt_pager(&$a, $i, $more = '', $less = '') {
+function alt_pager($i, $more = '', $less = '') {
if(! $more)
$more = t('older');
@@ -1588,7 +1588,7 @@ function generate_named_map($location) {
}
-function prepare_body(&$item,$attach = false) {
+function prepare_body(&$item,$attach = false,$opts = false) {
call_hooks('prepare_body_init', $item);
@@ -1616,7 +1616,7 @@ function prepare_body(&$item,$attach = false) {
$s .= prepare_binary($item);
}
else {
- $s .= prepare_text($item['body'],$item['mimetype'], false);
+ $s .= prepare_text($item['body'],$item['mimetype'], $opts);
}
$event = (($item['obj_type'] === ACTIVITY_OBJ_EVENT) ? format_event_obj($item['obj']) : false);
@@ -1698,7 +1698,8 @@ function prepare_binary($item) {
*
* @return string
*/
-function prepare_text($text, $content_type = 'text/bbcode', $cache = false) {
+function prepare_text($text, $content_type = 'text/bbcode', $opts = false) {
+
switch($content_type) {
case 'text/plain':
@@ -1742,7 +1743,7 @@ function prepare_text($text, $content_type = 'text/bbcode', $cache = false) {
if(stristr($text,'[nosmile]'))
$s = bbcode($text, [ 'cache' => $cache ]);
else
- $s = smilies(bbcode($text, [ 'cache' => $cache ]));
+ $s = smilies(bbcode($text, ((is_array($opts)) ? $opts : [] )));
$s = zidify_links($s);
@@ -2189,13 +2190,13 @@ function ids_to_querystr($arr,$idx = 'id',$quote = false) {
* @returns string
*/
-function array_elm_to_str($arr,$elm,$delim = ',') {
+function array_elm_to_str($arr,$elm,$delim = ',',$each = 'trim') {
$tmp = [];
if($arr && is_array($arr)) {
foreach($arr as $x) {
if(is_array($x) && array_key_exists($elm,$x)) {
- $z = trim($x[$elm]);
+ $z = $each($x[$elm]);
if(($z) && (! in_array($z,$tmp))) {
$tmp[] = $z;
}
@@ -2205,7 +2206,9 @@ function array_elm_to_str($arr,$elm,$delim = ',') {
return implode($delim,$tmp);
}
-
+function trim_and_unpunify($s) {
+ return unpunify(trim($s));
+}
/**
@@ -2248,7 +2251,7 @@ function xchan_query(&$items, $abook = true, $effective_uid = 0) {
$chans = q("select xchan.*,hubloc.* from xchan left join hubloc on hubloc_hash = xchan_hash
where xchan_hash in (" . protect_sprintf(implode(',', $arr)) . ") and hubloc_primary = 1");
}
- $xchans = q("select * from xchan where xchan_hash in (" . protect_sprintf(implode(',',$arr)) . ") and xchan_network in ('rss','unknown')");
+ $xchans = q("select * from xchan where xchan_hash in (" . protect_sprintf(implode(',',$arr)) . ") and xchan_network in ('rss','unknown', 'anon')");
if(! $chans)
$chans = $xchans;
else
@@ -2321,6 +2324,23 @@ function stringify_array_elms(&$arr, $escape = false) {
$arr[$x] = "'" . (($escape) ? dbesc($arr[$x]) : $arr[$x]) . "'";
}
+
+/**
+ * @brief Similar to stringify_array_elms but returns a string. If $escape is true, dbesc() each element before adding quotes.
+ *
+ * @param array $arr
+ * @param boolean $escape (optional) default false
+ * @return string
+ */
+function stringify_array($arr, $escape = false) {
+ if($arr) {
+ stringify_array_elms($arr);
+ return(implode(',',$arr));
+ }
+ return EMPTY_STR;
+}
+
+
/**
* @brief Indents a flat JSON string to make it more human-readable.
*
@@ -2384,7 +2404,7 @@ function jindent($json) {
*/
function design_tools() {
- $channel = App::get_channel();
+ $channel = channelx_by_n(App::$profile['profile_uid']);
$sys = false;
if(App::$is_sys && is_site_admin()) {
@@ -2574,6 +2594,9 @@ function handle_tag($a, &$body, &$access_tag, &$str_tags, $profile_uid, $tag, $d
// The @! tag will alter permissions
$exclusive = (((! $grouptag) && (strpos($tag,'!') === 1) && (! $diaspora)) ? true : false);
+ if(($grouptag) && (strpos($tag,'!!') === 0)) {
+ $exclusive = true;
+ }
//is it already replaced?
if(strpos($tag,'[zrl='))
@@ -2746,8 +2769,8 @@ function handle_tag($a, &$body, &$access_tag, &$str_tags, $profile_uid, $tag, $d
$profile = str_replace(',','%2c',$profile);
$url = $profile;
if($grouptag) {
- $newtag = '!' . '[zrl=' . $profile . ']' . $newname . '[/zrl]';
- $body = str_replace('!' . $name, $newtag, $body);
+ $newtag = '!' . (($exclusive) ? '!' : '') . '[zrl=' . $profile . ']' . $newname . '[/zrl]';
+ $body = str_replace('!' . (($exclusive) ? '!' : '') . $name, $newtag, $body);
}
else {
$newtag = '@' . (($exclusive) ? '!' : '') . '[zrl=' . $profile . ']' . $newname . (($forum && ! $trailing_plus_name) ? '+' : '') . '[/zrl]';
@@ -2797,6 +2820,7 @@ function linkify_tags($a, &$body, $uid, $diaspora = false) {
continue;
$success = handle_tag($a, $body, $access_tag, $str_tags, ($uid) ? $uid : App::$profile_uid , $tag, $diaspora);
+
$results[] = array('success' => $success, 'access_tag' => $access_tag);
if($success['replaced']) $tagged[] = $tag;
}
@@ -3243,6 +3267,7 @@ function cleanup_bbcode($body) {
* 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);
@@ -3272,7 +3297,6 @@ function cleanup_bbcode($body) {
$body = scale_external_images($body,false);
-
return $body;
}
@@ -3311,4 +3335,26 @@ function purify_filename($s) {
return $s;
}
+// callback for sorting the settings/featured entries.
+
+function featured_sort($a,$b) {
+ $s1 = substr($a,strpos($a,'id='),20);
+ $s2 = substr($b,strpos($b,'id='),20);
+ return(strcmp($s1,$s2));
+}
+
+
+function punify($s) {
+ require_once('vendor/simplepie/simplepie/idn/idna_convert.class.php');
+ $x = new idna_convert(['encoding' => 'utf8']);
+ return $x->encode($s);
+
+}
+
+function unpunify($s) {
+ require_once('vendor/simplepie/simplepie/idn/idna_convert.class.php');
+ $x = new idna_convert(['encoding' => 'utf8']);
+ return $x->decode($s);
+
+}
diff --git a/include/zid.php b/include/zid.php
index 67c1d9f6c..fe06948ba 100644
--- a/include/zid.php
+++ b/include/zid.php
@@ -53,14 +53,14 @@ function zid($s, $address = '') {
$mine = get_my_url();
$myaddr = (($address) ? $address : get_my_address());
- /**
- * @FIXME checking against our own channel url is no longer reliable. We may have a lot
- * of urls attached to our channel. Should probably match against our site, since we
- * will not need to remote authenticate on our own site anyway.
- */
+ $mine_parsed = parse_url($mine);
+ $s_parsed = parse_url($s);
+
+ if($mine_parsed['host'] === $s_parsed['host'])
+ $url_match = true;
- if ($mine && $myaddr && (! link_compare($mine,$s)))
- $zurl = $s . (($num_slashes >= 3) ? '' : '/') . $achar . 'zid=' . urlencode($myaddr);
+ if ($mine && $myaddr && (! $url_match))
+ $zurl = $s . (($num_slashes >= 3) ? '' : '/') . (($achar === '?') ? '?f=&' : '&') . 'zid=' . urlencode($myaddr);
else
$zurl = $s;
@@ -103,12 +103,17 @@ function strip_zats($s) {
return preg_replace('/[\?&]zat=(.*?)(&|$)/ism','$2',$s);
}
+function strip_escaped_zids($s) {
+ $x = preg_replace('/&amp\;zid=(.*?)(&|$)/ism','$2',$s);
+ return strip_query_param($x,'f');
+}
function clean_query_string($s = '') {
$x = strip_zids(($s) ? $s : \App::$query_string);
$x = strip_owt($x);
$x = strip_zats($x);
+ $x = strip_query_param($x,'sort');
return strip_query_param($x,'f');
}
@@ -346,4 +351,4 @@ function owt_init($token) {
info(sprintf( t('OpenWebAuth: %1$s welcomes %2$s'),\App::get_hostname(), $hubloc['xchan_name']));
logger('OpenWebAuth: auth success from ' . $hubloc['xchan_addr']);
-} \ No newline at end of file
+}
diff --git a/include/zot.php b/include/zot.php
index 87f449fb1..fd8247234 100644
--- a/include/zot.php
+++ b/include/zot.php
@@ -171,6 +171,8 @@ function zot_build_packet($channel, $type = 'notify', $recipients = null, $remot
* packet type: one of 'ping', 'pickup', 'purge', 'refresh', 'keychange', 'force_refresh', 'notify', 'auth_check'
* @param array $recipients
* envelope information, array ( 'guid' => string, 'guid_sig' => string ); empty for public posts
+ * @param string msg
+ * optional message
* @param string $remote_key
* optional public site key of target hub used to encrypt entire packet
* NOTE: remote_key and encrypted packets are required for 'auth_check' packets, optional for all others
@@ -299,7 +301,7 @@ function zot_zot($url, $data, $channel = null,$crypto = null) {
if($channel) {
$headers['X-Zot-Token'] = random_string();
$hash = \Zotlabs\Web\HTTPSig::generate_digest($data,false);
- $headers['X-Zot-Digest'] = 'SHA-256=' . $hash;
+ $headers['X-Zot-Digest'] = 'SHA-256=' . $hash;
$h = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'],'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false,false,'sha512',(($crypto) ? $crypto['hubloc_sitekey'] : ''), (($crypto) ? zot_best_algorithm($crypto['site_crypto']) : ''));
}
@@ -393,7 +395,7 @@ function zot_refresh($them, $channel = null, $force = false) {
if($s && intval($s[0]['site_dead']) && (! $force)) {
logger('zot_refresh: site ' . $url . ' is marked dead and force flag is not set. Cancelling operation.');
return false;
- }
+ }
$token = random_string();
@@ -1159,7 +1161,7 @@ function zot_process_response($hub, $arr, $outq) {
* and also that the signer and the sender match.
* If that happens, we do not need to fetch/pickup the message - we have it already and it is verified.
* Translate it into the form we need for zot_import() and import it.
- *
+ *
* Otherwise send back a pickup message, using our message tracking ID ($arr['secret']), which we will sign with our site
* private key.
* The entire pickup message is encrypted with the remote site's public key.
@@ -2283,13 +2285,31 @@ function process_mail_delivery($sender, $arr, $deliveries) {
continue;
}
+
if(! perm_is_allowed($channel['channel_id'],$sender['hash'],'post_mail')) {
- logger("permission denied for mail delivery {$channel['channel_id']}");
- $DR->update('permission denied');
- $result[] = $DR->get();
- continue;
+
+ /*
+ * Always allow somebody to reply if you initiated the conversation. It's anti-social
+ * and a bit rude to send a private message to somebody and block their ability to respond.
+ * If you are being harrassed and want to put an end to it, delete the conversation.
+ */
+
+ $return = false;
+ if($arr['parent_mid']) {
+ $return = q("select * from mail where mid = '%s' and channel_id = %d limit 1",
+ dbesc($arr['parent_mid']),
+ intval($channel['channel_id'])
+ );
+ }
+ if(! $return) {
+ logger("permission denied for mail delivery {$channel['channel_id']}");
+ $DR->update('permission denied');
+ $result[] = $DR->get();
+ continue;
+ }
}
+
$r = q("select id from mail where mid = '%s' and channel_id = %d limit 1",
dbesc($arr['mid']),
intval($channel['channel_id'])
@@ -3188,6 +3208,9 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) {
$channel = $r[0];
+ // don't provide these in the export
+
+ unset($channel['channel_active']);
unset($channel['channel_password']);
unset($channel['channel_salt']);
@@ -3454,6 +3477,14 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
continue;
}
+ // if the clone is active, so are we
+
+ if(substr($channel['channel_active'],0,10) !== substr(datetime_convert(),0,10)) {
+ q("UPDATE channel set channel_active = '%s' where channel_id = %d",
+ dbesc(datetime_convert()),
+ intval($channel['channel_id'])
+ );
+ }
if(array_key_exists('config',$arr) && is_array($arr['config']) && count($arr['config'])) {
foreach($arr['config'] as $cat => $k) {
@@ -3780,25 +3811,27 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
foreach($x as $y) {
// for each group, loop on members list we just received
- foreach($members[$y['hash']] as $member) {
- $found = false;
- $z = q("select xchan from group_member where gid = %d and uid = %d and xchan = '%s' limit 1",
- intval($y['id']),
- intval($channel['channel_id']),
- dbesc($member)
- );
- if($z)
- $found = true;
-
- // if somebody is in the group that wasn't before - add them
-
- if(! $found) {
- q("INSERT INTO group_member (uid, gid, xchan)
- VALUES( %d, %d, '%s' ) ",
- intval($channel['channel_id']),
+ if(isset($y['hash']) && isset($members[$y['hash']])) {
+ foreach($members[$y['hash']] as $member) {
+ $found = false;
+ $z = q("select xchan from group_member where gid = %d and uid = %d and xchan = '%s' limit 1",
intval($y['id']),
+ intval($channel['channel_id']),
dbesc($member)
);
+ if($z)
+ $found = true;
+
+ // if somebody is in the group that wasn't before - add them
+
+ if(! $found) {
+ q("INSERT INTO group_member (uid, gid, xchan)
+ VALUES( %d, %d, '%s' ) ",
+ intval($channel['channel_id']),
+ intval($y['id']),
+ dbesc($member)
+ );
+ }
}
}
@@ -3835,11 +3868,14 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
intval($channel['channel_id'])
);
if(! $x) {
- q("insert into profile ( profile_guid, aid, uid ) values ('%s', %d, %d)",
- dbesc($profile['profile_guid']),
- intval($channel['channel_account_id']),
- intval($channel['channel_id'])
+ profile_store_lowlevel(
+ [
+ 'aid' => $channel['channel_account_id'],
+ 'uid' => $channel['channel_id'],
+ 'profile_guid' => $profile['profile_guid'],
+ ]
);
+
$x = q("select * from profile where profile_guid = '%s' and uid = %d limit 1",
dbesc($profile['profile_guid']),
intval($channel['channel_id'])
@@ -5093,7 +5129,7 @@ function zot_reply_refresh($sender, $recipients) {
function zot6_check_sig() {
$ret = [ 'success' => false ];
-
+
logger('server: ' . print_r($_SERVER,true), LOGGER_DATA);
if(array_key_exists('HTTP_SIGNATURE',$_SERVER)) {