Merge branch '3.2RC'
This commit is contained in:
@@ -1,81 +0,0 @@
|
||||
<?php /** @file */
|
||||
|
||||
namespace Hubzilla\Import;
|
||||
|
||||
/**
|
||||
* @brief Class Import
|
||||
*
|
||||
*/
|
||||
class Import {
|
||||
|
||||
private $credentials = null;
|
||||
|
||||
protected $itemlist = null;
|
||||
protected $src_items = null;
|
||||
protected $items = null;
|
||||
|
||||
function get_credentials() {
|
||||
return $this->credentials;
|
||||
}
|
||||
|
||||
function get_itemlist() {
|
||||
return $this->itemlist;
|
||||
}
|
||||
|
||||
function get_item_ident($item) {
|
||||
|
||||
}
|
||||
|
||||
function get_item($item_ident) {
|
||||
|
||||
}
|
||||
|
||||
function get_taxonomy($item_ident) {
|
||||
|
||||
}
|
||||
|
||||
function get_children($item_ident) {
|
||||
|
||||
}
|
||||
|
||||
function convert_item($item_ident) {
|
||||
|
||||
}
|
||||
|
||||
function convert_taxonomy($item_ident) {
|
||||
|
||||
}
|
||||
|
||||
function convert_child($child) {
|
||||
|
||||
}
|
||||
|
||||
function store($item, $update = false) {
|
||||
|
||||
}
|
||||
|
||||
function run() {
|
||||
$this->credentials = $this->get_credentials();
|
||||
$this->itemlist = $this->get_itemlist();
|
||||
if($this->itemlist) {
|
||||
$this->src_items = array();
|
||||
$this->items = array();
|
||||
$cnt = 0;
|
||||
foreach($this->itemlist as $item) {
|
||||
$ident = $item->get_item_ident($item);
|
||||
$this->src_items[$ident]['item'] = $this->get_item($ident);
|
||||
$this->src_items[$ident]['taxonomy'] = $this->get_taxonomy($ident);
|
||||
$this->src_items[$ident]['children'] = $this->get_children($ident);
|
||||
$this->items[$cnt]['item'] = $this->convert_item($ident);
|
||||
$this->items[$cnt]['item']['term'] = $this->convert_taxonomy($ident);
|
||||
if($this->src_items[$ident]['children']) {
|
||||
$this->items[$cnt]['children'] = array();
|
||||
foreach($this->src_items[$ident]['children'] as $child) {
|
||||
$this[$cnt]['children'][] = $this->convert_child($child);
|
||||
}
|
||||
}
|
||||
$cnt ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,284 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once('include/html2bbcode.php');
|
||||
|
||||
// Sample module for importing conversation data from Reflection CMS. Some preparation was used to
|
||||
// dump relevant posts, categories and comments into individual JSON files, and also JSON dump of
|
||||
// the user table to search for avatars. Importation was also batched in sets of 20 posts per page
|
||||
// visit so as to survive shared hosting process limits. This provides some clues as how to handle
|
||||
// WordPress imports, which use a somewhat similar DB structure. The batching and individual files
|
||||
// might not be needed in VPS environments. As such this could be considered an extreme test case, but
|
||||
// the importation was successful in all regards using this code. The module URL was visited repeatedly
|
||||
// with a browser until all the posts had been imported.
|
||||
|
||||
|
||||
define('REDMATRIX_IMPORTCHANNEL','mike');
|
||||
define('REFLECT_EXPORTUSERNAME','mike');
|
||||
define('REFLECT_BLOGNAME','Diary and Other Rantings');
|
||||
define('REFLECT_BASEURL','http://example.com/');
|
||||
define('REFLECT_USERFILE','user.json');
|
||||
|
||||
// set to true if you need to process everything again
|
||||
define('REFLECT_OVERWRITE',false);
|
||||
|
||||
// we'll only process a small number of posts at a time on a shared host.
|
||||
|
||||
define('REFLECT_MAXPERRUN',30);
|
||||
|
||||
function reflect_get_channel() {
|
||||
|
||||
// this will be the channel_address or nickname of the red channel
|
||||
|
||||
$c = q("select * from channel left join xchan on channel_hash = xchan_hash
|
||||
where channel_address = '%s' limit 1",
|
||||
dbesc(REDMATRIX_IMPORTCHANNEL)
|
||||
);
|
||||
return $c[0];
|
||||
}
|
||||
|
||||
|
||||
function refimport_content(&$a) {
|
||||
|
||||
$channel = reflect_get_channel();
|
||||
|
||||
// load the user file. We need that to find the commenter's avatars
|
||||
|
||||
$u = file_get_contents(REFLECT_USERFILE);
|
||||
if($u) {
|
||||
$users = json_decode($u,true);
|
||||
}
|
||||
|
||||
$ignored = 0;
|
||||
$processed = 0;
|
||||
|
||||
$files = glob('article/*');
|
||||
if(! $files)
|
||||
return;
|
||||
|
||||
foreach($files as $f) {
|
||||
$s = file_get_contents($f);
|
||||
$j = json_decode($s,true);
|
||||
|
||||
if(! $j)
|
||||
continue;
|
||||
|
||||
$arr = array();
|
||||
|
||||
// see if this article was already processed
|
||||
$r = q("select * from item where mid = '%s' and uid = %d limit 1",
|
||||
dbesc($j['guid']),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
if($r) {
|
||||
if(REFLECT_OVERWRITE)
|
||||
$arr['id'] = $r[0]['id'];
|
||||
else {
|
||||
$ignored ++;
|
||||
rename($f,str_replace('article','done',$f));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$arr['uid'] = $channel['channel_account_id'];
|
||||
$arr['aid'] = $channel['channel_id'];
|
||||
$arr['mid'] = $arr['parent_mid'] = $j['guid'];
|
||||
$arr['created'] = $j['created'];
|
||||
$arr['edited'] = $j['edited'];
|
||||
$arr['author_xchan'] = $channel['channel_hash'];
|
||||
$arr['owner_xchan'] = $channel['channel_hash'];
|
||||
$arr['app'] = REFLECT_BLOGNAME;
|
||||
|
||||
$arr['item_origin'] = 1;
|
||||
$arr['item_wall'] = 1;
|
||||
$arr['item_thread_top'] = 1;
|
||||
|
||||
$arr['verb'] = ACTIVITY_POST;
|
||||
|
||||
// this is an assumption
|
||||
$arr['comment_policy'] = 'contacts';
|
||||
|
||||
|
||||
// import content. In this case the content is XHTML.
|
||||
|
||||
$arr['title'] = html2bbcode($j['title']);
|
||||
$arr['title'] = htmlspecialchars($arr['title'],ENT_COMPAT,'UTF-8',false);
|
||||
|
||||
|
||||
$arr['body'] = html2bbcode($j['body']);
|
||||
$arr['body'] = htmlspecialchars($arr['body'],ENT_COMPAT,'UTF-8',false);
|
||||
|
||||
|
||||
// convert relative urls to other posts on that service to absolute url on our service.
|
||||
$arr['body'] = preg_replace_callback("/\[url\=\/+article\/(.*?)\](.*?)\[url\]/",'reflect_article_callback',$arr['body']);
|
||||
|
||||
// also import any photos
|
||||
$arr['body'] = preg_replace_callback("/\[img(.*?)\](.*?)\[\/img\]/",'reflect_photo_callback',$arr['body']);
|
||||
|
||||
|
||||
// add categories
|
||||
|
||||
if($j['taxonomy'] && is_array($j['taxonomy']) && count($j['taxonomy'])) {
|
||||
$arr['term'] = array();
|
||||
foreach($j['taxonomy'] as $tax) {
|
||||
$arr['term'][] = array(
|
||||
'uid' => $channel['channel_id'],
|
||||
'type' => TERM_CATEGORY,
|
||||
'otype' => TERM_OBJ_POST,
|
||||
'term' => trim($tax['name']),
|
||||
'url' => $channel['xchan_url'] . '?f=&cat=' . urlencode(trim($tax['name']))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// store the item
|
||||
|
||||
if($arr['id'])
|
||||
item_store_update($arr);
|
||||
else
|
||||
item_store($arr);
|
||||
|
||||
// if there are any comments, process them
|
||||
// $comment['registered'] is somebody with an account on the system. Others are mostly anonymous
|
||||
|
||||
if($j['comments']) {
|
||||
foreach($j['comments'] as $comment) {
|
||||
$user = (($comment['registered']) ? reflect_find_user($users,$comment['author']) : null);
|
||||
reflect_comment_store($channel,$arr,$comment,$user);
|
||||
}
|
||||
}
|
||||
$processed ++;
|
||||
|
||||
if(REFLECT_MAXPERRUN && $processed > REFLECT_MAXPERRUN)
|
||||
break;
|
||||
}
|
||||
return 'processed: ' . $processed . EOL . 'completed: ' . $ignored . EOL;
|
||||
|
||||
}
|
||||
|
||||
function reflect_article_callback($matches) {
|
||||
return '[zrl=' . z_root() . '/display/'. $matches[1] . ']' . $matches[2] . '[/zrl]';
|
||||
}
|
||||
|
||||
function reflect_photo_callback($matches) {
|
||||
|
||||
if(strpos($matches[2],'http') !== false)
|
||||
return $matches[0];
|
||||
|
||||
$prefix = REFLECT_BASEURL;
|
||||
$x = z_fetch_url($prefix.$matches[2],true);
|
||||
|
||||
$hash = basename($matches[2]);
|
||||
|
||||
if($x['success']) {
|
||||
$channel = reflect_get_channel();
|
||||
require_once('include/photos.php');
|
||||
$p = photo_upload($channel,$channel,
|
||||
array('data' => $x['body'],
|
||||
'resource_id' => str_replace('-','',$hash),
|
||||
'filename' => $hash . '.jpg',
|
||||
'type' => 'image/jpeg',
|
||||
'visible' => false
|
||||
)
|
||||
);
|
||||
|
||||
if($p['success'])
|
||||
$newlink = $p['resource_id'] . '-0.jpg';
|
||||
|
||||
|
||||
// import photo and locate the link for it.
|
||||
return '[zmg]' . z_root() . '/photo/' . $newlink . '[/zmg]';
|
||||
|
||||
}
|
||||
// no replacement. Leave it alone.
|
||||
return $matches[0];
|
||||
}
|
||||
|
||||
function reflect_find_user($users,$name) {
|
||||
if($users) {
|
||||
foreach($users as $x) {
|
||||
if($x['name'] === $name) {
|
||||
return $x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
function reflect_comment_store($channel,$post,$comment,$user) {
|
||||
|
||||
// if the commenter was the channel owner, use their hubzilla xchan
|
||||
|
||||
if($comment['author'] === REFLECT_EXPORTUSERNAME && $comment['registered'])
|
||||
$hash = $channel['xchan_hash'];
|
||||
else {
|
||||
// we need a unique hash for the commenter. We don't know how many may have supplied
|
||||
// http://yahoo.com as their URL, so we'll use their avatar guid if they have one.
|
||||
// anonymous folks may get more than one xchan_hash if they commented more than once.
|
||||
|
||||
$hash = (($comment['registered'] && $user) ? $user['avatar'] : '');
|
||||
if(! $hash)
|
||||
$hash = random_string() . '.unknown';
|
||||
|
||||
// create an xchan for them which will also import their profile photo
|
||||
// they will have a network type 'unknown'.
|
||||
|
||||
$x = array(
|
||||
'hash' => $hash,
|
||||
'guid' => $hash,
|
||||
'url' => (($comment['url']) ? $comment['url'] : z_root()),
|
||||
'photo' => (($user) ? REFLECT_BASEURL . $user['avatar'] : z_root() . '/' . get_default_profile_photo()),
|
||||
'name' => $comment['author']
|
||||
);
|
||||
xchan_store($x);
|
||||
|
||||
}
|
||||
|
||||
$arr = array();
|
||||
|
||||
$r = q("select * from item where mid = '%s' and uid = %d limit 1",
|
||||
dbesc($comment['guid']),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
if($r) {
|
||||
if(REFLECT_OVERWRITE)
|
||||
$arr['id'] = $r[0]['id'];
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
// this is a lot like storing the post except for subtle differences, like parent_mid, flags, author_xchan,
|
||||
// and we don't have a comment edited field so use creation date
|
||||
|
||||
$arr['uid'] = $channel['channel_account_id'];
|
||||
$arr['aid'] = $channel['channel_id'];
|
||||
$arr['mid'] = $comment['guid'];
|
||||
$arr['parent_mid'] = $post['mid'];
|
||||
$arr['created'] = $comment['created'];
|
||||
$arr['edited'] = $comment['created'];
|
||||
$arr['author_xchan'] = $hash;
|
||||
$arr['owner_xchan'] = $channel['channel_hash'];
|
||||
$arr['item_origin'] = 1;
|
||||
$arr['item_wall'] = 1;
|
||||
$arr['verb'] = ACTIVITY_POST;
|
||||
$arr['comment_policy'] = 'contacts';
|
||||
|
||||
|
||||
$arr['title'] = html2bbcode($comment['title']);
|
||||
$arr['title'] = htmlspecialchars($arr['title'],ENT_COMPAT,'UTF-8',false);
|
||||
|
||||
|
||||
$arr['body'] = html2bbcode($comment['body']);
|
||||
$arr['body'] = htmlspecialchars($arr['body'],ENT_COMPAT,'UTF-8',false);
|
||||
$arr['body'] = preg_replace_callback("/\[url\=\/+article\/(.*?)\](.*?)\[url\]/",'reflect_article_callback',$arr['body']);
|
||||
$arr['body'] = preg_replace_callback("/\[img(.*?)\](.*?)\[\/img\]/",'reflect_photo_callback',$arr['body']);
|
||||
|
||||
// logger('comment: ' . print_r($arr,true));
|
||||
|
||||
if($arr['id'])
|
||||
item_store_update($arr);
|
||||
else
|
||||
item_store($arr);
|
||||
|
||||
}
|
||||
+33
-11
@@ -262,24 +262,46 @@ function create_account($arr) {
|
||||
|
||||
function verify_email_address($arr) {
|
||||
|
||||
$hash = random_string();
|
||||
if(array_key_exists('resend',$arr)) {
|
||||
$email = $arr['email'];
|
||||
$a = q("select * from account where account_email = '%s' limit 1",
|
||||
dbesc($arr['email'])
|
||||
);
|
||||
if(! ($a && ($a[0]['account_flags'] & ACCOUNT_UNVERIFIED))) {
|
||||
return false;
|
||||
}
|
||||
$account = $a[0];
|
||||
$v = q("select * from register where uid = %d and password = 'verify' limit 1",
|
||||
intval($account['account_id'])
|
||||
);
|
||||
if($v) {
|
||||
$hash = $v[0]['hash'];
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$hash = random_string(24);
|
||||
|
||||
$r = q("INSERT INTO register ( hash, created, uid, password, lang ) VALUES ( '%s', '%s', %d, '%s', '%s' ) ",
|
||||
dbesc($hash),
|
||||
dbesc(datetime_convert()),
|
||||
intval($arr['account']['account_id']),
|
||||
dbesc('verify'),
|
||||
dbesc($arr['account']['account_language'])
|
||||
);
|
||||
$r = q("INSERT INTO register ( hash, created, uid, password, lang ) VALUES ( '%s', '%s', %d, '%s', '%s' ) ",
|
||||
dbesc($hash),
|
||||
dbesc(datetime_convert()),
|
||||
intval($arr['account']['account_id']),
|
||||
dbesc('verify'),
|
||||
dbesc($arr['account']['account_language'])
|
||||
);
|
||||
$account = $arr['account'];
|
||||
}
|
||||
|
||||
push_lang(($arr['account']['account_language']) ? $arr['account']['account_language'] : 'en');
|
||||
push_lang(($account['account_language']) ? $account['account_language'] : 'en');
|
||||
|
||||
$email_msg = replace_macros(get_intltext_template('register_verify_member.tpl'),
|
||||
[
|
||||
'$sitename' => get_config('system','sitename'),
|
||||
'$siteurl' => z_root(),
|
||||
'$email' => $arr['email'],
|
||||
'$uid' => $arr['account']['account_id'],
|
||||
'$uid' => $account['account_id'],
|
||||
'$hash' => $hash,
|
||||
'$details' => $details
|
||||
]
|
||||
@@ -508,7 +530,7 @@ function account_deny($hash) {
|
||||
|
||||
function account_approve($hash) {
|
||||
|
||||
$ret = array('success' => false);
|
||||
$ret = false;
|
||||
|
||||
// Note: when the password in the register table is 'verify', the uid actually contains the account_id
|
||||
|
||||
|
||||
@@ -5,104 +5,9 @@
|
||||
* @package acl_selectors
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param string $selname
|
||||
* @param string $selclass
|
||||
* @param mixed $preselected
|
||||
* @param number $size
|
||||
* @return string
|
||||
*/
|
||||
function group_select($selname, $selclass, $preselected = false, $size = 4) {
|
||||
|
||||
$o = '';
|
||||
|
||||
$o .= "<select name=\"{$selname}[]\" id=\"$selclass\" class=\"$selclass\" multiple=\"multiple\" size=\"$size\">\r\n";
|
||||
|
||||
$r = q("SELECT * FROM groups WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
|
||||
$arr = array('group' => $r, 'entry' => $o);
|
||||
|
||||
// e.g. 'network_pre_group_deny', 'profile_pre_group_allow'
|
||||
|
||||
call_hooks(App::$module . '_pre_' . $selname, $arr);
|
||||
|
||||
if($r) {
|
||||
foreach($r as $rr) {
|
||||
if((is_array($preselected)) && in_array($rr['id'], $preselected))
|
||||
$selected = " selected=\"selected\" ";
|
||||
else
|
||||
$selected = '';
|
||||
$trimmed = mb_substr($rr['gname'],0,12);
|
||||
|
||||
$o .= "<option value=\"{$rr['id']}\" $selected title=\"{$rr['name']}\" >$trimmed</option>\r\n";
|
||||
}
|
||||
|
||||
}
|
||||
$o .= "</select>\r\n";
|
||||
|
||||
call_hooks(App::$module . '_post_' . $selname, $o);
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
function contact_select($selname, $selclass, $preselected = false, $size = 4, $privmail = false, $celeb = false, $privatenet = false, $tabindex = null) {
|
||||
|
||||
$o = '';
|
||||
|
||||
// When used for private messages, we limit correspondence to mutual DFRN/Friendica friends and the selector
|
||||
// to one recipient. By default our selector allows multiple selects amongst all contacts.
|
||||
|
||||
$sql_extra = '';
|
||||
|
||||
$tabindex = ($tabindex > 0 ? 'tabindex="$tabindex"' : '');
|
||||
|
||||
if($privmail)
|
||||
$o .= "<select name=\"$selname\" id=\"$selclass\" class=\"$selclass\" size=\"$size\" $tabindex >\r\n";
|
||||
else
|
||||
$o .= "<select name=\"{$selname}[]\" id=\"$selclass\" class=\"$selclass\" multiple=\"multiple\" size=\"$size\" $tabindex>\r\n";
|
||||
|
||||
$r = q("SELECT abook_id, xchan_name, xchan_url, xchan_photo_s from abook left join xchan on abook_xchan = xchan_hash
|
||||
where abook_self = 0 and abook_channel = %d
|
||||
$sql_extra
|
||||
ORDER BY xchan_name ASC",
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
|
||||
$arr = array('contact' => $r, 'entry' => $o);
|
||||
|
||||
// e.g. 'network_pre_contact_deny', 'profile_pre_contact_allow'
|
||||
|
||||
call_hooks(App::$module . '_pre_' . $selname, $arr);
|
||||
|
||||
if($r) {
|
||||
foreach($r as $rr) {
|
||||
if((is_array($preselected)) && in_array($rr['id'], $preselected))
|
||||
$selected = ' selected="selected" ';
|
||||
else
|
||||
$selected = '';
|
||||
|
||||
$trimmed = mb_substr($rr['xchan_name'], 0, 20);
|
||||
|
||||
$o .= "<option value=\"{$rr['abook_id']}\" $selected title=\"{$rr['xchan_name']}|{$rr['xchan_url']}\" >$trimmed</option>\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
$o .= "</select>\r\n";
|
||||
|
||||
call_hooks(App::$module . '_post_' . $selname, $o);
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
|
||||
function fixacl(&$item) {
|
||||
$item = str_replace(array('<', '>'), array('', ''), $item);
|
||||
$item = str_replace( [ '<', '>' ], [ '', '' ], $item);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
api_register_func('api/export/basic','api_export_basic', true);
|
||||
api_register_func('api/red/channel/export/basic','api_export_basic', true);
|
||||
api_register_func('api/z/1.0/channel/export/basic','api_export_basic', true);
|
||||
api_register_func('api/red/channel/list','api_channel_list', true);
|
||||
api_register_func('api/z/1.0/channel/list','api_channel_list', true);
|
||||
api_register_func('api/red/channel/stream','api_channel_stream', true);
|
||||
api_register_func('api/z/1.0/channel/stream','api_channel_stream', true);
|
||||
api_register_func('api/red/files','api_attach_list', true);
|
||||
@@ -111,9 +113,31 @@
|
||||
}
|
||||
}
|
||||
|
||||
function api_channel_list($type) {
|
||||
if(api_user() === false) {
|
||||
logger('api_channel_stream: no user');
|
||||
return false;
|
||||
}
|
||||
|
||||
$channel = channelx_by_n(api_user());
|
||||
if(! $channel)
|
||||
return false;
|
||||
|
||||
$ret = [];
|
||||
|
||||
$r = q("select channel_address from channel where channel_account_id = %d",
|
||||
intval($channel['channel_account_id'])
|
||||
);
|
||||
|
||||
if($r) {
|
||||
foreach($r as $rv) {
|
||||
$ret[] = $rv['channel_address'];
|
||||
}
|
||||
}
|
||||
|
||||
json_return_and_die($ret);
|
||||
|
||||
}
|
||||
|
||||
|
||||
function api_channel_stream($type) {
|
||||
|
||||
@@ -261,6 +261,7 @@ else {
|
||||
$verify = account_verify_password($_POST['username'], $_POST['password']);
|
||||
if($verify && array_key_exists('reason',$verify) && $verify['reason'] === 'unvalidated') {
|
||||
notice( t('Email validation is incomplete. Please check your email.'));
|
||||
goaway(z_root() . '/email_validation/' . bin2hex(trim(escape_tags($_POST['username']))));
|
||||
}
|
||||
elseif($verify) {
|
||||
$atoken = $verify['xchan'];
|
||||
|
||||
+51
-12
@@ -108,7 +108,11 @@ function tryzrlvideo($match) {
|
||||
if($zrl)
|
||||
$link = zid($link);
|
||||
|
||||
return '<video controls="controls" preload="none" src="' . str_replace(' ','%20',$link) . '" style="width:100%; max-width:' . App::$videowidth . 'px"><a href="' . str_replace(' ','%20',$link) . '">' . $link . '</a></video>';
|
||||
$static_link = get_config('system','video_default_poster','images/video_poster.jpg');
|
||||
if($static_link)
|
||||
$poster = 'poster="' . escape_tags($static_link) . '" ' ;
|
||||
|
||||
return '<video ' . $poster . ' controls="controls" preload="none" src="' . str_replace(' ','%20',$link) . '" style="width:100%; max-width:' . App::$videowidth . 'px"><a href="' . str_replace(' ','%20',$link) . '">' . $link . '</a></video>';
|
||||
}
|
||||
|
||||
// [noparse][i]italic[/i][/noparse] turns into
|
||||
@@ -428,6 +432,16 @@ function bb_spoilertag($match) {
|
||||
return '<div onclick="openClose(\'opendiv-' . $rnd . '\'); return false;" class="fakelink">' . $openclose . '</div><blockquote id="opendiv-' . $rnd . '" style="display: none;">' . $text . '</blockquote>';
|
||||
}
|
||||
|
||||
function bb_summary($match) {
|
||||
$rnd1 = mt_rand();
|
||||
$rnd2 = mt_rand();
|
||||
$rnd3 = mt_rand();
|
||||
$rnd4 = mt_rand();
|
||||
|
||||
return $match[1] . '<div style="display: block;" id="opendiv-' . $rnd2 . '">' . $match[2] . '</div><div style="display: block;" id="opendiv-' . $rnd3 . '" onclick="openClose(\'opendiv-' . $rnd1 . '\'); openClose(\'opendiv-' . $rnd2 . '\'); openClose(\'opendiv-' . $rnd3 . '\'); openClose(\'opendiv-' . $rnd4 . '\'); return false;" class="fakelink view-article">' . t('View article') . '</div><div style="display: none;" id="opendiv-' . $rnd4 . '" onclick="openClose(\'opendiv-' . $rnd1 . '\'); openClose(\'opendiv-' . $rnd2 . '\'); openClose(\'opendiv-' . $rnd3 . '\'); openClose(\'opendiv-' . $rnd4 . '\'); return false;" class="fakelink view-summary">' . t('View summary') . '</div><div id="opendiv-' . $rnd1 . '" style="display: none;">' . $match[3] . '</div>';
|
||||
}
|
||||
|
||||
|
||||
function bb_definitionList($match) {
|
||||
// $match[1] is the markup styles for the "terms" in the definition list.
|
||||
// $match[2] is the content between the [dl]...[/dl] tags
|
||||
@@ -600,29 +614,47 @@ function bb_observer($Text) {
|
||||
return $Text;
|
||||
}
|
||||
|
||||
function bb_code_protect($s) {
|
||||
return 'b64.^9e%.' . base64_encode($s) . '.b64.$9e%';
|
||||
}
|
||||
|
||||
function bb_code_unprotect($s) {
|
||||
return preg_replace_callback('|b64\.\^9e\%\.(.*?)\.b64\.\$9e\%|ism','bb_code_unprotect_sub',$s);
|
||||
}
|
||||
|
||||
function bb_code_unprotect_sub($match) {
|
||||
return base64_decode($match[1]);
|
||||
}
|
||||
|
||||
function bb_code($match) {
|
||||
if(strpos($match[0], "<br />"))
|
||||
return '<code>' . trim($match[1]) . '</code>';
|
||||
return '<pre><code>' . bb_code_protect(trim($match[1])) . '</code></pre>';
|
||||
else
|
||||
return '<code class="inline-code">' . trim($match[1]) . '</code>';
|
||||
return '<code class="inline-code">' . bb_code_protect(trim($match[1])) . '</code>';
|
||||
}
|
||||
|
||||
function bb_code_options($match) {
|
||||
if(strpos($match[0], "<br />")) {
|
||||
$class = "";
|
||||
$pre = true;
|
||||
} else {
|
||||
$class = "inline-code";
|
||||
$pre = false;
|
||||
}
|
||||
if(strpos($match[1], 'nowrap')) {
|
||||
$style = "overflow-x: auto; white-space: pre;";
|
||||
} else {
|
||||
$style = "";
|
||||
}
|
||||
return '<code class="'. $class .'" style="'. $style .'">' . trim($match[2]) . '</code>';
|
||||
if($pre) {
|
||||
return '<pre><code class="'. $class .'" style="'. $style .'">' . bb_code_protect(trim($match[2])) . '</code></pre>';
|
||||
} else {
|
||||
return '<code class="'. $class .'" style="'. $style .'">' . bb_code_protect(trim($match[2])) . '</code>';
|
||||
}
|
||||
}
|
||||
|
||||
function bb_highlight($match) {
|
||||
return text_highlight($match[2],strtolower($match[1]));
|
||||
return bb_code_protect(text_highlight($match[2],strtolower($match[1])));
|
||||
}
|
||||
|
||||
function bb_fixtable_lf($match) {
|
||||
@@ -812,6 +844,17 @@ function bbcode($Text, $options = []) {
|
||||
|
||||
$Text = str_replace(array("\t", " "), array(" ", " "), $Text);
|
||||
|
||||
|
||||
// Check for [code] text
|
||||
if (strpos($Text,'[code]') !== false) {
|
||||
$Text = preg_replace_callback("/\[code\](.*?)\[\/code\]/ism", 'bb_code', $Text);
|
||||
}
|
||||
|
||||
// Check for [code options] text
|
||||
if (strpos($Text,'[code ') !== false) {
|
||||
$Text = preg_replace_callback("/\[code(.*?)\](.*?)\[\/code\]/ism", 'bb_code_options', $Text);
|
||||
}
|
||||
|
||||
// Set up the parameters for a URL search string
|
||||
$URLSearchString = "^\[\]";
|
||||
// Set up the parameters for a MAIL search string
|
||||
@@ -1052,14 +1095,9 @@ function bbcode($Text, $options = []) {
|
||||
$Text = preg_replace("/\[font=(.*?)\](.*?)\[\/font\]/sm", "<span style=\"font-family: $1;\">$2</span>", $Text);
|
||||
}
|
||||
|
||||
// Check for [code] text
|
||||
if (strpos($Text,'[code]') !== false) {
|
||||
$Text = preg_replace_callback("/\[code\](.*?)\[\/code\]/ism", 'bb_code', $Text);
|
||||
}
|
||||
|
||||
// Check for [code options] text
|
||||
if (strpos($Text,'[code ') !== false) {
|
||||
$Text = preg_replace_callback("/\[code(.*?)\](.*?)\[\/code\]/ism", 'bb_code_options', $Text);
|
||||
if(strpos($Text,'[/summary]') !== false) {
|
||||
$Text = preg_replace_callback("/^(.*?)\[summary\](.*?)\[\/summary\](.*?)$/ism", 'bb_summary', $Text);
|
||||
}
|
||||
|
||||
// Check for [spoiler] text
|
||||
@@ -1273,6 +1311,7 @@ function bbcode($Text, $options = []) {
|
||||
|
||||
// replace escaped links in code= blocks
|
||||
$Text = str_replace('%eY9-!','http', $Text);
|
||||
$Text = bb_code_unprotect($Text);
|
||||
|
||||
$Text = preg_replace('/\[\&\;([#a-z0-9]+)\;\]/', '&$1;', $Text);
|
||||
|
||||
|
||||
+7
-6
@@ -1126,8 +1126,7 @@ function channel_export_items($channel_id, $start, $finish) {
|
||||
/**
|
||||
* @brief Loads a profile into the App structure.
|
||||
*
|
||||
* The function requires a writeable copy of the main App structure, and the
|
||||
* nickname of a valid channel.
|
||||
* The function requires the nickname of a valid channel.
|
||||
*
|
||||
* Permissions of the current observer are checked. If a restricted profile is available
|
||||
* to the current observer, that will be loaded instead of the channel default profile.
|
||||
@@ -1449,6 +1448,7 @@ function profile_sidebar($profile, $block = 0, $show_connect = true, $zcard = fa
|
||||
'$reddress' => $reddress,
|
||||
'$rating' => '',
|
||||
'$contact_block' => $contact_block,
|
||||
'$change_photo' => t('Change your profile photo'),
|
||||
'$editmenu' => profile_edit_menu($profile['uid'])
|
||||
));
|
||||
|
||||
@@ -1896,8 +1896,9 @@ function is_public_profile() {
|
||||
function get_profile_fields_basic($filter = 0) {
|
||||
|
||||
$profile_fields_basic = (($filter == 0) ? get_config('system','profile_fields_basic') : null);
|
||||
|
||||
if(! $profile_fields_basic)
|
||||
$profile_fields_basic = array('fullname','pdesc','chandesc','comms','gender','dob','dob_tz','address','locality','region','postal_code','country_name','marital','sexual','homepage','hometown','keywords','about','contact');
|
||||
$profile_fields_basic = array('fullname','pdesc','chandesc','comms','gender','dob','dob_tz','region','country_name','marital','sexual','homepage','hometown','keywords','about','contact');
|
||||
|
||||
$x = array();
|
||||
if($profile_fields_basic)
|
||||
@@ -1912,7 +1913,7 @@ function get_profile_fields_advanced($filter = 0) {
|
||||
$basic = get_profile_fields_basic($filter);
|
||||
$profile_fields_advanced = (($filter == 0) ? get_config('system','profile_fields_advanced') : null);
|
||||
if(! $profile_fields_advanced)
|
||||
$profile_fields_advanced = array('partner','howlong','politic','religion','likes','dislikes','interest','channels','music','book','film','tv','romance','employment','education');
|
||||
$profile_fields_advanced = array('address','locality','postal_code','partner','howlong','politic','religion','likes','dislikes','interest','channels','music','book','film','tv','romance','employment','education');
|
||||
|
||||
$x = array();
|
||||
if($basic)
|
||||
@@ -2553,10 +2554,10 @@ function channel_remove($channel_id, $local = true, $unset_session = false) {
|
||||
q("DELETE FROM profile WHERE uid = %d", intval($channel_id));
|
||||
q("DELETE FROM src WHERE src_channel_id = %d", intval($channel_id));
|
||||
|
||||
$r = q("select resource_id FROM attach WHERE uid = %d", intval($channel_id));
|
||||
$r = q("select hash FROM attach WHERE uid = %d", intval($channel_id));
|
||||
if($r) {
|
||||
foreach($r as $rv) {
|
||||
attach_delete($channel_id,$rv['resource_id']);
|
||||
attach_delete($channel_id,$rv['hash']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -974,7 +974,7 @@ function author_is_pmable($xchan, $abook) {
|
||||
if($x['result'] !== 'unset')
|
||||
return $x['result'];
|
||||
|
||||
if($xchan['xchan_network'] === 'zot')
|
||||
if($xchan['xchan_network'] === 'zot' && get_observer_hash())
|
||||
return true;
|
||||
return false;
|
||||
|
||||
@@ -1005,7 +1005,7 @@ function thread_author_menu($item, $mode = '') {
|
||||
$contact = App::$contacts[$item['author_xchan']];
|
||||
else
|
||||
if($local_channel && $item['author']['xchan_addr'])
|
||||
$follow_url = z_root() . '/follow/?f=&url=' . urlencode($item['author']['xchan_addr']);
|
||||
$follow_url = z_root() . '/follow/?f=&url=' . urlencode($item['author']['xchan_addr']) . '&interactive=0';
|
||||
|
||||
|
||||
if($item['uid'] > 0 && author_is_pmable($item['author'],$contact)) {
|
||||
@@ -1051,8 +1051,8 @@ function thread_author_menu($item, $mode = '') {
|
||||
'menu' => 'follow',
|
||||
'title' => t('Connect'),
|
||||
'icon' => 'fw',
|
||||
'action' => '',
|
||||
'href' => $follow_url
|
||||
'action' => 'doFollowAuthor(\'' . $follow_url . '\'); return false;',
|
||||
'href' => '#',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
+41
-51
@@ -31,19 +31,6 @@ function rsa_verify($data,$sig,$key,$alg = 'sha256') {
|
||||
return (($verify > 0) ? true : false);
|
||||
}
|
||||
|
||||
function pkcs5_pad ($text, $blocksize)
|
||||
{
|
||||
$pad = $blocksize - (strlen($text) % $blocksize);
|
||||
return $text . str_repeat(chr($pad), $pad);
|
||||
}
|
||||
|
||||
function pkcs5_unpad($text)
|
||||
{
|
||||
$pad = ord($text{strlen($text)-1});
|
||||
if ($pad > strlen($text)) return false;
|
||||
if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) return false;
|
||||
return substr($text, 0, -1 * $pad);
|
||||
}
|
||||
|
||||
function AES256CBC_encrypt($data,$key,$iv) {
|
||||
|
||||
@@ -132,10 +119,27 @@ function crypto_encapsulate($data,$pubkey,$alg='aes256cbc') {
|
||||
}
|
||||
|
||||
function other_encapsulate($data,$pubkey,$alg) {
|
||||
|
||||
if(! $pubkey)
|
||||
logger('no key. data: ' . $data);
|
||||
|
||||
$fn = strtoupper($alg) . '_encrypt';
|
||||
// This default will change in the future. For now make it backward compatible.
|
||||
|
||||
$padding = OPENSSL_PKCS1_PADDING;
|
||||
$base = $alg;
|
||||
|
||||
$exts = explode('.',$alg);
|
||||
if(count($exts) > 1) {
|
||||
switch($exts[1]) {
|
||||
case 'oaep':
|
||||
$padding = OPENSSL_PKCS1_OAEP_PADDING;
|
||||
break;
|
||||
}
|
||||
$base = $exts[0];
|
||||
}
|
||||
|
||||
|
||||
$fn = strtoupper($base) . '_encrypt';
|
||||
if(function_exists($fn)) {
|
||||
|
||||
// A bit hesitant to use openssl_random_pseudo_bytes() as we know
|
||||
@@ -153,14 +157,14 @@ function other_encapsulate($data,$pubkey,$alg) {
|
||||
$iv = openssl_random_pseudo_bytes(256);
|
||||
$result['data'] = base64url_encode($fn($data,$key,$iv),true);
|
||||
// log the offending call so we can track it down
|
||||
if(! openssl_public_encrypt($key,$k,$pubkey)) {
|
||||
if(! openssl_public_encrypt($key,$k,$pubkey,$padding)) {
|
||||
$x = debug_backtrace();
|
||||
logger('RSA failed. ' . print_r($x[0],true));
|
||||
}
|
||||
|
||||
$result['alg'] = $alg;
|
||||
$result['key'] = base64url_encode($k,true);
|
||||
openssl_public_encrypt($iv,$i,$pubkey);
|
||||
openssl_public_encrypt($iv,$i,$pubkey,$padding);
|
||||
$result['iv'] = base64url_encode($i,true);
|
||||
return $result;
|
||||
}
|
||||
@@ -179,7 +183,7 @@ function crypto_methods() {
|
||||
// The actual methods are responsible for deriving the actual key/iv from the provided parameters;
|
||||
// possibly by truncation or segmentation - though many other methods could be used.
|
||||
|
||||
$r = [ 'aes256ctr', 'camellia256cfb', 'cast5cfb', 'aes256cbc', 'aes128cbc', 'cast5cbc' ];
|
||||
$r = [ 'aes256ctr.oaep', 'camellia256cfb.oaep', 'cast5cfb.oaep', 'aes256ctr', 'camellia256cfb', 'cast5cfb', 'aes256cbc', 'aes128cbc', 'cast5cbc' ];
|
||||
call_hooks('crypto_methods',$r);
|
||||
return $r;
|
||||
|
||||
@@ -220,6 +224,7 @@ function aes_encapsulate($data,$pubkey) {
|
||||
function crypto_unencapsulate($data,$prvkey) {
|
||||
if(! $data)
|
||||
return;
|
||||
|
||||
$alg = ((array_key_exists('alg',$data)) ? $data['alg'] : 'aes256cbc');
|
||||
if($alg === 'aes256cbc')
|
||||
return aes_unencapsulate($data,$prvkey);
|
||||
@@ -229,10 +234,26 @@ function crypto_unencapsulate($data,$prvkey) {
|
||||
}
|
||||
|
||||
function other_unencapsulate($data,$prvkey,$alg) {
|
||||
$fn = strtoupper($alg) . '_decrypt';
|
||||
|
||||
// This default will change in the future. For now make it backward compatible.
|
||||
|
||||
$padding = OPENSSL_PKCS1_PADDING;
|
||||
$base = $alg;
|
||||
|
||||
$exts = explode('.',$alg);
|
||||
if(count($exts) > 1) {
|
||||
switch($exts[1]) {
|
||||
case 'oaep':
|
||||
$padding = OPENSSL_PKCS1_OAEP_PADDING;
|
||||
break;
|
||||
}
|
||||
$base = $exts[0];
|
||||
}
|
||||
|
||||
$fn = strtoupper($base) . '_decrypt';
|
||||
if(function_exists($fn)) {
|
||||
openssl_private_decrypt(base64url_decode($data['key']),$k,$prvkey);
|
||||
openssl_private_decrypt(base64url_decode($data['iv']),$i,$prvkey);
|
||||
openssl_private_decrypt(base64url_decode($data['key']),$k,$prvkey,$padding);
|
||||
openssl_private_decrypt(base64url_decode($data['iv']),$i,$prvkey,$padding);
|
||||
return $fn(base64url_decode($data['data']),$k,$i);
|
||||
}
|
||||
else {
|
||||
@@ -282,37 +303,6 @@ function new_keypair($bits) {
|
||||
|
||||
}
|
||||
|
||||
function pkcs1to8($oldkey,$len) {
|
||||
|
||||
if($len == 4096)
|
||||
$c = 'g';
|
||||
if($len == 2048)
|
||||
$c = 'Q';
|
||||
|
||||
if(strstr($oldkey,'BEGIN PUBLIC'))
|
||||
return $oldkey;
|
||||
|
||||
$oldkey = str_replace('-----BEGIN RSA PUBLIC KEY-----', '', $oldkey);
|
||||
$oldkey = trim(str_replace('-----END RSA PUBLIC KEY-----', '', $oldkey));
|
||||
$key = 'MIICIjANBgkqhkiG9w0BAQEFAAOCA' . $c . '8A' . str_replace("\n", '', $oldkey);
|
||||
$key = "-----BEGIN PUBLIC KEY-----\n" . wordwrap($key, 64, "\n", true) . "\n-----END PUBLIC KEY-----";
|
||||
return $key;
|
||||
}
|
||||
|
||||
function pkcs8to1($oldkey,$len) {
|
||||
|
||||
if(strstr($oldkey,'BEGIN RSA'))
|
||||
return $oldkey;
|
||||
|
||||
$oldkey = str_replace('-----BEGIN PUBLIC KEY-----', '', $oldkey);
|
||||
$oldkey = trim(str_replace('-----END PUBLIC KEY-----', '', $oldkey));
|
||||
$key = str_replace("\n",'',$oldkey);
|
||||
$key = substr($key,32);
|
||||
$key = "-----BEGIN RSA PUBLIC KEY-----\n" . wordwrap($key, 64, "\n", true) . "\n-----END RSA PUBLIC KEY-----";
|
||||
return $key;
|
||||
}
|
||||
|
||||
|
||||
function DerToPem($Der, $Private=false)
|
||||
{
|
||||
//Encode:
|
||||
|
||||
+17
-82
@@ -93,16 +93,6 @@ function datetime_convert($from = 'UTC', $to = 'UTC', $s = 'now', $fmt = "Y-m-d
|
||||
return $d->format($fmt);
|
||||
}
|
||||
|
||||
// Slight hackish adjustment so that 'zero' datetime actually returns what is intended
|
||||
// otherwise we end up with -0001-11-30 ...
|
||||
// add 32 days so that we at least get year 00, and then hack around the fact that
|
||||
// months and days always start with 1.
|
||||
|
||||
// if(substr($s,0,10) == '0000-00-00') {
|
||||
// $d = new DateTime($s . ' + 32 days', new DateTimeZone('UTC'));
|
||||
// return str_replace('1', '0', $d->format($fmt));
|
||||
// }
|
||||
|
||||
try {
|
||||
$from_obj = new DateTimeZone($from);
|
||||
} catch(Exception $e) {
|
||||
@@ -135,69 +125,19 @@ function datetime_convert($from = 'UTC', $to = 'UTC', $s = 'now', $fmt = "Y-m-d
|
||||
*/
|
||||
function dob($dob) {
|
||||
|
||||
list($year, $month, $day) = sscanf($dob, '%4d-%2d-%2d');
|
||||
$f = get_config('system', 'birthday_input_format');
|
||||
if (! $f)
|
||||
$f = 'ymd';
|
||||
|
||||
if ($dob === '0000-00-00')
|
||||
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'));
|
||||
|
||||
$o = replace_macros(get_markup_template("field_input.tpl"), array('$field' => array(
|
||||
'dob',
|
||||
t('Birthday'),
|
||||
$value,
|
||||
((intval($value)) ? t('Age: ') . age($value,App::$user['timezone'],App::$user['timezone']) : ''),
|
||||
'',
|
||||
'placeholder="' . t('YYYY-MM-DD or MM-DD') .'"'
|
||||
)));
|
||||
$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') .'"' ]
|
||||
]);
|
||||
|
||||
|
||||
// if ($dob && $dob != '0000-00-00')
|
||||
// $o = datesel($f,mktime(0,0,0,0,0,1900),mktime(),mktime(0,0,0,$month,$day,$year),'dob');
|
||||
// else
|
||||
// $o = datesel($f,mktime(0,0,0,0,0,1900),mktime(),false,'dob');
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a date selector.
|
||||
*
|
||||
* @see datetimesel()
|
||||
* @param string $format
|
||||
* format string, e.g. 'ymd' or 'mdy'. Not currently supported
|
||||
* @param DateTime $min
|
||||
* unix timestamp of minimum date
|
||||
* @param DateTime $max
|
||||
* unix timestap of maximum date
|
||||
* @param DateTime $default
|
||||
* unix timestamp of default date
|
||||
* @param string $id
|
||||
* id and name of datetimepicker (defaults to "datetimepicker")
|
||||
*/
|
||||
function datesel($format, $min, $max, $default, $id = 'datepicker') {
|
||||
return datetimesel($format, $min, $max, $default, '', $id, true, false, '', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a time selector.
|
||||
*
|
||||
* @param string $format
|
||||
* format string, e.g. 'ymd' or 'mdy'. Not currently supported
|
||||
* @param string $h
|
||||
* already selected hour
|
||||
* @param string $m
|
||||
* already selected minute
|
||||
* @param string $id
|
||||
* id and name of datetimepicker (defaults to "timepicker")
|
||||
*/
|
||||
function timesel($format, $h, $m, $id='timepicker') {
|
||||
return datetimesel($format, new DateTime(), new DateTime(), new DateTime("$h:$m"), '', $id, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a datetime selector.
|
||||
*
|
||||
@@ -449,12 +389,7 @@ function cal($y = 0, $m = 0, $links = false, $class='') {
|
||||
|
||||
// month table - start at 1 to match human usage.
|
||||
|
||||
$mtab = array(' ',
|
||||
'January','February','March',
|
||||
'April','May','June',
|
||||
'July','August','September',
|
||||
'October','November','December'
|
||||
);
|
||||
$mtab = [ ' ', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ];
|
||||
|
||||
$thisyear = datetime_convert('UTC',date_default_timezone_get(),'now','Y');
|
||||
$thismonth = datetime_convert('UTC',date_default_timezone_get(),'now','m');
|
||||
@@ -463,7 +398,7 @@ function cal($y = 0, $m = 0, $links = false, $class='') {
|
||||
if (! $m)
|
||||
$m = intval($thismonth);
|
||||
|
||||
$dn = array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');
|
||||
$dn = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ];
|
||||
$f = get_first_dim($y, $m);
|
||||
$l = get_dim($y, $m);
|
||||
$d = 1;
|
||||
@@ -569,17 +504,17 @@ function update_birthdays() {
|
||||
if (! perm_is_allowed($rr['abook_channel'], $rr['xchan_hash'], 'send_stream'))
|
||||
continue;
|
||||
|
||||
$ev = array();
|
||||
$ev['uid'] = $rr['abook_channel'];
|
||||
$ev['account'] = $rr['abook_account'];
|
||||
$ev['event_xchan'] = $rr['xchan_hash'];
|
||||
$ev['dtstart'] = datetime_convert('UTC', 'UTC', $rr['abook_dob']);
|
||||
$ev['dtend'] = datetime_convert('UTC', 'UTC', $rr['abook_dob'] . ' + 1 day ');
|
||||
$ev['adjust'] = intval(feature_enabled($rr['abook_channel'],'smart_birthdays'));
|
||||
$ev['summary'] = sprintf( t('%1$s\'s birthday'), $rr['xchan_name']);
|
||||
$ev['description'] = sprintf( t('Happy Birthday %1$s'),
|
||||
'[zrl=' . $rr['xchan_url'] . ']' . $rr['xchan_name'] . '[/zrl]') ;
|
||||
$ev['etype'] = 'birthday';
|
||||
$ev = [
|
||||
'uid' => $rr['abook_channel'],
|
||||
'account' => $rr['abook_account'],
|
||||
'event_xchan' => $rr['xchan_hash'],
|
||||
'dtstart' => datetime_convert('UTC', 'UTC', $rr['abook_dob']),
|
||||
'dtend' => datetime_convert('UTC', 'UTC', $rr['abook_dob'] . ' + 1 day '),
|
||||
'adjust' => intval(feature_enabled($rr['abook_channel'],'smart_birthdays')),
|
||||
'summary' => sprintf( t('%1$s\'s birthday'), $rr['xchan_name']),
|
||||
'description' => sprintf( t('Happy Birthday %1$s'), '[zrl=' . $rr['xchan_url'] . ']' . $rr['xchan_name'] . '[/zrl]'),
|
||||
'etype' => 'birthday',
|
||||
];
|
||||
|
||||
$z = event_store_event($ev);
|
||||
if ($z) {
|
||||
|
||||
+36
-50
@@ -1,15 +1,20 @@
|
||||
<?php
|
||||
/**
|
||||
* @file dba_driver.php
|
||||
* @brief Some database related functions and database classes.
|
||||
*
|
||||
* This file contains the abstract database driver class dba_driver, the
|
||||
* database class DBA and some functions for working with databases.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Database classs with database factory method.
|
||||
*
|
||||
* The factory will return a database driver which is an implementation of the
|
||||
* abstract dba_driver class.
|
||||
*/
|
||||
class DBA {
|
||||
|
||||
/**
|
||||
* @file dba_driver.php
|
||||
* @brief some database related functions and abstract driver class.
|
||||
*
|
||||
* This file contains the abstract database driver class dba_driver and some
|
||||
* functions for working with databases.
|
||||
*/
|
||||
|
||||
static public $dba = null;
|
||||
static public $dbtype = null;
|
||||
static public $scheme = 'mysql';
|
||||
@@ -21,7 +26,6 @@ class DBA {
|
||||
static public $tquot = "`";
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns the database driver object.
|
||||
*
|
||||
@@ -34,14 +38,11 @@ class DBA {
|
||||
* @param bool $install Defaults to false
|
||||
* @return null|dba_driver A database driver object (dba_pdo) or null if no driver found.
|
||||
*/
|
||||
|
||||
static public function dba_factory($server,$port,$user,$pass,$db,$dbtype,$install = false) {
|
||||
|
||||
self::$dba = null;
|
||||
|
||||
self::$dbtype = intval($dbtype);
|
||||
|
||||
|
||||
if(self::$dbtype == DBTYPE_POSTGRES) {
|
||||
if(!($port))
|
||||
$port = 5432;
|
||||
@@ -50,7 +51,6 @@ class DBA {
|
||||
self::$utc_now = "now() at time zone 'UTC'";
|
||||
self::$tquot = '"';
|
||||
self::$scheme = 'pgsql';
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -66,40 +66,27 @@ class DBA {
|
||||
|
||||
require_once('include/dba/dba_pdo.php');
|
||||
self::$dba = new dba_pdo($server,self::$scheme,$port,$user,$pass,$db,$install);
|
||||
|
||||
if(is_object(self::$dba) && self::$dba->connected) {
|
||||
|
||||
if(strpbrk($server,':;')) {
|
||||
$dsn = $server;
|
||||
}
|
||||
else {
|
||||
$dsn = self::$scheme . ':host=' . $server . (intval($port) ? '' : ';port=' . $port);
|
||||
}
|
||||
$dsn .= ';dbname=' . $db;
|
||||
|
||||
|
||||
self::$dba->pdo_set(array($dsn,$user,$pass));
|
||||
}
|
||||
|
||||
define('NULL_DATE', self::$null_date);
|
||||
define('ACTIVE_DBTYPE', self::$dbtype);
|
||||
define('TQUOT', self::$tquot);
|
||||
|
||||
return self::$dba;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief abstract database driver class.
|
||||
* @brief Abstract database driver class.
|
||||
*
|
||||
* This class gets extended by the real database driver classes, e.g. dba_mysql,
|
||||
* dba_mysqli.
|
||||
* This class gets extended by the real database driver class. We used to have
|
||||
* dba_mysql, dba_mysqli or dba_postgres, but we moved to PDO and the only
|
||||
* implemented driver is dba_pdo.
|
||||
*/
|
||||
abstract class dba_driver {
|
||||
// legacy behavior
|
||||
|
||||
public $db;
|
||||
protected $pdo = array();
|
||||
|
||||
public $debug = 0;
|
||||
public $connected = false;
|
||||
@@ -111,6 +98,7 @@ abstract class dba_driver {
|
||||
* This abstract function needs to be implemented in the real driver.
|
||||
*
|
||||
* @param string $server DB server name
|
||||
* @param string $scheme DB scheme
|
||||
* @param string $port DB port
|
||||
* @param string $user DB username
|
||||
* @param string $pass DB password
|
||||
@@ -166,6 +154,7 @@ abstract class dba_driver {
|
||||
$platform_name = \Zotlabs\Lib\System::get_platform_name();
|
||||
if(file_exists('install/' . $platform_name . '/' . \DBA::$install_script))
|
||||
return 'install/' . $platform_name . '/' . \DBA::$install_script;
|
||||
|
||||
return 'install/' . \DBA::$install_script;
|
||||
}
|
||||
|
||||
@@ -173,7 +162,6 @@ abstract class dba_driver {
|
||||
return \DBA::$tquot;
|
||||
}
|
||||
|
||||
|
||||
function utcnow() {
|
||||
return \DBA::$utc_now;
|
||||
}
|
||||
@@ -232,19 +220,12 @@ abstract class dba_driver {
|
||||
return $str;
|
||||
}
|
||||
|
||||
function pdo_set($x) {
|
||||
$this->pdo = $x;
|
||||
}
|
||||
|
||||
function pdo_get() {
|
||||
return $this->pdo;
|
||||
}
|
||||
|
||||
} // end abstract dba_driver class
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Procedural functions
|
||||
//
|
||||
|
||||
function printable($s) {
|
||||
$s = preg_replace("~([\x01-\x08\x0E-\x0F\x10-\x1F\x7F-\xFF])~",".", $s);
|
||||
@@ -275,7 +256,7 @@ function dbg($state) {
|
||||
* wrapping with intval().
|
||||
*
|
||||
* @param string $str A string to pass to a DB query
|
||||
* @return Return an escaped string of the value to pass to a DB query.
|
||||
* @return string Return an escaped string of the value to pass to a DB query.
|
||||
*/
|
||||
function dbesc($str) {
|
||||
|
||||
@@ -298,6 +279,7 @@ function dbunescbin($str) {
|
||||
function dbescdate($date) {
|
||||
if(is_null_date($date))
|
||||
return \DBA::$dba->escape(NULL_DATE);
|
||||
|
||||
return \DBA::$dba->escape($date);
|
||||
}
|
||||
|
||||
@@ -321,22 +303,26 @@ function db_concat($fld, $sep) {
|
||||
return \DBA::$dba->concat($fld, $sep);
|
||||
}
|
||||
|
||||
function db_use_index($str) {
|
||||
return \DBA::$dba->use_index($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Execute a SQL query with printf style args.
|
||||
*
|
||||
* printf style arguments %s and %d are replaced with variable arguments, which
|
||||
* should each be appropriately dbesc() or intval().
|
||||
*
|
||||
* SELECT queries return an array of results or false if SQL or DB error. Other
|
||||
* queries return true if the command was successful or false if it wasn't.
|
||||
*
|
||||
* Example:
|
||||
* $r = q("SELECT * FROM %s WHERE `uid` = %d",
|
||||
* 'user', 1);
|
||||
* @code{.php}$r = q("SELECT * FROM %s WHERE `uid` = %d",
|
||||
* 'user', 1);@endcode
|
||||
*
|
||||
* @param string $sql The SQL query to execute
|
||||
* @return bool|array
|
||||
*/
|
||||
|
||||
function q($sql) {
|
||||
|
||||
$args = func_get_args();
|
||||
@@ -355,8 +341,8 @@ function q($sql) {
|
||||
}
|
||||
|
||||
/*
|
||||
* This will happen occasionally trying to store the
|
||||
* session data after abnormal program termination
|
||||
* This will happen occasionally trying to store the
|
||||
* session data after abnormal program termination
|
||||
*/
|
||||
|
||||
db_logger('dba: no database: ' . print_r($args,true),LOGGER_NORMAL,LOG_CRIT);
|
||||
@@ -385,8 +371,8 @@ function dbq($sql) {
|
||||
|
||||
// Caller is responsible for ensuring that any integer arguments to
|
||||
// dbesc_array are actually integers and not malformed strings containing
|
||||
// SQL injection vectors. All integer array elements should be specifically
|
||||
// cast to int to avoid trouble.
|
||||
// SQL injection vectors. All integer array elements should be specifically
|
||||
// cast to int to avoid trouble.
|
||||
|
||||
function dbesc_array_cb(&$item, $key) {
|
||||
if(is_string($item)) {
|
||||
@@ -419,7 +405,7 @@ function dbesc_array(&$arr) {
|
||||
function db_getfunc($f) {
|
||||
$lookup = array(
|
||||
'rand'=>array(
|
||||
DBTYPE_MYSQL=>'RAND()',
|
||||
DBTYPE_MYSQL=>'RAND()',
|
||||
DBTYPE_POSTGRES=>'RANDOM()'
|
||||
),
|
||||
'utc_timestamp'=>array(
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once('include/dba/dba_driver.php');
|
||||
|
||||
|
||||
class dba_mysql extends dba_driver {
|
||||
|
||||
function connect($server, $scheme, $port, $user,$pass,$db) {
|
||||
$this->db = mysql_connect($server.":".$port,$user,$pass);
|
||||
if($this->db && mysql_select_db($db,$this->db)) {
|
||||
$this->connected = true;
|
||||
}
|
||||
if($this->connected) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function q($sql) {
|
||||
if((! $this->db) || (! $this->connected))
|
||||
return false;
|
||||
|
||||
$this->error = '';
|
||||
$result = @mysql_query($sql,$this->db);
|
||||
|
||||
|
||||
if(mysql_errno($this->db))
|
||||
$this->error = mysql_error($this->db);
|
||||
|
||||
if($result === false || $this->error) {
|
||||
logger('dba_mysql: ' . printable($sql) . ' returned false.' . "\n" . $this->error);
|
||||
if(file_exists('dbfail.out'))
|
||||
file_put_contents('dbfail.out', datetime_convert() . "\n" . printable($sql) . ' returned false' . "\n" . $this->error . "\n", FILE_APPEND);
|
||||
}
|
||||
|
||||
if(($result === true) || ($result === false))
|
||||
return $result;
|
||||
|
||||
$r = array();
|
||||
if(mysql_num_rows($result)) {
|
||||
while($x = mysql_fetch_array($result,MYSQL_ASSOC))
|
||||
$r[] = $x;
|
||||
mysql_free_result($result);
|
||||
if($this->debug)
|
||||
logger('dba_mysql: ' . printable(print_r($r,true)));
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function escape($str) {
|
||||
if($this->db && $this->connected) {
|
||||
return @mysql_real_escape_string($str,$this->db);
|
||||
}
|
||||
}
|
||||
|
||||
function close() {
|
||||
if($this->db)
|
||||
mysql_close($this->db);
|
||||
$this->connected = false;
|
||||
}
|
||||
|
||||
function getdriver() {
|
||||
return 'mysql';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
<?php /** @file */
|
||||
|
||||
require_once('include/dba/dba_driver.php');
|
||||
|
||||
class dba_mysqli extends dba_driver {
|
||||
|
||||
function connect($server,$scheme,$port,$user,$pass,$db) {
|
||||
if($port)
|
||||
$this->db = new mysqli($server,$user,$pass,$db, $port);
|
||||
else
|
||||
$this->db = new mysqli($server,$user,$pass,$db);
|
||||
|
||||
if($this->db->connect_error) {
|
||||
$this->connected = false;
|
||||
$this->error = $this->db->connect_error;
|
||||
|
||||
if(file_exists('dbfail.out')) {
|
||||
file_put_contents('dbfail.out', datetime_convert() . "\nConnect: " . $this->error . "\n", FILE_APPEND);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$this->connected = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function q($sql) {
|
||||
if((! $this->db) || (! $this->connected))
|
||||
return false;
|
||||
|
||||
$this->error = '';
|
||||
$result = $this->db->query($sql);
|
||||
|
||||
if($this->db->errno)
|
||||
$this->error = $this->db->error;
|
||||
|
||||
|
||||
if($this->error) {
|
||||
db_logger('dba_mysqli: ERROR: ' . printable($sql) . "\n" . $this->error, LOGGER_NORMAL, LOG_ERR);
|
||||
if(file_exists('dbfail.out')) {
|
||||
file_put_contents('dbfail.out', datetime_convert() . "\n" . printable($sql) . "\n" . $this->error . "\n", FILE_APPEND);
|
||||
}
|
||||
}
|
||||
|
||||
if(($result === true) || ($result === false)) {
|
||||
if($this->debug) {
|
||||
db_logger('dba_mysqli: DEBUG: ' . printable($sql) . ' returns ' . (($result) ? 'true' : 'false'), LOGGER_NORMAL,(($result) ? LOG_INFO : LOG_ERR));
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
if($this->debug) {
|
||||
db_logger('dba_mysqli: DEBUG: ' . printable($sql) . ' returned ' . $result->num_rows . ' results.', LOGGER_NORMAL, LOG_INFO);
|
||||
}
|
||||
|
||||
$r = array();
|
||||
if($result->num_rows) {
|
||||
while($x = $result->fetch_array(MYSQLI_ASSOC))
|
||||
$r[] = $x;
|
||||
$result->free_result();
|
||||
if($this->debug) {
|
||||
db_logger('dba_mysqli: ' . printable(print_r($r,true)), LOGGER_NORMAL, LOG_INFO);
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function escape($str) {
|
||||
if($this->db && $this->connected) {
|
||||
return @$this->db->real_escape_string($str);
|
||||
}
|
||||
}
|
||||
|
||||
function close() {
|
||||
if($this->db)
|
||||
$this->db->close();
|
||||
$this->connected = false;
|
||||
}
|
||||
|
||||
function getdriver() {
|
||||
return 'mysqli';
|
||||
}
|
||||
|
||||
}
|
||||
+41
-15
@@ -1,23 +1,30 @@
|
||||
<?php /** @file */
|
||||
<?php
|
||||
|
||||
require_once('include/dba/dba_driver.php');
|
||||
require_once 'include/dba/dba_driver.php';
|
||||
|
||||
/**
|
||||
* @brief PDO based database driver.
|
||||
*
|
||||
*/
|
||||
class dba_pdo extends dba_driver {
|
||||
|
||||
|
||||
public $driver_dbtype = null;
|
||||
|
||||
function connect($server,$scheme,$port,$user,$pass,$db) {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see dba_driver::connect()
|
||||
*/
|
||||
function connect($server, $scheme, $port, $user, $pass, $db) {
|
||||
|
||||
$this->driver_dbtype = $scheme;
|
||||
|
||||
if(strpbrk($server,':;')) {
|
||||
$dsn = $server;
|
||||
}
|
||||
else {
|
||||
$dsn = $this->driver_dbtype . ':host=' . $server . (intval($port) ? '' : ';port=' . $port);
|
||||
$dsn = $this->driver_dbtype . ':host=' . $server . (intval($port) ? ';port=' . $port : '');
|
||||
}
|
||||
|
||||
|
||||
$dsn .= ';dbname=' . $db;
|
||||
|
||||
try {
|
||||
@@ -36,10 +43,19 @@ class dba_pdo extends dba_driver {
|
||||
$this->q("SET standard_conforming_strings = 'off'; SET backslash_quote = 'on';");
|
||||
|
||||
$this->connected = true;
|
||||
return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see dba_driver::q()
|
||||
*
|
||||
* @return bool|array|PDOStatement
|
||||
* - \b false if not connected or PDOException occured on query
|
||||
* - \b array with results on a SELECT query
|
||||
* - \b PDOStatement on a non SELECT SQL query
|
||||
*/
|
||||
function q($sql) {
|
||||
if((! $this->db) || (! $this->connected))
|
||||
return false;
|
||||
@@ -50,14 +66,15 @@ class dba_pdo extends dba_driver {
|
||||
}
|
||||
}
|
||||
|
||||
$result = null;
|
||||
$this->error = '';
|
||||
$select = ((stripos($sql,'select') === 0) ? true : false);
|
||||
$select = ((stripos($sql, 'select') === 0) ? true : false);
|
||||
|
||||
try {
|
||||
$result = $this->db->query($sql, PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
|
||||
|
||||
$this->error = $e->getMessage();
|
||||
if($this->error) {
|
||||
db_logger('dba_pdo: ERROR: ' . printable($sql) . "\n" . $this->error, LOGGER_NORMAL, LOG_ERR);
|
||||
@@ -82,11 +99,10 @@ 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: DEBUG: ' . printable($sql) . ' returned ' . count($r) . ' results.', LOGGER_NORMAL, LOG_INFO);
|
||||
db_logger('dba_pdo: ' . printable(print_r($r,true)), LOGGER_NORMAL, LOG_INFO);
|
||||
}
|
||||
|
||||
|
||||
return (($this->error) ? false : $r);
|
||||
}
|
||||
|
||||
@@ -99,9 +115,10 @@ class dba_pdo extends dba_driver {
|
||||
function close() {
|
||||
if($this->db)
|
||||
$this->db = null;
|
||||
|
||||
$this->connected = false;
|
||||
}
|
||||
|
||||
|
||||
function concat($fld,$sep) {
|
||||
if($this->driver_dbtype === 'pgsql') {
|
||||
return 'string_agg(' . $fld . ',\'' . $sep . '\')';
|
||||
@@ -111,6 +128,15 @@ class dba_pdo extends dba_driver {
|
||||
}
|
||||
}
|
||||
|
||||
function use_index($str) {
|
||||
if($this->driver_dbtype === 'pgsql') {
|
||||
return '';
|
||||
}
|
||||
else {
|
||||
return 'USE INDEX( ' . $str . ')';
|
||||
}
|
||||
}
|
||||
|
||||
function quote_interval($txt) {
|
||||
if($this->driver_dbtype === 'pgsql') {
|
||||
return "'$txt'";
|
||||
@@ -131,7 +157,7 @@ class dba_pdo extends dba_driver {
|
||||
return $this->escape($str);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function unescapebin($str) {
|
||||
if($this->driver_dbtype === 'pgsql' && (! is_null($str))) {
|
||||
$x = '';
|
||||
@@ -154,4 +180,4 @@ class dba_pdo extends dba_driver {
|
||||
return 'pdo';
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once('include/dba/dba_driver.php');
|
||||
|
||||
|
||||
class dba_postgres extends dba_driver {
|
||||
const INSTALL_SCRIPT='install/schema_postgres.sql';
|
||||
const NULL_DATE = '0001-01-01 00:00:00';
|
||||
const UTC_NOW = "now() at time zone 'UTC'";
|
||||
const TQUOT = '"';
|
||||
|
||||
function connect($server,$scheme,$port,$user,$pass,$db) {
|
||||
if(!$port) $port = 5432;
|
||||
$connstr = 'host=' . $server . ' port='.$port . ' user=' . $user . ' password=' . $pass . ' dbname='. $db;
|
||||
$this->db = pg_connect($connstr);
|
||||
if($this->db !== false) {
|
||||
$this->connected = true;
|
||||
} else {
|
||||
$this->connected = false;
|
||||
}
|
||||
$this->q("SET standard_conforming_strings = 'off'; SET backslash_quote = 'on';"); // emulate mysql string escaping to prevent massive code-clobber
|
||||
return $this->connected;
|
||||
}
|
||||
|
||||
function q($sql) {
|
||||
if((! $this->db) || (! $this->connected))
|
||||
return false;
|
||||
|
||||
if(!strpos($sql, ';'))
|
||||
$sql .= ';';
|
||||
|
||||
if(strpos($sql, '`')) // this is a hack. quoted identifiers should be replaced everywhere in the code with dbesc_identifier(), remove this once it is
|
||||
$sql = str_replace('`', '"', $sql);
|
||||
|
||||
$this->error = '';
|
||||
$result = @pg_query($this->db, $sql);
|
||||
if(file_exists('db-allqueries.out')) {
|
||||
$bt = debug_backtrace();
|
||||
$trace = array();
|
||||
foreach($bt as $frame) {
|
||||
if(!empty($frame['file']) && @strstr($frame['file'], $_SERVER['DOCUMENT_ROOT']))
|
||||
$frame['file'] = substr($frame['file'], strlen($_SERVER['DOCUMENT_ROOT'])+1);
|
||||
|
||||
$trace[] = $frame['file'] . ':' . $frame['function'] . '():' . $frame['line'] ;
|
||||
}
|
||||
$compact = join(', ', $trace);
|
||||
file_put_contents('db-allqueries.out', datetime_convert() . ": " . $sql . ' is_resource: '.var_export(is_resource($result), true).', backtrace: '.$compact."\n\n", FILE_APPEND);
|
||||
}
|
||||
|
||||
if($result === false)
|
||||
$this->error = pg_last_error($this->db);
|
||||
|
||||
if($result === false || $this->error) {
|
||||
//db_logger('dba_postgres: ' . printable($sql) . ' returned false.' . "\n" . $this->error);
|
||||
if(file_exists('dbfail.out'))
|
||||
file_put_contents('dbfail.out', datetime_convert() . "\n" . printable($sql) . ' returned false' . "\n" . $this->error . "\n", FILE_APPEND);
|
||||
}
|
||||
|
||||
if(($result === true) || ($result === false))
|
||||
return $result;
|
||||
|
||||
if(pg_result_status($result) == PGSQL_COMMAND_OK)
|
||||
return true;
|
||||
|
||||
$r = array();
|
||||
if(pg_num_rows($result)) {
|
||||
while($x = pg_fetch_array($result, null, PGSQL_ASSOC))
|
||||
$r[] = $x;
|
||||
pg_free_result($result);
|
||||
if($this->debug)
|
||||
db_logger('dba_postgres: ' . printable(print_r($r,true)));
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function escape($str) {
|
||||
if($this->db && $this->connected) {
|
||||
$x = @pg_escape_string($this->db, $str);
|
||||
return $x;
|
||||
}
|
||||
}
|
||||
|
||||
function escapebin($str) {
|
||||
return pg_escape_bytea($str);
|
||||
}
|
||||
|
||||
function unescapebin($str) {
|
||||
return pg_unescape_bytea($str);
|
||||
}
|
||||
|
||||
function close() {
|
||||
if($this->db)
|
||||
pg_close($this->db);
|
||||
$this->connected = false;
|
||||
}
|
||||
|
||||
function quote_interval($txt) {
|
||||
return "'$txt'";
|
||||
}
|
||||
|
||||
function escape_identifier($str) {
|
||||
return pg_escape_identifier($this->db, $str);
|
||||
}
|
||||
|
||||
function optimize_table($table) {
|
||||
// perhaps do some equivalent thing here, vacuum, etc? I think this is the DBA's domain anyway. Applications should not need to muss with this.
|
||||
// for now do nothing without a compelling reason. function overrides default legacy mysql.
|
||||
}
|
||||
|
||||
function concat($fld, $sep) {
|
||||
return 'string_agg(' . $fld . ',\'' . $sep . '\')';
|
||||
}
|
||||
|
||||
function getdriver() {
|
||||
return 'pgsql';
|
||||
}
|
||||
}
|
||||
+10
-3
@@ -6,6 +6,8 @@
|
||||
|
||||
use Sabre\VObject;
|
||||
|
||||
require_once('include/bbcode.php');
|
||||
|
||||
/**
|
||||
* @brief Returns an event as HTML.
|
||||
*
|
||||
@@ -14,7 +16,6 @@ use Sabre\VObject;
|
||||
*/
|
||||
function format_event_html($ev) {
|
||||
|
||||
require_once('include/bbcode.php');
|
||||
|
||||
if(! ((is_array($ev)) && count($ev)))
|
||||
return '';
|
||||
@@ -192,7 +193,7 @@ function format_todo_ical($ev) {
|
||||
|
||||
|
||||
function format_ical_text($s) {
|
||||
require_once('include/bbcode.php');
|
||||
|
||||
require_once('include/html2plain.php');
|
||||
|
||||
$s = html2plain(bbcode($s));
|
||||
@@ -983,7 +984,6 @@ function event_store_item($arr, $event) {
|
||||
|
||||
require_once('include/datetime.php');
|
||||
require_once('include/items.php');
|
||||
require_once('include/bbcode.php');
|
||||
|
||||
$item = null;
|
||||
|
||||
@@ -1200,6 +1200,13 @@ function event_store_item($arr, $event) {
|
||||
));
|
||||
}
|
||||
|
||||
// propagate the event resource_id so that posts containing it are easily searchable in downstream copies
|
||||
// of the item which have not stored the actual event. Required for Diaspora event federation as Diaspora
|
||||
// event_participation messages refer to the event resource_id as a parent, while out own event attendance
|
||||
// activities refer to the item message_id as the parent.
|
||||
|
||||
set_iconfig($item_arr, 'system','event_id',$event['event_hash'],true);
|
||||
|
||||
$res = item_store($item_arr);
|
||||
|
||||
$item_id = $res['item_id'];
|
||||
|
||||
+68
-45
@@ -54,14 +54,6 @@ function get_features($filtered = true) {
|
||||
t('General Features'),
|
||||
|
||||
|
||||
[
|
||||
'multi_profiles',
|
||||
t('Multiple Profiles'),
|
||||
t('Ability to create multiple profiles'),
|
||||
false,
|
||||
get_config('feature_lock','multi_profiles'),
|
||||
feature_level('multi_profiles',3),
|
||||
],
|
||||
|
||||
[
|
||||
'advanced_profiles',
|
||||
@@ -126,7 +118,7 @@ function get_features($filtered = true) {
|
||||
feature_level('cards',1),
|
||||
],
|
||||
|
||||
/* reserved, work in progress
|
||||
|
||||
[
|
||||
'articles',
|
||||
t('Articles'),
|
||||
@@ -135,7 +127,7 @@ function get_features($filtered = true) {
|
||||
get_config('feature_lock','articles'),
|
||||
feature_level('articles',1),
|
||||
],
|
||||
*/
|
||||
|
||||
[
|
||||
'nav_channel_select',
|
||||
t('Navigation Channel Select'),
|
||||
@@ -163,14 +155,6 @@ function get_features($filtered = true) {
|
||||
feature_level('ajaxchat',1),
|
||||
],
|
||||
|
||||
[
|
||||
'permcats',
|
||||
t('Permission Groups'),
|
||||
t('Provide alternate connection permission roles.'),
|
||||
false,
|
||||
get_config('feature_lock','permcats'),
|
||||
feature_level('permcats',2),
|
||||
],
|
||||
|
||||
[
|
||||
'smart_birthdays',
|
||||
@@ -190,6 +174,16 @@ function get_features($filtered = true) {
|
||||
feature_level('event_tz_select',2),
|
||||
],
|
||||
|
||||
|
||||
[
|
||||
'premium_channel',
|
||||
t('Premium Channel'),
|
||||
t('Allows you to set restrictions and terms on those that connect with your channel'),
|
||||
false,
|
||||
get_config('feature_lock','premium_channel'),
|
||||
feature_level('premium_channel',4),
|
||||
],
|
||||
|
||||
[
|
||||
'advanced_dirsearch',
|
||||
t('Advanced Directory Search'),
|
||||
@@ -209,6 +203,58 @@ function get_features($filtered = true) {
|
||||
],
|
||||
],
|
||||
|
||||
|
||||
'access_control' => [
|
||||
t('Access Control and Permissions'),
|
||||
|
||||
[
|
||||
'groups',
|
||||
t('Privacy Groups'),
|
||||
t('Enable management and selection of privacy groups'),
|
||||
true,
|
||||
get_config('feature_lock','groups'),
|
||||
feature_level('groups',0),
|
||||
],
|
||||
|
||||
[
|
||||
'multi_profiles',
|
||||
t('Multiple Profiles'),
|
||||
t('Ability to create multiple profiles'),
|
||||
false,
|
||||
get_config('feature_lock','multi_profiles'),
|
||||
feature_level('multi_profiles',3),
|
||||
],
|
||||
|
||||
|
||||
[
|
||||
'permcats',
|
||||
t('Permission Groups'),
|
||||
t('Provide alternate connection permission roles.'),
|
||||
false,
|
||||
get_config('feature_lock','permcats'),
|
||||
feature_level('permcats',2),
|
||||
],
|
||||
|
||||
[
|
||||
'oauth_clients',
|
||||
t('OAuth Clients'),
|
||||
t('Manage authenticatication tokens for mobile and remote apps.'),
|
||||
false,
|
||||
get_config('feature_lock','oauth_clients'),
|
||||
feature_level('oauth_clients',1),
|
||||
],
|
||||
|
||||
[
|
||||
'access_tokens',
|
||||
t('Access Tokens'),
|
||||
t('Create access tokens so that non-members can access private content.'),
|
||||
false,
|
||||
get_config('feature_lock','access_tokens'),
|
||||
feature_level('access_tokens',2),
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
// Post composition
|
||||
'composition' => [
|
||||
|
||||
@@ -302,14 +348,6 @@ function get_features($filtered = true) {
|
||||
feature_level('archives',1),
|
||||
],
|
||||
|
||||
[
|
||||
'groups',
|
||||
t('Privacy Groups'),
|
||||
t('Enable management and selection of privacy groups'),
|
||||
true,
|
||||
get_config('feature_lock','groups'),
|
||||
feature_level('groups',0),
|
||||
],
|
||||
|
||||
[
|
||||
'savedsearch',
|
||||
@@ -373,15 +411,6 @@ function get_features($filtered = true) {
|
||||
|
||||
t('Post/Comment Tools'),
|
||||
|
||||
[
|
||||
'markdown',
|
||||
t('Markdown'),
|
||||
t('Use markdown for editing posts'),
|
||||
false,
|
||||
get_config('feature_lock','markdown'),
|
||||
feature_level('markdown',2),
|
||||
],
|
||||
|
||||
[
|
||||
'commtag',
|
||||
t('Community Tagging'),
|
||||
@@ -447,16 +476,10 @@ function get_features($filtered = true) {
|
||||
],
|
||||
];
|
||||
|
||||
$x = [ 'features' => $arr, ];
|
||||
call_hooks('get_features',$x);
|
||||
|
||||
$arr['general'][] = [
|
||||
'premium_channel',
|
||||
t('Premium Channel'),
|
||||
t('Allows you to set restrictions and terms on those that connect with your channel'),
|
||||
false,
|
||||
get_config('feature_lock','premium_channel'),
|
||||
feature_level('premium_channel',4),
|
||||
];
|
||||
|
||||
$arr = $x['features'];
|
||||
|
||||
$techlevel = get_account_techlevel();
|
||||
|
||||
@@ -490,6 +513,6 @@ function get_features($filtered = true) {
|
||||
else {
|
||||
$narr = $arr;
|
||||
}
|
||||
call_hooks('get_features',$narr);
|
||||
|
||||
return $narr;
|
||||
}
|
||||
|
||||
+179
-132
@@ -15,15 +15,6 @@
|
||||
*/
|
||||
function get_public_feed($channel, $params) {
|
||||
|
||||
/* $type = 'xml';
|
||||
$begin = NULL_DATE;
|
||||
$end = '';
|
||||
$start = 0;
|
||||
$records = 40;
|
||||
$direction = 'desc';
|
||||
$pages = 0;
|
||||
*/
|
||||
|
||||
if(! $params)
|
||||
$params = [];
|
||||
|
||||
@@ -106,23 +97,15 @@ function get_feed_for($channel, $observer_hash, $params) {
|
||||
$owner = atom_render_author('zot:owner',$channel);
|
||||
|
||||
$atom .= replace_macros($feed_template, array(
|
||||
'$version' => xmlify(Zotlabs\Lib\System::get_project_version()),
|
||||
'$red' => xmlify(Zotlabs\Lib\System::get_platform_name()),
|
||||
'$feed_id' => xmlify($channel['xchan_url']),
|
||||
'$feed_title' => xmlify($channel['channel_name']),
|
||||
'$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', 'now', ATOM_TIME)),
|
||||
'$author' => $feed_author,
|
||||
'$owner' => $owner,
|
||||
'$name' => xmlify($channel['channel_name']),
|
||||
'$profile_page' => xmlify($channel['xchan_url']),
|
||||
'$mimephoto' => xmlify($channel['xchan_photo_mimetype']),
|
||||
'$photo' => xmlify($channel['xchan_photo_l']),
|
||||
'$thumb' => xmlify($channel['xchan_photo_m']),
|
||||
'$picdate' => '',
|
||||
'$uridate' => '',
|
||||
'$namdate' => '',
|
||||
'$birthday' => '',
|
||||
'$community' => '',
|
||||
'$version' => xmlify(Zotlabs\Lib\System::get_project_version()),
|
||||
'$generator' => xmlify(Zotlabs\Lib\System::get_platform_name()),
|
||||
'$generator_uri' => 'https://hubzilla.org',
|
||||
'$feed_id' => xmlify($channel['xchan_url']),
|
||||
'$feed_title' => xmlify($channel['channel_name']),
|
||||
'$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', 'now', ATOM_TIME)),
|
||||
'$author' => $feed_author,
|
||||
'$owner' => $owner,
|
||||
'$profile_page' => xmlify($channel['xchan_url']),
|
||||
));
|
||||
|
||||
|
||||
@@ -270,19 +253,18 @@ function construct_activity_target($item) {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return an array with a parsed atom item.
|
||||
* @brief Return an array with a parsed atom author.
|
||||
*
|
||||
* @param SimplePie $feed
|
||||
* @param array $item
|
||||
* @param[out] array $author
|
||||
* @return array Associative array with the parsed item data
|
||||
* @param SimplePie $item
|
||||
* @return array $author
|
||||
*/
|
||||
function get_atom_elements($feed, $item, &$author) {
|
||||
|
||||
require_once('include/html2bbcode.php');
|
||||
function get_atom_author($feed, $item) {
|
||||
|
||||
$res = array();
|
||||
$author = [];
|
||||
|
||||
$found_author = $item->get_author();
|
||||
if($found_author) {
|
||||
@@ -307,52 +289,6 @@ function get_atom_elements($feed, $item, &$author) {
|
||||
if(substr($author['author_link'],-1,1) == '/')
|
||||
$author['author_link'] = substr($author['author_link'],0,-1);
|
||||
|
||||
$res['mid'] = normalise_id(unxmlify($item->get_id()));
|
||||
$res['title'] = unxmlify($item->get_title());
|
||||
$res['body'] = unxmlify($item->get_content());
|
||||
$res['plink'] = unxmlify($item->get_link(0));
|
||||
$res['item_rss'] = 1;
|
||||
|
||||
|
||||
$summary = unxmlify($item->get_description(true));
|
||||
|
||||
// removing the content of the title if its identically to the body
|
||||
// This helps with auto generated titles e.g. from tumblr
|
||||
|
||||
if (title_is_body($res['title'], $res['body']))
|
||||
$res['title'] = "";
|
||||
|
||||
if($res['plink'])
|
||||
$base_url = implode('/', array_slice(explode('/',$res['plink']),0,3));
|
||||
else
|
||||
$base_url = '';
|
||||
|
||||
|
||||
$rawcreated = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published');
|
||||
if($rawcreated)
|
||||
$res['created'] = unxmlify($rawcreated[0]['data']);
|
||||
|
||||
$rawedited = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated');
|
||||
if($rawedited)
|
||||
$res['edited'] = unxmlify($rawedited[0]['data']);
|
||||
|
||||
if((x($res,'edited')) && (! (x($res,'created'))))
|
||||
$res['created'] = $res['edited'];
|
||||
|
||||
if(! $res['created'])
|
||||
$res['created'] = $item->get_date('c');
|
||||
|
||||
if(! $res['edited'])
|
||||
$res['edited'] = $item->get_date('c');
|
||||
|
||||
$rawverb = $item->get_item_tags(NAMESPACE_ACTIVITY, 'verb');
|
||||
|
||||
// select between supported verbs
|
||||
|
||||
if($rawverb) {
|
||||
$res['verb'] = unxmlify($rawverb[0]['data']);
|
||||
}
|
||||
|
||||
|
||||
// look for a photo. We should check media size and find the best one,
|
||||
// but for now let's just find any author photo
|
||||
@@ -431,6 +367,122 @@ function get_atom_elements($feed, $item, &$author) {
|
||||
}
|
||||
}
|
||||
|
||||
$rawowner = $item->get_item_tags(NAMESPACE_DFRN, 'owner');
|
||||
if(! $rawowner)
|
||||
$rawowner = $item->get_item_tags(NAMESPACE_ZOT, 'owner');
|
||||
|
||||
if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])
|
||||
$author['owner_name'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']);
|
||||
elseif($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data'])
|
||||
$author['owner_name'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data']);
|
||||
if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])
|
||||
$author['owner_link'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']);
|
||||
elseif($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data'])
|
||||
$author['owner_link'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data']);
|
||||
|
||||
if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
|
||||
$base = $rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
|
||||
|
||||
foreach($base as $link) {
|
||||
if(!x($author, 'owner_photo') || ! $author['owner_photo']) {
|
||||
if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar')
|
||||
$author['owner_photo'] = unxmlify($link['attribs']['']['href']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// build array to pass to hook
|
||||
$arr = [
|
||||
'feed' => $feed,
|
||||
'item' => $item,
|
||||
'author' => $author
|
||||
];
|
||||
/**
|
||||
* @hooks parse_atom
|
||||
* * \e SimplePie \b feed - The original SimplePie feed
|
||||
* * \e SimplePie \b item
|
||||
* * \e array \b result - the result array that will also get returned
|
||||
*/
|
||||
call_hooks('parse_atom_author', $arr);
|
||||
|
||||
logger('author: ' . print_r($arr['author'], true), LOGGER_DATA);
|
||||
|
||||
return $arr['author'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return an array with a parsed atom item.
|
||||
*
|
||||
* @param SimplePie $feed
|
||||
* @param SimplePie $item
|
||||
* @param[out] array $author
|
||||
* @return array Associative array with the parsed item data
|
||||
*/
|
||||
|
||||
function get_atom_elements($feed, $item) {
|
||||
|
||||
require_once('include/html2bbcode.php');
|
||||
|
||||
$res = array();
|
||||
|
||||
|
||||
$res['mid'] = normalise_id(unxmlify($item->get_id()));
|
||||
$res['title'] = unxmlify($item->get_title());
|
||||
$res['body'] = unxmlify($item->get_content());
|
||||
$res['plink'] = unxmlify($item->get_link(0));
|
||||
$res['item_rss'] = 1;
|
||||
|
||||
|
||||
$summary = unxmlify($item->get_description(true));
|
||||
|
||||
if($summary === $res['body'])
|
||||
$summary = '';
|
||||
|
||||
if(($summary) && ((strpos($summary,'<') !== false) || (strpos($summary,'>') !== false))) {
|
||||
$summary = purify_html($summary);
|
||||
$summary = html2bbcode($summary);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// removing the content of the title if its identically to the body
|
||||
// This helps with auto generated titles e.g. from tumblr
|
||||
|
||||
if (title_is_body($res['title'], $res['body']))
|
||||
$res['title'] = "";
|
||||
|
||||
if($res['plink'])
|
||||
$base_url = implode('/', array_slice(explode('/',$res['plink']),0,3));
|
||||
else
|
||||
$base_url = '';
|
||||
|
||||
|
||||
$rawcreated = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published');
|
||||
if($rawcreated)
|
||||
$res['created'] = unxmlify($rawcreated[0]['data']);
|
||||
|
||||
$rawedited = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated');
|
||||
if($rawedited)
|
||||
$res['edited'] = unxmlify($rawedited[0]['data']);
|
||||
|
||||
if((x($res,'edited')) && (! (x($res,'created'))))
|
||||
$res['created'] = $res['edited'];
|
||||
|
||||
if(! $res['created'])
|
||||
$res['created'] = $item->get_date('c');
|
||||
|
||||
if(! $res['edited'])
|
||||
$res['edited'] = $item->get_date('c');
|
||||
|
||||
$rawverb = $item->get_item_tags(NAMESPACE_ACTIVITY, 'verb');
|
||||
|
||||
// select between supported verbs
|
||||
|
||||
if($rawverb) {
|
||||
$res['verb'] = unxmlify($rawverb[0]['data']);
|
||||
}
|
||||
|
||||
$rawcnv = $item->get_item_tags(NAMESPACE_OSTATUS, 'conversation');
|
||||
if($rawcnv) {
|
||||
// new style
|
||||
@@ -445,7 +497,7 @@ function get_atom_elements($feed, $item, &$author) {
|
||||
}
|
||||
}
|
||||
|
||||
$ostatus_protocol = (($ostatus_conversation) ? true : false);
|
||||
$ostatus_protocol = (($ostatus_conversation || $res['verb']) ? true : false);
|
||||
|
||||
$mastodon = (($item->get_item_tags('http://mastodon.social/schema/1.0','scope')) ? true : false);
|
||||
if($mastodon) {
|
||||
@@ -454,6 +506,8 @@ function get_atom_elements($feed, $item, &$author) {
|
||||
$res['item_private'] = 1;
|
||||
}
|
||||
|
||||
logger('ostatus_protocol: ' . intval($ostatus_protocol), LOGGER_DEBUG);
|
||||
|
||||
$apps = $item->get_item_tags(NAMESPACE_STATUSNET, 'notice_info');
|
||||
if($apps && $apps[0]['attribs']['']['source']) {
|
||||
$res['app'] = strip_tags(unxmlify($apps[0]['attribs']['']['source']));
|
||||
@@ -557,9 +611,8 @@ function get_atom_elements($feed, $item, &$author) {
|
||||
);
|
||||
}
|
||||
|
||||
// turn Mastodon content warning into a #nsfw hashtag
|
||||
if($mastodon && $summary) {
|
||||
$res['body'] = $summary . "\n\n" . $res['body'] . "\n\n#ContentWarning\n";
|
||||
if($summary && $res['body']) {
|
||||
$res['body'] = '[summary]' . $summary . '[/summary]' . $res['body'];
|
||||
}
|
||||
|
||||
|
||||
@@ -588,29 +641,6 @@ function get_atom_elements($feed, $item, &$author) {
|
||||
$res['created'] = datetime_convert('UTC','UTC',$res['created']);
|
||||
$res['edited'] = datetime_convert('UTC','UTC',$res['edited']);
|
||||
|
||||
$rawowner = $item->get_item_tags(NAMESPACE_DFRN, 'owner');
|
||||
if(! $rawowner)
|
||||
$rawowner = $item->get_item_tags(NAMESPACE_ZOT, 'owner');
|
||||
|
||||
if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])
|
||||
$author['owner_name'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']);
|
||||
elseif($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data'])
|
||||
$author['owner_name'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data']);
|
||||
if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])
|
||||
$author['owner_link'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']);
|
||||
elseif($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data'])
|
||||
$author['owner_link'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data']);
|
||||
|
||||
if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
|
||||
$base = $rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
|
||||
|
||||
foreach($base as $link) {
|
||||
if(!x($author, 'owner_photo') || ! $author['owner_photo']) {
|
||||
if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar')
|
||||
$author['owner_photo'] = unxmlify($link['attribs']['']['href']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$rawgeo = $item->get_item_tags(NAMESPACE_GEORSS, 'point');
|
||||
if($rawgeo)
|
||||
@@ -773,20 +803,17 @@ function get_atom_elements($feed, $item, &$author) {
|
||||
$arr = [
|
||||
'feed' => $feed,
|
||||
'item' => $item,
|
||||
'author' => $author,
|
||||
'result' => $res
|
||||
];
|
||||
/**
|
||||
* @hooks parse_atom
|
||||
* * \e SimplePie \b feed - The original SimplePie feed
|
||||
* * \e array \b item
|
||||
* * \e array \b author
|
||||
* * \e SimplePie \b item
|
||||
* * \e array \b result - the result array that will also get returned
|
||||
*/
|
||||
call_hooks('parse_atom', $arr);
|
||||
|
||||
logger('author: ' .print_r($arr['author'], true), LOGGER_DATA);
|
||||
logger('result: ' .print_r($arr['result'], true), LOGGER_DATA);
|
||||
logger('result: ' . print_r($arr['result'], true), LOGGER_DATA);
|
||||
|
||||
return $arr['result'];
|
||||
}
|
||||
@@ -985,9 +1012,9 @@ function process_feed_tombstones($feed,$importer,$contact,$pass) {
|
||||
* @param string $xml
|
||||
* The (atom) feed to consume - RSS isn't as fully supported but may work for simple feeds.
|
||||
* @param array $importer
|
||||
* The contact_record (joined to user_record) of the local user who owns this
|
||||
* The channel record of the local user who owns this
|
||||
* relationship. It is this person's stuff that is going to be updated.
|
||||
* @param[in,out] array $contact
|
||||
* @param[in,out] array $contact (abook record joined to xchan record)
|
||||
* The person who is sending us stuff. If not set, we MAY be processing a "follow" activity
|
||||
* from an external network and MAY create an appropriate contact record. Otherwise, we MUST
|
||||
* have a contact record.
|
||||
@@ -1074,8 +1101,8 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
|
||||
|
||||
// Have we seen it? If not, import it.
|
||||
|
||||
$author = array();
|
||||
$datarray = get_atom_elements($feed,$item,$author);
|
||||
$author = get_atom_author($feed,$item);
|
||||
$datarray = get_atom_elements($feed,$item);
|
||||
|
||||
if(! $datarray['mid'])
|
||||
continue;
|
||||
@@ -1327,8 +1354,8 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
|
||||
|
||||
// Head post of a conversation. Have we seen it? If not, import it.
|
||||
|
||||
$author = array();
|
||||
$datarray = get_atom_elements($feed,$item,$author);
|
||||
$author = get_atom_author($feed,$item);
|
||||
$datarray = get_atom_elements($feed,$item);
|
||||
|
||||
if(! $datarray['mid'])
|
||||
continue;
|
||||
@@ -1530,11 +1557,11 @@ function normalise_id($id) {
|
||||
*/
|
||||
function process_salmon_feed($xml, $importer) {
|
||||
|
||||
$ret = array();
|
||||
$ret = [];
|
||||
|
||||
if(! strlen($xml)) {
|
||||
logger('process_feed: empty input');
|
||||
return;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
$feed = new SimplePie();
|
||||
@@ -1548,8 +1575,10 @@ function process_salmon_feed($xml, $importer) {
|
||||
|
||||
$feed->init();
|
||||
|
||||
if($feed->error())
|
||||
if($feed->error()) {
|
||||
logger('Error parsing XML: ' . $feed->error());
|
||||
return $ret;
|
||||
}
|
||||
|
||||
$permalink = $feed->get_permalink();
|
||||
|
||||
@@ -1576,16 +1605,13 @@ function process_salmon_feed($xml, $importer) {
|
||||
if($is_reply)
|
||||
$ret['parent_mid'] = $parent_mid;
|
||||
|
||||
$ret['author'] = array();
|
||||
|
||||
$datarray = get_atom_elements($feed, $item, $ret['author']);
|
||||
$ret['author'] = get_atom_author($feed,$item);
|
||||
$ret['item'] = get_atom_elements($feed,$item);
|
||||
|
||||
// reset policies which are restricted by default for RSS connections
|
||||
// This item is likely coming from GNU-social via salmon and allows public interaction
|
||||
$datarray['public_policy'] = '';
|
||||
$datarray['comment_policy'] = 'authenticated';
|
||||
|
||||
$ret['item'] = $datarray;
|
||||
$ret['item']['public_policy'] = '';
|
||||
$ret['item']['comment_policy'] = 'authenticated';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1801,12 +1827,17 @@ function compat_photos_list($s) {
|
||||
|
||||
if($found) {
|
||||
foreach($matches as $match) {
|
||||
$ret[] = [
|
||||
$entry = [
|
||||
'href' => $match[2],
|
||||
'length' => 0,
|
||||
'type' => guess_image_type($match[2])
|
||||
];
|
||||
$sizer = new \Zotlabs\Lib\Img_filesize($match[2]);
|
||||
$size = $sizer->getSize();
|
||||
if(intval($size)) {
|
||||
$entry['length'] = intval($size);
|
||||
}
|
||||
|
||||
$ret[] = $entry;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1838,10 +1869,24 @@ function atom_entry($item, $type, $author, $owner, $comment = false, $cid = 0, $
|
||||
|
||||
create_export_photo_body($item);
|
||||
|
||||
if($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid'])
|
||||
$body = fix_private_photos($item['body'],$owner['uid'],$item,$cid);
|
||||
// provide separate summary and content unless compat is true; as summary represents a content-warning on some networks
|
||||
|
||||
$matches = false;
|
||||
if(preg_match('|\[summary\](.*?)\[/summary\]|ism',$item['body'],$matches))
|
||||
$summary = $matches[1];
|
||||
else
|
||||
$body = $item['body'];
|
||||
$summary = '';
|
||||
|
||||
$body = $item['body'];
|
||||
|
||||
if($summary)
|
||||
$body = preg_replace('|^(.*?)\[summary\](.*?)\[/summary\](.*?)$|ism','$1$3',$item['body']);
|
||||
|
||||
if($compat)
|
||||
$summary = '';
|
||||
|
||||
if($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid'])
|
||||
$body = fix_private_photos($body,$owner['uid'],$item,$cid);
|
||||
|
||||
if($compat) {
|
||||
$compat_photos = compat_photos_list($body);
|
||||
@@ -1882,6 +1927,8 @@ function atom_entry($item, $type, $author, $owner, $comment = false, $cid = 0, $
|
||||
}
|
||||
else {
|
||||
$o .= '<title>' . xmlify($item['title']) . '</title>' . "\r\n";
|
||||
if($summary)
|
||||
$o .= '<summary type="' . $type . '" >' . xmlify(prepare_text($summary,$item['mimetype'])) . '</summary>' . "\r\n";
|
||||
$o .= '<content type="' . $type . '" >' . xmlify(prepare_text($body,$item['mimetype'])) . '</content>' . "\r\n";
|
||||
}
|
||||
|
||||
|
||||
@@ -188,13 +188,14 @@ function html2bbcode($message)
|
||||
|
||||
node2bbcode($doc, 'hr', array(), "[hr]", "");
|
||||
|
||||
node2bbcode($doc, 'table', array(), "", "");
|
||||
node2bbcode($doc, 'tr', array(), "\n", "");
|
||||
node2bbcode($doc, 'td', array(), "\t", "");
|
||||
//node2bbcode($doc, 'table', array(), "[table]", "[/table]");
|
||||
//node2bbcode($doc, 'th', array(), "[th]", "[/th]");
|
||||
//node2bbcode($doc, 'tr', array(), "[tr]", "[/tr]");
|
||||
//node2bbcode($doc, 'td', array(), "[td]", "[/td]");
|
||||
// node2bbcode($doc, 'table', array(), "", "");
|
||||
// node2bbcode($doc, 'tr', array(), "\n", "");
|
||||
// node2bbcode($doc, 'td', array(), "\t", "");
|
||||
|
||||
node2bbcode($doc, 'table', array(), "[table]", "[/table]");
|
||||
node2bbcode($doc, 'th', array(), "[th]", "[/th]");
|
||||
node2bbcode($doc, 'tr', array(), "[tr]", "[/tr]");
|
||||
node2bbcode($doc, 'td', array(), "[td]", "[/td]");
|
||||
|
||||
node2bbcode($doc, 'h1', array(), "\n\n[h1]", "[/h1]\n");
|
||||
node2bbcode($doc, 'h2', array(), "\n\n[h2]", "[/h2]\n");
|
||||
@@ -211,7 +212,7 @@ function html2bbcode($message)
|
||||
|
||||
node2bbcode($doc, 'video', array('src'=>'/(.+)/'), '[video]$1', '[/video]');
|
||||
node2bbcode($doc, 'audio', array('src'=>'/(.+)/'), '[audio]$1', '[/audio]');
|
||||
node2bbcode($doc, 'iframe', array('src'=>'/(.+)/'), '[iframe]$1', '[/iframe]');
|
||||
// node2bbcode($doc, 'iframe', array('src'=>'/(.+)/'), '[iframe]$1', '[/iframe]');
|
||||
|
||||
node2bbcode($doc, 'code', array(), '[code]', '[/code]');
|
||||
|
||||
|
||||
@@ -257,6 +257,24 @@ function hubloc_mark_as_down($posturl) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief return comma separated string of non-dead clone locations (net addresses) for a given netid
|
||||
*
|
||||
* @param string $netid network identity (typically xchan_hash or hubloc_hash)
|
||||
* @return string
|
||||
*/
|
||||
|
||||
function locations_by_netid($netid) {
|
||||
|
||||
$locs = q("select hubloc_addr as location from hubloc left join site on hubloc_url = site_url where hubloc_hash = '%s' and hubloc_deleted = 0 and site_dead = 0",
|
||||
dbesc($netid)
|
||||
);
|
||||
|
||||
return array_elm_to_str($locs,'location',', ');
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function ping_site($url) {
|
||||
|
||||
|
||||
+3
-2
@@ -82,7 +82,8 @@ function import_channel($channel, $account_id, $seize) {
|
||||
'channel_r_storage', 'channel_r_pages', 'channel_w_stream', 'channel_w_wall',
|
||||
'channel_w_comment', 'channel_w_mail', 'channel_w_like', 'channel_w_tagwall',
|
||||
'channel_w_chat', 'channel_w_storage', 'channel_w_pages', 'channel_a_republish',
|
||||
'channel_a_delegate', 'perm_limits', 'channel_password', 'channel_salt'
|
||||
'channel_a_delegate', 'perm_limits', 'channel_password', 'channel_salt',
|
||||
'channel_moved'
|
||||
];
|
||||
|
||||
$clean = array();
|
||||
@@ -185,7 +186,7 @@ function import_profiles($channel, $profiles) {
|
||||
*
|
||||
* @param array $channel
|
||||
* @param array $hublocs
|
||||
* @param unknown $seize
|
||||
* @param boolean $seize
|
||||
* @param boolean $moving (optional) default false
|
||||
*/
|
||||
function import_hublocs($channel, $hublocs, $seize, $moving = false) {
|
||||
|
||||
+53
-17
@@ -390,7 +390,7 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) {
|
||||
$arr['comment_policy'] = map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'post_comments'));
|
||||
|
||||
if ((! $arr['plink']) && (intval($arr['item_thread_top']))) {
|
||||
$arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . urlencode($arr['mid']);
|
||||
$arr['plink'] = substr(z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . urlencode($arr['mid']),0,190);
|
||||
}
|
||||
|
||||
|
||||
@@ -1412,6 +1412,13 @@ function get_mail_elements($x) {
|
||||
}
|
||||
else {
|
||||
$arr['body'] = (($x['body']) ? htmlspecialchars($x['body'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
|
||||
$maxlen = get_max_import_size();
|
||||
|
||||
if($maxlen && mb_strlen($arr['body']) > $maxlen) {
|
||||
$arr['body'] = mb_substr($arr['body'],0,$maxlen,'UTF-8');
|
||||
logger('message length exceeds max_import_size: truncated');
|
||||
}
|
||||
}
|
||||
|
||||
$arr['title'] = (($x['title'])? htmlspecialchars($x['title'],ENT_COMPAT,'UTF-8',false) : '');
|
||||
@@ -2327,6 +2334,16 @@ function send_status_notifications($post_id,$item) {
|
||||
|
||||
$parent = 0;
|
||||
|
||||
if(array_key_exists('verb',$item) && (activity_match($item['verb'], ACTIVITY_LIKE) || activity_match($item['verb'], ACTIVITY_DISLIKE))) {
|
||||
|
||||
$r = q("select id from item where mid = '%s' and uid = %d limit 1",
|
||||
dbesc($item['thr_parent']),
|
||||
intval($item['uid'])
|
||||
);
|
||||
|
||||
$thr_parent_id = $r[0]['id'];
|
||||
}
|
||||
|
||||
$r = q("select channel_hash from channel where channel_id = %d limit 1",
|
||||
intval($item['uid'])
|
||||
);
|
||||
@@ -2392,10 +2409,10 @@ function send_status_notifications($post_id,$item) {
|
||||
'to_xchan' => $r[0]['channel_hash'],
|
||||
'item' => $item,
|
||||
'link' => $link,
|
||||
'verb' => ACTIVITY_POST,
|
||||
'verb' => $item['verb'],
|
||||
'otype' => 'item',
|
||||
'parent' => $parent,
|
||||
'parent_mid' => $item['parent_mid']
|
||||
'parent' => $thr_parent_id ? $thr_parent_id : $parent,
|
||||
'parent_mid' => $thr_parent_id ? $item['thr_parent'] : $item['parent_mid']
|
||||
));
|
||||
}
|
||||
|
||||
@@ -2454,7 +2471,7 @@ function tag_deliver($uid, $item_id) {
|
||||
// this is an update (edit) to a post which was already processed by us and has a second delivery chain
|
||||
// Just start the second delivery chain to deliver the updated post
|
||||
// after resetting ownership and permission bits
|
||||
|
||||
logger('updating edited tag_deliver post for ' . $u[0]['channel_address']);
|
||||
start_delivery_chain($u[0], $item, $item_id, 0);
|
||||
return;
|
||||
}
|
||||
@@ -2757,6 +2774,16 @@ function tgroup_check($uid, $item) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// see if we already have this item. Maybe it is being updated.
|
||||
|
||||
$r = q("select id from item where mid = '%s' and uid = %d limit 1",
|
||||
dbesc($item['mid']),
|
||||
intval($uid)
|
||||
);
|
||||
if($r)
|
||||
return true;
|
||||
|
||||
if(! perm_is_allowed($uid,$item['author_xchan'],'tag_deliver'))
|
||||
return false;
|
||||
|
||||
@@ -3009,14 +3036,17 @@ function check_item_source($uid, $item) {
|
||||
$words = explode("\n",$r[0]['src_patt']);
|
||||
if($words) {
|
||||
foreach($words as $word) {
|
||||
if(substr($word,0,1) === '#' && $tags) {
|
||||
$w = trim($word);
|
||||
if(! $w)
|
||||
continue;
|
||||
if(substr($w,0,1) === '#' && $tags) {
|
||||
foreach($tags as $t)
|
||||
if((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
|
||||
if((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($w,1)) || (substr($w,1) === '*')))
|
||||
return true;
|
||||
}
|
||||
elseif((strpos($word,'/') === 0) && preg_match($word,$text))
|
||||
elseif((strpos($w,'/') === 0) && preg_match($w,$text))
|
||||
return true;
|
||||
elseif(stristr($text,$word) !== false)
|
||||
elseif(stristr($text,$w) !== false)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -3650,7 +3680,7 @@ function delete_item_lowlevel($item, $stage = DROPITEM_NORMAL, $force = false) {
|
||||
|
||||
$linked_item = (($item['resource_id']) ? true : false);
|
||||
|
||||
logger('item: ' . $item . ' stage: ' . $stage . ' force: ' . $force, LOGGER_DATA);
|
||||
logger('item: ' . $item['id'] . ' stage: ' . $stage . ' force: ' . $force, LOGGER_DATA);
|
||||
|
||||
switch($stage) {
|
||||
case DROPITEM_PHASE2:
|
||||
@@ -3990,18 +4020,24 @@ function zot_feed($uid, $observer_hash, $arr) {
|
||||
$item_normal = item_normal();
|
||||
|
||||
if(is_sys_channel($uid)) {
|
||||
$r = q("SELECT parent, created, postopts from item
|
||||
WHERE uid != %d
|
||||
$item_normal
|
||||
|
||||
$nonsys_uids = q("SELECT channel_id FROM channel WHERE channel_system = 0");
|
||||
$nonsys_uids_str = ids_to_querystr($nonsys_uids,'channel_id');
|
||||
|
||||
$r = q("SELECT parent, postopts FROM item
|
||||
WHERE uid IN ( %s )
|
||||
AND item_wall = 1
|
||||
and item_private = 0 $sql_extra ORDER BY created ASC $limit",
|
||||
intval($uid)
|
||||
AND item_private = 0
|
||||
$item_normal
|
||||
$sql_extra ORDER BY created ASC $limit",
|
||||
intval($nonsys_uids_str)
|
||||
);
|
||||
}
|
||||
else {
|
||||
$r = q("SELECT parent, created, postopts from item
|
||||
WHERE uid = %d $item_normal
|
||||
$r = q("SELECT parent, postopts FROM item
|
||||
WHERE uid = %d
|
||||
AND item_wall = 1
|
||||
$item_normal
|
||||
$sql_extra ORDER BY created ASC $limit",
|
||||
intval($uid)
|
||||
);
|
||||
|
||||
+10
-4
@@ -24,10 +24,16 @@ function js_strings() {
|
||||
'$leavethispage' => t('Unsaved changes. Are you sure you wish to leave this page?'),
|
||||
'$location' => t('Location'),
|
||||
|
||||
'$t01' => ((t('timeago.prefixAgo') != 'timeago.prefixAgo') ? t('timeago.prefixAgo') : ''),
|
||||
'$t02' => ((t('timeago.prefixFromNow') != 'timeago.prefixFromNow') ? t('timeago.prefixFromNow') : ''),
|
||||
'$t03' => t('ago'),
|
||||
'$t04' => t('from now'),
|
||||
// translatable prefix and suffix strings for jquery.timeago -
|
||||
// using the defaults set below if left untranslated, empty strings if
|
||||
// translated to "NONE" and the corresponding language strings
|
||||
// if translated to anything else
|
||||
'$t01' => ((t('timeago.prefixAgo') == 'timeago.prefixAgo') ? '' : ((t('timeago.prefixAgo') == 'NONE') ? '' : t('timeago.prefixAgo'))),
|
||||
'$t02' => ((t('timeago.prefixFromNow') == 'timeago.prefixFromNow') ? '' : ((t('timeago.prefixFromNow') == 'NONE') ? '' : t('timeago.prefixFromNow'))),
|
||||
'$t03' => ((t('timeago.suffixAgo') == 'timeago.suffixAgo') ? 'ago' : ((t('timeago.suffixAgo') == 'NONE') ? '' : t('timeago.suffixAgo'))),
|
||||
'$t04' => ((t('timeago.suffixFromNow') == 'timeago.suffixFromNow') ? 'from now' : ((t('timeago.suffixFromNow') == 'NONE') ? '' : t('timeago.suffixFromNow'))),
|
||||
|
||||
// translatable main strings for jquery.timeago
|
||||
'$t05' => t('less than a minute'),
|
||||
'$t06' => t('about a minute'),
|
||||
'$t07' => t('%d minutes'),
|
||||
|
||||
+34
-1
@@ -73,8 +73,35 @@ function get_best_language() {
|
||||
}
|
||||
}
|
||||
|
||||
if(! isset($preferred))
|
||||
|
||||
if(! isset($preferred)) {
|
||||
|
||||
/*
|
||||
* We could find no perfect match for any of the preferred languages.
|
||||
* For cases where the preference is fr-fr and we have fr but *not* fr-fr
|
||||
* run the test again and only look for the language base
|
||||
* which should provide an interface they can sort of understand
|
||||
*/
|
||||
|
||||
if(isset($langs) && count($langs)) {
|
||||
foreach ($langs as $lang => $v) {
|
||||
if(strlen($lang) === 2) {
|
||||
/* we have already checked this language */
|
||||
continue;
|
||||
}
|
||||
/* Check the base */
|
||||
$lang = strtolower(substr($lang,0,2));
|
||||
if(is_dir("view/$lang")) {
|
||||
$preferred = $lang;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(! isset($preferred)) {
|
||||
$preferred = 'unset';
|
||||
}
|
||||
|
||||
$arr = array('langs' => $langs, 'preferred' => $preferred);
|
||||
|
||||
@@ -86,6 +113,12 @@ function get_best_language() {
|
||||
return ((isset(App::$config['system']['language'])) ? App::$config['system']['language'] : 'en');
|
||||
}
|
||||
|
||||
/*
|
||||
* push_lang and pop_lang let you temporarily override the default language.
|
||||
* Often used to email the administrator during a session created in another language.
|
||||
* The stack is one level deep - so you must pop after every push.
|
||||
*/
|
||||
|
||||
|
||||
function push_lang($language) {
|
||||
|
||||
|
||||
+1
-35
@@ -73,9 +73,7 @@ EOT;
|
||||
// nav links: array of array('href', 'text', 'extra css classes', 'title')
|
||||
$nav = [];
|
||||
|
||||
$disable_discover_tab = get_config('system','disable_discover_tab') || get_config('system','disable_discover_tab') === false;
|
||||
|
||||
if(! $disable_discover_tab)
|
||||
if(can_view_public_stream())
|
||||
$nav['pubs'] = true;
|
||||
|
||||
/**
|
||||
@@ -100,38 +98,6 @@ EOT;
|
||||
|
||||
if(local_channel()) {
|
||||
|
||||
|
||||
|
||||
$nav['network'] = array('network', t('Activity'), "", t('Network Activity'),'network_nav_btn');
|
||||
$nav['network']['all'] = [ 'network', t('View your network activity'), '','' ];
|
||||
$nav['network']['mark'] = array('', t('Mark all activity notifications seen'), '','');
|
||||
|
||||
$nav['home'] = array('channel/' . $channel['channel_address'], t('Channel Home'), "", t('Channel home'),'home_nav_btn');
|
||||
$nav['home']['all'] = [ 'channel/' . $channel['channel_address'], t('View your channel home'), '' , '' ];
|
||||
$nav['home']['mark'] = array('', t('Mark all channel notifications seen'), '','');
|
||||
|
||||
|
||||
$nav['intros'] = array('connections/ifpending', t('Connections'), "", t('Connections'),'connections_nav_btn');
|
||||
if(is_site_admin())
|
||||
$nav['registrations'] = array('admin/accounts', t('Registrations'), "", t('Registrations'),'registrations_nav_btn');
|
||||
|
||||
|
||||
$nav['notifications'] = array('notifications/system', t('Notices'), "", t('Notifications'),'notifications_nav_btn');
|
||||
$nav['notifications']['all']=array('notifications/system', t('View all notifications'), "", "");
|
||||
$nav['notifications']['mark'] = array('', t('Mark all system notifications seen'), '','');
|
||||
|
||||
$nav['messages'] = array('mail/combined', t('Mail'), "", t('Private mail'),'mail_nav_btn');
|
||||
$nav['messages']['all']=array('mail/combined', t('View your private messages'), "", "");
|
||||
$nav['messages']['mark'] = array('', t('Mark all private messages seen'), '','');
|
||||
$nav['messages']['inbox'] = array('mail/inbox', t('Inbox'), "", t('Inbox'));
|
||||
$nav['messages']['outbox']= array('mail/outbox', t('Outbox'), "", t('Outbox'));
|
||||
$nav['messages']['new'] = array('mail/new', t('New Message'), "", t('New Message'));
|
||||
|
||||
|
||||
$nav['all_events'] = array('events', t('Events'), "", t('Event Calendar'),'events_nav_btn');
|
||||
$nav['all_events']['all']=array('events', t('View events'), "", "");
|
||||
$nav['all_events']['mark'] = array('', t('Mark all events seen'), '','');
|
||||
|
||||
if(! $_SESSION['delegate']) {
|
||||
$nav['manage'] = array('manage', t('Channel Manager'), "", t('Manage Your Channels'),'manage_nav_btn');
|
||||
}
|
||||
|
||||
+11
-6
@@ -1579,6 +1579,7 @@ function get_site_info() {
|
||||
$channels_active_halfyear_stat = intval(get_config('system','channels_active_halfyear_stat'));
|
||||
$channels_active_monthly_stat = intval(get_config('system','channels_active_monthly_stat'));
|
||||
$local_posts_stat = intval(get_config('system','local_posts_stat'));
|
||||
$local_comments_stat = intval(get_config('system','local_comments_stat'));
|
||||
$hide_in_statistics = intval(get_config('system','hide_in_statistics'));
|
||||
$site_expire = intval(get_config('system', 'default_expire_days'));
|
||||
|
||||
@@ -1604,24 +1605,28 @@ function get_site_info() {
|
||||
'commit' => $commit,
|
||||
'plugins' => $visible_plugins,
|
||||
'register_policy' => $register_policy[get_config('system','register_policy')],
|
||||
'invitation_only' => intval(get_config('system','invitation_only')),
|
||||
'invitation_only' => (bool) intval(get_config('system','invitation_only')),
|
||||
'directory_mode' => $directory_mode[get_config('system','directory_mode')],
|
||||
'language' => get_config('system','language'),
|
||||
'rss_connections' => intval(get_config('system','feed_contacts')),
|
||||
'rss_connections' => (bool) intval(get_config('system','feed_contacts')),
|
||||
'expiration' => $site_expire,
|
||||
'default_service_restrictions' => $service_class,
|
||||
'locked_features' => $locked_features,
|
||||
'admin' => $admin,
|
||||
'dbdriver' => DBA::$dba->getdriver(),
|
||||
'dbdriver' => DBA::$dba->getdriver() . ' ' . ((ACTIVE_DBTYPE == DBTYPE_POSTGRES) ? 'postgres' : 'mysql'),
|
||||
'lastpoll' => get_config('system','lastpoll'),
|
||||
'info' => (($site_info) ? $site_info : ''),
|
||||
'channels_total' => $channels_total_stat,
|
||||
'channels_active_halfyear' => $channels_active_halfyear_stat,
|
||||
'channels_active_monthly' => $channels_active_monthly_stat,
|
||||
'local_posts' => $local_posts_stat,
|
||||
'hide_in_statistics' => $hide_in_statistics
|
||||
];
|
||||
|
||||
if(! $hide_in_statistics) {
|
||||
$data['channels_active_halfyear'] = $channels_active_halfyear_stat;
|
||||
$data['channels_active_monthly'] = $channels_active_monthly_stat;
|
||||
$data['local_posts'] = $local_posts_stat;
|
||||
$data['local_comments'] = $local_comments_stat;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
+157
-3
@@ -47,7 +47,10 @@ function uninstall_plugin($plugin) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief installs an addon.
|
||||
* @brief Installs an addon.
|
||||
*
|
||||
* This function is called once to install the addon (either from the cli or via
|
||||
* the web admin). This will also call load_plugin() once.
|
||||
*
|
||||
* @param string $plugin name of the addon
|
||||
* @return bool
|
||||
@@ -176,19 +179,91 @@ function reload_plugins() {
|
||||
}
|
||||
|
||||
|
||||
function plugins_installed_list() {
|
||||
|
||||
$r = q("select * from addon where installed = 1 order by aname asc");
|
||||
return(($r) ? ids_to_array($r,'aname') : []);
|
||||
}
|
||||
|
||||
|
||||
function plugins_sync() {
|
||||
|
||||
/**
|
||||
*
|
||||
* Synchronise plugins:
|
||||
*
|
||||
* App::$config['system']['addon'] contains a comma-separated list of names
|
||||
* of plugins/addons which are used on this system.
|
||||
* Go through the database list of already installed addons, and if we have
|
||||
* an entry, but it isn't in the config list, call the unload procedure
|
||||
* and mark it uninstalled in the database (for now we'll remove it).
|
||||
* Then go through the config list and if we have a plugin that isn't installed,
|
||||
* call the install procedure and add it to the database.
|
||||
*
|
||||
*/
|
||||
|
||||
$installed = plugins_installed_list();
|
||||
|
||||
$plugins = get_config('system', 'addon', '');
|
||||
|
||||
$plugins_arr = explode(',', $plugins);
|
||||
|
||||
// array_trim is in include/text.php
|
||||
|
||||
if(! array_walk($plugins_arr,'array_trim'))
|
||||
return;
|
||||
|
||||
App::$plugins = $plugins_arr;
|
||||
|
||||
$installed_arr = [];
|
||||
|
||||
if(count($installed)) {
|
||||
foreach($installed as $i) {
|
||||
if(! in_array($i, $plugins_arr)) {
|
||||
unload_plugin($i);
|
||||
}
|
||||
else {
|
||||
$installed_arr[] = $i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(count($plugins_arr)) {
|
||||
foreach($plugins_arr as $p) {
|
||||
if(! in_array($p, $installed_arr)) {
|
||||
load_plugin($p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get a list of non hidden addons.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function visible_plugin_list() {
|
||||
|
||||
$r = q("select * from addon where hidden = 0 order by aname asc");
|
||||
return(($r) ? ids_to_array($r,'aname') : array());
|
||||
$x = (($r) ? ids_to_array($r,'aname') : array());
|
||||
$y = [];
|
||||
if($x) {
|
||||
foreach($x as $xv) {
|
||||
if(is_dir('addon/' . $xv)) {
|
||||
$y[] = $xv;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $y;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief registers a hook.
|
||||
* @brief Registers a hook.
|
||||
*
|
||||
* @see ::Zotlabs::Extend::Hook::register()
|
||||
*
|
||||
* @param string $hook the name of the hook
|
||||
* @param string $file the name of the file that hooks into
|
||||
@@ -219,6 +294,8 @@ function register_hook($hook, $file, $function, $priority = 0) {
|
||||
/**
|
||||
* @brief unregisters a hook.
|
||||
*
|
||||
* @see ::Zotlabs::Extend::Hook::unregister
|
||||
*
|
||||
* @param string $hook the name of the hook
|
||||
* @param string $file the name of the file that hooks into
|
||||
* @param string $function the name of the function that the hook called
|
||||
@@ -397,6 +474,83 @@ function get_plugin_info($plugin){
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parse widget comment in search of widget info.
|
||||
*
|
||||
* like
|
||||
* \code
|
||||
* * Name: MyWidget
|
||||
* * Description: A widget
|
||||
* * Version: 1.2.3
|
||||
* * Author: John <profile url>
|
||||
* * Author: Jane <email>
|
||||
* *
|
||||
*\endcode
|
||||
* @param string $widget the name of the widget
|
||||
* @return array with the information
|
||||
*/
|
||||
function get_widget_info($widget){
|
||||
$m = array();
|
||||
$info = array(
|
||||
'name' => $widget,
|
||||
'description' => '',
|
||||
'author' => array(),
|
||||
'maintainer' => array(),
|
||||
'version' => '',
|
||||
'requires' => ''
|
||||
);
|
||||
|
||||
$ucwidget = ucfirst($widget);
|
||||
|
||||
$checkpaths = [
|
||||
"Zotlabs/SiteWidget/$ucwidget.php",
|
||||
"Zotlibs/Widget/$ucwidget.php",
|
||||
"addon/$ucwidget/$ucwidget.php",
|
||||
"addon/$widget.php"
|
||||
];
|
||||
|
||||
$widget_found = false;
|
||||
|
||||
foreach ($checkpaths as $path) {
|
||||
if (is_file($path)) {
|
||||
$widget_found = true;
|
||||
$f = file_get_contents($path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(! ($widget_found && $f))
|
||||
return $info;
|
||||
|
||||
$f = escape_tags($f);
|
||||
$r = preg_match("|/\*.*\*/|msU", $f, $m);
|
||||
|
||||
if ($r) {
|
||||
$ll = explode("\n", $m[0]);
|
||||
foreach( $ll as $l ) {
|
||||
$l = trim($l, "\t\n\r */");
|
||||
if ($l != ""){
|
||||
list($k, $v) = array_map("trim", explode(":", $l, 2));
|
||||
$k = strtolower($k);
|
||||
if ($k == 'author' || $k == 'maintainer'){
|
||||
$r = preg_match("|([^<]+)<([^>]+)>|", $v, $m);
|
||||
if ($r) {
|
||||
$info[$k][] = array('name' => $m[1], 'link' => $m[2]);
|
||||
} else {
|
||||
$info[$k][] = array('name' => $v);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$info[$k] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
|
||||
function check_plugin_versions($info) {
|
||||
|
||||
if(! is_array($info))
|
||||
|
||||
+27
-2
@@ -121,7 +121,7 @@ function queue_deliver($outq, $immediate = false) {
|
||||
|
||||
$base = null;
|
||||
$h = parse_url($outq['outq_posturl']);
|
||||
if($h)
|
||||
if($h !== false)
|
||||
$base = $h['scheme'] . '://' . $h['host'] . (($h['port']) ? ':' . $h['port'] : '');
|
||||
|
||||
if(($base) && ($base !== z_root()) && ($immediate)) {
|
||||
@@ -160,6 +160,9 @@ function queue_deliver($outq, $immediate = false) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$arr = array('outq' => $outq, 'base' => $base, 'handled' => false, 'immediate' => $immediate);
|
||||
call_hooks('queue_deliver',$arr);
|
||||
if($arr['handled'])
|
||||
@@ -216,7 +219,29 @@ function queue_deliver($outq, $immediate = false) {
|
||||
// normal zot delivery
|
||||
|
||||
logger('deliver: dest: ' . $outq['outq_posturl'], LOGGER_DEBUG);
|
||||
$result = zot_zot($outq['outq_posturl'],$outq['outq_notify']);
|
||||
|
||||
$channel = null;
|
||||
|
||||
if($outq['outq_msg'] && $outq['outq_channel']) {
|
||||
$channel = channelx_by_n($outq['outq_channel']);
|
||||
}
|
||||
|
||||
$host_crypto = null;
|
||||
|
||||
if($channel && $base) {
|
||||
$h = q("select hubloc_sitekey, site_crypto from hubloc left join site on hubloc_url = site_url where site_url = '%s' order by hubloc_id desc limit 1",
|
||||
dbesc($base)
|
||||
);
|
||||
if($h) {
|
||||
$host_crypto = $h[0];
|
||||
}
|
||||
}
|
||||
|
||||
$msg = $outq['outq_notify'];
|
||||
|
||||
$result = zot_zot($outq['outq_posturl'],$msg,$channel,$host_crypto);
|
||||
|
||||
|
||||
if($result['success']) {
|
||||
logger('deliver: remote zot delivery succeeded to ' . $outq['outq_posturl']);
|
||||
zot_process_response($outq['outq_posturl'],$result, $outq);
|
||||
|
||||
+10
-6
@@ -52,7 +52,7 @@ function poco_load($xchan = '', $url = null) {
|
||||
elseif($s['return_code'] == 404)
|
||||
logger('poco_load: nothing found');
|
||||
else
|
||||
logger('poco_load: returns ' . print_r($s,true));
|
||||
logger('poco_load: returns ' . print_r($s,true), LOGGER_DATA);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -178,11 +178,12 @@ function poco_load($xchan = '', $url = null) {
|
||||
);
|
||||
|
||||
if(! $r) {
|
||||
q("insert into xlink ( xlink_xchan, xlink_link, xlink_rating, xlink_rating_text, xlink_updated, xlink_static ) values ( '%s', '%s', %d, '%s', '%s', 0 ) ",
|
||||
q("insert into xlink ( xlink_xchan, xlink_link, xlink_rating, xlink_rating_text, xlink_sig, xlink_updated, xlink_static ) values ( '%s', '%s', %d, '%s', '%s', '%s', 0 ) ",
|
||||
dbesc($xchan),
|
||||
dbesc($hash),
|
||||
intval(0),
|
||||
dbesc(''),
|
||||
dbesc(''),
|
||||
dbesc(datetime_convert())
|
||||
);
|
||||
}
|
||||
@@ -287,11 +288,14 @@ function suggestion_query($uid, $myxchan, $start = 0, $limit = 80) {
|
||||
|
||||
function update_suggestions() {
|
||||
|
||||
$dirmode = get_config('system', 'directory_mode');
|
||||
if($dirmode === false)
|
||||
$dirmode = DIRECTORY_MODE_NORMAL;
|
||||
$dirmode = get_config('system', 'directory_mode', DIRECTORY_MODE_NORMAL);
|
||||
|
||||
if(($dirmode == DIRECTORY_MODE_PRIMARY) || ($dirmode == DIRECTORY_MODE_STANDALONE)) {
|
||||
if($dirmode == DIRECTORY_MODE_STANDALONE) {
|
||||
poco_load('', z_root() . '/poco');
|
||||
return;
|
||||
}
|
||||
|
||||
if($dirmode == DIRECTORY_MODE_PRIMARY) {
|
||||
$url = z_root() . '/sitelist';
|
||||
}
|
||||
else {
|
||||
|
||||
+5
-14
@@ -309,35 +309,29 @@ function article_tagadelic($uid, $count = 0, $authors = '', $owner = '', $flags
|
||||
|
||||
|
||||
|
||||
function dir_tagadelic($count = 0) {
|
||||
function dir_tagadelic($count = 0, $hub = '') {
|
||||
|
||||
$count = intval($count);
|
||||
|
||||
$dirmode = get_config('system','directory_mode');
|
||||
|
||||
if($dirmode == DIRECTORY_MODE_STANDALONE) {
|
||||
// Fetch tags
|
||||
if($hub) {
|
||||
$r = q("select xtag_term as term, count(xtag_term) as total from xtag
|
||||
left join hubloc on xtag_hash = hubloc_hash
|
||||
where xtag_flags = 0 and hubloc_url = '%s'
|
||||
where xtag_flags = 0 and xtag_hash in (select hubloc_hash from hubloc where hubloc_host = '%s' )
|
||||
group by xtag_term order by total desc %s",
|
||||
dbesc(z_root()),
|
||||
dbesc($hub),
|
||||
((intval($count)) ? "limit $count" : '')
|
||||
);
|
||||
}
|
||||
else {
|
||||
// Fetch tags
|
||||
$r = q("select xtag_term as term, count(xtag_term) as total from xtag where xtag_flags = 0
|
||||
group by xtag_term order by total desc %s",
|
||||
((intval($count)) ? "limit $count" : '')
|
||||
);
|
||||
}
|
||||
if(! $r)
|
||||
return array();
|
||||
|
||||
return [];
|
||||
|
||||
return Zotlabs\Text\Tagadelic::calc($r);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -485,9 +479,6 @@ function dir_tagblock($link,$r) {
|
||||
$o = '';
|
||||
|
||||
$observer = get_observer_hash();
|
||||
if(! get_directory_setting($observer, 'globaldir'))
|
||||
return $o;
|
||||
|
||||
|
||||
if(! $r)
|
||||
$r = App::$data['directory_keywords'];
|
||||
|
||||
+152
-32
@@ -24,12 +24,20 @@ define('RANDOM_STRING_TEXT', 0x01 );
|
||||
* @return string substituted string
|
||||
*/
|
||||
function replace_macros($s, $r) {
|
||||
$arr = [
|
||||
'template' => $s,
|
||||
'params' => $r
|
||||
];
|
||||
|
||||
$arr = array('template' => $s, 'params' => $r);
|
||||
/**
|
||||
* @hooks replace_macros
|
||||
* * \e string \b template
|
||||
* * \e array \b params
|
||||
*/
|
||||
call_hooks('replace_macros', $arr);
|
||||
|
||||
$t = App::template_engine();
|
||||
$output = $t->replace_macros($arr['template'],$arr['params']);
|
||||
$output = $t->replace_macros($arr['template'], $arr['params']);
|
||||
|
||||
return $output;
|
||||
}
|
||||
@@ -301,12 +309,16 @@ function purify_html($s, $allow_position = false) {
|
||||
|
||||
|
||||
/**
|
||||
* @brief generate a string that's random, but usually pronounceable.
|
||||
* @brief Generate a string that's random, but usually pronounceable.
|
||||
*
|
||||
* Used to generate initial passwords.
|
||||
*
|
||||
* @param int $len
|
||||
* @return string
|
||||
* @note In order to create "pronounceable" strings some consonant pairs or
|
||||
* letters that does not make a very good word ending are chopped off, so that
|
||||
* the returned string length can be lower than $len.
|
||||
*
|
||||
* @param int $len max length of generated string
|
||||
* @return string Genereated random, but usually pronounceable string
|
||||
*/
|
||||
function autoname($len) {
|
||||
|
||||
@@ -343,6 +355,7 @@ function autoname($len) {
|
||||
$midcons = array('ck','ct','gn','ld','lf','lm','lt','mb','mm', 'mn','mp',
|
||||
'nd','ng','nk','nt','rn','rp','rt');
|
||||
|
||||
// avoid these consonant pairs at the end of the string
|
||||
$noend = array('bl', 'br', 'cl','cr','dr','fl','fr','gl','gr',
|
||||
'kh', 'kl','kr','mn','pl','pr','rh','tr','qu','wh');
|
||||
|
||||
@@ -355,7 +368,7 @@ function autoname($len) {
|
||||
$word = '';
|
||||
|
||||
for ($x = 0; $x < $len; $x ++) {
|
||||
$r = mt_rand(0,count($table) - 1);
|
||||
$r = mt_rand(0, count($table) - 1);
|
||||
$word .= $table[$r];
|
||||
|
||||
if ($table == $vowels)
|
||||
@@ -364,14 +377,15 @@ function autoname($len) {
|
||||
$table = $vowels;
|
||||
}
|
||||
|
||||
$word = substr($word,0,$len);
|
||||
$word = substr($word, 0, $len);
|
||||
|
||||
foreach ($noend as $noe) {
|
||||
if ((strlen($word) > 2) && (substr($word,-2) == $noe)) {
|
||||
$word = substr($word,0,-1);
|
||||
if ((strlen($word) > 2) && (substr($word, -2) == $noe)) {
|
||||
$word = substr($word, 0, -1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// avoid the letter 'q' as it does not make a very good word ending
|
||||
if (substr($word, -1) == 'q')
|
||||
$word = substr($word, 0, -1);
|
||||
|
||||
@@ -959,7 +973,14 @@ function contact_block() {
|
||||
$contacts = t('Connections');
|
||||
$micropro = Array();
|
||||
foreach($r as $rr) {
|
||||
$rr['archived'] = (intval($rr['abook_archived']) ? true : false);
|
||||
|
||||
// There is no setting to discover if you are bi-directionally connected
|
||||
// Use the ability to post comments as an indication that this relationship is more
|
||||
// than wishful thinking; even though soapbox channels and feeds will disable it.
|
||||
|
||||
if(! intval(get_abconfig(App::$profile['uid'],$rr['xchan_hash'],'their_perms','post_comments'))) {
|
||||
$rr['oneway'] = true;
|
||||
}
|
||||
$micropro[] = micropro($rr,true,'mpfriend');
|
||||
}
|
||||
}
|
||||
@@ -1012,6 +1033,7 @@ function micropro($contact, $redirect = false, $class = '', $textmode = false) {
|
||||
return replace_macros(get_markup_template(($textmode)?'micropro_txt.tpl':'micropro_img.tpl'),array(
|
||||
'$click' => (($contact['click']) ? $contact['click'] : ''),
|
||||
'$class' => $class . (($contact['archived']) ? ' archived' : ''),
|
||||
'$oneway' => (($contact['oneway']) ? true : false),
|
||||
'$url' => $url,
|
||||
'$photo' => $contact['xchan_photo_s'],
|
||||
'$name' => $contact['xchan_name'],
|
||||
@@ -1094,17 +1116,19 @@ function sslify($s) {
|
||||
return $s;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get an array of poke verbs.
|
||||
*
|
||||
* @return array
|
||||
* * \e index is present tense verb
|
||||
* * \e value is array containing past tense verb, translation of present, translation of past
|
||||
*/
|
||||
function get_poke_verbs() {
|
||||
// index is present tense verb
|
||||
// value is array containing past tense verb, translation of present, translation of past
|
||||
|
||||
if(get_config('system','poke_basic')) {
|
||||
if (get_config('system', 'poke_basic')) {
|
||||
$arr = array(
|
||||
'poke' => array( 'poked', t('poke'), t('poked')),
|
||||
'poke' => array('poked', t('poke'), t('poked')),
|
||||
);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$arr = array(
|
||||
'poke' => array( 'poked', t('poke'), t('poked')),
|
||||
'ping' => array( 'pinged', t('ping'), t('pinged')),
|
||||
@@ -1114,15 +1138,26 @@ function get_poke_verbs() {
|
||||
'rebuff' => array( 'rebuffed', t('rebuff'), t('rebuffed')),
|
||||
);
|
||||
|
||||
/**
|
||||
* @hooks poke_verbs
|
||||
* * \e array associative array with another array as value
|
||||
*/
|
||||
call_hooks('poke_verbs', $arr);
|
||||
}
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get an array of mood verbs.
|
||||
*
|
||||
* @return array
|
||||
* * \e index is the verb
|
||||
* * \e value is the translated verb
|
||||
*/
|
||||
function get_mood_verbs() {
|
||||
|
||||
$arr = array(
|
||||
$arr = [
|
||||
'happy' => t('happy'),
|
||||
'sad' => t('sad'),
|
||||
'mellow' => t('mellow'),
|
||||
@@ -1144,9 +1179,14 @@ function get_mood_verbs() {
|
||||
'motivated' => t('motivated'),
|
||||
'relaxed' => t('relaxed'),
|
||||
'surprised' => t('surprised'),
|
||||
);
|
||||
];
|
||||
|
||||
/**
|
||||
* @hooks mood_verbs
|
||||
* * \e array associative array with mood verbs
|
||||
*/
|
||||
call_hooks('mood_verbs', $arr);
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
@@ -1513,14 +1553,37 @@ function format_filer(&$item) {
|
||||
function generate_map($coord) {
|
||||
$coord = trim($coord);
|
||||
$coord = str_replace(array(',','/',' '),array(' ',' ',' '),$coord);
|
||||
$arr = array('lat' => trim(substr($coord,0,strpos($coord,' '))), 'lon' => trim(substr($coord,strpos($coord,' ')+1)), 'html' => '');
|
||||
call_hooks('generate_map',$arr);
|
||||
|
||||
$arr = [
|
||||
'lat' => trim(substr($coord, 0, strpos($coord, ' '))),
|
||||
'lon' => trim(substr($coord, strpos($coord, ' ')+1)),
|
||||
'html' => ''
|
||||
];
|
||||
|
||||
/**
|
||||
* @hooks generate_map
|
||||
* * \e string \b lat
|
||||
* * \e string \b lon
|
||||
* * \e string \b html the parsed HTML to return
|
||||
*/
|
||||
call_hooks('generate_map', $arr);
|
||||
|
||||
return (($arr['html']) ? $arr['html'] : $coord);
|
||||
}
|
||||
|
||||
function generate_named_map($location) {
|
||||
$arr = array('location' => $location, 'html' => '');
|
||||
call_hooks('generate_named_map',$arr);
|
||||
$arr = [
|
||||
'location' => $location,
|
||||
'html' => ''
|
||||
];
|
||||
|
||||
/**
|
||||
* @hooks generate_named_map
|
||||
* * \e string \b location
|
||||
* * \e string \b html the parsed HTML to return
|
||||
*/
|
||||
call_hooks('generate_named_map', $arr);
|
||||
|
||||
return (($arr['html']) ? $arr['html'] : $location);
|
||||
}
|
||||
|
||||
@@ -1626,13 +1689,11 @@ function prepare_binary($item) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Given a text string, convert from bbcode to html and add smilie icons.
|
||||
*
|
||||
* @param string $text
|
||||
* @param sting $content_type (optional) default text/bbcode
|
||||
* @param string $content_type (optional) default text/bbcode
|
||||
* @param boolean $cache (optional) default false
|
||||
*
|
||||
* @return string
|
||||
@@ -1958,18 +2019,37 @@ function item_post_type($item) {
|
||||
return $post_type;
|
||||
}
|
||||
|
||||
// This needs to be fixed to use quoted tag strings
|
||||
|
||||
function undo_post_tagging($s) {
|
||||
|
||||
$matches = null;
|
||||
// undo tags and mentions
|
||||
$cnt = preg_match_all('/([@#])(\!*)\[zrl=(.*?)\](.*?)\[\/zrl\]/ism',$s,$matches,PREG_SET_ORDER);
|
||||
if($cnt) {
|
||||
foreach($matches as $mtch) {
|
||||
$s = str_replace($mtch[0], $mtch[1] . $mtch[2] . str_replace(' ','_',$mtch[4]),$s);
|
||||
$s = str_replace($mtch[0], $mtch[1] . $mtch[2] . quote_tag($mtch[4]),$s);
|
||||
}
|
||||
}
|
||||
// undo forum tags
|
||||
$cnt = preg_match_all('/\!\[zrl=(.*?)\](.*?)\[\/zrl\]/ism',$s,$matches,PREG_SET_ORDER);
|
||||
if($cnt) {
|
||||
foreach($matches as $mtch) {
|
||||
$s = str_replace($mtch[0], '!' . quote_tag($mtch[2]),$s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $s;
|
||||
}
|
||||
|
||||
function quote_tag($s) {
|
||||
if(strpos($s,' ') !== false)
|
||||
return '"' . $s . '"';
|
||||
return $s;
|
||||
}
|
||||
|
||||
|
||||
function fix_mce_lf($s) {
|
||||
$s = str_replace("\r\n","\n",$s);
|
||||
// $s = str_replace("\n\n","\n",$s);
|
||||
@@ -2099,6 +2179,35 @@ function ids_to_querystr($arr,$idx = 'id',$quote = false) {
|
||||
return(implode(',', $t));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief array_elm_to_str($arr,$elm,$delim = ',') extract unique individual elements from an array of arrays and return them as a string separated by a delimiter
|
||||
* similar to ids_to_querystr, but allows a different delimiter instead of a db-quote option
|
||||
* empty elements (evaluated after trim()) are ignored.
|
||||
* @param $arr array
|
||||
* @param $elm array key to extract from sub-array
|
||||
* @param $delim string default ','
|
||||
* @returns string
|
||||
*/
|
||||
|
||||
function array_elm_to_str($arr,$elm,$delim = ',') {
|
||||
|
||||
$tmp = [];
|
||||
if($arr && is_array($arr)) {
|
||||
foreach($arr as $x) {
|
||||
if(is_array($x) && array_key_exists($elm,$x)) {
|
||||
$z = trim($x[$elm]);
|
||||
if(($z) && (! in_array($z,$tmp))) {
|
||||
$tmp[] = $z;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return implode($delim,$tmp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Fetches xchan and hubloc data for an array of items with only an
|
||||
* author_xchan and owner_xchan.
|
||||
@@ -3033,8 +3142,19 @@ function text_highlight($s, $lang) {
|
||||
$s = jindent($s);
|
||||
}
|
||||
|
||||
$arr = [ 'text' => $s, 'language' => $lang, 'success' => false ];
|
||||
call_hooks('text_highlight',$arr);
|
||||
$arr = [
|
||||
'text' => $s,
|
||||
'language' => $lang,
|
||||
'success' => false
|
||||
];
|
||||
|
||||
/**
|
||||
* @hooks text_highlight
|
||||
* * \e string \b text
|
||||
* * \e string \b language
|
||||
* * \e boolean \b success default false
|
||||
*/
|
||||
call_hooks('text_highlight', $arr);
|
||||
|
||||
if($arr['success'])
|
||||
$o = $arr['text'];
|
||||
@@ -3117,7 +3237,6 @@ function share_unshield($m) {
|
||||
|
||||
function cleanup_bbcode($body) {
|
||||
|
||||
|
||||
/**
|
||||
* fix naked links by passing through a callback to see if this is a hubzilla site
|
||||
* (already known to us) which will get a zrl, otherwise link with url, add bookmark tag to both.
|
||||
@@ -3155,7 +3274,6 @@ function cleanup_bbcode($body) {
|
||||
|
||||
|
||||
return $body;
|
||||
|
||||
}
|
||||
|
||||
function gen_link_id($mid) {
|
||||
@@ -3192,3 +3310,5 @@ function purify_filename($s) {
|
||||
return '';
|
||||
return $s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+12
-6
@@ -127,8 +127,11 @@ function clean_query_string($s = '') {
|
||||
* @return string
|
||||
*/
|
||||
function zidify_callback($match) {
|
||||
$is_zid = ((feature_enabled(local_channel(), 'sendzid')) || (strpos($match[1], 'zrl')) ? true : false);
|
||||
$replace = '<a' . $match[1] . ' href="' . (($is_zid) ? zid($match[2]) : $match[2]) . '"';
|
||||
|
||||
$arr = [ 'zid' => ((strpos($match[1],'zrl')) ? true : false), 'url' => $match[2] ];
|
||||
call_hooks('zidify', $arr);
|
||||
|
||||
$replace = '<a' . $match[1] . ' href="' . (intval($arr['zid']) ? zid($arr['url']) : $arr['url']) . '"';
|
||||
|
||||
$x = str_replace($match[0], $replace, $match[0]);
|
||||
|
||||
@@ -136,8 +139,11 @@ function zidify_callback($match) {
|
||||
}
|
||||
|
||||
function zidify_img_callback($match) {
|
||||
$is_zid = ((feature_enabled(local_channel(), 'sendzid')) || (strpos($match[1], 'zrl')) ? true : false);
|
||||
$replace = '<img' . $match[1] . ' src="' . (($is_zid) ? zid($match[2]) : $match[2]) . '"';
|
||||
|
||||
$arr = [ 'zid' => ((strpos($match[1],'zrl')) ? true : false), 'url' => $match[2] ];
|
||||
call_hooks('zidify', $arr);
|
||||
|
||||
$replace = '<img' . $match[1] . ' src="' . (intval($arr['zid']) ? zid($arr['url']) : $arr['url']) . '"';
|
||||
|
||||
$x = str_replace($match[0], $replace, $match[0]);
|
||||
|
||||
@@ -259,9 +265,9 @@ function red_zrlify_img_callback($matches) {
|
||||
*/
|
||||
function owt_init($token) {
|
||||
|
||||
\Zotlabs\Zot\Verify::purge('owt', '3 MINUTE');
|
||||
\Zotlabs\Lib\Verify::purge('owt', '3 MINUTE');
|
||||
|
||||
$ob_hash = \Zotlabs\Zot\Verify::get_meta('owt', 0, $token);
|
||||
$ob_hash = \Zotlabs\Lib\Verify::get_meta('owt', 0, $token);
|
||||
|
||||
if($ob_hash === false) {
|
||||
return;
|
||||
|
||||
+191
-35
@@ -158,6 +158,85 @@ function zot_build_packet($channel, $type = 'notify', $recipients = null, $remot
|
||||
return json_encode($data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Builds a zot6 notification packet.
|
||||
*
|
||||
* Builds a zot6 notification packet that you can either store in the queue with
|
||||
* a message array or call zot_zot to immediately zot it to the other side.
|
||||
*
|
||||
* @param array $channel
|
||||
* sender channel structure
|
||||
* @param string $type
|
||||
* 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 $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
|
||||
* @param string $methods
|
||||
* optional comma separated list of encryption methods @ref zot_best_algorithm()
|
||||
* @param string $secret
|
||||
* random string, required for packets which require verification/callback
|
||||
* e.g. 'pickup', 'purge', 'notify', 'auth_check'. Packet types 'ping', 'force_refresh', and 'refresh' do not require verification
|
||||
* @param string $extra
|
||||
* @returns string json encoded zot packet
|
||||
*/
|
||||
function zot6_build_packet($channel, $type = 'notify', $recipients = null, $msg = '', $remote_key = null, $methods = '', $secret = null, $extra = null) {
|
||||
|
||||
$sig_method = get_config('system','signature_algorithm','sha256');
|
||||
|
||||
$data = [
|
||||
'type' => $type,
|
||||
'sender' => [
|
||||
'guid' => $channel['channel_guid'],
|
||||
'guid_sig' => base64url_encode(rsa_sign($channel['channel_guid'],$channel['channel_prvkey'],$sig_method)),
|
||||
'url' => z_root(),
|
||||
'url_sig' => base64url_encode(rsa_sign(z_root(),$channel['channel_prvkey'],$sig_method)),
|
||||
'sitekey' => get_config('system','pubkey')
|
||||
],
|
||||
'callback' => '/post',
|
||||
'version' => Zotlabs\Lib\System::get_zot_revision(),
|
||||
'encryption' => crypto_methods(),
|
||||
'signing' => signing_methods()
|
||||
];
|
||||
|
||||
if ($recipients) {
|
||||
for ($x = 0; $x < count($recipients); $x ++)
|
||||
unset($recipients[$x]['hash']);
|
||||
|
||||
$data['recipients'] = $recipients;
|
||||
}
|
||||
|
||||
if($msg) {
|
||||
$data['msg'] = $msg;
|
||||
}
|
||||
|
||||
if ($secret) {
|
||||
$data['secret'] = preg_replace('/[^0-9a-fA-F]/','',$secret);
|
||||
$data['secret_sig'] = base64url_encode(rsa_sign($secret,$channel['channel_prvkey'],$sig_method));
|
||||
}
|
||||
|
||||
if ($extra) {
|
||||
foreach ($extra as $k => $v)
|
||||
$data[$k] = $v;
|
||||
}
|
||||
|
||||
logger('zot6_build_packet: ' . print_r($data,true), LOGGER_DATA, LOG_DEBUG);
|
||||
|
||||
// Hush-hush ultra top-secret mode
|
||||
|
||||
if($remote_key) {
|
||||
$algorithm = zot_best_algorithm($methods);
|
||||
$data = crypto_encapsulate(json_encode($data),$remote_key, $algorithm);
|
||||
}
|
||||
|
||||
return json_encode($data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Choose best encryption function from those available on both sites.
|
||||
*
|
||||
@@ -209,10 +288,23 @@ function zot_best_algorithm($methods) {
|
||||
*
|
||||
* @param string $url
|
||||
* @param array $data
|
||||
* @param array $channel (optional if using zot6 delivery)
|
||||
* @param array $crypto (optional if encrypted httpsig, requires hubloc_sitekey and site_crypto elements)
|
||||
* @return array see z_post_url() for returned data format
|
||||
*/
|
||||
function zot_zot($url, $data) {
|
||||
return z_post_url($url, array('data' => $data));
|
||||
function zot_zot($url, $data, $channel = null,$crypto = null) {
|
||||
|
||||
$headers = [];
|
||||
|
||||
if($channel) {
|
||||
$headers['X-Zot-Token'] = random_string();
|
||||
$hash = \Zotlabs\Web\HTTPSig::generate_digest($data,false);
|
||||
$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']) : ''));
|
||||
}
|
||||
|
||||
$redirects = 0;
|
||||
return z_post_url($url, array('data' => $data),$redirects,((empty($h)) ? [] : [ 'headers' => $h ]));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -495,13 +587,16 @@ function zot_refresh($them, $channel = null, $force = false) {
|
||||
|
||||
|
||||
// If there is a default group for this channel, add this connection to it
|
||||
// for pending connections this will happens at acceptance time.
|
||||
|
||||
$default_group = $channel['channel_default_group'];
|
||||
if($default_group) {
|
||||
require_once('include/group.php');
|
||||
$g = group_rec_byhash($channel['channel_id'],$default_group);
|
||||
if($g)
|
||||
group_add_member($channel['channel_id'],'',$x['hash'],$g['id']);
|
||||
if(! intval($new_connection[0]['abook_pending'])) {
|
||||
$default_group = $channel['channel_default_group'];
|
||||
if($default_group) {
|
||||
require_once('include/group.php');
|
||||
$g = group_rec_byhash($channel['channel_id'],$default_group);
|
||||
if($g)
|
||||
group_add_member($channel['channel_id'],'',$x['hash'],$g['id']);
|
||||
}
|
||||
}
|
||||
|
||||
unset($new_connection[0]['abook_id']);
|
||||
@@ -1060,7 +1155,12 @@ function zot_process_response($hub, $arr, $outq) {
|
||||
* @brief
|
||||
*
|
||||
* We received a notification packet (in mod_post) that a message is waiting for us, and we've verified the sender.
|
||||
* Now send back a pickup message, using our message tracking ID ($arr['secret']), which we will sign with our site
|
||||
* Check if the site is using zot6 delivery and includes a verified HTTP Signature, signed content, and a 'msg' field,
|
||||
* 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.
|
||||
* If everything checks out on the remote end, we will receive back a packet containing one or more messages,
|
||||
@@ -1078,38 +1178,61 @@ function zot_fetch($arr) {
|
||||
|
||||
$url = $arr['sender']['url'] . $arr['callback'];
|
||||
|
||||
// set $multiple param on zot_gethub() to return all matching hubs
|
||||
// This allows us to recover from re-installs when a redundant (but invalid) hubloc for
|
||||
// this identity is widely dispersed throughout the network.
|
||||
$import = null;
|
||||
$hubs = null;
|
||||
|
||||
$ret_hubs = zot_gethub($arr['sender'],true);
|
||||
if(! $ret_hubs) {
|
||||
$zret = zot6_check_sig();
|
||||
|
||||
if($zret['success'] && $zret['hubloc'] && $zret['hubloc']['hubloc_guid'] === $data['sender']['guid'] && $data['msg']) {
|
||||
logger('zot6_delivery',LOGGER_DEBUG);
|
||||
logger('zot6_data: ' . print_r($data,true),LOGGER_DATA);
|
||||
|
||||
$ret['collected'] = true;
|
||||
|
||||
$import = [ 'success' => true, 'body' => json_encode( [ 'success' => true, 'pickup' => [ [ 'notify' => $data, 'message' => json_decode($data['msg'],true) ] ] ] ) ];
|
||||
$hubs = [ $zret['hubloc'] ] ;
|
||||
}
|
||||
|
||||
if(! $hubs) {
|
||||
// set $multiple param on zot_gethub() to return all matching hubs
|
||||
// This allows us to recover from re-installs when a redundant (but invalid) hubloc for
|
||||
// this identity is widely dispersed throughout the network.
|
||||
|
||||
$hubs = zot_gethub($arr['sender'],true);
|
||||
}
|
||||
|
||||
if(! $hubs) {
|
||||
logger('No hub: ' . print_r($arr['sender'],true));
|
||||
return;
|
||||
}
|
||||
|
||||
foreach($ret_hubs as $ret_hub) {
|
||||
foreach($hubs as $hub) {
|
||||
|
||||
$secret = substr(preg_replace('/[^0-9a-fA-F]/','',$arr['secret']),0,64);
|
||||
if(! $import) {
|
||||
$secret = substr(preg_replace('/[^0-9a-fA-F]/','',$arr['secret']),0,64);
|
||||
|
||||
$data = [
|
||||
'type' => 'pickup',
|
||||
'url' => z_root(),
|
||||
'callback_sig' => base64url_encode(rsa_sign(z_root() . '/post', get_config('system','prvkey'))),
|
||||
'callback' => z_root() . '/post',
|
||||
'secret' => $secret,
|
||||
'secret_sig' => base64url_encode(rsa_sign($secret, get_config('system','prvkey')))
|
||||
];
|
||||
$data = [
|
||||
'type' => 'pickup',
|
||||
'url' => z_root(),
|
||||
'callback_sig' => base64url_encode(rsa_sign(z_root() . '/post', get_config('system','prvkey'))),
|
||||
'callback' => z_root() . '/post',
|
||||
'secret' => $secret,
|
||||
'secret_sig' => base64url_encode(rsa_sign($secret, get_config('system','prvkey')))
|
||||
];
|
||||
|
||||
$algorithm = zot_best_algorithm($ret_hub['site_crypto']);
|
||||
$datatosend = json_encode(crypto_encapsulate(json_encode($data),$ret_hub['hubloc_sitekey'], $algorithm));
|
||||
$algorithm = zot_best_algorithm($hub['site_crypto']);
|
||||
$datatosend = json_encode(crypto_encapsulate(json_encode($data),$hub['hubloc_sitekey'], $algorithm));
|
||||
|
||||
$fetch = zot_zot($url,$datatosend);
|
||||
$import = zot_zot($url,$datatosend);
|
||||
}
|
||||
else {
|
||||
$algorithm = zot_best_algorithm($hub['site_crypto']);
|
||||
}
|
||||
|
||||
$result = zot_import($fetch, $arr['sender']['url']);
|
||||
$result = zot_import($import, $arr['sender']['url']);
|
||||
|
||||
if($result) {
|
||||
$result = crypto_encapsulate(json_encode($result),$ret_hub['hubloc_sitekey'], $algorithm);
|
||||
$result = crypto_encapsulate(json_encode($result),$hub['hubloc_sitekey'], $algorithm);
|
||||
return $result;
|
||||
}
|
||||
|
||||
@@ -1608,7 +1731,7 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $
|
||||
foreach($deliveries as $d) {
|
||||
$local_public = $public;
|
||||
|
||||
$DR = new Zotlabs\Zot\DReport(z_root(),$sender['hash'],$d['hash'],$arr['mid']);
|
||||
$DR = new Zotlabs\Lib\DReport(z_root(),$sender['hash'],$d['hash'],$arr['mid']);
|
||||
|
||||
$r = q("select * from channel where channel_hash = '%s' limit 1",
|
||||
dbesc($d['hash'])
|
||||
@@ -2137,7 +2260,7 @@ function process_mail_delivery($sender, $arr, $deliveries) {
|
||||
|
||||
foreach($deliveries as $d) {
|
||||
|
||||
$DR = new Zotlabs\Zot\DReport(z_root(),$sender['hash'],$d['hash'],$arr['mid']);
|
||||
$DR = new Zotlabs\Lib\DReport(z_root(),$sender['hash'],$d['hash'],$arr['mid']);
|
||||
|
||||
$r = q("select * from channel where channel_hash = '%s' limit 1",
|
||||
dbesc($d['hash'])
|
||||
@@ -3778,11 +3901,11 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
|
||||
// we should probably do this for all items, but usually we only send one.
|
||||
|
||||
if(array_key_exists('item',$arr) && is_array($arr['item'][0])) {
|
||||
$DR = new Zotlabs\Zot\DReport(z_root(),$d['hash'],$d['hash'],$arr['item'][0]['message_id'],'channel sync processed');
|
||||
$DR = new Zotlabs\Lib\DReport(z_root(),$d['hash'],$d['hash'],$arr['item'][0]['message_id'],'channel sync processed');
|
||||
$DR->addto_recipient($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
|
||||
}
|
||||
else
|
||||
$DR = new Zotlabs\Zot\DReport(z_root(),$d['hash'],$d['hash'],'sync packet','channel sync delivered');
|
||||
$DR = new Zotlabs\Lib\DReport(z_root(),$d['hash'],$d['hash'],'sync packet','channel sync delivered');
|
||||
|
||||
$result[] = $DR->get();
|
||||
}
|
||||
@@ -4793,7 +4916,7 @@ function zot_reply_auth_check($data,$encrypted_packet) {
|
||||
* the web server. We should probably convert this to webserver time rather than DB time so
|
||||
* that the different clocks won't affect it and allow us to keep the time short.
|
||||
*/
|
||||
Zotlabs\Zot\Verify::purge('auth', '30 MINUTE');
|
||||
Zotlabs\Lib\Verify::purge('auth', '30 MINUTE');
|
||||
|
||||
$y = q("select xchan_pubkey from xchan where xchan_hash = '%s' limit 1",
|
||||
dbesc($sender_hash)
|
||||
@@ -4834,7 +4957,7 @@ function zot_reply_auth_check($data,$encrypted_packet) {
|
||||
// This additionally checks for forged sites since we already stored the expected result in meta
|
||||
// and we've already verified that this is them via zot_gethub() and that their key signed our token
|
||||
|
||||
$z = Zotlabs\Zot\Verify::match('auth',$c[0]['channel_id'],$data['secret'],$data['sender']['url']);
|
||||
$z = Zotlabs\Lib\Verify::match('auth',$c[0]['channel_id'],$data['secret'],$data['sender']['url']);
|
||||
if (! $z) {
|
||||
logger('mod_zot: auth_check: verification key not found.');
|
||||
$ret['message'] .= 'verification key not found' . EOL;
|
||||
@@ -4967,6 +5090,39 @@ 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)) {
|
||||
$sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER['HTTP_SIGNATURE']);
|
||||
if($sigblock) {
|
||||
$keyId = $sigblock['keyId'];
|
||||
|
||||
if($keyId) {
|
||||
$r = q("select hubloc.*, site_crypto from hubloc left join site on hubloc_url = site_url
|
||||
where hubloc_addr = '%s' ",
|
||||
dbesc(str_replace('acct:','',$keyId))
|
||||
);
|
||||
if($r) {
|
||||
foreach($r as $hubloc) {
|
||||
$verified = \Zotlabs\Web\HTTPSig::verify('',$hubloc['xchan_pubkey']);
|
||||
if($verified && $verified['header_signed'] && $verified['header_valid'] && $verified['content_signed'] && $verified['content_valid']) {
|
||||
$ret['hubloc'] = $hubloc;
|
||||
$ret['success'] = true;
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function zot_reply_notify($data) {
|
||||
|
||||
$ret = array('success' => false);
|
||||
|
||||
Reference in New Issue
Block a user