aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/acl_selectors.php47
-rw-r--r--include/api_zot.php15
-rw-r--r--include/attach.php231
-rw-r--r--include/auth.php7
-rw-r--r--include/bbcode.php307
-rw-r--r--include/cdav.php186
-rw-r--r--include/channel.php226
-rw-r--r--include/connections.php73
-rw-r--r--include/contact_widgets.php49
-rw-r--r--include/conversation.php108
-rwxr-xr-xinclude/dba/dba_driver.php4
-rwxr-xr-xinclude/dba/dba_pdo.php9
-rw-r--r--include/dir_fns.php23
-rw-r--r--include/event.php175
-rw-r--r--include/features.php28
-rw-r--r--include/feedutils.php5
-rw-r--r--include/group.php9
-rw-r--r--include/help.php2
-rw-r--r--include/hubloc.php12
-rw-r--r--include/import.php141
-rwxr-xr-xinclude/items.php216
-rw-r--r--include/js_strings.php5
-rw-r--r--include/language.php7
-rw-r--r--include/markdown.php12
-rw-r--r--include/menu.php4
-rw-r--r--include/message.php4
-rw-r--r--include/nav.php10
-rw-r--r--include/network.php110
-rw-r--r--include/permissions.php20
-rw-r--r--include/photo/photo_driver.php128
-rw-r--r--include/photos.php12
-rw-r--r--include/queue_fn.php80
-rw-r--r--include/security.php4
-rw-r--r--include/socgraph.php2
-rw-r--r--include/taxonomy.php93
-rw-r--r--include/text.php214
-rw-r--r--include/xchan.php4
-rw-r--r--include/zid.php46
-rw-r--r--include/zot.php145
39 files changed, 2193 insertions, 580 deletions
diff --git a/include/acl_selectors.php b/include/acl_selectors.php
index 35e385058..a3476439a 100644
--- a/include/acl_selectors.php
+++ b/include/acl_selectors.php
@@ -79,24 +79,44 @@ function populate_acl($defaults = null,$show_jotnets = true, $emptyACL_descripti
$custom = false;
}
- $r = q("SELECT id, profile_guid, profile_name from profile where is_default = 0 and uid = %d order by profile_name",
+ $r = q("SELECT id, hash, gname FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
intval(local_channel())
);
+
if($r) {
- foreach($r as $rv) {
- $selected = (($single_group && 'vp.' . $rv['profile_guid'] === $allow_gid[0]) ? ' selected = "selected" ' : '');
- $groups .= '<option id="' . 'vp' . $rv['id'] . '" value="' . 'vp.' . $rv['profile_guid'] . '"' . $selected . '>' . t('Profile','acl') . ' ' . $rv['profile_name'] . '</option>' . "\r\n";
+ $groups .= '<optgroup label = "' . t('Privacy Groups').'">';
+ foreach($r as $rr) {
+ $selected = (($single_group && $rr['hash'] === $allow_gid[0]) ? ' selected = "selected" ' : '');
+ $groups .= '<option id="' . $rr['id'] . '" value="' . $rr['hash'] . '"' . $selected . '>' . $rr['gname'] . '</option>' . "\r\n";
}
+ $groups .= '</optgroup>';
}
- $r = q("SELECT id, hash, gname FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
+ $r = q("SELECT id, profile_guid, profile_name from profile where is_default = 0 and uid = %d order by profile_name",
intval(local_channel())
);
if($r) {
- foreach($r as $rr) {
- $selected = (($single_group && $rr['hash'] === $allow_gid[0]) ? ' selected = "selected" ' : '');
- $groups .= '<option id="' . $rr['id'] . '" value="' . $rr['hash'] . '"' . $selected . '>' . $rr['gname'] . '</option>' . "\r\n";
+ $groups .= '<optgroup label = "' . t('Profile-Based Privacy Groups').'">';
+ foreach($r as $rv) {
+ $selected = (($single_group && 'vp.' . $rv['profile_guid'] === $allow_gid[0]) ? ' selected = "selected" ' : '');
+ $groups .= '<option id="' . 'vp' . $rv['id'] . '" value="' . 'vp.' . $rv['profile_guid'] . '"' . $selected . '>' . $rv['profile_name'] . '</option>' . "\r\n";
+ }
+ $groups .= '</optgroup>';
+ }
+
+ // $dialog_description is only set in places where we set permissions for a post.
+ // Abuse this fact to decide if forums should be displayed or not.
+ if($dialog_description) {
+ $forums = get_forum_channels(local_channel(),1);
+ if($forums) {
+ $groups .= '<optgroup label = "' . t('Forums').'">';
+ foreach($forums as $f) {
+ $private = (($f['private_forum']) ? ' (' . t('Private Forum') . ')' : '');
+ $selected = (($single_group && $f['hash'] === $allow_cid[0]) ? ' selected = "selected" ' : '');
+ $groups .= '<option id="^' . $f['abook_id'] . '" value="^' . $f['xchan_hash'] . '"' . $selected . '>' . $f['xchan_name'] . $private . '</option>' . "\r\n";
+ }
+ $groups .= '</optgroup>';
}
}
@@ -104,17 +124,18 @@ function populate_acl($defaults = null,$show_jotnets = true, $emptyACL_descripti
$o = replace_macros($tpl, array(
'$showall' => $showall_caption,
'$onlyme' => t('Only me'),
- '$groups' => $groups,
+ '$groups' => $groups,
'$public_selected' => (($has_acl) ? false : true),
'$justme_selected' => $just_me,
'$custom_selected' => $custom,
'$showallOrigin' => $showall_origin,
'$showallIcon' => $showall_icon,
- '$select_label' => t('Who can see this?'),
+ '$select_label' => t('Share with'),
'$custom' => t('Custom selection'),
- '$showlimitedDesc' => t('Select "Show" to allow viewing. "Don\'t show" lets you override and limit the scope of "Show".'),
- '$show' => t('Show'),
- '$hide' => t("Don't show"),
+ '$custom_label' => t('Advanced'),
+ '$showlimitedDesc' => t('Select "Allow" to allow viewing. "Don\'t allow" lets you override and limit the scope of "Allow".'),
+ '$show' => t('Allow'),
+ '$hide' => t("Don't allow"),
'$search' => t('Search'),
'$allowcid' => json_encode($allow_cid),
'$allowgid' => json_encode($allow_gid),
diff --git a/include/api_zot.php b/include/api_zot.php
index 287720484..8f621d998 100644
--- a/include/api_zot.php
+++ b/include/api_zot.php
@@ -1,7 +1,9 @@
<?php
function zot_api_init() {
- api_register_func('api/red/version','api_zot_version',false);
+ api_register_func('api/z/1.0/verify','api_verify', true);
+
+ api_register_func('api/red/version','api_zot_version',false);
api_register_func('api/z/1.0/version','api_zot_version',false);
api_register_func('api/export/basic','api_export_basic', true);
api_register_func('api/red/channel/export/basic','api_export_basic', true);
@@ -47,6 +49,17 @@
return;
}
+ function api_verify($type) {
+ if (api_user() === false) {
+ logger('no channel');
+ return false;
+ }
+ $channel = channelx_by_n(api_user());
+ // logger('channel: ' . print_r($channel,true));
+
+ json_return_and_die($channel);
+ }
+
function api_zot_version($type) {
diff --git a/include/attach.php b/include/attach.php
index 80efe0838..c9649a4ce 100644
--- a/include/attach.php
+++ b/include/attach.php
@@ -11,6 +11,11 @@
* @todo Also an 'append' option to the storage function might be a useful addition.
*/
+use Zotlabs\Lib\Libsync;
+use Zotlabs\Lib\Activity;
+use Zotlabs\Access\PermissionLimits;
+use Zotlabs\Daemon\Master;
+
require_once('include/permissions.php');
require_once('include/security.php');
require_once('include/group.php');
@@ -56,6 +61,7 @@ function z_mime_content_type($filename) {
'jpeg' => 'image/jpeg',
'jpg' => 'image/jpeg',
'gif' => 'image/gif',
+ 'webp' => 'image/webp',
'bmp' => 'image/bmp',
'ico' => 'image/vnd.microsoft.icon',
'tiff' => 'image/tiff',
@@ -616,7 +622,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$is_photo = 0;
$gis = @getimagesize($src);
logger('getimagesize: ' . print_r($gis,true), LOGGER_DATA);
- if(($gis) && ($gis[2] === IMAGETYPE_GIF || $gis[2] === IMAGETYPE_JPEG || $gis[2] === IMAGETYPE_PNG)) {
+ if(($gis) && ($gis[2] === IMAGETYPE_GIF || $gis[2] === IMAGETYPE_JPEG || $gis[2] === IMAGETYPE_PNG || $gis[2] === IMAGETYPE_WEBP)) {
$is_photo = 1;
if($gis[2] === IMAGETYPE_GIF)
$def_extension = '.gif';
@@ -624,6 +630,8 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$def_extension = '.jpg';
if($gis[2] === IMAGETYPE_PNG)
$def_extension = '.png';
+ if($gis[2] === IMAGETYPE_WEBP)
+ $def_extension = '.webp';
}
// If we know it's a photo, over-ride the type in case the source system could not determine what it was
@@ -908,7 +916,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
);
}
- if($is_photo) {
+ if($is_photo && $r) {
$args = array( 'source' => $source, 'visible' => $visible, 'resource_id' => $hash, 'album' => $pathname, 'os_syspath' => $os_basepath . $os_relpath, 'os_path' => $os_path, 'display_path' => $display_path, 'filename' => $filename, 'getimagesize' => $gis, 'directory' => $direct, 'options' => $options );
if($arr['contact_allow'])
@@ -942,9 +950,15 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$args['deliver'] = $dosync;
$p = photo_upload($channel,$observer,$args);
- if($p['success']) {
- $ret['body'] = $p['body'];
+ if($p['success'])
+ $ret['body'] = $p['body'];
+ else {
+ // Attach as ordinary file if image processing is failed
+ $x = q("UPDATE attach SET is_photo = 0 WHERE hash = '%s'",
+ dbesc($hash)
+ );
}
+
}
if(($options !== 'update') && ($remove_when_processed))
@@ -1009,13 +1023,11 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$sync = attach_export_data($channel,$hash);
if($sync)
- build_sync_packet($channel['channel_id'],array('file' => array($sync)));
+ Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
}
if($notify) {
- $cloudPath = z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['0']['display_path'];
- $object = get_file_activity_object($channel['channel_id'], $r['0']['hash'], $cloudPath);
- file_activity($channel['channel_id'], $object, $r['0']['allow_cid'], $r['0']['allow_gid'], $r['0']['deny_cid'], $r['0']['deny_gid'], 'post', $notify);
+ attach_store_item($channel, $observer, $r[0]);
}
return $ret;
@@ -1394,7 +1406,7 @@ function attach_change_permissions($channel_id, $resource, $allow_cid, $allow_gi
$data = attach_export_data($channel,$resource);
if($data)
- build_sync_packet($channel['channel_id'],array('file' => array($data)));
+ Libsync::build_sync_packet($channel['channel_id'],array('file' => array($data)));
}
}
@@ -1441,9 +1453,6 @@ function attach_delete($channel_id, $resource, $is_photo = 0) {
return;
}
- $url = get_cloud_url($channel_id, $channel_address, $resource);
- $object = get_file_activity_object($channel_id, $resource, $url);
-
// If resource is a directory delete everything in the directory recursive
if(intval($r[0]['is_dir'])) {
$x = q("SELECT hash, os_storage, is_dir, flags FROM attach WHERE folder = '%s' AND uid = %d",
@@ -1487,6 +1496,9 @@ function attach_delete($channel_id, $resource, $is_photo = 0) {
if($r[0]['is_photo']) {
attach_drop_photo($channel_id,$resource);
}
+ else {
+ attach_drop_item($channel_id,$resource);
+ }
// update the parent folder's lastmodified timestamp
@@ -1506,8 +1518,6 @@ function attach_delete($channel_id, $resource, $is_photo = 0) {
*/
call_hooks('attach_delete', $arr);
- file_activity($channel_id, $object, $object['allow_cid'], $object['allow_gid'], $object['deny_cid'], $object['deny_gid'], 'update', true);
-
return;
}
@@ -1542,6 +1552,21 @@ function attach_drop_photo($channel_id,$resource) {
}
+function attach_drop_item($channel_id,$resource) {
+
+ $x = q("select id, item_hidden from item where resource_id = '%s' and resource_type = 'attach' and uid = %d and item_deleted = 0",
+ dbesc($resource),
+ intval($channel_id)
+ );
+
+ if($x) {
+ $stage = (($x[0]['item_hidden']) ? DROPITEM_NORMAL : DROPITEM_PHASE1);
+ $interactive = (($x[0]['item_hidden']) ? false : true);
+ drop_item($x[0]['id'], $interactive, $stage);
+ }
+
+}
+
/**
* @brief Returns path to file in cloud/.
@@ -1743,6 +1768,7 @@ function pipe_streams($in, $out, $bufsize = 16384) {
* @param string $verb
* @param boolean $notify
*/
+/*
function file_activity($channel_id, $object, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $verb, $notify) {
require_once('include/items.php');
@@ -1791,7 +1817,7 @@ function file_activity($channel_id, $object, $allow_cid, $allow_gid, $deny_cid,
$uuid = item_message_id();
$mid = z_root() . '/item/' . $uuid;
- $objtype = ACTIVITY_OBJ_FILE;
+ $objtype = 'ACTIVITY_OBJ_FILE';
$arr = array();
$arr['aid'] = get_account_id();
@@ -1890,6 +1916,148 @@ function file_activity($channel_id, $object, $allow_cid, $allow_gid, $deny_cid,
return;
}
+*/
+
+
+function attach_store_item($channel, $observer, $file) {
+
+
+ if(is_string($file)) {
+ $r = q("SELECT * FROM attach WHERE uid = %d AND hash = '%s' LIMIT 1",
+ intval($channel['channel_id']),
+ dbesc($file)
+ );
+
+ if(! $r)
+ return;
+
+ $file = $r[0];
+
+ }
+
+ $path = z_root() . '/cloud/' . $channel['channel_address'] . '/' . $file['display_path'];
+
+ $r = q("SELECT * FROM item WHERE resource_id = '%s' AND resource_type = 'attach' and uid = %d LIMIT 1",
+ dbesc($file['hash']),
+ intval($channel['channel_id'])
+ );
+
+ if($r) {
+
+ // At the moment only file permission edits are possible.
+ // Since we do not support permission editing on posts yet,
+ // we will delete the item and create a new one with the new permissions for now.
+
+ if($r[0]['allow_cid'] === $file['allow_cid'] && $r[0]['allow_gid'] === $file['allow_gid'] && $r[0]['deny_cid'] === $file['deny_cid'] && $r[0]['deny_gid'] === $file['deny_gid']) {
+
+ /* once possible, other edits (eg rename) can be done here.
+
+ q("UPDATE item SET title = '%s' WHERE id = %d AND uid = %d",
+ dbesc($file['filename'])
+ );
+
+ $meta = [
+ 'name' => $file['filename'],
+ 'type' => $file['filetype'],
+ 'size' => $file['filesize'],
+ 'revision' => $file['revision'],
+ 'size' => $file['filesize'],
+ 'created' => $file['created'],
+ 'edited' => $file['edited'],
+ 'path' => $path
+ ];
+
+ set_iconfig($r[0], 'attach', 'meta' , $meta, true);
+
+ $post = item_store($arr);
+
+ $item_id = $post['item_id'];
+
+ if($item_id) {
+ Master::Summon(['Notifier', 'activity', $item_id]);
+ }
+
+ */
+
+ return;
+
+ }
+
+ $stage = (($r[0]['item_hidden']) ? DROPITEM_NORMAL : DROPITEM_PHASE1);
+ $interactive = (($r[0]['item_hidden']) ? false : true);
+ drop_item($r[0]['id'], $interactive, $stage);
+
+ }
+
+ $filetype_parts = explode('/', $file['filetype']);
+
+ switch($filetype_parts[0]) {
+ case 'image':
+ $type = 'Image';
+ break;
+ case 'audio':
+ $type = 'Audio';
+ break;
+ case 'video':
+ $type = 'Video';
+ break;
+ default:
+ $type = 'Document';
+ }
+
+ $resource_id = $file['hash'];
+ $uuid = new_uuid();
+
+ $mid = z_root() . '/item/' . $uuid;
+
+ $arr = []; // Initialize the array of parameters for the post
+ $arr['aid'] = $channel['channel_account_id'];
+ $arr['uuid'] = $uuid;
+ $arr['uid'] = $channel['channel_id'];
+ $arr['mid'] = $mid;
+ $arr['parent_mid'] = $mid;
+ $arr['resource_type'] = 'attach';
+ $arr['resource_id'] = $resource_id;
+ $arr['owner_xchan'] = $channel['channel_hash'];
+ $arr['author_xchan'] = $observer['xchan_hash'];
+ $arr['title'] = $file['filename'];
+ $arr['allow_cid'] = $file['allow_cid'];
+ $arr['allow_gid'] = $file['allow_gid'];
+ $arr['deny_cid'] = $file['deny_cid'];
+ $arr['deny_gid'] = $file['deny_gid'];
+ $arr['item_wall'] = 1;
+ $arr['item_origin'] = 1;
+ $arr['item_thread_top'] = 1;
+ $arr['item_private'] = (($file['allow_cid'] || $file['allow_gid'] || $file['deny_cid'] || $file['deny_gid']) ? 1 : 0);
+ $arr['verb'] = ACTIVITY_CREATE;
+ $arr['obj_type'] = $type;
+ $arr['title'] = $file['filename'];
+ $body_str = sprintf(t('%s shared a %s with you'), '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]', '[zrl=' . $path . ']' . t('file') . '[/zrl]');
+ $arr['body'] = $body_str;
+
+ $meta = [
+ 'name' => $file['filename'],
+ 'type' => $file['filetype'],
+ 'size' => $file['filesize'],
+ 'revision' => $file['revision'],
+ 'size' => $file['filesize'],
+ 'created' => $file['created'],
+ 'edited' => $file['edited'],
+ 'path' => $path
+ ];
+
+ set_iconfig($arr, 'attach', 'meta' , $meta, true);
+
+ $post = item_store($arr);
+
+ $item_id = $post['item_id'];
+
+ if($item_id) {
+ Master::Summon(['Notifier', 'activity', $item_id]);
+ }
+
+}
+
/**
* @brief Create file activity object.
@@ -1906,17 +2074,28 @@ function get_file_activity_object($channel_id, $hash, $url) {
dbesc($hash)
);
- $url = rawurlencode($url);
-
- $links = array();
- $links[] = array(
+ $links = [];
+ $links[] = [
'rel' => 'alternate',
- 'type' => 'text/html',
+ 'type' => $x[0]['filetype'],
'href' => $url
- );
+ ];
+
+ $filetype_parts = explode('/', $x[0]['filetype']);
+
+ switch($filetype_parts[0]) {
+ case 'audio':
+ $type = 'Audio';
+ break;
+ case 'video':
+ $type = 'Video';
+ break;
+ default:
+ $type = 'Document';
+ }
$object = array(
- 'type' => ACTIVITY_OBJ_FILE,
+ 'type' => $type,
'title' => $x[0]['filename'],
'id' => $url,
'link' => $links,
@@ -2628,6 +2807,12 @@ function save_chunk($channel,$start,$end,$len) {
$new_path = $new_base . '/' . $_FILES['files']['name'];
+ if(file_exists($new_path) && intval($start) === 0) {
+ $result['partial'] = true;
+ $result['length'] = intval(filesize($new_path));
+ return $result;
+ }
+
if(! file_exists($new_path)) {
rename($tmp_path,$new_path);
}
@@ -2654,5 +2839,3 @@ function save_chunk($channel,$start,$end,$len) {
$result['length'] = intval(filesize($new_path));
return $result;
}
-
-
diff --git a/include/auth.php b/include/auth.php
index b952754fd..8eeb077b5 100644
--- a/include/auth.php
+++ b/include/auth.php
@@ -9,6 +9,8 @@
* Also provides a function for OpenID identiy matching.
*/
+use Zotlabs\Lib\Libzot;
+
require_once('include/api_auth.php');
require_once('include/security.php');
@@ -224,12 +226,13 @@ if((isset($_SESSION)) && (x($_SESSION, 'authenticated')) &&
$r = array(atoken_xchan($y[0]));
}
else {
- $r = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where xchan_hash = '%s' limit 1",
+ $r = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where xchan_hash = '%s' and hubloc_deleted = 0",
dbesc($_SESSION['visitor_id'])
);
}
if($r) {
- App::set_observer($r[0]);
+ $r = Libzot::zot_record_preferred($r);
+ App::set_observer($r);
}
else {
unset($_SESSION['visitor_id']);
diff --git a/include/bbcode.php b/include/bbcode.php
index c7dea53c5..d79429719 100644
--- a/include/bbcode.php
+++ b/include/bbcode.php
@@ -218,7 +218,7 @@ function bb_replace_images($body, $images) {
// We're depending on the property of 'foreach' (specified on the PHP website) that
// it loops over the array starting from the first element and going sequentially
// to the last element
- $newbody = str_replace('[$#saved_image' . $cnt . '#$]', '<img src="' . $image .'" alt="' . t('Image/photo') . '" />', $newbody);
+ $newbody = str_replace('[$#saved_image' . $cnt . '#$]', '<img src="' . $image .'" alt="' . t('Image/photo') . '" loading="eager" />', $newbody);
$cnt++;
}
// logger('replace_images: ' . $newbody);
@@ -233,7 +233,7 @@ function bb_replace_images($body, $images) {
*/
function bb_parse_crypt($match) {
- $matches = array();
+ $matches = [];
$attributes = $match[1];
$algorithm = "";
@@ -257,7 +257,17 @@ function bb_parse_crypt($match) {
$x = random_string();
- $Text = '<br /><div id="' . $x . '"><img src="' . z_root() . '/images/lock_icon.gif" onclick="red_decrypt(\'' . $algorithm . '\',\'' . $hint . '\',\'' . $match[2] . '\',\'#' . $x . '\');" alt="' . t('Encrypted content') . '" title="' . t('Encrypted content') . '" /></div><br />';
+ $f = 'hz_decrypt';
+
+ //legacy cryptojs support
+ if(plugin_is_installed('cryptojs')) {
+ $f = ((in_array($algorithm, ['AES-128-CCM', 'rot13', 'triple-rot13'])) ? 'hz_decrypt' : 'red_decrypt');
+ }
+
+ $onclick = 'onclick="' . $f . '(\'' . $algorithm . '\',\'' . $hint . '\',\'' . $match[2] . '\',\'#' . $x . '\');"';
+ $label = t('Encrypted content');
+
+ $Text = '<br /><div id="' . $x . '"><img class="cursor-pointer" src="' . z_root() . '/images/lock_icon.svg" ' . $onclick . ' alt="' . $label . '" title="' . $label . '" /></div><br />';
return $Text;
}
@@ -319,6 +329,139 @@ function translate_design_element($type) {
return $ret;
}
+function bb_format_attachdata($body) {
+
+ $data = getAttachmentData($body);
+
+ if($data) {
+ $txt = '';
+ if($data['url'] && $data['title']) {
+ $txt .= "\n\n" . '[url=' . $data['url'] . ']' . $data['title'] . '[/url]';
+ }
+ else {
+ if($data['url']) {
+ $txt .= "\n\n" . $data['url'];
+ }
+ if($data['title']) {
+ $txt .= "\n\n" . $data['title'];
+ }
+ }
+ if($data['preview']) {
+ $txt .= "\n\n" . '[img]' . $data['preview'] . '[/img]';
+ }
+ if($data['image']) {
+ $txt .= "\n\n" . '[img]' . $data['image'] . '[/img]';
+ }
+
+
+ $txt .= "\n\n" . $data['text'];
+ return preg_replace('/\[attachment(.*?)\](.*?)\[\/attachment\]/ism',$txt,$body);
+ }
+
+ return $body;
+}
+
+function getAttachmentData($body) {
+
+ $data = [];
+
+ if (! preg_match("/\[attachment(.*?)\](.*?)\[\/attachment\]/ism", $body, $match)) {
+ return null;
+ }
+
+ $attributes = $match[1];
+
+ $data["text"] = trim($match[2]);
+
+ $type = "";
+ preg_match("/type='(.*?)'/ism", $attributes, $matches);
+
+ if (x($matches, 1)) {
+ $type = strtolower($matches[1]);
+ }
+
+ preg_match('/type=\&quot\;(.*?)\&quot\;/ism', $attributes, $matches);
+ if (x($matches, 1)) {
+ $type = strtolower($matches[1]);
+ }
+
+ if ($type == "") {
+ return [];
+ }
+
+ if (!in_array($type, ["link", "audio", "photo", "video"])) {
+ return [];
+ }
+
+ if ($type != "") {
+ $data["type"] = $type;
+ }
+ $url = "";
+ preg_match("/url='(.*?)'/ism", $attributes, $matches);
+ if (x($matches, 1)) {
+ $url = $matches[1];
+ }
+
+ preg_match('/url=\&quot\;(.*?)\&quot\;/ism', $attributes, $matches);
+ if (x($matches, 1)) {
+ $url = $matches[1];
+ }
+
+ if ($url != "") {
+ $data["url"] = html_entity_decode($url, ENT_QUOTES, 'UTF-8');
+ }
+
+ $title = "";
+ preg_match("/title='(.*?)'/ism", $attributes, $matches);
+ if (x($matches, 1)) {
+ $title = $matches[1];
+ }
+
+ preg_match('/title=\&quot\;(.*?)\&quot\;/ism', $attributes, $matches);
+ if (x($matches, 1)) {
+ $title = $matches[1];
+ }
+ if ($title != "") {
+ $title = html_entity_decode($title, ENT_QUOTES, 'UTF-8');
+ $title = str_replace(["[", "]"], ["&#91;", "&#93;"], $title);
+ $data["title"] = $title;
+ }
+
+ $image = "";
+ preg_match("/image='(.*?)'/ism", $attributes, $matches);
+ if (x($matches, 1)) {
+ $image = $matches[1];
+ }
+
+ preg_match('/image=\&quot\;(.*?)\&quot\;/ism', $attributes, $matches);
+ if (x($matches, 1)) {
+ $image = $matches[1];
+ }
+
+ if ($image != "") {
+ $data["image"] = html_entity_decode($image, ENT_QUOTES, 'UTF-8');
+ }
+
+ $preview = "";
+ preg_match("/preview='(.*?)'/ism", $attributes, $matches);
+ if (x($matches, 1)) {
+ $preview = $matches[1];
+ }
+
+ preg_match('/preview=\&quot\;(.*?)\&quot\;/ism', $attributes, $matches);
+ if (x($matches, 1)) {
+ $preview = $matches[1];
+ }
+ if ($preview != "") {
+ $data["preview"] = html_entity_decode($preview, ENT_QUOTES, 'UTF-8');
+ }
+
+ $data["description"] = trim($match[3]);
+
+ $data["after"] = trim($match[4]);
+
+ return $data;
+}
function bb_ShareAttributes($match) {
@@ -370,7 +513,7 @@ function bb_ShareAttributes($match) {
$headline = '<div id="shared_container_' . $rnd . '" class="shared_container"> <div id="shared_header_' . $rnd . '" class="shared_header">';
if ($avatar != "")
- $headline .= '<a href="' . (($auth) ? zid($profile) : $profile) . '" ><img src="' . $avatar . '" alt="' . $author . '" height="32" width="32" /></a>';
+ $headline .= '<a href="' . (($auth) ? zid($profile) : $profile) . '" ><img src="' . $avatar . '" alt="' . $author . '" height="32" width="32" loading="lazy" /></a>';
if(strpos($link,'/cards/'))
$type = t('card');
@@ -382,7 +525,7 @@ function bb_ShareAttributes($match) {
// Bob Smith wrote the following post 2 hours ago
$fmt = sprintf( t('%1$s wrote the following %2$s %3$s'),
- '<a href="' . (($auth) ? zid($profile) : $profile) . '" >' . $author . '</a>',
+ '<a href="' . (($auth) ? zid($profile) : $profile) . '" ><bdi>' . $author . '</bdi></a>',
'<a href="' . (($auth) ? zid($link) : $link) . '" >' . $type . '</a>',
$reldate
);
@@ -655,6 +798,109 @@ function bb_observer($Text) {
return $Text;
}
+function bb_imgoptions($match) {
+
+ // $Text = preg_replace_callback("/\[([zi])mg([ \=])(.*?)\](.*?)\[\/[zi]mg\]/ism",'bb_imgoptions',$Text);
+ // alt text cannot contain ']'
+
+ // [img|zmg=wwwxhhh float=left|right alt=alt text]url[/img|zmg]
+
+ $local_match = null;
+ $width = 0;
+ $float = false;
+ $alt = false;
+
+ $style = EMPTY_STR;
+
+ $attributes = $match[3];
+
+ $x = preg_match("/alt='(.*?)'/ism", $attributes, $matches);
+ if ($x) {
+ $alt = $matches[1];
+ }
+
+ $x = preg_match("/alt=\&quot\;(.*?)\&quot\;/ism", $attributes, $matches);
+ if ($x) {
+ $alt = $matches[1];
+ }
+
+ $x = preg_match("/width='(.*?)'/ism", $attributes, $matches);
+ if ($x) {
+ $width = $matches[1];
+ }
+
+ $x = preg_match("/width=\&quot\;(.*?)\&quot\;/ism", $attributes, $matches);
+ if ($x) {
+ $width = $matches[1];
+ }
+
+ $x = preg_match("/height='(.*?)'/ism", $attributes, $matches);
+ if ($x) {
+ $height = $matches[1];
+ }
+
+ $x = preg_match("/height=\&quot\;(.*?)\&quot\;/ism", $attributes, $matches);
+ if ($x) {
+ $height = $matches[1];
+ }
+
+ $x = preg_match("/style='(.*?)'/ism", $attributes, $matches);
+ if ($x) {
+ $style = $matches[1];
+ }
+
+ $x = preg_match("/style=\&quot\;(.*?)\&quot\;/ism", $attributes, $matches);
+ if ($x) {
+ $style = $matches[1];
+ }
+
+ // legacy img options
+
+ if ($match[2] === '=') {
+ // pull out (optional) legacy size declarations first
+ if (preg_match("/([0-9]*)x([0-9]*)/ism",$match[3],$local_match)) {
+ $width = intval($local_match[1]);
+ }
+ $match[3] = substr($match[3],strpos($match[3],' '));
+ }
+
+ // then (optional) legacy float specifiers
+ if ($n = strpos($match[3],'float=left') !== false) {
+ $float = 'left';
+ $match[3] = substr($match[3],$n + 10);
+ }
+ if ($n = strpos($match[3],'float=right') !== false) {
+ $float = 'right';
+ $match[3] = substr($match[3],$n + 11);
+ }
+
+ // finally alt text which extends to the close of the tag
+ if ((! $alt) && ($n = strpos($match[3],'alt=') !== false)) {
+ $alt = substr($match[3],$n + 4);
+ }
+
+ // now assemble the resulting img tag from these components
+
+ $output = '<img ' . (($match[1] === 'z') ? 'class="zrl" loading="eager"' : '') . ' ';
+
+ if ($width) {
+ $style .= 'width: 100%; max-width: ' . $width . 'px; ';
+ }
+ else {
+ $style .= 'max-width: 100%; ';
+ }
+ if ($float) {
+ $style .= 'float: ' . $float . '; ';
+ }
+
+ $output .= (($style) ? 'style="' . $style . '" ' : '') . 'alt="' . htmlentities(($alt) ? $alt : t('Image/photo'),ENT_COMPAT,'UTF-8') . '" ';
+
+ $output .= 'src="' . $match[4] . '" >';
+
+ return $output;
+
+}
+
function bb_code_protect($s) {
return 'b64.^9e%.' . base64_encode($s) . '.b64.$9e%';
}
@@ -832,6 +1078,8 @@ function bbcode($Text, $options = []) {
$Text = preg_replace_callback("/\[pre\](.*?)\[\/pre\]/ism", 'bb_spacefy',$Text);
}
+ $Text = bb_format_attachdata($Text);
+
// If we find any event code, turn it into an event.
// After we're finished processing the bbcode we'll
// replace all of the event code with a reformatted version.
@@ -1111,6 +1359,12 @@ function bbcode($Text, $options = []) {
if (strpos($Text,'[/footer]') !== false) {
$Text = preg_replace("(\[footer\](.*?)\[\/footer\])ism", "<div class=\"wall-item-footer\">$1</div>", $Text);
}
+
+ // Check for bdi
+ if (strpos($Text,'[/bdi]') !== false) {
+ $Text = preg_replace("(\[bdi\](.*?)\[\/bdi\])ism", "<bdi>$1</bdi>", $Text);
+ }
+
// Check for list text
$Text = preg_replace("/<br \/>\[\*\]/ism",'[*]',$Text);
@@ -1229,47 +1483,22 @@ function bbcode($Text, $options = []) {
// Images
// [img]pathtoimage[/img]
if (strpos($Text,'[/img]') !== false) {
- $Text = preg_replace("/\[img\](.*?)\[\/img\]/ism", '<img style="max-width: 100%;" src="$1" alt="' . t('Image/photo') . '" />', $Text);
- }
- if (strpos($Text,'[/zmg]') !== false) {
- $Text = preg_replace("/\[zmg\](.*?)\[\/zmg\]/ism", '<img class="zrl" style="max-width: 100%;" src="$1" alt="' . t('Image/photo') . '" />', $Text);
- }
-
- // [img float={left, right}]pathtoimage[/img]
- if (strpos($Text,'[/img]') !== false) {
- $Text = preg_replace("/\[img float=left\](.*?)\[\/img\]/ism", '<img src="$1" style="max-width: 100%; float: left;" alt="' . t('Image/photo') . '" />', $Text);
+ $Text = preg_replace("/\[img\](.*?)\[\/img\]/ism", '<img style="max-width: 100%;" src="$1" alt="' . t('Image/photo') . '" loading="eager" />', $Text);
}
+ // [img=pathtoimage]image description[/img]
if (strpos($Text,'[/img]') !== false) {
- $Text = preg_replace("/\[img float=right\](.*?)\[\/img\]/ism", '<img src="$1" style="max-width: 100%; float: right;" alt="' . t('Image/photo') . '" />', $Text);
- }
- if (strpos($Text,'[/zmg]') !== false) {
- $Text = preg_replace("/\[zmg float=left\](.*?)\[\/zmg\]/ism", '<img class="zrl" src="$1" style="max-width: 100%; float: left;" alt="' . t('Image/photo') . '" />', $Text);
+ $Text = preg_replace("/\[img=http(.*?)\](.*?)\[\/img\]/ism", '<img style="max-width: 100%;" src="http$1" alt="$2" title="$2" loading="eager" />', $Text);
}
+ // [zmg]pathtoimage[/zmg]
if (strpos($Text,'[/zmg]') !== false) {
- $Text = preg_replace("/\[zmg float=right\](.*?)\[\/zmg\]/ism", '<img class="zrl" src="$1" style="max-width: 100%; float: right;" alt="' . t('Image/photo') . '" />', $Text);
- }
-
- // [img=widthxheight]pathtoimage[/img]
- if (strpos($Text,'[/img]') !== false) {
- $Text = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '<img src="$3" style="width: 100%; max-width: $1px;" alt="' . t('Image/photo') . '" />', $Text);
+ $Text = preg_replace("/\[zmg\](.*?)\[\/zmg\]/ism", '<img class="zrl" style="max-width: 100%;" src="$1" alt="' . t('Image/photo') . '" loading="eager" />', $Text);
}
+ // [zmg=pathtoimage]image description[/zmg]
if (strpos($Text,'[/zmg]') !== false) {
- $Text = preg_replace("/\[zmg\=([0-9]*)x([0-9]*)\](.*?)\[\/zmg\]/ism", '<img class="zrl" src="$3" style="width: 100%; max-width: $1px;" alt="' . t('Image/photo') . '" />', $Text);
+ $Text = preg_replace("/\[zmg=http(.*?)\](.*?)\[\/zmg\]/ism", '<img class="zrl" style="max-width: 100%;" src="http$1" alt="$2" title="$2" loading="eager" />', $Text);
}
- // [img=widthxheight float={left, right}]pathtoimage[/img]
- if (strpos($Text,'[/img]') !== false) {
- $Text = preg_replace("/\[img\=([0-9]*)x([0-9]*) float=left\](.*?)\[\/img\]/ism", '<img src="$3" style="width: 100%; max-width: $1px; float: left;" alt="' . t('Image/photo') . '" />', $Text);
- }
- if (strpos($Text,'[/img]') !== false) {
- $Text = preg_replace("/\[img\=([0-9]*)x([0-9]*) float=right\](.*?)\[\/img\]/ism", '<img src="$3" style="width: 100%; max-width: $1px; float: right;" alt="' . t('Image/photo') . '" />', $Text);
- }
- if (strpos($Text,'[/zmg]') !== false) {
- $Text = preg_replace("/\[zmg\=([0-9]*)x([0-9]*) float=left\](.*?)\[\/zmg\]/ism", '<img class="zrl" src="$3" style="width: 100%; max-width: $1px; float: left;" alt="' . t('Image/photo') . '" />', $Text);
- }
- if (strpos($Text,'[/zmg]') !== false) {
- $Text = preg_replace("/\[zmg\=([0-9]*)x([0-9]*) float=right\](.*?)\[\/zmg\]/ism", '<img class="zrl" src="$3" style="width: 100%; max-width: $1px; float: right;" alt="' . t('Image/photo') . '" />', $Text);
- }
+ $Text = preg_replace_callback("/\[([zi])mg([ \=])(.*?)\](.*?)\[\/[zi]mg\]/ism",'bb_imgoptions',$Text);
// style (sanitized)
if (strpos($Text,'[/style]') !== false) {
@@ -1279,7 +1508,7 @@ function bbcode($Text, $options = []) {
// crypt
if (strpos($Text,'[/crypt]') !== false) {
$x = random_string();
- $Text = preg_replace("/\[crypt\](.*?)\[\/crypt\]/ism",'<br /><div id="' . $x . '"><img src="' .z_root() . '/images/lock_icon.gif" onclick="red_decrypt(\'rot13\',\'\',\'$1\',\'#' . $x . '\');" alt="' . t('Encrypted content') . '" title="' . t('Encrypted content') . '" /><br /></div>', $Text);
+ $Text = preg_replace("/\[crypt\](.*?)\[\/crypt\]/ism",'<br /><div id="' . $x . '"><img class="cursor-pointer" src="' .z_root() . '/images/lock_icon.svg" onclick="red_decrypt(\'rot13\',\'\',\'$1\',\'#' . $x . '\');" alt="' . t('Encrypted content') . '" title="' . t('Encrypted content') . '" /><br /></div>', $Text);
$Text = preg_replace_callback("/\[crypt (.*?)\](.*?)\[\/crypt\]/ism", 'bb_parse_crypt', $Text);
}
diff --git a/include/cdav.php b/include/cdav.php
new file mode 100644
index 000000000..ef248a9fe
--- /dev/null
+++ b/include/cdav.php
@@ -0,0 +1,186 @@
+<?php
+
+/**
+ * @brief Process CardDAV card
+ *
+ * @param array $f fields
+ * @param obj $vcard SabreDAV object
+ * @param bool $edit update card
+ *
+ */
+
+function process_cdav_card($f, &$vcard, $edit = false) {
+
+ if($f['org'])
+ $vcard->ORG = $f['org'];
+ else
+ if($edit)
+ unset($vcard->ORG);
+
+
+ if($f['title'])
+ $vcard->TITLE = $f['title'];
+ else
+ if($edit)
+ unset($vcard->TITLE);
+
+ if($edit)
+ unset($vcard->TEL);
+ if($f['tel']) {
+ $i = 0;
+ foreach($f['tel'] as $item) {
+ if($item) {
+ $vcard->add('TEL', $item, ['type' => $f['tel_type'][$i]]);
+ }
+ $i++;
+ }
+ }
+
+ if($edit)
+ unset($vcard->EMAIL);
+ if($f['email']) {
+ $i = 0;
+ foreach($f['email'] as $item) {
+ if($item) {
+ $vcard->add('EMAIL', $item, ['type' => $f['email_type'][$i]]);
+ }
+ $i++;
+ }
+ }
+
+ if($edit)
+ unset($vcard->IMPP);
+ if($f['impp']) {
+ $i = 0;
+ foreach($f['impp'] as $item) {
+ if($item) {
+ $vcard->add('IMPP', $item, ['type' => $f['impp_type'][$i]]);
+ }
+ $i++;
+ }
+ }
+
+ if($edit)
+ unset($vcard->URL);
+ if($f['url']) {
+ $i = 0;
+ foreach($f['url'] as $item) {
+ if($item) {
+ $vcard->add('URL', $item, ['type' => $f['url_type'][$i]]);
+ }
+ $i++;
+ }
+ }
+
+ if($edit)
+ unset($vcard->ADR);
+ if($f['adr']) {
+ $i = 0;
+ foreach($f['adr'] as $item) {
+ if($item) {
+ $vcard->add('ADR', $item, ['type' => $f['adr_type'][$i]]);
+ }
+ $i++;
+ }
+ }
+
+ if($f['note']) {
+ $vcard->NOTE = $f['note'];
+ }
+ else
+ if($edit)
+ unset($vcard->NOTE);
+}
+
+
+/**
+ * @brief Import CardDAV or CalDAV card
+ *
+ * @param mixed $id card id
+ * @param str $ext card extension
+ * @param str $table name
+ * @param str $column name
+ * @param obj $objects
+ * @param str $profile
+ * @param obj $backend
+ * @param array $ids
+ * @param bool $notice
+ *
+ */
+
+function import_cdav_card($id, $ext, $table, $column, $objects, $profile, $backend, &$ids, $notice = false) {
+
+ $i = 0;
+ $newid = (count($ids) ? false : true);
+
+ while ($object = $objects->getNext()) {
+
+ if($_REQUEST['a_upload'])
+ $object = $object->convert(\Sabre\VObject\Document::VCARD40);
+
+ $ret = $object->validate($profile & \Sabre\VObject\Node::REPAIR);
+
+ //level 3 Means that the document is invalid,
+ //level 2 means a warning. A warning means it's valid but it could cause interopability issues,
+ //level 1 means that there was a problem earlier, but the problem was automatically repaired.
+
+ if($ret[0]['level'] < 3) {
+
+ if($newid) {
+ do {
+ $duplicate = false;
+ $objectUri = random_string(40) . '.' . $ext;
+
+ $r = q("SELECT uri FROM $table WHERE $column = %d AND uri = '%s' LIMIT 1",
+ dbesc($id),
+ dbesc($objectUri)
+ );
+ if (count($r))
+ $duplicate = true;
+ } while ($duplicate == true);
+ $ids[$i] = $objectUri;
+ }
+ else
+ $objectUri = $ids[$i];
+
+ $i++;
+
+ if($ext == 'ics')
+ $backend->createCalendarObject($id, $objectUri, $object->serialize());
+
+ if($ext == 'vcf')
+ $backend->createCard($id, $objectUri, $object->serialize());
+ }
+ else {
+ if($notice && $ext == 'ics') {
+ notice(
+ '<strong>' . t('INVALID EVENT DISMISSED!') . '</strong>' . EOL .
+ '<strong>' . t('Summary: ') . '</strong>' . (($object->VEVENT->SUMMARY) ? $object->VEVENT->SUMMARY : t('Unknown')) . EOL .
+ '<strong>' . t('Date: ') . '</strong>' . (($object->VEVENT->DTSTART) ? $object->VEVENT->DTSTART : t('Unknown')) . EOL .
+ '<strong>' . t('Reason: ') . '</strong>' . $ret[0]['message'] . EOL
+ );
+ }
+
+ if($notice && $exp == 'vcf') {
+ notice(
+ '<strong>' . t('INVALID CARD DISMISSED!') . '</strong>' . EOL .
+ '<strong>' . t('Name: ') . '</strong>' . (($object->FN) ? $object->FN : t('Unknown')) . EOL .
+ '<strong>' . t('Reason: ') . '</strong>' . $ret[0]['message'] . EOL
+ );
+ }
+ }
+ }
+}
+
+
+function get_cdav_id($principaluri, $uri, $table) {
+
+ $r = q("SELECT * FROM $table WHERE principaluri = '%s' AND uri = '%s' LIMIT 1",
+ dbesc($principaluri),
+ dbesc($uri)
+ );
+ if(! $r)
+ return false;
+
+ return $r[0];
+}
diff --git a/include/channel.php b/include/channel.php
index 29835eac6..e2be4d8a8 100644
--- a/include/channel.php
+++ b/include/channel.php
@@ -4,6 +4,7 @@
* @brief Channel related functions.
*/
+
use Zotlabs\Access\PermissionRoles;
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Access\Permissions;
@@ -11,6 +12,8 @@ use Zotlabs\Daemon\Master;
use Zotlabs\Lib\System;
use Zotlabs\Render\Comanche;
use Zotlabs\Lib\Libzot;
+use Zotlabs\Lib\Connect;
+use Zotlabs\Lib\Libsync;
require_once('include/zot.php');
require_once('include/crypto.php');
@@ -126,10 +129,10 @@ function create_sys_channel() {
* @return array|boolean
*/
function get_sys_channel() {
- $r = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_system = 1 limit 1");
+ $r = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_system = 1");
if ($r)
- return $r[0];
+ return Libzot::zot_record_preferred($r, 'xchan_network');
return false;
}
@@ -228,12 +231,16 @@ function create_identity($arr) {
return $ret;
}
- $guid = zot_new_uid($nick);
+ $guid = Libzot::new_uid($nick);
$key = new_keypair(4096);
- $sig = base64url_encode(rsa_sign($guid,$key['prvkey']));
- $hash = make_xchan_hash($guid,$sig);
- $zhash = Libzot::make_xchan_hash($guid,$key['pubkey']);
+ // legacy zot
+ $zsig = base64url_encode(rsa_sign($guid,$key['prvkey']));
+ $zhash = make_xchan_hash($guid,$zsig);
+
+ // zot6
+ $sig = Libzot::sign($guid,$key['prvkey']);
+ $hash = Libzot::make_xchan_hash($guid,$key['pubkey']);
// Force a few things on the short term until we can provide a theme or app with choice
@@ -332,8 +339,9 @@ function create_identity($arr) {
$r = hubloc_store_lowlevel(
[
'hubloc_guid' => $guid,
- 'hubloc_guid_sig' => $sig,
- 'hubloc_hash' => $hash,
+ 'hubloc_guid_sig' => $zsig,
+ 'hubloc_hash' => $zhash,
+ 'hubloc_id_url' => channel_url($ret['channel']),
'hubloc_addr' => channel_reddress($ret['channel']),
'hubloc_primary' => intval($primary),
'hubloc_url' => z_root(),
@@ -346,18 +354,18 @@ function create_identity($arr) {
]
);
if(! $r)
- logger('Unable to store hub location');
+ logger('Unable to store hub location (zot)');
$r = hubloc_store_lowlevel(
[
'hubloc_guid' => $guid,
- 'hubloc_guid_sig' => 'sha256.' . $sig,
- 'hubloc_hash' => $zhash,
- 'hubloc_id_url' => channel_url($ret['channel']),
+ 'hubloc_guid_sig' => $sig,
+ 'hubloc_hash' => $hash,
+ 'hubloc_id_url' => channel_url($ret['channel']),
'hubloc_addr' => channel_reddress($ret['channel']),
'hubloc_primary' => intval($primary),
'hubloc_url' => z_root(),
- 'hubloc_url_sig' => 'sha256.' . base64url_encode(rsa_sign(z_root(),$ret['channel']['channel_prvkey'])),
+ 'hubloc_url_sig' => Libzot::sign(z_root(),$ret['channel']['channel_prvkey']),
'hubloc_site_id' => Libzot::make_xchan_hash(z_root(),get_config('system','pubkey')),
'hubloc_host' => App::get_hostname(),
'hubloc_callback' => z_root() . '/zot',
@@ -367,16 +375,16 @@ function create_identity($arr) {
]
);
if(! $r)
- logger('Unable to store hub location');
+ logger('Unable to store hub location (zot6)');
$newuid = $ret['channel']['channel_id'];
$r = xchan_store_lowlevel(
[
- 'xchan_hash' => $hash,
+ 'xchan_hash' => $zhash,
'xchan_guid' => $guid,
- 'xchan_guid_sig' => $sig,
+ 'xchan_guid_sig' => $zsig,
'xchan_pubkey' => $key['pubkey'],
'xchan_photo_mimetype' => (($photo_type) ? $photo_type : 'image/png'),
'xchan_photo_l' => z_root() . "/photo/profile/l/{$newuid}",
@@ -393,12 +401,14 @@ function create_identity($arr) {
'xchan_system' => $system
]
);
+ if(! $r)
+ logger('Unable to store xchan (zot)');
$r = xchan_store_lowlevel(
[
- 'xchan_hash' => $zhash,
+ 'xchan_hash' => $hash,
'xchan_guid' => $guid,
- 'xchan_guid_sig' => 'sha256.' . $sig,
+ 'xchan_guid_sig' => $sig,
'xchan_pubkey' => $key['pubkey'],
'xchan_photo_mimetype' => (($photo_type) ? $photo_type : 'image/png'),
'xchan_photo_l' => z_root() . "/photo/profile/l/{$newuid}",
@@ -415,6 +425,8 @@ function create_identity($arr) {
'xchan_system' => $system
]
);
+ if(! $r)
+ logger('Unable to store xchan (zot6)');
@@ -521,13 +533,22 @@ function create_identity($arr) {
$accts = get_config('system','auto_follow');
if(($accts) && (! $total_identities)) {
- require_once('include/follow.php');
if(! is_array($accts))
$accts = array($accts);
foreach($accts as $acct) {
- if(trim($acct))
- new_contact($newuid,trim($acct),$ret['channel'],false);
+ $acct = trim($acct);
+ if($acct) {
+ $f = connect_and_sync($ret['channel'], $acct);
+ if($f['success']) {
+ $can_view_stream = their_perms_contains($ret['channel']['channel_id'],$f['abook']['abook_xchan'],'view_stream');
+
+ // If we can view their stream, pull in some posts
+ if(($can_view_stream) || ($f['abook']['xchan_network'] === 'rss')) {
+ Master::Summon([ 'Onepoll',$f['abook']['abook_id'] ]);
+ }
+ }
+ }
}
}
@@ -539,6 +560,7 @@ function create_identity($arr) {
call_hooks('create_identity', $newuid);
Master::Summon(array('Directory', $ret['channel']['channel_id']));
+
}
$ret['success'] = true;
@@ -546,6 +568,35 @@ function create_identity($arr) {
}
+function connect_and_sync($channel,$address, $sub_channel = false) {
+
+ if((! $channel) || (! $address)) {
+ return false;
+ }
+
+ $f = Connect::connect($channel,$address, $sub_channel);
+ if($f['success']) {
+ $clone = [];
+ foreach($f['abook'] as $k => $v) {
+ if(strpos($k,'abook_') === 0) {
+ $clone[$k] = $v;
+ }
+ }
+ unset($clone['abook_id']);
+ unset($clone['abook_account']);
+ unset($clone['abook_channel']);
+
+ $abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']);
+ if($abconfig) {
+ $clone['abconfig'] = $abconfig;
+ }
+
+ Libsync::build_sync_packet($channel['channel_id'], [ 'abook' => [ $clone ] ], true);
+ return $f;
+ }
+ return false;
+}
+
function change_channel_keys($channel) {
$ret = array('success' => false);
@@ -624,7 +675,7 @@ function change_channel_keys($channel) {
}
}
- build_sync_packet($channel['channel_id'], [ 'keychange' => $stored ]);
+ Libsync::build_sync_packet($channel['channel_id'], [ 'keychange' => $stored ]);
$a = q("select * from abook where abook_xchan = '%s' and abook_self = 1",
dbesc($stored['old_hash'])
@@ -796,7 +847,7 @@ function get_default_export_sections() {
* @return array
* See function for details
*/
-function identity_basic_export($channel_id, $sections = null) {
+function identity_basic_export($channel_id, $sections = null, $zap_compat = false) {
/*
* basic channel export
@@ -812,12 +863,16 @@ function identity_basic_export($channel_id, $sections = null) {
// with a non-standard platform and version.
$ret['compatibility'] = [
- 'project' => PLATFORM_NAME,
+ 'project' => (($zap_compat) ? 'zap' : PLATFORM_NAME),
'version' => STD_VERSION,
'database' => DB_UPDATE_VERSION,
'server_role' => System::get_server_role()
];
+ if ($zap_compat) {
+ $ret['compatibility']['codebase'] = 'zap';
+ }
+
/*
* Process channel information regardless of it is one of the sections desired
* because we need the channel relocation information in all export files/streams.
@@ -834,6 +889,13 @@ function identity_basic_export($channel_id, $sections = null) {
unset($ret['channel']['channel_password']);
unset($ret['channel']['channel_salt']);
}
+ if ($zap_compat) {
+ $channel['channel_guid_sig'] = 'sha256.' . $channel['channel_guid_sig'];
+ $channel['channel_hash'] = $channel['channel_portable_id'];
+ unset($channel['channel_portable_id']);
+ }
+
+
}
if(in_array('channel',$sections) || in_array('profile',$sections)) {
@@ -853,7 +915,7 @@ function identity_basic_export($channel_id, $sections = null) {
$ret['photo'] = [
'type' => $r[0]['mimetype'],
'data' => (($r[0]['os_storage'])
- ? base64url_encode(file_get_contents($r[0]['content'])) : base64url_encode($r[0]['content']))
+ ? base64url_encode(file_get_contents($r[0]['content'])) : base64url_encode(dbunescbin($r[0]['content'])))
];
}
}
@@ -867,11 +929,38 @@ function identity_basic_export($channel_id, $sections = null) {
$ret['abook'] = $r;
for($x = 0; $x < count($ret['abook']); $x ++) {
+
$xchans[] = $ret['abook'][$x]['abook_xchan'];
+ $my_perms = [];
+ $their_perms = [];
+ $newconfig = [];
$abconfig = load_abconfig($channel_id,$ret['abook'][$x]['abook_xchan']);
- if($abconfig)
- $ret['abook'][$x]['abconfig'] = $abconfig;
+ if($abconfig) {
+ foreach ($abconfig as $abc) {
+
+ if ($abc['cat'] === 'my_perms' && intval($abc['v'])) {
+ $my_perms[] = $abc['k'];
+ continue;
+ }
+ if ($abc['cat'] === 'their_perms' && intval($abc['v'])) {
+ $their_perms[] = $abc['k'];
+ continue;
+ }
+ if ($zap_compat && preg_match('|^a:[0-9]+:{.*}$|s', $abc['v'])) {
+ $abc['v'] = serialise(unserialize($abc['v']));
+ }
+ $newconfig[] = $abc;
+ }
+
+ $ret['abook'][$x]['abconfig'] = $newconfig;
+ if ($zap_compat) {
+ $ret['abook'][$x]['abconfig'][] = [ 'chan' => $channel_id, 'xchan' => $ret['abook'][$x]['abook_chan'], 'cat' => 'system', 'k' => 'my_perms', 'v' => implode(',',$my_perms) ];
+ $ret['abook'][$x]['abconfig'][] = [ 'chan' => $channel_id, 'xchan' => $ret['abook'][$x]['abook_chan'], 'cat' => 'system', 'k' => 'their_perms', 'v' => implode(',',$their_perms) ];
+ }
+ }
+
translate_abook_perms_outbound($ret['abook'][$x]);
+
}
// pick up the zot6 xchan and hublocs also
@@ -911,8 +1000,17 @@ function identity_basic_export($channel_id, $sections = null) {
$r = q("select * from pconfig where uid = %d",
intval($channel_id)
);
- if($r)
+
+ if($r) {
+ if ($zap_compat) {
+ for($x = 0; $x < count($r); $x ++) {
+ if (preg_match('|^a:[0-9]+:{.*}$|s', $r[$x]['v'])) {
+ $r[$x]['v'] = serialise(unserialize($r[$x]['v']));
+ }
+ }
+ }
$ret['config'] = $r;
+ }
// All other term types will be included in items, if requested.
@@ -1827,15 +1925,16 @@ function zid_init() {
call_hooks('zid_init', $arr);
if(! local_channel()) {
- $r = q("select * from hubloc where hubloc_addr = '%s' order by hubloc_connected desc",
+ $r = q("select hubloc_url, hubloc_hash, hubloc_network from hubloc where hubloc_addr = '%s' order by hubloc_connected desc",
dbesc($tmp_str)
);
if(! $r) {
Master::Summon(array('Gprobe',bin2hex($tmp_str)));
}
if($r) {
- $r = zot_record_preferred($r);
+ $r = Libzot::zot_record_preferred($r);
}
+
if($r && remote_channel() && remote_channel() === $r['hubloc_hash'])
return;
@@ -2145,7 +2244,7 @@ function profiles_build_sync($channel_id,$send = true) {
);
if($r) {
if($send) {
- build_sync_packet($channel_id,array('profile' => $r));
+ Libsync::build_sync_packet($channel_id,array('profile' => $r));
}
else {
return $r;
@@ -2285,8 +2384,8 @@ function get_zcard($channel, $observer_hash = '', $args = array()) {
$cover = $r[0];
$cover['href'] = z_root() . '/photo/' . $r[0]['resource_id'] . '-' . $r[0]['imgscale'];
} else {
- $default_cover = get_config('system','default_cover_photo','pexels-94622');
- $cover = [ 'href' => z_root() . '/images/default_cover_photos/' . $default_cover . '/' . $cover_width . '.jpg' ];
+ $default_cover = get_config('system','default_cover_photo','bggenerator');
+ $cover = [ 'href' => z_root() . '/images/default_cover_photos/' . $default_cover . '/' . $cover_width . '.png' ];
}
$o .= replace_macros(get_markup_template('zcard.tpl'), array(
@@ -2359,8 +2458,8 @@ function get_zcard_embed($channel, $observer_hash = '', $args = array()) {
$cover['href'] = z_root() . '/photo/' . $r[0]['resource_id'] . '-' . $r[0]['imgscale'];
}
else {
- $default_cover = get_config('system','default_cover_photo','pexels-94622');
- $cover = [ 'href' => z_root() . '/images/default_cover_photos/' . $default_cover . '/' . $cover_width . '.jpg' ];
+ $default_cover = get_config('system','default_cover_photo','bggenerator');
+ $cover = [ 'href' => z_root() . '/images/default_cover_photos/' . $default_cover . '/' . $cover_width . '.png' ];
}
$o .= replace_macros(get_markup_template('zcard_embed.tpl'),array(
@@ -2390,6 +2489,12 @@ function channelx_by_nick($nick) {
$nick = punify($nick);
+ // return a cached copy if there is a cached copy and it's a match
+
+ if (App::$channel && is_array(App::$channel) && array_key_exists('channel_address',App::$channel) && App::$channel['channel_address'] === $nick) {
+ return App::$channel;
+ }
+
$r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_address = '%s' and channel_removed = 0 LIMIT 1",
dbesc($nick)
);
@@ -2404,6 +2509,11 @@ function channelx_by_nick($nick) {
* @return array|boolean false if channel ID not found, otherwise the channel array
*/
function channelx_by_hash($hash) {
+
+ if (App::$channel && is_array(App::$channel) && array_key_exists('channel_hash',App::$channel) && App::$channel['channel_hash'] === $hash) {
+ return App::$channel;
+ }
+
$r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_hash = '%s' and channel_removed = 0 LIMIT 1",
dbesc($hash)
);
@@ -2419,6 +2529,11 @@ function channelx_by_hash($hash) {
* @return array|boolean false if channel ID not found, otherwise the channel array
*/
function channelx_by_portid($hash) {
+
+ if (App::$channel && is_array(App::$channel) && array_key_exists('channel_portable_id',App::$channel) && intval(App::$channel['channel_portable_id']) === intval($hash)) {
+ return App::$channel;
+ }
+
$r = q("SELECT * FROM channel left join xchan on channel_portable_id = xchan_hash WHERE channel_portable_id = '%s' and channel_removed = 0 LIMIT 1",
dbesc($hash)
);
@@ -2433,6 +2548,11 @@ function channelx_by_portid($hash) {
* @return array|boolean false if channel ID not found, otherwise the channel array
*/
function channelx_by_n($id) {
+
+ if (App::$channel && is_array(App::$channel) && array_key_exists('channel_id',App::$channel) && intval(App::$channel['channel_id']) === intval($id)) {
+ return App::$channel;
+ }
+
$r = q("SELECT * FROM channel LEFT JOIN xchan ON channel_hash = xchan_hash WHERE channel_id = %d AND channel_removed = 0 LIMIT 1",
dbesc($id)
);
@@ -2596,6 +2716,9 @@ function account_remove($account_id, $local = true, $unset_session = true) {
logger('account_remove: ' . $account_id);
+ // Global removal (all clones) not currently supported
+ $local = true;
+
if(! intval($account_id)) {
logger('No account.');
return false;
@@ -2656,6 +2779,11 @@ function channel_remove($channel_id, $local = true, $unset_session = false) {
if(! $channel_id)
return;
+ // global removal (all clones) not currently supported
+ // hence this operation _may_ leave orphan data on remote servers
+
+ $local = true;
+
logger('Removing channel: ' . $channel_id);
logger('local only: ' . intval($local));
@@ -2674,6 +2802,7 @@ function channel_remove($channel_id, $local = true, $unset_session = false) {
*/
call_hooks('channel_remove', $r[0]);
+/*
if(! $local) {
if(intval($r[0]['channel_removed'])) {
@@ -2693,17 +2822,20 @@ function channel_remove($channel_id, $local = true, $unset_session = false) {
logger('deleting hublocs',LOGGER_DEBUG);
- $r = q("update hubloc set hubloc_deleted = 1 where hubloc_hash = '%s'",
- dbesc($channel['channel_hash'])
+ $r = q("UPDATE hubloc SET hubloc_deleted = 1 WHERE hubloc_hash = '%s' OR hubloc_hash = '%s'",
+ dbesc($channel['channel_hash']),
+ dbesc($channel['channel_portable_id'])
+
);
- $r = q("update xchan set xchan_deleted = 1 where xchan_hash = '%s'",
- dbesc($channel['channel_hash'])
+ $r = q("UPDATE xchan SET xchan_deleted = 1 WHERE xchan_hash = '%s' OR xchan_hash = '%s'",
+ dbesc($channel['channel_hash']),
+ dbesc($channel['channel_portable_id'])
);
Master::Summon(array('Notifier','purge_all',$channel_id));
}
-
+*/
$r = q("select iid from iconfig left join item on item.id = iconfig.iid
where item.uid = %d",
@@ -2782,8 +2914,9 @@ function channel_remove($channel_id, $local = true, $unset_session = false) {
logger('deleting hublocs',LOGGER_DEBUG);
- $r = q("update hubloc set hubloc_deleted = 1 where hubloc_hash = '%s' and hubloc_url = '%s' ",
+ $r = q("UPDATE hubloc SET hubloc_deleted = 1 WHERE (hubloc_hash = '%s' OR hubloc_hash = '%s') AND hubloc_url = '%s' ",
dbesc($channel['channel_hash']),
+ dbesc($channel['channel_portable_id']),
dbesc(z_root())
);
@@ -2798,14 +2931,14 @@ function channel_remove($channel_id, $local = true, $unset_session = false) {
$hublocs = count($r);
if(! $hublocs) {
- $r = q("update xchan set xchan_deleted = 1 where xchan_hash = '%s' ",
- dbesc($channel['channel_hash'])
+ $r = q("UPDATE xchan SET xchan_deleted = 1 WHERE xchan_hash = '%s' OR xchan_hash = '%s'",
+ dbesc($channel['channel_hash']),
+ dbesc($channel['channel_portable_id'])
);
}
//remove from file system
-
$f = 'store/' . $channel['channel_address'];
if(is_dir($f)) {
@rrmdir($f);
@@ -2953,3 +3086,8 @@ function pchan_to_chan($pchan) {
function channel_url($channel) {
return (($channel) ? z_root() . '/channel/' . $channel['channel_address'] : z_root());
}
+
+function get_channel_hashes() {
+ $r = q("SELECT channel_hash FROM channel WHERE channel_removed = 0");
+ return flatten_array_recursive($r);
+}
diff --git a/include/connections.php b/include/connections.php
index 51df18b70..658fb6ee6 100644
--- a/include/connections.php
+++ b/include/connections.php
@@ -446,8 +446,13 @@ function contact_remove($channel_id, $abook_id) {
);
$r = q("delete from abconfig where chan = %d and xchan = '%s'",
- intval($channel_id),
- dbesc($abook['abook_xchan'])
+ intval($channel_id),
+ dbesc($abook['abook_xchan'])
+ );
+
+ $r = q("delete from source where src_channel_id = %d and src_xchan = '%s'",
+ intval($channel_id),
+ dbesc($abook['abook_xchan'])
);
return true;
@@ -772,3 +777,67 @@ function vcard_query(&$r) {
}
}
}
+
+function z6trans_connections() {
+
+ $r = dbq("SELECT DISTINCT abook.abook_xchan, hubloc.hubloc_addr, hubloc.hubloc_url, hubloc.hubloc_guid, site.site_project, site.site_version FROM abook
+ LEFT JOIN hubloc ON abook_xchan = hubloc_hash
+ LEFT JOIN site ON hubloc_url = site_url
+ WHERE abook.abook_self = 0 AND hubloc.hubloc_network = 'zot'
+ AND hubloc.hubloc_deleted = 0 AND site.site_dead = 0"
+ );
+
+ foreach($r as $rr) {
+ if(stripos($rr['site_project'], 'hubzilla') !== false && version_compare($rr['site_version'], '4.7.4', '>=')) {
+
+ $zot_xchan = $rr['abook_xchan'];
+ $guid = $rr['hubloc_guid'];
+ $hub_url = $rr['hubloc_url'];
+ $addr = $rr['hubloc_addr'];
+
+ $x = q("SELECT hubloc_hash FROM hubloc
+ WHERE hubloc_guid = '%s' AND hubloc_url = '%s' AND hubloc_network = 'zot6' AND hubloc_deleted = 0",
+ dbesc($guid),
+ dbesc($hub_url)
+ );
+
+ if(!$x) {
+ logger("z6trans_connections: zot6 hubloc for $addr not found");
+ discover_by_webbie($addr,'zot6');
+ continue;
+ }
+
+ $zot6_xchan = $x[0]['hubloc_hash'];
+
+ logger("z6trans_connections: transition $zot_xchan to $zot6_xchan");
+
+ dbq("START TRANSACTION");
+
+ $q1 = q("UPDATE abook set abook_xchan = '%s' WHERE abook_xchan = '%s'",
+ dbesc($zot6_xchan),
+ dbesc($zot_xchan)
+ );
+
+ $q2 = q("UPDATE abconfig set xchan = '%s' WHERE xchan = '%s'",
+ dbesc($zot6_xchan),
+ dbesc($zot_xchan)
+ );
+
+ $q3 = q("UPDATE pgrp_member set xchan = '%s' WHERE xchan = '%s'",
+ dbesc($zot6_xchan),
+ dbesc($zot_xchan)
+ );
+
+ if($q1 && $q2 && $q3) {
+ dbq("COMMIT");
+ logger("z6trans_connections: completed");
+ continue;
+ }
+
+ logger("z6trans_connections: failed - performing rollback");
+ dbq("ROLLBACK");
+
+ }
+ }
+
+}
diff --git a/include/contact_widgets.php b/include/contact_widgets.php
index 6ad276b00..626a825b2 100644
--- a/include/contact_widgets.php
+++ b/include/contact_widgets.php
@@ -1,6 +1,6 @@
<?php /** @file */
-
+use Zotlabs\Lib\Cache;
function findpeople_widget() {
@@ -59,6 +59,7 @@ function fileas_widget($baseurl,$selected = '') {
));
}
+
function categories_widget($baseurl,$selected = '') {
if(! feature_enabled(App::$profile['profile_uid'],'categories'))
@@ -70,25 +71,36 @@ function categories_widget($baseurl,$selected = '') {
$item_normal = item_normal();
+ $key = __FUNCTION__ . "-" . App::$profile['profile_uid'];
+ $content = Cache::get($key, '5 MINUTE');
+
+ if (! $content) {
+ $r = q("select distinct(term.term) from term join item on term.oid = item.id
+ where item.uid = %d
+ and term.uid = item.uid
+ and term.ttype = %d
+ and term.otype = %d
+ and item.owner_xchan = '%s'
+ and item.item_wall = 1
+ and item.verb != '%s'
+ $item_normal
+ $sql_extra
+ order by term.term asc",
+ intval(App::$profile['profile_uid']),
+ intval(TERM_CATEGORY),
+ intval(TERM_OBJ_POST),
+ dbesc(App::$profile['channel_hash']),
+ dbesc(ACTIVITY_UPDATE)
+ );
+ }
+ else
+ $r = unserialize($content);
+
$terms = array();
- $r = q("select distinct(term.term) from term join item on term.oid = item.id
- where item.uid = %d
- and term.uid = item.uid
- and term.ttype = %d
- and term.otype = %d
- and item.owner_xchan = '%s'
- and item.item_wall = 1
- and item.verb != '%s'
- $item_normal
- $sql_extra
- order by term.term asc",
- intval(App::$profile['profile_uid']),
- intval(TERM_CATEGORY),
- intval(TERM_OBJ_POST),
- dbesc(App::$profile['channel_hash']),
- dbesc(ACTIVITY_UPDATE)
- );
if($r && count($r)) {
+
+ Cache::set($key, serialize($r));
+
foreach($r as $rr)
$terms[] = array('name' => $rr['term'], 'selected' => (($selected == $rr['term']) ? 'selected' : ''));
@@ -104,6 +116,7 @@ function categories_widget($baseurl,$selected = '') {
return '';
}
+
function cardcategories_widget($baseurl,$selected = '') {
if(! feature_enabled(App::$profile['profile_uid'],'categories'))
diff --git a/include/conversation.php b/include/conversation.php
index e2dd02ffc..e77404cff 100644
--- a/include/conversation.php
+++ b/include/conversation.php
@@ -1,5 +1,7 @@
<?php /** @file */
+use Zotlabs\Lib\Apps;
+
require_once('include/items.php');
@@ -100,22 +102,33 @@ function localize_item(&$item){
logger('localize_item: failed to decode object: ' . print_r($item['obj'],true));
}
- if($obj['author'] && $obj['author']['link'])
+ if(is_array($obj['author']) && $obj['author']['link'])
$author_link = get_rel_link($obj['author']['link'],'alternate');
+ elseif(is_array($obj['actor']) && $obj['actor']['url'])
+ $author_link = ((is_array($obj['actor']['url'])) ? $obj['actor']['url'][0]['href'] : $obj['actor']['url']);
else
$author_link = '';
$author_name = (($obj['author'] && $obj['author']['name']) ? $obj['author']['name'] : '');
- $item_url = get_rel_link($obj['link'],'alternate');
+ if(!$author_name)
+ $author_name = ((is_array($obj['actor']) && $obj['actor']['name']) ? $obj['actor']['name'] : '');
+
+ if(is_array($obj['link']))
+ $item_url = get_rel_link($obj['link'],'alternate');
+
+ if(!$item_url)
+ $item_url = $obj['id'];
$Bphoto = '';
switch($obj['type']) {
case ACTIVITY_OBJ_PHOTO:
+ case 'Photo':
$post_type = t('photo');
break;
case ACTIVITY_OBJ_EVENT:
+ case 'Event':
$post_type = t('event');
break;
case ACTIVITY_OBJ_PERSON:
@@ -140,9 +153,10 @@ function localize_item(&$item){
break;
case ACTIVITY_OBJ_NOTE:
+ case 'Note':
default:
- $post_type = t('status');
- if($obj['id'] != $obj['parent'])
+ $post_type = t('post');
+ if(($obj['parent'] && $obj['id'] != $obj['parent']) || $obj['inReplyTo'])
$post_type = t('comment');
break;
}
@@ -172,9 +186,9 @@ function localize_item(&$item){
$shortbodyverb = t('doesn\'t like %1$s\'s %2$s');
}
- $item['shortlocalize'] = sprintf($shortbodyverb, $objauthor, $plink);
+ $item['shortlocalize'] = sprintf($shortbodyverb, '[bdi]' . $author_name . '[/bdi]', $post_type);
- $item['body'] = $item['localize'] = sprintf($bodyverb, $author, $objauthor, $plink);
+ $item['body'] = $item['localize'] = sprintf($bodyverb, '[bdi]' . $author . '[/bdi]', '[bdi]' . $objauthor . '[/bdi]', $plink);
if($Bphoto != "")
$item['body'] .= "\n\n\n" . '[zrl=' . chanlink_url($author_link) . '][zmg=80x80]' . $Bphoto . '[/zmg][/zrl]';
@@ -205,10 +219,12 @@ function localize_item(&$item){
$Bname = $obj['title'];
- $A = '[zrl=' . chanlink_url($Alink) . ']' . $Aname . '[/zrl]';
- $B = '[zrl=' . chanlink_url($Blink) . ']' . $Bname . '[/zrl]';
+ $A = '[zrl=' . chanlink_url($Alink) . '][bdi]' . $Aname . '[/bdi][/zrl]';
+ $B = '[zrl=' . chanlink_url($Blink) . '][bdi]' . $Bname . '[/bdi][/zrl]';
if ($Bphoto!="") $Bphoto = '[zrl=' . chanlink_url($Blink) . '][zmg=80x80]' . $Bphoto . '[/zmg][/zrl]';
+ $item['shortlocalize'] = sprintf( t('%1$s is now connected with %2$s'), '[bdi]' . $Aname . '[/bdi]', '[bdi]' . $Bname . '[/bdi]');
+
$item['body'] = $item['localize'] = sprintf( t('%1$s is now connected with %2$s'), $A, $B);
$item['body'] .= "\n\n\n" . $Bphoto;
}
@@ -237,8 +253,8 @@ function localize_item(&$item){
}
$Bname = $obj['title'];
- $A = '[zrl=' . chanlink_url($Alink) . ']' . $Aname . '[/zrl]';
- $B = '[zrl=' . chanlink_url($Blink) . ']' . $Bname . '[/zrl]';
+ $A = '[zrl=' . chanlink_url($Alink) . '][bdi]' . $Aname . '[/bdi][/zrl]';
+ $B = '[zrl=' . chanlink_url($Blink) . '][bdi]' . $Bname . '[/bdi][/zrl]';
if ($Bphoto!="") $Bphoto = '[zrl=' . chanlink_url($Blink) . '][zmg=80x80]' . $Bphoto . '[/zmg][/zrl]';
// we can't have a translation string with three positions but no distinguishable text
@@ -252,6 +268,8 @@ function localize_item(&$item){
// then do the sprintf on the translation string
+ $item['shortlocalize'] = sprintf($txt, '[bdi]' . $Aname . '[/bdi]', '[bdi]' . $Bname . '[/bdi]');
+
$item['body'] = $item['localize'] = sprintf($txt, $A, $B);
$item['body'] .= "\n\n\n" . $Bphoto;
}
@@ -263,7 +281,7 @@ function localize_item(&$item){
$Aname = $item['author']['xchan_name'];
$Alink = $item['author']['xchan_url'];
- $A = '[zrl=' . chanlink_url($Alink) . ']' . $Aname . '[/zrl]';
+ $A = '[zrl=' . chanlink_url($Alink) . '][bdi]' . $Aname . '[/bdi][/zrl]';
$txt = t('%1$s is %2$s','mood');
@@ -409,14 +427,28 @@ function visible_activity($item) {
if(intval($item['item_notshown']))
return false;
+ if ($item['obj_type'] === 'Answer') {
+ return false;
+ }
+
foreach($hidden_activities as $act) {
if((activity_match($item['verb'], $act)) && ($item['mid'] != $item['parent_mid'])) {
return false;
}
}
- if(is_edit_activity($item))
- return false;
+ // We only need edit activities for other federated protocols
+ // which do not support edits natively. While this does federate
+ // edits, it presents a number of issues locally - such as #757 and #758.
+ // The SQL check for an edit activity would not perform that well so to fix these issues
+ // requires an additional item flag (perhaps 'item_edit_activity') that we can add to the
+ // query for searches and notifications.
+
+ // For now we'll just forget about trying to make edits work on network protocols that
+ // don't support them.
+
+ // if(is_edit_activity($item))
+ // return false;
return true;
}
@@ -615,11 +647,17 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa
$items = $cb['items'];
- $conv_responses = array(
- 'like' => array('title' => t('Likes','title')),'dislike' => array('title' => t('Dislikes','title')),
- 'agree' => array('title' => t('Agree','title')),'disagree' => array('title' => t('Disagree','title')), 'abstain' => array('title' => t('Abstain','title')),
- 'attendyes' => array('title' => t('Attending','title')), 'attendno' => array('title' => t('Not attending','title')), 'attendmaybe' => array('title' => t('Might attend','title'))
- );
+ $conv_responses = [
+ 'like' => ['title' => t('Likes','title')],
+ 'dislike' => ['title' => t('Dislikes','title')],
+ 'agree' => ['title' => t('Agree','title')],
+ 'disagree' => ['title' => t('Disagree','title')],
+ 'abstain' => ['title' => t('Abstain','title')],
+ 'attendyes' => ['title' => t('Attending','title')],
+ 'attendno' => ['title' => t('Not attending','title')],
+ 'attendmaybe' => ['title' => t('Might attend','title')],
+ 'answer' => []
+ ];
// array with html for each thread (parent+comments)
@@ -736,6 +774,7 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa
'delete' => t('Delete'),
'preview_lbl' => $preview_lbl,
'id' => (($preview) ? 'P0' : $item['item_id']),
+ 'mids' => json_encode(['b64.' . base64url_encode($item['mid'])]),
'linktitle' => sprintf( t('View %s\'s profile @ %s'), $profile_name, $profile_url),
'profile_url' => $profile_link,
'thread_action_menu' => thread_action_menu($item,$mode),
@@ -1009,18 +1048,18 @@ function thread_author_menu($item, $mode = '') {
$contact = App::$contacts[$item['author_xchan']];
}
else {
- if($local_channel && $item['author']['xchan_addr'] && (! in_array($item['author']['xchan_network'],[ 'rss', 'anon','unknown' ]))) {
- $follow_url = z_root() . '/follow/?f=&url=' . urlencode($item['author']['xchan_addr']) . '&interactive=0';
+ $url = (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url']);
+ if($local_channel && $url && (! in_array($item['author']['xchan_network'],[ 'rss', 'anon','unknown' ]))) {
+ $follow_url = z_root() . '/follow/?f=&url=' . urlencode($url) . '&interactive=0';
}
}
-
if($item['uid'] > 0 && author_is_pmable($item['author'],$contact)) {
$pm_url = z_root() . '/mail/new/?f=&hash=' . urlencode($item['author_xchan']);
}
}
if($contact) {
- $poke_link = z_root() . '/poke/?f=&c=' . $contact['abook_id'];
+ $poke_link = ((Apps::system_app_installed($local_channel, 'Poke')) ? z_root() . '/poke/?f=&c=' . $contact['abook_id'] : '');
if (! intval($contact['abook_self']))
$contact_url = z_root() . '/connedit/' . $contact['abook_id'];
$posts_link = z_root() . '/network/?cid=' . $contact['abook_id'];
@@ -1125,7 +1164,7 @@ function builtin_activity_puller($item, &$conv_responses) {
// if this item is a post or comment there's nothing for us to do here, just return.
- if(activity_match($item['verb'],ACTIVITY_POST))
+ if(activity_match($item['verb'],ACTIVITY_POST) && $item['obj_type'] !== 'Answer')
return;
foreach($conv_responses as $mode => $v) {
@@ -1157,6 +1196,9 @@ function builtin_activity_puller($item, &$conv_responses) {
case 'attendmaybe':
$verb = ACTIVITY_ATTENDMAYBE;
break;
+ case 'answer':
+ $verb = ACTIVITY_POST;
+ break;
default:
return;
break;
@@ -1172,6 +1214,11 @@ function builtin_activity_puller($item, &$conv_responses) {
if(! $item['thr_parent'])
$item['thr_parent'] = $item['parent_mid'];
+ $conv_responses[$mode]['mids'][$item['thr_parent']][] = 'b64.' . base64url_encode($item['mid']);
+
+ if($item['obj_type'] === 'Answer')
+ continue;
+
if(! ((isset($conv_responses[$mode][$item['thr_parent'] . '-l']))
&& (is_array($conv_responses[$mode][$item['thr_parent'] . '-l']))))
$conv_responses[$mode][$item['thr_parent'] . '-l'] = array();
@@ -1262,13 +1309,6 @@ function hz_status_editor($a, $x, $popup = false) {
$plaintext = true;
-// if(feature_enabled(local_channel(),'richtext'))
-// $plaintext = false;
-
- $feature_voting = feature_enabled($x['profile_uid'], 'consensus_tools');
- if(x($x, 'hide_voting'))
- $feature_voting = false;
-
$feature_nocomment = feature_enabled($x['profile_uid'], 'disable_comments');
if(x($x, 'disable_comments'))
$feature_nocomment = false;
@@ -1370,7 +1410,7 @@ function hz_status_editor($a, $x, $popup = false) {
$cipher = get_pconfig($x['profile_uid'], 'system', 'default_cipher');
if(! $cipher)
- $cipher = 'aes256';
+ $cipher = 'AES-128-CCM';
if(array_key_exists('catsenabled',$x))
$catsenabled = $x['catsenabled'];
@@ -1416,7 +1456,11 @@ function hz_status_editor($a, $x, $popup = false) {
'$embedPhotosModalOK' => t('OK'),
'$setloc' => $setloc,
'$voting' => t('Toggle voting'),
- '$feature_voting' => $feature_voting,
+ '$poll' => t('Toggle poll'),
+ '$poll_option_label' => t('Option'),
+ '$poll_add_option_label' => t('Add option'),
+ '$poll_expire_unit_label' => [t('Minutes'), t('Hours'), t('Days')],
+ '$multiple_answers' => ['poll_multiple_answers', t("Allow multiple answers"), '', '', [t('No'), t('Yes')]],
'$consensus' => ((array_key_exists('item',$x)) ? $x['item']['item_consensus'] : 0),
'$nocommenttitle' => t('Disable comments'),
'$nocommenttitlesub' => t('Toggle comments'),
diff --git a/include/dba/dba_driver.php b/include/dba/dba_driver.php
index cfb208e2d..b96601fec 100755
--- a/include/dba/dba_driver.php
+++ b/include/dba/dba_driver.php
@@ -307,6 +307,10 @@ function db_use_index($str) {
return \DBA::$dba->use_index($str);
}
+function db_str_to_date($str) {
+ return \DBA::$dba->str_to_date($str);
+}
+
/**
* @brief Execute a SQL query with printf style args.
*
diff --git a/include/dba/dba_pdo.php b/include/dba/dba_pdo.php
index 0279342ec..49f741601 100755
--- a/include/dba/dba_pdo.php
+++ b/include/dba/dba_pdo.php
@@ -139,6 +139,15 @@ class dba_pdo extends dba_driver {
}
}
+ function str_to_date($str) {
+ if($this->driver_dbtype === 'pgsql') {
+ return "TO_TIMESTAMP($str, 'YYYY-MM-DD HH24:MI:SS')";
+ }
+ else {
+ return "STR_TO_DATE($str, '%Y-%m-%d %H:%i:%s')";
+ }
+ }
+
function quote_interval($txt) {
if($this->driver_dbtype === 'pgsql') {
return "'$txt'";
diff --git a/include/dir_fns.php b/include/dir_fns.php
index 08a9fb653..f477b35dd 100644
--- a/include/dir_fns.php
+++ b/include/dir_fns.php
@@ -3,6 +3,10 @@
* @file include/dir_fns.php
*/
+use Zotlabs\Lib\Libzot;
+use Zotlabs\Lib\Webfinger;
+use Zotlabs\Lib\Zotfinger;
+
require_once('include/permissions.php');
/**
@@ -67,15 +71,10 @@ function check_upstream_directory() {
$isadir = true;
if ($directory) {
- $h = parse_url($directory);
- if ($h) {
- $j = Zotlabs\Zot\Finger::run('[system]@' . $h['host']);
- if ($j['success']) {
- if (array_key_exists('site', $j) && array_key_exists('directory_mode', $j['site'])) {
- if ($j['site']['directory_mode'] === 'normal') {
- $isadir = false;
- }
- }
+ $j = Zotfinger::exec($directory);
+ if (array_path_exists('data/directory_mode',$j)) {
+ if ($j['data']['directory_mode'] === 'normal') {
+ $isadir = false;
}
}
}
@@ -341,15 +340,15 @@ function update_directory_entry($ud) {
// Hubzilla channels running traditional zot which have not upgraded can or will be dropped from the directory or
// "not found" at the end of the transition period as the directory will only serve zot6 entries at that time.
- $uri = \Zotlabs\Lib\Webfinger::zot_url($ud['ud_addr']);
+ $uri = Webfinger::zot_url($ud['ud_addr']);
if($uri) {
- $record = \Zotlabs\Lib\Zotfinger::exec($uri);
+ $record = Zotfinger::exec($uri);
// Check the HTTP signature
$hsig = $record['signature'];
if($hsig && $hsig['signer'] === $url && $hsig['header_valid'] === true && $hsig['content_valid'] === true) {
- $x = \Zotlabs\Zot\Libzot::import_xchan($record['data'], 0, $ud);
+ $x = \Zotlabs\Lib\Libzot::import_xchan($record['data'], 0, $ud);
if($x['success']) {
$success = true;
}
diff --git a/include/event.php b/include/event.php
index 6be1b6705..765086167 100644
--- a/include/event.php
+++ b/include/event.php
@@ -8,6 +8,7 @@
use Sabre\VObject;
use Zotlabs\Lib\Activity;
+use Zotlabs\Lib\Libsync;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
@@ -40,7 +41,7 @@ function format_event_html($ev) {
$o .= '<div class="event-start"><span class="event-label">' . t('Starts:') . '</span>&nbsp;<span class="dtstart" title="'
. datetime_convert('UTC', 'UTC', $ev['dtstart'], (($ev['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' ))
. '" >'
- . (($ev['adjust']) ? day_translate(datetime_convert($tz, date_default_timezone_get(),
+ . (($ev['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(),
$ev['dtstart'] , $bd_format ))
: day_translate(datetime_convert('UTC', 'UTC',
$ev['dtstart'] , $bd_format)))
@@ -50,7 +51,7 @@ function format_event_html($ev) {
$o .= '<div class="event-end" ><span class="event-label">' . t('Finishes:') . '</span>&nbsp;<span class="dtend" title="'
. datetime_convert('UTC','UTC',$ev['dtend'], (($ev['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' ))
. '" >'
- . (($ev['adjust']) ? day_translate(datetime_convert($tz, date_default_timezone_get(),
+ . (($ev['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(),
$ev['dtend'] , $bd_format ))
: day_translate(datetime_convert('UTC', 'UTC',
$ev['dtend'] , $bd_format )))
@@ -73,48 +74,67 @@ function format_event_obj($jobject) {
$object = json_decode($jobject,true);
- //ensure compatibility with older items - this check can be removed at a later point
- if(array_key_exists('description', $object)) {
+ $event_tz = '';
+ if($object['adjust'] && is_array($object['asld']) && is_array($object['asld']['attachment'])) {
+ foreach($object['asld']['attachment'] as $attachment) {
+ if($attachment['type'] === 'PropertyValue' && $attachment['name'] == 'zot.event.timezone' ) {
+ // check if the offset of the timezones is different and only set event_tz if offset is not the same
+ $local_tz = new DateTimeZone(date_default_timezone_get());
+ $local_dt = new DateTime('now', $local_tz);
+
+ $ev_tz = new DateTimeZone($attachment['value']);
+ $ev_dt = new DateTime('now', $ev_tz);
+ if($local_dt->getOffset() !== $ev_dt->getOffset())
+ $event_tz = $attachment['value'];
+ break;
+ }
+ }
- $tz = (($object['timezone']) ? $object['timezone'] : 'UTC');
- $allday = (($object['adjust']) ? false : true);
+ }
- $dtstart = new DateTime($object['dtstart']);
- $dtend = new DateTime($object['dtend']);
- $dtdiff = $dtstart->diff($dtend);
+ $allday = (($object['adjust']) ? false : true);
- if($allday && ($dtdiff->days < 2))
- $oneday = true;
+ $dtstart = new DateTime($object['dtstart']);
+ $dtend = new DateTime($object['dtend']);
+ $dtdiff = $dtstart->diff($dtend);
- if($allday && !$oneday) {
- // Subtract one day from the end date so we can use the "first day - last day" format for display.
- $dtend->modify('-1 day');
- $object['dtend'] = datetime_convert('UTC', 'UTC', $dtend->format('Y-m-d H:i:s'));
- }
+ if($allday && ($dtdiff->days < 2))
+ $oneday = true;
- $bd_format = (($allday) ? t('l F d, Y') : t('l F d, Y \@ g:i A')); // Friday January 18, 2011 @ 8:01 AM or Friday January 18, 2011 for allday events
-
- $event['header'] = replace_macros(get_markup_template('event_item_header.tpl'),array(
- '$title' => zidify_links(smilies(bbcode($object['title']))),
- '$dtstart_label' => t('Start:'),
- '$dtstart_title' => datetime_convert($tz, date_default_timezone_get(), $object['dtstart'], (($object['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' )),
- '$dtstart_dt' => (($object['adjust']) ? day_translate(datetime_convert($tz, date_default_timezone_get(), $object['dtstart'] , $bd_format )) : day_translate(datetime_convert('UTC', 'UTC', $object['dtstart'] , $bd_format))),
- '$finish' => (($object['nofinish']) ? false : true),
- '$dtend_label' => t('End:'),
- '$dtend_title' => datetime_convert($tz, date_default_timezone_get(), $object['dtend'], (($object['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' )),
- '$dtend_dt' => (($object['adjust']) ? day_translate(datetime_convert($tz, date_default_timezone_get(), $object['dtend'] , $bd_format )) : day_translate(datetime_convert('UTC', 'UTC', $object['dtend'] , $bd_format ))),
- '$allday' => $allday,
- '$oneday' => $oneday
- ));
-
- $event['content'] = replace_macros(get_markup_template('event_item_content.tpl'),array(
- '$description' => zidify_links(smilies(bbcode($object['description']))),
- '$location_label' => t('Location:'),
- '$location' => zidify_links(smilies(bbcode($object['location'])))
- ));
+ if($allday && !$oneday) {
+ // Subtract one day from the end date so we can use the "first day - last day" format for display.
+ $dtend->modify('-1 day');
+ $object['dtend'] = datetime_convert('UTC', 'UTC', $dtend->format('Y-m-d H:i:s'));
+ }
+ $bd_format = (($allday) ? t('l F d, Y') : t('l F d, Y \@ g:i A')); // Friday January 18, 2011 @ 8:01 AM or Friday January 18, 2011 for allday events
+
+ $event['header'] = replace_macros(get_markup_template('event_item_header.tpl'),array(
+ '$title' => zidify_links(smilies(bbcode($object['title']))),
+ '$dtstart_label' => t('Start:'),
+ '$dtstart_title' => datetime_convert('UTC', date_default_timezone_get(), $object['dtstart'], (($object['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' )),
+ '$dtstart_dt' => (($object['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(), $object['dtstart'] , $bd_format )) : day_translate(datetime_convert('UTC', 'UTC', $object['dtstart'] , $bd_format))),
+ '$finish' => (($object['nofinish']) ? false : true),
+ '$dtend_label' => t('End:'),
+ '$dtend_title' => datetime_convert('UTC', date_default_timezone_get(), $object['dtend'], (($object['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' )),
+ '$dtend_dt' => (($object['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(), $object['dtend'] , $bd_format )) : day_translate(datetime_convert('UTC', 'UTC', $object['dtend'] , $bd_format ))),
+ '$allday' => $allday,
+ '$oneday' => $oneday,
+ '$event_tz' => ['label' => t('Timezone'), 'value' => (($event_tz === date_default_timezone_get()) ? '' : $event_tz)]
+ ));
+
+ $event_src = [];
+
+ if(array_path_exists('asld/source', $object) && $object['asld']['source']['mediaType'] === 'text/bbcode') {
+ $event_src = bbtoevent($object['asld']['source']['content']);
}
+ $event['content'] = replace_macros(get_markup_template('event_item_content.tpl'),array(
+ '$description' => zidify_links(smilies(bbcode($event_src ? $event_src['description'] : $object['description']))),
+ '$location_label' => t('Location:'),
+ '$location' => zidify_links(smilies(bbcode($event_src ? $event_src['location'] : $object['location']))),
+ ));
+
return $event;
}
@@ -250,14 +270,22 @@ function format_ical_sourcetext($s) {
}
-function format_event_bbcode($ev) {
+function format_event_bbcode($ev, $utc = false) {
$o = '';
if($ev['event_vdata']) {
$o .= '[event]' . $ev['event_vdata'] . '[/event]';
}
-
+/*
+ if ($utc && $ev['event-timezone'] !== 'UTC') {
+ $ev['dtstart'] = datetime_convert($ev['timezone'],'UTC',$ev['dtstart']);
+ if ($ev['dtend'] && ! $ev['nofinish']) {
+ $ev['dtend'] = datetime_convert($ev['timezone'],'UTC',$ev['dtend']);
+ }
+ $ev['timezone'] = 'UTC';
+ }
+*/
if($ev['summary'])
$o .= '[event-summary]' . $ev['summary'] . '[/event-summary]';
@@ -276,8 +304,8 @@ function format_event_bbcode($ev) {
if($ev['event_hash'])
$o .= '[event-id]' . $ev['event_hash'] . '[/event-id]';
- if($ev['timezone'])
- $o .= '[event-timezone]' . $ev['timezone'] . '[/event-timezone]';
+// if($ev['timezone'])
+// $o .= '[event-timezone]' . $ev['timezone'] . '[/event-timezone]';
if($ev['adjust'])
$o .= '[event-adjust]' . $ev['adjust'] . '[/event-adjust]';
@@ -394,6 +422,10 @@ function event_store_event($arr) {
$arr['event_xchan'] = (($arr['event_xchan']) ? $arr['event_xchan'] : '');
$arr['event_priority'] = (($arr['event_priority']) ? $arr['event_priority'] : 0);
+ if (! $arr['dtend']) {
+ $arr['dtend'] = NULL_DATE;
+ $arr['nofinish'] = 1;
+ }
if(array_key_exists('event_status_date',$arr))
$arr['event_status_date'] = datetime_convert('UTC','UTC', $arr['event_status_date']);
@@ -479,9 +511,9 @@ function event_store_event($arr) {
deny_gid = '%s'
WHERE id = %d AND uid = %d",
- dbesc($arr['edited']),
- dbesc($arr['dtstart']),
- dbesc($arr['dtend']),
+ dbesc(datetime_convert('UTC','UTC',$arr['edited'])),
+ dbesc(datetime_convert('UTC','UTC',$arr['dtstart'])),
+ dbesc(datetime_convert('UTC','UTC',$arr['dtend'])),
dbesc($arr['summary']),
dbesc($arr['description']),
dbesc($arr['location']),
@@ -489,7 +521,7 @@ function event_store_event($arr) {
intval($arr['adjust']),
intval($arr['nofinish']),
dbesc($arr['event_status']),
- dbesc($arr['event_status_date']),
+ dbesc(datetime_convert('UTC','UTC',$arr['event_status_date'])),
intval($arr['event_percent']),
dbesc($arr['event_repeat']),
intval($arr['event_sequence']),
@@ -525,10 +557,10 @@ function event_store_event($arr) {
intval($arr['account']),
dbesc($arr['event_xchan']),
dbesc($hash),
- dbesc($arr['created']),
- dbesc($arr['edited']),
- dbesc($arr['dtstart']),
- dbesc($arr['dtend']),
+ dbesc(datetime_convert('UTC','UTC',$arr['created'])),
+ dbesc(datetime_convert('UTC','UTC',$arr['edited'])),
+ dbesc(datetime_convert('UTC','UTC',$arr['dtstart'])),
+ dbesc(datetime_convert('UTC','UTC',$arr['dtend'])),
dbesc($arr['summary']),
dbesc($arr['description']),
dbesc($arr['location']),
@@ -536,7 +568,7 @@ function event_store_event($arr) {
intval($arr['adjust']),
intval($arr['nofinish']),
dbesc($arr['event_status']),
- dbesc($arr['event_status_date']),
+ dbesc(datetime_convert('UTC','UTC',$arr['event_status_date'])),
intval($arr['event_percent']),
dbesc($arr['event_repeat']),
intval($arr['event_sequence']),
@@ -553,9 +585,19 @@ function event_store_event($arr) {
dbesc($hash),
intval($arr['uid'])
);
- if($r)
+ if($r) {
+
+ /**
+ * @hooks event_store_event_end
+ * Called after an event record was stored.
+ * * \e array \b event
+ */
+ call_hooks('event_store_event_end', $r[0]);
+
return $r[0];
+ }
+
return false;
}
@@ -596,7 +638,7 @@ function event_addtocal($item_id, $uid) {
$ev['event_hash'] = $item['resource_id'];
}
- if($ev->private)
+ if($ev['private'])
$ev['allow_cid'] = '<' . $channel['channel_hash'] . '>';
else {
$acl = new Zotlabs\Access\AccessList($channel);
@@ -626,7 +668,7 @@ function event_addtocal($item_id, $uid) {
intval($channel['channel_id'])
);
if($z) {
- build_sync_packet($channel['channel_id'],array('event_item' => array(encode_item($sync_item[0],true)),'event' => $z));
+ Libsync::build_sync_packet($channel['channel_id'],array('event_item' => array(encode_item($sync_item[0],true)),'event' => $z));
}
return true;
}
@@ -1073,12 +1115,17 @@ function event_store_item($arr, $event) {
$item_arr['comment_policy'] = 'none';
}
- $r = q("SELECT * FROM item left join xchan on author_xchan = xchan_hash WHERE resource_id = '%s' AND resource_type = 'event' and uid = %d LIMIT 1",
+ $r = q("SELECT * FROM item WHERE resource_id = '%s' AND resource_type = 'event' and uid = %d LIMIT 1",
dbesc($event['event_hash']),
intval($arr['uid'])
);
if($r) {
+
+ set_iconfig($r[0]['id'], 'event', 'timezone', $arr['timezone'], true);
+ xchan_query($r);
+ $r = fetch_post_tags($r,true);
+
$object = json_encode(array(
'type' => ACTIVITY_OBJ_EVENT,
'id' => z_root() . '/event/' . $r[0]['resource_id'],
@@ -1093,13 +1140,13 @@ function event_store_item($arr, $event) {
'content' => format_event_bbcode($arr),
'attachment' => Activity::encode_attachment($r[0]),
'author' => array(
- 'name' => $r[0]['xchan_name'],
- 'address' => $r[0]['xchan_addr'],
- 'guid' => $r[0]['xchan_guid'],
- 'guid_sig' => $r[0]['xchan_guid_sig'],
+ 'name' => $r[0]['author']['xchan_name'],
+ 'address' => $r[0]['author']['xchan_addr'],
+ 'guid' => $r[0]['author']['xchan_guid'],
+ 'guid_sig' => $r[0]['author']['xchan_guid_sig'],
'link' => array(
- array('rel' => 'alternate', 'type' => 'text/html', 'href' => $r[0]['xchan_url']),
- array('rel' => 'photo', 'type' => $r[0]['xchan_photo_mimetype'], 'href' => $r[0]['xchan_photo_m'])
+ array('rel' => 'alternate', 'type' => 'text/html', 'href' => $r[0]['author']['xchan_url']),
+ array('rel' => 'photo', 'type' => $r[0]['author']['xchan_photo_mimetype'], 'href' => $r[0]['author']['xchan_photo_m'])
),
),
));
@@ -1149,7 +1196,6 @@ function event_store_item($arr, $event) {
}
$item_id = $r[0]['id'];
- set_iconfig($item_id, 'event', 'timezone', $arr['timezone'], true);
/**
* @hooks event_updated
@@ -1184,7 +1230,7 @@ function event_store_item($arr, $event) {
if(! $arr['mid']) {
$arr['uuid'] = $event['event_hash'];
- $arr['mid'] = z_root() . '/event/' . $event['event_hash'];
+ $arr['mid'] = z_root() . '/activity/' . $event['event_hash'];
}
$item_arr['aid'] = $z[0]['channel_account_id'];
@@ -1201,7 +1247,7 @@ function event_store_item($arr, $event) {
$item_arr['deny_cid'] = $arr['deny_cid'];
$item_arr['deny_gid'] = $arr['deny_gid'];
$item_arr['item_private'] = $private;
- $item_arr['verb'] = ACTIVITY_POST;
+ $item_arr['verb'] = 'Invite';
$item_arr['item_wall'] = $item_wall;
$item_arr['item_origin'] = $item_origin;
$item_arr['item_thread_top'] = $item_thread_top;
@@ -1229,10 +1275,12 @@ function event_store_item($arr, $event) {
// otherwise we'll fallback to /display/$message_id
if($wall)
- $item_arr['plink'] = z_root() . '/channel/' . $z[0]['channel_address'] . '/?f=&mid=' . gen_link_id($item_arr['mid']);
+ $item_arr['plink'] = $item_arr['mid'];
else
$item_arr['plink'] = z_root() . '/display/' . gen_link_id($item_arr['mid']);
+ set_iconfig($item_arr, 'event','timezone',$arr['timezone'],true);
+
$x = q("select * from xchan where xchan_hash = '%s' limit 1",
dbesc($arr['event_xchan'])
);
@@ -1268,7 +1316,6 @@ function event_store_item($arr, $event) {
// activities refer to the item message_id as the parent.
set_iconfig($item_arr, 'system','event_id',$event['event_hash'],true);
- set_iconfig($item_arr, 'event','timezone',$arr['timezone'],true);
$res = item_store($item_arr);
diff --git a/include/features.php b/include/features.php
index 87df0c50d..e1457604b 100644
--- a/include/features.php
+++ b/include/features.php
@@ -144,7 +144,7 @@ function get_features($filtered = true, $level = (-1)) {
'conversation' => [
t('Conversation'),
-
+ /* disable until we agree on how to implemnt this in zot6/activitypub
[
'commtag',
t('Community Tagging'),
@@ -152,7 +152,7 @@ function get_features($filtered = true, $level = (-1)) {
false,
get_config('feature_lock','commtag'),
],
-
+ */
[
'emojis',
t('Emoji Reactions'),
@@ -229,14 +229,6 @@ function get_features($filtered = true, $level = (-1)) {
false,
get_config('feature_lock','content_encrypt'),
],
-
- [
- 'consensus_tools',
- t('Enable Voting Tools'),
- t('Provide a class of post which others can vote on'),
- false,
- get_config('feature_lock','consensus_tools'),
- ],
[
'disable_comments',
@@ -299,6 +291,22 @@ function get_features($filtered = true, $level = (-1)) {
t('Network'),
[
+ 'events_tab',
+ t('Events Filter'),
+ t('Ability to display only events'),
+ false,
+ get_config('feature_lock','events_tab')
+ ],
+
+ [
+ 'polls_tab',
+ t('Polls Filter'),
+ t('Ability to display only polls'),
+ false,
+ get_config('feature_lock','polls_tab')
+ ],
+
+ [
'savedsearch',
t('Saved Searches'),
t('Save search terms for re-use'),
diff --git a/include/feedutils.php b/include/feedutils.php
index 6d14eb5c4..0a9af7ee1 100644
--- a/include/feedutils.php
+++ b/include/feedutils.php
@@ -155,7 +155,7 @@ function get_feed_for($channel, $observer_hash, $params) {
if($item['item_private'])
continue;
- $atom .= atom_entry($item, $type, null, $owner, true, '', $params['compat']);
+ $atom .= atom_entry($item, $type, null, $channel, true, '', $params['compat']);
}
}
@@ -452,6 +452,7 @@ function get_atom_elements($feed, $item) {
else {
$res['title'] = bbcode($res['title'], [ 'tryoembed' => false ]);
$res['title'] = html2plain($res['title'], 0, true);
+ $res['title'] = strip_tags($res['title']);
$res['title'] = html_entity_decode($res['title'], ENT_QUOTES, 'UTF-8');
$res['title'] = preg_replace("/https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@]+/", "", $res['title']);
while (strpos($res['title'], "\n") !== false)
@@ -1921,7 +1922,7 @@ function atom_entry($item, $type, $author, $owner, $comment = false, $cid = 0, $
$summary = '';
if($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid'])
- $body = fix_private_photos($body,$owner['uid'],$item,$cid);
+ $body = fix_private_photos($body,$owner['channel_id'],$item,$cid);
if($compat) {
$compat_photos = compat_photos_list($body);
diff --git a/include/group.php b/include/group.php
index 6011af08f..efda389d6 100644
--- a/include/group.php
+++ b/include/group.php
@@ -1,5 +1,6 @@
<?php /** @file */
+use Zotlabs\Lib\Libsync;
function group_add($uid,$name,$public = 0) {
@@ -44,7 +45,7 @@ function group_add($uid,$name,$public = 0) {
$ret = $r;
}
- build_sync_packet($uid,null,true);
+ Libsync::build_sync_packet($uid,null,true);
return $ret;
}
@@ -113,7 +114,7 @@ function group_rmv($uid,$name) {
}
- build_sync_packet($uid,null,true);
+ Libsync::build_sync_packet($uid,null,true);
return $ret;
}
@@ -155,7 +156,7 @@ function group_rmv_member($uid,$name,$member) {
dbesc($member)
);
- build_sync_packet($uid,null,true);
+ Libsync::build_sync_packet($uid,null,true);
return $r;
@@ -186,7 +187,7 @@ function group_add_member($uid,$name,$member,$gid = 0) {
dbesc($member)
);
- build_sync_packet($uid,null,true);
+ Libsync::build_sync_packet($uid,null,true);
return $r;
}
diff --git a/include/help.php b/include/help.php
index e82fa96da..affe64495 100644
--- a/include/help.php
+++ b/include/help.php
@@ -223,7 +223,7 @@ function find_doc_file($s) {
*/
function search_doc_files($s) {
- \App::set_pager_itemspage(60);
+ \App::set_pager_itemspage(30);
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(\App::$pager['itemspage']), intval(\App::$pager['start']));
$regexop = db_getfunc('REGEXP');
diff --git a/include/hubloc.php b/include/hubloc.php
index 4a1f77733..6b896c627 100644
--- a/include/hubloc.php
+++ b/include/hubloc.php
@@ -247,6 +247,7 @@ function hubloc_change_primary($hubloc) {
*
* We use the post url to distinguish between http and https hublocs.
* The https might be alive, and the http dead.
+ * Also set site_dead for the corresponding entry in the site table.
*
* @param string $posturl Hubloc callback url which to disable
*/
@@ -255,6 +256,13 @@ function hubloc_mark_as_down($posturl) {
intval(HUBLOC_OFFLINE),
dbesc($posturl)
);
+
+ // extract the baseurl and set site.site_dead to match
+ $m = parse_url($posturl);
+ $h = $m['scheme'] . '://' . $m['host'];
+ $r = q("update site set site_dead = 1 where site_url = '%s'",
+ dbesc($h)
+ );
}
@@ -317,7 +325,7 @@ function z6_discover() {
if ($c) {
foreach ($c as $entry) {
$q1 = q("select * from hubloc left join site on hubloc_url = site_url where hubloc_deleted = 0 and site_dead = 0 and hubloc_hash = '%s' and hubloc_url != '%s'",
- dbesc($entry['channel_hash']),
+ dbesc($entry['channel_portable_id']),
dbesc(z_root())
);
if (! $q1) {
@@ -327,7 +335,7 @@ function z6_discover() {
// does this particular server have a zot6 clone registered on our site for this channel?
foreach ($q1 as $q) {
$q2 = q("select * from hubloc left join site on hubloc_url = site_url where hubloc_deleted = 0 and site_dead = 0 and hubloc_hash = '%s' and hubloc_url = '%s'",
- dbesc($entry['channel_portable_id']),
+ dbesc($entry['channel_hash']),
dbesc($q['hubloc_url'])
);
if ($q2) {
diff --git a/include/import.php b/include/import.php
index 6a3895b9f..910cb8be7 100644
--- a/include/import.php
+++ b/include/import.php
@@ -1,6 +1,7 @@
<?php
use Zotlabs\Lib\IConfig;
+use Zotlabs\Lib\Libzot;
use Zotlabs\Web\HTTPSig;
@@ -31,7 +32,7 @@ function import_channel($channel, $account_id, $seize, $newname = '') {
// Ignore the hash provided and re-calculate
- $channel['channel_hash'] = make_xchan_hash($channel['channel_guid'],$channel['channel_guid_sig']);
+ $channel['channel_hash'] = Libzot::make_xchan_hash($channel['channel_guid'],$channel['channel_pubkey']);
if($newname) {
$channel['channel_address'] = $newname;
@@ -1503,6 +1504,144 @@ function sync_files($channel, $files) {
}
}
+
+/**
+ * @brief Synchronize addressbooks.
+ *
+ * @param array $channel
+ * @param array $data
+ */
+function sync_addressbook($channel, $data) {
+
+ if(! \Zotlabs\Lib\Apps::system_app_installed($channel['channel_id'], 'CardDAV'))
+ return;
+
+ logger("debug: " . print_r($data,true), LOGGER_DEBUG);
+
+ require_once('include/cdav.php');
+
+ $principalUri = 'principals/' . $channel['channel_address'];
+
+ if($data['action'] !== 'create') {
+ $id = get_cdav_id($principalUri, $data['uri'], 'addressbooks');
+ if(! $id)
+ return;
+ }
+
+ $pdo = \DBA::$dba->db;
+
+ $carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo);
+ $addressbooks = $carddavBackend->getAddressBooksForUser($principalUri);
+
+ switch($data['action']) {
+
+ case 'create':
+ $carddavBackend->createAddressBook($principalUri, $data['uri'], $data['properties']);
+ break;
+
+ case 'drop':
+ $carddavBackend->deleteAddressBook($id);
+ break;
+
+ case 'edit':
+ $patch = new \Sabre\DAV\PropPatch($data['mutations']);
+ $carddavBackend->updateAddressBook($id, $patch);
+ $patch->commit();
+ break;
+
+ case 'delete_card':
+ $carddavBackend->deleteCard($id, $data['carduri']);
+ break;
+
+ case 'update_card':
+ $vcard = \Sabre\VObject\Reader::read($data['card']);
+ $object = $vcard->convert(\Sabre\VObject\Document::VCARD40);
+ $cardData = $vcard->serialize();
+ $carddavBackend->updateCard($id, $data['carduri'], $cardData);
+ break;
+
+ case 'import':
+ $objects = new \Sabre\VObject\Splitter\VCard($data['card']);
+ $profile = \Sabre\VObject\Node::PROFILE_CARDDAV;
+ import_cdav_card($id, 'vcf', 'cards', 'addressbookid', $objects, $profile, $carddavBackend, $data['ids']);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/**
+ * @brief Synchronize calendars.
+ *
+ * @param array $channel
+ * @param array $data
+ */
+function sync_calendar($channel, $data) {
+
+ if(! \Zotlabs\Lib\Apps::system_app_installed($channel['channel_id'], 'Calendar'))
+ return;
+
+ logger("debug: " . print_r($data,true), LOGGER_DEBUG);
+
+ require_once('include/cdav.php');
+
+ $principalUri = 'principals/' . $channel['channel_address'];
+
+ if($data['action'] !== 'create') {
+ $x = get_cdav_id($principalUri, $data['uri'], 'calendarinstances');
+ if(! $x)
+ return;
+ $id = [ $x['id'], $x['calendarid'] ];
+ }
+
+ $pdo = \DBA::$dba->db;
+
+ $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo);
+ $calendars = $caldavBackend->getCalendarsForUser($principalUri);
+
+ switch($data['action']) {
+
+ case 'create':
+ $id = $caldavBackend->createCalendar($principalUri, $data['uri'], $data['properties']);
+ set_pconfig($channel['channel_id'], 'cdav_calendar', $id[0], 1);
+ break;
+
+ case 'drop':
+ $caldavBackend->deleteCalendar($id);
+ break;
+
+ case 'edit':
+ $patch = new \Sabre\DAV\PropPatch($data['mutations']);
+ $caldavBackend->updateCalendar($id, $patch);
+ $patch->commit();
+ break;
+
+ case 'delete_card':
+ $caldavBackend->deleteCalendarObject($id, $data['carduri']);
+ break;
+
+ case 'update_card':
+ $caldavBackend->updateCalendarObject($id, $data['carduri'], $data['card']);
+ break;
+
+ case 'switch':
+ set_pconfig($channel['channel_id'], 'cdav_calendar', $id[0], $data['switch']);
+ break;
+
+ case 'import':
+ $objects = new \Sabre\VObject\Splitter\ICalendar($data['card']);
+ $profile = \Sabre\VObject\Node::PROFILE_CALDAV;
+ import_cdav_card($id, 'ics', 'calendarobjects', 'calendarid', $objects, $profile, $caldavBackend, $data['ids']);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
/**
* @brief Rename a key in an array.
*
diff --git a/include/items.php b/include/items.php
index 917808ad5..960aa3580 100755
--- a/include/items.php
+++ b/include/items.php
@@ -9,7 +9,10 @@ use Zotlabs\Lib\MarkdownSoap;
use Zotlabs\Lib\MessageFilter;
use Zotlabs\Lib\ThreadListener;
use Zotlabs\Lib\IConfig;
+use Zotlabs\Lib\Activity;
+use Zotlabs\Lib\Libsync;
use Zotlabs\Access\PermissionLimits;
+use Zotlabs\Access\PermissionRoles;
use Zotlabs\Access\AccessList;
use Zotlabs\Daemon\Master;
@@ -237,19 +240,19 @@ function comments_are_now_closed($item) {
function item_normal() {
return " and item.item_hidden = 0 and item.item_type = 0 and item.item_deleted = 0
and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
- and item.item_blocked = 0 and item.obj_type != '" . ACTIVITY_OBJ_FILE . "' ";
+ and item.item_blocked = 0 ";
}
function item_normal_search() {
return " and item.item_hidden = 0 and item.item_type in (0,3,6,7) and item.item_deleted = 0
and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
- and item.item_blocked = 0 and item.obj_type != '" . ACTIVITY_OBJ_FILE . "' ";
+ and item.item_blocked = 0 ";
}
function item_normal_update() {
return " and item.item_hidden = 0 and item.item_type = 0
and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
- and item.item_blocked = 0 and item.obj_type != '" . ACTIVITY_OBJ_FILE . "' ";
+ and item.item_blocked = 0 ";
}
@@ -265,7 +268,7 @@ function is_item_normal($item) {
if(intval($item['item_hidden']) || intval($item['item_type']) || intval($item['item_deleted'])
|| intval($item['item_unpublished']) || intval($item['item_delayed']) || intval($item['item_pending_remove'])
- || intval($item['item_blocked']) || ($item['obj_type'] == ACTIVITY_OBJ_FILE))
+ || intval($item['item_blocked']))
return false;
return true;
@@ -288,7 +291,7 @@ function is_item_normal($item) {
*/
function can_comment_on_post($observer_xchan, $item) {
-// logger('Comment_policy: ' . $item['comment_policy'], LOGGER_DEBUG);
+ // logger('Comment_policy: ' . $item['comment_policy'], LOGGER_DEBUG);
$x = [
'observer_hash' => $observer_xchan,
@@ -349,7 +352,8 @@ function can_comment_on_post($observer_xchan, $item) {
return true;
}
break;
- default:
+
+ default:
break;
}
if(strstr($item['comment_policy'],'network:') && strstr($item['comment_policy'],'red')) {
@@ -421,7 +425,7 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) {
if(! array_key_exists('item_origin',$arr))
$arr['item_origin'] = 1;
if(! array_key_exists('item_wall',$arr) && (! $is_comment))
- $arr['item_wall'] = 1;
+ $arr['item_wall'] = 0;
if(! array_key_exists('item_thread_top',$arr) && (! $is_comment))
$arr['item_thread_top'] = 1;
@@ -930,8 +934,19 @@ function import_author_xchan($x) {
}
// if we were told that it's a zot connection, don't probe/import anything else
- if(array_key_exists('network',$x) && $x['network'] === 'zot')
+ if(array_key_exists('network',$x) && $x['network'] === 'zot') {
+ if($x['url']) {
+ // check if we already have the zot6 xchan of this xchan_url. if not import it.
+ $r = q("SELECT xchan_hash FROM xchan WHERE xchan_url = '%s' AND xchan_network = 'zot6'",
+ dbesc($x['url'])
+ );
+
+ if(! $r)
+ discover_by_webbie($x['url'], 'zot6');
+ }
+
return $y;
+ }
// perform zot6 discovery
@@ -1936,6 +1951,11 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
if(intval($r[0]['item_uplink']) && (! $r[0]['item_private']))
$arr['item_private'] = 0;
+
+ if(in_array($arr['obj_type'], ['Note','Answer']) && $r[0]['obj_type'] === 'Question' && intval($r[0]['item_wall'])) {
+ Activity::update_poll($r[0],$arr);
+ }
+
}
else {
logger('item_store: item parent was not found - ignoring item');
@@ -1955,8 +1975,9 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
);
}
else {
- $r = q("SELECT id FROM item WHERE mid = '%s' AND uid = %d and revision = %d LIMIT 1",
+ $r = q("SELECT id FROM item WHERE (mid = '%s' OR mid = '%s') AND uid = %d and revision = %d LIMIT 1",
dbesc($arr['mid']),
+ dbesc(basename(rawurldecode($arr['mid']))), // de-duplicate relayed comments from hubzilla < 4.0
intval($arr['uid']),
intval($arr['revision'])
);
@@ -2609,6 +2630,12 @@ function get_item_contact($item,$contacts) {
*/
function tag_deliver($uid, $item_id) {
+ $role = get_pconfig($uid,'system','permissions_role');
+ $rolesettings = PermissionRoles::role_perms($role);
+ $channel_type = isset($rolesettings['channel_type']) ? $rolesettings['channel_type'] : 'normal';
+
+ $is_group = (($channel_type === 'group') ? true : false);
+
$mention = false;
/*
@@ -2628,18 +2655,43 @@ function tag_deliver($uid, $item_id) {
if(! $i)
return;
+ xchan_query($i,true);
$i = fetch_post_tags($i);
$item = $i[0];
- if(($item['source_xchan']) && intval($item['item_uplink'])
+ if(intval($item['item_uplink']) && $item['source_xchan']
&& intval($item['item_thread_top']) && ($item['edited'] != $item['created'])) {
// 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, true);
+ start_delivery_chain($u[0], $item, $item_id, 0, false, true);
+ return;
+ }
+
+ if ($is_group && intval($item['item_private']) === 2 && intval($item['item_thread_top'])) {
+ // group delivery via DM
+ if(perm_is_allowed($uid,$item['owner_xchan'],'post_wall') || perm_is_allowed($uid,$item['owner_xchan'],'tag_deliver')) {
+ logger('group DM delivery for ' . $u[0]['channel_address']);
+ start_delivery_chain($u[0], $item, $item_id, 0, true, (($item['edited'] != $item['created']) || $item['item_deleted']));
+ }
+ return;
+ }
+
+
+ if ($is_group && intval($item['item_thread_top']) && intval($item['item_wall']) && $item['author_xchan'] !== $item['owner_xchan']) {
+ if (strpos($item['body'],'[/share]')) {
+ logger('W2W post already shared');
+ return;
+ }
+ // group delivery via W2W
+ logger('rewriting W2W post for ' . $u[0]['channel_address']);
+ start_delivery_chain($u[0], $item, $item_id, 0, true, (($item['edited'] != $item['created']) || $item['item_deleted']));
+ q("update item set item_wall = 0 where id = %d",
+ intval($item_id)
+ );
return;
}
@@ -2946,6 +2998,13 @@ function item_community_tag($channel,$item) {
*/
function tgroup_check($uid, $item) {
+
+ $role = get_pconfig($uid,'system','permissions_role');
+ $rolesettings = PermissionRoles::role_perms($role);
+ $channel_type = isset($rolesettings['channel_type']) ? $rolesettings['channel_type'] : 'normal';
+
+ $is_group = (($channel_type === 'group') ? true : false);
+
$mention = false;
// check that the message originated elsewhere and is a top-level post
@@ -2962,6 +3021,15 @@ function tgroup_check($uid, $item) {
return false;
}
+ // post to group via DM
+
+ if ($is_group) {
+ if (intval($item['item_private']) === 2 && $item['mid'] === $item['parent_mid']) {
+ return true;
+ }
+ }
+
+
// 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",
@@ -3070,7 +3138,7 @@ function tgroup_check($uid, $item) {
* @param boolean $edit (optional) default false
* @return void
*/
-function start_delivery_chain($channel, $item, $item_id, $parent, $edit = false) {
+function start_delivery_chain($channel, $item, $item_id, $parent, $group = false, $edit = false) {
$sourced = check_item_source($channel['channel_id'],$item);
@@ -3107,6 +3175,7 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $edit = false)
// This MAY cause you to run afoul of copyright law.
$rewrite_author = intval(get_abconfig($channel['channel_id'],$item['owner_xchan'],'system','rself'));
+
if($rewrite_author) {
$item['author_xchan'] = $channel['channel_hash'];
@@ -3117,6 +3186,107 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $edit = false)
}
}
+ if ($group && (! $parent)) {
+
+ $arr = [];
+
+ if ($edit) {
+ // process edit or delete action
+ $r = q("select * from item where source_xchan = '%s' and body like '%s' and uid = %d limit 1",
+ dbesc($item['owner_xchan']),
+ dbesc("%message_id='" . $item['mid'] . "'%"),
+ intval($channel['channel_id'])
+ );
+ if ($r) {
+ if (intval($item['item_deleted'])) {
+ drop_item($r[0]['id'],false,DROPITEM_PHASE1);
+ Master::Summon([ 'Notifier','drop',$r[0]['id'] ]);
+ return;
+ }
+ $arr['id'] = intval($r[0]['id']);
+ $arr['parent'] = intval($r[0]['parent']);
+ $arr['uuid'] = $r[0]['uuid'];
+ $arr['mid'] = $r[0]['mid'];
+ $arr['parent_mid'] = $r[0]['parent_mid'];
+ $arr['edited'] = datetime_convert();
+ }
+ else {
+ logger('unable to locate original group post ' . $item['mid']);
+ return;
+ }
+
+ }
+ else {
+ $arr['uuid'] = item_message_id();
+ $arr['mid'] = z_root() . '/activity/' . $arr['uuid'];
+ $arr['parent_mid'] = $arr['mid'];
+ }
+
+ $arr['aid'] = $channel['channel_account_id'];
+ $arr['uid'] = $channel['channel_id'];
+
+ // WARNING: the presence of both source_xchan and non-zero item_uplink here will cause a delivery loop
+
+ $arr['item_uplink'] = 0;
+ $arr['source_xchan'] = $item['owner_xchan'];
+
+ $arr['item_private'] = (($channel['channel_allow_cid'] || $channel['channel_allow_gid']
+ || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 1 : 0);
+
+ $arr['item_origin'] = 1;
+ $arr['item_wall'] = 1;
+
+ $arr['item_thread_top'] = 1;
+
+ if (strpos($item['body'], "[/share]") !== false) {
+ $pos = strpos($item['body'], "[share");
+ $bb = substr($item['body'], $pos);
+ } else {
+ $bb = "[share author='" . urlencode($item['author']['xchan_name']).
+ "' profile='" . $item['author']['xchan_url'] .
+ "' portable_id='" . $item['author']['xchan_hash'] .
+ "' avatar='" . $item['author']['xchan_photo_s'] .
+ "' link='" . $item['plink'] .
+ "' auth='" . ((in_array($item['author']['xchan_network'], ['zot6','zot'])) ? 'true' : 'false') .
+ "' posted='" . $item['created'] .
+ "' message_id='" . $item['mid'] .
+ "']";
+ if($item['title'])
+ $bb .= '[b]'.$item['title'].'[/b]'."\r\n";
+ $bb .= $item['body'];
+ $bb .= "[/share]";
+ }
+
+ $arr['body'] = $bb;
+
+ $arr['author_xchan'] = $channel['channel_hash'];
+ $arr['owner_xchan'] = $channel['channel_hash'];
+
+ $arr['obj_type'] = $item['obj_type'];
+ $arr['verb'] = ACTIVITY_POST;
+
+ $arr['allow_cid'] = $channel['channel_allow_cid'];
+ $arr['allow_gid'] = $channel['channel_allow_gid'];
+ $arr['deny_cid'] = $channel['channel_deny_cid'];
+ $arr['deny_gid'] = $channel['channel_deny_gid'];
+ $arr['comment_policy'] = map_scope(PermissionLimits::Get($channel['channel_id'],'post_comments'));
+
+ if ($arr['id']) {
+ $post = item_store_update($arr);
+ }
+ else {
+ $post = item_store($arr);
+ }
+
+ $post_id = $post['item_id'];
+
+ if($post_id) {
+ Master::Summon([ 'Notifier','tgroup',$post_id ]);
+ }
+ return;
+ }
+
+
// Change this copy of the post to a forum head message and deliver to all the tgroup members
// also reset all the privacy bits to the forum default permissions
@@ -3206,7 +3376,7 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $edit = false)
function check_item_source($uid, $item) {
logger('source: uid: ' . $uid, LOGGER_DEBUG);
- $xchan = (($item['source_xchan']) ? $item['source_xchan'] : $item['owner_xchan']);
+ $xchan = (($item['source_xchan'] && intval($item['item_uplink'])) ? $item['source_xchan'] : $item['owner_xchan']);
$r = q("select * from source where src_channel_id = %d and ( src_xchan = '%s' or src_xchan = '*' ) limit 1",
intval($uid),
@@ -3856,7 +4026,7 @@ function delete_item_lowlevel($item, $stage = DROPITEM_NORMAL) {
if($x) {
$sync_data['event_deleted'] = 1;
- build_sync_packet($item['uid'], ['event' => [$sync_data]]);
+ Libsync::build_sync_packet($item['uid'], ['event' => [$sync_data]]);
}
}
@@ -3865,7 +4035,7 @@ function delete_item_lowlevel($item, $stage = DROPITEM_NORMAL) {
$channel = channelx_by_n($item['uid']);
$sync_data = attach_export_data($channel, $item['resource_id'], true);
if($sync_data)
- build_sync_packet($item['uid'], ['file' => [$sync_data]]);
+ Libsync::build_sync_packet($item['uid'], ['file' => [$sync_data]]);
}
// immediately remove any undesired profile likes.
@@ -4367,8 +4537,8 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
// only setup pagination on initial page view
$pager_sql = '';
} else {
- $itemspage = (($channel) ? get_pconfig($uid,'system','itemspage') : 20);
- App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20));
+ $itemspage = (($channel) ? get_pconfig($uid,'system','itemspage') : 10);
+ App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 10));
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start']));
}
@@ -4661,14 +4831,6 @@ function send_profile_photo_activity($channel,$photo,$profile) {
$arr['item_thread_top'] = 1;
$arr['item_origin'] = 1;
$arr['item_wall'] = 1;
- $arr['obj_type'] = ACTIVITY_OBJ_PHOTO;
- $arr['verb'] = ACTIVITY_UPDATE;
-
- $arr['obj'] = json_encode(array(
- 'type' => $arr['obj_type'],
- 'id' => z_root() . '/photo/profile/l/' . $channel['channel_id'],
- 'link' => array('rel' => 'photo', 'type' => $photo['type'], 'href' => z_root() . '/photo/profile/l/' . $channel['channel_id'])
- ));
if(stripos($profile['gender'],t('female')) !== false)
$t = t('%1$s updated her %2$s');
@@ -4709,7 +4871,7 @@ function sync_an_item($channel_id,$item_id) {
if($r) {
xchan_query($r);
$sync_item = fetch_post_tags($r);
- build_sync_packet($channel_id, array('item' => array(encode_item($sync_item[0],true))));
+ Libsync::build_sync_packet($channel_id, array('item' => array(encode_item($sync_item[0],true))));
}
}
@@ -4911,7 +5073,7 @@ function item_create_edit_activity($post) {
if($r) {
xchan_query($r);
$sync_item = fetch_post_tags($r);
- build_sync_packet($new_item['uid'],array('item' => array(encode_item($sync_item[0],true))));
+ Libsync::build_sync_packet($new_item['uid'],array('item' => array(encode_item($sync_item[0],true))));
}
}
diff --git a/include/js_strings.php b/include/js_strings.php
index f01fa87ae..6f559f4c4 100644
--- a/include/js_strings.php
+++ b/include/js_strings.php
@@ -33,7 +33,10 @@ function js_strings() {
'$name_empty' => t('A channel name is required.'),
'$name_ok1' => t('This is a '),
'$name_ok2' => t(' channel name'),
- '$to_reply' => t('Back to reply'),
+ '$to_reply' => t('Back to reply'),
+ '$pinned' => t('Pinned'),
+ '$pin_item' => t('Pin to the top'),
+ '$unpin_item' => t('Unpin from the top'),
// translatable prefix and suffix strings for jquery.timeago -
// using the defaults set below if left untranslated, empty strings if
diff --git a/include/language.php b/include/language.php
index e9d62e434..622b9614d 100644
--- a/include/language.php
+++ b/include/language.php
@@ -217,9 +217,10 @@ function t($s, $ctx = '') {
*/
function translate_projectname($s) {
-
- return str_replace(array('$projectname','$Projectname'),array(Zotlabs\Lib\System::get_platform_name(),ucfirst(Zotlabs\Lib\System::get_platform_name())),$s);
-
+ if(strpos($s,'rojectname') !== false) {
+ return str_replace(array('$projectname','$Projectname'),array(Zotlabs\Lib\System::get_platform_name(),ucfirst(Zotlabs\Lib\System::get_platform_name())),$s);
+ }
+ return $s;
}
diff --git a/include/markdown.php b/include/markdown.php
index 69cc264df..0bfe595b8 100644
--- a/include/markdown.php
+++ b/include/markdown.php
@@ -76,7 +76,7 @@ function markdown_to_bb($s, $use_zrl = false, $options = []) {
$s = html2bbcode($s);
- $s = bb_code_protect($s);
+ // $s = bb_code_protect($s);
// Convert everything that looks like a link to a link
if($use_zrl) {
@@ -84,13 +84,13 @@ function markdown_to_bb($s, $use_zrl = false, $options = []) {
$s = preg_replace_callback("/\[img\](.*?)\[\/img\]/ism", 'use_zrl_cb_img', $s);
$s = preg_replace_callback("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", 'use_zrl_cb_img_x', $s);
}
- $s = preg_replace_callback("/([^\]\=\{\/]|^)(https?\:\/\/)([a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@\(\)]+)/ismu", 'use_zrl_cb_link',$s);
+ $s = preg_replace_callback("/([^\]\=\{\/]|^)(https?\:\/\/)([a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@\(\)]+)([\,\.\:\;]\s|$)/ismu", 'use_zrl_cb_link',$s);
}
else {
- $s = preg_replace("/([^\]\=\{\/]|^)(https?\:\/\/)([a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@\(\)]+)/ismu", '$1[url=$2$3]$2$3[/url]',$s);
+ $s = preg_replace("/([^\]\=\{\/]|^)(https?\:\/\/)([a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@\(\)]+)([\,\.\:\;]\s|$)/ismu", '$1[url=$2$3]$2$3[/url]$4',$s);
}
- $s = bb_code_unprotect($s);
+ // $s = bb_code_unprotect($s);
// remove duplicate adjacent code tags
$s = preg_replace("/(\[code\])+(.*?)(\[\/code\])+/ism","[code]$2[/code]", $s);
@@ -110,9 +110,9 @@ function use_zrl_cb_link($match) {
$is_zid = is_matrix_url(trim($match[0]));
if($is_zid)
- $res = $match[1] . '[zrl=' . $match[2] . $match[3] . ']' . $match[2] . $match[3] . '[/zrl]';
+ $res = $match[1] . '[zrl=' . $match[2] . $match[3] . ']' . $match[2] . $match[3] . '[/zrl]' . $match[4];
else
- $res = $match[1] . '[url=' . $match[2] . $match[3] . ']' . $match[2] . $match[3] . '[/url]';
+ $res = $match[1] . '[url=' . $match[2] . $match[3] . ']' . $match[2] . $match[3] . '[/url]' . $match[4];
return $res;
}
diff --git a/include/menu.php b/include/menu.php
index 1a2059451..88863f57b 100644
--- a/include/menu.php
+++ b/include/menu.php
@@ -1,5 +1,7 @@
<?php /** @file */
+use Zotlabs\Lib\Libsync;
+
require_once('include/security.php');
require_once('include/bbcode.php');
@@ -405,7 +407,7 @@ function menu_sync_packet($uid,$observer_hash,$menu_id,$delete = false) {
if($m) {
if($delete)
$m['menu_delete'] = 1;
- build_sync_packet($uid,array('menu' => array(menu_element($c,$m))));
+ Libsync::build_sync_packet($uid,array('menu' => array(menu_element($c,$m))));
}
}
}
diff --git a/include/message.php b/include/message.php
index 7d05b9ab7..37fe6749d 100644
--- a/include/message.php
+++ b/include/message.php
@@ -299,10 +299,6 @@ function create_conversation($channel,$recipient,$subject) {
}
-
-
-
-
function private_messages_list($uid, $mailbox = '', $start = 0, $numitems = 0) {
$where = '';
diff --git a/include/nav.php b/include/nav.php
index 672cc2689..b2a061661 100644
--- a/include/nav.php
+++ b/include/nav.php
@@ -59,6 +59,8 @@ function nav($template = 'default') {
if($banner === false)
$banner = get_config('system','sitename');
+
+ call_hooks('get_banner',$banner);
App::$page['header'] .= replace_macros(get_markup_template('hdr.tpl'), array(
//we could additionally use this to display important system notifications e.g. for updates
@@ -294,14 +296,10 @@ function nav($template = 'default') {
$app['active'] = true;
if($is_owner) {
- if(strpos($app['categories'],'nav_pinned_app') === false) {
- $nav_apps[] = Apps::app_render($app,'nav');
- }
+ $nav_apps[] = Apps::app_render($app,'nav');
}
elseif(! $is_owner && strpos($app['requires'], 'local_channel') === false) {
- if(strpos($app['categories'],'nav_pinned_app') === false) {
- $nav_apps[] = Apps::app_render($app,'nav');
- }
+ $nav_apps[] = Apps::app_render($app,'nav');
}
}
}
diff --git a/include/network.php b/include/network.php
index f6992291d..9d4c00ee8 100644
--- a/include/network.php
+++ b/include/network.php
@@ -61,7 +61,8 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) {
@curl_setopt($ch, CURLOPT_CAINFO, get_capath());
@curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
@curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
- @curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (compatible; zot)");
+ @curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; zot)');
+ @curl_setopt($ch, CURLOPT_ENCODING, '');
$ciphers = @get_config('system','curl_ssl_ciphers');
if($ciphers)
@@ -257,6 +258,7 @@ function z_post_url($url, $params, $redirects = 0, $opts = array()) {
@curl_setopt($ch, CURLOPT_POST,1);
@curl_setopt($ch, CURLOPT_POSTFIELDS,$params);
@curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (compatible; zot)");
+ @curl_setopt($ch, CURLOPT_ENCODING, '');
$ciphers = @get_config('system','curl_ssl_ciphers');
if($ciphers)
@@ -505,7 +507,7 @@ function z_dns_check($h,$check_mx = 0) {
// Otherwise we will assume dns_get_record() works as documented
- $opts = DNS_A + DNS_CNAME + DNS_PTR;
+ $opts = DNS_A + DNS_AAAA;
if($check_mx)
$opts += DNS_MX;
@@ -1099,7 +1101,33 @@ function discover_by_webbie($webbie, $protocol = '') {
$network = null;
$x = webfinger_rfc7033($webbie, true);
- if($x && array_key_exists('links',$x) && $x['links']) {
+ if($x && array_key_exists('links',$x) && is_array($x['links'])) {
+
+ foreach($x['links'] as $link) {
+ if(array_key_exists('rel',$link)) {
+ if($link['rel'] === PROTOCOL_ZOT6 && ((! $protocol) || (strtolower($protocol) === 'zot6'))) {
+ logger('zot6 found for ' . $webbie, LOGGER_DEBUG);
+ $record = Zotfinger::exec($link['href']);
+
+ // Check the HTTP signature
+
+ $hsig = $record['signature'];
+ if($hsig && ($hsig['signer'] === $url || $hsig['signer'] === $link['href']) && $hsig['header_valid'] === true && $hsig['content_valid'] === true)
+ $hsig_valid = true;
+
+ if(! $hsig_valid) {
+ logger('http signature not valid: ' . print_r($hsig,true));
+ continue;
+ }
+
+ $y = Libzot::import_xchan($record['data']);
+ if($y['success']) {
+ return $y['hash'];
+ }
+ }
+ }
+ }
+
foreach($x['links'] as $link) {
if(array_key_exists('rel',$link)) {
@@ -1124,30 +1152,6 @@ function discover_by_webbie($webbie, $protocol = '') {
}
}
- foreach($x['links'] as $link) {
- if(array_key_exists('rel',$link)) {
- if($link['rel'] === PROTOCOL_ZOT6 && ((! $protocol) || (strtolower($protocol) === 'zot6'))) {
- logger('zot6 found for ' . $webbie, LOGGER_DEBUG);
- $record = Zotfinger::exec($link['href']);
-
- // Check the HTTP signature
-
- $hsig = $record['signature'];
- if($hsig && ($hsig['signer'] === $url || $hsig['signer'] === $link['href']) && $hsig['header_valid'] === true && $hsig['content_valid'] === true)
- $hsig_valid = true;
-
- if(! $hsig_valid) {
- logger('http signature not valid: ' . print_r($hsig,true));
- continue;
- }
-
- $x = Libzot::import_xchan($record['data']);
- if($x['success']) {
- return $x['hash'];
- }
- }
- }
- }
}
logger('webfinger: ' . print_r($x,true), LOGGER_DATA, LOG_INFO);
@@ -1329,14 +1333,15 @@ function fetch_xrd_links($url) {
*/
function scrape_feed($url) {
- require_once('library/HTML5/Parser.php');
$ret = array();
$level = 0;
$x = z_fetch_url($url,false,$level,array('novalidate' => true));
- if(! $x['success'])
+ if(! $x['success']) {
+ logger('ERROR fetching URL');
return $ret;
+ }
$headers = $x['header'];
$code = $x['return_code'];
@@ -1370,17 +1375,16 @@ function scrape_feed($url) {
}
}
+ $dom = new DOMDocument();
try {
- $dom = HTML5_Parser::parse($s);
+ $dom->loadHTML( $s);
} catch (DOMException $e) {
- logger('Parse error: ' . $e);
- }
-
- if(! $dom) {
- logger('Failed to parse.');
+ logger('Feed parse error: ' . $e);
+ // logger('Feed parse ERROR: ' . libxml_get_last_error()->message);
return $ret;
}
+
$head = $dom->getElementsByTagName('base');
if($head) {
foreach($head as $head0) {
@@ -1842,15 +1846,15 @@ function probe_api_path($host) {
function scrape_vcard($url) {
- require_once('library/HTML5/Parser.php');
-
$ret = array();
logger('url=' . $url);
$x = z_fetch_url($url);
- if(! $x['success'])
+ if(! $x['success']) {
+ logger('ERROR fetching URL');
return $ret;
+ }
$s = $x['body'];
@@ -1867,14 +1871,14 @@ function scrape_vcard($url) {
}
}
+ $dom = new DOMDocument();
try {
- $dom = HTML5_Parser::parse($s);
+ $dom->loadHTML( $s);
} catch (DOMException $e) {
- logger('Parse error: ' . $e);
- }
-
- if(! $dom)
+ logger('hCard parse error: ' . $e);
+ // logger('hCard fetch ERROR: ' . libxml_get_last_error()->message);
return $ret;
+ }
// Pull out hCard profile elements
@@ -2057,3 +2061,23 @@ function get_request_string($url) {
return '/' . ((count($a) > 3) ? $a[3] : EMPTY_STR);
}
+
+
+/*
+ *
+ * Takes the output of parse_url and builds a URL from it
+ *
+ */
+
+function unparse_url($parsed_url) {
+ $scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : '';
+ $host = isset($parsed_url['host']) ? $parsed_url['host'] : '';
+ $port = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '';
+ $user = isset($parsed_url['user']) ? $parsed_url['user'] : '';
+ $pass = isset($parsed_url['pass']) ? ':' . $parsed_url['pass'] : '';
+ $pass = ($user || $pass) ? "$pass@" : '';
+ $path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
+ $query = isset($parsed_url['query']) ? '?' . $parsed_url['query'] : '';
+ $fragment = isset($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : '';
+ return "$scheme$user$pass$host$port$path$query$fragment";
+}
diff --git a/include/permissions.php b/include/permissions.php
index 501b2cc77..ca8ff6e93 100644
--- a/include/permissions.php
+++ b/include/permissions.php
@@ -554,4 +554,24 @@ function site_default_perms() {
return $ret;
}
+function their_perms_contains($channel_id,$xchan_hash,$perm) {
+ $x = get_abconfig($channel_id,$xchan_hash,'system','their_perms');
+ if($x) {
+ $y = explode(',',$x);
+ if(in_array($perm,$y)) {
+ return true;
+ }
+ }
+ return false;
+}
+function my_perms_contains($channel_id,$xchan_hash,$perm) {
+ $x = get_abconfig($channel_id,$xchan_hash,'system','my_perms');
+ if($x) {
+ $y = explode(',',$x);
+ if(in_array($perm,$y)) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/include/photo/photo_driver.php b/include/photo/photo_driver.php
index c11580bdc..52f761b65 100644
--- a/include/photo/photo_driver.php
+++ b/include/photo/photo_driver.php
@@ -135,6 +135,8 @@ function guess_image_type($filename, $headers = '') {
$type = 'image/gif';
elseif(strpos(strtolower($filename),'png') !== false)
$type = 'image/png';
+ elseif(strpos(strtolower($filename),'webp') !== false)
+ $type = 'image/webp';
}
}
@@ -188,25 +190,27 @@ function delete_thing_photo($url, $ob_hash) {
* * \e string \b 5 => modification date
*/
function import_xchan_photo($photo, $xchan, $thing = false, $force = false) {
+
$modified = '';
$o = null;
-
$flags = (($thing) ? PHOTO_THING : PHOTO_XCHAN);
$album = (($thing) ? 'Things' : 'Contact Photos');
logger('Updating channel photo from ' . $photo . ' for ' . $xchan, LOGGER_DEBUG);
- if($thing) {
+ if($thing)
$hash = photo_new_resource();
- } else {
- $r = q("select resource_id, edited, mimetype from photo where xchan = '%s' and photo_usage = %d and imgscale = 4 limit 1", dbesc($xchan), intval(PHOTO_XCHAN));
+ else {
+ $r = q("SELECT resource_id, edited, mimetype, expires, description FROM photo WHERE xchan = '%s' AND photo_usage = %d AND imgscale = 4 LIMIT 1", dbesc($xchan), intval(PHOTO_XCHAN));
if($r) {
$hash = $r[0]['resource_id'];
$modified = $r[0]['edited'];
$type = $r[0]['mimetype'];
- } else {
- $hash = photo_new_resource();
+ $exp = strtotime($r[0]['expires']);
+ $etag = $r[0]['description'];
}
+ else
+ $hash = photo_new_resource();
}
$photo_failure = false;
@@ -214,37 +218,74 @@ function import_xchan_photo($photo, $xchan, $thing = false, $force = false) {
if($photo) {
- if($force || $modified == '') {
+ if($force || empty($modified))
$result = z_fetch_url($photo, true);
- } else {
- $h = [
- 'headers' => [
- 'If-Modified-Since: ' . gmdate('D, d M Y H:i:s', strtotime($modified . 'Z')) . ' GMT'
- ]
- ];
- $result = z_fetch_url($photo, true, 0, $h);
+ elseif($exp - 60 < time()) {
+ $h = [];
+ $h[] = "If-Modified-Since: " . gmdate("D, d M Y H:i:s", $exp) . " GMT";
+ if(! empty($etag))
+ $h[] = "If-None-Match: " . $etag;
+ $result = z_fetch_url($photo, true, 0, [ 'headers' => $h ]);
}
- if($result['success']) {
- $img_str = $result['body'];
- $type = guess_image_type($photo, $result['header']);
- $modified = gmdate('Y-m-d H:i:s', (preg_match('/last-modified: (.+) \S+/i', $result['header'], $o) ? strtotime($o[1] . 'Z') : time()));
- if(is_null($type))
+ if(isset($result)) {
+ $hdrs = [];
+ $h = explode("\n", $result['header']);
+ foreach ($h as $l) {
+ list($t,$v) = array_map("trim", explode(":", trim($l), 2));
+ $hdrs[strtolower($t)] = $v;
+ }
+
+ if(array_key_exists('expires', $hdrs))
+ $expires = strtotime($hdrs['expires']);
+ if($expires - 60 < time())
+ $expires = time() + 60;
+ else {
+ $cc = '';
+ if(array_key_exists('cache-control', $hdrs))
+ $cc = $hdrs['cache-control'];
+ if(strpos($cc, 'no-cache'))
+ $expires = time() + 60;
+ else {
+ $ttl = (preg_match('/max-age=(\d+)/i', $cc, $o) ? intval($o[1]) : 86400);
+ $expires = time() + $ttl;
+ }
+ }
+
+ $modified = gmdate('Y-m-d H:i:s', (array_key_exists('last-modified', $hdrs) ? strtotime($hdrs['last-modified']) : time()));
+
+ if($result['success']) {
+ $img_str = $result['body'];
+ $type = guess_image_type($photo, $result['header']);
+ if(is_null($type))
+ $photo_failure = true;
+ }
+ else
$photo_failure = true;
- } elseif($result['return_code'] == 304) {
+ }
+
+ if(! isset($result) || $result['return_code'] == 304) {
$photo = z_root() . '/photo/' . $hash . '-4';
$thumb = z_root() . '/photo/' . $hash . '-5';
$micro = z_root() . '/photo/' . $hash . '-6';
- } else {
+ if(isset($result))
+ q("UPDATE photo SET expires = '%s' WHERE xchan = '%s' and photo_usage = %d and imgscale IN (4, 5, 6)",
+ dbescdate(gmdate('Y-m-d H:i:s', (isset($expires) ? $expires : time() + 86400))),
+ dbesc($xchan),
+ intval(PHOTO_XCHAN)
+ );
+ $photo_notmodified = true;
$photo_failure = true;
}
- } else {
- $photo_failure = true;
}
+ else
+ $photo_failure = true;
+
+ if(! $photo_failure) {
- if(!$photo_failure && $result['return_code'] != 304) {
$img = photo_factory($img_str, $type);
if($img->is_valid()) {
+
$width = $img->getWidth();
$height = $img->getHeight();
@@ -253,25 +294,28 @@ function import_xchan_photo($photo, $xchan, $thing = false, $force = false) {
// crop out the sides
$margin = $width - $height;
$img->cropImage(300, ($margin / 2), 0, $height, $height);
- } elseif(($height / $width) > 1.2) {
+ }
+ elseif(($height / $width) > 1.2) {
// crop out the bottom
$margin = $height - $width;
$img->cropImage(300, 0, 0, $width, $width);
- } else {
- $img->scaleImageSquare(300);
}
- } else {
- $photo_failure = true;
+ else
+ $img->scaleImageSquare(300);
}
+ else
+ $photo_failure = true;
$p = [
- 'xchan' => $xchan,
- 'resource_id' => $hash,
- 'filename' => basename($photo),
- 'album' => $album,
- 'photo_usage' => $flags,
- 'imgscale' => 4,
- 'edited' => $modified,
+ 'xchan' => $xchan,
+ 'resource_id' => $hash,
+ 'filename' => basename($photo),
+ 'album' => $album,
+ 'photo_usage' => $flags,
+ 'imgscale' => 4,
+ 'edited' => $modified,
+ 'description' => (array_key_exists('etag', $hdrs) ? $hdrs['etag'] : ''),
+ 'expires' => gmdate('Y-m-d H:i:s', (isset($expires) ? $expires : time() + 86400))
];
$r = $img->save($p);
@@ -293,12 +337,14 @@ function import_xchan_photo($photo, $xchan, $thing = false, $force = false) {
$photo = z_root() . '/photo/' . $hash . '-4';
$thumb = z_root() . '/photo/' . $hash . '-5';
$micro = z_root() . '/photo/' . $hash . '-6';
- } else {
+ }
+ else {
logger('Invalid image from ' . $photo);
$photo_failure = true;
}
}
- if($photo_failure) {
+
+ if($photo_failure && ! isset($photo_notmodified)) {
$default = get_default_profile_photo();
$photo = z_root() . '/' . $default;
$thumb = z_root() . '/' . get_default_profile_photo(80);
@@ -307,12 +353,12 @@ function import_xchan_photo($photo, $xchan, $thing = false, $force = false) {
$modified = gmdate('Y-m-d H:i:s', filemtime($default));
}
- logger('HTTP code: ' . $result['return_code'] . '; modified: ' . $modified
- . '; failure: ' . ($photo_failure ? 'yes' : 'no') . '; URL: ' . $photo, LOGGER_DEBUG);
+ logger('xchan: ' . $xchan . '; HTTP code: ' . (isset($result) && array_key_exists('return_code', $result) ? $result['return_code'] : 'none') . '; modified: ' . $modified . '; URL: ' . $photo, LOGGER_DEBUG);
- return([$photo, $thumb, $micro, $type, $photo_failure, $modified]);
+ return([ $photo, $thumb, $micro, $type, $photo_failure, $modified ]);
}
+
/**
* @brief Import channel photo from a URL.
*
diff --git a/include/photos.php b/include/photos.php
index ee662f707..11dd07586 100644
--- a/include/photos.php
+++ b/include/photos.php
@@ -388,7 +388,7 @@ function photo_upload($channel, $observer, $args) {
'title' => $title,
'created' => $p['created'],
'edited' => $p['edited'],
- 'id' => z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo_hash,
+ 'id' => z_root() . '/item/' . $photo_hash,
'link' => $link,
'body' => $summary
);
@@ -438,13 +438,13 @@ function photo_upload($channel, $observer, $args) {
}
}
else {
- $uuid = item_message_id();
- $mid = z_root() . '/item/' . $uuid;
+ // $uuid = item_message_id();
+ $mid = z_root() . '/item/' . $photo_hash;
$arr = [
'aid' => $account_id,
'uid' => $channel_id,
- 'uuid' => $uuid,
+ 'uuid' => $photo_hash,
'mid' => $mid,
'parent_mid' => $mid,
'item_hidden' => $item_hidden,
@@ -469,7 +469,7 @@ function photo_upload($channel, $observer, $args) {
'body' => $summary
];
- $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . urlencode($arr['mid']);
+ $arr['plink'] = $mid;
if($lat && $lon)
$arr['coord'] = $lat . ' ' . $lon;
@@ -850,7 +850,7 @@ function photos_create_item($channel, $creator_hash, $photo, $visible = false) {
$arr['deny_cid'] = $photo['deny_cid'];
$arr['deny_gid'] = $photo['deny_gid'];
- $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . urlencode($arr['mid']);
+ $arr['plink'] = $mid;
$arr['body'] = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo['resource_id'] . ']'
. '[zmg]' . z_root() . '/photo/' . $photo['resource_id'] . '-' . $photo['imgscale'] . '[/zmg]'
diff --git a/include/queue_fn.php b/include/queue_fn.php
index 865228041..b72730d2f 100644
--- a/include/queue_fn.php
+++ b/include/queue_fn.php
@@ -228,49 +228,49 @@ function queue_deliver($outq, $immediate = false) {
// normal zot delivery
- logger('deliver: dest: ' . $outq['outq_posturl'], LOGGER_DEBUG);
+ logger('deliver: dest: ' . $outq['outq_posturl'] . ' driver: ' . $outq['outq_driver'], LOGGER_DEBUG);
if($outq['outq_driver'] === 'zot6') {
- if($outq['outq_posturl'] === z_root() . '/zot') {
- // local delivery
- $zot = new Receiver(new Zot6Handler(),$outq['outq_notify']);
- $result = $zot->run(true);
- logger('returned_json: ' . json_encode($result,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES), LOGGER_DATA);
- logger('deliver: local zot6 delivery succeeded to ' . $outq['outq_posturl']);
- Libzot::process_response($outq['outq_posturl'],[ 'success' => true, 'body' => json_encode($result) ], $outq);
- }
- else {
- logger('remote');
- $channel = null;
-
- if($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' and hubloc_network = 'zot6' order by hubloc_id desc limit 1",
- dbesc($base)
- );
- if($h) {
- $host_crypto = $h[0];
- }
- }
-
- $msg = $outq['outq_notify'];
-
- $result = Libzot::zot($outq['outq_posturl'],$msg,$channel,$host_crypto);
-
- if($result['success']) {
- logger('deliver: remote zot6 delivery succeeded to ' . $outq['outq_posturl']);
- Libzot::process_response($outq['outq_posturl'],$result, $outq);
- }
- else {
- logger('deliver: remote zot6 delivery failed to ' . $outq['outq_posturl']);
- logger('deliver: remote zot6 delivery fail data: ' . print_r($result,true), LOGGER_DATA);
- update_queue_item($outq['outq_hash'],10);
- }
+ if($outq['outq_posturl'] === z_root() . '/zot') {
+ // local delivery
+ $zot = new Receiver(new Zot6Handler(),$outq['outq_notify']);
+ $result = $zot->run(true);
+ logger('returned_json: ' . json_encode($result,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES), LOGGER_DATA);
+ logger('deliver: local zot6 delivery succeeded to ' . $outq['outq_posturl']);
+ Libzot::process_response($outq['outq_posturl'],[ 'success' => true, 'body' => json_encode($result) ], $outq);
+ }
+ else {
+ logger('remote');
+ $channel = null;
+
+ if($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' and hubloc_network = 'zot6' order by hubloc_id desc limit 1",
+ dbesc($base)
+ );
+ if($h) {
+ $host_crypto = $h[0];
+ }
+ }
+
+ $msg = $outq['outq_notify'];
+
+ $result = Libzot::zot($outq['outq_posturl'],$msg,$channel,$host_crypto);
+
+ if($result['success']) {
+ logger('deliver: remote zot6 delivery succeeded to ' . $outq['outq_posturl']);
+ Libzot::process_response($outq['outq_posturl'],$result, $outq);
+ }
+ else {
+ logger('deliver: remote zot6 delivery failed to ' . $outq['outq_posturl']);
+ logger('deliver: remote zot6 delivery fail data: ' . print_r($result,true), LOGGER_DATA);
+ update_queue_item($outq['outq_hash'],10);
+ }
}
return;
diff --git a/include/security.php b/include/security.php
index 38cb72263..c9df00f1e 100644
--- a/include/security.php
+++ b/include/security.php
@@ -594,9 +594,11 @@ function check_form_security_token($typename = '', $formname = 'form_security_to
$hash = $_REQUEST[$formname];
$max_livetime = 10800; // 3 hours
+ $min_livetime = 3; // 3 sec
$x = explode('.', $hash);
- if (time() > (IntVal($x[0]) + $max_livetime)) return false;
+ if (time() > (IntVal($x[0]) + $max_livetime) || time() < (IntVal($x[0]) + $min_livetime))
+ return false;
$sec_hash = hash('whirlpool', App::$observer['xchan_guid'] . ((local_channel()) ? App::$channel['channel_prvkey'] : '') . session_id() . $x[0] . $typename);
diff --git a/include/socgraph.php b/include/socgraph.php
index 3d26f5cfd..3da4dce63 100644
--- a/include/socgraph.php
+++ b/include/socgraph.php
@@ -158,7 +158,7 @@ function poco_load($xchan = '', $url = null) {
if($address) {
if($network === 'zot6') {
$j = Zotfinger::exec($profile_url);
- if(is_array($j) && array_path_exists('signature/signer',$j) && $j['signature']['signer'] === $profile_url && intval($j['signature']['header_valid'])) {
+ if(array_path_exists('signature/signer',$j) && $j['signature']['signer'] === $profile_url && intval($j['signature']['header_valid'])) {
Libzot::import_xchan($j['data']);
}
$x = q("select xchan_hash from xchan where xchan_hash = '%s' limit 1",
diff --git a/include/taxonomy.php b/include/taxonomy.php
index b0304de5b..e06568d19 100644
--- a/include/taxonomy.php
+++ b/include/taxonomy.php
@@ -5,6 +5,9 @@
// and save to file categories in square brackets.
// To do this we need to escape these characters if they appear in our tag.
+use Zotlabs\Lib\Cache;
+
+
function file_tag_encode($s) {
return str_replace(array('<','>','[',']'),array('%3c','%3e','%5b','%5d'),$s);
}
@@ -327,50 +330,56 @@ function pubtagblock($net,$site,$limit,$recent = 0,$safemode = 1, $type = TERM_H
return $o;
}
-function pub_tagadelic($net,$site,$limit,$recent,$safemode,$type) {
-
-
- $item_normal = item_normal();
- $count = intval($limit);
-
- if($site) {
- $uids = " and item.uid in ( " . stream_perms_api_uids(PERMS_PUBLIC) . " ) and item_private = 0 and item_wall = 1 ";
- }
- else {
- $sys = get_sys_channel();
- $uids = " and item.uid = " . intval($sys['channel_id']) . " ";
- $sql_extra = " and item_private = 0 ";
- }
-
- if($recent)
- $sql_extra .= " and item.created > '" . datetime_convert('UTC','UTC', 'now - ' . intval($recent) . ' days ') . "' ";
+function pub_tagadelic($net,$site,$limit,$recent,$safemode,$type) {
- if($safemode) {
- $unsafetags = get_config('system','unsafepubtags', [ 'boobs', 'bot', 'rss', 'girl','girls', 'nsfw', 'sexy', 'nude' ]);
- if($unsafetags) {
- $sql_extra .= " and not term.term in ( " . stringify_array($unsafetags,true) . ") ";
- }
- }
-
-
- // Fetch tags
- $r = q("select term, count(term) as total from term left join item on term.oid = item.id
- where term.ttype = %d
- and otype = %d and item_type = %d
- $sql_extra $uids $item_normal
- group by term order by total desc %s",
- intval($type),
- intval(TERM_OBJ_POST),
- intval(ITEM_TYPE_POST),
- ((intval($count)) ? "limit $count" : '')
- );
-
- if(! $r)
- return array();
-
- return Zotlabs\Text\Tagadelic::calc($r);
-
+ $item_normal = item_normal();
+ $count = intval($limit);
+
+ if($site)
+ $uids = " and item.uid in ( " . stream_perms_api_uids(PERMS_PUBLIC) . " ) and item_private = 0 and item_wall = 1 ";
+ else {
+ $sys = get_sys_channel();
+ $uids = " and item.uid = " . intval($sys['channel_id']) . " ";
+ $sql_extra = " and item_private = 0 ";
+ }
+
+ if($recent)
+ $sql_extra .= " and item.created > '" . datetime_convert('UTC','UTC', 'now - ' . intval($recent) . ' days ') . "' ";
+
+
+ if($safemode) {
+ $unsafetags = get_config('system','unsafepubtags', [ 'boobs', 'bot', 'rss', 'girl','girls', 'nsfw', 'sexy', 'nude' ]);
+ if($unsafetags) {
+ $sql_extra .= " and not term.term in ( " . stringify_array($unsafetags,true) . ") ";
+ }
+ }
+
+
+ $key = __FUNCTION__ . "-" . md5($site . $recent . $safemode . $limit . $type);
+ $content = Cache::get($key, '1 MINUTE');
+
+ if(! $content) {
+ // Fetch tags
+ $r = q("SELECT term, count(term) AS total FROM term LEFT JOIN item ON term.oid = item.id
+ where term.ttype = %d
+ and otype = %d and item_type = %d
+ $sql_extra $uids $item_normal
+ group by term order by total desc %s",
+ intval($type),
+ intval(TERM_OBJ_POST),
+ intval(ITEM_TYPE_POST),
+ ((intval($count)) ? "limit $count" : '')
+ );
+ } else
+ $r = unserialize($content);
+
+ if(! $r)
+ return array();
+ else
+ Cache::set($key, serialize($r));
+
+ return Zotlabs\Text\Tagadelic::calc($r);
}
diff --git a/include/text.php b/include/text.php
index 44af40810..58cde7838 100644
--- a/include/text.php
+++ b/include/text.php
@@ -659,6 +659,26 @@ function hz_syslog($msg, $priority = LOG_INFO) {
closelog();
}
+/**
+ * @brief like hz_syslog() but with a function backtrace to pinpoint certain classes
+ * of problems which show up deep in the calling stack.
+ *
+ * @param string $msg Message to log
+ * @param int $priority - compatible with syslog
+ */
+function bt_syslog($msg, $priority = LOG_INFO) {
+ $stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
+ if($stack) {
+ for($x = 1; $x < count($stack); $x ++) {
+ $s = 'stack: ' . basename($stack[$x]['file']) . ':' . $stack[$x]['line'] . ':' . $stack[$x]['function'] . '()';
+ openlog("bt-log", LOG_PID | LOG_PERROR, LOG_LOCAL0);
+ syslog($priority, $s);
+ closelog();
+ }
+ }
+}
+
+
/**
* @brief Logging function for Hubzilla.
@@ -742,7 +762,6 @@ function btlogger($msg, $level = LOGGER_NORMAL, $priority = LOG_INFO) {
for($x = 1; $x < count($stack); $x ++) {
$s = 'stack: ' . basename($stack[$x]['file']) . ':' . $stack[$x]['line'] . ':' . $stack[$x]['function'] . '()';
logger($s,$level, $priority);
-
if(file_exists(BTLOGGER_DEBUG_FILE) && is_writable(BTLOGGER_DEBUG_FILE)) {
@file_put_contents(BTLOGGER_DEBUG_FILE, $s . PHP_EOL, FILE_APPEND);
}
@@ -864,6 +883,11 @@ function get_tags($s) {
$ret[] = $mtch;
}
}
+ if(preg_match_all('/([@#\!]\".*?\")/',$s,$match)) {
+ foreach($match[1] as $mtch) {
+ $ret[] = $mtch;
+ }
+ }
// match bracket mentions
@@ -1010,16 +1034,36 @@ function contact_block() {
if(count($r)) {
$contacts = t('Connections');
- $micropro = Array();
+ $micropro = [];
foreach($r as $rr) {
// 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.
+ $rr['perminfo']['connpermcount']=0;
+ $rr['perminfo']['connperms']=t('Accepts').': ';
+ if(intval(get_abconfig(App::$profile['uid'],$rr['xchan_hash'],'their_perms','post_comments'))) {
+ $rr['perminfo']['connpermcount']++;
+ $rr['perminfo']['connperms'] .= t('Comments');
+ }
+ if(intval(get_abconfig(App::$profile['uid'],$rr['xchan_hash'],'their_perms','send_stream'))) {
+ $rr['perminfo']['connpermcount']++;
+ $rr['perminfo']['connperms'] = ($rr['perminfo']['connperms']) ? $rr['perminfo']['connperms'] . ', ' : $rr['perminfo']['connperms'] ;
+ $rr['perminfo']['connperms'] .= t('Stream items');
+ }
+ if(intval(get_abconfig(App::$profile['uid'],$rr['xchan_hash'],'their_perms','post_wall'))) {
+ $rr['perminfo']['connpermcount']++;
+ $rr['perminfo']['connperms'] = ($rr['perminfo']['connperms']) ? $rr['perminfo']['connperms'] . ', ' : $rr['perminfo']['connperms'] ;
+ $rr['perminfo']['connperms'] .= t('Wall posts');
+ }
- if(! intval(get_abconfig(App::$profile['uid'],$rr['xchan_hash'],'their_perms','post_comments'))) {
- $rr['oneway'] = true;
+ if ($rr['perminfo']['connpermcount'] == 0) {
+ $rr['perminfo']['connperms'] .= t('Nothing');
}
+
+ if(!$is_owner && $rr['perminfo']['connpermcount'] !== 0)
+ unset($rr['perminfo']);
+
$micropro[] = micropro($rr,true,'mpfriend');
}
}
@@ -1030,7 +1074,7 @@ function contact_block() {
'$contacts' => $contacts,
'$nickname' => App::$profile['channel_address'],
'$viewconnections' => (($total > $shown) ? sprintf(t('View all %s connections'),$total) : ''),
- '$micropro' => $micropro,
+ '$micropro' => $micropro
));
$arr = ['contacts' => $r, 'output' => $o];
@@ -1086,6 +1130,7 @@ function micropro($contact, $redirect = false, $class = '', $mode = false) {
'$click' => (($contact['click']) ? $contact['click'] : ''),
'$class' => $class . (($contact['archived']) ? ' archived' : ''),
'$oneway' => (($contact['oneway']) ? true : false),
+ '$perminfo' => $contact['perminfo'],
'$url' => $url,
'$photo' => $contact['xchan_photo_s'],
'$name' => $contact['xchan_name'],
@@ -1713,6 +1758,11 @@ function prepare_body(&$item,$attach = false,$opts = false) {
}
}
+ $poll = (($item['obj_type'] === 'Question' && in_array($item['verb'],[ ACTIVITY_POST, ACTIVITY_UPDATE, ACTIVITY_SHARE ])) ? format_poll($item, $s, $opts) : false);
+ if ($poll) {
+ $s = $poll;
+ }
+
$event = (($item['obj_type'] === ACTIVITY_OBJ_EVENT) ? format_event_obj($item['obj']) : false);
$prep_arr = [
@@ -1796,6 +1846,89 @@ function prepare_binary($item) {
}
+function format_poll($item,$s,$opts) {
+
+ if (! is_array($item['obj'])) {
+ $act = json_decode($item['obj'],true);
+ }
+ else {
+ $act = $item['obj'];
+ }
+
+ if (! is_array($act)) {
+ return EMPTY_STR;
+ }
+
+ $commentable = can_comment_on_post(((local_channel()) ? get_observer_hash() : EMPTY_STR),$item);
+
+ //logger('format_poll: ' . print_r($item,true));
+ $activated = ((local_channel() && local_channel() == $item['uid']) ? true : false);
+ $output = $s . EOL. EOL;
+
+ if ($act['type'] === 'Question') {
+ if ($activated and $commentable) {
+ $output .= '<form id="question-form-' . $item['id'] . '" >';
+ }
+ if (array_key_exists('anyOf',$act) && is_array($act['anyOf'])) {
+ foreach ($act['anyOf'] as $poll) {
+ if (array_key_exists('name',$poll) && $poll['name']) {
+ $text = html2plain(purify_html($poll['name']),256);
+ if (array_path_exists('replies/totalItems',$poll)) {
+ $total = $poll['replies']['totalItems'];
+ }
+ else {
+ $total = 0;
+ }
+ if ($activated && $commentable) {
+ $output .= '<input type="checkbox" name="answer[]" value="' . htmlspecialchars($text) . '"> ' . $text . '</input>' . ' (' . $total . ')' . EOL;
+ }
+ else {
+ $output .= '[ ] ' . $text . ' (' . $total . ')' . EOL;
+ }
+ }
+ }
+ }
+ if (array_key_exists('oneOf',$act) && is_array($act['oneOf'])) {
+ foreach ($act['oneOf'] as $poll) {
+ if (array_key_exists('name',$poll) && $poll['name']) {
+ $text = html2plain(purify_html($poll['name']),256);
+ if (array_path_exists('replies/totalItems',$poll)) {
+ $total = $poll['replies']['totalItems'];
+ }
+ else {
+ $total = 0;
+ }
+ if ($activated && $commentable) {
+ $output .= '<input type="radio" name="answer" value="' . htmlspecialchars($text) . '"> ' . $text . '</input>' . ' (' . $total . ')' . EOL;
+ }
+ else {
+ $output .= '( ) ' . $text . ' (' . $total . ')' . EOL;
+ }
+ }
+ }
+ }
+ if ($item['comments_closed'] > NULL_DATE) {
+ $t = datetime_convert('UTC',date_default_timezone_get(), $item['comments_closed'], 'Y-m-d H:i');
+ $closed = ((datetime_convert() > $item['comments_closed']) ? true : false);
+ if ($closed) {
+ $message = t('Poll has ended.');
+ }
+ else {
+ $message = sprintf(t('Poll ends: %s'),$t);
+ }
+ $output .= EOL . '<div>' . $message . '</div>';
+ }
+ if ($activated and $commentable) {
+ $output .= EOL . '<input type="button" class="btn btn-std btn-success" name="vote" value="' . t("Vote") . '" onclick="submitPoll(' . $item['id'] . '); return false;">'. '</form>';
+ }
+
+ }
+ return $output;
+}
+
+
+
+
/**
* @brief Given a text string, convert from content_type to HTML.
*
@@ -1932,7 +2065,7 @@ function get_plink($item,$conversation_mode = true) {
$zidify = true;
- if(array_key_exists('author',$item) && $item['author']['xchan_network'] !== 'zot')
+ if(array_key_exists('author',$item) && in_array($item['author']['xchan_network'], ['zot6', 'zot']) === false)
$zidify = false;
if(x($item,$key)) {
@@ -2122,7 +2255,7 @@ function item_post_type($item) {
$post_type = t('event');
break;
default:
- $post_type = t('status');
+ $post_type = t('post');
if($item['mid'] != $item['parent_mid'])
$post_type = t('comment');
break;
@@ -2131,6 +2264,9 @@ function item_post_type($item) {
if(strlen($item['verb']) && (! activity_match($item['verb'],ACTIVITY_POST)))
$post_type = t('activity');
+ if($item['obj_type'] === 'Question')
+ $post_type = t('poll');
+
return $post_type;
}
@@ -2686,6 +2822,10 @@ function handle_tag(&$body, &$str_tags, $profile_uid, $tag, $in_network = true)
$basetag = substr($tag,7);
$basetag = substr($basetag,0,-6);
}
+ elseif((substr($tag,0,2) === '#"') && (substr($tag,-1,1) === '"')) {
+ $basetag = substr($tag,2);
+ $basetag = substr($basetag,0,-1);
+ }
else
$basetag = substr($tag,1);
@@ -2768,6 +2908,10 @@ function handle_tag(&$body, &$str_tags, $profile_uid, $tag, $in_network = true)
$newname = substr($name,6);
$newname = substr($newname,0,-6);
}
+ elseif((substr($name,0,1) === '"') && (substr($name,-1,1) === '"')) {
+ $newname = substr($name,1);
+ $newname = substr($newname,0,-1);
+ }
// select someone from this user's contacts by name
@@ -2974,6 +3118,7 @@ function getIconFromType($type) {
'image/jpeg' => 'fa-picture-o',
'image/png' => 'fa-picture-o',
'image/gif' => 'fa-picture-o',
+ 'image/webp' => 'fa-picture-o',
'image/svg+xml' => 'fa-picture-o',
//Archive
'application/zip' => 'fa-file-archive-o',
@@ -3535,11 +3680,15 @@ function get_forum_channels($uid) {
if(! $uid)
return;
- $xf = false;
+ if(App::$data['forum_channels'])
+ return App::$data['forum_channels'];
+
+ $xf = '';
$x1 = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'send_stream' and v = '0'",
intval($uid)
);
+
if($x1) {
$xc = ids_to_querystr($x1,'xchan',true);
@@ -3547,22 +3696,21 @@ function get_forum_channels($uid) {
intval($uid)
);
- if($x2) {
- $xf = ids_to_querystr($x2,'xchan',true);
+ $xf = ids_to_querystr($x2,'xchan',true);
+ $sql_extra = (($xf) ? ' and not xchan in (' . $xf . ')' : '');
- // private forums
- $x3 = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'post_wall' and v = '1' and xchan in (" . $xc . ") and not xchan in (" . $xf . ") ",
- intval(local_channel())
- );
- if($x3) {
- $xf = ids_to_querystr(array_merge($x2,$x3),'xchan',true);
- }
+ // private forums
+ $x3 = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'post_wall' and v = '1' and xchan in (" . $xc . ") $sql_extra ",
+ intval(local_channel())
+ );
+ if($x3) {
+ $xf = ids_to_querystr(array_merge($x2,$x3),'xchan',true);
}
}
- $sql_extra = (($xf) ? " and ( xchan_hash in (" . $xf . ") or xchan_pubforum = 1 ) " : " and xchan_pubforum = 1 ");
+ $sql_extra_1 = (($xf) ? " and ( xchan_hash in (" . $xf . ") or xchan_pubforum = 1 ) " : " and xchan_pubforum = 1 ");
- $r = q("select abook_id, xchan_hash, xchan_name, xchan_url, xchan_addr, xchan_photo_s from abook left join xchan on abook_xchan = xchan_hash where xchan_deleted = 0 and abook_channel = %d and abook_pending = 0 and abook_ignored = 0 and abook_blocked = 0 and abook_archived = 0 $sql_extra order by xchan_name",
+ $r = q("select abook_id, xchan_hash, xchan_name, xchan_url, xchan_addr, xchan_photo_s from abook left join xchan on abook_xchan = xchan_hash where xchan_deleted = 0 and abook_channel = %d and abook_pending = 0 and abook_ignored = 0 and abook_blocked = 0 and abook_archived = 0 $sql_extra_1 order by xchan_name",
intval($uid)
);
@@ -3576,6 +3724,8 @@ function get_forum_channels($uid) {
}
}
+ App::$data['forum_channels'] = $r;
+
return $r;
}
@@ -3625,7 +3775,7 @@ function array_path_exists($str,$arr) {
if($search) {
foreach($search as $s) {
- if(array_key_exists($s,$ptr)) {
+ if ($ptr && is_array($ptr) && array_key_exists($s,$ptr)) {
$ptr = $ptr[$s];
}
else {
@@ -3675,3 +3825,27 @@ function svg2bb($s) {
}
return EMPTY_STR;
}
+
+
+
+function serialise($x) {
+ return ((is_array($x)) ? 'json:' . json_encode($x) : $x);
+}
+
+function unserialise($x) {
+ if (is_array($x)) {
+ return $x;
+ }
+ $y = ((substr($x,0,5) === 'json:') ? json_decode(substr($x,5),true) : '');
+ return ((is_array($y)) ? $y : $x);
+}
+
+/**
+ * @brief Remove new lines and tabs from strings.
+ *
+ * @return string
+ */
+function sanitize_text_field($str) {
+ return preg_replace('/\s+/S', ' ', $str);
+}
+
diff --git a/include/xchan.php b/include/xchan.php
index d69d707aa..5de828e7f 100644
--- a/include/xchan.php
+++ b/include/xchan.php
@@ -25,7 +25,7 @@ function xchan_store_lowlevel($arr) {
'xchan_connurl' => ((array_key_exists('xchan_connurl',$arr)) ? $arr['xchan_connurl'] : ''),
'xchan_follow' => ((array_key_exists('xchan_follow',$arr)) ? $arr['xchan_follow'] : ''),
'xchan_connpage' => ((array_key_exists('xchan_connpage',$arr)) ? $arr['xchan_connpage'] : ''),
- 'xchan_name' => ((array_key_exists('xchan_name',$arr)) ? $arr['xchan_name'] : ''),
+ 'xchan_name' => ((array_key_exists('xchan_name',$arr)) ? sanitize_text_field($arr['xchan_name']) : ''),
'xchan_network' => ((array_key_exists('xchan_network',$arr)) ? $arr['xchan_network'] : ''),
'xchan_instance_url' => ((array_key_exists('xchan_instance_url',$arr)) ? $arr['xchan_instance_url'] : ''),
'xchan_flags' => ((array_key_exists('xchan_flags',$arr)) ? intval($arr['xchan_flags']) : 0),
@@ -264,4 +264,4 @@ function xchan_change_key($oldx,$newx,$data) {
foreach($acls as $k => $v) {
xchan_keychange_acl($k,$v,$oldx,$newx);
}
-} \ No newline at end of file
+}
diff --git a/include/zid.php b/include/zid.php
index 3b3dd8554..538adcc41 100644
--- a/include/zid.php
+++ b/include/zid.php
@@ -1,5 +1,6 @@
<?php
+use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\Verify;
function is_matrix_url($url) {
@@ -278,44 +279,39 @@ function owt_init($token) {
Verify::purge('owt', '3 MINUTE');
- $key = Verify::get_meta('owt', 0, $token);
+ $ob_hash = Verify::get_meta('owt', 0, $token);
- if($key === false) {
- return;
- }
-
- $parts = explode(',',$key,2);
- if(count($parts) < 2) {
+ if($ob_hash === false) {
return;
}
$r = q("select * from hubloc left join xchan on xchan_hash = hubloc_hash
- where hubloc_network = '%s' and hubloc_addr = '%s' order by hubloc_id desc",
- dbesc($parts[0]),
- dbesc($parts[1])
+ where hubloc_addr = '%s' or hubloc_id_url = '%s' or hubloc_hash = '%s' order by hubloc_id desc",
+ dbesc($ob_hash),
+ dbesc($ob_hash),
+ dbesc($ob_hash)
);
if(! $r) {
-
// finger them if they can't be found.
- // @todo check that this is still needed. Discovery should have been performed in the Owa module.
-
- $j = \Zotlabs\Zot\Finger::run($parts[1], null);
- if ($j['success']) {
- import_xchan($j);
+ $wf = discover_by_webbie($ob_hash);
+ if($wf) {
$r = q("select * from hubloc left join xchan on xchan_hash = hubloc_hash
- where hubloc_network = '%s' and hubloc_addr = '%s' order by hubloc_id desc",
- dbesc($parts[0]),
- dbesc($parts[1])
+ where hubloc_addr = '%s' or hubloc_id_url = '%s' or hubloc_hash = '%s' order by hubloc_id desc",
+ dbesc($ob_hash),
+ dbesc($ob_hash),
+ dbesc($ob_hash)
);
}
}
if(! $r) {
- logger('owt: unable to finger ' . $key);
+ logger('owt: unable to finger ' . $ob_hash);
return;
}
-
- $hubloc = $r[0];
+
+ $r = Libzot::zot_record_preferred($r);
+
+ $hubloc = $r;
$_SESSION['authenticated'] = 1;
@@ -341,7 +337,7 @@ function owt_init($token) {
if (! $delegate_success) {
// normal visitor (remote_channel) login session credentials
$_SESSION['visitor_id'] = $hubloc['xchan_hash'];
- $_SESSION['my_url'] = $hubloc['xchan_url'];
+ $_SESSION['my_url'] = $hubloc['xchan_url'];
$_SESSION['my_address'] = $hubloc['hubloc_addr'];
$_SESSION['remote_hub'] = $hubloc['hubloc_url'];
$_SESSION['DNT'] = 1;
@@ -401,9 +397,7 @@ function observer_auth($ob_hash) {
return;
}
- // Note: this has no Libzot namespace so prefers zot over zot6
-
- $hubloc = zot_record_preferred($r);
+ $hubloc = Libzot::zot_record_preferred($r);
$_SESSION['authenticated'] = 1;
diff --git a/include/zot.php b/include/zot.php
index d08146287..8a2177de7 100644
--- a/include/zot.php
+++ b/include/zot.php
@@ -9,6 +9,8 @@
*/
use Zotlabs\Lib\DReport;
+use Zotlabs\Lib\Libzot;
+use Zotlabs\Lib\Activity;
require_once('include/crypto.php');
require_once('include/items.php');
@@ -407,8 +409,8 @@ function zot_refresh($them, $channel = null, $force = false) {
$postvars['token'] = $token;
if($channel) {
- $postvars['target'] = $channel['channel_guid'];
- $postvars['target_sig'] = $channel['channel_guid_sig'];
+ $postvars['target'] = $channel['xchan_guid'];
+ $postvars['target_sig'] = str_replace('sha256.', '', $channel['xchan_guid_sig']);
$postvars['key'] = $channel['channel_pubkey'];
}
@@ -426,7 +428,6 @@ function zot_refresh($them, $channel = null, $force = false) {
logger('zot_refresh: ' . $url, LOGGER_DATA, LOG_INFO);
-
$result = z_post_url($url . $rhs,$postvars);
if ($result['success']) {
@@ -578,7 +579,7 @@ function zot_refresh($them, $channel = null, $force = false) {
[
'type' => NOTIFY_INTRO,
'from_xchan' => $x['hash'],
- 'to_xchan' => $channel['channel_hash'],
+ 'to_xchan' => $channel['channel_portable_id'],
'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id']
]
);
@@ -921,7 +922,7 @@ function import_xchan($arr, $ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) {
// see if this is a channel clone that's hosted locally - which we treat different from other xchans/connections
- $local = q("select channel_account_id, channel_id from channel where channel_hash = '%s' limit 1",
+ $local = q("select channel_account_id, channel_id from channel where channel_portable_id = '%s' limit 1",
dbesc($xchan_hash)
);
@@ -1299,7 +1300,7 @@ function zot_fetch($arr) {
*
* @returns array
* Suitable for logging remotely, enumerating the processing results of each message/recipient combination
- * * [0] => \e string $channel_hash
+ * * [0] => \e string $channel_portable_id
* * [1] => \e string $delivery_status
* * [2] => \e string $address
*/
@@ -1385,7 +1386,7 @@ function zot_import($arr, $sender_url) {
if($recip_arr) {
stringify_array_elms($recip_arr);
$recips = implode(',',$recip_arr);
- $r = q("select channel_hash as hash from channel where channel_hash in ( " . $recips . " )
+ $r = q("select channel_portable_id as hash from channel where channel_portable_id in ( " . $recips . " )
and channel_removed = 0 ");
}
@@ -1596,11 +1597,11 @@ function public_recips($msg) {
$r = array();
- $c = q("select channel_id, channel_hash from channel where channel_removed = 0");
+ $c = q("select channel_id, channel_portable_id from channel where channel_removed = 0");
if($c) {
foreach($c as $cc) {
if(perm_is_allowed($cc['channel_id'],$msg['notify']['sender']['hash'],$perm)) {
- $r[] = [ 'hash' => $cc['channel_hash'] ];
+ $r[] = [ 'hash' => $cc['channel_portable_id'] ];
}
}
}
@@ -1610,7 +1611,7 @@ function public_recips($msg) {
if($include_sys && array_key_exists('public_scope',$msg['message']) && $msg['message']['public_scope'] === 'public') {
$sys = get_sys_channel();
if($sys)
- $r[] = [ 'hash' => $sys['channel_hash'] ];
+ $r[] = [ 'hash' => $sys['channel_portable_id'] ];
}
// look for any public mentions on this site
@@ -1624,7 +1625,7 @@ function public_recips($msg) {
if(($tag['type'] === 'mention' || $tag['type'] === 'forum') && (strpos($tag['url'],z_root()) !== false)) {
$address = basename($tag['url']);
if($address) {
- $z = q("select channel_hash as hash from channel where channel_address = '%s'
+ $z = q("select channel_portable_id as hash from channel where channel_address = '%s'
and channel_removed = 0 limit 1",
dbesc($address)
);
@@ -1727,7 +1728,7 @@ function allowed_public_recips($msg) {
$condensed_recips[] = $rr['hash'];
$results = array();
- $r = q("select channel_hash as hash, channel_id from channel left join abook on abook_channel = channel_id where abook_xchan = '%s' and channel_removed = 0 ",
+ $r = q("select channel_portable_id as hash, channel_id from channel left join abook on abook_channel = channel_id where abook_xchan = '%s' and channel_removed = 0 ",
dbesc($hash)
);
if($r) {
@@ -1776,7 +1777,7 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $
$DR = new Zotlabs\Lib\DReport(z_root(),$sender['hash'],$d['hash'],$arr['mid']);
- $channel = channelx_by_hash($d['hash']);
+ $channel = channelx_by_portid($d['hash']);
if(! $channel) {
$DR->update('recipient not found');
@@ -1953,6 +1954,34 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $
intval($channel['channel_id']),
dbesc($arr['owner_xchan'])
);
+
+ if(! $ab) {
+
+ $best_owner_xchan = find_best_zot_identity($arr['owner_xchan']);
+
+ $ab = q("select * from abook where abook_channel = %d and abook_xchan = '%s'",
+ intval($channel['channel_id']),
+ dbesc($best_owner_xchan)
+ );
+
+ if($ab) {
+ logger('rewrite owner: ' . $arr['owner_xchan'] . ' > ' . $best_owner_xchan);
+ $arr['owner_xchan'] = $best_owner_xchan;
+ }
+ }
+
+ $best_author_xchan = find_best_zot_identity($arr['author_xchan']);
+
+ $ab_author = q("select * from abook where abook_channel = %d and abook_xchan = '%s'",
+ intval($channel['channel_id']),
+ dbesc($best_author_xchan)
+ );
+
+ if($ab_author) {
+ logger('rewrite author: ' . $arr['author_xchan'] . ' > ' . $best_author_xchan);
+ $arr['author_xchan'] = $best_author_xchan;
+ }
+
$abook = (($ab) ? $ab[0] : null);
if(intval($arr['item_deleted'])) {
@@ -2076,7 +2105,7 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $
$stored = (($item_result && $item_result['item']) ? $item_result['item'] : false);
if((is_array($stored)) && ($stored['id'] != $stored['parent'])
- && ($stored['author_xchan'] === $channel['channel_hash'])) {
+ && ($stored['author_xchan'] === $channel['channel_portable_id'])) {
retain_item($stored['item']['parent']);
}
@@ -2344,7 +2373,7 @@ function process_mail_delivery($sender, $arr, $deliveries) {
$DR = new Zotlabs\Lib\DReport(z_root(),$sender['hash'],$d['hash'],$arr['mid']);
- $r = q("select * from channel where channel_hash = '%s' limit 1",
+ $r = q("select * from channel where channel_portable_id = '%s' limit 1",
dbesc($d['hash'])
);
@@ -2555,7 +2584,7 @@ function check_location_move($sender_hash, $locations) {
$loc = $locations[0];
- $r = q("select * from channel where channel_hash = '%s' limit 1",
+ $r = q("select * from channel where channel_portable_id = '%s' limit 1",
dbesc($sender_hash)
);
@@ -2563,7 +2592,7 @@ function check_location_move($sender_hash, $locations) {
return;
if($loc['url'] !== z_root()) {
- $x = q("update channel set channel_moved = '%s' where channel_hash = '%s' limit 1",
+ $x = q("update channel set channel_moved = '%s' where channel_portable_id = '%s' limit 1",
dbesc($loc['url']),
dbesc($sender_hash)
);
@@ -2764,6 +2793,8 @@ function sync_locations($sender, $arr, $absolute = false) {
}
logger('New hub: ' . $location['url']);
+ $addr_arr = explode('@', $location['address']);
+
$r = hubloc_store_lowlevel(
[
'hubloc_guid' => $sender['guid'],
@@ -2778,7 +2809,8 @@ function sync_locations($sender, $arr, $absolute = false) {
'hubloc_callback' => $location['callback'],
'hubloc_sitekey' => $location['sitekey'],
'hubloc_updated' => datetime_convert(),
- 'hubloc_connected' => datetime_convert()
+ 'hubloc_connected' => datetime_convert(),
+ 'hubloc_id_url' => $location['url'] . '/channel/' . $addr_arr[0]
]
);
@@ -2826,13 +2858,13 @@ function sync_locations($sender, $arr, $absolute = false) {
*
* @see zot_get_hublocs()
* @param array $channel an associative array which must contain
- * * \e string \b channel_hash the hash of the channel
+ * * \e string \b channel_portable_id the hash of the channel
* @return array an array with associative arrays
*/
function zot_encode_locations($channel) {
$ret = array();
- $x = zot_get_hublocs($channel['channel_hash']);
+ $x = zot_get_hublocs($channel['channel_portable_id']);
if($x && count($x)) {
foreach($x as $hub) {
@@ -3300,8 +3332,8 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) {
if(intval($channel['channel_removed']))
return;
- $h = q("select hubloc.*, site.site_crypto from hubloc left join site on site_url = hubloc_url where hubloc_hash = '%s' and hubloc_deleted = 0",
- dbesc(($keychange) ? $packet['keychange']['old_hash'] : $channel['channel_hash'])
+ $h = q("select hubloc.*, site.site_crypto, site.site_version, site.site_project from hubloc left join site on site_url = hubloc_url where hubloc_hash = '%s' and hubloc_deleted = 0",
+ dbesc(($keychange) ? $packet['keychange']['old_hash'] : $channel['channel_portable_id'])
);
if(! $h)
@@ -3313,6 +3345,14 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) {
if($x['hubloc_host'] == App::get_hostname())
continue;
+ if(stripos($x['site_project'], 'hubzilla') !== false && version_compare($x['site_version'], '4.7.3', '<=')) {
+
+ logger('Dismiss sync due to incompatible version.');
+ // logger(print_r($x,true));
+ continue;
+
+ }
+
$y = q("select site_dead from site where site_url = '%s' limit 1",
dbesc($x['hubloc_url'])
);
@@ -3325,8 +3365,9 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) {
return;
$r = q("select xchan_guid, xchan_guid_sig from xchan where xchan_hash = '%s' limit 1",
- dbesc($channel['channel_hash'])
+ dbesc($channel['channel_portable_id'])
);
+
if(! $r)
return;
@@ -3611,6 +3652,12 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
if(array_key_exists('app',$arr) && $arr['app'])
sync_apps($channel,$arr['app']);
+ if(array_key_exists('addressbook',$arr) && $arr['addressbook'])
+ sync_addressbook($channel,$arr['addressbook']);
+
+ if(array_key_exists('calendar',$arr) && $arr['calendar'])
+ sync_calendar($channel,$arr['calendar']);
+
if(array_key_exists('chatroom',$arr) && $arr['chatroom'])
sync_chatrooms($channel,$arr['chatroom']);
@@ -4186,7 +4233,7 @@ function zot_reply_message_request($data) {
$arr = $data['recipients'][0];
$recip_hash = make_xchan_hash($arr['guid'],$arr['guid_sig']);
- $c = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_hash = '%s' limit 1",
+ $c = q("select * from channel left join xchan on channel_portable_id = xchan_hash where channel_portable_id = '%s' limit 1",
dbesc($recip_hash)
);
if (! $c) {
@@ -4332,21 +4379,21 @@ function zotinfo($arr) {
$r = null;
if(strlen($zhash)) {
- $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
- where channel_hash = '%s' limit 1",
+ $r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
+ where channel_portable_id = '%s' limit 1",
dbesc($zhash)
);
}
elseif(strlen($zguid) && strlen($zguid_sig)) {
- $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
+ $r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
where channel_guid = '%s' and channel_guid_sig = '%s' limit 1",
dbesc($zguid),
- dbesc($zguid_sig)
+ dbesc('sha256.' . $zguid_sig)
);
}
elseif(strlen($zaddr)) {
if(strpos($zaddr,'[system]') === false) { /* normal address lookup */
- $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
+ $r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
where ( channel_address = '%s' or xchan_addr = '%s' ) limit 1",
dbesc($zaddr),
dbesc($zaddr)
@@ -4366,10 +4413,10 @@ function zotinfo($arr) {
*
*/
- $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
+ $r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
where channel_system = 1 order by channel_id limit 1");
if(! $r) {
- $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
+ $r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
where channel_removed = 0 order by channel_id limit 1");
}
}
@@ -4693,14 +4740,14 @@ function check_zotinfo($channel, $locations, &$ret) {
// for the sys channel as normal channels will be trickier.
q("delete from hubloc where hubloc_hash = '%s'",
- dbesc($channel['channel_hash'])
+ dbesc($channel['channel_portable_id'])
);
$r = hubloc_store_lowlevel(
[
'hubloc_guid' => $channel['channel_guid'],
'hubloc_guid_sig' => $channel['channel_guid_sig'],
- 'hubloc_hash' => $channel['channel_hash'],
+ 'hubloc_hash' => $channel['channel_portable_id'],
'hubloc_addr' => channel_reddress($channel),
'hubloc_network' => 'zot',
'hubloc_primary' => 1,
@@ -4755,7 +4802,7 @@ function delivery_report_is_storable($dr) {
// Is the sender one of our channels?
- $c = q("select channel_id from channel where channel_hash = '%s' limit 1",
+ $c = q("select channel_id from channel where channel_portable_id = '%s' limit 1",
dbesc($dr['sender'])
);
if(! $c)
@@ -5101,7 +5148,7 @@ function zot_reply_auth_check($data,$encrypted_packet) {
$arr = $data['recipients'][0];
$recip_hash = make_xchan_hash($arr['guid'], $arr['guid_sig']);
- $c = q("select channel_id, channel_account_id, channel_prvkey from channel where channel_hash = '%s' limit 1",
+ $c = q("select channel_id, channel_account_id, channel_prvkey from channel where channel_portable_id = '%s' limit 1",
dbesc($recip_hash)
);
if (! $c) {
@@ -5168,7 +5215,7 @@ function zot_reply_purge($sender, $recipients) {
// basically this means "unfriend"
foreach ($recipients as $recip) {
$r = q("select channel.*,xchan.* from channel
- left join xchan on channel_hash = xchan_hash
+ left join xchan on channel_portable_id = xchan_hash
where channel_guid = '%s' and channel_guid_sig = '%s' limit 1",
dbesc($recip['guid']),
dbesc($recip['guid_sig'])
@@ -5221,12 +5268,11 @@ function zot_reply_refresh($sender, $recipients) {
foreach ($recipients as $recip) {
$r = q("select channel.*,xchan.* from channel
- left join xchan on channel_hash = xchan_hash
- where channel_guid = '%s' and channel_guid_sig = '%s' limit 1",
+ left join xchan on channel_portable_id = xchan_hash
+ where xchan_guid = '%s' and xchan_guid_sig = '%s' limit 1",
dbesc($recip['guid']),
dbesc($recip['guid_sig'])
);
-
$x = zot_refresh(array(
'xchan_guid' => $sender['guid'],
'xchan_guid_sig' => $sender['guid_sig'],
@@ -5325,3 +5371,24 @@ function zot_record_preferred($arr, $check = 'hubloc_network') {
return $arr[0];
}
+
+function find_best_zot_identity($xchan) {
+
+ $r = q("select hubloc_addr from hubloc where hubloc_hash = '%s' and hubloc_network in ('zot6', 'zot') and hubloc_deleted = 0",
+ dbesc($xchan)
+ );
+
+ if ($r) {
+
+ $r = q("select hubloc_hash, hubloc_network from hubloc where hubloc_addr = '%s' and hubloc_network in ('zot6', 'zot') and hubloc_deleted = 0",
+ dbesc($r[0]['hubloc_addr'])
+ );
+ if ($r) {
+ $r = Libzot::zot_record_preferred($r);
+ logger('find_best_zot_identity: ' . $xchan . ' > ' . $r['hubloc_hash']);
+ return $r['hubloc_hash'];
+ }
+ }
+
+ return $xchan;
+}