aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-x.homeinstall/hubzilla-setup.sh24
-rw-r--r--Zotlabs/Daemon/Cron.php9
-rw-r--r--Zotlabs/Daemon/Importfile.php4
-rw-r--r--Zotlabs/Daemon/Onepoll.php6
-rw-r--r--Zotlabs/Lib/Activity.php238
-rw-r--r--Zotlabs/Lib/ActivityStreams.php13
-rw-r--r--Zotlabs/Lib/Apps.php6
-rw-r--r--Zotlabs/Lib/Chatroom.php4
-rw-r--r--Zotlabs/Lib/Connect.php2
-rw-r--r--Zotlabs/Lib/Enotify.php3
-rw-r--r--Zotlabs/Lib/NativeWiki.php6
-rw-r--r--Zotlabs/Lib/Share.php3
-rw-r--r--Zotlabs/Lib/ThreadItem.php2
-rw-r--r--Zotlabs/Module/Activity.php2
-rw-r--r--Zotlabs/Module/Channel_calendar.php8
-rw-r--r--Zotlabs/Module/Chat.php6
-rw-r--r--Zotlabs/Module/Connedit.php5
-rw-r--r--Zotlabs/Module/Cover_photo.php6
-rw-r--r--Zotlabs/Module/Defperms.php3
-rw-r--r--Zotlabs/Module/Display.php5
-rw-r--r--Zotlabs/Module/File_upload.php6
-rw-r--r--Zotlabs/Module/Filestorage.php12
-rw-r--r--Zotlabs/Module/Group.php3
-rw-r--r--Zotlabs/Module/Item.php100
-rw-r--r--Zotlabs/Module/Like.php5
-rw-r--r--Zotlabs/Module/Moderate.php4
-rw-r--r--Zotlabs/Module/Notes.php3
-rw-r--r--Zotlabs/Module/Pconfig.php4
-rw-r--r--Zotlabs/Module/Pdledit.php3
-rw-r--r--Zotlabs/Module/Permcats.php5
-rw-r--r--Zotlabs/Module/Photos.php10
-rw-r--r--Zotlabs/Module/Profile_photo.php8
-rw-r--r--Zotlabs/Module/Profiles.php4
-rw-r--r--Zotlabs/Module/Settings/Calendar.php3
-rw-r--r--Zotlabs/Module/Settings/Channel.php3
-rw-r--r--Zotlabs/Module/Settings/Channel_home.php4
-rw-r--r--Zotlabs/Module/Settings/Connections.php3
-rw-r--r--Zotlabs/Module/Settings/Conversation.php3
-rw-r--r--Zotlabs/Module/Settings/Directory.php3
-rw-r--r--Zotlabs/Module/Settings/Display.php3
-rw-r--r--Zotlabs/Module/Settings/Editor.php3
-rw-r--r--Zotlabs/Module/Settings/Events.php3
-rw-r--r--Zotlabs/Module/Settings/Featured.php3
-rw-r--r--Zotlabs/Module/Settings/Features.php4
-rw-r--r--Zotlabs/Module/Settings/Manage.php4
-rw-r--r--Zotlabs/Module/Settings/Network.php3
-rw-r--r--Zotlabs/Module/Settings/Photos.php3
-rw-r--r--Zotlabs/Module/Settings/Profiles.php4
-rw-r--r--Zotlabs/Module/Share.php3
-rw-r--r--Zotlabs/Module/Sharedwithme.php99
-rw-r--r--Zotlabs/Module/Sse_bs.php22
-rw-r--r--Zotlabs/Module/Starred.php3
-rw-r--r--Zotlabs/Module/Tagger.php4
-rw-r--r--Zotlabs/Module/Thing.php8
-rw-r--r--Zotlabs/Module/Wall_attach.php4
-rw-r--r--Zotlabs/Storage/Directory.php9
-rw-r--r--Zotlabs/Storage/File.php7
-rw-r--r--Zotlabs/Update/_1236.php46
-rw-r--r--include/attach.php206
-rw-r--r--include/bbcode.php135
-rw-r--r--include/channel.php6
-rw-r--r--include/conversation.php20
-rw-r--r--include/event.php27
-rw-r--r--include/features.php8
-rw-r--r--include/group.php9
-rwxr-xr-xinclude/items.php19
-rw-r--r--include/menu.php4
-rw-r--r--include/photos.php4
-rw-r--r--include/text.php2
-rw-r--r--include/zid.php5
-rw-r--r--include/zot.php2
-rw-r--r--spec/HTTPSignatures/Home.md34
-rw-r--r--spec/OpenWebAuth/Home.md57
-rw-r--r--spec/Zot6/Changelog.md16
-rw-r--r--spec/Zot6/Content.md15
-rw-r--r--spec/Zot6/Discovery.md112
-rw-r--r--spec/Zot6/Encryption+Signatures.md142
-rw-r--r--spec/Zot6/Home.md92
-rw-r--r--spec/Zot6/Message Types.md111
-rw-r--r--spec/Zot6/Messages.md135
-rw-r--r--spec/Zot6/Nomadic Identity.md7
-rwxr-xr-xutil/connect4
-rwxr-xr-xutil/dmkdir6
-rwxr-xr-xutil/pconfig4
-rwxr-xr-xview/tpl/jot.tpl12
85 files changed, 1617 insertions, 353 deletions
diff --git a/.homeinstall/hubzilla-setup.sh b/.homeinstall/hubzilla-setup.sh
index f1395e8ce..063cfcea4 100755
--- a/.homeinstall/hubzilla-setup.sh
+++ b/.homeinstall/hubzilla-setup.sh
@@ -235,7 +235,7 @@ function install_sendmail {
function install_php {
# openssl and mbstring are included in libapache2-mod-php
print_info "installing php..."
- nocheck_install "libapache2-mod-php php php-pear php-curl php-gd php-mysqli php-mbstring php-xml php-zip"
+ nocheck_install "libapache2-mod-php php php-pear php-curl php-gd php-mbstring php-xml php-zip"
sed -i "s/^upload_max_filesize =.*/upload_max_filesize = 100M/g" /etc/php/7.3/apache2/php.ini
sed -i "s/^post_max_size =.*/post_max_size = 100M/g" /etc/php/7.3/apache2/php.ini
}
@@ -322,7 +322,7 @@ function run_freedns {
then
die "You can not use freeDNS AND selfHOST for dynamic IP updates ('freedns_key' AND 'selfhost_user' set in $configfile)"
fi
- wget --no-check-certificate -O - https://freedns.afraid.org/dynamic/update.php?$freedns_key
+ wget --no-check-certificate -O - http://freedns.afraid.org/dynamic/update.php?$freedns_key
fi
}
@@ -389,8 +389,8 @@ function configure_cron_freedns {
# - every 30 minutes
if [ -z "`grep 'freedns.afraid.org' /etc/crontab`" ]
then
- echo "@reboot root https://freedns.afraid.org/dynamic/update.php?$freedns_key > /dev/null 2>&1" >> /etc/crontab
- echo "*/30 * * * * root wget --no-check-certificate -O - https://freedns.afraid.org/dynamic/update.php?$freedns_key > /dev/null 2>&1" >> /etc/crontab
+ echo "@reboot root http://freedns.afraid.org/dynamic/update.php?$freedns_key > /dev/null 2>&1" >> /etc/crontab
+ echo "*/30 * * * * root wget --no-check-certificate -O - http://freedns.afraid.org/dynamic/update.php?$freedns_key > /dev/null 2>&1" >> /etc/crontab
else
print_info "cron for freedns was configured already"
fi
@@ -448,11 +448,11 @@ function check_https {
function install_hubzilla {
print_info "installing addons..."
cd /var/www/html/
- if git remote -v | grep -i "origin.*hubzilla.*core"
+ if git remote -v | grep -i "origin.*hubzilla.*"
then
print_info "hubzilla"
util/add_addon_repo https://framagit.org/hubzilla/addons hzaddons
- elif git remote -v | grep -i "origin.*zap.*core"
+ elif git remote -v | grep -i "origin.*zap.*"
then
print_info "zap"
util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons
@@ -460,6 +460,7 @@ function install_hubzilla {
die "neither zap nor hubzilla repository > did not install addons or zap/hubzilla"
fi
mkdir -p "store/[data]/smarty3"
+ mkdir -p "store"
chmod -R 777 store
touch .htconfig.php
chmod ou+w .htconfig.php
@@ -624,7 +625,6 @@ configure_cron_selfhost
if [ "$le_domain" != "localhost" ]
then
install_letsencrypt
- configure_apache_for_https
check_https
else
print_info "is localhost - skipped installation of letsencrypt and configuration of apache for https"
@@ -632,20 +632,12 @@ fi
install_hubzilla
-if [ "$le_domain" != "localhost" ]
-then
- rewrite_to_https
- install_rsnapshot
-else
- print_info "is localhost - skipped rewrite to https and installation of rsnapshot"
-fi
-
configure_cron_daily
if [ "$le_domain" != "localhost" ]
then
install_cryptosetup
- write_uninstall_script
+ install_rsync
else
print_info "is localhost - skipped installation of cryptosetup"
fi
diff --git a/Zotlabs/Daemon/Cron.php b/Zotlabs/Daemon/Cron.php
index bd4e0b294..46f4e4071 100644
--- a/Zotlabs/Daemon/Cron.php
+++ b/Zotlabs/Daemon/Cron.php
@@ -2,6 +2,8 @@
namespace Zotlabs\Daemon;
+use Zotlabs\Lib\Libsync;
+
class Cron {
static public function run($argc,$argv) {
@@ -36,11 +38,6 @@ class Cron {
Master::Summon(array('Poller'));
- // maintenance for mod sharedwithme - check for updated items and remove them
-
- require_once('include/sharedwithme.php');
- apply_updates();
-
/**
* Chatpresence: if somebody hasn't pinged recently, they've most likely left the page
* and shouldn't count as online anymore. We allow an expection for bots.
@@ -147,7 +144,7 @@ class Cron {
if($z) {
xchan_query($z);
$sync_item = fetch_post_tags($z);
- build_sync_packet($sync_item[0]['uid'],
+ Libsync::build_sync_packet($sync_item[0]['uid'],
[
'item' => [ encode_item($sync_item[0],true) ]
]
diff --git a/Zotlabs/Daemon/Importfile.php b/Zotlabs/Daemon/Importfile.php
index c68ed21cf..749949679 100644
--- a/Zotlabs/Daemon/Importfile.php
+++ b/Zotlabs/Daemon/Importfile.php
@@ -2,6 +2,8 @@
namespace Zotlabs\Daemon;
+use Zotlabs\Lib\Libsync;
+
class Importfile {
static public function run($argc,$argv){
@@ -40,7 +42,7 @@ class Importfile {
$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)));
return;
}
diff --git a/Zotlabs/Daemon/Onepoll.php b/Zotlabs/Daemon/Onepoll.php
index 2f06ec125..fdcb907d1 100644
--- a/Zotlabs/Daemon/Onepoll.php
+++ b/Zotlabs/Daemon/Onepoll.php
@@ -76,7 +76,11 @@ class Onepoll {
// update permissions
- $x = zot_refresh($contact,$importer);
+ if($contact['xchan_network'] === 'zot6')
+ $x = Libzot::refresh($contact,$importer);
+
+ if($contact['xchan_network'] === 'zot')
+ $x = zot_refresh($contact,$importer);
$responded = false;
$updated = datetime_convert();
diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php
index 3c16a5367..5c72a1175 100644
--- a/Zotlabs/Lib/Activity.php
+++ b/Zotlabs/Lib/Activity.php
@@ -178,7 +178,6 @@ class Activity {
static function fetch_image($x) {
-
$ret = [
'type' => 'Image',
'id' => $x['id'],
@@ -419,7 +418,71 @@ class Activity {
$ret['attachment'] = $a;
}
+ $public = (($i['item_private']) ? false : true);
+ $top_level = (($i['mid'] === $i['parent_mid']) ? true : false);
+
+ if ($public) {
+ $ret['to'] = [ ACTIVITY_PUBLIC_INBOX ];
+ $ret['cc'] = [ z_root() . '/followers/' . substr($i['author']['xchan_addr'],0,strpos($i['author']['xchan_addr'],'@')) ];
+ }
+ else {
+
+ // private activity
+
+ if ($top_level) {
+ $ret['to'] = self::map_acl($i);
+ }
+ else {
+ $ret['to'] = [];
+ if ($ret['tag']) {
+ foreach ($ret['tag'] as $mention) {
+ if (is_array($mention) && array_key_exists('href',$mention) && $mention['href']) {
+ $h = q("select * from hubloc where hubloc_id_url = '%s' limit 1",
+ dbesc($mention['href'])
+ );
+ if ($h) {
+ if ($h[0]['hubloc_network'] === 'activitypub') {
+ $addr = $h[0]['hubloc_hash'];
+ }
+ else {
+ $addr = $h[0]['hubloc_id_url'];
+ }
+ if (! in_array($addr,$ret['to'])) {
+ $ret['to'][] = $addr;
+ }
+ }
+ }
+ }
+ }
+ $d = q("select hubloc.* from hubloc left join item on hubloc_hash = owner_xchan where item.id = %d limit 1",
+ intval($i['parent'])
+ );
+ if ($d) {
+ if ($d[0]['hubloc_network'] === 'activitypub') {
+ $addr = $d[0]['hubloc_hash'];
+ }
+ else {
+ $addr = $d[0]['hubloc_id_url'];
+ }
+ if (! in_array($addr,$ret['to'])) {
+ $ret['cc'][] = $addr;
+ }
+ }
+ }
+ }
+
+ $mentions = self::map_mentions($i);
+ if (count($mentions) > 0) {
+ if (! $ret['to']) {
+ $ret['to'] = $mentions;
+ }
+ else {
+ $ret['to'] = array_values(array_unique(array_merge($ret['to'], $mentions)));
+ }
+ }
+
return $ret;
+
}
static function decode_taxonomy($item) {
@@ -756,57 +819,155 @@ class Activity {
return [];
}
+ $t = self::encode_taxonomy($i);
+ if ($t) {
+ $ret['tag'] = $t;
+ }
+
+ // addressing madness
+
+ $public = (($i['item_private']) ? false : true);
+ $top_level = (($reply) ? false : true);
+
+ if ($public) {
+ $ret['to'] = [ ACTIVITY_PUBLIC_INBOX ];
+ $ret['cc'] = [ z_root() . '/followers/' . substr($i['author']['xchan_addr'],0,strpos($i['author']['xchan_addr'],'@')) ];
+ }
+ else {
+
+ // private activity
+
+ if ($top_level) {
+ $ret['to'] = self::map_acl($i);
+ }
+ else {
+ $ret['to'] = [];
+ if ($ret['tag']) {
+ foreach ($ret['tag'] as $mention) {
+ if (is_array($mention) && array_key_exists('href',$mention) && $mention['href']) {
+ $h = q("select * from hubloc where hubloc_id_url = '%s' limit 1",
+ dbesc($mention['href'])
+ );
+ if ($h) {
+ if ($h[0]['hubloc_network'] === 'activitypub') {
+ $addr = $h[0]['hubloc_hash'];
+ }
+ else {
+ $addr = $h[0]['hubloc_id_url'];
+ }
+ if (! in_array($addr,$ret['to'])) {
+ $ret['to'][] = $addr;
+ }
+ }
+ }
+ }
+ }
+
+ $d = q("select hubloc.* from hubloc left join item on hubloc_hash = owner_xchan where item.id = %d limit 1",
+ intval($i['parent'])
+ );
+ if ($d) {
+ if ($d[0]['hubloc_network'] === 'activitypub') {
+ $addr = $d[0]['hubloc_hash'];
+ }
+ else {
+ $addr = $d[0]['hubloc_id_url'];
+ }
+ if (! in_array($addr,$ret['to'])) {
+ $ret['cc'][] = $addr;
+ }
+ }
+ }
+ }
+
+ $mentions = self::map_mentions($i);
+ if (count($mentions) > 0) {
+ if (! $ret['to']) {
+ $ret['to'] = $mentions;
+ }
+ else {
+ $ret['to'] = array_values(array_unique(array_merge($ret['to'], $mentions)));
+ }
+ }
+
return $ret;
}
+ // Returns an array of URLS for any mention tags found in the item array $i.
+
static function map_mentions($i) {
- if(! $i['term']) {
+
+ if (! $i['term']) {
return [];
}
$list = [];
foreach ($i['term'] as $t) {
- if($t['ttype'] == TERM_MENTION) {
- $list[] = $t['url'];
+ if (! $t['url']) {
+ continue;
+ }
+ if ($t['ttype'] == TERM_MENTION) {
+ $url = self::lookup_term_url($t['url']);
+ $list[] = (($url) ? $url : $t['url']);
}
}
return $list;
}
- static function map_acl($i,$mentions = false) {
-
- $private = false;
- $list = [];
- $x = collect_recipients($i,$private);
- if($x) {
- stringify_array_elms($x);
- if(! $x)
- return;
+ // Returns an array of all recipients targeted by private item array $i.
- $strict = (($mentions) ? true : get_config('activitypub','compliance'));
+ static function map_acl($i) {
+ $ret = [];
- $sql_extra = (($strict) ? " and xchan_network = 'activitypub' " : '');
+ if (! $i['item_private']) {
+ return $ret;
+ }
- $details = q("select xchan_url, xchan_addr, xchan_name from xchan where xchan_hash in (" . implode(',',$x) . ") $sql_extra");
+ if ($i['allow_gid']) {
+ $tmp = expand_acl($i['allow_gid']);
+ if ($tmp) {
+ foreach ($tmp as $t) {
+ $ret[] = z_root() . '/lists/' . $t;
+ }
+ }
+ }
- if($details) {
- foreach($details as $d) {
- if($mentions) {
- $list[] = [ 'type' => 'Mention', 'href' => $d['xchan_url'], 'name' => '@' . (($d['xchan_addr']) ? $d['xchan_addr'] : $d['xchan_name']) ];
- }
- else {
- $list[] = $d['xchan_url'];
+ if ($i['allow_cid']) {
+ $tmp = expand_acl($i['allow_cid']);
+ $list = stringify_array($tmp,true);
+ if ($list) {
+ $details = q("select hubloc_id_url from hubloc where hubloc_hash in (" . $list . ") and hubloc_id_url != ''");
+ if ($details) {
+ foreach ($details as $d) {
+ $ret[] = $d['hubloc_id_url'];
}
}
}
}
- return $list;
-
+ return $ret;
}
+ static function lookup_term_url($url) {
+
+ // The xchan_url for mastodon is a text/html rendering. This is called from map_mentions where we need
+ // to convert the mention url to an ActivityPub id. If this fails for any reason, return the url we have
+
+ $r = q("select hubloc_network, hubloc_hash, hubloc_id_url from hubloc where hubloc_id_url = '%s' limit 1",
+ dbesc($url)
+ );
+
+ if ($r) {
+ if ($r[0]['hubloc_network'] === 'activitypub') {
+ return $r[0]['hubloc_hash'];
+ }
+ return $r[0]['hubloc_id_url'];
+ }
+
+ return $url;
+ }
static function encode_person($p, $extended = true) {
@@ -969,7 +1130,6 @@ class Activity {
'http://activitystrea.ms/schema/1.0/photo' => 'Image',
'http://activitystrea.ms/schema/1.0/profile-photo' => 'Icon',
'http://activitystrea.ms/schema/1.0/event' => 'Event',
- 'http://activitystrea.ms/schema/1.0/wiki' => 'Document',
'http://purl.org/zot/activity/location' => 'Place',
'http://purl.org/zot/activity/chessgame' => 'Game',
'http://purl.org/zot/activity/tagterm' => 'zot:Tag',
@@ -977,7 +1137,10 @@ class Activity {
'http://purl.org/zot/activity/file' => 'zot:File',
'http://purl.org/zot/activity/mood' => 'zot:Mood',
'Invite' => 'Invite',
- 'Question' => 'Question'
+ 'Question' => 'Question',
+ 'Document' => 'Document',
+ 'Audio' => 'Audio',
+ 'Video' => 'Video'
];
call_hooks('activity_obj_decode_mapper',$objs);
@@ -1005,7 +1168,6 @@ class Activity {
'http://activitystrea.ms/schema/1.0/photo' => 'Image',
'http://activitystrea.ms/schema/1.0/profile-photo' => 'Icon',
'http://activitystrea.ms/schema/1.0/event' => 'Event',
- 'http://activitystrea.ms/schema/1.0/wiki' => 'Document',
'http://purl.org/zot/activity/location' => 'Place',
'http://purl.org/zot/activity/chessgame' => 'Game',
'http://purl.org/zot/activity/tagterm' => 'zot:Tag',
@@ -1013,7 +1175,9 @@ class Activity {
'http://purl.org/zot/activity/file' => 'zot:File',
'http://purl.org/zot/activity/mood' => 'zot:Mood',
'Invite' => 'Invite',
- 'Question' => 'Question'
+ 'Question' => 'Question',
+ 'Audio' => 'Audio',
+ 'Video' => 'Video'
];
call_hooks('activity_obj_mapper',$objs);
@@ -2077,9 +2241,7 @@ class Activity {
}
- // avoid double images from hubzilla to zap/osada
-
- if($act->obj['type'] === 'Image' && strpos($s['body'],'zrl=') === false) {
+ if($act->obj['type'] === 'Image') {
$ptr = null;
@@ -2093,10 +2255,11 @@ class Activity {
}
foreach($ptr as $vurl) {
if(strpos($s['body'],$vurl['href']) === false) {
- $s['body'] .= '[zmg]' . $vurl['href'] . '[/zmg]' . "\n\n" . $s['body'];
+ $bb_imgs .= '[zmg]' . $vurl['href'] . '[/zmg]' . "\n\n";
break;
}
}
+ $s['body'] = $bb_imgs . $s['body'];
}
elseif(is_string($act->obj['url'])) {
if(strpos($s['body'],$act->obj['url']) === false) {
@@ -2177,8 +2340,13 @@ class Activity {
$s['plink'] = $s['mid'];
}
- if ($act->recips && (! in_array(ACTIVITY_PUBLIC_INBOX,$act->recips)))
- $s['item_private'] = 1;
+ // assume this is private unless specifically told otherwise.
+
+ $s['item_private'] = 1;
+
+ if ($act->recips && in_array(ACTIVITY_PUBLIC_INBOX, $act->recips)) {
+ $s['item_private'] = 0;
+ }
if (is_array($act->obj)) {
if (array_key_exists('directMessage',$act->obj) && intval($act->obj['directMessage'])) {
diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php
index d8bd72943..b1ef59364 100644
--- a/Zotlabs/Lib/ActivityStreams.php
+++ b/Zotlabs/Lib/ActivityStreams.php
@@ -146,15 +146,20 @@ class ActivityStreams {
*/
function collect_recips($base = '', $namespace = '') {
$x = [];
+
$fields = [ 'to', 'cc', 'bto', 'bcc', 'audience'];
foreach($fields as $f) {
$y = $this->get_compound_property($f, $base, $namespace);
if($y) {
- $x = array_merge($x, $y);
- if(! is_array($this->raw_recips))
+ if (! is_array($this->raw_recips)) {
$this->raw_recips = [];
+ }
- $this->raw_recips[$f] = $x;
+ if (! is_array($y)) {
+ $y = [ $y ];
+ }
+ $this->raw_recips[$f] = $y;
+ $x = array_merge($x, $y);
}
}
// not yet ready for prime time
@@ -411,4 +416,4 @@ class ActivityStreams {
}
-} \ No newline at end of file
+}
diff --git a/Zotlabs/Lib/Apps.php b/Zotlabs/Lib/Apps.php
index 9d60e9eae..d65eed14f 100644
--- a/Zotlabs/Lib/Apps.php
+++ b/Zotlabs/Lib/Apps.php
@@ -2,6 +2,8 @@
namespace Zotlabs\Lib;
+use Zotlabs\Lib\Libsync;
+
require_once('include/plugin.php');
require_once('include/channel.php');
@@ -603,7 +605,7 @@ class Apps {
intval(TERM_OBJ_APP),
intval($r[0]['id'])
);
- build_sync_packet($uid,array('app' => $r[0]));
+ Libsync::build_sync_packet($uid,array('app' => $r[0]));
}
}
}
@@ -669,7 +671,7 @@ class Apps {
);
}
if(! intval($x[0]['app_system'])) {
- build_sync_packet($uid,array('app' => $x));
+ Libsync::build_sync_packet($uid,array('app' => $x));
}
}
else {
diff --git a/Zotlabs/Lib/Chatroom.php b/Zotlabs/Lib/Chatroom.php
index 882c846cd..34853b6ab 100644
--- a/Zotlabs/Lib/Chatroom.php
+++ b/Zotlabs/Lib/Chatroom.php
@@ -1,6 +1,8 @@
<?php
namespace Zotlabs\Lib;
+use Zotlabs\Lib\Libsync;
+
/**
* @brief A class with chatroom related static methods.
*/
@@ -91,7 +93,7 @@ class Chatroom {
return $ret;
}
- build_sync_packet($channel['channel_id'],array('chatroom' => $r));
+ Libsync::build_sync_packet($channel['channel_id'],array('chatroom' => $r));
q("delete from chatroom where cr_id = %d",
intval($r[0]['cr_id'])
diff --git a/Zotlabs/Lib/Connect.php b/Zotlabs/Lib/Connect.php
index 5fc0e3fe1..caac30f7a 100644
--- a/Zotlabs/Lib/Connect.php
+++ b/Zotlabs/Lib/Connect.php
@@ -97,7 +97,7 @@ class Connect {
$feeds = get_config('system','feed_contacts');
if (($feeds) && (in_array($protocol, [ '', 'feed', 'rss' ]))) {
- $d = discover_feed($url);
+ $d = discover_by_url($url);
}
else {
$result['message'] = t('Remote channel or protocol unavailable.');
diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php
index 85e90d67c..a4fc8aa75 100644
--- a/Zotlabs/Lib/Enotify.php
+++ b/Zotlabs/Lib/Enotify.php
@@ -818,6 +818,9 @@ class Enotify {
$itemem_text = sprintf( t('repeated %s\'s post'), '[bdi]' . $item['author']['xchan_name'] . '[/bdi]');
}
+ if(in_array($item['obj_type'], ['Document', 'Video', 'Audio', 'Image'])) {
+ $itemem_text = t('shared a file with you');
+ }
}
$edit = false;
diff --git a/Zotlabs/Lib/NativeWiki.php b/Zotlabs/Lib/NativeWiki.php
index 662fddad0..3ec032075 100644
--- a/Zotlabs/Lib/NativeWiki.php
+++ b/Zotlabs/Lib/NativeWiki.php
@@ -2,6 +2,8 @@
namespace Zotlabs\Lib;
+use Zotlabs\Lib\Libsync;
+
define ( 'NWIKI_ITEM_RESOURCE_TYPE', 'nwiki' );
class NativeWiki {
@@ -71,7 +73,7 @@ class NativeWiki {
$arr['item_thread_top'] = 1;
$arr['item_private'] = intval($acl->is_private());
$arr['verb'] = ACTIVITY_CREATE;
- $arr['obj_type'] = ACTIVITY_OBJ_WIKI;
+ $arr['obj_type'] = 'Document';
$arr['body'] = '[table][tr][td][h1]New Wiki[/h1][/td][/tr][tr][td][zrl=' . $wiki_url . ']' . $wiki['htmlName'] . '[/zrl][/td][/tr][/table]';
$arr['public_policy'] = map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_wiki'),true);
@@ -178,7 +180,7 @@ class NativeWiki {
foreach($sync_item as $w) {
$pkt[] = encode_item($w,true);
}
- build_sync_packet($uid,array('wiki' => $pkt));
+ Libsync::build_sync_packet($uid,array('wiki' => $pkt));
}
}
}
diff --git a/Zotlabs/Lib/Share.php b/Zotlabs/Lib/Share.php
index 3a2ab1783..f8b636c10 100644
--- a/Zotlabs/Lib/Share.php
+++ b/Zotlabs/Lib/Share.php
@@ -2,6 +2,7 @@
namespace Zotlabs\Lib;
+use Zotlabs\Lib\Activity;
class Share {
@@ -54,7 +55,7 @@ class Share {
if(! $this->item)
return $obj;
- $obj['asld'] = $this->item['mid'];
+ $obj['asld'] = Activity::fetch_item( [ 'id' => $this->item['mid'] ] );
$obj['type'] = $this->item['obj_type'];
$obj['id'] = $this->item['mid'];
$obj['content'] = $this->item['body'];
diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php
index dee7cda56..a5dd81d40 100644
--- a/Zotlabs/Lib/ThreadItem.php
+++ b/Zotlabs/Lib/ThreadItem.php
@@ -113,7 +113,7 @@ class ThreadItem {
if(intval($item['item_private']) && ($item['owner']['xchan_network'] === 'activitypub')) {
$recips = get_iconfig($item['parent'], 'activitypub', 'recips');
- if(! in_array($observer['xchan_url'], $recips['to']))
+ if(! is_array($recips['to']) || ! in_array($observer['xchan_url'], $recips['to']))
$privacy_warning = true;
}
diff --git a/Zotlabs/Module/Activity.php b/Zotlabs/Module/Activity.php
index 93b5a15fc..9971ee60f 100644
--- a/Zotlabs/Module/Activity.php
+++ b/Zotlabs/Module/Activity.php
@@ -170,6 +170,8 @@ class Activity extends Controller {
}
+ goaway(z_root() . '/item/' . argv(1));
+
}
}
diff --git a/Zotlabs/Module/Channel_calendar.php b/Zotlabs/Module/Channel_calendar.php
index 5d5fe300a..ae4afb2f3 100644
--- a/Zotlabs/Module/Channel_calendar.php
+++ b/Zotlabs/Module/Channel_calendar.php
@@ -1,6 +1,8 @@
<?php
namespace Zotlabs\Module;
+use Zotlabs\Lib\Libsync;
+
require_once('include/conversation.php');
require_once('include/bbcode.php');
require_once('include/datetime.php');
@@ -188,7 +190,7 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
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));
}
}
}
@@ -430,7 +432,7 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
if($r) {
$sync_event['event_deleted'] = 1;
- build_sync_packet(0,array('event' => array($sync_event)));
+ Libsync::build_sync_packet(0,array('event' => array($sync_event)));
$i = q("select * from item where resource_type = 'event' and resource_id = '%s' and uid = %d",
dbesc($event_id),
@@ -479,7 +481,7 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
if($ii) {
xchan_query($ii);
$sync_item = fetch_post_tags($ii);
- build_sync_packet($i[0]['uid'],array('item' => array(encode_item($sync_item[0],true))));
+ Libsync::build_sync_packet($i[0]['uid'],array('item' => array(encode_item($sync_item[0],true))));
}
if($complex) {
diff --git a/Zotlabs/Module/Chat.php b/Zotlabs/Module/Chat.php
index db77e2612..6a46cdace 100644
--- a/Zotlabs/Module/Chat.php
+++ b/Zotlabs/Module/Chat.php
@@ -7,9 +7,7 @@ use Zotlabs\Lib\Apps;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Chatroom;
use Zotlabs\Access\AccessList;
-
-
-
+use Zotlabs\Lib\Libsync;
require_once('include/bookmarks.php');
@@ -80,7 +78,7 @@ class Chat extends Controller {
intval(local_channel())
);
- build_sync_packet(0, array('chatroom' => $x));
+ Libsync::build_sync_packet(0, array('chatroom' => $x));
if($x)
goaway(z_root() . '/chat/' . $channel['channel_address'] . '/' . $x[0]['cr_id']);
diff --git a/Zotlabs/Module/Connedit.php b/Zotlabs/Module/Connedit.php
index acd7cb769..c0df57390 100644
--- a/Zotlabs/Module/Connedit.php
+++ b/Zotlabs/Module/Connedit.php
@@ -9,6 +9,7 @@ namespace Zotlabs\Module;
use Zotlabs\Lib\Apps;
use Zotlabs\Lib\Libzot;
+use Zotlabs\Lib\Libsync;
require_once('include/socgraph.php');
require_once('include/selectors.php');
@@ -382,7 +383,7 @@ class Connedit extends \Zotlabs\Web\Controller {
if($abconfig)
$clone['abconfig'] = $abconfig;
- build_sync_packet(0 /* use the current local_channel */, array('abook' => array($clone)));
+ Libsync::build_sync_packet(0 /* use the current local_channel */, array('abook' => array($clone)));
}
/* @brief Generate content of connection edit page
@@ -558,7 +559,7 @@ class Connedit extends \Zotlabs\Web\Controller {
// PLACEHOLDER
contact_remove(local_channel(), $orig_record[0]['abook_id']);
- build_sync_packet(0 /* use the current local_channel */,
+ Libsync::build_sync_packet(0 /* use the current local_channel */,
array('abook' => array(array(
'abook_xchan' => $orig_record[0]['abook_xchan'],
'entry_deleted' => true))
diff --git a/Zotlabs/Module/Cover_photo.php b/Zotlabs/Module/Cover_photo.php
index d97014f9c..615ca6fe0 100644
--- a/Zotlabs/Module/Cover_photo.php
+++ b/Zotlabs/Module/Cover_photo.php
@@ -1,6 +1,8 @@
<?php
namespace Zotlabs\Module;
+use Zotlabs\Lib\Libsync;
+
/*
@file cover_photo.php
@brief Module-file with functions for handling of cover-photos
@@ -66,7 +68,7 @@ class Cover_photo extends \Zotlabs\Web\Controller {
$sync = attach_export_data($channel,$r[0]['resource_id']);
if($sync)
- build_sync_packet($channel['channel_id'],array('file' => array($sync)));
+ Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
}
// Update directory in background
@@ -230,7 +232,7 @@ class Cover_photo extends \Zotlabs\Web\Controller {
$sync = attach_export_data($channel,$base_image['resource_id']);
if($sync)
- build_sync_packet($channel['channel_id'],array('file' => array($sync)));
+ Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
// Update directory in background
\Zotlabs\Daemon\Master::Summon(array('Directory',$channel['channel_id']));
diff --git a/Zotlabs/Module/Defperms.php b/Zotlabs/Module/Defperms.php
index 463ecb57a..f2f7c10e5 100644
--- a/Zotlabs/Module/Defperms.php
+++ b/Zotlabs/Module/Defperms.php
@@ -4,6 +4,7 @@ namespace Zotlabs\Module;
use App;
use Zotlabs\Lib\Apps;
use Zotlabs\Web\Controller;
+use Zotlabs\Lib\Libsync;
require_once('include/socgraph.php');
require_once('include/selectors.php');
@@ -164,7 +165,7 @@ class Defperms extends Controller {
if($abconfig)
$clone['abconfig'] = $abconfig;
- build_sync_packet(0 /* use the current local_channel */, array('abook' => array($clone)));
+ Libsync::build_sync_packet(0 /* use the current local_channel */, array('abook' => array($clone)));
}
/* @brief Generate content of connection default permissions page
diff --git a/Zotlabs/Module/Display.php b/Zotlabs/Module/Display.php
index 777d183e1..f45f37001 100644
--- a/Zotlabs/Module/Display.php
+++ b/Zotlabs/Module/Display.php
@@ -101,7 +101,7 @@ class Display extends \Zotlabs\Web\Controller {
if($decoded)
$item_hash = $decoded;
- $r = q("select id, uid, mid, parent_mid, thr_parent, verb, item_type, item_deleted, author_xchan, item_blocked from item where mid like '%s' limit 1",
+ $r = q("select id, uid, mid, parent, parent_mid, thr_parent, verb, item_type, item_deleted, author_xchan, item_blocked from item where mid like '%s' limit 1",
dbesc($item_hash . '%')
);
@@ -159,14 +159,17 @@ class Display extends \Zotlabs\Web\Controller {
}
}
if($target_item['item_type'] == ITEM_TYPE_CARD) {
+
$x = q("select * from channel where channel_id = %d limit 1",
intval($target_item['uid'])
);
+
$y = q("select * from iconfig left join item on iconfig.iid = item.id
where item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'CARD' and item.id = %d limit 1",
intval($target_item['uid']),
intval($target_item['parent'])
);
+
if($x && $y) {
goaway(z_root() . '/cards/' . $x[0]['channel_address'] . '/' . $y[0]['v']);
}
diff --git a/Zotlabs/Module/File_upload.php b/Zotlabs/Module/File_upload.php
index 4d1cc4cda..1735e9487 100644
--- a/Zotlabs/Module/File_upload.php
+++ b/Zotlabs/Module/File_upload.php
@@ -1,6 +1,8 @@
<?php
namespace Zotlabs\Module;
+use Zotlabs\Lib\Libsync;
+
require_once('include/attach.php');
require_once('include/channel.php');
require_once('include/photos.php');
@@ -41,7 +43,7 @@ class File_upload extends \Zotlabs\Web\Controller {
$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)));
}
goaway(z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['data']['display_path']);
@@ -97,7 +99,7 @@ class File_upload extends \Zotlabs\Web\Controller {
if($r['success']) {
$sync = attach_export_data($channel,$r['data']['hash']);
if($sync)
- build_sync_packet($channel['channel_id'],array('file' => array($sync)));
+ Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
}
}
diff --git a/Zotlabs/Module/Filestorage.php b/Zotlabs/Module/Filestorage.php
index 2c247cd65..0c6233493 100644
--- a/Zotlabs/Module/Filestorage.php
+++ b/Zotlabs/Module/Filestorage.php
@@ -5,7 +5,7 @@ namespace Zotlabs\Module;
*
*/
-
+use Zotlabs\Lib\Libsync;
class Filestorage extends \Zotlabs\Web\Controller {
@@ -35,12 +35,12 @@ class Filestorage extends \Zotlabs\Web\Controller {
$url = get_cloud_url($channel_id, $channel['channel_address'], $resource);
- //get the object before permissions change so we can catch eventual former allowed members
- $object = get_file_activity_object($channel_id, $resource, $url);
-
attach_change_permissions($channel_id, $resource, $x['allow_cid'], $x['allow_gid'], $x['deny_cid'], $x['deny_gid'], $recurse, true);
- file_activity($channel_id, $object, $x['allow_cid'], $x['allow_gid'], $x['deny_cid'], $x['deny_gid'], 'post', $notify);
+ if($notify) {
+ $observer = \App::get_observer();
+ attach_store_item($channel, $observer, $resource);
+ }
goaway(dirname($url));
}
@@ -131,7 +131,7 @@ class Filestorage extends \Zotlabs\Web\Controller {
if(! $admin_delete) {
$sync = attach_export_data($channel, $f['hash'], true);
if($sync) {
- build_sync_packet($channel['channel_id'], array('file' => array($sync)));
+ Libsync::build_sync_packet($channel['channel_id'], array('file' => array($sync)));
}
}
diff --git a/Zotlabs/Module/Group.php b/Zotlabs/Module/Group.php
index f836978ee..993d428f5 100644
--- a/Zotlabs/Module/Group.php
+++ b/Zotlabs/Module/Group.php
@@ -4,6 +4,7 @@ namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Apps;
+use Zotlabs\Lib\Libsync;
require_once('include/group.php');
@@ -80,7 +81,7 @@ class Group extends Controller {
info( t('Privacy group updated.') . EOL );
- build_sync_packet(local_channel(),null,true);
+ Libsync::build_sync_packet(local_channel(),null,true);
}
goaway(z_root() . '/group/' . argv(1) . '/' . argv(2));
diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php
index cdfc3c9a8..95359ccad 100644
--- a/Zotlabs/Module/Item.php
+++ b/Zotlabs/Module/Item.php
@@ -2,6 +2,7 @@
namespace Zotlabs\Module;
+use Zotlabs\Lib\Config;
use Zotlabs\Lib\IConfig;
use Zotlabs\Lib\Enotify;
use Zotlabs\Web\Controller;
@@ -43,9 +44,11 @@ class Item extends Controller {
if (Libzot::is_zot_request()) {
+ $conversation = false;
+
$item_id = argv(1);
- if (! $item_id)
+ if(! $item_id)
http_status_exit(404, 'Not found');
$portable_id = EMPTY_STR;
@@ -66,32 +69,24 @@ class Item extends Controller {
// process an authenticated fetch
- $sigdata = HTTPSig::verify(EMPTY_STR);
- if($sigdata['portable_id'] && $sigdata['header_valid']) {
+ $sigdata = HTTPSig::verify(($_SERVER['REQUEST_METHOD'] === 'POST') ? file_get_contents('php://input') : EMPTY_STR);
+ if ($sigdata['portable_id'] && $sigdata['header_valid']) {
$portable_id = $sigdata['portable_id'];
+ if (! check_channelallowed($portable_id)) {
+ http_status_exit(403, 'Permission denied');
+ }
+ if (! check_siteallowed($sigdata['signer'])) {
+ http_status_exit(403, 'Permission denied');
+ }
observer_auth($portable_id);
- // first see if we have a copy of this item's parent owned by the current signer
- // include xchans for all zot-like networks - these will have the same guid and public key
-
- $x = q("select * from xchan where xchan_hash = '%s'",
- dbesc($sigdata['portable_id'])
+ $i = q("select id as item_id from item where mid = '%s' $item_normal and owner_xchan = '%s' limit 1",
+ dbesc($r[0]['parent_mid']),
+ dbesc($portable_id)
);
-
- if ($x) {
- $xchans = q("select xchan_hash from xchan where xchan_hash = '%s' OR ( xchan_guid = '%s' AND xchan_pubkey = '%s' ) ",
- dbesc($sigdata['portable_id']),
- dbesc($x[0]['xchan_guid']),
- dbesc($x[0]['xchan_pubkey'])
- );
-
- if ($xchans) {
- $hashes = ids_to_querystr($xchans,'xchan_hash',true);
- $i = q("select id as item_id from item where mid = '%s' $item_normal and owner_xchan in ( " . protect_sprintf($hashes) . " ) limit 1",
- dbesc($r[0]['parent_mid'])
- );
- }
- }
+ }
+ elseif (Config::get('system','require_authenticated_fetch',false)) {
+ http_status_exit(403,'Permission denied');
}
// if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access
@@ -111,7 +106,7 @@ class Item extends Controller {
$parents_str = ids_to_querystr($i,'item_id');
- $items = q("SELECT item.*, item.id AS item_id FROM item WHERE item.parent IN ( %s ) $item_normal ",
+ $items = q("SELECT item.*, item.id AS item_id FROM item WHERE item.parent IN ( %s ) $item_normal order by item.id asc",
dbesc($parents_str)
);
@@ -122,43 +117,10 @@ class Item extends Controller {
xchan_query($items,true);
$items = fetch_post_tags($items,true);
- $observer = App::get_observer();
- $parent = $items[0];
- $recips = (($parent['owner']['xchan_network'] === 'activitypub') ? get_iconfig($parent['id'],'activitypub','recips', []) : []);
- $to = (($recips && array_key_exists('to',$recips) && is_array($recips['to'])) ? $recips['to'] : null);
- $nitems = [];
- foreach($items as $i) {
-
- $mids = [];
-
- if(intval($i['item_private'])) {
- if(! $observer) {
- continue;
- }
- // ignore private reshare, possibly from hubzilla
- if($i['verb'] === 'Announce') {
- if(! in_array($i['thr_parent'],$mids)) {
- $mids[] = $i['thr_parent'];
- }
- continue;
- }
- // also ignore any children of the private reshares
- if(in_array($i['thr_parent'],$mids)) {
- continue;
- }
-
- if((! $to) || (! in_array($observer['xchan_url'],$to))) {
- continue;
- }
-
- }
- $nitems[] = $i;
- }
-
- if(! $nitems)
+ if(! $items)
http_status_exit(404, 'Not found');
- $chan = channelx_by_n($nitems[0]['uid']);
+ $chan = channelx_by_n($items[0]['uid']);
if(! $chan)
http_status_exit(404, 'Not found');
@@ -166,7 +128,8 @@ class Item extends Controller {
if(! perm_is_allowed($chan['channel_id'],get_observer_hash(),'view_stream'))
http_status_exit(403, 'Forbidden');
- $i = Activity::encode_item_collection($nitems,'conversation/' . $item_id,'OrderedCollection');
+
+ $i = Activity::encode_item_collection($items, 'conversation/' . $item_id, 'OrderedCollection');
if($portable_id) {
ThreadListener::store(z_root() . '/item/' . $item_id,$portable_id);
}
@@ -194,8 +157,9 @@ class Item extends Controller {
}
if(argc() > 1 && argv(1) !== 'drop') {
- $x = q("select uid, item_wall, llink, mid from item where mid = '%s' ",
- dbesc(z_root() . '/item/' . argv(1))
+ $x = q("select uid, item_wall, llink, mid from item where mid = '%s' or mid = '%s' ",
+ dbesc(z_root() . '/item/' . argv(1)),
+ dbesc(z_root() . '/activity/' . argv(1))
);
if($x) {
foreach($x as $xv) {
@@ -712,6 +676,8 @@ class Item extends Controller {
$str_group_allow = $gacl['allow_gid'];
$str_contact_deny = $gacl['deny_cid'];
$str_group_deny = $gacl['deny_gid'];
+
+ $post_tags = [];
if($mimetype === 'text/bbcode') {
@@ -746,7 +712,6 @@ class Item extends Controller {
// Set permissions based on tag replacements
set_linkified_perms($results, $str_contact_allow, $str_group_allow, $profile_uid, $parent_item, $private);
- $post_tags = array();
foreach($results as $result) {
$success = $result['success'];
if($success['replaced']) {
@@ -759,6 +724,7 @@ class Item extends Controller {
);
}
}
+
}
if(($str_contact_allow) && (! $str_group_allow)) {
@@ -990,8 +956,9 @@ class Item extends Controller {
}
if ((! $plink) && ($item_thread_top)) {
- $plink = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . gen_link_id($mid);
- $plink = substr($plink,0,190);
+ // $plink = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . gen_link_id($mid);
+ // $plink = substr($plink,0,190);
+ $plink = $mid;
}
if ($datarray['obj']) {
@@ -1055,10 +1022,9 @@ class Item extends Controller {
$datarray['layout_mid'] = $layout_mid;
$datarray['public_policy'] = $public_policy;
$datarray['comment_policy'] = map_scope($comment_policy);
- $datarray['term'] = $post_tags;
+ $datarray['term'] = array_unique($post_tags, SORT_REGULAR);
$datarray['plink'] = $plink;
$datarray['route'] = $route;
-
// A specific ACL over-rides public_policy completely
diff --git a/Zotlabs/Module/Like.php b/Zotlabs/Module/Like.php
index e4636a4a6..61f73bfd5 100644
--- a/Zotlabs/Module/Like.php
+++ b/Zotlabs/Module/Like.php
@@ -2,6 +2,7 @@
namespace Zotlabs\Module;
use Zotlabs\Lib\Activity;
+use Zotlabs\Lib\Libsync;
require_once('include/security.php');
require_once('include/bbcode.php');
@@ -235,7 +236,7 @@ class Like extends \Zotlabs\Web\Controller {
if($z) {
$z[0]['deleted'] = 1;
- build_sync_packet($ch[0]['channel_id'],array('likes' => $z));
+ Libsync::build_sync_packet($ch[0]['channel_id'],array('likes' => $z));
q("delete from likes where id = %d",
intval($z[0]['id'])
@@ -566,7 +567,7 @@ class Like extends \Zotlabs\Web\Controller {
dbesc($obj_id)
);
if($r)
- build_sync_packet($ch[0]['channel_id'],array('likes' => $r));
+ Libsync::build_sync_packet($ch[0]['channel_id'],array('likes' => $r));
}
diff --git a/Zotlabs/Module/Moderate.php b/Zotlabs/Module/Moderate.php
index a7c98e05e..f1bff3c50 100644
--- a/Zotlabs/Module/Moderate.php
+++ b/Zotlabs/Module/Moderate.php
@@ -2,6 +2,8 @@
namespace Zotlabs\Module;
+use Zotlabs\Lib\Libsync;
+
require_once('include/conversation.php');
@@ -77,7 +79,7 @@ class Moderate extends \Zotlabs\Web\Controller {
if($r) {
xchan_query($r);
$sync_item = fetch_post_tags($r);
- build_sync_packet(local_channel(),array('item' => array(encode_item($sync_item[0],true))));
+ Libsync::build_sync_packet(local_channel(),array('item' => array(encode_item($sync_item[0],true))));
}
if($action === 'approve') {
\Zotlabs\Daemon\Master::Summon(array('Notifier', 'comment-new', $post_id));
diff --git a/Zotlabs/Module/Notes.php b/Zotlabs/Module/Notes.php
index 7572f7420..b448cff83 100644
--- a/Zotlabs/Module/Notes.php
+++ b/Zotlabs/Module/Notes.php
@@ -4,6 +4,7 @@ namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Apps;
+use Zotlabs\Lib\Libsync;
/**
* @brief Notes Module controller.
@@ -38,7 +39,7 @@ class Notes extends Controller {
if((argc() > 1) && (argv(1) === 'sync')) {
require_once('include/zot.php');
- build_sync_packet();
+ Libsync::build_sync_packet();
}
logger('notes saved.', LOGGER_DEBUG);
diff --git a/Zotlabs/Module/Pconfig.php b/Zotlabs/Module/Pconfig.php
index 06b94b34f..b2b5d4386 100644
--- a/Zotlabs/Module/Pconfig.php
+++ b/Zotlabs/Module/Pconfig.php
@@ -1,7 +1,7 @@
<?php
namespace Zotlabs\Module;
-
+use Zotlabs\Lib\Libsync;
@@ -38,7 +38,7 @@ class Pconfig extends \Zotlabs\Web\Controller {
}
set_pconfig(local_channel(),$cat,$k,$v);
- build_sync_packet();
+ Libsync::build_sync_packet();
if($aj)
killme();
diff --git a/Zotlabs/Module/Pdledit.php b/Zotlabs/Module/Pdledit.php
index 5cedb29a8..36201544f 100644
--- a/Zotlabs/Module/Pdledit.php
+++ b/Zotlabs/Module/Pdledit.php
@@ -4,6 +4,7 @@ namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Apps;
+use Zotlabs\Lib\Libsync;
class Pdledit extends Controller {
@@ -22,7 +23,7 @@ class Pdledit extends Controller {
goaway(z_root() . '/pdledit');
}
set_pconfig(local_channel(),'system','mod_' . $_REQUEST['module'] . '.pdl',escape_tags($_REQUEST['content']));
- build_sync_packet();
+ Libsync::build_sync_packet();
info( t('Layout updated.') . EOL);
goaway(z_root() . '/pdledit/' . $_REQUEST['module']);
}
diff --git a/Zotlabs/Module/Permcats.php b/Zotlabs/Module/Permcats.php
index 75ac2ac87..6a599282c 100644
--- a/Zotlabs/Module/Permcats.php
+++ b/Zotlabs/Module/Permcats.php
@@ -5,6 +5,7 @@ namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Apps;
+use Zotlabs\Lib\Libsync;
class Permcats extends Controller {
@@ -42,7 +43,7 @@ class Permcats extends Controller {
\Zotlabs\Lib\Permcat::update(local_channel(),$name,$pcarr);
- build_sync_packet();
+ Libsync::build_sync_packet();
info( t('Permission category saved.') . EOL);
@@ -71,7 +72,7 @@ class Permcats extends Controller {
if(argc() > 2 && argv(2) === 'drop') {
\Zotlabs\Lib\Permcat::delete(local_channel(),$name);
- build_sync_packet();
+ Libsync::build_sync_packet();
json_return_and_die([ 'success' => true ]);
}
diff --git a/Zotlabs/Module/Photos.php b/Zotlabs/Module/Photos.php
index 43c9f86ee..fae8c17f6 100644
--- a/Zotlabs/Module/Photos.php
+++ b/Zotlabs/Module/Photos.php
@@ -1,6 +1,8 @@
<?php
namespace Zotlabs\Module;
+use Zotlabs\Lib\Libsync;
+
require_once('include/photo/photo_driver.php');
require_once('include/photos.php');
require_once('include/items.php');
@@ -162,7 +164,7 @@ class Photos extends \Zotlabs\Web\Controller {
$sync = attach_export_data(\App::$data['channel'],$folder_hash, true);
if($sync)
- build_sync_packet($page_owner_uid,array('file' => array($sync)));
+ Libsync::build_sync_packet($page_owner_uid,array('file' => array($sync)));
}
}
@@ -189,7 +191,7 @@ class Photos extends \Zotlabs\Web\Controller {
$sync = attach_export_data(\App::$data['channel'],$r[0]['resource_id'], true);
if($sync)
- build_sync_packet($page_owner_uid,array('file' => array($sync)));
+ Libsync::build_sync_packet($page_owner_uid,array('file' => array($sync)));
}
elseif(is_site_admin()) {
// If the admin deletes a photo, don't sync
@@ -210,7 +212,7 @@ class Photos extends \Zotlabs\Web\Controller {
$sync = attach_export_data(\App::$data['channel'],argv(2),true);
if($sync)
- build_sync_packet($page_owner_uid,array('file' => array($sync)));
+ Libsync::build_sync_packet($page_owner_uid,array('file' => array($sync)));
if(! ($_POST['desc'] && $_POST['newtag']))
goaway(z_root() . '/' . $_SESSION['photo_return']);
@@ -420,7 +422,7 @@ class Photos extends \Zotlabs\Web\Controller {
$sync = attach_export_data(\App::$data['channel'],$resource_id);
if($sync)
- build_sync_packet($page_owner_uid,array('file' => array($sync)));
+ Libsync::build_sync_packet($page_owner_uid,array('file' => array($sync)));
goaway(z_root() . '/' . $_SESSION['photo_return']);
return; // NOTREACHED
diff --git a/Zotlabs/Module/Profile_photo.php b/Zotlabs/Module/Profile_photo.php
index a812ca210..d6c80b653 100644
--- a/Zotlabs/Module/Profile_photo.php
+++ b/Zotlabs/Module/Profile_photo.php
@@ -1,6 +1,8 @@
<?php
namespace Zotlabs\Module;
+use Zotlabs\Lib\Libsync;
+
/*
* @file Profile_photo.php
* @brief Module-file with functions for handling of profile-photos
@@ -73,7 +75,7 @@ class Profile_photo extends \Zotlabs\Web\Controller {
$sync = attach_export_data($channel,$r[0]['resource_id']);
if($sync)
- build_sync_packet($channel['channel_id'],array('file' => array($sync)));
+ Libsync:: build_sync_packet($channel['channel_id'],array('file' => array($sync)));
}
$_SESSION['reload_avatar'] = true;
@@ -243,7 +245,7 @@ class Profile_photo extends \Zotlabs\Web\Controller {
$sync = attach_export_data($channel,$base_image['resource_id']);
if($sync)
- build_sync_packet($channel['channel_id'],array('file' => array($sync), 'profile' => $sync_profiles));
+ Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync), 'profile' => $sync_profiles));
// Similarly, tell the nav bar to bypass the cache and update the avatar image.
@@ -411,7 +413,7 @@ class Profile_photo extends \Zotlabs\Web\Controller {
$sync = attach_export_data($channel,$resource_id);
if($sync)
- build_sync_packet($channel['channel_id'],array('file' => array($sync)));
+ Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
$_SESSION['reload_avatar'] = true;
diff --git a/Zotlabs/Module/Profiles.php b/Zotlabs/Module/Profiles.php
index 33e7d8a9d..7deceabab 100644
--- a/Zotlabs/Module/Profiles.php
+++ b/Zotlabs/Module/Profiles.php
@@ -1,6 +1,8 @@
<?php
namespace Zotlabs\Module;
+use Zotlabs\Lib\Libsync;
+
require_once('include/channel.php');
require_once('include/selectors.php');
@@ -599,7 +601,7 @@ class Profiles extends \Zotlabs\Web\Controller {
);
if($r) {
require_once('include/zot.php');
- build_sync_packet(local_channel(),array('profile' => $r));
+ Libsync::build_sync_packet(local_channel(),array('profile' => $r));
}
$channel = \App::get_channel();
diff --git a/Zotlabs/Module/Settings/Calendar.php b/Zotlabs/Module/Settings/Calendar.php
index 0298b412e..ab85eb450 100644
--- a/Zotlabs/Module/Settings/Calendar.php
+++ b/Zotlabs/Module/Settings/Calendar.php
@@ -2,6 +2,7 @@
namespace Zotlabs\Module\Settings;
+use Zotlabs\Lib\Libsync;
class Calendar {
@@ -15,7 +16,7 @@ class Calendar {
process_module_features_post(local_channel(), $features, $_POST);
- build_sync_packet();
+ Libsync::build_sync_packet();
if($_POST['rpath'])
goaway($_POST['rpath']);
diff --git a/Zotlabs/Module/Settings/Channel.php b/Zotlabs/Module/Settings/Channel.php
index b0115d352..ab9b72490 100644
--- a/Zotlabs/Module/Settings/Channel.php
+++ b/Zotlabs/Module/Settings/Channel.php
@@ -3,6 +3,7 @@
namespace Zotlabs\Module\Settings;
use Zotlabs\Lib\Apps;
+use Zotlabs\Lib\Libsync;
require_once('include/selectors.php');
@@ -286,7 +287,7 @@ class Channel {
\Zotlabs\Daemon\Master::Summon(array('Directory',local_channel()));
- build_sync_packet();
+ Libsync::build_sync_packet();
if($email_changed && \App::$config['system']['register_policy'] == REGISTER_VERIFY) {
diff --git a/Zotlabs/Module/Settings/Channel_home.php b/Zotlabs/Module/Settings/Channel_home.php
index b6ecf4ff1..e8faa7fb2 100644
--- a/Zotlabs/Module/Settings/Channel_home.php
+++ b/Zotlabs/Module/Settings/Channel_home.php
@@ -2,6 +2,8 @@
namespace Zotlabs\Module\Settings;
+use Zotlabs\Lib\Libsync;
+
require_once('include/menu.php');
class Channel_home {
@@ -24,7 +26,7 @@ class Channel_home {
$channel_menu = ((x($_POST['channel_menu'])) ? htmlspecialchars_decode(trim($_POST['channel_menu']),ENT_QUOTES) : '');
set_pconfig(local_channel(),'system','channel_menu',$channel_menu);
- build_sync_packet();
+ Libsync::build_sync_packet();
if($_POST['rpath'])
goaway($_POST['rpath']);
diff --git a/Zotlabs/Module/Settings/Connections.php b/Zotlabs/Module/Settings/Connections.php
index cac357791..4369deb27 100644
--- a/Zotlabs/Module/Settings/Connections.php
+++ b/Zotlabs/Module/Settings/Connections.php
@@ -2,6 +2,7 @@
namespace Zotlabs\Module\Settings;
+use Zotlabs\Lib\Libsync;
class Connections {
@@ -15,7 +16,7 @@ class Connections {
process_module_features_post(local_channel(), $features, $_POST);
- build_sync_packet();
+ Libsync::build_sync_packet();
if($_POST['rpath'])
goaway($_POST['rpath']);
diff --git a/Zotlabs/Module/Settings/Conversation.php b/Zotlabs/Module/Settings/Conversation.php
index 43e59a3c2..aa0ff6a7e 100644
--- a/Zotlabs/Module/Settings/Conversation.php
+++ b/Zotlabs/Module/Settings/Conversation.php
@@ -2,6 +2,7 @@
namespace Zotlabs\Module\Settings;
+use Zotlabs\Lib\Libsync;
class Conversation {
@@ -15,7 +16,7 @@ class Conversation {
process_module_features_post(local_channel(), $features, $_POST);
- build_sync_packet();
+ Libsync::build_sync_packet();
if($_POST['aj']) {
if($_POST['auto_update'] == 1)
diff --git a/Zotlabs/Module/Settings/Directory.php b/Zotlabs/Module/Settings/Directory.php
index 13fe6eb79..d1dd0677e 100644
--- a/Zotlabs/Module/Settings/Directory.php
+++ b/Zotlabs/Module/Settings/Directory.php
@@ -2,6 +2,7 @@
namespace Zotlabs\Module\Settings;
+use Zotlabs\Lib\Libsync;
class Directory {
@@ -15,7 +16,7 @@ class Directory {
process_module_features_post(local_channel(), $features, $_POST);
- build_sync_packet();
+ Libsync::build_sync_packet();
if($_POST['rpath'])
goaway($_POST['rpath']);
diff --git a/Zotlabs/Module/Settings/Display.php b/Zotlabs/Module/Settings/Display.php
index 45d80e011..f553fc057 100644
--- a/Zotlabs/Module/Settings/Display.php
+++ b/Zotlabs/Module/Settings/Display.php
@@ -2,6 +2,7 @@
namespace Zotlabs\Module\Settings;
+use Zotlabs\Lib\Libsync;
class Display {
@@ -78,7 +79,7 @@ class Display {
);
call_hooks('display_settings_post', $_POST);
- build_sync_packet();
+ Libsync::build_sync_packet();
goaway(z_root() . '/settings/display' );
return; // NOTREACHED
}
diff --git a/Zotlabs/Module/Settings/Editor.php b/Zotlabs/Module/Settings/Editor.php
index 5e7a9473a..cf6dd2807 100644
--- a/Zotlabs/Module/Settings/Editor.php
+++ b/Zotlabs/Module/Settings/Editor.php
@@ -2,6 +2,7 @@
namespace Zotlabs\Module\Settings;
+use Zotlabs\Lib\Libsync;
class Editor {
@@ -15,7 +16,7 @@ class Editor {
process_module_features_post(local_channel(), $features, $_POST);
- build_sync_packet();
+ Libsync::build_sync_packet();
if($_POST['rpath'])
goaway($_POST['rpath']);
diff --git a/Zotlabs/Module/Settings/Events.php b/Zotlabs/Module/Settings/Events.php
index eb6dda99b..ab393c932 100644
--- a/Zotlabs/Module/Settings/Events.php
+++ b/Zotlabs/Module/Settings/Events.php
@@ -2,6 +2,7 @@
namespace Zotlabs\Module\Settings;
+use Zotlabs\Lib\Libsync;
class Events {
@@ -15,7 +16,7 @@ class Events {
process_module_features_post(local_channel(), $features, $_POST);
- build_sync_packet();
+ Libsync::build_sync_packet();
if($_POST['rpath'])
goaway($_POST['rpath']);
diff --git a/Zotlabs/Module/Settings/Featured.php b/Zotlabs/Module/Settings/Featured.php
index d5d740aff..d615e176c 100644
--- a/Zotlabs/Module/Settings/Featured.php
+++ b/Zotlabs/Module/Settings/Featured.php
@@ -2,6 +2,7 @@
namespace Zotlabs\Module\Settings;
+use Zotlabs\Lib\Libsync;
class Featured {
@@ -10,7 +11,7 @@ class Featured {
call_hooks('feature_settings_post', $_POST);
- build_sync_packet();
+ Libsync::build_sync_packet();
return;
}
diff --git a/Zotlabs/Module/Settings/Features.php b/Zotlabs/Module/Settings/Features.php
index 6a3ab104b..553ff0836 100644
--- a/Zotlabs/Module/Settings/Features.php
+++ b/Zotlabs/Module/Settings/Features.php
@@ -2,6 +2,8 @@
namespace Zotlabs\Module\Settings;
+use Zotlabs\Lib\Libsync;
+
class Features {
@@ -19,7 +21,7 @@ class Features {
set_pconfig(local_channel(),'feature', $k, '');
}
}
- build_sync_packet();
+ Libsync::build_sync_packet();
return;
}
diff --git a/Zotlabs/Module/Settings/Manage.php b/Zotlabs/Module/Settings/Manage.php
index 9bae12022..cbc494cf8 100644
--- a/Zotlabs/Module/Settings/Manage.php
+++ b/Zotlabs/Module/Settings/Manage.php
@@ -2,6 +2,8 @@
namespace Zotlabs\Module\Settings;
+use Zotlabs\Lib\Libsync;
+
class Manage {
@@ -15,7 +17,7 @@ class Manage {
process_module_features_post(local_channel(), $features, $_POST);
- build_sync_packet();
+ Libsync::build_sync_packet();
if($_POST['rpath'])
goaway($_POST['rpath']);
diff --git a/Zotlabs/Module/Settings/Network.php b/Zotlabs/Module/Settings/Network.php
index ae02b06e9..9f5bdb2e5 100644
--- a/Zotlabs/Module/Settings/Network.php
+++ b/Zotlabs/Module/Settings/Network.php
@@ -2,6 +2,7 @@
namespace Zotlabs\Module\Settings;
+use Zotlabs\Lib\Libsync;
class Network {
@@ -21,7 +22,7 @@ class Network {
set_pconfig(local_channel(),'system','network_divmore_height', $network_divmore_height);
- build_sync_packet();
+ Libsync::build_sync_packet();
if($_POST['rpath'])
goaway($_POST['rpath']);
diff --git a/Zotlabs/Module/Settings/Photos.php b/Zotlabs/Module/Settings/Photos.php
index 9edbaa929..8195d660b 100644
--- a/Zotlabs/Module/Settings/Photos.php
+++ b/Zotlabs/Module/Settings/Photos.php
@@ -2,6 +2,7 @@
namespace Zotlabs\Module\Settings;
+use Zotlabs\Lib\Libsync;
class Photos {
@@ -15,7 +16,7 @@ class Photos {
process_module_features_post(local_channel(), $features, $_POST);
- build_sync_packet();
+ Libsync::build_sync_packet();
if($_POST['rpath'])
goaway($_POST['rpath']);
diff --git a/Zotlabs/Module/Settings/Profiles.php b/Zotlabs/Module/Settings/Profiles.php
index fb6abf664..67b03e04f 100644
--- a/Zotlabs/Module/Settings/Profiles.php
+++ b/Zotlabs/Module/Settings/Profiles.php
@@ -2,6 +2,8 @@
namespace Zotlabs\Module\Settings;
+use Zotlabs\Lib\Libsync;
+
require_once('include/selectors.php');
class Profiles {
@@ -19,7 +21,7 @@ class Profiles {
$profile_assign = ((x($_POST,'profile_assign')) ? notags(trim($_POST['profile_assign'])) : '');
set_pconfig(local_channel(),'system','profile_assign',$profile_assign);
- build_sync_packet();
+ Libsync::build_sync_packet();
if($_POST['rpath'])
goaway($_POST['rpath']);
diff --git a/Zotlabs/Module/Share.php b/Zotlabs/Module/Share.php
index a18a81937..c0db9978e 100644
--- a/Zotlabs/Module/Share.php
+++ b/Zotlabs/Module/Share.php
@@ -4,6 +4,7 @@ namespace Zotlabs\Module;
use App;
use Zotlabs\Daemon\Master;
use Zotlabs\Lib\Activity;
+use Zotlabs\Lib\Libsync;
require_once('include/security.php');
@@ -124,7 +125,7 @@ class Share extends \Zotlabs\Web\Controller {
if($r) {
xchan_query($r);
$sync_item = fetch_post_tags($r);
- build_sync_packet($channel['channel_id'], [ 'item' => [ encode_item($sync_item[0],true) ] ]);
+ Libsync::build_sync_packet($channel['channel_id'], [ 'item' => [ encode_item($sync_item[0],true) ] ]);
}
Master::Summon([ 'Notifier','like',$post_id ]);
diff --git a/Zotlabs/Module/Sharedwithme.php b/Zotlabs/Module/Sharedwithme.php
index c986f6695..4211a3af8 100644
--- a/Zotlabs/Module/Sharedwithme.php
+++ b/Zotlabs/Module/Sharedwithme.php
@@ -1,5 +1,8 @@
<?php
namespace Zotlabs\Module;
+
+use Zotlabs\Web\Controller;
+
require_once('include/conversation.php');
require_once('include/text.php');
@@ -9,7 +12,7 @@ require_once('include/text.php');
*
*/
-class Sharedwithme extends \Zotlabs\Web\Controller {
+class Sharedwithme extends Controller {
function get() {
if(! local_channel()) {
@@ -20,81 +23,80 @@ class Sharedwithme extends \Zotlabs\Web\Controller {
$channel = \App::get_channel();
$is_owner = (local_channel() && (local_channel() == $channel['channel_id']));
-
- //check for updated items and remove them
- require_once('include/sharedwithme.php');
- apply_updates();
+
+ $item_normal = item_normal();
//drop single file - localuser
if((argc() > 2) && (argv(2) === 'drop')) {
-
+
$id = intval(argv(1));
-
- q("DELETE FROM item WHERE id = %d AND uid = %d",
- intval($id),
- intval(local_channel())
- );
-
+
+ drop_item($id);
+
goaway(z_root() . '/sharedwithme');
+
}
//drop all files - localuser
if((argc() > 1) && (argv(1) === 'dropall')) {
-
- q("DELETE FROM item WHERE verb = '%s' AND obj_type = '%s' AND uid = %d",
+
+ $r = q("SELECT id FROM item WHERE verb = '%s' AND obj_type IN ('Document', 'Video', 'Audio', 'Image') AND uid = %d AND owner_xchan != '%s' $item_normal",
dbesc(ACTIVITY_POST),
- dbesc(ACTIVITY_OBJ_FILE),
- intval(local_channel())
+ intval(local_channel()),
+ dbesc($channel['channel_hash'])
);
-
+
+ $ids = ids_to_array($r);
+
+ if($ids)
+ drop_items($ids);
+
goaway(z_root() . '/sharedwithme');
+
}
-
+
//list files
- $r = q("SELECT id, uid, obj, item_unseen FROM item WHERE verb = '%s' AND obj_type = '%s' AND uid = %d AND owner_xchan != '%s'",
+ $r = q("SELECT id, uid, obj, item_unseen FROM item WHERE verb = '%s' AND obj_type IN ('Document', 'Video', 'Audio', 'Image') AND uid = %d AND owner_xchan != '%s' $item_normal",
dbesc(ACTIVITY_POST),
- dbesc(ACTIVITY_OBJ_FILE),
intval(local_channel()),
dbesc($channel['channel_hash'])
);
-
- $items =array();
- $ids = '';
-
+
+ $items = [];
+ $ids = [];
+
if($r) {
foreach($r as $rr) {
$object = json_decode($rr['obj'],true);
-
- $item = array();
+ $meta = self::get_meta($object);
+
+ $item = [];
$item['id'] = $rr['id'];
- $item['objfiletype'] = $object['filetype'];
- $item['objfiletypeclass'] = getIconFromType($object['filetype']);
- $item['objurl'] = rawurldecode(get_rel_link($object['link'],'alternate')) . '?f=&zid=' . $channel['xchan_addr'];
- $item['objfilename'] = $object['filename'];
- $item['objfilesize'] = userReadableSize($object['filesize']);
- $item['objedited'] = $object['edited'];
+ $item['objfiletype'] = $meta['type'];
+ $item['objfiletypeclass'] = getIconFromType($meta['type']);
+ $item['objurl'] = $meta['path'] . '?f=&zid=' . $channel['xchan_addr'];
+ $item['objfilename'] = $object['name'];
+ $item['objfilesize'] = userReadableSize($meta['size']);
+ $item['objedited'] = $meta['edited'];
$item['unseen'] = $rr['item_unseen'];
$items[] = $item;
- if($item['unseen'] > 0) {
- $ids .= " '" . $rr['id'] . "',";
+ if($item['unseen']) {
+ $ids[] = $rr['id'];
}
}
}
-
+
+ $ids = implode(',', $ids);
+
if($ids) {
-
- //remove trailing ,
- $ids = rtrim($ids, ",");
-
q("UPDATE item SET item_unseen = 0 WHERE id IN ( $ids ) AND uid = %d",
intval(local_channel())
);
-
}
$o = '';
@@ -114,5 +116,22 @@ class Sharedwithme extends \Zotlabs\Web\Controller {
}
+ function get_meta($object) {
+
+ $ret = [];
+
+ if(! is_array($object['attachment']))
+ return;
+
+ foreach($object['attachment'] as $a) {
+ if($a['name'] === 'zot.attach.meta') {
+ $ret = $a['value'];
+ break;
+ }
+ }
+
+ return $ret;
+
+ }
}
diff --git a/Zotlabs/Module/Sse_bs.php b/Zotlabs/Module/Sse_bs.php
index 89e852120..cb4c54961 100644
--- a/Zotlabs/Module/Sse_bs.php
+++ b/Zotlabs/Module/Sse_bs.php
@@ -119,7 +119,7 @@ class Sse_bs extends Controller {
$sql_extra2 = '';
if(self::$xchans)
- $sql_extra2 = " AND (author_xchan IN (" . self::$xchans . ") OR owner_xchan IN (" . self::$xchans . ")) ";
+ $sql_extra2 = " AND author_xchan IN (" . self::$xchans . ") ";
$item_normal = item_normal();
@@ -128,6 +128,7 @@ class Sse_bs extends Controller {
WHERE uid = %d
AND created <= '%s'
AND item_unseen = 1 AND item_wall = 0
+ AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
AND author_xchan != '%s'
$item_normal
$sql_extra
@@ -183,7 +184,7 @@ class Sse_bs extends Controller {
$sql_extra2 = '';
if(self::$xchans)
- $sql_extra2 = " AND (author_xchan IN (" . self::$xchans . ") OR owner_xchan IN (" . self::$xchans . ")) ";
+ $sql_extra2 = " AND author_xchan IN (" . self::$xchans . ") ";
$item_normal = item_normal();
@@ -193,6 +194,7 @@ class Sse_bs extends Controller {
WHERE uid = %d
AND created <= '%s'
AND item_unseen = 1 AND item_wall = 1
+ AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
AND author_xchan != '%s'
$item_normal
$sql_extra
@@ -259,7 +261,7 @@ class Sse_bs extends Controller {
$sql_extra2 = '';
if(self::$xchans)
- $sql_extra2 = " AND (author_xchan IN (" . self::$xchans . ") OR owner_xchan IN (" . self::$xchans . ")) ";
+ $sql_extra2 = " AND author_xchan IN (" . self::$xchans . ") ";
$item_normal = item_normal();
@@ -268,6 +270,7 @@ class Sse_bs extends Controller {
WHERE uid = %d
AND created <= '%s'
AND item_unseen = 1
+ AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
AND author_xchan != '%s'
AND created > '%s'
$item_normal
@@ -446,21 +449,24 @@ class Sse_bs extends Controller {
if(! self::$uid)
return $result;
+ $item_normal = item_normal();
+
$r = q("SELECT * FROM item
WHERE verb = '%s'
- AND obj_type = '%s'
+ AND obj_type IN ('Document', 'Video', 'Audio', 'Image')
AND uid = %d
- AND owner_xchan != '%s'
- AND item_unseen = 1",
+ AND author_xchan != '%s'
+ AND item_unseen = 1
+ $item_normal
+ ORDER BY created DESC",
dbesc(ACTIVITY_POST),
- dbesc(ACTIVITY_OBJ_FILE),
intval(self::$uid),
dbesc(self::$ob_hash)
);
if($r) {
xchan_query($r);
foreach($r as $rr) {
- $result['files']['notifications'][] = Enotify::format_files($rr);
+ $result['files']['notifications'][] = Enotify::format($rr);
}
$result['files']['count'] = count($r);
}
diff --git a/Zotlabs/Module/Starred.php b/Zotlabs/Module/Starred.php
index 8349ae25c..2d7063669 100644
--- a/Zotlabs/Module/Starred.php
+++ b/Zotlabs/Module/Starred.php
@@ -1,6 +1,7 @@
<?php
namespace Zotlabs\Module;
+use Zotlabs\Lib\Libsync;
class Starred extends \Zotlabs\Web\Controller {
@@ -37,7 +38,7 @@ class Starred extends \Zotlabs\Web\Controller {
if($r) {
xchan_query($r);
$sync_item = fetch_post_tags($r);
- build_sync_packet(local_channel(),[
+ Libsync::build_sync_packet(local_channel(),[
'item' => [
encode_item($sync_item[0],true)
]
diff --git a/Zotlabs/Module/Tagger.php b/Zotlabs/Module/Tagger.php
index e6e80dce3..4fbfb7070 100644
--- a/Zotlabs/Module/Tagger.php
+++ b/Zotlabs/Module/Tagger.php
@@ -1,6 +1,8 @@
<?php
namespace Zotlabs\Module;
+use Zotlabs\Lib\Libsync;
+
require_once('include/security.php');
require_once('include/bbcode.php');
require_once('include/items.php');
@@ -149,7 +151,7 @@ class Tagger extends \Zotlabs\Web\Controller {
$ret = post_activity_item($arr);
if($ret['success']) {
- build_sync_packet(local_channel(),
+ Libsync::build_sync_packet(local_channel(),
[
'item' => [ encode_item($ret['activity'],true) ]
]
diff --git a/Zotlabs/Module/Thing.php b/Zotlabs/Module/Thing.php
index c3d8ff802..b065b0022 100644
--- a/Zotlabs/Module/Thing.php
+++ b/Zotlabs/Module/Thing.php
@@ -5,6 +5,8 @@
namespace Zotlabs\Module;
+use Zotlabs\Lib\Libsync;
+
require_once('include/items.php');
require_once('include/security.php');
require_once('include/selectors.php');
@@ -124,7 +126,7 @@ class Thing extends \Zotlabs\Web\Controller {
dbesc($term_hash)
);
if($r) {
- build_sync_packet(0, array('obj' => $r));
+ Libsync::build_sync_packet(0, array('obj' => $r));
}
return;
@@ -180,7 +182,7 @@ class Thing extends \Zotlabs\Web\Controller {
dbesc($hash)
);
if($r) {
- build_sync_packet(0, array('obj' => $r));
+ Libsync::build_sync_packet(0, array('obj' => $r));
}
if($activity) {
@@ -353,7 +355,7 @@ class Thing extends \Zotlabs\Web\Controller {
$r[0]['obj_deleted'] = 1;
- build_sync_packet(0,array('obj' => $r));
+ Libsync::build_sync_packet(0,array('obj' => $r));
return $o;
}
diff --git a/Zotlabs/Module/Wall_attach.php b/Zotlabs/Module/Wall_attach.php
index e1088d18f..2c0eeec77 100644
--- a/Zotlabs/Module/Wall_attach.php
+++ b/Zotlabs/Module/Wall_attach.php
@@ -1,6 +1,8 @@
<?php
namespace Zotlabs\Module;
+use Zotlabs\Lib\Libsync;
+
require_once('include/attach.php');
require_once('include/photos.php');
@@ -134,7 +136,7 @@ class Wall_attach extends \Zotlabs\Web\Controller {
$sync = attach_export_data($channel,$r['data']['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($using_api)
diff --git a/Zotlabs/Storage/Directory.php b/Zotlabs/Storage/Directory.php
index ae36fc1c0..8cda75fd1 100644
--- a/Zotlabs/Storage/Directory.php
+++ b/Zotlabs/Storage/Directory.php
@@ -3,6 +3,7 @@
namespace Zotlabs\Storage;
use Sabre\DAV;
+use Zotlabs\Lib\Libsync;
/**
* @brief RedDirectory class.
@@ -179,7 +180,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
if ($ch) {
$sync = attach_export_data($ch, $this->folder_hash);
if ($sync)
- build_sync_packet($ch['channel_id'], array('file' => array($sync)));
+ Libsync::build_sync_packet($ch['channel_id'], array('file' => array($sync)));
}
$this->red_path = $new_path;
@@ -368,7 +369,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
$sync = attach_export_data($c[0], $hash);
if ($sync)
- build_sync_packet($c[0]['channel_id'], array('file' => array($sync)));
+ Libsync::build_sync_packet($c[0]['channel_id'], array('file' => array($sync)));
}
/**
@@ -401,7 +402,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
logger('createDirectory: attach_export_data returns $sync:' . print_r($sync, true), LOGGER_DEBUG);
if($sync) {
- build_sync_packet($r[0]['channel_id'], array('file' => array($sync)));
+ Libsync::build_sync_packet($r[0]['channel_id'], array('file' => array($sync)));
}
}
else {
@@ -432,7 +433,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
if ($ch) {
$sync = attach_export_data($ch, $this->folder_hash, true);
if ($sync)
- build_sync_packet($ch['channel_id'], array('file' => array($sync)));
+ Libsync::build_sync_packet($ch['channel_id'], array('file' => array($sync)));
}
}
diff --git a/Zotlabs/Storage/File.php b/Zotlabs/Storage/File.php
index 36aff1e05..68edde166 100644
--- a/Zotlabs/Storage/File.php
+++ b/Zotlabs/Storage/File.php
@@ -3,6 +3,7 @@
namespace Zotlabs\Storage;
use Sabre\DAV;
+use Zotlabs\Lib\Libsync;
/**
* @brief This class represents a file in DAV.
@@ -106,7 +107,7 @@ class File extends DAV\Node implements DAV\IFile {
if($ch) {
$sync = attach_export_data($ch,$this->data['hash']);
if($sync)
- build_sync_packet($ch['channel_id'],array('file' => array($sync)));
+ Libsync::build_sync_packet($ch['channel_id'],array('file' => array($sync)));
}
}
@@ -254,7 +255,7 @@ class File extends DAV\Node implements DAV\IFile {
$sync = attach_export_data($c[0],$this->data['hash']);
if($sync)
- build_sync_packet($c[0]['channel_id'],array('file' => array($sync)));
+ Libsync::build_sync_packet($c[0]['channel_id'],array('file' => array($sync)));
}
@@ -378,7 +379,7 @@ class File extends DAV\Node implements DAV\IFile {
if($ch) {
$sync = attach_export_data($ch, $this->data['hash'], true);
if($sync)
- build_sync_packet($ch['channel_id'], array('file' => array($sync)));
+ Libsync::build_sync_packet($ch['channel_id'], array('file' => array($sync)));
}
}
}
diff --git a/Zotlabs/Update/_1236.php b/Zotlabs/Update/_1236.php
index 6b4e7b299..e57338e16 100644
--- a/Zotlabs/Update/_1236.php
+++ b/Zotlabs/Update/_1236.php
@@ -61,6 +61,34 @@ class _1236 {
xchan_store_lowlevel($rec);
}
+ // Now try again
+ $xchan = q("SELECT xchan_hash, xchan_guid_sig FROM xchan WHERE xchan_guid = '%s' AND xchan_network = 'zot6'",
+ dbesc($guid)
+ );
+
+ if(! $xchan) {
+ logger('Could not create zot6 xchan record for: ' . $zot_xchan);
+ continue;
+ }
+
+ }
+
+ $zot6_xchan = $xchan[0]['xchan_hash'];
+ $zot6_xchan_guid_sig = $xchan[0]['xchan_guid_sig'];
+
+ $hubloc = q("SELECT hubloc_hash FROM hubloc WHERE hubloc_guid = '%s' AND hubloc_url = '%s' AND hubloc_network = 'zot6'",
+ dbesc($guid),
+ dbesc(z_root())
+ );
+
+ if(! $hubloc) {
+ // This should not actually happen.
+ // A local zot6 hubloc for every channel should have been
+ // created in update _1226.
+
+ // In case this failed, we will try to fix it here.
+ logger('No local zot6 hubloc found for: ' . $rr['channel_hash']);
+
$h = q("SELECT * FROM hubloc WHERE hubloc_hash = '%s' AND hubloc_url = '%s' LIMIT 1",
dbesc($zot_xchan),
dbesc(z_root())
@@ -68,31 +96,23 @@ class _1236 {
if($h) {
$rec = $h[0];
- $rec['hubloc_hash'] = $zhash;
+ $rec['hubloc_hash'] = $zot6_xchan;
$rec['hubloc_guid_sig'] = 'sha256.' . $rec['hubloc_guid_sig'];
$rec['hubloc_network'] = 'zot6';
$rec['hubloc_url_sig'] = 'sha256.' . $rec['hubloc_url_sig'];
$rec['hubloc_callback'] = z_root() . '/zot';
$rec['hubloc_id_url'] = channel_url($rr);
$rec['hubloc_site_id'] = Libzot::make_xchan_hash(z_root(),get_config('system','pubkey'));
- hubloc_store_lowlevel($rec);
- }
- // Now try again
- $xchan = q("SELECT xchan_hash, xchan_guid_sig FROM xchan WHERE xchan_guid = '%s' AND xchan_network = 'zot6'",
- dbesc($guid)
- );
+ $hubloc = hubloc_store_lowlevel($rec);
+ }
- if(!$xchan) {
- logger('Could not create zot6 xchan record for: ' . $zot_xchan);
+ if(! $hubloc) {
+ logger('Could not create local zot6 hubloc record for: ' . $zot_xchan);
continue;
}
-
}
- $zot6_xchan = $xchan[0]['xchan_hash'];
- $zot6_xchan_guid_sig = $xchan[0]['xchan_guid_sig'];
-
logger('Transforming channel: ' . $zot_xchan);
q("UPDATE channel SET channel_hash = '%s', channel_portable_id = '%s', channel_guid_sig = '%s' WHERE channel_hash = '%s'",
dbesc($zot6_xchan),
diff --git a/include/attach.php b/include/attach.php
index 952270949..80f71b9ea 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');
@@ -1018,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;
@@ -1403,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)));
}
}
@@ -1450,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",
@@ -1496,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
@@ -1515,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;
}
@@ -1551,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/.
@@ -1752,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');
@@ -1800,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();
@@ -1899,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.
@@ -1915,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,
diff --git a/include/bbcode.php b/include/bbcode.php
index b2e3f1d3b..e846e38db 100644
--- a/include/bbcode.php
+++ b/include/bbcode.php
@@ -319,6 +319,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) {
@@ -935,6 +1068,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.
diff --git a/include/channel.php b/include/channel.php
index 25eb93cac..742d9e3a7 100644
--- a/include/channel.php
+++ b/include/channel.php
@@ -673,7 +673,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'])
@@ -1930,7 +1930,7 @@ function zid_init() {
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;
@@ -2241,7 +2241,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;
diff --git a/include/conversation.php b/include/conversation.php
index 62d4b405f..b0e81b7e2 100644
--- a/include/conversation.php
+++ b/include/conversation.php
@@ -423,10 +423,18 @@ function visible_activity($item) {
}
}
+ // 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;
+ // if(is_edit_activity($item))
+ // return false;
return true;
}
@@ -1287,13 +1295,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;
@@ -1446,7 +1447,6 @@ function hz_status_editor($a, $x, $popup = false) {
'$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')]],
- '$feature_voting' => $feature_voting,
'$consensus' => ((array_key_exists('item',$x)) ? $x['item']['item_consensus'] : 0),
'$nocommenttitle' => t('Disable comments'),
'$nocommenttitlesub' => t('Toggle comments'),
diff --git a/include/event.php b/include/event.php
index 69ca64e0f..82f6ca81e 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;
@@ -421,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']);
@@ -506,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']),
@@ -516,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']),
@@ -552,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']),
@@ -563,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']),
@@ -663,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;
}
@@ -1270,7 +1275,7 @@ function event_store_item($arr, $event) {
// otherwise we'll fallback to /display/$message_id
if($wall)
- $item_arr['plink'] = z_root() . '/channel/' . $z[0]['channel_address'] . '/?f=&mid=' . 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']);
diff --git a/include/features.php b/include/features.php
index c6cfcf822..0dd245e7f 100644
--- a/include/features.php
+++ b/include/features.php
@@ -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',
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/items.php b/include/items.php
index 9768fdf23..87ae5c6a5 100755
--- a/include/items.php
+++ b/include/items.php
@@ -10,6 +10,7 @@ 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\AccessList;
use Zotlabs\Daemon\Master;
@@ -238,19 +239,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 ";
}
@@ -266,7 +267,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;
@@ -422,7 +423,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;
@@ -3873,7 +3874,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]]);
}
}
@@ -3882,7 +3883,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.
@@ -4726,7 +4727,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))));
}
}
@@ -4928,7 +4929,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/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/photos.php b/include/photos.php
index 631660d7a..11dd07586 100644
--- a/include/photos.php
+++ b/include/photos.php
@@ -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/text.php b/include/text.php
index 5d1cf6eff..6f56a0754 100644
--- a/include/text.php
+++ b/include/text.php
@@ -3732,7 +3732,7 @@ function array_path_exists($str,$arr) {
if($search) {
foreach($search as $s) {
- if($ptr && array_key_exists($s,$ptr)) {
+ if(is_array($ptr) && array_key_exists($s,$ptr)) {
$ptr = $ptr[$s];
}
else {
diff --git a/include/zid.php b/include/zid.php
index 325af5580..10e09e212 100644
--- a/include/zid.php
+++ b/include/zid.php
@@ -1,5 +1,6 @@
<?php
+use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\Verify;
use Zotlabs\Zot\Finger;
@@ -402,9 +403,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 8b9cb0767..fb0804aa7 100644
--- a/include/zot.php
+++ b/include/zot.php
@@ -408,7 +408,7 @@ function zot_refresh($them, $channel = null, $force = false) {
if($channel) {
$postvars['target'] = $channel['xchan_guid'];
- $postvars['target_sig'] = $channel['xchan_guid_sig'];
+ $postvars['target_sig'] = str_replace('sha256.', '', $channel['xchan_guid_sig']);
$postvars['key'] = $channel['channel_pubkey'];
}
diff --git a/spec/HTTPSignatures/Home.md b/spec/HTTPSignatures/Home.md
new file mode 100644
index 000000000..3c1874f67
--- /dev/null
+++ b/spec/HTTPSignatures/Home.md
@@ -0,0 +1,34 @@
+### Encrypted HTTP Signatures
+
+draft-cavage-http-signatures-09 describes a method for providing public key signatures and authentication for HTTP requests.
+
+A fundamental limitation (flaw) of HTTP signatures is the fact that they often leak metadata of the originator of a communication via the 'keyId'.
+
+Encrypted HTTP signatures corrects this by encrypting the signature header.
+
+Encryption uses the public key of the receiving site. The content of the Signature or Authorization header after creating an HTTP signature is passed through an encryption function f(header,key,algorithm) with the public key of the remote site and a mutually agreed encryption algorithm which returns an encrypted structure containing
+
+key: a "random" string encrypted with the RSA public key of the remote site and base64_url encoded
+iv: a "random" string encrypted with the RSA public key of the remote site and base64_url encoded (optional)
+alg: the encryption algorithm used
+data: the encrypted data, base64_url encoded
+hmac: base64_url encoded hmac (optional)
+
+The header is generated by applying each field name followed by '=' followed by the double-quoted field value and fields separated by commas (the same as draft-cavage-http-signatures)
+
+The encryption is performed by encrypting the header string with the chosen algorithm using key and iv. Key and iv **may** be of a greater length than the specified algorithm permits. These strings are truncated to the desired key length and initialisation vector length prior to encryption, but transmitted in their entirety. Typically the random string is of length 256 octets and the key and iv are generally restricted to 16 or 32 octets (depending on the encryption algorithm used). There are no restrictions on the characters of the "random" octet string.
+
+Resulting header:
+
+````
+Signature: iv="d-uqkRoeXCoL1T5DU74ywizSM2RgsI9ZXWREKVg3_Qjd-mUWTJVGLq2hOQi3XKaa9Q7R6uB6UzlRmLfxBMZhVIxHjdNgfSRQ_oXafiSv8bZzMVKLZCjw6PfxBcljFs5gaQ7vEGuOVZ5nUaNEU7QX7WFr7BQKlev_6GFruv7HOsehGCokpyHHkKwrQ_4WJxUZp7o1ZhS1masPqMrEtUxDGfKwHfiHILuMdWDBvv2Xk4iHzlCi9fRVUEvzzFvv1rXsanjbaypZMIfSNj31kvsGfs6IyHpIaKbFqRs_iCxfujKDYh-2Dsg02bJTF1qx9BHJqLKNpfc0iReVe_xV2Qom3-SrJe1K8mRzYQJuOyyDuQk04GBlw7ken698JcwuS0G0OMfvGh5okq_0wM_O09iYumnJlEZT2a5nJ8ifc-kZfu8zdIPyAjJvS3a3KGEsytLxuUekFPVIpEoV2rmgOWz0TzDg-mIgwFffcx3kDa_WWhPGCFwVOzGU9um0KKStThKNXrbjYEAHVxD0gYXPgwmL8KayCo2A2s4bE2W8FfSURGu4Noqr9VsZ69Bcygzitv3aWCeIAk0y7kjJ0yQDfuIOjK1GP4HECq5NJIf8L3LJKw8QIBKm_0nx4gV9rLSAKCe3S63-D1tp9hafeiKQvGSwR0ybhxTJrhkcxd2nieVAyoA",key="Ca14lvjZua-ED8kXbedNLmrk6mRMHZm9NugcphyBMKEBo8MXLLnTsZchkAP-auWa0iJFKRwtdYUW_IGO-WX_qKZ8VNOslViveTYY-ybLTjQUj--YCFuURLYUWYTEmDcOImPWc8cQYGjTL_PN5X7vo7t3cm6rdV2W4tio2Rrmg3-cjhXBBRElr3GQKQ7i9ljBPs2YffoRsJ7f8DycKeyTv1T9xwr5lDklWOcOMTD4_39cZN2BI-b3AcGhBG4oYabUavW3BLGX7-SnezUcbTP3RyCVGI0ylVS8FmHSBZmW0oWfrVmz0oc0UcZYQMk8rb2WL_2ZdnzV_yZsjbBTFHG1ytIYyMeJsUU-pv4b4TodZmuDKT5UGtXPhm8Lsh-JpFo8xj5Yl15T9H6yLVHMR7Wzx_r2SvlJUsyqzBpaZE8DMd0zzrNZwgHQZ08wVHieKKO-TIqdypZHkxGGM68u2NPPW8-mXHgd_w9fUNM5fZRKPL9GxoVqoe9hx2f6CXPD95GAwjer9hbJcOmvxA1veXpIQzlkd-kEc8EuECaC50aUZJZbUIghYFo9NAA-UgNb26TyuY1OwE55MstPA6OO1sFki2u1G1T5JGWWgIOAziCcZbDYl1NPFWD2I1sV__rYeZ6XaaW4GXIVqD3wyBpmBRIoFx43gVDTISyUjhjUjjVHbZE",alg="aes256ctr",data="CLBNNE-tR1lRm0QL5gS86HyfwMs_16xKSSHTBP7MUEmRhGR00s0cdOfLC-PCZKlpG3ZRvc_lxnd53GGycNiTskisAb1mTbTrUBvk7hpDGNciUEB_7-hehjRiztmfi_oR-H0sCsVK9qDJdYepr4BYIgznVcB0uEN-POm97H4cTTVD8xCxLeEX0ArgDzgv_-Bq-nMcyht2LdGFl4Ej3bhEOhzvd-Xs1m6Z3E55dw0Bx7QDtkorvoetgMJrhgPKjYkIUWGoyVqa8MssvYIT8w9mpPDm4_QuVSNiPLIrKwQ3vob_hxcvENY-l0vXihdnpMzg81Sdk0E4FS4uQ9HtYSWsjOaFDSWRlxc-C5RhIvnHST4uEy3tjI--OHYQo2mFG2fWM3h8bYPq6r41W79qxsfmdSydmV1G5rFIqaz7gOa2JGOtW19WPJ8FTNFLVDehrFD6FJUy185gYyXosonp2EF3qlC8k_fzmazrzUrx0YmQ941870LJAwtEC7P-XiHV3dj-tZRYPgiSp7m8cMm7Z8WGgN8lLb61t5di5XS8zAv3FU1EAvvyL7PQhDi1U-s2cQXk3hXTNhOIymUYRhSV8NZrk80EsOrbPevSNQyYKXWCeUbnyhUznZQ3Lwq-UWAufcwrVY5uIJKeNu2lZ42xzSHWW3hn0ymcXzBOz7_wip9pSPY1nsTwApqTaIjURMEHhPvgaKRzNmuKbWP-d5Ihjeqw6JGXoAw0beWPJ4rqOlpQtn63deyBR5ylcRe4Ok2n03fZBnzJAobfZuHkiW93Yvc_byF-rpMJ3C8BSFYhGNDzYeRea3d9BEsqz_sr2HNpJyLhPssiZlZdjGRfqQ5UvCIJgT_NY57FoRCx4RHRpSxkjyF5XaKXW0_uNK7Oxk30qOCbIsLkQJqB2JIVrFFDBPITZIQVq2OamcBVk09OPuIMvsNBUTt2sxcZ7LVAA61ubv0jU39TcYO_OCs2eL7WaH7zDs9wHmxlwvzrPclduY5Gx2pwkrI_nb42j4Nc5imUkvzkIAhbYOB-XBClNVjFdEqYH35lziqEl9I6_w"
+````
+
+Decrypting the header reverses this process.
+
+- base64url_decode the key and iv and data fields and if used, the hmac field.
+- use the site private key to decrypt key and iv
+- apply decryption algorithm 'alg' to 'data' using 'key' and 'iv', truncating 'key' and 'iv' if necessary for the chosen algorithm.
+- The end result is an HTTP Signature as sepcified in draft-cavage-http-signatures, process according to that document.
+
+Discovery of site public keys and algorithm negotiation is outside the scope of this document. \ No newline at end of file
diff --git a/spec/OpenWebAuth/Home.md b/spec/OpenWebAuth/Home.md
new file mode 100644
index 000000000..7d5adf449
--- /dev/null
+++ b/spec/OpenWebAuth/Home.md
@@ -0,0 +1,57 @@
+### OpenWebAuth
+
+OpenWebAuth provides a light-weight form of cross-domain authentication between websites on the open web. The principals involved in the authentication may or may not have any pre-existing relationship.
+
+OpenWebAuth utilises webfinger (RFC7033) and HTTP Signatures (draft-cavage-http-signatures-09) with a simple token generation service to provide seamless and interaction free authentication between diverse websites.
+
+For example, on website podunk.edu a member has made a video available privately to bob@example.com. In order for bob@example.com to verify his identity and view the protected video, he must establish proof of his identity to podunk.edu.
+
+At a high level, for an actor to visit another site as an authenticated viewer, he/she first redirects to a service which can create digital signatures on their behalf and which is provided a destination URL. This service must have access to their private signing key.
+
+The public key is stored on a webfinger compatible service or provided directly as a webfinger property. The webfinger resource is provided as the keyID of an HTTP Signature 'Authorization' header.
+
+There is very little concensus on providing public keys in webfinger except for the salmon magic-public-key. For those that prefer a higher level key format a property name of 'https://w3id.org/security/v1#publicKeyPem' MAY be used and although unofficial, aligns with JSON-LD and ActivityPub. Servers MAY look at other webfinger resources if there is no usable public key found in the webfinger JRD document. These discovery mechanisms are outside the scope of this document.
+
+A webfinger request to the baseurl of the destination URL returns an entry for an OpenWebAuth service endpoint. For example:
+
+````
+rel: https://purl.org/openwebauth/v1
+type: application/json
+href: https://example.com/openwebauth
+````
+
+The redirector signs an HTTPS GET request to the OpenWebAuth endpoint using HTTP Signatures, which returns a json document:
+
+````
+{
+ 'success': true,
+ 'encrypted_token': 'bgU50kUhtlMV5gKo1ce'
+}
+````
+
+The 'token' is a single use access token; generally a unique hash value of 16 to 56 chars in length (this is consistent with RSA OAEP encryption using a 1024-bit RSA key). The resulting token will very likely be used in a URL, so the characters MUST be in the range of [a-zA-Z0-9]. To generate the 'encrypted\_token' this token is first encrypted with the actor's public key using RSA encryption, and the result base64\_url encoded.
+
+If the Signature cannot be validated, the OpenWebAuth service returns
+
+````
+{
+ 'success': false,
+ 'message': 'Reason'
+}
+````
+
+'message' is not required.
+
+If an encrypted_token is returned, this token is decrypted:
+
+base64\_url decode the 'encrypted_token'
+decrypt this result with the RSA private key belonging to the original actor, which results in a plaintext 'token'.
+
+added to the destination URL as a query parameter 'owt' (OpenWebToken).
+
+303 https://example.com/some/url?owt=abc123
+
+
+The user's browser session is now redirected to the destination URL (with the token provided) and is authenticated and allowed access to various web resources depending on the permissions granted to their webfinger identity.
+
+Notes: All interactions MUST take place over https: transport with valid certificates. HTTP Signatures offer no protection against replay attacks. The OpenWebAuth token service MUST discard tokens after first use and SHOULD discard unused tokens within a few minutes of generation. \ No newline at end of file
diff --git a/spec/Zot6/Changelog.md b/spec/Zot6/Changelog.md
new file mode 100644
index 000000000..301ad48fa
--- /dev/null
+++ b/spec/Zot6/Changelog.md
@@ -0,0 +1,16 @@
+### Changes
+
+2018-09-14
+Remove 'request' message type. To request missing conversation contents fetch the message 'id' attribute with an Accept header of 'application/x-zot+json'. An OrderedCollection of the containing conversation will be returned. The fetch should be signed by the requestor and permissions checked by the target server.
+
+2018-08-28
+Moved linked identity paragraph which was incorrectly placed in the 'nomadic considerations' text block.
+
+2018-08-17
+Clarify that ActivityStreams objects are assumed to have a default @context of "https://www.w3.org/ns/activitystreams" in the absence of a specific @context declaration.
+
+2018-08-16
+Added reference to encrypted HTTP Signatures, added pointer to reference implementation.
+
+2018-08-01
+Removed the "mail" message type and documented the "sync" message. \ No newline at end of file
diff --git a/spec/Zot6/Content.md b/spec/Zot6/Content.md
new file mode 100644
index 000000000..a3179ff16
--- /dev/null
+++ b/spec/Zot6/Content.md
@@ -0,0 +1,15 @@
+## Content
+
+Some Zot applications/implementations are able to support complex content structures including embedded apps, identity-aware content, and authenticated links. Not all implementations are required to support, or may be able to support these types of content. Additionally, the data serialisation formats supported by the implementation may affect the ability to fully represent rich identity-aware content.
+
+### ActivityStreams
+
+An implementation which only supports ActivityStreams2 will receive "message" content as type 'Article', and which contains a generic HTML rendering of the source content in the "content" or "contentMap" elements. This generic rendering is suitable for any observer and some HTML links may be inaccessible due to permission and authentication requirements.
+
+The source for the rendered HTML is available in the "source" element. Implementations which wish to support identity-aware content and authenticated links should use this source content (especially if it is type "text/x-zot-bbcode") to dynamically generate an HTML rendering that is specific to the current observer.
+
+The exact feature set supported by the implementation and local security filtering MAY result in rendered content that is empty. Implementations MAY choose not to display rendered content that is empty or MAY indicate to the observer that the content could not be rendered sucessfully. Implementations SHOULD provide a menu option to 'view source' and provide the ability to access the original content if the rendering results in empty content and is a mimetype that is determined to be safe to display in source format.
+
+### Zot
+
+The same considerations apply to content which uses the 'zot' serialisation. In this case, the content source is the "body" element and is of type "mimetype". The observer-neutral HTML rendering will be provided in the "html" element. \ No newline at end of file
diff --git a/spec/Zot6/Discovery.md b/spec/Zot6/Discovery.md
new file mode 100644
index 000000000..a5f3f01c8
--- /dev/null
+++ b/spec/Zot6/Discovery.md
@@ -0,0 +1,112 @@
+### Discovery
+
+Channel discovery is accomplished primarily through webfinger (RFC7033). You will be looking for an entry with
+
+````
+rel: http://purl.org/zot/protocol/6.0
+type: application/x-zot+json
+href: (discovery rhef)
+````
+
+Load the url from the href using and HTTP Accept header of
+
+````
+Accept: application/x-zot+json;
+````
+
+This will provide a channel discovery document. It also includes a site discovery section.
+You may load the site discovery packet separately by accessing the domain top level with
+
+````
+Accept: application/x-zot+json;
+````
+
+Sample channel discovery document
+
+````
+{
+ "id": "XSWtrP_U65k9ZXeBxoYbcBgy6cVteo3yLwmLy4ppkjXqAryky0pYBq8YWnj7rApoTSdgy-QeciQG7Yhz7QYt4g",
+ "id_sig": "sha256.yG_Biu8pTpV0DlKPzoZHi0PbpM3okDYB7v5z2UuB___6J85gSOiOdes1tLwSmFkjbYMZbL2oksIe2tmD32lJWxpycSWJlDNbK8oggAtMx1sfVwyZOX_O0QBde2SxWCp0EIrRTRacIyKBzJhPRxCsGkc0uWin6XesXVZuYEVCxESr0KMT35Y79keOXGjJGv822C-Z2Nb4vphpbpftllGjxXOV70PxTNF0uZTWeVSmv2O0FGhkqBeBvBZU0FaWdYZqZZbd2AN_bto-8P95KMw6Fdfl2NIeL6vpD3xSu59Qhztl8L5npU13S3yvywzSvNg8DVgpNqcRmMiebaspfcjttCEAKtB2H-uiPkeuvDUk_iMXGtSUulcsNt1VFtSTnLEG371O6kj3dsczCV4QrpKBdIWNF3_41xHhrLi4Pug5JQg_wncyBSXu6Uj9pkCiD-JPVfI0ViCPccJcCKB-kXpP2EQIoPMhjV5x3bruI0TFLxrJqKWuoY6m8KUYrlGRdewaPYJ7pOY2NSNeLb9z6PO3UHT0bnr3DLyNxypxiUo5Pg4BxnHeuVKmiTxULF06KSwLmPDGsscrBSX1wIbHP6rhcmh0vDP0af2ixluLJbcLbptI2d137tFDVT4lTWBZ8PRNPWi1rfSl_x-dzevF8Dd3vi0iWd7D-aK89rqmRfUKsWk",
+ "aliases": [
+ "acct:zapper@zap.macgirvin.com",
+ "https://zap.macgirvin.com/channel/zapper"
+ ],
+ "primary_location": {
+ "address": "zapper@zap.macgirvin.com",
+ "url": "https://zap.macgirvin.com/channel/zapper",
+ "connections_url": "https://zap.macgirvin.com/poco/zapper",
+ "follow_url": "https://zap.macgirvin.com/follow?f=&url=%s"
+ },
+ "public_key": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA154VVJChRzsdm1Aba4su\nMLhhnuTELsQCIuDGB07lxTlHmJeeD9eImLXzQPDTNlLcCYVQkKH1uPhfhwnBFITu\noG7hr9QklhFZxfe9IFiAfr7w1+IRFXCYEwfe/eAaYDoprNqtMxonniOiVvnAdNs+\nRi1/Bfasd9d4BRBSj2KwuAeTke7gvHlACRKmauhFmhfG2fzj53AL2ixsraBzdccR\nFseICC99eldgWk2Jg16J1Euh51HV56jUWoz4ZYb1Kxri8zf55R2GiQJCHvSCLlgl\noFaiHLPS+yBIlCkNZ+47ee6DL7ePJ6kip6+ukAP5/1vOM0ahTPANoqaWmg19RsOu\n2q0LPyotWyLX1JX13rtLC7qFlSST31gxY082G8QIJfEbWgYoci0g2XOCDjAZ3JjI\neK/+tZwLzrV5l5Tcorf35Kbc/lHbMSm+wuyc6eQV14tj542nUftZAgpkPOImHsRm\nLqwiG6uxpfIW0TFuUse45F/faYbV4pbcaGm7Hwp/MbXl8vNiE0LpV9eqZu5ryVjZ\nT+Vt32ISWuTeyLqB1Wb/lWP9lGsMFDtsiZ5Wst1W8omrAgYfYo4RxOr14TUiJg3T\nmgTg10fBrcTC210Kl0lKNkHGi0qK8LaB2QwuWy7FKgx5I7yhgWKSWLVFhIOlca/X\nFo0mxCf8NPqOrhxRdS6UeucCAwEAAQ==\n-----END PUBLIC KEY-----\n",
+ "name": "Zapper",
+ "name_updated": "2018-06-04 03:22:19",
+ "username": "zapper",
+ "photo": {
+ "url": "https://zap.macgirvin.com/photo/profile/l/2",
+ "type": "image/png",
+ "updated": "2018-06-04 03:22:19"
+ },
+ "channel_role": "social",
+ "searchable": true,
+ "adult_content": false,
+ "public_forum": false,
+ "profile": {
+ "description": "",
+ "birthday": "",
+ "gender": "",
+ "marital": "",
+ "sexual": "",
+ "locale": "",
+ "region": "",
+ "postcode": "",
+ "country": "",
+ "about": "",
+ "homepage": "",
+ "hometown": ""
+ },
+ "permissions": "view_stream,view_profile,view_contacts,view_storage,view_pages,view_wiki",
+ "permissions_for": "",
+ "locations": [
+ {
+ "host": "zap.macgirvin.com",
+ "address": "zapper@zap.macgirvin.com",
+ "id_url": "https://zap.macgirvin.com/channel/zapper",
+ "primary": true,
+ "url": "https://zap.macgirvin.com",
+ "url_sig": "sha256.qBKZU6tReyUkVcNgGldRfdINiPoBneN9wWc-RHN7CFj8z9GgRW26LDUgmWL6kNoobYvHO6VIdZLxJb6CGdTLs7pjYGMZeTxpHHTgo3uHdBBIJdWPAwyEoppKGR3qT3S5iYWW9P0dsMtGjQ_q2VdaiqguoG8Z3lnTWikT7ujPI4NXZP2R0PVzEmaefN4SXqTO22XhXO-SuK4EOHylGcusQCfO6hXji9KItfwH1rnPx588YNRQ9WvBkV95ArZYSELRoFuJfHWh4ABqqAwQ4BqTO4-Pv1LiN1bWoNwVTki79Lx2GhQlw-_7HcHtVpqW_TQ04G4iPXvWHLzKfErfbGnQ575sbsF1gc2MYOINCofOmTq8eU_HOWaGK8D10HxpCVMMZXK37i8b6QEk3wpCoGiStGe5nsytVepZwNhsdnmW5msyO2ew_jZo3t_lP7U3oRvJHyJ7JpZBZg4E-MkLa-00KtiVGIosCesmFbZ042OwwTH3iJeSgz-yxrOsg3xdCj3e7rx4E93ra91OdN-mL-x8K4iYjcPQ6UpjInx2qsc_B8qwiw7L4jqJan7SYRDlxSiAb3yd1NFqL5gEMBg7RkS9s9a92hU3R6_K6CPpP9fb4mzRAzxpgRMpzhmBKnzlWF_Uz6c0urQpJLqJxfV4OzFThyxuqi3UyPg_R59DY3JfDUI",
+ "site_id": "gcwJ1OzIZbwtfgDcBYVYhwlUmjaxsgPyJezd-F2IS1F3IrlVsyOesNpm3hvoWemIBxoHmgIlMYKkhFeYihsqBQ",
+ "callback": "https://zap.macgirvin.com/zot",
+ "sitekey": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuOkQslfq9EjZJLVniWP1\n3anzfdASnlgUKUYK1zyxy/HbwxAXl0GupYpJEVNIpkrGtTUMWY7ppxH7y/EAiSTJ\nsMIFIy1AnHgS/ecx6N/tH6rzZ68jD8yJQxjZBUk7MfhfYOK8KUti/qmp859Pr3cA\n1K1woCtSLRx2HNzHED8LDTUCGSwneHA2m7Ffc1MNfII8Ia/VtoF7pBwOixayws2N\nlY5syuDqOO3LtMJnDMBRN5WbtTw5jobyaoK6o4+Kg7Kln0nymloD3knFFsPvIdJd\nl493ItBi6k5QR0PV8NtElZMWRy8gZjzI5c4yukXku0WK1lVJBpjl4/LfjulWSMaR\nzj+YZKTjw7G56EEB2drNUVn/ZYLYwvMn6Bv/8lYu4VwL873UbupITNGX/Wh7+EU3\ntJqvXvdh8scIAKR3+sS/SrNI6OMn34HKewaX8iMf6NgW5lrskr9dhOYuZVr63huc\nhXxdGv+6b5+ARYEOpTn5QQd89WSL4Vui+1VaO4FARt9oRiC9s3sd0swyTxFqJSY4\nYJcpuVMUKY54jOGpsT0+1DlYFZf+lOk7pRpuYY1Vv/AhWCpkt6Uamf5d11rnVikA\nuPFgFqaObFenM1u1EKF1xrNaQqy3NbhOb0yRatVPcnAwOlesHbM7tgKmyZSopJTW\nJ2ug8isS+vNI0q+4IwET5FMCAwEAAQ==\n-----END PUBLIC KEY-----\n",
+ "deleted": false
+ }
+ ],
+ "site": {
+ "url": "https://zap.macgirvin.com",
+ "site_sig": "sha256.OWCNR-OocRwk2Y4RwSHtE-y_bcWPkXYPQetvRO-8VjO_b0eqwKDjvB52WPKKl43UQRHRn0CN6Xc487zPY7bVqIaLcsE23R0JOacl9IO3_9k-RbeH6H8KV8E_GynM-6cucPI1Dh7s3rgcqk-GXwoRaFaraurYDHvoGEVHOa1jHpv75lT2COCi1sDGhDR3-KPJbug61y58CUu3bJj2VRAqBaoiMz5TwbUIY9Sb22d205X_UzoIF_TlPDMoZv-Mbrkcxn9kgIfatgVyKGKKyoAnvyJeFzjHm1xCY4sZtt4C_em0a5wpcVPl31KbI5BodKn910ChErHXMCedBPeYWhRA0a-9Y_vYGonun3jXqJZ33WxzG9P1Gllp4bhxK6tm9X1iRpUnB7j8g8RHSH4PukQKSl2ErZ2vPLdHMIkczX9YEhhCbeZIvcX6T_5s82Ua75rlVktJGHsh8yLw3iqCdWljpCVhTWpEK0NmhJB6TcadE9qlRN9Gun7keEV4Ov6Dl5O7I-0ssoWbhv7lHU6JcjhAuf2TDLod_Izka32ZZk_8s8ZmqFzEEG6g6pRyuzvqk4XNK6cTL6dvBGIua5D0bRTBn4XTELx8u4B3yK7_MArr_m5Z5KfXOm_ngGMCN-lIZuKhxAQpCVDD5jcHmnCzjcDiR5m5LvOfvBSxwtpgHZUr3AU",
+ "post": "https://zap.macgirvin.com/zot",
+ "openWebAuth": "https://zap.macgirvin.com/owa",
+ "authRedirect": "https://zap.macgirvin.com/magic",
+ "sitekey": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuOkQslfq9EjZJLVniWP1\n3anzfdASnlgUKUYK1zyxy/HbwxAXl0GupYpJEVNIpkrGtTUMWY7ppxH7y/EAiSTJ\nsMIFIy1AnHgS/ecx6N/tH6rzZ68jD8yJQxjZBUk7MfhfYOK8KUti/qmp859Pr3cA\n1K1woCtSLRx2HNzHED8LDTUCGSwneHA2m7Ffc1MNfII8Ia/VtoF7pBwOixayws2N\nlY5syuDqOO3LtMJnDMBRN5WbtTw5jobyaoK6o4+Kg7Kln0nymloD3knFFsPvIdJd\nl493ItBi6k5QR0PV8NtElZMWRy8gZjzI5c4yukXku0WK1lVJBpjl4/LfjulWSMaR\nzj+YZKTjw7G56EEB2drNUVn/ZYLYwvMn6Bv/8lYu4VwL873UbupITNGX/Wh7+EU3\ntJqvXvdh8scIAKR3+sS/SrNI6OMn34HKewaX8iMf6NgW5lrskr9dhOYuZVr63huc\nhXxdGv+6b5+ARYEOpTn5QQd89WSL4Vui+1VaO4FARt9oRiC9s3sd0swyTxFqJSY4\nYJcpuVMUKY54jOGpsT0+1DlYFZf+lOk7pRpuYY1Vv/AhWCpkt6Uamf5d11rnVikA\nuPFgFqaObFenM1u1EKF1xrNaQqy3NbhOb0yRatVPcnAwOlesHbM7tgKmyZSopJTW\nJ2ug8isS+vNI0q+4IwET5FMCAwEAAQ==\n-----END PUBLIC KEY-----\n",
+ "directory_mode": "normal",
+ "encryption": [
+ "aes256ctr.oaep",
+ "camellia256cfb.oaep",
+ "cast5cfb.oaep"
+ ],
+ "zot": "6.1",
+ "register_policy": "closed",
+ "access_policy": "private",
+ "accounts": 1,
+ "channels": 3,
+ "admin": "mike@macgirvin.com",
+ "plugins": [],
+ "sitehash": "c89e5a2b5059d04cc05078899c2083d4b89c190e6d6b247300256bfc66a930b3",
+ "sitename": "Zap Development",
+ "sellpage": "",
+ "location": "",
+ "realm": "RED_GLOBAL",
+ "project": "zap",
+ "version": "6.6"
+ }
+}
+```` \ No newline at end of file
diff --git a/spec/Zot6/Encryption+Signatures.md b/spec/Zot6/Encryption+Signatures.md
new file mode 100644
index 000000000..b1071fcb4
--- /dev/null
+++ b/spec/Zot6/Encryption+Signatures.md
@@ -0,0 +1,142 @@
+### Encryption
+
+Sites provide in their site discovery document an array containing 0 or more encryption algorithms which it is willing to accept in order of preference. Sites sending encrypted documents MUST use this list to determine the most suitable algorithm to both parties. If a suitable algorithm cannot be negotiated, the site MAY fall back to plaintext (unencrypted data) but if the communications channel is not secured with SSL the sending site MUST NOT use plaintext and a receiving site MAY ignore or reject the communication if it contains private or sensitive information.
+
+If the receiving site does not support the provided algorithm, it MUST return error 400.
+
+Encrypted information is encapsulated into a JSON array/object with the following components:
+
+````
+'encrypted' => true
+'key' => The encryption key, base64urlencoded
+'iv' => The encryption initialisation vector, base64urlencoded
+'alg' => The encryption algorithm used
+'data' => The encrypted payload, base64urlencoded
+````
+
+The 'encrypted' boolean flag indicates this is a cryptographic structure and requires decryption to extract the information. 'alg' is required. Other elements may be change as necessary to support different mechanisms/algorithms. For instance some mechanisms may require an 'hmac' field. The elements shown support a wide variety of standard encryption algorithms.
+
+The key and iv are psuedo-random byte sequences, encrypted with the RSA public key of the recipient prior to base64urlencoding. The recipient key used in most cases (by default) will be the remote site public key. In certain circumstances (where specified) the RSA public key will be that of the target channel or recipient.
+
+Both 'key' and 'iv' MAY be padded to 255 chars. The amount of padding necessary is dependent on the encryption algorithm. The incoming site MUST strip additional padding on both parameters to limit the maximum length supported by the chosen algorithm. For example, the aes256cbc algorithm (not recommended) uses a key length of 32 bytes and an iv of 16 bytes.
+
+Algorithm names for common algorithms are the lowercase algorithm names used by the openssl library with punctuation removed. The openssl 'aes-256-ctr' algorithm for example is designated as 'aes256ctr'.
+
+Uncommon algorithms which are unsupported by openssl may be used, but the exact algorithm names are undefined by this document.
+
+
+### Signatures
+
+Identity provenance is provided using HTTP Signatures (draft-cavage-http-signatures-10 is the relevant specification currently). If using encrypted transport, the HTTP Signature MAY be encrypted using the same negotiated algorithm as is used in the message for envelope protection. See [HTTP Signatures](spec/HTTPSignatures/Home). If a site uses negotiated encryption as described in the preceding section, it MUST be capable of decrypting the HTTP Signatures.
+
+In several places of the communications where verification is associated with a third party which is not the sender of the relevant HTTP packet, signed data/objects are specified/required. Two signature methods may be used, depending on whether the signed data is a single value or a JSON object. The method used for single values is referred to here as SimpleSignatures. The object signature method used is traditionally known as salmon magic signatures, using the JSON serialisation.
+
+#### Simple Signatures
+
+A data value is signed with an appropriate RSA method and hash algorithm; for instance 'sha256' which indicates an RSA keypair signature using the designated RSA private key and the 'sha256' hash algorithm. The result is base64url encoded, prepended with the algorithm name and a period (0x2e) and sent as an additional data item where specified.
+
+````
+"foo_sig": "sha256.EvGSD2vi8qYcveHnb-rrlok07qnCXjn8YSeCDDXlbhILSabgvNsPpbe..."
+````
+
+To verify, the element content is separated at the first period to extract the algorithm and signature. The signature is base64urldecoded and verified using the appropriate method and hash algorithm using the designated RSA public key (in the case of RSA signatures). The appropriate key to use is defined elsewhere in the Zot protocol depending on the context of the signature.
+
+Implementations MUST support RSA-SHA256 signatures. They MAY support additional signature methods.
+
+#### Salmon "magic envelope" Signatures with JSON serialisation.
+
+````
+{
+ "signed": true,
+ "data": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGl...",
+ "data_type": "application/x-zot+json",
+ "encoding": "base64url",
+ "alg": "RSA-SHA256",
+ "sigs": [
+ {
+ "value": "EvGSD2vi8qYcveHnb-rrlok07qnCXjn8YSeCDDXlbhILSabgvNsPpbe...",
+ "key_id": "4k8ikoyC2Xh+8BiIeQ+ob7Hcd2J7/Vj3uM61dy9iRMI"
+ }
+ ]
+}
+````
+
+The boolean "signed" element is not defined in the magic envelope specification. This is a boolean flag which indicates the current element is a signed object and requires verification and unpacking to retrieve the actual element content.
+
+The signed data is retrieved by unpacking the magic signature 'data' component. Unpacking is accomplished by stripping all whitespace characters (0x0d 0x0a 0x20 and 0x09) and applying base64 "url" decoding.
+
+The key_id is the base64urlencoded identifier of the signer, which when applied to the Zot 'Discovery' process will result in locating the public key. This is typically the server base url or the channel "home" url. Webfinger identifiers (acct:user@domain) MAY also be used if the resultant webfinger document contains a discoverable public key (salmon-public-key or Webid key).
+
+Verification is performed by using the magic envelope verification method. First remove all whitespace characters from the 'data' value. Append the following fields together separated with a period (0x2e).
+
+data . data_type . encoding . algorithm
+
+This is the "signed data". Verification will take place using the RSA verify function using the signed data, the base64urldecoded sigs.value, algorithm specified in 'alg' and the public key found by performing Zot discovery on the base64urldecoded sigs.key_id.
+
+When performing Zot discovery for keys, it is important to verify that the principal returned in the discovery response matches the principal in the key_id and that the discovery response is likewise signed and validated.
+
+Some historical variants of magic signatures emit base64 url encoding with or without padding.
+
+In this specification, encoding MUST be the string "base64url", indicating the url safe base64 encoding as described in RFC4648, and without any trailing padding using equals (=) characters
+
+The unpacked data (once verified) may contain a single value or a compound object. If it contains a single value, this becomes the value of the enclosing element. Otherwise it is merged back as a compound object.
+
+Example: source document
+
+````
+{
+ "guid": {
+ "signed": true,
+ "data": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGl...",
+ "data_type": "application/x-zot+json",
+ "encoding": "base64url",
+ "alg": "RSA-SHA256",
+ "sigs": [
+ {
+ "value": "EvGSD2vi8qYcveHnb-rrlok07qnCXjn8YSeCDDXlbhILSabgvNsPpbe...",
+ "key_id": "4k8ikoyC2Xh+8BiIeQ+ob7Hcd2J7/Vj3uM61dy9iRMI"
+ }
+ ]
+ },
+ "address": "foo@bar"
+}
+````
+
+Decoding the data parameter (and assuming successful signature verification) results in
+
+````
+"abc12345"
+````
+
+Merging with the original document produces
+
+````
+{
+ "guid": "abc12345",
+ "address": "foo@bar"
+}
+````
+
+Example using a signed object containing multiple elements:
+
+
+Decoding the data parameter (and assuming successful signature verification) results in
+
+````
+{
+ "guid": "abc12345",
+ "name": "Barbara Jenkins"
+}
+````
+
+Merging this with the original document produces
+
+````
+{
+ "guid": {
+ "guid": "abc12345",
+ "name": "Barbara Jenkins"
+ },
+ "address": "foo@bar"
+}
+```` \ No newline at end of file
diff --git a/spec/Zot6/Home.md b/spec/Zot6/Home.md
new file mode 100644
index 000000000..8b563dc7b
--- /dev/null
+++ b/spec/Zot6/Home.md
@@ -0,0 +1,92 @@
+## Zot/6 aka Zot 2018
+
+This document describes version 6 of the Zot protocol. This is a living document, last modified on 2018-09-14.
+
+Zot is a **WebMTA** which provides a decentralised identity and communications protocol using HTTPS/JSON.
+
+Earlier revisions of the zot protocol dealt with the creation of nomadic identities and cross-domain authentication to enable a decentralised network with features rivaling large centralised providers.
+
+Zot/6 builds on those concepts and streamlines many of the interactions, applying lessons learned over decades of building decentralised systems.
+
+A reference implementation (a social media app) is provided at https://framagit.org/zot/zap ; the reference implementation is not yet 100% spec compliant or complete but may be used for basic compatibility testing and development purposes.
+
+### Differences from earlier Zot versions
+
+1. Streamlined communications using direct (push) transfer. Earlier versions used a 'notify/pickup' delivery model.
+2. The authentication component (Magic-Auth) has been spun off into a separate and independent specification ['OpenWebAuth'](spec/OpenWebAuth/Home.md).
+3. Inclusion of ActivityStreams (JSON-LD) as a supported (primary) serialisation.
+4. Dropping the requirements for implementations to support secondary serialisations.
+5. Moving service discovery to "Accept-header" based service endpoints; where different representations can be selected by modification of the HTTPS request Accept: header.
+6. Separation of the "portable-id" from the signature algorithm used.
+
+### Differences between Zot and other WebMTA services
+
+Zot is architecturally different from other HTTPS-based "social communications" protocols such as OStatus, ActivityPub, and Diaspora. The primary differences are:
+
+1. Support for nomadic identity where an identity is not permanently bound to a DNS server.
+2. MUAs built on top of Zot are able to use and express detailed cross-domain permissions.
+3. Encryption negotation for additional message protection in addition to HTTPS
+4. Zot does not define an absolute payload format for content. Implementations MUST support ActivityStreams. Additional message types and serialisation formats MAY provide vendor specific enhancements.
+5. Federation between other WebMTA protocols is not hampered by unnecessary restrictions on 3rd party communications. Messages from incompatible systems may be relayed to other sites which do not support the 3rd party protocol.
+6. Detailed delivery reporting is provided for auditing and troubleshooting; which is critical in a distributed communications service.
+
+## Fundamental Concepts
+
+### Identity
+
+In Zot/6 decentralised identity is a core attribute of the system. This is somewhat different than (and often incompatible with) typical decentralised or P2P communications projects where messaging is the key component and identity is merely an atribution on a message.
+
+An identity consists of two primary components.
+
+1. An identity "claim" which is essentially a text string
+2. An RSA based key with which to verify that identity
+
+These will be described in detail later. A "valid" identity is an identity which has been verified using public key cryptographic techniques. Until verified, an identity is "claimed" (unverified). An "invalid" identity is an identity which failed verification or has been revoked.
+
+In Zot/6 claimed (unverified) identities are allowed to exist, and MAY be allowed permissions to perform operations. This allows cross communication to occur between Zot/6 and other communications systems with different concepts of identity and different methods of validation.
+
+An implementation MAY choose to block unverified identities. This may significantly reduce the ability to interact with foreign systems, protocols, and networks.
+
+Invalid identities MUST NOT be allowed any permissions. By definition they are forgeries or have been revoked.
+
+### Channels
+
+Channels are what would typically be referred to as "users" on other systems, although this notion is abstracted in Zot/6 and can take on other meanings. A channel is represented as an identity.
+
+### Location and Location Independence
+
+A location is an identity and follows all the rules associated with an identity. The identity claim is typically the fully qualified "base" URL of the web service providing Zot/6 services, lowercased, with trailing slashes removed. International domain names are converted to "punycode".
+
+A "location independent identity" is a valid channel identity paired with a valid location, with the additional property that the channel/location pair has been validated using the key of the channel identity. In layman's terms, the user signs his/her website with their own key.
+
+The location independent model allows mobility of a channel to different or even multiple locations; which may all be valid simultaneously. This is referred to elsewhere as a "nomadic" identity.
+
+For the benefit of those that are new to this concept, this means in basic terms that a channel can appear at any location at any time as long as the location independent identity is valid.
+
+### Linked identities
+
+One or more channels/identities can be linked. In simple terms, this allows us to define a persistent token which refers to an identity whose claim string or public key (or both) have changed or is being merged from another system. In order to link identities, in addition to the requirement that both identities MUST validate, each identity MUST sign the other linked identity and all of these signatures MUST be valid.
+
+In the case of providing controlled access to website resources, all linked identities SHOULD be folded or reduced to a common identifier so that an attempt to access a protected resource by any linked identity will succeed for a resource that has been made available to any of its linked identities.
+
+### Nomadic Considerations
+
+The location independent properties of Zot/6 place additional requirements on communications systems. For outgoing messages, delivery SHOULD be attempted to every linked and nomadic location associated with the identity being delivered to. The service MAY remove a valid linked or nomadic location from the list of delivery targets if the location is marked "dead" or "unreachable". A location MAY be marked "dead" or "unreachable" for a number of reasons; generally by a failure to communicate for more than 30 days, or by manual means if the site administrator has reason to believe the location has been shut down permanently. A site SHOULD retain the location record and automatically remove the "dead" or "unreachable" designation if valid communications are initiated from that location in the future.
+
+
+## Transport and Protocol Basics
+
+Communications with Zot/6 take place primarily with https JSON requests. Requests are signed by the "sender" using HTTP-Signatures (draft-cavage-http-signatures-xx). If a payload is present, the signed headers MUST include a Digest header using SHA-256 or SHA-512 as specified in RFC5843.
+
+For HTTP requests which do not carry a payload any headers may be signed, but at least one header MUST be signed.
+
+Signed requests MAY be rejected if
+
+- Digest verification fails
+- The request has a JSON payload and the content is not signed
+- public-key retrieval fails
+
+
+Public keys are retrieved by utilising Zot/6 Discovery on the signature data's 'keyId' property and retrieving the public key from that document. Zot Discovery is described in a later chapter.
+
+Receivers verifying these requests SHOULD verify that the signer has authority over the data provided; either by virtue of being the author or a relay agent (sender). \ No newline at end of file
diff --git a/spec/Zot6/Message Types.md b/spec/Zot6/Message Types.md
new file mode 100644
index 000000000..e4e0f1c22
--- /dev/null
+++ b/spec/Zot6/Message Types.md
@@ -0,0 +1,111 @@
+## Message Types
+
+### purge
+
+This message type has no payload or encoding. If the message has recipients, it is considered an "unfriend" action. The sender's relationship with the recipients is severed. The exact actions which are undertaken as a result are implementation specific. Generally, the sender's permissions to the receiver are revoked. Permissions granted to the sender by the receiver MAY be left intact.
+
+If the message has no recipients, it is considered a notification that the sender identity no longer exists. Receiving sites MUST mark the channel as unavailable and discontinue further communications. They SHOULD destroy all public content attributed to the sender and MAY remove the connection and private content from connected channels.
+
+The response to this message is
+
+````
+{
+ 'success': true
+}
+````
+
+or
+
+````
+{
+ 'success': false,
+ 'message': 'optional error message or reason'
+}
+````
+
+Servers SHOULD only provide a single recipient when using a targetted message as the single return response may be ambiguous.
+
+
+### refresh
+
+This message has no payload or encoding. It is a message to the receiving server that important channel information has changed. The receiving server MUST process a zot discovery operation and update any locally stored information which has changed. If the message has recipients, this action should be accomplished by the receiver using a signed discovery fetch, signed by the recipient. Response is the same as for a purge message.
+
+A targetted refresh message (e.g. containing recipients) is commonly used to indicate a change in permissions granted to the recipient by the sender. If no permissions have previously been associated with this sender, it is considered to be a "friend request", meaning some permissions are available which may not have been available before. The receiving channel SHOULD store the updated permissions and SHOULD add the sender to the receiver's known connections. It MAY notify the recipient that a new friend exists and put the connection into a 'pending' state until the request has been reviewed/accepted/rejected by the recipient.
+
+### rekey
+
+The rekey message is sent with no recipients. The message indicates the sender has changed their public key. The key change MUST be signed with both the old and new private keys and these signatures MUST validate or the operation MUST fail.
+The 'update' boolean flag (if present) indicates the old portable\_id associated with that key is to be changed, and the old portable\_id discarded. If 'update' is false, a new portable\_id is generated and the old and new identities are linked. This means that both portable\_id's are valid nomadic identifiers for the same channel. Response is the same as for the purge message.
+
+### activity
+
+Message encoding: activitystreams
+
+This message type is used for normal communications. If recipients are specified, the message is private. If no recipients are specified, the message is public. The recipient list MAY be filtered and contain only the recipients which are known to be available on the receiving website. A message MUST NOT be sent by the sender if the message is private and the recipient list for a particular receiving site is empty.
+
+
+````
+{
+ "type": "Create",
+ "id": "https://example.org/item/e8a20a21dd7e0d8d2207a5df62d2168d65db7db08f1a91ca",
+ "published": "2018-06-25T04:14:08Z",
+ "actor": "https://example.org/channel/zapper",
+ "object": {
+ "type": "Article",
+ "id": "https://example.org/item/e8a20a21dd7e0d8d2207a5df62d2168d65db7db08f1a91ca",
+ "published": "2018-06-25T04:14:08Z",
+ "content": "just another Zot6 message",
+ "actor": "https://example.org/channel/zapper",
+ },
+}
+````
+
+Upon delivery, a delivery report is generated and returned to the sending site.
+
+````
+{
+ "success": true,
+ "delivery_report": [
+ {
+ "location": "https://zap.macgirvin.com",
+ "sender": "T5ni0wUAlYmyqlibiTQiS54PqLKXCL7XAJhOSKeJMqEXeKn46AkDPdCJZ4JUA05Vlhux25OLTkBPyV7L60JmyQ",
+ "recipient": "xxWsqvZp3w-sr3FXrmb6wxmKZx6khMLjBCOafPdRT1lWzYmCPHeaDDBD9KwOqpOAt4lezIFQbyaLt9I3H54M9Q",
+ "name": "System",
+ "message_id": "https://zap.macgirvin.com/item/ebaa483a2e8331a21a68b9d9e4a72a079c260162d2e37edc",
+ "status": "posted",
+ "date": "2018-06-26 05:19:48"
+ },
+ {
+ "location": "https://zap.macgirvin.com",
+ "sender": "T5ni0wUAlYmyqlibiTQiS54PqLKXCL7XAJhOSKeJMqEXeKn46AkDPdCJZ4JUA05Vlhux25OLTkBPyV7L60JmyQ",
+ "recipient": "wXDz7WR51QHwAORaVR8-0wff06LBtBWvhd_zfDWTYEzaqaPfJ_fsK7nRaM4aVeKPmZklUAgtqs09zUzitwNT2w",
+ "name": "Zapper",
+ "message_id": "https://zap.macgirvin.com/item/ebaa483a2e8331a21a68b9d9e4a72a079c260162d2e37edc",
+ "status": "posted",
+ "date": "2018-06-26 05:19:48"
+ },
+ {
+ "location": "https://zap.macgirvin.com",
+ "sender": "T5ni0wUAlYmyqlibiTQiS54PqLKXCL7XAJhOSKeJMqEXeKn46AkDPdCJZ4JUA05Vlhux25OLTkBPyV7L60JmyQ",
+ "recipient": "T5ni0wUAlYmyqlibiTQiS54PqLKXCL7XAJhOSKeJMqEXeKn46AkDPdCJZ4JUA05Vlhux25OLTkBPyV7L60JmyQ",
+ "name": "Bopper",
+ "message_id": "https://zap.macgirvin.com/item/ebaa483a2e8331a21a68b9d9e4a72a079c260162d2e37edc",
+ "status": "update ignored",
+ "date": "2018-06-26 05:19:48"
+ }
+ ]
+}
+````
+
+### response
+
+The response message is used to send a comment or reply "upstream" to the sender. The sender will then redeliver the message to all downstream recipients. It is the same as the activity message type except that it MUST have one and only one recipient - the sender of the activity that this activity references. This entire activity SHOULD be signed by the sender of the response and encapsulated as a json salmon magic envelope as described in [[Encryption/Signatures]].
+
+
+### sync
+
+Sync messages are used between nomadic clones to synchronise changed data structures. These messages are sent to nomadic instances of the sender as private messages and SHOULD be encrypted with additional encryption beyond HTTPS transport encryption as the messages may contain private keys.
+
+Implementations MAY provide sync messages and they MAY attempt to co-exist with sync packets created by other implementations. If their data synchronisation needs cannot be mapped to the sync structures provided by others, they MUST provide a unique encoding type (recommend the name of the implementation using only the letters [a-z] of the US-ASCII character set). If a site receives a sync message with an unknown encoding and data format it MUST be ignored.
+
+Basic sync information includes any local changes to personal settings, profile settings, and changes in the social graph. Implementations MAY support syncing of all available information including uploaded files and photos, events, and other application specific data structures. \ No newline at end of file
diff --git a/spec/Zot6/Messages.md b/spec/Zot6/Messages.md
new file mode 100644
index 000000000..744f0a4c0
--- /dev/null
+++ b/spec/Zot6/Messages.md
@@ -0,0 +1,135 @@
+### Messages
+
+Zot6 is primarily a transport and identification format. The semantics of message content are in many respects outside the scope of this document. Sites/servers MUST provide in their site discovery document what standardised message formats are acceptable.
+
+The message formats of primary concern to us are
+
+1. ActivityStreams (ActivityStreams JSON-LD) (format='activitystreams')
+2. Zot (format='zot')
+
+When using ActivityStreams JSON-LD, a default @context of "https://www.w3.org/ns/activitystreams" is assumed. Activity objects only need to specify or provide a @context declaration if there are differences from the default.
+
+### Delivery
+
+Delivery is a POST of envelope+data to the zot endpoint. HTTP Signatures are used to validate the sender.
+
+Delivery reports for private messages SHOULD be encrypted and MUST include results for host blocking.
+
+Here is a sample activity...
+
+````
+{
+ "type": "activity",
+ "encoding": "activitystreams",
+ "sender": "wXDz7WR51QHwAORaVR8-0wff06LBtBWvhd_zfDWTYEzaqaPfJ_fsK7nRaM4aVeKPmZklUAgtqs09zUzitwNT2w",
+ "site_id": "gcwJ1OzIZbwtfgDcBYVYhwlUmjaxsgPyJezd-F2IS1F3IrlVsyOesNpm3hvoWemIBxoHmgIlMYKkhFeYihsqBQ",
+ "recipients": {
+ "xxWsqvZp3w-sr3FXrmb6wxmKZx6khMLjBCOafPdRT1lWzYmCPHeaDDBD9KwOqpOAt4lezIFQbyaLt9I3H54M9Q",
+ "T5ni0wUAlYmyqlibiTQiS54PqLKXCL7XAJhOSKeJMqEXeKn46AkDPdCJZ4JUA05Vlhux25OLTkBPyV7L60JmyQ",
+ },
+ "version": "6.0",
+ "data": {
+ "type": "Create",
+ "id": "https://example.org/item/e8a20a21dd7e0d8d2207a5df62d2168d65db7db08f1a91ca",
+ "published": "2018-06-25T04:14:08Z",
+ "actor": "https://example.org/channel/zapper",
+ "object": {
+ "type": "Article",
+ "id": "https://example.org/item/e8a20a21dd7e0d8d2207a5df62d2168d65db7db08f1a91ca",
+ "published": "2018-06-25T04:14:08Z",
+ "content": "just another Zot6 message",
+ "actor": "https://example.org/channel/zapper",
+ },
+ },
+}
+````
+
+The sender\_id is the portable\_id of the sender. The site\_id is the portable\_id of the sender's website.
+Recipients is a simple array of portable_id's of message recipients. This list MAY be filtered and contain only the recipients which are known to be available on the receiving website.
+
+Version is provided to resolve potential protocol version differences over time. Data contains the actual ActivityStreams (in this case) payload.
+
+
+Receiving sites MUST verify the HTTP Signature provided and MUST reject (error 400) posts with no signature or invalid signatures. Discovery is used during the verification process and generates a locally stored portable\_id. If the portable\_id does not match the verified signer's portable\_id, the message MUST be rejected (error 400).
+
+If the recipients field is non-existent or empty, the post is considered public and may be delivered to any channel following the sender. If the recipient field has contents, the message MUST NOT be delivered to anybody except the listed recipients.
+
+Upon successful delivery, a delivery report is generated and returned to the sending site.
+
+````
+ {
+ "success": true,
+ "delivery_report": [
+ {
+ "location": "https://zap.macgirvin.com",
+ "sender": "T5ni0wUAlYmyqlibiTQiS54PqLKXCL7XAJhOSKeJMqEXeKn46AkDPdCJZ4JUA05Vlhux25OLTkBPyV7L60JmyQ",
+ "recipient": "xxWsqvZp3w-sr3FXrmb6wxmKZx6khMLjBCOafPdRT1lWzYmCPHeaDDBD9KwOqpOAt4lezIFQbyaLt9I3H54M9Q",
+ "name": "System ",
+ "message_id": "https://zap.macgirvin.com/item/ebaa483a2e8331a21a68b9d9e4a72a079c260162d2e37edc",
+ "status": "posted",
+ "date": "2018-06-26 05:19:48"
+ },
+ {
+ "location": "https://zap.macgirvin.com",
+ "sender": "T5ni0wUAlYmyqlibiTQiS54PqLKXCL7XAJhOSKeJMqEXeKn46AkDPdCJZ4JUA05Vlhux25OLTkBPyV7L60JmyQ",
+ "recipient": "wXDz7WR51QHwAORaVR8-0wff06LBtBWvhd_zfDWTYEzaqaPfJ_fsK7nRaM4aVeKPmZklUAgtqs09zUzitwNT2w",
+ "name": "Zapper ",
+ "message_id": "https://zap.macgirvin.com/item/ebaa483a2e8331a21a68b9d9e4a72a079c260162d2e37edc",
+ "status": "posted",
+ "date": "2018-06-26 05:19:48"
+ },
+ {
+ "location": "https://zap.macgirvin.com",
+ "sender": "T5ni0wUAlYmyqlibiTQiS54PqLKXCL7XAJhOSKeJMqEXeKn46AkDPdCJZ4JUA05Vlhux25OLTkBPyV7L60JmyQ",
+ "recipient": "T5ni0wUAlYmyqlibiTQiS54PqLKXCL7XAJhOSKeJMqEXeKn46AkDPdCJZ4JUA05Vlhux25OLTkBPyV7L60JmyQ",
+ "name": "Bopper ",
+ "message_id": "https://zap.macgirvin.com/item/ebaa483a2e8331a21a68b9d9e4a72a079c260162d2e37edc",
+ "status": "update ignored",
+ "date": "2018-06-26 05:19:48"
+ }
+ ]
+}
+````
+
+### Followups
+
+Followups to any post (replies, likes, reactions, etc.) MUST be sent as a private activity (single recipient) to the sender of the original with a message type 'response'. This is referred to as an "upstream delivery".
+
+Additionally these activities MUST provide an 'inReplyTo' element set to the id of the activity that is the object of the response. Implementations SHOULD support multi-level likes. Servers MAY support multi-level comments.
+
+
+The original sender MUST resend the followups to all of the original message recipients using message type 'activity'. This is referred to as a "downstream delivery".
+
+This single-source mechanism ensures the original sender's privacy settings are respected and conversations are kept intact for all recipients of the original message.
+
+### Multi-level support
+
+If multi-level comments are not supported, the receiver MUST re-parent the multi-level comment to the original conversation head, flattening the conversation to one level. The receiving server SHOULD store the correct target id, even if the comment is re-parented.
+
+If multi-level likes are not supported, the incoming "like" activity for a non-parent conversation node MAY be dropped or rejected, rather than being re-parented to a potentially unrelated activity than was intended.
+
+
+### Portable IDs
+
+Portable IDs are intended to provide location-independent identifiers across the network. A portable ID can only be trusted if it has been verified or if it has been generated on this site. Verification is performed during the [[Discovery]] process.
+
+The portable ID uses an obtained public\_key. In order to ensure that the portable ID calculation is portable, the calculation MUST be performed on a PKCS#8 public\_key. If the source key is provided in another format (such as a salmon [modulus/exponent] key or PKCS#1), the key MUST be converted to PKCS#8 format prior to calculating the portable ID.
+
+Here are the steps for generating a portable\_id.
+
+1. Via [[Discovery]], obtain the zot-info packet for a network URI. The network URI will often be presented as the signer keyID in a signed message, but may also be provided as an acct: URI submitted by site users.
+2. The zot-info packet contains everything necessary to verify an identity claim.
+3. With the public\_key, verify the id\_sig against the id (claimed identity).
+4. With the public\_key, verify the location->url\_sig against the location->url **for the discovery site**.
+5. With site->sitekey, verify the site->site\_sig against the site->url.
+6. Concatenate the id and the public\_key. Perform a whirlpool hash function on this concatenated string and base64_url encode the result.
+7. This is the channel portable\_id.
+8. Concatenate the url and site->sitekey. Perform a whirlpool hash function on this concatenated string and base64_url encode the result.
+9. This is the portable site\_id. Check that it matches the location->site\_id in the discovery packet.
+10. If any verification step fails, discard the results and return an error.
+
+This is generally considered an expensive calculation; hence the results should be stored as a channel/location pair.
+
+When receiving a Zot message, use the stored results (if available) for the signer's keyID when checking the HTTP Signature. If the HTTP Signature validates, and the keyID matches the location->id\_url for this location, and the sender portable\_id matches the calculated/stored portable\_id for this channel/location pair, the nomadic sender has been validated.
+
+If no stored results are available for the keyID, perform [[Discovery]] as described. \ No newline at end of file
diff --git a/spec/Zot6/Nomadic Identity.md b/spec/Zot6/Nomadic Identity.md
new file mode 100644
index 000000000..188707f62
--- /dev/null
+++ b/spec/Zot6/Nomadic Identity.md
@@ -0,0 +1,7 @@
+### Nomadic Identity
+
+One of the fundamental differences between Zot and other messaging systems/protocols is the support for nomadic identity. This simply means that your identity (who you are) is independent from the server you are posting from (where you are).
+
+As a consequence, a person can have any number of active locations. Implementations which support nomadic identity MUST send a copy of all communications destined for that identity to all known active locations. If sites receive a communication from the given identity from any location, they MUST validate that the identity has authorised this location and (if verification is successful) deliver it appropriately. They SHOULD store the newly verified location and MAY subsequently used the stored information rather than re-validating.
+
+When an identity modifies its location information, it MUST send a 'refresh' packet to all known sites where they maintain connections and which are capable of nomadic operation. The 'refresh' message informs the other site to perform network discovery and update all stored information related to the identity which may have changed. \ No newline at end of file
diff --git a/util/connect b/util/connect
index eed14961c..7ceda300f 100755
--- a/util/connect
+++ b/util/connect
@@ -1,6 +1,8 @@
#!/usr/bin/env php
<?php
+use Zotlabs\Lib\Libsync;
+
// connect utility
if(! file_exists('include/cli_startup.php')) {
@@ -51,7 +53,7 @@ cli_startup();
$abconfig = load_abconfig($c['channel_id'],$clone['abook_xchan']);
if($abconfig)
$clone['abconfig'] = $abconfig;
- build_sync_packet($c['channel_id'], array('abook' => array($clone)), true);
+ Libsync::build_sync_packet($c['channel_id'], array('abook' => array($clone)), true);
$can_view_stream = intval(get_abconfig($c['channel_id'],$clone['abook_xchan'],'their_perms','view_stream'));
diff --git a/util/dmkdir b/util/dmkdir
index 72ab22431..b939bc901 100755
--- a/util/dmkdir
+++ b/util/dmkdir
@@ -1,6 +1,8 @@
#!/usr/bin/env php
<?php
+use Zotlabs\Lib\Libsync;
+
// file import to DAV utility
if(!file_exists('include/cli_startup.php')) {
@@ -52,6 +54,6 @@ if($argc != 2) {
$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)));
}
- } \ No newline at end of file
+ }
diff --git a/util/pconfig b/util/pconfig
index 36d894fb5..c2027adaf 100755
--- a/util/pconfig
+++ b/util/pconfig
@@ -1,6 +1,8 @@
#!/usr/bin/env php
<?php
+use Zotlabs\Lib\Libsync;
+
// Red pconfig utility
@@ -63,7 +65,7 @@ if($argc > 2 && strpos($argv[2],'.')) {
if($argc > 4) {
set_pconfig($argv[1],$argv[2],$argv[3],$argv[4]);
- build_sync_packet($argv[1]);
+ Libsync::build_sync_packet($argv[1]);
echo "pconfig[{$argv[1]}][{$argv[2]}][{$argv[3]}] = " . get_pconfig($argv[1],$argv[2],$argv[3]) . "\n";
}
diff --git a/view/tpl/jot.tpl b/view/tpl/jot.tpl
index 4a9717c01..09ddb062d 100755
--- a/view/tpl/jot.tpl
+++ b/view/tpl/jot.tpl
@@ -155,16 +155,9 @@
<i id="profile-encrypt" class="fa fa-key jot-icons"></i>
</button>
{{/if}}
- {{if $feature_voting}}
- <button id="profile-voting-wrapper" class="btn btn-outline-secondary btn-sm" title="{{$voting}}" onclick="toggleVoting();return false;">
- <i id="profile-voting" class="fa fa-square-o jot-icons"></i>
- </button>
- {{/if}}
-
<button type="button" id="profile-poll-wrapper" class="btn btn-outline-secondary btn-sm" title="{{$poll}}" onclick="initPoll();">
<i id="profile-poll" class="fa fa-bar-chart jot-icons"></i>
</button>
-
{{if $feature_nocomment}}
<button id="profile-nocomment-wrapper" class="btn btn-outline-secondary btn-sm" title="{{$nocommenttitle}}" onclick="toggleNoComment();return false;">
<i id="profile-nocomment" class="fa fa-comments jot-icons"></i>
@@ -174,7 +167,7 @@
{{$custommoretoolsbuttons}}
{{/if}}
</div>
- {{if $writefiles || $weblink || $setloc || $clearloc || $feature_expire || $feature_encrypt || $feature_voting || $custommoretoolsdropdown}}
+ {{if $writefiles || $weblink || $setloc || $clearloc || $feature_expire || $feature_encrypt || $custommoretoolsdropdown}}
<div class="btn-group d-lg-none">
<button type="button" id="more-tools" class="btn btn-outline-secondary btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<i id="more-tools-icon" class="fa fa-cog jot-icons"></i>
@@ -206,9 +199,6 @@
{{if $feature_encrypt}}
<a class="dropdown-item" href="#" onclick="red_encrypt('{{$cipher}}','#profile-jot-text',$('#profile-jot-text').val());return false;"><i class="fa fa-key"></i>&nbsp;{{$encrypt}}</a>
{{/if}}
- {{if $feature_voting}}
- <a class="dropdown-item" href="#" onclick="toggleVoting(); return false;"><i id="profile-voting-sub" class="fa fa-square-o"></i>&nbsp;{{$voting}}</a>
- {{/if}}
<a class="dropdown-item" href="#" onclick="initPoll(); return false"><i id="profile-poll" class="fa fa-bar-chart jot-icons"></i>&nbsp;{{$poll}}</a>
{{if $feature_nocomment}}
<a class="dropdown-item" href="#" onclick="toggleNoComment(); return false;"><i id="profile-nocomment-sub" class="fa fa-comments"></i>&nbsp;{{$nocommenttitlesub}}</a>