aboutsummaryrefslogtreecommitdiffstats
path: root/Zotlabs
diff options
context:
space:
mode:
authorMario <mario@mariovavti.com>2020-11-05 08:46:42 +0000
committerMario <mario@mariovavti.com>2020-11-05 08:46:42 +0000
commitbafbf0416462c6f18c3fb6c8c06a063c8d6fdae6 (patch)
tree8929845be585b09d0f420621281c5531e1efad3e /Zotlabs
parent6f93d9848c43019d43ea76c27d42d657ba031cd7 (diff)
parentfdefa101d84dc2a9424eaedbdb003a4c30ec5d01 (diff)
downloadvolse-hubzilla-bafbf0416462c6f18c3fb6c8c06a063c8d6fdae6.tar.gz
volse-hubzilla-bafbf0416462c6f18c3fb6c8c06a063c8d6fdae6.tar.bz2
volse-hubzilla-bafbf0416462c6f18c3fb6c8c06a063c8d6fdae6.zip
Merge branch '5.0RC'5.0
Diffstat (limited to 'Zotlabs')
-rw-r--r--Zotlabs/Access/PermissionRoles.php4
-rw-r--r--Zotlabs/Access/Permissions.php13
-rw-r--r--Zotlabs/Daemon/Cron.php21
-rw-r--r--Zotlabs/Daemon/Cron_daily.php7
-rw-r--r--Zotlabs/Daemon/Directory.php19
-rw-r--r--Zotlabs/Daemon/Expire.php13
-rw-r--r--Zotlabs/Daemon/Gprobe.php14
-rw-r--r--Zotlabs/Daemon/Importfile.php4
-rw-r--r--Zotlabs/Daemon/Notifier.php168
-rw-r--r--Zotlabs/Daemon/Onepoll.php8
-rw-r--r--Zotlabs/Lib/AccessList.php411
-rw-r--r--Zotlabs/Lib/Activity.php756
-rw-r--r--Zotlabs/Lib/ActivityStreams.php34
-rw-r--r--Zotlabs/Lib/Apps.php14
-rw-r--r--Zotlabs/Lib/Cache.php14
-rw-r--r--Zotlabs/Lib/Chatroom.php4
-rw-r--r--Zotlabs/Lib/Connect.php312
-rw-r--r--Zotlabs/Lib/Enotify.php167
-rw-r--r--Zotlabs/Lib/JSalmon.php2
-rw-r--r--Zotlabs/Lib/Libsync.php31
-rw-r--r--Zotlabs/Lib/Libzot.php139
-rw-r--r--Zotlabs/Lib/Libzotdir.php26
-rw-r--r--Zotlabs/Lib/NativeWiki.php6
-rw-r--r--Zotlabs/Lib/NativeWikiPage.php7
-rw-r--r--Zotlabs/Lib/Queue.php2
-rw-r--r--Zotlabs/Lib/Share.php5
-rw-r--r--Zotlabs/Lib/System.php11
-rw-r--r--Zotlabs/Lib/ThreadItem.php62
-rw-r--r--Zotlabs/Lib/ThreadStream.php2
-rw-r--r--Zotlabs/Lib/Webfinger.php2
-rw-r--r--Zotlabs/Lib/Zotfinger.php2
-rw-r--r--Zotlabs/Module/Acl.php3
-rw-r--r--Zotlabs/Module/Activity.php269
-rw-r--r--Zotlabs/Module/Admin/Addons.php4
-rw-r--r--Zotlabs/Module/Apporder.php4
-rw-r--r--Zotlabs/Module/Apschema.php5
-rw-r--r--Zotlabs/Module/Articles.php2
-rw-r--r--Zotlabs/Module/Cards.php2
-rw-r--r--Zotlabs/Module/Cdav.php529
-rw-r--r--Zotlabs/Module/Channel.php46
-rw-r--r--Zotlabs/Module/Channel_calendar.php40
-rw-r--r--Zotlabs/Module/Chanview.php95
-rw-r--r--Zotlabs/Module/Chat.php8
-rw-r--r--Zotlabs/Module/Connect.php17
-rw-r--r--Zotlabs/Module/Connections.php25
-rw-r--r--Zotlabs/Module/Connedit.php103
-rw-r--r--Zotlabs/Module/Cover_photo.php14
-rw-r--r--Zotlabs/Module/Dav.php2
-rw-r--r--Zotlabs/Module/Defperms.php3
-rw-r--r--Zotlabs/Module/Dircensor.php52
-rw-r--r--Zotlabs/Module/Directory.php41
-rw-r--r--Zotlabs/Module/Dirsearch.php54
-rw-r--r--Zotlabs/Module/Display.php23
-rw-r--r--Zotlabs/Module/Embedphotos.php2
-rw-r--r--Zotlabs/Module/Event.php76
-rw-r--r--Zotlabs/Module/Feed.php2
-rw-r--r--Zotlabs/Module/Fhubloc_id_url.php79
-rw-r--r--Zotlabs/Module/Fhublocs.php38
-rw-r--r--Zotlabs/Module/File_upload.php6
-rw-r--r--Zotlabs/Module/Filestorage.php12
-rw-r--r--Zotlabs/Module/Follow.php102
-rw-r--r--Zotlabs/Module/Group.php3
-rw-r--r--Zotlabs/Module/Help.php5
-rw-r--r--Zotlabs/Module/Hq.php22
-rw-r--r--Zotlabs/Module/Import.php119
-rw-r--r--Zotlabs/Module/Item.php382
-rw-r--r--Zotlabs/Module/Like.php61
-rw-r--r--Zotlabs/Module/Locs.php34
-rw-r--r--Zotlabs/Module/Magic.php237
-rw-r--r--Zotlabs/Module/Mail.php449
-rw-r--r--Zotlabs/Module/Moderate.php6
-rw-r--r--Zotlabs/Module/Network.php90
-rw-r--r--Zotlabs/Module/Notes.php3
-rw-r--r--Zotlabs/Module/Oep.php8
-rw-r--r--Zotlabs/Module/Owa.php95
-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/Photo.php30
-rw-r--r--Zotlabs/Module/Photos.php16
-rw-r--r--Zotlabs/Module/Pin.php69
-rw-r--r--Zotlabs/Module/Profile_photo.php8
-rw-r--r--Zotlabs/Module/Profiles.php8
-rw-r--r--Zotlabs/Module/Pubstream.php13
-rw-r--r--Zotlabs/Module/Regdir.php35
-rw-r--r--Zotlabs/Module/Register.php2
-rw-r--r--Zotlabs/Module/Removeaccount.php4
-rw-r--r--Zotlabs/Module/Removeme.php4
-rw-r--r--Zotlabs/Module/Rmagic.php19
-rw-r--r--Zotlabs/Module/Search.php3
-rw-r--r--Zotlabs/Module/Settings/Calendar.php3
-rw-r--r--Zotlabs/Module/Settings/Channel.php8
-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.php13
-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.php121
-rw-r--r--Zotlabs/Module/Sse_bs.php691
-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/Viewconnections.php28
-rw-r--r--Zotlabs/Module/Vote.php143
-rw-r--r--Zotlabs/Module/Wall_attach.php4
-rw-r--r--Zotlabs/Module/Well_known.php5
-rw-r--r--Zotlabs/Module/Wfinger.php28
-rw-r--r--Zotlabs/Module/Z6trans.php161
-rw-r--r--Zotlabs/Module/Zfinger.php3
-rw-r--r--Zotlabs/Photo/PhotoGd.php18
-rw-r--r--Zotlabs/Photo/PhotoImagick.php30
-rw-r--r--Zotlabs/Storage/BasicAuth.php11
-rw-r--r--Zotlabs/Storage/Directory.php28
-rw-r--r--Zotlabs/Storage/File.php16
-rw-r--r--Zotlabs/Update/_1235.php25
-rw-r--r--Zotlabs/Update/_1236.php137
-rw-r--r--Zotlabs/Update/_1237.php25
-rw-r--r--Zotlabs/Update/_1238.php78
-rw-r--r--Zotlabs/Web/HTTPSig.php25
-rw-r--r--Zotlabs/Web/WebServer.php11
-rw-r--r--Zotlabs/Widget/Activity_filter.php44
-rw-r--r--Zotlabs/Widget/Notifications.php20
-rw-r--r--Zotlabs/Widget/Pinned.php280
-rw-r--r--Zotlabs/Zot6/Zot6Handler.php8
134 files changed, 5798 insertions, 1998 deletions
diff --git a/Zotlabs/Access/PermissionRoles.php b/Zotlabs/Access/PermissionRoles.php
index c8b4953a5..82df0c34b 100644
--- a/Zotlabs/Access/PermissionRoles.php
+++ b/Zotlabs/Access/PermissionRoles.php
@@ -100,6 +100,7 @@ class PermissionRoles {
'post_mail', 'post_like' , 'republish', 'chat'
];
$ret['limits'] = PermissionLimits::Std_Limits();
+ $ret['channel_type'] = 'group';
break;
@@ -113,6 +114,7 @@ class PermissionRoles {
'view_pages', 'view_wiki', 'post_wall', 'post_comments', 'tag_deliver',
'post_mail', 'post_like' , 'chat' ];
$ret['limits'] = PermissionLimits::Std_Limits();
+ $ret['channel_type'] = 'group';
break;
@@ -132,6 +134,7 @@ class PermissionRoles {
$ret['limits']['view_storage'] = PERMS_SPECIFIC;
$ret['limits']['view_pages'] = PERMS_SPECIFIC;
$ret['limits']['view_wiki'] = PERMS_SPECIFIC;
+ $ret['channel_type'] = 'group';
break;
@@ -187,6 +190,7 @@ class PermissionRoles {
'post_mail', 'post_like' , 'republish', 'chat', 'write_wiki'
];
$ret['limits'] = PermissionLimits::Std_Limits();
+ $ret['channel_type'] = 'group';
break;
diff --git a/Zotlabs/Access/Permissions.php b/Zotlabs/Access/Permissions.php
index 20dc22a72..35016ed57 100644
--- a/Zotlabs/Access/Permissions.php
+++ b/Zotlabs/Access/Permissions.php
@@ -283,4 +283,15 @@ class Permissions {
return ( [ 'perms' => $my_perms, 'automatic' => $automatic ] );
}
-} \ No newline at end of file
+ static public function serialise($p) {
+ $n = [];
+ if($p) {
+ foreach($p as $k => $v) {
+ if(intval($v)) {
+ $n[] = $k;
+ }
+ }
+ }
+ return implode(',',$n);
+ }
+}
diff --git a/Zotlabs/Daemon/Cron.php b/Zotlabs/Daemon/Cron.php
index 8fa31e6ce..703d6ce08 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,10 +38,14 @@ 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.
+ */
+ q("delete from chatpresence where cp_last < %s - INTERVAL %s and cp_client != 'auto' ",
+ db_utcnow(),
+ db_quoteinterval('3 MINUTE')
+ );
// expire any expired mail
@@ -138,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) ]
]
@@ -149,6 +155,11 @@ class Cron {
}
}
+
+ // check if any connections transitioned to zot6 and upgrade the connections to zot6 at this hub if so.
+ require_once('include/connections.php');
+ z6trans_connections();
+
require_once('include/attach.php');
attach_upgrade();
diff --git a/Zotlabs/Daemon/Cron_daily.php b/Zotlabs/Daemon/Cron_daily.php
index eebdb0229..07533cc6e 100644
--- a/Zotlabs/Daemon/Cron_daily.php
+++ b/Zotlabs/Daemon/Cron_daily.php
@@ -44,6 +44,12 @@ class Cron_daily {
db_utcnow(), db_quoteinterval('1 YEAR')
);
+ // expire anonymous sse notification entries once a day
+
+ q("delete from xconfig where xchan like '%s'",
+ dbesc('sse_id.%')
+ );
+
// Clean up emdedded content cache
q("DELETE FROM cache WHERE updated < %s - INTERVAL %s",
db_utcnow(),
@@ -90,6 +96,7 @@ class Cron_daily {
Master::Summon(array('Cli_suggest'));
remove_obsolete_hublocs();
+
z6_discover();
call_hooks('cron_daily',datetime_convert());
diff --git a/Zotlabs/Daemon/Directory.php b/Zotlabs/Daemon/Directory.php
index c8cdafdf5..c698995c2 100644
--- a/Zotlabs/Daemon/Directory.php
+++ b/Zotlabs/Daemon/Directory.php
@@ -2,10 +2,9 @@
namespace Zotlabs\Daemon;
-require_once('include/zot.php');
-require_once('include/dir_fns.php');
-require_once('include/queue_fn.php');
-
+use Zotlabs\Lib\Libzot;
+use Zotlabs\Lib\Libzotdir;
+use Zotlabs\Lib\Queue;
class Directory {
@@ -42,7 +41,7 @@ class Directory {
// this is an in-memory update and we don't need to send a network packet.
- local_dir_update($argv[1],$force);
+ Libzotdir::local_dir_update($argv[1],$force);
q("update channel set channel_dirdate = '%s' where channel_id = %d",
dbesc(datetime_convert()),
@@ -58,13 +57,15 @@ class Directory {
// otherwise send the changes upstream
- $directory = find_upstream_directory($dirmode);
+ $directory = Libzotdir::find_upstream_directory($dirmode);
$url = $directory['url'] . '/post';
// ensure the upstream directory is updated
- $packet = zot_build_packet($channel,(($force) ? 'force_refresh' : 'refresh'));
- $z = zot_zot($url,$packet);
+
+ $packet = Libzot::build_packet($channel,(($force) ? 'force_refresh' : 'refresh'));
+ $z = Libzot::zot($url,$packet,$channel);
+
// re-queue if unsuccessful
@@ -76,7 +77,7 @@ class Directory {
$hash = random_string();
- queue_insert(array(
+ Queue::insert(array(
'hash' => $hash,
'account_id' => $channel['channel_account_id'],
'channel_id' => $channel['channel_id'],
diff --git a/Zotlabs/Daemon/Expire.php b/Zotlabs/Daemon/Expire.php
index 398425861..a688d6f97 100644
--- a/Zotlabs/Daemon/Expire.php
+++ b/Zotlabs/Daemon/Expire.php
@@ -8,6 +8,15 @@ class Expire {
static public function run($argc,$argv){
cli_startup();
+
+ $pid = get_config('expire', 'procid', false);
+ if ($pid && (function_exists('posix_kill') ? posix_kill($pid, 0) : true)) {
+ logger('Expire: procedure already run with pid ' . $pid, LOGGER_DEBUG);
+ return;
+ }
+
+ $pid = getmypid();
+ set_config('expire', 'procid', $pid);
// perform final cleanup on previously delete items
@@ -32,7 +41,7 @@ class Expire {
if (intval(get_config('system', 'optimize_items')))
q("optimize table item");
- logger('expire: start', LOGGER_DEBUG);
+ logger('expire: start with pid ' . $pid, LOGGER_DEBUG);
$site_expire = intval(get_config('system', 'default_expire_days'));
$commented_days = intval(get_config('system','active_expire_days'));
@@ -90,5 +99,7 @@ class Expire {
logger('Expire: sys: done', LOGGER_DEBUG);
}
+
+ del_config('expire', 'procid');
}
}
diff --git a/Zotlabs/Daemon/Gprobe.php b/Zotlabs/Daemon/Gprobe.php
index f1ffb2d81..6951aa1d4 100644
--- a/Zotlabs/Daemon/Gprobe.php
+++ b/Zotlabs/Daemon/Gprobe.php
@@ -2,7 +2,9 @@
namespace Zotlabs\Daemon;
-require_once('include/zot.php');
+use Zotlabs\Lib\Libzot;
+use Zotlabs\Lib\Webfinger;
+use Zotlabs\Lib\Zotfinger;
// performs zot_finger on $argv[1], which is a hex_encoded webbie/reddress
@@ -22,12 +24,16 @@ class Gprobe {
);
if(! $r) {
- $j = \Zotlabs\Zot\Finger::run($url,null);
- if($j['success']) {
- $y = import_xchan($j);
+ $href = Webfinger::zot_url(punify($url));
+ if($href) {
+ $zf = Zotfinger::exec($href, null);
+ }
+ if(is_array($zf) && array_path_exists('signature/signer',$zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) {
+ $xc = Libzot::import_xchan($zf['data']);
}
}
return;
+
}
}
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/Notifier.php b/Zotlabs/Daemon/Notifier.php
index 1d0be10d9..8ea75af61 100644
--- a/Zotlabs/Daemon/Notifier.php
+++ b/Zotlabs/Daemon/Notifier.php
@@ -3,6 +3,7 @@
namespace Zotlabs\Daemon;
use Zotlabs\Lib\Libzot;
+use Zotlabs\Lib\Activity;
require_once('include/queue_fn.php');
require_once('include/html2plain.php');
@@ -44,18 +45,18 @@ require_once('include/bbcode.php');
*
* where COMMAND is one of the following:
*
- * activity (in diaspora.php, dfrn_confirm.php, profiles.php)
- * comment-import (in diaspora.php, items.php)
- * comment-new (in item.php)
- * drop (in diaspora.php, items.php, photos.php)
- * edit_post (in item.php)
- * event (in events.php)
- * expire (in items.php)
- * like (in like.php, poke.php)
- * mail (in message.php)
- * tag (in photos.php, poke.php, tagger.php)
- * tgroup (in items.php)
- * wall-new (in photos.php, item.php)
+ * activity (in diaspora.php, dfrn_confirm.php, profiles.php)
+ * comment-import (in diaspora.php, items.php)
+ * comment-new (in item.php)
+ * drop (in diaspora.php, items.php, photos.php)
+ * edit_post (in item.php)
+ * event (in events.php)
+ * expire (in items.php)
+ * like (in like.php, poke.php)
+ * mail (in message.php)
+ * tag (in photos.php, poke.php, tagger.php)
+ * tgroup (in items.php)
+ * wall-new (in photos.php, item.php)
*
* and ITEM_ID is the id of the item in the database that needs to be sent to others.
*
@@ -65,9 +66,10 @@ require_once('include/bbcode.php');
* permission_reject abook_id
* permission_update abook_id
* refresh_all channel_id
+ * purge channel_id xchan_hash
* purge_all channel_id
* expire channel_id
- * relay item_id (item was relayed to owner, we will deliver it as owner)
+ * relay item_id (item was relayed to owner, we will deliver it as owner)
* single_activity item_id (deliver to a singleton network from the appropriate clone)
* single_mail mail_id (deliver to a singleton network from the appropriate clone)
* location channel_id
@@ -239,25 +241,40 @@ class Notifier {
$packet_type = 'location';
$location = true;
}
+ elseif($cmd === 'purge') {
+ $xchan = $argv[3];
+ logger('notifier: purge: ' . $item_id . ' => ' . $xchan);
+ if (! $xchan) {
+ return;
+ }
+
+ $channel = channelx_by_n($item_id);
+ $recipients[] = $xchan;
+ $private = true;
+ $packet_type = 'purge';
+ $packet_recips[] = ['hash' => $xchan];
+ }
elseif($cmd === 'purge_all') {
+
logger('notifier: purge_all: ' . $item_id);
- $s = q("select * from channel where channel_id = %d limit 1",
- intval($item_id)
- );
- if($s)
- $channel = $s[0];
- $uid = $item_id;
- $recipients = array();
+ $channel = channelx_by_n($item_id);
+
+ $recipients = [];
$r = q("select abook_xchan from abook where abook_channel = %d and abook_self = 0",
intval($item_id)
);
- if($r) {
- foreach($r as $rr) {
- $recipients[] = $rr['abook_xchan'];
- }
+ if (! $r) {
+ return;
+ }
+ foreach ($r as $rr) {
+ $recipients[] = $rr['abook_xchan'];
+ $packet_recips[] = ['hash' => $rr['abook_xchan']];
}
+
$private = false;
$packet_type = 'purge';
+
+
}
else {
@@ -277,6 +294,12 @@ class Notifier {
$r = fetch_post_tags($r);
$target_item = $r[0];
+
+ if(in_array($target_item['author']['xchan_network'], ['rss', 'anon'])) {
+ logger('notifier: target item author is not a fetchable actor', LOGGER_DEBUG);
+ return;
+ }
+
$deleted_item = false;
if(intval($target_item['item_deleted'])) {
@@ -360,15 +383,24 @@ class Notifier {
$encoded_item = encode_item($target_item);
- // activitystreams version
- $m = get_iconfig($target_item,'activitystreams','signed_data');
+ // Re-use existing signature unless the activity type changed to a Tombstone, which won't verify.
+ $m = ((intval($target_item['item_deleted'])) ? '' : get_iconfig($target_item,'activitystreams','signed_data'));
+
if($m) {
$activity = json_decode($m,true);
}
else {
- $activity = \Zotlabs\Lib\Activity::encode_activity($target_item);
+ $activity = array_merge(['@context' => [
+ ACTIVITYSTREAMS_JSONLD_REV,
+ 'https://w3id.org/security/v1',
+ z_root() . ZOT_APSCHEMA_REV
+ ]], Activity::encode_activity($target_item)
+ );
}
+ logger('target_item: ' . print_r($target_item,true), LOGGER_DEBUG);
+ logger('encoded: ' . print_r($activity,true), LOGGER_DEBUG);
+
// Send comments to the owner to re-deliver to everybody in the conversation
// We only do this if the item in question originated on this site. This prevents looping.
// To clarify, a site accepting a new comment is responsible for sending it to the owner for relay.
@@ -467,7 +499,6 @@ class Notifier {
$details = q("select xchan_hash, xchan_network, xchan_addr, xchan_guid, xchan_guid_sig from xchan where xchan_hash in (" . protect_sprintf(implode(',',$recipients)) . ")");
-
$recip_list = array();
if($details) {
@@ -532,18 +563,40 @@ class Notifier {
// Now we have collected recipients (except for external mentions, FIXME)
// Let's reduce this to a set of hubs; checking that the site is not dead.
- $r = q("select hubloc.*, site.site_crypto, site.site_flags from hubloc left join site on site_url = hubloc_url where hubloc_hash in (" . protect_sprintf(implode(',',$recipients)) . ")
- and hubloc_error = 0 and hubloc_deleted = 0 and ( site_dead = 0 OR site_dead is null ) "
- );
+ $hubs = q("select hubloc.*, site.site_crypto, site.site_flags, site.site_version, site.site_project, site.site_dead from hubloc left join site on site_url = hubloc_url
+ where hubloc_hash in (" . protect_sprintf(implode(',',$recipients)) . ")
+ and hubloc_error = 0 and hubloc_deleted = 0"
+ );
+
+ // public posts won't make it to the local public stream unless there's a recipient on this site.
+ // This code block sees if it's a public post and localhost is missing, and if so adds an entry for the local sys channel to the $hubs list
+
+ if (! $private) {
+ $found_localhost = false;
+ if ($hubs) {
+ foreach ($hubs as $h) {
+ if ($h['hubloc_url'] === z_root()) {
+ $found_localhost = true;
+ break;
+ }
+ }
+ }
+ if (! $found_localhost) {
+ $localhub = q("select hubloc.*, site.site_crypto, site.site_flags, site.site_version, site.site_project, site.site_dead from hubloc
+ left join site on site_url = hubloc_url where hubloc_id_url = '%s' and hubloc_error = 0 and hubloc_deleted = 0",
+ dbesc(z_root() . '/channel/sys')
+ );
+ if ($localhub) {
+ $hubs = array_merge($hubs, $localhub);
+ }
+ }
+ }
-
- if(! $r) {
+ if(! $hubs) {
logger('notifier: no hubs', LOGGER_NORMAL, LOG_NOTICE);
return;
}
- $hubs = $r;
-
/**
* Reduce the hubs to those that are unique. For zot hubs, we need to verify uniqueness by the sitekey,
* since it may have been a re-install which has not yet been detected and pruned.
@@ -556,9 +609,15 @@ class Notifier {
$keys = []; // array of keys to check uniquness for zot hubs
$urls = []; // array of urls to check uniqueness of hubs from other networks
$hub_env = []; // per-hub envelope so we don't broadcast the entire envelope to all
+ $dead = []; // known dead hubs - report them as undeliverable
foreach($hubs as $hub) {
+ if (intval($hub['site_dead'])) {
+ $dead[] = $hub;
+ continue;
+ }
+
if($env_recips) {
foreach($env_recips as $er) {
if($hub['hubloc_hash'] === $er['hash']) {
@@ -630,7 +689,7 @@ class Notifier {
}
// singleton deliveries by definition 'not got zot'.
- // Single deliveries are other federated networks (plugins) and we're essentially
+ // Single deliveries are other federated networks (plugins) and we're essentially
// delivering only to those that have this site url in their abook_instance
// and only from within a sync operation. This means if you post from a clone,
// and a connection is connected to one of your other clones; assuming that hub
@@ -725,7 +784,24 @@ class Notifier {
$packet = zot_build_packet($channel,'notify',$env, (($private) ? $hub['hubloc_sitekey'] : null), $hub['site_crypto'],$hash);
}
- }
+ }
+
+
+ // remove this after most hubs have updated to version 5.0
+ if(stripos($hub['site_project'], 'hubzilla') !== false && version_compare($hub['site_version'], '4.7.3', '<=')) {
+ if($encoded_item['type'] === 'mail') {
+ $encoded_item['from']['network'] = 'zot';
+ $encoded_item['from']['guid_sig'] = str_replace('sha256.', '', $encoded_item['from']['guid_sig']);
+ }
+ else {
+ $encoded_item['owner']['network'] = 'zot';
+ $encoded_item['owner']['guid_sig'] = str_replace('sha256.', '', $encoded_item['owner']['guid_sig']);
+ if(strpos($encoded_item['author']['url'], z_root()) === 0) {
+ $encoded_item['author']['network'] = 'zot';
+ $encoded_item['author']['guid_sig'] = str_replace('sha256.', '', $encoded_item['author']['guid_sig']);
+ }
+ }
+ }
queue_insert(
[
@@ -768,6 +844,24 @@ class Notifier {
logger('notifier: basic loop complete.', LOGGER_DEBUG);
+ if ($dead) {
+ foreach ($dead as $deceased) {
+ if (is_array($target_item) && (! $target_item['item_deleted']) && (! get_config('system','disable_dreport'))) {
+ q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_name, dreport_result, dreport_time, dreport_xchan, dreport_queue )
+ values ( '%s', '%s','%s','%s','%s','%s','%s','%s' ) ",
+ dbesc($target_item['mid']),
+ dbesc($deceased['hubloc_host']),
+ dbesc($deceased['hubloc_host']),
+ dbesc($deceased['hubloc_host']),
+ dbesc('undeliverable/unresponsive site'),
+ dbesc(datetime_convert()),
+ dbesc($channel['channel_hash']),
+ dbesc(random_string(48))
+ );
+ }
+ }
+ }
+
call_hooks('notifier_end',$target_item);
logger('notifer: complete.');
diff --git a/Zotlabs/Daemon/Onepoll.php b/Zotlabs/Daemon/Onepoll.php
index 2f06ec125..93a5412b0 100644
--- a/Zotlabs/Daemon/Onepoll.php
+++ b/Zotlabs/Daemon/Onepoll.php
@@ -2,6 +2,8 @@
namespace Zotlabs\Daemon;
+use Zotlabs\Lib\Libzot;
+
require_once('include/zot.php');
require_once('include/socgraph.php');
@@ -76,7 +78,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/AccessList.php b/Zotlabs/Lib/AccessList.php
new file mode 100644
index 000000000..3c008f8c7
--- /dev/null
+++ b/Zotlabs/Lib/AccessList.php
@@ -0,0 +1,411 @@
+<?php
+
+namespace Zotlabs\Lib;
+
+use Zotlabs\Lib\Libsync;
+
+
+class AccessList {
+
+ static function add($uid,$name,$public = 0) {
+
+ $ret = false;
+ if ($uid && $name) {
+ $r = self::byname($uid,$name); // check for dups
+ if ($r !== false) {
+
+ // This could be a problem.
+ // Let's assume we've just created a list which we once deleted
+ // all the old members are gone, but the list remains so we don't break any security
+ // access lists. What we're doing here is reviving the dead list, but old content which
+ // was restricted to this list may now be seen by the new list members.
+
+ $z = q("SELECT * FROM pgrp WHERE id = %d LIMIT 1",
+ intval($r)
+ );
+ if(($z) && $z[0]['deleted']) {
+ q('UPDATE pgrp SET deleted = 0 WHERE id = %d', intval($z[0]['id']));
+ notice( t('A deleted list with this name was revived. Existing item permissions <strong>may</strong> apply to this list and any future members. If this is not what you intended, please create another list with a different name.') . EOL);
+ }
+ return true;
+ }
+
+ $hash = new_uuid();
+
+ $r = q("INSERT INTO pgrp ( hash, uid, visible, gname )
+ VALUES( '%s', %d, %d, '%s' ) ",
+ dbesc($hash),
+ intval($uid),
+ intval($public),
+ dbesc($name)
+ );
+ $ret = $r;
+ }
+
+ Libsync::build_sync_packet($uid,null,true);
+ return $ret;
+ }
+
+
+ static function remove($uid,$name) {
+ $ret = false;
+ if ($uid && $name) {
+ $r = q("SELECT id, hash FROM pgrp WHERE uid = %d AND gname = '%s' LIMIT 1",
+ intval($uid),
+ dbesc($name)
+ );
+ if ($r) {
+ $group_id = $r[0]['id'];
+ $group_hash = $r[0]['hash'];
+ }
+ else {
+ return false;
+ }
+
+ // remove group from default posting lists
+ $r = q("SELECT channel_default_group, channel_allow_gid, channel_deny_gid FROM channel WHERE channel_id = %d LIMIT 1",
+ intval($uid)
+ );
+ if ($r) {
+ $user_info = array_shift($r);
+ $change = false;
+
+ if ($user_info['channel_default_group'] == $group_hash) {
+ $user_info['channel_default_group'] = '';
+ $change = true;
+ }
+ if (strpos($user_info['channel_allow_gid'], '<' . $group_hash . '>') !== false) {
+ $user_info['channel_allow_gid'] = str_replace('<' . $group_hash . '>', '', $user_info['channel_allow_gid']);
+ $change = true;
+ }
+ if (strpos($user_info['channel_deny_gid'], '<' . $group_hash . '>') !== false) {
+ $user_info['channel_deny_gid'] = str_replace('<' . $group_hash . '>', '', $user_info['channel_deny_gid']);
+ $change = true;
+ }
+
+ if ($change) {
+ q("UPDATE channel SET channel_default_group = '%s', channel_allow_gid = '%s', channel_deny_gid = '%s'
+ WHERE channel_id = %d",
+ intval($user_info['channel_default_group']),
+ dbesc($user_info['channel_allow_gid']),
+ dbesc($user_info['channel_deny_gid']),
+ intval($uid)
+ );
+ }
+ }
+
+ // remove all members
+ $r = q("DELETE FROM pgrp_member WHERE uid = %d AND gid = %d ",
+ intval($uid),
+ intval($group_id)
+ );
+
+ // remove group
+ $r = q("UPDATE pgrp SET deleted = 1 WHERE uid = %d AND gname = '%s'",
+ intval($uid),
+ dbesc($name)
+ );
+
+ $ret = $r;
+
+ }
+
+ Libsync::build_sync_packet($uid,null,true);
+
+ return $ret;
+ }
+
+ // returns the integer id of an access group owned by $uid and named $name
+ // or false.
+
+ static function byname($uid,$name) {
+ if (! ($uid && $name)) {
+ return false;
+ }
+ $r = q("SELECT id FROM pgrp WHERE uid = %d AND gname = '%s' LIMIT 1",
+ intval($uid),
+ dbesc($name)
+ );
+ if ($r) {
+ return $r[0]['id'];
+ }
+ return false;
+ }
+
+ static function by_id($uid,$id) {
+ if (! ($uid && $id)) {
+ return false;
+ }
+
+ $r = q("SELECT * FROM pgrp WHERE uid = %d AND id = %d and deleted = 0",
+ intval($uid),
+ intval($id)
+ );
+ if ($r) {
+ return array_shift($r);
+ }
+ return false;
+ }
+
+
+
+ static function rec_byhash($uid,$hash) {
+ if (! ( $uid && $hash)) {
+ return false;
+ }
+ $r = q("SELECT * FROM pgrp WHERE uid = %d AND hash = '%s' LIMIT 1",
+ intval($uid),
+ dbesc($hash)
+ );
+ if ($r) {
+ return array_shift($r);
+ }
+ return false;
+ }
+
+
+ static function member_remove($uid,$name,$member) {
+ $gid = self::byname($uid,$name);
+ if (! $gid) {
+ return false;
+ }
+ if (! ($uid && $gid && $member)) {
+ return false;
+ }
+ $r = q("DELETE FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' ",
+ intval($uid),
+ intval($gid),
+ dbesc($member)
+ );
+
+ Libsync::build_sync_packet($uid,null,true);
+
+ return $r;
+ }
+
+
+ static function member_add($uid,$name,$member,$gid = 0) {
+ if (! $gid) {
+ $gid = self::byname($uid,$name);
+ }
+ if (! ($gid && $uid && $member)) {
+ return false;
+ }
+
+ $r = q("SELECT * FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' LIMIT 1",
+ intval($uid),
+ intval($gid),
+ dbesc($member)
+ );
+ if ($r) {
+ return true; // You might question this, but
+ // we indicate success because the group member was in fact created
+ // -- It was just created at another time
+ }
+ else {
+ $r = q("INSERT INTO pgrp_member (uid, gid, xchan)
+ VALUES( %d, %d, '%s' ) ",
+ intval($uid),
+ intval($gid),
+ dbesc($member)
+ );
+ }
+ Libsync::build_sync_packet($uid,null,true);
+ return $r;
+ }
+
+
+ static function members($uid, $gid) {
+ $ret = [];
+ if (intval($gid)) {
+ $r = q("SELECT * FROM pgrp_member
+ LEFT JOIN abook ON abook_xchan = pgrp_member.xchan left join xchan on xchan_hash = abook_xchan
+ WHERE gid = %d AND abook_channel = %d and pgrp_member.uid = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 ORDER BY xchan_name ASC ",
+ intval($gid),
+ intval($uid),
+ intval($uid)
+ );
+ if ($r) {
+ $ret = $r;
+ }
+ }
+ return $ret;
+ }
+
+ static function members_xchan($uid,$gid) {
+ $ret = [];
+ if (intval($gid)) {
+ $r = q("SELECT xchan FROM pgrp_member WHERE gid = %d AND uid = %d",
+ intval($gid),
+ intval($uid)
+ );
+ if ($r) {
+ foreach ($r as $rv) {
+ $ret[] = $rv['xchan'];
+ }
+ }
+ }
+ return $ret;
+ }
+
+ static function members_profile_xchan($uid,$gid) {
+ $ret = [];
+ if (intval($gid)) {
+ $r = q("SELECT abook_xchan as xchan from abook left join profile on abook_profile = profile_guid where profile.id = %d and profile.uid = %d",
+ intval($gid),
+ intval($uid)
+ );
+ if ($r) {
+ foreach($r as $rv) {
+ $ret[] = $rv['xchan'];
+ }
+ }
+ }
+ return $ret;
+ }
+
+
+
+
+ static function select($uid,$group = '') {
+
+ $grps = [];
+
+ $r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
+ intval($uid)
+ );
+ $grps[] = [ 'name' => '', 'hash' => '0', 'selected' => '' ];
+ if ($r) {
+ foreach ($r as $rr) {
+ $grps[] = [ 'name' => $rr['gname'], 'id' => $rr['hash'], 'selected' => (($group == $rr['hash']) ? 'true' : '') ];
+ }
+
+ }
+
+ return replace_macros(get_markup_template('group_selection.tpl'), [
+ '$label' => t('Add new connections to this access list'),
+ '$groups' => $grps
+ ]);
+ }
+
+
+ static function widget($every="connections",$each="lists",$edit = false, $group_id = 0, $cid = '',$mode = 1) {
+
+ $o = '';
+
+ $groups = [];
+
+ $r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
+ intval($_SESSION['uid'])
+ );
+ $member_of = [];
+ if ($cid) {
+ $member_of = self::containing(local_channel(),$cid);
+ }
+
+ if ($r) {
+ foreach ($r as $rr) {
+ $selected = (($group_id == $rr['id']) ? ' group-selected' : '');
+
+ if ($edit) {
+ $groupedit = [ 'href' => "lists/".$rr['id'], 'title' => t('edit') ];
+ }
+ else {
+ $groupedit = null;
+ }
+
+ $groups[] = [
+ 'id' => $rr['id'],
+ 'enc_cid' => base64url_encode($cid),
+ 'cid' => $cid,
+ 'text' => $rr['gname'],
+ 'selected' => $selected,
+ 'href' => (($mode == 0) ? $each.'?f=&gid='.$rr['id'] : $each."/".$rr['id']) . ((x($_GET,'new')) ? '&new=' . $_GET['new'] : '') . ((x($_GET,'order')) ? '&order=' . $_GET['order'] : ''),
+ 'edit' => $groupedit,
+ 'ismember' => in_array($rr['id'],$member_of),
+ ];
+ }
+ }
+
+ return replace_macros(get_markup_template('group_side.tpl'), [
+ '$title' => t('Lists'),
+ '$edittext' => t('Edit list'),
+ '$createtext' => t('Create new list'),
+ '$ungrouped' => (($every === 'contacts') ? t('Channels not in any access list') : ''),
+ '$groups' => $groups,
+ '$add' => t('add'),
+ ]);
+
+ }
+
+
+ static function expand($g) {
+ if (! (is_array($g) && count($g))) {
+ return [];
+ }
+
+ $ret = [];
+ $x = [];
+
+ // private profile linked virtual groups
+
+ foreach ($g as $gv) {
+ if (substr($gv,0,3) === 'vp.') {
+ $profile_hash = substr($gv,3);
+ if ($profile_hash) {
+ $r = q("select abook_xchan from abook where abook_profile = '%s'",
+ dbesc($profile_hash)
+ );
+ if ($r) {
+ foreach ($r as $rv) {
+ $ret[] = $rv['abook_xchan'];
+ }
+ }
+ }
+ }
+ else {
+ $x[] = $gv;
+ }
+ }
+
+ if ($x) {
+ stringify_array_elms($x,true);
+ $groups = implode(',', $x);
+ if ($groups) {
+ $r = q("SELECT xchan FROM pgrp_member WHERE gid IN ( select id from pgrp where hash in ( $groups ))");
+ if ($r) {
+ foreach ($r as $rv) {
+ $ret[] = $rv['xchan'];
+ }
+ }
+ }
+ }
+ return $ret;
+ }
+
+
+ static function member_of($c) {
+ $r = q("SELECT pgrp.gname, pgrp.id FROM pgrp LEFT JOIN pgrp_member ON pgrp_member.gid = pgrp.id
+ WHERE pgrp_member.xchan = '%s' AND pgrp.deleted = 0 ORDER BY pgrp.gname ASC ",
+ dbesc($c)
+ );
+
+ return $r;
+ }
+
+ static function containing($uid,$c) {
+
+ $r = q("SELECT gid FROM pgrp_member WHERE uid = %d AND pgrp_member.xchan = '%s' ",
+ intval($uid),
+ dbesc($c)
+ );
+
+ $ret = [];
+ if ($r) {
+ foreach ($r as $rv)
+ $ret[] = $rv['gid'];
+ }
+
+ return $ret;
+ }
+} \ No newline at end of file
diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php
index 08a8b8d03..e7fa6352a 100644
--- a/Zotlabs/Lib/Activity.php
+++ b/Zotlabs/Lib/Activity.php
@@ -168,13 +168,16 @@ class Activity {
if($r) {
xchan_query($r,true);
$r = fetch_post_tags($r,true);
+ if (in_array($r[0]['verb'], ['Create', 'Invite']) && $r[0]['obj_type'] === ACTIVITY_OBJ_EVENT) {
+ $r[0]['verb'] = 'Invite';
+ return self::encode_activity($r[0]);
+ }
return self::encode_item($r[0]);
}
}
static function fetch_image($x) {
-
$ret = [
'type' => 'Image',
'id' => $x['id'],
@@ -220,7 +223,7 @@ class Activity {
'startTime' => (($ev['adjust']) ? datetime_convert($ev['timezone'],'UTC',$ev['dtstart'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtstart'],'Y-m-d\\TH:i:s-00:00')),
'content' => bbcode($ev['description'], [ 'cache' => true ]),
'location' => [ 'type' => 'Place', 'content' => bbcode($ev['location'], [ 'cache' => true ]) ],
- 'source' => [ 'content' => format_event_bbcode($ev), 'mediaType' => 'text/bbcode' ],
+ 'source' => [ 'content' => format_event_bbcode($ev,true), 'mediaType' => 'text/bbcode' ],
'actor' => $actor,
];
if(! $ev['nofinish']) {
@@ -311,17 +314,51 @@ class Activity {
else {
$objtype = self::activity_obj_mapper($i['obj_type']);
}
-
- if(intval($i['item_deleted'])) {
+
+ if ($i['obj']) {
+ $ret = Activity::encode_object($i['obj']);
+ }
+
+ if (intval($i['item_deleted'])) {
$ret['type'] = 'Tombstone';
$ret['formerType'] = $objtype;
- $ret['id'] = ((strpos($i['mid'],'http') === 0) ? $i['mid'] : z_root() . '/item/' . urlencode($i['mid']));
+ $ret['id'] = $i['mid'];
+ if($i['id'] != $i['parent'])
+ $ret['inReplyTo'] = $i['thr_parent'];
+
+ $ret['to'] = [ ACTIVITY_PUBLIC_INBOX ];
return $ret;
}
+ if ($i['obj']) {
+ if (is_array($i['obj'])) {
+ $ret = $i['obj'];
+ }
+ else {
+ $ret = json_decode($i['obj'],true);
+ }
+ }
+
$ret['type'] = $objtype;
+ if ($objtype === 'Question') {
+ if ($i['obj']) {
+ if (is_array($i['obj'])) {
+ $ret = $i['obj'];
+ }
+ else {
+ $ret = json_decode($i['obj'],true);
+ }
+
+ if(array_path_exists('actor/id',$ret)) {
+ $ret['actor'] = $ret['actor']['id'];
+ }
+ }
+ }
+
+
$ret['id'] = ((strpos($i['mid'],'http') === 0) ? $i['mid'] : z_root() . '/item/' . urlencode($i['mid']));
+ $ret['diaspora:guid'] = $i['uuid'];
if($i['title'])
$ret['name'] = $i['title'];
@@ -394,7 +431,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) {
@@ -484,10 +585,47 @@ class Activity {
}
}
}
+ if ($item['iconfig']) {
+ foreach ($item['iconfig'] as $att) {
+ if ($att['sharing']) {
+ $value = ((is_string($att['v']) && preg_match('|^a:[0-9]+:{.*}$|s', $att['v'])) ? unserialize($att['v']) : $att['v']);
+ $ret[] = [ 'type' => 'PropertyValue', 'name' => 'zot.' . $att['cat'] . '.' . $att['k'], 'value' => $value ];
+ }
+ }
+ }
return $ret;
}
+ static function decode_iconfig($item) {
+
+ $ret = [];
+
+ if (is_array($item['attachment']) && $item['attachment']) {
+ $ptr = $item['attachment'];
+ if (! array_key_exists(0,$ptr)) {
+ $ptr = [ $ptr ];
+ }
+ foreach ($ptr as $att) {
+ $entry = [];
+ if ($att['type'] === 'PropertyValue') {
+ if (array_key_exists('name',$att) && $att['name']) {
+ $key = explode('.',$att['name']);
+ if (count($key) === 3 && $key[0] === 'zot') {
+ $entry['cat'] = $key[1];
+ $entry['k'] = $key[2];
+ $entry['v'] = $att['value'];
+ $entry['sharing'] = '1';
+ $ret[] = $entry;
+ }
+ }
+ }
+ }
+ }
+ return $ret;
+ }
+
+
static function decode_attachment($item) {
@@ -514,7 +652,7 @@ class Activity {
- static function encode_activity($i) {
+ static function encode_activity($i, $recurse = false) {
$ret = [];
$reply = false;
@@ -525,20 +663,46 @@ class Activity {
$ret['obj'] = [];
}
- if(intval($i['item_deleted'])) {
- $ret['type'] = 'Tombstone';
- $ret['formerType'] = self::activity_obj_mapper($i['obj_type']);
- $ret['id'] = ((strpos($i['mid'],'http') === 0) ? $i['mid'] : z_root() . '/item/' . urlencode($i['mid']));
+ $ret['type'] = self::activity_mapper($i['verb']);
+ $fragment = '';
+
+ if (intval($i['item_deleted']) && !$recurse) {
+ $is_response = false;
+
+ if (ActivityStreams::is_response_activity($ret['type'])) {
+ $ret['type'] = 'Undo';
+ $fragment = 'undo';
+ $is_response = true;
+ }
+ else {
+ $ret['type'] = 'Delete';
+ $fragment = 'delete';
+ }
+
+ $ret['id'] = str_replace('/item/','/activity/',$i['mid']) . '#' . $fragment;
$actor = self::encode_person($i['author'],false);
- if($actor)
+ if ($actor)
$ret['actor'] = $actor;
else
return [];
- return $ret;
- }
+ $obj = (($is_response) ? self::encode_activity($i,true) : self::encode_item($i,true));
+ if ($obj) {
+ if (array_path_exists('object/id',$obj)) {
+ $obj['object'] = $obj['object']['id'];
+ }
+ unset($obj['cc']);
+ $obj['to'] = [ ACTIVITY_PUBLIC_INBOX ];
+ $ret['object'] = $obj;
+ }
+ else
+ return [];
+
+ $ret['to'] = [ ACTIVITY_PUBLIC_INBOX ];
- $ret['type'] = self::activity_mapper($i['verb']);
+ return $ret;
+
+ }
if($ret['type'] === 'emojiReaction') {
// There may not be an object for these items for legacy reasons - it should be the conversation parent.
@@ -572,8 +736,17 @@ class Activity {
}
}
+ if (strpos($i['mid'],z_root() . '/item/') !== false) {
+ $ret['id'] = str_replace('/item/','/activity/',$i['mid']);
+ }
+ elseif (strpos($i['mid'],z_root() . '/event/') !== false) {
+ $ret['id'] = str_replace('/event/','/activity/',$i['mid']);
+ }
+ else {
+ $ret['id'] = ((strpos($i['mid'],'http') === 0) ? $i['mid'] : z_root() . '/activity/' . urlencode($i['mid']));
+ }
- $ret['id'] = ((strpos($i['mid'],'http') === 0) ? $i['mid'] : z_root() . '/activity/' . urlencode($i['mid']));
+ $ret['diaspora:guid'] = $i['uuid'];
if($i['title'])
$ret['name'] = html2plain(bbcode($i['title'], [ 'cache' => true ]));
@@ -611,10 +784,10 @@ class Activity {
if($i['id'] != $i['parent']) {
$reply = true;
- // inReplyTo needs to be set in the activity for followup actiions (Like, Dislike, Attend, Announce, etc.),
- // but *not* for comments, where it should only be present in the object
-
- if (! in_array($ret['type'],[ 'Create','Update' ])) {
+ // inReplyTo needs to be set in the activity for followup actions (Like, Dislike, Announce, etc.),
+ // but *not* for comments and RSVPs, where it should only be present in the object
+
+ if (! in_array($ret['type'],[ 'Create','Update','Accept','Reject','TentativeAccept','TentativeReject' ])) {
$ret['inReplyTo'] = ((strpos($i['thr_parent'],'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent']));
}
@@ -672,6 +845,9 @@ class Activity {
return [];
}
+ if(array_path_exists('object/type',$ret) && $ret['object']['type'] === 'Event' && $ret['type'] === 'Create') {
+ $ret['type'] = 'Invite';
+ }
if($i['target']) {
if(! is_array($i['target'])) {
@@ -684,57 +860,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) {
+ // Returns an array of all recipients targeted by private item array $i.
- $private = false;
- $list = [];
- $x = collect_recipients($i,$private);
- if($x) {
- stringify_array_elms($x);
- if(! $x)
- return;
-
- $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) {
@@ -744,6 +1018,7 @@ class Activity {
if(! $extended) {
return $p['xchan_url'];
}
+
$ret = [];
$c = ((array_key_exists('channel_id',$p)) ? $p : channelx_by_hash($p['xchan_hash']));
@@ -789,10 +1064,16 @@ class Activity {
]
];
+ $ret['publicKey'] = [
+ 'id' => $p['xchan_url'],
+ 'owner' => $p['xchan_url'],
+ 'publicKeyPem' => $p['xchan_pubkey']
+ ];
+
$arr = [ 'xchan' => $p, 'encoded' => $ret ];
call_hooks('encode_person', $arr);
- $ret = $arr['encoded'];
+ $ret = $arr['encoded'];
return $ret;
}
@@ -822,7 +1103,10 @@ class Activity {
'http://activitystrea.ms/schema/1.0/unfollow' => 'Unfollow',
'http://purl.org/zot/activity/attendyes' => 'Accept',
'http://purl.org/zot/activity/attendno' => 'Reject',
- 'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept'
+ 'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept',
+ 'Invite' => 'Invite',
+ 'Delete' => 'Delete',
+ 'Undo' => 'Undo'
];
call_hooks('activity_mapper',$acts);
@@ -868,7 +1152,10 @@ class Activity {
'http://activitystrea.ms/schema/1.0/unfollow' => 'Unfollow',
'http://purl.org/zot/activity/attendyes' => 'Accept',
'http://purl.org/zot/activity/attendno' => 'Reject',
- 'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept'
+ 'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept',
+ 'Invite' => 'Invite',
+ 'Delete' => 'Delete',
+ 'Undo' => 'Undo'
];
call_hooks('activity_decode_mapper',$acts);
@@ -895,14 +1182,19 @@ 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',
'http://purl.org/zot/activity/thing' => 'Object',
'http://purl.org/zot/activity/file' => 'zot:File',
'http://purl.org/zot/activity/mood' => 'zot:Mood',
-
+ 'Invite' => 'Invite',
+ 'Question' => 'Question',
+ 'Document' => 'Document',
+ 'Audio' => 'Audio',
+ 'Video' => 'Video',
+ 'Delete' => 'Delete',
+ 'Undo' => 'Undo'
];
call_hooks('activity_obj_decode_mapper',$objs);
@@ -922,10 +1214,6 @@ class Activity {
static function activity_obj_mapper($obj) {
- if(strpos($obj,'/') === false) {
- return $obj;
- }
-
$objs = [
'http://activitystrea.ms/schema/1.0/note' => 'Note',
'http://activitystrea.ms/schema/1.0/comment' => 'Note',
@@ -934,18 +1222,31 @@ 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',
'http://purl.org/zot/activity/thing' => 'Object',
'http://purl.org/zot/activity/file' => 'zot:File',
'http://purl.org/zot/activity/mood' => 'zot:Mood',
-
+ 'Invite' => 'Invite',
+ 'Question' => 'Question',
+ 'Audio' => 'Audio',
+ 'Video' => 'Video',
+ 'Delete' => 'Delete',
+ 'Undo' => 'Undo'
];
call_hooks('activity_obj_mapper',$objs);
+ if ($obj === 'Answer') {
+ return 'Note';
+ }
+
+ if (strpos($obj,'/') === false) {
+ return $obj;
+ }
+
+
if(array_key_exists($obj,$objs)) {
return $objs[$obj];
}
@@ -1208,11 +1509,35 @@ class Activity {
$icon = $person_obj['icon'];
}
- if(is_array($person_obj['url']) && array_key_exists('href', $person_obj['url']))
- $profile = $person_obj['url']['href'];
- else
- $profile = $url;
+ $links = false;
+ $profile = false;
+
+ if (is_array($person_obj['url'])) {
+ if (! array_key_exists(0,$person_obj['url'])) {
+ $links = [ $person_obj['url'] ];
+ }
+ else {
+ $links = $person_obj['url'];
+ }
+ }
+
+ if ($links) {
+ foreach ($links as $link) {
+ if (array_key_exists('mediaType',$link) && $link['mediaType'] === 'text/html') {
+ $profile = $link['href'];
+ }
+ }
+ if (! $profile) {
+ $profile = $links[0]['href'];
+ }
+ }
+ elseif (isset($person_obj['url']) && is_string($person_obj['url'])) {
+ $profile = $person_obj['url'];
+ }
+ if (! $profile) {
+ $profile = $url;
+ }
$inbox = $person_obj['inbox'];
@@ -1244,6 +1569,7 @@ class Activity {
);
if(! $r) {
// create a new record
+
$r = xchan_store_lowlevel(
[
'xchan_hash' => $url,
@@ -1302,7 +1628,8 @@ class Activity {
'hubloc_host' => $hostname,
'hubloc_callback' => $inbox,
'hubloc_updated' => datetime_convert(),
- 'hubloc_primary' => 1
+ 'hubloc_primary' => 1,
+ 'hubloc_id_url' => $profile
]
);
}
@@ -1352,7 +1679,7 @@ class Activity {
// sort function width decreasing
- static function as_vid_sort($a,$b) {
+ static function vid_sort($a,$b) {
if($a['width'] === $b['width'])
return 0;
return (($a['width'] > $b['width']) ? -1 : 1);
@@ -1416,7 +1743,25 @@ class Activity {
$s['aid'] = $channel['channel_account_id'];
$s['uid'] = $channel['channel_id'];
+
+ // Make sure we use the zot6 identity where applicable
+
+ $s['author_xchan'] = self::find_best_identity($s['author_xchan']);
+ $s['owner_xchan'] = self::find_best_identity($s['owner_xchan']);
+
+ if(!$s['author_xchan']) {
+ logger('No author: ' . print_r($act, true));
+ }
+
+ if(!$s['owner_xchan']) {
+ logger('No owner: ' . print_r($act, true));
+ }
+
+ if(!$s['author_xchan'] || !$s['owner_xchan'])
+ return;
+
$s['mid'] = urldecode($act->obj['id']);
+ $s['uuid'] = $act->obj['diaspora:guid'];
$s['plink'] = urldecode($act->obj['id']);
@@ -1522,7 +1867,7 @@ class Activity {
}
}
if($mps) {
- usort($mps,'as_vid_sort');
+ usort($mps,[ __CLASS__, 'vid_sort' ]);
foreach($mps as $m) {
if(intval($m['width']) < 500) {
$s['body'] .= "\n\n" . '[video]' . $m['href'] . '[/video]';
@@ -1596,6 +1941,101 @@ class Activity {
}
+
+ static function update_poll($item,$post) {
+ $multi = false;
+ $mid = $post['mid'];
+ $content = $post['title'];
+
+ if (! $item) {
+ return false;
+ }
+
+ $o = json_decode($item['obj'],true);
+ if ($o && array_key_exists('anyOf',$o)) {
+ $multi = true;
+ }
+
+ $r = q("select mid, title from item where parent_mid = '%s' and author_xchan = '%s'",
+ dbesc($item['mid']),
+ dbesc($post['author_xchan'])
+ );
+
+ // prevent any duplicate votes by same author for oneOf and duplicate votes with same author and same answer for anyOf
+
+ if ($r) {
+ if ($multi) {
+ foreach ($r as $rv) {
+ if ($rv['title'] === $content && $rv['mid'] !== $mid) {
+ return false;
+ }
+ }
+ }
+ else {
+ foreach ($r as $rv) {
+ if ($rv['mid'] !== $mid) {
+ return false;
+ }
+ }
+ }
+ }
+
+ $answer_found = false;
+ $found = false;
+ if ($multi) {
+ for ($c = 0; $c < count($o['anyOf']); $c ++) {
+ if ($o['anyOf'][$c]['name'] === $content) {
+ $answer_found = true;
+ if (is_array($o['anyOf'][$c]['replies'])) {
+ foreach($o['anyOf'][$c]['replies'] as $reply) {
+ if(is_array($reply) && array_key_exists('id',$reply) && $reply['id'] === $mid) {
+ $found = true;
+ }
+ }
+ }
+
+ if (! $found) {
+ $o['anyOf'][$c]['replies']['totalItems'] ++;
+ $o['anyOf'][$c]['replies']['items'][] = [ 'id' => $mid, 'type' => 'Note' ];
+ }
+ }
+ }
+ }
+ else {
+ for ($c = 0; $c < count($o['oneOf']); $c ++) {
+ if ($o['oneOf'][$c]['name'] === $content) {
+ $answer_found = true;
+ if (is_array($o['oneOf'][$c]['replies'])) {
+ foreach($o['oneOf'][$c]['replies'] as $reply) {
+ if(is_array($reply) && array_key_exists('id',$reply) && $reply['id'] === $mid) {
+ $found = true;
+ }
+ }
+ }
+
+ if (! $found) {
+ $o['oneOf'][$c]['replies']['totalItems'] ++;
+ $o['oneOf'][$c]['replies']['items'][] = [ 'id' => $mid, 'type' => 'Note' ];
+ }
+ }
+ }
+ }
+ logger('updated_poll: ' . print_r($o,true),LOGGER_DATA);
+ if ($answer_found && ! $found) {
+ $x = q("update item set obj = '%s', edited = '%s' where id = %d",
+ dbesc(json_encode($o)),
+ dbesc(datetime_convert()),
+ intval($item['id'])
+ );
+ Master::Summon( [ 'Notifier', 'wall-new', $item['id'] ] );
+ return true;
+ }
+
+ return false;
+ }
+
+
+
static function decode_note($act) {
$response_activity = false;
@@ -1613,6 +2053,7 @@ class Activity {
self::actor_store($act->actor['id'],$act->actor);
$s['mid'] = $act->obj['id'];
+ $s['uuid'] = $act->obj['diaspora:guid'];
$s['parent_mid'] = $act->parent_id;
if($act->data['published']) {
@@ -1634,13 +2075,13 @@ class Activity {
$s['expires'] = datetime_convert('UTC','UTC',$act->obj['expires']);
}
-
- if(in_array($act->type, [ 'Like', 'Dislike', 'Flag', 'Block', 'Announce', 'Accept', 'Reject', 'TentativeAccept', 'emojiReaction' ])) {
+ if(ActivityStreams::is_response_activity($act->type)) {
$response_activity = true;
$s['mid'] = $act->id;
- $s['parent_mid'] = $act->obj['id'];
+ // $s['parent_mid'] = $act->obj['id'];
+ $s['uuid'] = $act->data['diaspora:guid'];
// over-ride the object timestamp with the activity
@@ -1664,15 +2105,23 @@ class Activity {
if($act->type === 'Dislike') {
$content['content'] = sprintf( t('Doesn\'t like %1$s\'s %2$s'),$mention,$act->obj['type']) . "\n\n" . $content['content'];
}
- if($act->type === 'Accept' && $act->obj['type'] === 'Event' ) {
- $content['content'] = sprintf( t('Will attend %1$s\'s %2$s'),$mention,$act->obj['type']) . "\n\n" . $content['content'];
- }
- if($act->type === 'Reject' && $act->obj['type'] === 'Event' ) {
- $content['content'] = sprintf( t('Will not attend %1$s\'s %2$s'),$mention,$act->obj['type']) . "\n\n" . $content['content'];
- }
- if($act->type === 'TentativeAccept' && $act->obj['type'] === 'Event' ) {
- $content['content'] = sprintf( t('May attend %1$s\'s %2$s'),$mention,$act->obj['type']) . "\n\n" . $content['content'];
+
+ // handle event RSVPs
+ if (($act->obj['type'] === 'Event') || ($act->obj['type'] === 'Invite' && array_path_exists('object/type',$act->obj) && $act->obj['object']['type'] === 'Event')) {
+ if ($act->type === 'Accept') {
+ $content['content'] = sprintf( t('Will attend %s\'s event'),$mention) . EOL . EOL . $content['content'];
+ }
+ if ($act->type === 'Reject') {
+ $content['content'] = sprintf( t('Will not attend %s\'s event'),$mention) . EOL . EOL . $content['content'];
+ }
+ if ($act->type === 'TentativeAccept') {
+ $content['content'] = sprintf( t('May attend %s\'s event'),$mention) . EOL . EOL . $content['content'];
+ }
+ if ($act->type === 'TentativeReject') {
+ $content['content'] = sprintf( t('May not attend %s\'s event'),$mention) . EOL . EOL . $content['content'];
+ }
}
+
if($act->type === 'Announce') {
$content['content'] = sprintf( t('&#x1f501; Repeated %1$s\'s %2$s'), $mention, $act->obj['type']);
}
@@ -1693,8 +2142,12 @@ class Activity {
$s['verb'] = self::activity_decode_mapper($act->type);
+ // Mastodon does not provide update timestamps when updating poll tallies which means race conditions may occur here.
+ if ($act->type === 'Update' && $act->obj['type'] === 'Question' && $s['edited'] === $s['created']) {
+ $s['edited'] = datetime_convert();
+ }
- if($act->type === 'Tombstone' || $act->type === 'Delete' || ($act->type === 'Create' && $act->obj['type'] === 'Tombstone')) {
+ if(in_array($act->type, [ 'Delete', 'Undo', 'Tombstone' ]) || ($act->type === 'Create' && $act->obj['type'] === 'Tombstone')) {
$s['item_deleted'] = 1;
}
@@ -1703,28 +2156,42 @@ class Activity {
$s['obj_type'] = ACTIVITY_OBJ_COMMENT;
}
+ $eventptr = null;
+
+ if ($act->obj['type'] === 'Invite' && array_path_exists('object/type',$act->obj) && $act->obj['object']['type'] === 'Event') {
+ $eventptr = $act->obj['object'];
+ $s['mid'] = $s['parent_mid'] = $act->obj['id'];
+ }
+
if($act->obj['type'] === 'Event') {
+ if ($act->type === 'Invite') {
+ $s['mid'] = $s['parent_mid'] = $act->id;
+ }
+ $eventptr = $act->obj;
+ }
+
+ if ($eventptr) {
$s['obj'] = [];
- $s['obj']['asld'] = $act->obj;
+ $s['obj']['asld'] = $eventptr;
$s['obj']['type'] = ACTIVITY_OBJ_EVENT;
- $s['obj']['id'] = $act->obj['id'];
- $s['obj']['title'] = $act->obj['name'];
+ $s['obj']['id'] = $eventptr['id'];
+ $s['obj']['title'] = $eventptr['name'];
if(strpos($act->obj['startTime'],'Z'))
$s['obj']['adjust'] = true;
else
$s['obj']['adjust'] = false;
- $s['obj']['dtstart'] = datetime_convert('UTC','UTC',$act->obj['startTime']);
+ $s['obj']['dtstart'] = datetime_convert('UTC','UTC',$eventptr['startTime']);
if($act->obj['endTime'])
- $s['obj']['dtend'] = datetime_convert('UTC','UTC',$act->obj['endTime']);
+ $s['obj']['dtend'] = datetime_convert('UTC','UTC',$eventptr['endTime']);
else
$s['obj']['nofinish'] = true;
- $s['obj']['description'] = $act->obj['content'];
+ $s['obj']['description'] = $eventptr['content'];
- if(array_path_exists('location/content',$act->obj))
- $s['obj']['location'] = $act->obj['location']['content'];
+ if(array_path_exists('location/content',$eventptr))
+ $s['obj']['location'] = $eventptr['location']['content'];
}
else {
@@ -1755,16 +2222,33 @@ class Activity {
}
}
- $a = self::decode_attachment($act->obj);
- if($a) {
- $s['attach'] = $a;
- }
+ }
+
+ $a = self::decode_attachment($act->obj);
+ if ($a) {
+ $s['attach'] = $a;
+ }
+
+ $a = self::decode_iconfig($act->obj);
+ if ($a) {
+ $s['iconfig'] = $a;
}
if($act->obj['type'] === 'Note' && $s['attach']) {
$s['body'] .= self::bb_attach($s['attach'],$s['body']);
}
+ if ($act->obj['type'] === 'Question' && in_array($act->type,['Create','Update'])) {
+ if ($act->obj['endTime']) {
+ $s['comments_closed'] = datetime_convert('UTC','UTC', $act->obj['endTime']);
+ }
+ }
+
+ if ($act->obj['closed']) {
+ $s['comments_closed'] = datetime_convert('UTC','UTC', $act->obj['closed']);
+ }
+
+
// we will need a hook here to extract magnet links e.g. peertube
// right now just link to the largest mp4 we find that will fit in our
@@ -1857,9 +2341,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;
@@ -1873,10 +2355,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) {
@@ -1957,8 +2440,19 @@ 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'])) {
+ $s['item_private'] = 2;
+ }
+ }
set_iconfig($s,'activitypub','recips',$act->raw_recips);
@@ -2006,17 +2500,23 @@ class Activity {
$item['aid'] = $channel['channel_account_id'];
$item['uid'] = $channel['channel_id'];
- $s['uuid'] = '';
- // Friendica sends the diaspora guid in a nonstandard field via AP
- if($act->obj['diaspora:guid'])
- $s['uuid'] = $act->obj['diaspora:guid'];
+ // Make sure we use the zot6 identity where applicable
- if(! ( $item['author_xchan'] && $item['owner_xchan'])) {
- logger('owner or author missing.');
- return;
+ $item['author_xchan'] = self::find_best_identity($item['author_xchan']);
+ $item['owner_xchan'] = self::find_best_identity($item['owner_xchan']);
+
+ if(!$item['author_xchan']) {
+ logger('No author: ' . print_r($act, true));
+ }
+
+ if(!$item['owner_xchan']) {
+ logger('No owner: ' . print_r($act, true));
}
+ if(!$item['author_xchan'] || !$item['owner_xchan'])
+ return;
+
if($channel['channel_system']) {
if(! MessageFilter::evaluate($item,get_config('system','pubstream_incl'),get_config('system','pubstream_excl'))) {
logger('post is filtered');
@@ -2048,7 +2548,7 @@ class Activity {
set_iconfig($item,'activitypub','recips',$act->raw_recips);
if(! $is_parent) {
- $p = q("select parent_mid from item where mid = '%s' and uid = %d limit 1",
+ $p = q("select parent_mid, id, obj_type from item where mid = '%s' and uid = %d limit 1",
dbesc($item['parent_mid']),
intval($item['uid'])
);
@@ -2078,6 +2578,15 @@ class Activity {
// $s['thr_parent'] = $s['mid'];
}
}
+
+
+ if ($p[0]['obj_type'] === 'Question') {
+ if ($item['obj_type'] === ACTIVITY_OBJ_NOTE && $item['title'] && (! $item['content'])) {
+ $item['obj_type'] = 'Answer';
+ }
+ }
+
+
if($p[0]['parent_mid'] !== $item['parent_mid']) {
$item['thr_parent'] = $item['parent_mid'];
}
@@ -2156,8 +2665,8 @@ class Activity {
switch($a->type) {
case 'Create':
case 'Update':
- case 'Like':
- case 'Dislike':
+ //case 'Like':
+ //case 'Dislike':
case 'Announce':
$item = self::decode_note($a);
break;
@@ -2203,6 +2712,7 @@ class Activity {
static public function fetch_and_store_replies($channel, $arr) {
logger('fetching replies');
+ logger(print_r($arr,true));
$p = [];
@@ -2447,7 +2957,7 @@ class Activity {
$s['parent_mid'] = $s['mid'];
- $post_type = (($parent_item['resource_type'] === 'photo') ? t('photo') : t('status'));
+ $post_type = (($parent_item['resource_type'] === 'photo') ? t('photo') : t('post'));
$links = array(array('rel' => 'alternate','type' => 'text/html', 'href' => $parent_item['plink']));
$objtype = (($parent_item['resource_type'] === 'photo') ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE );
@@ -2637,7 +3147,7 @@ class Activity {
}
}
- if (array_key_exists('source',$act) && array_key_exists('mediaType',$act['source'])) {
+ if (array_path_exists('source/mediaType',$act) && array_path_exists('source/content',$act)) {
if ($act['source']['mediaType'] === 'text/bbcode') {
$content['bbcode'] = purify_html($act['source']['content']);
}
@@ -2664,5 +3174,45 @@ class Activity {
return $content;
}
+ // Find either an Authorization: Bearer token or 'token' request variable
+ // in the current web request and return it
+
+ static function token_from_request() {
+
+ foreach ( [ 'REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION' ] as $s ) {
+ $auth = ((array_key_exists($s,$_SERVER) && strpos($_SERVER[$s],'Bearer ') === 0)
+ ? str_replace('Bearer ', EMPTY_STR, $_SERVER[$s])
+ : EMPTY_STR
+ );
+ if ($auth) {
+ break;
+ }
+ }
+
+ if (! $auth) {
+ if (array_key_exists('token',$_REQUEST) && $_REQUEST['token']) {
+ $auth = $_REQUEST['token'];
+ }
+ }
+
+ return $auth;
+ }
+
+ static function find_best_identity($xchan) {
+
+ if(filter_var($xchan, FILTER_VALIDATE_URL)) {
+ $r = q("select hubloc_hash, hubloc_network from hubloc where hubloc_id_url = '%s' and hubloc_network in ('zot6', 'zot') and hubloc_deleted = 0",
+ dbesc($xchan)
+ );
+ if ($r) {
+ $r = Libzot::zot_record_preferred($r);
+ logger('find_best_identity: ' . $xchan . ' > ' . $r['hubloc_hash']);
+ return $r['hubloc_hash'];
+ }
+ }
+
+ return $xchan;
+
+ }
}
diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php
index 006744aff..a0ba52aa6 100644
--- a/Zotlabs/Lib/ActivityStreams.php
+++ b/Zotlabs/Lib/ActivityStreams.php
@@ -101,7 +101,13 @@ class ActivityStreams {
$this->actor = $this->get_actor('attributedTo',$this->obj);
}
}
+
+ // fetch recursive or embedded activities
+ if ($this->obj && is_array($this->obj) && array_key_exists('object',$this->obj)) {
+ $this->obj['object'] = $this->get_compound_property($this->obj['object']);
+ }
+
if($this->obj && is_array($this->obj) && $this->obj['actor'])
$this->obj['actor'] = $this->get_actor('actor',$this->obj);
if($this->tgt && is_array($this->tgt) && $this->tgt['actor'])
@@ -140,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
@@ -263,12 +274,19 @@ class ActivityStreams {
return self::fetch($url);
}
- static function fetch($url,$channel = null) {
- return Activity::fetch($url,$channel);
+ static function fetch($url, $channel = null) {
+ return Activity::fetch($url, $channel);
}
static function is_an_actor($s) {
- return(in_array($s,[ 'Application','Group','Organization','Person','Service' ]));
+ return (in_array($s, [ 'Application','Group','Organization','Person','Service' ]));
+ }
+
+ static function is_response_activity($s) {
+ if (! $s) {
+ return false;
+ }
+ return (in_array($s, [ 'Like', 'Dislike', 'Flag', 'Block', 'Announce', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject', 'emojiReaction', 'EmojiReaction', 'EmojiReact' ]));
}
/**
@@ -391,7 +409,6 @@ class ActivityStreams {
return $x;
}
-
static function is_as_request() {
$x = getBestSupportedMimeType([
@@ -404,5 +421,4 @@ class ActivityStreams {
}
-
-} \ No newline at end of file
+}
diff --git a/Zotlabs/Lib/Apps.php b/Zotlabs/Lib/Apps.php
index 69996b49d..7b980b8d3 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');
@@ -74,7 +76,6 @@ class Apps {
'Directory',
'Search',
'Help',
- 'Mail',
'Profile Photo'
]);
@@ -371,7 +372,6 @@ class Apps {
'OAuth2 Apps Manager' => t('OAuth2 Apps Manager'),
'PDL Editor' => t('PDL Editor'),
'Permission Categories' => t('Permission Categories'),
- 'Premium Channel' => t('Premium Channel'),
'Public Stream' => t('Public Stream'),
'My Chatrooms' => t('My Chatrooms'),
'Channel Export' => t('Channel Export')
@@ -564,7 +564,8 @@ class Apps {
'$featured' => ((strpos($papp['categories'], 'nav_featured_app') === false) ? false : true),
'$pinned' => ((strpos($papp['categories'], 'nav_pinned_app') === false) ? false : true),
'$navapps' => (($mode == 'nav') ? true : false),
- '$order' => (($mode == 'nav-order') ? true : false),
+ '$order' => (($mode === 'nav-order' || $mode === 'nav-order-pinned') ? true : false),
+ '$mode' => $mode,
'$add' => t('Add to app-tray'),
'$remove' => t('Remove from app-tray'),
'$add_nav' => t('Pin to navbar'),
@@ -604,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]));
}
}
}
@@ -670,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 {
@@ -959,9 +960,6 @@ class Apps {
if($list) {
foreach($list as $li) {
$papp = self::app_encode($li);
- if($menu !== 'nav_pinned_app' && strpos($papp['categories'],'nav_pinned_app') !== false)
- continue;
-
$syslist[] = $papp;
}
}
diff --git a/Zotlabs/Lib/Cache.php b/Zotlabs/Lib/Cache.php
index 878201a42..a5052a183 100644
--- a/Zotlabs/Lib/Cache.php
+++ b/Zotlabs/Lib/Cache.php
@@ -7,14 +7,23 @@ namespace Zotlabs\Lib;
*/
class Cache {
- public static function get($key) {
+
+ /**
+ * @brief Returns cached content
+ *
+ * @param string $key
+ * @param string $age in SQL format, default is '30 DAY'
+ * @return string
+ */
+
+ public static function get($key, $age = '') {
$hash = hash('whirlpool',$key);
$r = q("SELECT v FROM cache WHERE k = '%s' AND updated > %s - INTERVAL %s LIMIT 1",
dbesc($hash),
db_utcnow(),
- db_quoteinterval(get_config('system','object_cache_days', '30') . ' DAY')
+ db_quoteinterval(($age ? $age : get_config('system','object_cache_days', '30') . ' DAY'))
);
if ($r)
@@ -43,4 +52,3 @@ class Cache {
}
}
}
-
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
new file mode 100644
index 000000000..481b02ce2
--- /dev/null
+++ b/Zotlabs/Lib/Connect.php
@@ -0,0 +1,312 @@
+<?php /** @file */
+
+namespace Zotlabs\Lib;
+
+use App;
+use Zotlabs\Access\Permissions;
+use Zotlabs\Daemon\Master;
+
+
+
+class Connect {
+
+ /**
+ * Takes a $channel and a $url/handle and adds a new connection
+ *
+ * Returns array
+ * $return['success'] boolean true if successful
+ * $return['abook'] Address book entry joined with xchan if successful
+ * $return['message'] error text if success is false.
+ *
+ * This function does NOT send sync packets to clones. The caller is responsible for doing this
+ */
+
+ static function connect($channel, $url, $sub_channel = false) {
+
+ $uid = $channel['channel_id'];
+
+ if (strpos($url,'@') === false && strpos($url,'/') === false) {
+ $url = $url . '@' . App::get_hostname();
+ }
+
+ $result = [ 'success' => false, 'message' => '' ];
+
+ $my_perms = false;
+ $protocol = '';
+
+ if (substr($url,0,1) === '[') {
+ $x = strpos($url,']');
+ if ($x) {
+ $protocol = substr($url,1,$x-1);
+ $url = substr($url,$x+1);
+ }
+ }
+
+ if (! check_siteallowed($url)) {
+ $result['message'] = t('Channel is blocked on this site.');
+ return $result;
+ }
+
+ if (! $url) {
+ $result['message'] = t('Channel location missing.');
+ return $result;
+ }
+
+ // check service class limits
+
+ $r = q("select count(*) as total from abook where abook_channel = %d and abook_self = 0 ",
+ intval($uid)
+ );
+ if ($r) {
+ $total_channels = $r[0]['total'];
+ }
+
+ if (! service_class_allows($uid,'total_channels',$total_channels)) {
+ $result['message'] = upgrade_message();
+ return $result;
+ }
+
+ $xchan_hash = '';
+ $sql_options = (($protocol) ? " and xchan_network = '" . dbesc($protocol) . "' " : '');
+
+ $r = q("select * from xchan where ( xchan_hash = '%s' or xchan_url = '%s' or xchan_addr = '%s') $sql_options ",
+ dbesc($url),
+ dbesc($url),
+ dbesc($url)
+ );
+
+ if ($r) {
+
+ // reset results to the best record or the first if we don't have the best
+ // note: this is a single record and not an array of results
+
+ $r = Libzot::zot_record_preferred($r,'xchan_network');
+
+ }
+
+ $singleton = false;
+ $d = false;
+
+ if (! $r) {
+
+ // not in cache - try discovery
+
+ $wf = discover_by_webbie($url,$protocol);
+
+ if (! $wf) {
+ $feeds = get_config('system','feed_contacts');
+
+ if (($feeds) && (in_array($protocol, [ '', 'feed', 'rss' ]))) {
+ $d = discover_by_url($url);
+ }
+ else {
+ $result['message'] = t('Remote channel or protocol unavailable.');
+ return $result;
+ }
+ }
+ }
+
+ if ($wf || $d) {
+
+ // something was discovered - find the record which was just created.
+
+ $r = q("select * from xchan where ( xchan_hash = '%s' or xchan_url = '%s' or xchan_addr = '%s' ) $sql_options",
+ dbesc(($wf) ? $wf : $url),
+ dbesc($url),
+ dbesc($url)
+ );
+
+ // convert to a single record (once again preferring a zot solution in the case of multiples)
+
+ if ($r) {
+ $r = Libzot::zot_record_preferred($r,'xchan_network');
+ }
+ }
+
+ // if discovery was a success or the channel was already cached we should have an xchan record in $r
+
+ if ($r) {
+ $xchan = $r;
+ $xchan_hash = $r['xchan_hash'];
+ $their_perms = EMPTY_STR;
+ }
+
+ // failure case
+
+ if (! $xchan_hash) {
+ $result['message'] = t('Channel discovery failed.');
+ logger('follow: ' . $result['message']);
+ return $result;
+ }
+
+ if (! check_channelallowed($xchan_hash)) {
+ $result['message'] = t('Channel is blocked on this site.');
+ logger('follow: ' . $result['message']);
+ return $result;
+
+ }
+
+ $allowed = ((in_array($xchan['xchan_network'],['rss','zot','zot6'])) ? 1 : 0);
+
+ $hookdata = ['channel_id' => $uid, 'follow_address' => $url, 'xchan' => $xchan, 'allowed' => $allowed, 'singleton' => 0];
+ call_hooks('follow_allow',$hookdata);
+
+ if(! $hookdata['allowed']) {
+ $result['message'] = t('Protocol disabled.');
+ return $result;
+ }
+
+ $singleton = intval($hookdata['singleton']);
+
+ // Now start processing the new connection
+
+ $aid = $channel['channel_account_id'];
+ $default_group = $channel['channel_default_group'];
+
+ if (in_array($xchan_hash, [$channel['channel_hash'], $channel['channel_portable_id']])) {
+ $result['message'] = t('Cannot connect to yourself.');
+ return $result;
+ }
+
+ if ($xchan['xchan_network'] === 'rss') {
+
+ // check service class feed limits
+
+ $t = q("select count(*) as total from abook where abook_account = %d and abook_feed = 1 ",
+ intval($aid)
+ );
+ if ($t) {
+ $total_feeds = $t[0]['total'];
+ }
+
+ if (! service_class_allows($uid,'total_feeds',$total_feeds)) {
+ $result['message'] = upgrade_message();
+ return $result;
+ }
+
+ // Always set these "remote" permissions for feeds since we cannot interact with them
+ // to negotiate a suitable permission response
+
+ set_abconfig($uid,$xchan_hash,'their_perms','view_stream',1);
+ set_abconfig($uid,$xchan_hash,'their_perms','republish',1);
+
+ }
+
+
+ $p = Permissions::connect_perms($uid);
+
+ // parent channels have unencumbered write permission
+
+ if ($sub_channel) {
+ $p['perms']['post_wall'] = 1;
+ $p['perms']['post_comments'] = 1;
+ $p['perms']['write_storage'] = 1;
+ $p['perms']['post_like'] = 1;
+ $p['perms']['delegate'] = 0;
+ $p['perms']['moderated'] = 0;
+ }
+
+ $my_perms = $p['perms'];
+
+ $profile_assign = get_pconfig($uid,'system','profile_assign','');
+
+
+ // See if we are already connected by virtue of having an abook record
+
+ $r = q("select abook_id, abook_xchan, abook_pending, abook_instance from abook
+ where abook_xchan = '%s' and abook_channel = %d limit 1",
+ dbesc($xchan_hash),
+ intval($uid)
+ );
+
+ if ($r) {
+
+ $abook_instance = $r[0]['abook_instance'];
+
+ // If they are on a non-nomadic network, add them to this location
+
+ if (($singleton) && strpos($abook_instance,z_root()) === false) {
+ if ($abook_instance) {
+ $abook_instance .= ',';
+ }
+ $abook_instance .= z_root();
+
+ $x = q("update abook set abook_instance = '%s', abook_not_here = 0 where abook_id = %d",
+ dbesc($abook_instance),
+ intval($r[0]['abook_id'])
+ );
+ }
+
+ // if they have a pending connection, we just followed them so approve the connection request
+
+ if (intval($r[0]['abook_pending'])) {
+ $x = q("update abook set abook_pending = 0 where abook_id = %d",
+ intval($r[0]['abook_id'])
+ );
+ }
+ }
+ else {
+
+ // create a new abook record
+
+ $closeness = get_pconfig($uid,'system','new_abook_closeness',80);
+
+ $r = abook_store_lowlevel(
+ [
+ 'abook_account' => intval($aid),
+ 'abook_channel' => intval($uid),
+ 'abook_closeness' => intval($closeness),
+ 'abook_xchan' => $xchan_hash,
+ 'abook_profile' => $profile_assign,
+ 'abook_feed' => intval(($xchan['xchan_network'] === 'rss') ? 1 : 0),
+ 'abook_created' => datetime_convert(),
+ 'abook_updated' => datetime_convert(),
+ 'abook_instance' => (($singleton) ? z_root() : '')
+ ]
+ );
+ }
+
+ if (! $r) {
+ logger('abook creation failed');
+ $result['message'] = t('error saving data');
+ return $result;
+ }
+
+ // Set suitable permissions to the connection
+
+ if($my_perms) {
+ foreach($my_perms as $k => $v) {
+ set_abconfig($uid,$xchan_hash,'my_perms',$k,$v);
+ }
+ }
+
+ // fetch the entire record
+
+ $r = q("select abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash
+ where abook_xchan = '%s' and abook_channel = %d limit 1",
+ dbesc($xchan_hash),
+ intval($uid)
+ );
+
+ if ($r) {
+ $result['abook'] = array_shift($r);
+ Master::Summon([ 'Notifier', 'permission_create', $result['abook']['abook_id'] ]);
+ }
+
+ $arr = [ 'channel_id' => $uid, 'channel' => $channel, 'abook' => $result['abook'] ];
+
+ call_hooks('follow', $arr);
+
+ /** If there is a default group for this channel, add this connection to it */
+
+ if ($default_group) {
+ $g = AccessList::rec_byhash($uid,$default_group);
+ if ($g) {
+ AccessList::member_add($uid,'',$xchan_hash,$g['id']);
+ }
+ }
+
+ $result['success'] = true;
+ return $result;
+ }
+}
diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php
index 92a488f67..c78325ee3 100644
--- a/Zotlabs/Lib/Enotify.php
+++ b/Zotlabs/Lib/Enotify.php
@@ -143,19 +143,26 @@ class Enotify {
$action = t('commented on');
- if(array_key_exists('item',$params) && in_array($params['item']['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) {
+ if(array_key_exists('item',$params)) {
- if(! $always_show_in_notices || !($vnotify & VNOTIFY_LIKE)) {
- logger('notification: not a visible activity. Ignoring.');
- pop_lang();
- return;
- }
+ if(in_array($params['item']['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) {
- if(activity_match($params['verb'], ACTIVITY_LIKE))
- $action = t('liked');
+ if(! $always_show_in_notices || !($vnotify & VNOTIFY_LIKE)) {
+ logger('notification: not a visible activity. Ignoring.');
+ pop_lang();
+ return;
+ }
- if(activity_match($params['verb'], ACTIVITY_DISLIKE))
- $action = t('disliked');
+ if(activity_match($params['verb'], ACTIVITY_LIKE))
+ $action = t('liked');
+
+ if(activity_match($params['verb'], ACTIVITY_DISLIKE))
+ $action = t('disliked');
+
+ }
+
+ if($params['item']['obj_type'] === 'Answer')
+ $action = t('voted on');
}
@@ -550,6 +557,11 @@ class Enotify {
if ((\App::$language === 'en' || (! \App::$language)) && strpos($msg,', '))
$msg = substr($msg,strpos($msg,', ')+1);
+ $datarray['id'] = $notify_id;
+ $datarray['msg'] = $msg;
+
+ call_hooks('enotify_store_end', $datarray);
+
$r = q("update notify set msg = '%s' where id = %d and uid = %d",
dbesc($msg),
intval($notify_id),
@@ -805,13 +817,17 @@ class Enotify {
}
else {
$itemem_text = (($item['item_thread_top'])
- ? t('created a new post')
- : sprintf( t('commented on %s\'s post'), $item['owner']['xchan_name']));
+ ? (($item['obj_type'] === 'Question') ? t('created a new poll') : t('created a new post'))
+ : (($item['obj_type'] === 'Answer') ? sprintf( t('voted on %s\'s poll'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]') : sprintf( t('commented on %s\'s post'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]'))
+ );
if($item['verb'] === ACTIVITY_SHARE) {
- $itemem_text = sprintf( t('repeated %s\'s post'), $item['author']['xchan_name']);
+ $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;
@@ -838,15 +854,16 @@ class Enotify {
'addr' => (($item[$who]['xchan_addr']) ? $item[$who]['xchan_addr'] : $item[$who]['xchan_url']),
'url' => $item[$who]['xchan_url'],
'photo' => $item[$who]['xchan_photo_s'],
- 'when' => relative_date(($edit)? $item['edited'] : $item['created']),
+ 'when' => (($edit) ? datetime_convert('UTC', date_default_timezone_get(), $item['edited']) : datetime_convert('UTC', date_default_timezone_get(), $item['created'])),
'class' => (intval($item['item_unseen']) ? 'notify-unseen' : 'notify-seen'),
- 'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? 'b64.' . base64url_encode($item['thr_parent']) : 'b64.' . base64url_encode($item['mid'])),
- 'notify_id' => 'undefined',
+ 'b64mid' => (($item['mid']) ? 'b64.' . base64url_encode($item['mid']) : ''),
+ //'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? 'b64.' . base64url_encode($item['thr_parent']) : 'b64.' . base64url_encode($item['mid'])),
'thread_top' => (($item['item_thread_top']) ? true : false),
- 'message' => strip_tags(bbcode($itemem_text)),
+ 'message' => bbcode(escape_tags($itemem_text)),
+ 'body' => htmlentities(html2plain(bbcode($item['body']), 75, true), ENT_COMPAT, 'UTF-8', false),
// these are for the superblock addon
'hash' => $item[$who]['xchan_hash'],
- 'uid' => local_channel(),
+ 'uid' => $item['uid'],
'display' => true
);
@@ -858,4 +875,118 @@ class Enotify {
return $x;
}
+ static public function format_notify($tt) {
+
+ $message = trim(strip_tags(bbcode($tt['msg'])));
+
+ if(strpos($message, $tt['xname']) === 0)
+ $message = substr($message, strlen($tt['xname']) + 1);
+
+ $mid = basename($tt['link']);
+
+ $b64mid = ((strpos($mid, 'b64.') === 0) ? $mid : 'b64.' . base64url_encode($mid));
+ $x = [
+ 'notify_link' => z_root() . '/notify/view/' . $tt['id'],
+ 'name' => $tt['xname'],
+ 'url' => $tt['url'],
+ 'photo' => $tt['photo'],
+ 'when' => datetime_convert('UTC', date_default_timezone_get(), $tt['created']),
+ 'hclass' => (($tt['seen']) ? 'notify-seen' : 'notify-unseen'),
+ 'b64mid' => (($tt['otype'] == 'item') ? $b64mid : ''),
+ 'notify_id' => (($tt['otype'] == 'item') ? $tt['id'] : ''),
+ 'message' => $message
+ ];
+
+ return $x;
+
+ }
+
+ static public function format_intros($rr) {
+
+ $x = [
+ 'notify_link' => z_root() . '/connections/ifpending',
+ 'name' => $rr['xchan_name'],
+ 'addr' => $rr['xchan_addr'],
+ 'url' => $rr['xchan_url'],
+ 'photo' => $rr['xchan_photo_s'],
+ 'when' => datetime_convert('UTC', date_default_timezone_get(), $rr['abook_created']),
+ 'hclass' => ('notify-unseen'),
+ 'message' => t('added your channel')
+ ];
+
+ return $x;
+
+ }
+
+ static public function format_files($rr) {
+
+ $x = [
+ 'notify_link' => z_root() . '/sharedwithme',
+ 'name' => $rr['author']['xchan_name'],
+ 'addr' => $rr['author']['xchan_addr'],
+ 'url' => $rr['author']['xchan_url'],
+ 'photo' => $rr['author']['xchan_photo_s'],
+ 'when' => datetime_convert('UTC', date_default_timezone_get(), $rr['created']),
+ 'hclass' => ('notify-unseen'),
+ 'message' => t('shared a file with you')
+ ];
+
+ return $x;
+
+ }
+
+ static public function format_mail($rr) {
+
+ $x = [
+ 'notify_link' => z_root() . '/mail/' . $rr['id'],
+ 'name' => $rr['xchan_name'],
+ 'addr' => $rr['xchan_addr'],
+ 'url' => $rr['xchan_url'],
+ 'photo' => $rr['xchan_photo_s'],
+ 'when' => datetime_convert('UTC', date_default_timezone_get(), $rr['created']),
+ 'hclass' => (intval($rr['mail_seen']) ? 'notify-seen' : 'notify-unseen'),
+ 'message' => t('sent you a private message'),
+ ];
+
+ return $x;
+
+ }
+
+ static public function format_all_events($rr) {
+
+ $bd_format = t('g A l F d') ; // 8 AM Friday January 18
+ $strt = datetime_convert('UTC', (($rr['adjust']) ? date_default_timezone_get() : 'UTC'), $rr['dtstart']);
+ $today = ((substr($strt, 0, 10) === datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d')) ? true : false);
+ $when = day_translate(datetime_convert('UTC', (($rr['adjust']) ? date_default_timezone_get() : 'UTC'), $rr['dtstart'], $bd_format)) . (($today) ? ' ' . t('[today]') : '');
+
+ $x = [
+ 'notify_link' => z_root() . '/cdav/calendar/' . $rr['event_hash'],
+ 'name' => $rr['xchan_name'],
+ 'addr' => $rr['xchan_addr'],
+ 'url' => $rr['xchan_url'],
+ 'photo' => $rr['xchan_photo_s'],
+ 'when' => $when,
+ 'hclass' => (($today) ? 'notify-unseen bg-warning' : 'notify-unseen'),
+ 'message' => t('created an event')
+ ];
+
+ return $x;
+
+ }
+
+ static public function format_register($rr) {
+
+ $x = [
+ 'notify_link' => z_root() . '/admin/accounts',
+ 'name' => $rr['account_email'],
+ //'addr' => $rr['account_email'],
+ 'photo' => z_root() . '/' . get_default_profile_photo(48),
+ 'when' => datetime_convert('UTC', date_default_timezone_get(),$rr['account_created']),
+ 'hclass' => ('notify-unseen'),
+ 'message' => t('requires approval')
+ ];
+
+ return $x;
+
+ }
}
diff --git a/Zotlabs/Lib/JSalmon.php b/Zotlabs/Lib/JSalmon.php
index bed748432..67512046f 100644
--- a/Zotlabs/Lib/JSalmon.php
+++ b/Zotlabs/Lib/JSalmon.php
@@ -69,4 +69,4 @@ class JSalmon {
}
-} \ No newline at end of file
+}
diff --git a/Zotlabs/Lib/Libsync.php b/Zotlabs/Lib/Libsync.php
index d93270bc5..cff320e11 100644
--- a/Zotlabs/Lib/Libsync.php
+++ b/Zotlabs/Lib/Libsync.php
@@ -83,7 +83,7 @@ class Libsync {
$info = (($packet) ? $packet : array());
$info['type'] = 'sync';
- $info['encoding'] = 'red'; // note: not zot, this packet is very platform specific
+ $info['encoding'] = 'hz'; // note: not zot, this packet is very platform specific
$info['relocate'] = ['channel_address' => $channel['channel_address'], 'url' => z_root() ];
if(array_key_exists($uid,\App::$config) && array_key_exists('transient',\App::$config[$uid])) {
@@ -144,12 +144,13 @@ class Libsync {
foreach($synchubs as $hub) {
$hash = random_string();
- $n = Libzot::build_packet($channel,'sync',$env_recips,json_encode($info),'red',$hub['hubloc_sitekey'],$hub['site_crypto']);
+ $n = Libzot::build_packet($channel,'sync',$env_recips,json_encode($info),'hz',$hub['hubloc_sitekey'],$hub['site_crypto']);
Queue::insert(array(
'hash' => $hash,
'account_id' => $channel['channel_account_id'],
'channel_id' => $channel['channel_id'],
'posturl' => $hub['hubloc_callback'],
+ 'driver' => $hub['hubloc_network'],
'notify' => $n,
'msg' => EMPTY_STR
));
@@ -244,7 +245,13 @@ class Libsync {
if(array_key_exists('app',$arr) && $arr['app'])
sync_apps($channel,$arr['app']);
-
+
+ if(array_key_exists('addressbook',$arr) && $arr['addressbook'])
+ sync_addressbook($channel,$arr['addressbook']);
+
+ if(array_key_exists('calendar',$arr) && $arr['calendar'])
+ sync_calendar($channel,$arr['calendar']);
+
if(array_key_exists('chatroom',$arr) && $arr['chatroom'])
sync_chatrooms($channel,$arr['chatroom']);
@@ -812,9 +819,9 @@ class Libsync {
}
if(intval($r[0]['hubloc_primary']) && (! $location['primary'])) {
- $m = q("update hubloc set hubloc_primary = 0, hubloc_updated = '%s' where hubloc_id = %d",
+ $m = q("update hubloc set hubloc_primary = 0, hubloc_updated = '%s' where hubloc_id_url = '%s'",
dbesc(datetime_convert()),
- intval($r[0]['hubloc_id'])
+ dbesc($r[0]['hubloc_id_url'])
);
$r[0]['hubloc_primary'] = intval($location['primary']);
hubloc_change_primary($r[0]);
@@ -841,18 +848,18 @@ class Libsync {
}
}
if(intval($r[0]['hubloc_deleted']) && (! intval($location['deleted']))) {
- $n = q("update hubloc set hubloc_deleted = 0, hubloc_updated = '%s' where hubloc_id = %d",
+ $n = q("update hubloc set hubloc_deleted = 0, hubloc_updated = '%s' where hubloc_id_url = '%s'",
dbesc(datetime_convert()),
- intval($r[0]['hubloc_id'])
+ dbesc($r[0]['hubloc_id_url'])
);
$what .= 'undelete_hub ';
$changed = true;
}
elseif((! intval($r[0]['hubloc_deleted'])) && (intval($location['deleted']))) {
logger('deleting hubloc: ' . $r[0]['hubloc_addr']);
- $n = q("update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id = %d",
+ $n = q("update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id_url = '%s'",
dbesc(datetime_convert()),
- intval($r[0]['hubloc_id'])
+ dbesc($r[0]['hubloc_id_url'])
);
$what .= 'delete_hub ';
$changed = true;
@@ -911,9 +918,9 @@ class Libsync {
foreach($xisting as $x) {
if(! array_key_exists('updated',$x)) {
logger('Deleting unreferenced hub location ' . $x['hubloc_addr']);
- $r = q("update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id = %d",
+ $r = q("update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id_url = '%s'",
dbesc(datetime_convert()),
- intval($x['hubloc_id'])
+ dbesc($x['hubloc_id_url'])
);
$what .= 'removed_hub ';
$changed = true;
@@ -1016,4 +1023,4 @@ class Libsync {
}
-} \ No newline at end of file
+}
diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php
index 100d45c05..f0fe3ab24 100644
--- a/Zotlabs/Lib/Libzot.php
+++ b/Zotlabs/Lib/Libzot.php
@@ -105,7 +105,7 @@ class Libzot {
$data = [
'type' => $type,
'encoding' => $encoding,
- 'sender' => $channel['channel_portable_id'],
+ 'sender' => $channel['channel_hash'],
'site_id' => self::make_xchan_hash(z_root(), get_config('system','pubkey')),
'version' => System::get_zot_revision(),
];
@@ -316,16 +316,20 @@ class Libzot {
$x = self::import_xchan($record['data'], (($force) ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED));
+
if(! $x['success'])
return false;
if($channel && $record['data']['permissions']) {
$permissions = explode(',',$record['data']['permissions']);
+
if($permissions && is_array($permissions)) {
$old_read_stream_perm = get_abconfig($channel['channel_id'],$x['hash'],'their_perms','view_stream');
- foreach($permissions as $p) {
- set_abconfig($channel['channel_id'],$x['hash'],'their_perms',$p,'1');
+ $permissions = Permissions::FilledPerms($permissions);
+
+ foreach($permissions as $k => $v) {
+ set_abconfig($channel['channel_id'],$x['hash'],'their_perms',$k,$v);
}
}
@@ -422,7 +426,7 @@ class Libzot {
[
'type' => NOTIFY_INTRO,
'from_xchan' => $x['hash'],
- 'to_xchan' => $channel['channel_portable_id'],
+ 'to_xchan' => $channel['channel_hash'],
'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id']
]
);
@@ -788,7 +792,7 @@ class Libzot {
// see if this is a channel clone that's hosted locally - which we treat different from other xchans/connections
- $local = q("select channel_account_id, channel_id from channel where channel_portable_id = '%s' limit 1",
+ $local = q("select channel_account_id, channel_id from channel where channel_hash = '%s' limit 1",
dbesc($xchan_hash)
);
if($local) {
@@ -1133,6 +1137,7 @@ class Libzot {
}
logger($AS->debug(),LOGGER_DATA);
+
}
@@ -1151,7 +1156,7 @@ class Libzot {
if($recip_arr) {
stringify_array_elms($recip_arr,true);
$recips = implode(',',$recip_arr);
- $r = q("select channel_portable_id as hash from channel where channel_portable_id in ( " . $recips . " ) and channel_removed = 0 ");
+ $r = q("select channel_hash as hash from channel where channel_hash in ( " . $recips . " ) and channel_removed = 0 ");
}
if(! $r) {
@@ -1193,10 +1198,6 @@ class Libzot {
if(in_array($env['type'],['activity','response'])) {
- $arr = Activity::decode_note($AS);
-
- //logger($AS->debug());
-
$r = q("select hubloc_hash, hubloc_network from hubloc where hubloc_id_url = '%s' ",
dbesc($AS->actor['id'])
);
@@ -1207,6 +1208,10 @@ class Libzot {
$arr['author_xchan'] = $r['hubloc_hash'];
}
+ if (! $arr['author_xchan']) {
+ logger('No author!');
+ return;
+ }
$s = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1",
dbesc($env['sender'])
@@ -1220,8 +1225,8 @@ class Libzot {
$arr['owner_xchan'] = $env['sender'];
}
- if($private) {
- $arr['item_private'] = true;
+ if ($private && (! intval($arr['item_private']))) {
+ $arr['item_private'] = 1;
}
if ($arr['mid'] === $arr['parent_mid']) {
@@ -1277,7 +1282,12 @@ class Libzot {
logger('Channel sync received: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG);
logger('Channel sync recipients: ' . print_r($deliveries,true), LOGGER_DATA, LOG_DEBUG);
- $result = Libsync::process_channel_sync_delivery($env['sender'],$arr,$deliveries);
+ if ($env['encoding'] === 'hz') {
+ $result = Libsync::process_channel_sync_delivery($env['sender'],$arr,$deliveries);
+ }
+ else {
+ logger('sync packet type not supported.');
+ }
}
}
if ($result) {
@@ -1363,12 +1373,12 @@ class Libzot {
$r = [];
- $c = q("select channel_id, channel_portable_id from channel where channel_removed = 0");
+ $c = q("select channel_id, channel_hash from channel where channel_removed = 0");
if($c) {
foreach($c as $cc) {
if(perm_is_allowed($cc['channel_id'],$msg['sender'],$perm)) {
- $r[] = $cc['channel_portable_id'];
+ $r[] = $cc['channel_hash'];
}
}
}
@@ -1376,7 +1386,7 @@ class Libzot {
if($include_sys) {
$sys = get_sys_channel();
if($sys)
- $r[] = $sys['channel_portable_id'];
+ $r[] = $sys['channel_hash'];
}
@@ -1392,7 +1402,7 @@ class Libzot {
if($tag['type'] === 'Mention' && (strpos($tag['href'],z_root()) !== false)) {
$address = basename($tag['href']);
if($address) {
- $z = q("select channel_portable_id as hash from channel where channel_address = '%s'
+ $z = q("select channel_hash as hash from channel where channel_address = '%s'
and channel_removed = 0 limit 1",
dbesc($address)
);
@@ -1413,7 +1423,7 @@ class Libzot {
$thread_parent = self::find_parent($msg,$act);
if($thread_parent) {
- $z = q("select channel_portable_id as hash from channel left join item on channel.channel_id = item.uid where ( item.thr_parent = '%s' OR item.parent_mid = '%s' ) ",
+ $z = q("select channel_hash as hash from channel left join item on channel.channel_id = item.uid where ( item.thr_parent = '%s' OR item.parent_mid = '%s' ) ",
dbesc($thread_parent),
dbesc($thread_parent)
);
@@ -1468,7 +1478,7 @@ class Libzot {
$DR = new DReport(z_root(),$sender,$d,$arr['mid']);
- $channel = channelx_by_portid($d);
+ $channel = channelx_by_hash($d);
if (! $channel) {
$DR->update('recipient not found');
@@ -1483,13 +1493,14 @@ class Libzot {
// Try again using the delivery channel credentials.
// We will also need to re-parse the $item array,
// but preserve any values that were set during anonymous parsing.
-
+
$o = Activity::fetch($act->obj,$channel);
if($o) {
$act->obj = $o;
$arr = array_merge(Activity::decode_note($act),$arr);
}
else {
+
$DR->update('Incomplete or corrupt activity');
$result[] = $DR->get();
continue;
@@ -1505,7 +1516,7 @@ class Libzot {
* access checks.
*/
- if($sender === $channel['channel_portable_id'] && $arr['author_xchan'] === $channel['channel_portable_id'] && $arr['mid'] === $arr['parent_mid']) {
+ if($sender === $channel['channel_hash'] && $arr['author_xchan'] === $channel['channel_hash'] && $arr['mid'] === $arr['parent_mid']) {
$DR->update('self delivery ignored');
$result[] = $DR->get();
continue;
@@ -1608,10 +1619,11 @@ class Libzot {
// As a side effect we will also do a preliminary check that we have the top-level-post, otherwise
// processing it is pointless.
- $r = q("select route, id, owner_xchan, item_private from item where mid = '%s' and uid = %d limit 1",
+ $r = q("select route, id, parent_mid, mid, owner_xchan, item_private, obj_type from item where mid = '%s' and uid = %d limit 1",
dbesc($arr['parent_mid']),
intval($channel['channel_id'])
);
+
if(! $r) {
$DR->update('comment parent not found');
$result[] = $DR->get();
@@ -1634,6 +1646,16 @@ class Libzot {
continue;
}
+ if ($r[0]['obj_type'] === 'Question') {
+ // route checking doesn't work correctly here because we've changed the privacy
+ $r[0]['route'] = EMPTY_STR;
+ // If this is a poll response, convert the obj_type to our (internal-only) "Answer" type
+ if ($arr['obj_type'] === ACTIVITY_OBJ_COMMENT && $arr['title'] && (! $arr['body'])) {
+ $arr['obj_type'] = 'Answer';
+ }
+ }
+
+
if($relay || $friendofriend || (intval($r[0]['item_private']) === 0 && intval($arr['item_private']) === 0)) {
// reset the route in case it travelled a great distance upstream
// use our parent's route so when we go back downstream we'll match
@@ -1701,7 +1723,7 @@ class Libzot {
$arr['aid'] = $channel['channel_account_id'];
$arr['uid'] = $channel['channel_id'];
- $item_id = self::delete_imported_item($sender,$arr,$channel['channel_id'],$relay);
+ $item_id = self::delete_imported_item($sender,$act,$arr,$channel['channel_id'],$relay);
$DR->update(($item_id) ? 'deleted' : 'delete_failed');
$result[] = $DR->get();
@@ -1715,11 +1737,15 @@ class Libzot {
continue;
}
+ // reactions such as like and dislike could have an mid with /activity/ in it.
+ // Check for both forms in order to prevent duplicates.
- $r = q("select * from item where mid = '%s' and uid = %d limit 1",
+ $r = q("select * from item where mid in ('%s','%s') and uid = %d limit 1",
dbesc($arr['mid']),
+ dbesc(str_replace(z_root() . '/activity/', z_root() . '/item/', $arr['mid'])),
intval($channel['channel_id'])
);
+
if($r) {
// We already have this post.
$item_id = $r[0]['id'];
@@ -1811,7 +1837,7 @@ class Libzot {
$stored = (($item_result && $item_result['item']) ? $item_result['item'] : false);
if((is_array($stored)) && ($stored['id'] != $stored['parent'])
- && ($stored['author_xchan'] === $channel['channel_hash'] || $stored['author_xchan'] === $channel['channel_portable_id'])) {
+ && ($stored['author_xchan'] === $channel['channel_hash'] || $stored['author_xchan'] === $channel['channel_hash'])) {
retain_item($stored['item']['parent']);
}
@@ -1933,9 +1959,9 @@ class Libzot {
}
logger('FOF Activity received: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG);
- logger('FOF Activity recipient: ' . $channel['channel_portable_id'], LOGGER_DATA, LOG_DEBUG);
+ logger('FOF Activity recipient: ' . $channel['channel_hash'], LOGGER_DATA, LOG_DEBUG);
- $result = self::process_delivery($arr['owner_xchan'],$AS, $arr, [ $channel['channel_portable_id'] ],false,false,true);
+ $result = self::process_delivery($arr['owner_xchan'],$AS, $arr, [ $channel['channel_hash'] ],false,false,true);
if ($result) {
$ret = array_merge($ret, $result);
}
@@ -2080,7 +2106,7 @@ class Libzot {
* @return boolean|int post_id
*/
- static function delete_imported_item($sender, $item, $uid, $relay) {
+ static function delete_imported_item($sender, $act, $item, $uid, $relay) {
logger('invoked', LOGGER_DEBUG);
@@ -2088,38 +2114,39 @@ class Libzot {
$item_found = false;
$post_id = 0;
+ if ($item['verb'] === 'Tombstone') {
+ // The id of the deleted thing is the item mid (activity id)
+ $mid = $item['mid'];
+ }
+ else {
+ // The id is the object id if the type is Undo or Delete
+ $mid = ((is_array($act->obj)) ? $act->obj['id'] : $act->obj);
+ }
+
+ // we may have stored either the object id or the activity id if it was a response activity (like, dislike, etc.)
+
$r = q("select * from item where ( author_xchan = '%s' or owner_xchan = '%s' or source_xchan = '%s' )
- and mid = '%s' and uid = %d limit 1",
+ and mid IN ('%s', '%s') and uid = %d limit 1",
dbesc($sender),
dbesc($sender),
dbesc($sender),
- dbesc($item['mid']),
+ dbesc($mid),
+ dbesc(str_replace('/activity/','/item/',$mid)),
intval($uid)
);
if($r) {
$stored = $r[0];
- if($stored['author_xchan'] === $sender || $stored['owner_xchan'] === $sender || $stored['source_xchan'] === $sender)
- $ownership_valid = true;
+ // we proved ownership in the sql query
+ $ownership_valid = true;
$post_id = $stored['id'];
$item_found = true;
}
else {
-
- // perhaps the item is still in transit and the delete notification got here before the actual item did. Store it with the deleted flag set.
- // item_store() won't try to deliver any notifications or start delivery chains if this flag is set.
- // This means we won't end up with potentially even more delivery threads trying to push this delete notification.
- // But this will ensure that if the (undeleted) original post comes in at a later date, we'll reject it because it will have an older timestamp.
-
- logger('delete received for non-existent item - storing item data.');
-
- if($item['author_xchan'] === $sender || $item['owner_xchan'] === $sender || $item['source_xchan'] === $sender) {
- $ownership_valid = true;
- $item_result = item_store($item);
- $post_id = $item_result['item_id'];
- }
+ // this will fail with an ownership issue, so explain the real reason
+ logger('delete received for non-existent item or not owned by sender - ignoring.');
}
if($ownership_valid === false) {
@@ -2191,7 +2218,7 @@ class Libzot {
$DR = new DReport(z_root(),$sender,$d,$arr['mid']);
- $r = q("select * from channel where channel_portable_id = '%s' limit 1",
+ $r = q("select * from channel where channel_hash = '%s' limit 1",
dbesc($d['hash'])
);
@@ -2346,7 +2373,7 @@ class Libzot {
$loc = $locations[0];
- $r = q("select * from channel where channel_portable_id = '%s' limit 1",
+ $r = q("select * from channel where channel_hash = '%s' limit 1",
dbesc($sender_hash)
);
@@ -2354,7 +2381,7 @@ class Libzot {
return;
if($loc['url'] !== z_root()) {
- $x = q("update channel set channel_moved = '%s' where channel_portable_id = '%s' limit 1",
+ $x = q("update channel set channel_moved = '%s' where channel_hash = '%s' limit 1",
dbesc($loc['url']),
dbesc($sender_hash)
);
@@ -2388,7 +2415,7 @@ class Libzot {
static function encode_locations($channel) {
$ret = [];
- $x = self::get_hublocs($channel['channel_portable_id']);
+ $x = self::get_hublocs($channel['channel_hash']);
if($x && count($x)) {
foreach($x as $hub) {
@@ -2736,13 +2763,13 @@ class Libzot {
$r = null;
if(strlen($zhash)) {
- $r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
- where channel_portable_id = '%s' limit 1",
+ $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
+ where channel_hash = '%s' limit 1",
dbesc($zhash)
);
}
elseif(strlen($zguid) && strlen($zguid_sig)) {
- $r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
+ $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
where channel_guid = '%s' and channel_guid_sig = '%s' limit 1",
dbesc($zguid),
dbesc($zguid_sig)
@@ -2750,7 +2777,7 @@ class Libzot {
}
elseif(strlen($zaddr)) {
if(strpos($zaddr,'[system]') === false) { /* normal address lookup */
- $r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
+ $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
where ( channel_address = '%s' or xchan_addr = '%s' ) limit 1",
dbesc($zaddr),
dbesc($zaddr)
@@ -2770,10 +2797,10 @@ class Libzot {
*
*/
- $r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
+ $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
where channel_system = 1 order by channel_id limit 1");
if(! $r) {
- $r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
+ $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
where channel_removed = 0 order by channel_id limit 1");
}
}
@@ -2892,7 +2919,7 @@ class Libzot {
];
$ret['channel_role'] = get_pconfig($e['channel_id'],'system','permissions_role','custom');
- $ret['protocols'] = [ 'zot', 'zot6' ];
+ $ret['protocols'] = [ 'zot6', 'zot' ];
$ret['searchable'] = $searchable;
$ret['adult_content'] = $adult_channel;
$ret['public_forum'] = $public_forum;
diff --git a/Zotlabs/Lib/Libzotdir.php b/Zotlabs/Lib/Libzotdir.php
index 1cb52275c..b02516a98 100644
--- a/Zotlabs/Lib/Libzotdir.php
+++ b/Zotlabs/Lib/Libzotdir.php
@@ -3,6 +3,8 @@
namespace Zotlabs\Lib;
use Zotlabs\Lib\Libzot;
+use Zotlabs\Lib\Zotfinger;
+use Zotlabs\Lib\Webfinger;
require_once('include/permissions.php');
@@ -307,9 +309,9 @@ class Libzotdir {
if ($ud['ud_addr'] && (! ($ud['ud_flags'] & UPDATE_FLAGS_DELETED))) {
$success = false;
- $href = \Zotlabs\Lib\Webfinger::zot_url(punify($ud['ud_addr']));
+ $href = Webfinger::zot_url(punify($ud['ud_addr']));
if($href) {
- $zf = \Zotlabs\Lib\Zotfinger::exec($href);
+ $zf = Zotfinger::exec($href);
}
if(is_array($zf) && array_path_exists('signature/signer',$zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) {
$xc = Libzot::import_xchan($zf['data'], 0, $ud);
@@ -339,7 +341,7 @@ class Libzotdir {
logger('local_dir_update: uid: ' . $uid, LOGGER_DEBUG);
- $p = q("select channel.channel_hash, channel_address, channel_timezone, profile.* from profile left join channel on channel_id = uid where uid = %d and is_default = 1",
+ $p = q("select channel.channel_hash, channel_address, channel_timezone, channel_portable_id, profile.* from profile left join channel on channel_id = uid where uid = %d and is_default = 1",
intval($uid)
);
@@ -348,6 +350,7 @@ class Libzotdir {
if ($p) {
$hash = $p[0]['channel_hash'];
+ $legacy_hash = $p[0]['channel_portable_id'];
$profile['description'] = $p[0]['pdesc'];
$profile['birthday'] = $p[0]['dob'];
@@ -381,14 +384,15 @@ class Libzotdir {
logger('hidden: ' . $hidden);
- $r = q("select xchan_hidden from xchan where xchan_hash = '%s' limit 1",
+ $r = q("select xchan_hidden from xchan where xchan_hash = '%s'",
dbesc($p[0]['channel_hash'])
);
if(intval($r[0]['xchan_hidden']) != $hidden) {
- $r = q("update xchan set xchan_hidden = %d where xchan_hash = '%s'",
+ $r = q("update xchan set xchan_hidden = %d where xchan_hash in ('%s', '%s')",
intval($hidden),
- dbesc($p[0]['channel_hash'])
+ dbesc($hash),
+ dbesc($legacy_hash)
);
}
@@ -402,11 +406,13 @@ class Libzotdir {
}
else {
// they may have made it private
- $r = q("delete from xprof where xprof_hash = '%s'",
- dbesc($hash)
+ q("delete from xprof where xprof_hash in ('%s', '%s')",
+ dbesc($hash),
+ dbesc($legacy_hash)
);
- $r = q("delete from xtag where xtag_hash = '%s'",
- dbesc($hash)
+ q("delete from xtag where xtag_hash in ('%s', '%s')",
+ dbesc($hash),
+ dbesc($legacy_hash)
);
}
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/NativeWikiPage.php b/Zotlabs/Lib/NativeWikiPage.php
index dddd26af3..d84cc50a8 100644
--- a/Zotlabs/Lib/NativeWikiPage.php
+++ b/Zotlabs/Lib/NativeWikiPage.php
@@ -530,8 +530,11 @@ class NativeWikiPage {
foreach ($match[1] as $m) {
// TODO: Why do we need to double urlencode for this to work?
//$pageURLs[] = urlencode(urlencode(escape_tags($m)));
- $pageURLs[] = Zlib\NativeWiki::name_encode(escape_tags($m));
- $pages[] = $m;
+ $titleUri = explode('|',$m);
+ $page = $titleUri[0] ?? '';
+ $title = $titleUri[1] ?? $page;
+ $pageURLs[] = Zlib\NativeWiki::name_encode(escape_tags($page));
+ $pages[] = $title;
}
$idx = 0;
while(strpos($s,'[[') !== false) {
diff --git a/Zotlabs/Lib/Queue.php b/Zotlabs/Lib/Queue.php
index 49891a55b..6acc58bc5 100644
--- a/Zotlabs/Lib/Queue.php
+++ b/Zotlabs/Lib/Queue.php
@@ -116,7 +116,7 @@ class Queue {
dbesc($arr['hash']),
intval($arr['account_id']),
intval($arr['channel_id']),
- dbesc(($arr['driver']) ? $arr['driver'] : 'zot'),
+ dbesc(($arr['driver']) ? $arr['driver'] : 'zot6'),
dbesc($arr['posturl']),
intval(1),
intval(($arr['priority']) ? $arr['priority'] : 0),
diff --git a/Zotlabs/Lib/Share.php b/Zotlabs/Lib/Share.php
index 3a2ab1783..419e6ed5f 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'];
@@ -127,7 +128,7 @@ class Share {
"' profile='" . $this->item['author']['xchan_url'] .
"' avatar='" . $this->item['author']['xchan_photo_s'] .
"' link='" . $this->item['plink'] .
- "' auth='" . (($this->item['author']['network'] === 'zot') ? 'true' : 'false') .
+ "' auth='" . ((in_array($this->item['author']['xchan_network'], ['zot6', 'zot'])) ? 'true' : 'false') .
"' posted='" . $this->item['created'] .
"' message_id='" . $this->item['mid'] .
"']";
diff --git a/Zotlabs/Lib/System.php b/Zotlabs/Lib/System.php
index 7bf1343bb..3cc46fbda 100644
--- a/Zotlabs/Lib/System.php
+++ b/Zotlabs/Lib/System.php
@@ -5,9 +5,14 @@ namespace Zotlabs\Lib;
class System {
static public function get_platform_name() {
- if(is_array(\App::$config) && is_array(\App::$config['system']) && array_key_exists('platform_name',\App::$config['system']))
- return \App::$config['system']['platform_name'];
- return PLATFORM_NAME;
+ static $platform_name = '';
+ if(empty($platform_name)) {
+ if(is_array(\App::$config) && is_array(\App::$config['system']) && array_key_exists('platform_name',\App::$config['system']))
+ $platform_name = \App::$config['system']['platform_name'];
+ else
+ $platform_name = PLATFORM_NAME;
+ }
+ return $platform_name;
}
static public function get_site_name() {
diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php
index 667ea269a..024502d2a 100644
--- a/Zotlabs/Lib/ThreadItem.php
+++ b/Zotlabs/Lib/ThreadItem.php
@@ -78,7 +78,7 @@ class ThreadItem {
*/
public function get_template_data($conv_responses, $thread_level=1, $conv_flags = []) {
-
+
$result = array();
$item = $this->get_data();
@@ -95,7 +95,7 @@ class ThreadItem {
$total_children = $this->count_descendants();
$unseen_comments = (($item['real_uid']) ? 0 : $this->count_unseen_descendants());
- $conv = $this->get_conversation();
+ $conv = $this->get_conversation();
$observer = $conv->get_observer();
$lock = (((intval($item['item_private'])) || (($item['uid'] == local_channel()) && (strlen($item['allow_cid']) || strlen($item['allow_gid'])
@@ -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;
}
@@ -150,9 +150,11 @@ class ThreadItem {
$edpost = false;
- if($observer['xchan_hash'] == $this->get_data_value('author_xchan')
+ if($observer && $observer['xchan_hash']
+ && ($observer['xchan_hash'] == $this->get_data_value('author_xchan')
|| $observer['xchan_hash'] == $this->get_data_value('owner_xchan')
- || $this->get_data_value('uid') == local_channel())
+ || $observer['xchan_hash'] == $this->get_data_value('source_xchan')
+ || $this->get_data_value('uid') == local_channel()))
$dropping = true;
@@ -204,6 +206,10 @@ class ThreadItem {
}
}
+ if($item['obj_type'] === 'Question') {
+ $response_verbs[] = 'answer';
+ }
+
$consensus = (intval($item['item_consensus']) ? true : false);
if($consensus) {
$response_verbs[] = 'agree';
@@ -281,12 +287,16 @@ class ThreadItem {
$settings = '';
+ $tagger = [];
+
// FIXME - check this permission
if($conv->get_profile_owner() == local_channel()) {
+ /* disable until we agree on how to implemnt this in zot6/activitypub
$tagger = array(
'tagit' => t("Add Tag"),
'classtagger' => "",
);
+ */
$settings = t('Conversation Tools');
}
@@ -346,7 +356,7 @@ class ThreadItem {
$viewthread = z_root() . '/channel/' . $owner_address . '?f=&mid=' . urlencode(gen_link_id($item['mid']));
$comment_count_txt = sprintf( tt('%d comment','%d comments',$total_children),$total_children );
- $list_unseen_txt = (($unseen_comments) ? sprintf('%d unseen',$unseen_comments) : '');
+ $list_unseen_txt = (($unseen_comments) ? sprintf( t('%d unseen'),$unseen_comments) : '');
$children = $this->get_children();
@@ -356,11 +366,28 @@ class ThreadItem {
call_hooks('dropdown_extras',$dropdown_extras_arr);
$dropdown_extras = $dropdown_extras_arr['dropdown_extras'];
+ $midb64 = 'b64.' . base64url_encode($item['mid']);
+ $mids = [ $midb64 ];
+ $response_mids = [];
+ foreach($response_verbs as $v) {
+ if(isset($conv_responses[$v]['mids'][$item['mid']])) {
+ $response_mids = array_merge($response_mids, $conv_responses[$v]['mids'][$item['mid']]);
+ }
+ }
+
+ $mids = array_merge($mids, $response_mids);
+ $json_mids = json_encode($mids);
+
+ // Pinned item processing
+ $allowed_type = (in_array($item['item_type'], get_config('system', 'pin_types', [ ITEM_TYPE_POST ])) ? true : false);
+ $pinned_items = ($allowed_type ? get_pconfig($item['uid'], 'pinned', $item['item_type'], []) : []);
+ $pinned = ((!empty($pinned_items) && in_array($midb64, $pinned_items)) ? true : false);
+
$tmp_item = array(
'template' => $this->get_template(),
'mode' => $mode,
'item_type' => intval($item['item_type']),
- 'type' => implode("",array_slice(explode("/",$item['verb']),-1)),
+ //'type' => implode("",array_slice(explode("/",$item['verb']),-1)),
'body' => $body['html'],
'tags' => $body['tags'],
'categories' => $body['categories'],
@@ -369,7 +396,8 @@ class ThreadItem {
'folders' => $body['folders'],
'text' => strip_tags($body['html']),
'id' => $this->get_id(),
- 'mid' => $item['mid'],
+ 'mid' => $midb64,
+ 'mids' => $json_mids,
'parent' => $item['parent'],
'author_id' => (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url']),
'isevent' => $isevent,
@@ -377,8 +405,8 @@ class ThreadItem {
'consensus' => $consensus,
'conlabels' => $conlabels,
'canvote' => $canvote,
- 'linktitle' => sprintf( t('View %s\'s profile - %s'), $profile_name, (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url'])),
- 'olinktitle' => sprintf( t('View %s\'s profile - %s'), $this->get_owner_name(), (($item['owner']['xchan_addr']) ? $item['owner']['xchan_addr'] : $item['owner']['xchan_url'])),
+ 'linktitle' => (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url']),
+ 'olinktitle' => (($item['owner']['xchan_addr']) ? $item['owner']['xchan_addr'] : $item['owner']['xchan_url']),
'llink' => $item['llink'],
'viewthread' => $viewthread,
'to' => t('to'),
@@ -396,7 +424,7 @@ class ThreadItem {
'sparkle' => $sparkle,
'title' => $item['title'],
'title_tosource' => get_pconfig($conv->get_profile_owner(),'system','title_tosource'),
- 'ago' => relative_date($item['created']),
+ //'ago' => relative_date($item['created']),
'app' => $item['app'],
'str_app' => sprintf( t('from %s'), $item['app']),
'isotime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'c'),
@@ -404,6 +432,7 @@ class ThreadItem {
'editedtime' => (($item['edited'] != $item['created']) ? sprintf( t('last edited: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['edited'], 'r')) : ''),
'expiretime' => (($item['expires'] > NULL_DATE) ? sprintf( t('Expires: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['expires'], 'r')):''),
'lock' => $lock,
+ 'delayed' => $item['item_delayed'],
'privacy_warning' => $privacy_warning,
'verified' => $verified,
'unverified' => $unverified,
@@ -437,6 +466,9 @@ class ThreadItem {
'star' => ((feature_enabled($conv->get_profile_owner(),'star_posts') && ($item['item_type'] == ITEM_TYPE_POST)) ? $star : ''),
'tagger' => ((feature_enabled($conv->get_profile_owner(),'commtag')) ? $tagger : ''),
'filer' => ((feature_enabled($conv->get_profile_owner(),'filing') && ($item['item_type'] == ITEM_TYPE_POST)) ? $filer : ''),
+ 'pinned' => ($pinned ? t('Pinned post') : ''),
+ 'pinnable' => (($this->is_toplevel() && local_channel() && $item['owner_xchan'] == $observer['xchan_hash'] && $allowed_type && $item['item_private'] == 0 && $item['item_delayed'] == 0) ? '1' : ''),
+ 'pinme' => ($pinned ? t('Unpin from the top') : t('Pin to the top')),
'bookmark' => (($conv->get_profile_owner() == local_channel() && local_channel() && $has_bookmarks) ? t('Save Bookmarks') : ''),
'addtocal' => (($has_event) ? t('Add to Calendar') : ''),
'drop' => $drop,
@@ -463,14 +495,13 @@ class ThreadItem {
'modal_dismiss' => t('Close'),
'showlike' => $showlike,
'showdislike' => $showdislike,
- 'comment' => $this->get_comment_box($indent),
+ 'comment' => ($item['item_delayed'] ? '' : $this->get_comment_box($indent)),
'previewing' => ($conv->is_preview() ? true : false ),
'preview_lbl' => t('This is an unsaved preview'),
'wait' => t('Please wait'),
- 'submid' => str_replace(['+','='], ['',''], base64_encode($item['mid'])),
'thread_level' => $thread_level,
'settings' => $settings,
- 'thr_parent' => (($item['parent_mid'] != $item['thr_parent']) ? $item['thr_parent'] : '')
+ 'thr_parent' => (($item['parent_mid'] != $item['thr_parent']) ? 'b64.' . base64url_encode($item['thr_parent']) : '')
);
$arr = array('item' => $item, 'output' => $tmp_item);
@@ -863,7 +894,4 @@ class ThreadItem {
return $this->visiting;
}
-
-
-
}
diff --git a/Zotlabs/Lib/ThreadStream.php b/Zotlabs/Lib/ThreadStream.php
index 020e8729b..68b2c70dd 100644
--- a/Zotlabs/Lib/ThreadStream.php
+++ b/Zotlabs/Lib/ThreadStream.php
@@ -23,7 +23,7 @@ class ThreadStream {
private $preview = false;
private $prepared_item = '';
public $reload = '';
- private $cipher = 'aes256';
+ private $cipher = 'AES-128-CCM';
// $prepared_item is for use by alternate conversation structures such as photos
// wherein we've already prepared a top level item which doesn't look anything like
diff --git a/Zotlabs/Lib/Webfinger.php b/Zotlabs/Lib/Webfinger.php
index c2364ac4d..611c36889 100644
--- a/Zotlabs/Lib/Webfinger.php
+++ b/Zotlabs/Lib/Webfinger.php
@@ -106,4 +106,4 @@ class Webfinger {
-} \ No newline at end of file
+}
diff --git a/Zotlabs/Lib/Zotfinger.php b/Zotlabs/Lib/Zotfinger.php
index 2d2e6796b..722e34dfc 100644
--- a/Zotlabs/Lib/Zotfinger.php
+++ b/Zotlabs/Lib/Zotfinger.php
@@ -60,4 +60,4 @@ class Zotfinger {
-} \ No newline at end of file
+}
diff --git a/Zotlabs/Module/Acl.php b/Zotlabs/Module/Acl.php
index 82c156a9c..e0206bd43 100644
--- a/Zotlabs/Module/Acl.php
+++ b/Zotlabs/Module/Acl.php
@@ -42,7 +42,7 @@ class Acl extends \Zotlabs\Web\Controller {
// $type =
- // 'm' => autocomplete private mail recipient (checks post_mail permission)
+ // 'm' => autocomplete private mail recipient (checks post_mail permission and displays only zot, diaspora, friendica-over-diaspora xchan_network xchan's)
// 'a' => autocomplete connections (mod_connections, mod_poke, mod_sources, mod_photos)
// 'x' => nav search bar autocomplete (match any xchan)
// $_REQUEST['query'] contains autocomplete search text.
@@ -286,6 +286,7 @@ class Acl extends \Zotlabs\Web\Controller {
FROM abook left join xchan on abook_xchan = xchan_hash
WHERE abook_channel = %d
and xchan_deleted = 0
+ and xchan_network IN ('zot', 'diaspora', 'friendica-over-diaspora')
$sql_extra3
ORDER BY xchan_name ASC ",
intval(local_channel())
diff --git a/Zotlabs/Module/Activity.php b/Zotlabs/Module/Activity.php
new file mode 100644
index 000000000..b75f0b245
--- /dev/null
+++ b/Zotlabs/Module/Activity.php
@@ -0,0 +1,269 @@
+<?php
+namespace Zotlabs\Module;
+
+use Zotlabs\Lib\IConfig;
+use Zotlabs\Lib\Enotify;
+use Zotlabs\Web\Controller;
+use Zotlabs\Daemon\Master;
+use Zotlabs\Lib\Activity as ZlibActivity;
+use Zotlabs\Lib\ActivityStreams;
+use Zotlabs\Lib\LDSignatures;
+use Zotlabs\Web\HTTPSig;
+use Zotlabs\Lib\Libzot;
+use Zotlabs\Lib\ThreadListener;
+use App;
+
+
+class Activity extends Controller {
+
+ function init() {
+
+ if (Libzot::is_zot_request()) {
+
+ $item_id = argv(1);
+ if (! $item_id)
+ http_status_exit(404, 'Not found');
+
+ $portable_id = EMPTY_STR;
+
+ $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 ";
+
+ $i = null;
+
+ // do we have the item (at all)?
+
+ $r = q("select * from item where mid = '%s' $item_normal limit 1",
+ dbesc(z_root() . '/activity/' . $item_id)
+ );
+
+ if (! $r) {
+ http_status_exit(404,'Not found');
+ }
+
+ // process an authenticated fetch
+
+ $sigdata = HTTPSig::verify(EMPTY_STR);
+ if($sigdata['portable_id'] && $sigdata['header_valid']) {
+ $portable_id = $sigdata['portable_id'];
+ 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'])
+ );
+
+ 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'])
+ );
+ }
+ }
+ }
+
+ // 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
+ // with a bias towards those items owned by channels on this site (item_wall = 1)
+
+ $sql_extra = item_permissions_sql(0);
+
+ if (! $i) {
+ $i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1",
+ dbesc($r[0]['parent_mid'])
+ );
+ }
+
+ if(! $i) {
+ http_status_exit(403,'Forbidden');
+ }
+
+ $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 ",
+ dbesc($parents_str)
+ );
+
+ if(! $items) {
+ http_status_exit(404, 'Not found');
+ }
+
+ 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)
+ http_status_exit(404, 'Not found');
+
+ $chan = channelx_by_n($nitems[0]['uid']);
+
+ if(! $chan)
+ http_status_exit(404, 'Not found');
+
+ if(! perm_is_allowed($chan['channel_id'],get_observer_hash(),'view_stream'))
+ http_status_exit(403, 'Forbidden');
+
+ $i = ZlibActivity::encode_item_collection($nitems,'conversation/' . $item_id,'OrderedCollection');
+ if($portable_id) {
+ ThreadListener::store(z_root() . '/activity/' . $item_id,$portable_id);
+ }
+
+ if(! $i)
+ http_status_exit(404, 'Not found');
+
+ $x = array_merge(['@context' => [
+ ACTIVITYSTREAMS_JSONLD_REV,
+ 'https://w3id.org/security/v1',
+ z_root() . ZOT_APSCHEMA_REV
+ ]], $i);
+
+ $headers = [];
+ $headers['Content-Type'] = 'application/x-zot+json' ;
+ $x['signature'] = LDSignatures::sign($x,$chan);
+ $ret = json_encode($x, JSON_UNESCAPED_SLASHES);
+ $headers['Digest'] = HTTPSig::generate_digest_header($ret);
+ $headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
+ $h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],channel_url($chan));
+ HTTPSig::set_headers($h);
+ echo $ret;
+ killme();
+
+ }
+
+ if(ActivityStreams::is_as_request()) {
+
+ $item_id = argv(1);
+
+ if (! $item_id) {
+ return;
+ }
+
+ $ob_authorise = false;
+ $item_uid = 0;
+
+ $bear = ZlibActivity::token_from_request();
+ if ($bear) {
+ logger('bear: ' . $bear, LOGGER_DEBUG);
+ $t = q("select item.uid, iconfig.v from iconfig left join item on iid = item.id where cat = 'ocap' and item.uuid = '%s'",
+ dbesc($item_id)
+ );
+ if ($t) {
+ foreach ($t as $token) {
+ if ($token['v'] === $bear) {
+ $ob_authorize = true;
+ $item_uid = $token['uid'];
+ break;
+ }
+ }
+ }
+ }
+
+ $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0
+ and item.item_delayed = 0 and item.item_blocked = 0 ";
+
+ $sigdata = HTTPSig::verify(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);
+ }
+
+ // if passed an owner_id of 0 to item_permissions_sql(), we force "guest access" or observer checking
+ // Give ocap tokens priority
+
+ if ($ob_authorize) {
+ $sql_extra = " and item.uid = " . intval($token['uid']) . " ";
+ }
+ else {
+ $sql_extra = item_permissions_sql(0);
+ }
+
+ $r = q("select * from item where uuid = '%s' $item_normal $sql_extra limit 1",
+ dbesc($item_id)
+ );
+
+ if (! $r) {
+ $r = q("select * from item where uuid = '%s' $item_normal limit 1",
+ dbesc($item_id)
+ );
+ if($r) {
+ http_status_exit(403, 'Forbidden');
+ }
+ http_status_exit(404, 'Not found');
+ }
+
+ xchan_query($r,true);
+ $items = fetch_post_tags($r,false);
+
+ $channel = channelx_by_n($items[0]['uid']);
+
+ $x = array_merge( ['@context' => [
+ ACTIVITYSTREAMS_JSONLD_REV,
+ 'https://w3id.org/security/v1',
+ z_root() . ZOT_APSCHEMA_REV
+ ]], ZlibActivity::encode_activity($items[0],true));
+
+ $headers = [];
+ $headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ;
+ $x['signature'] = LDSignatures::sign($x,$channel);
+ $ret = json_encode($x, JSON_UNESCAPED_SLASHES);
+ $headers['Date'] = datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T');
+ $headers['Digest'] = HTTPSig::generate_digest_header($ret);
+ $headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
+
+ $h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel));
+ HTTPSig::set_headers($h);
+ echo $ret;
+ killme();
+
+ }
+
+ goaway(z_root() . '/item/' . argv(1));
+
+ }
+
+}
diff --git a/Zotlabs/Module/Admin/Addons.php b/Zotlabs/Module/Admin/Addons.php
index 243eb242f..b67ab7b3a 100644
--- a/Zotlabs/Module/Admin/Addons.php
+++ b/Zotlabs/Module/Admin/Addons.php
@@ -18,7 +18,7 @@ class Addons {
@include_once("addon/" . argv(2) . "/" . argv(2) . ".php");
if(function_exists(argv(2).'_plugin_admin_post')) {
$func = argv(2) . '_plugin_admin_post';
- $func($a);
+ $func();
}
goaway(z_root() . '/admin/addons/' . argv(2) );
@@ -332,7 +332,7 @@ class Addons {
@require_once("addon/$plugin/$plugin.php");
if(function_exists($plugin.'_plugin_admin')) {
$func = $plugin.'_plugin_admin';
- $func($a, $admin_form);
+ $func($admin_form);
}
}
diff --git a/Zotlabs/Module/Apporder.php b/Zotlabs/Module/Apporder.php
index eac1abc2d..313c2df50 100644
--- a/Zotlabs/Module/Apporder.php
+++ b/Zotlabs/Module/Apporder.php
@@ -34,9 +34,9 @@ class Apporder extends \Zotlabs\Web\Controller {
foreach($syslist as $app) {
if($l === 'nav_pinned_app') {
- $navbar_apps[] = Zlib\Apps::app_render($app,'nav-order');
+ $navbar_apps[] = Zlib\Apps::app_render($app,'nav-order-pinned');
}
- elseif(strpos($app['categories'],'nav_pinned_app') === false) {
+ else {
$nav_apps[] = Zlib\Apps::app_render($app,'nav-order');
}
}
diff --git a/Zotlabs/Module/Apschema.php b/Zotlabs/Module/Apschema.php
index 756057a8a..6b0325d44 100644
--- a/Zotlabs/Module/Apschema.php
+++ b/Zotlabs/Module/Apschema.php
@@ -29,7 +29,10 @@ class Apschema extends \Zotlabs\Web\Controller {
'emojiReaction' => 'zot:emojiReaction',
'expires' => 'zot:expires',
'directMessage' => 'zot:directMessage',
-
+ 'schema' => 'http://schema.org#',
+ 'PropertyValue' => 'schema:PropertyValue',
+ 'value' => 'schema:value',
+
'magicEnv' => [
'@id' => 'zot:magicEnv',
'@type' => '@id'
diff --git a/Zotlabs/Module/Articles.php b/Zotlabs/Module/Articles.php
index 2c43b4764..3f726ebb9 100644
--- a/Zotlabs/Module/Articles.php
+++ b/Zotlabs/Module/Articles.php
@@ -149,7 +149,7 @@ class Articles extends Controller {
}
$itemspage = get_pconfig(local_channel(),'system','itemspage');
- App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20));
+ App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 10));
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start']));
diff --git a/Zotlabs/Module/Cards.php b/Zotlabs/Module/Cards.php
index 3f0e93de5..c44f7942b 100644
--- a/Zotlabs/Module/Cards.php
+++ b/Zotlabs/Module/Cards.php
@@ -145,7 +145,7 @@ class Cards extends Controller {
$itemspage = get_pconfig(local_channel(),'system','itemspage');
- App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20));
+ App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 10));
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start']));
diff --git a/Zotlabs/Module/Cdav.php b/Zotlabs/Module/Cdav.php
index af40689c1..d7d57664c 100644
--- a/Zotlabs/Module/Cdav.php
+++ b/Zotlabs/Module/Cdav.php
@@ -10,6 +10,7 @@ require_once('include/event.php');
require_once('include/auth.php');
require_once('include/security.php');
+require_once('include/cdav.php');
class Cdav extends Controller {
@@ -156,6 +157,79 @@ class Cdav extends Controller {
}
}
+
+ // Track CDAV updates from remote clients
+
+ $httpmethod = $_SERVER['REQUEST_METHOD'];
+
+ if($httpmethod === 'PUT' || $httpmethod === 'DELETE') {
+
+ $httpuri = $_SERVER['REQUEST_URI'];
+
+ logger("debug: method: " . $httpmethod, LOGGER_DEBUG);
+ logger("debug: uri: " . $httpuri, LOGGER_DEBUG);
+
+ if(strpos($httpuri, 'cdav/addressbooks')) {
+ $sync = 'addressbook';
+ $cdavtable = 'addressbooks';
+ }
+ elseif(strpos($httpuri, 'cdav/calendars')) {
+ $sync = 'calendar';
+ $cdavtable = 'calendarinstances';
+ }
+ else
+ $sync = false;
+
+ if($sync) {
+
+ $uri = basename($httpuri);
+ $httpbody = file_get_contents('php://input');
+
+ logger("debug: body: " . $httpbody, LOGGER_DEBUG);
+
+ if($x = get_cdav_id($principalUri, explode("/", $httpuri)[4], $cdavtable)) {
+
+ $cdavdata = $this->get_cdav_data($x['id'], $cdavtable);
+
+ $etag = (isset($_SERVER['HTTP_IF_MATCH']) ? $_SERVER['HTTP_IF_MATCH'] : false);
+
+ // delete
+ if($httpmethod === 'DELETE' && $cdavdata['etag'] == $etag)
+ build_sync_packet($channel['channel_id'], [
+ $sync => [
+ 'action' => 'delete_card',
+ 'uri' => $cdavdata['uri'],
+ 'carduri' => $uri
+ ]
+ ]);
+ else {
+ if($etag) {
+ // update
+ if($cdavdata['etag'] !== $etag)
+ build_sync_packet($channel['channel_id'], [
+ $sync => [
+ 'action' => 'update_card',
+ 'uri' => $cdavdata['uri'],
+ 'carduri' => $uri,
+ 'card' => $httpbody
+ ]
+ ]);
+ }
+ else {
+ // new
+ build_sync_packet($channel['channel_id'], [
+ $sync => [
+ 'action' => 'import',
+ 'uri' => $cdavdata['uri'],
+ 'ids' => [ $uri ],
+ 'card' => $httpbody
+ ]
+ ]);
+ }
+ }
+ }
+ }
+ }
$principalBackend = new \Sabre\DAVACL\PrincipalBackend\PDO($pdo);
@@ -262,6 +336,14 @@ class Cdav extends Controller {
// set new calendar to be visible
set_pconfig(local_channel(), 'cdav_calendar' , $id[0], 1);
+
+ build_sync_packet($channel['channel_id'], [
+ 'calendar' => [
+ 'action' => 'create',
+ 'uri' => $calendarUri,
+ 'properties' => $properties
+ ]
+ ]);
}
//create new calendar object via ajax request
@@ -272,6 +354,8 @@ class Cdav extends Controller {
if(!cdav_perms($id[0],$calendars,true))
return;
+ $cdavdata = $this->get_cdav_data($id[0], 'calendarinstances');
+
$timezone = ((x($_POST,'timezone_select')) ? escape_tags(trim($_POST['timezone_select'])) : '');
$tz = (($timezone) ? $timezone : date_default_timezone_get());
@@ -327,9 +411,17 @@ class Cdav extends Controller {
$vcalendar->VEVENT->DTSTART['TZID'] = $tz;
$calendarData = $vcalendar->serialize();
-
$caldavBackend->createCalendarObject($id, $objectUri, $calendarData);
+ build_sync_packet($channel['channel_id'], [
+ 'calendar' => [
+ 'action' => 'import',
+ 'uri' => $cdavdata['uri'],
+ 'ids' => [ $objectUri ],
+ 'card' => $calendarData
+ ]
+ ]);
+
killme();
}
@@ -341,17 +433,24 @@ class Cdav extends Controller {
if(! cdav_perms($id[0],$calendars))
return;
+ $cdavdata = $this->get_cdav_data($id[0], 'calendarinstances');
+
$mutations = [
'{DAV:}displayname' => $_REQUEST['{DAV:}displayname'],
'{http://apple.com/ns/ical/}calendar-color' => $_REQUEST['color']
];
$patch = new \Sabre\DAV\PropPatch($mutations);
-
$caldavBackend->updateCalendar($id, $patch);
-
$patch->commit();
+ build_sync_packet($channel['channel_id'], [
+ 'calendar' => [
+ 'action' => 'edit',
+ 'uri' => $cdavdata['uri'],
+ 'mutations' => $mutations,
+ ]
+ ]);
}
//edit calendar object via ajax request
@@ -359,9 +458,11 @@ class Cdav extends Controller {
$id = explode(':', $_REQUEST['target']);
- if(!cdav_perms($id[0],$calendars,true))
+ if(! cdav_perms($id[0],$calendars,true))
return;
+ $cdavdata = $this->get_cdav_data($id[0], 'calendarinstances');
+
$timezone = ((x($_POST,'timezone_select')) ? escape_tags(trim($_POST['timezone_select'])) : '');
$tz = (($timezone) ? $timezone : date_default_timezone_get());
@@ -407,9 +508,17 @@ class Cdav extends Controller {
$vcalendar->VEVENT->LOCATION = $location;
$calendarData = $vcalendar->serialize();
-
$caldavBackend->updateCalendarObject($id, $uri, $calendarData);
+ build_sync_packet($channel['channel_id'], [
+ 'calendar' => [
+ 'action' => 'update_card',
+ 'uri' => $cdavdata['uri'],
+ 'carduri' => $uri,
+ 'card' => $calendarData
+ ]
+ ]);
+
killme();
}
@@ -418,13 +527,23 @@ class Cdav extends Controller {
$id = explode(':', $_REQUEST['target']);
- if(!cdav_perms($id[0],$calendars,true))
+ if(! cdav_perms($id[0],$calendars,true))
return;
+ $cdavdata = $this->get_cdav_data($id[0], 'calendarinstances');
+
$uri = $_REQUEST['uri'];
$caldavBackend->deleteCalendarObject($id, $uri);
+ build_sync_packet($channel['channel_id'], [
+ 'calendar' => [
+ 'action' => 'delete_card',
+ 'uri' => $cdavdata['uri'],
+ 'carduri' => $uri
+ ]
+ ]);
+
killme();
}
@@ -433,9 +552,11 @@ class Cdav extends Controller {
$id = [$_REQUEST['id'][0], $_REQUEST['id'][1]];
- if(!cdav_perms($id[0],$calendars,true))
+ if(! cdav_perms($id[0],$calendars,true))
return;
+ $cdavdata = $this->get_cdav_data($id[0], 'calendarinstances');
+
$timezone = ((x($_POST,'timezone_select')) ? escape_tags(trim($_POST['timezone_select'])) : '');
$tz = (($timezone) ? $timezone : date_default_timezone_get());
@@ -471,9 +592,17 @@ class Cdav extends Controller {
unset($vcalendar->VEVENT->DTEND);
$calendarData = $vcalendar->serialize();
-
$caldavBackend->updateCalendarObject($id, $uri, $calendarData);
+ build_sync_packet($channel['channel_id'], [
+ 'calendar' => [
+ 'action' => 'update_card',
+ 'uri' => $cdavdata['uri'],
+ 'carduri' => $uri,
+ 'card' => $calendarData
+ ]
+ ]);
+
killme();
}
@@ -523,6 +652,14 @@ class Cdav extends Controller {
$properties = ['{DAV:}displayname' => $_REQUEST['{DAV:}displayname']];
$carddavBackend->createAddressBook($principalUri, $addressbookUri, $properties);
+
+ build_sync_packet($channel['channel_id'], [
+ 'addressbook' => [
+ 'action' => 'create',
+ 'uri' => $addressbookUri,
+ 'properties' => $properties
+ ]
+ ]);
}
//edit addressbook
@@ -533,21 +670,32 @@ class Cdav extends Controller {
if(! cdav_perms($id,$addressbooks))
return;
+ $cdavdata = $this->get_cdav_data($id, 'addressbooks');
+
$mutations = [
'{DAV:}displayname' => $_REQUEST['{DAV:}displayname']
];
$patch = new \Sabre\DAV\PropPatch($mutations);
-
$carddavBackend->updateAddressBook($id, $patch);
-
$patch->commit();
+
+ build_sync_packet($channel['channel_id'], [
+ 'addressbook' => [
+ 'action' => 'edit',
+ 'uri' => $cdavdata['uri'],
+ 'mutations' => $mutations,
+ ]
+ ]);
}
//create addressbook card
if($_REQUEST['create'] && $_REQUEST['target'] && $_REQUEST['fn']) {
+
$id = $_REQUEST['target'];
+ $cdavdata = $this->get_cdav_data($id, 'addressbooks');
+
do {
$duplicate = false;
$uri = random_string(40) . '.vcf';
@@ -569,86 +717,21 @@ class Cdav extends Controller {
'N' => array_reverse(explode(' ', $fn))
]);
- $org = $_REQUEST['org'];
- if($org) {
- $vcard->ORG = $org;
- }
-
- $title = $_REQUEST['title'];
- if($title) {
- $vcard->TITLE = $title;
- }
-
- $tel = $_REQUEST['tel'];
- $tel_type = $_REQUEST['tel_type'];
- if($tel) {
- $i = 0;
- foreach($tel as $item) {
- if($item) {
- $vcard->add('TEL', $item, ['type' => $tel_type[$i]]);
- }
- $i++;
- }
- }
+ $fields = $this->request_to_array($_REQUEST);
- $email = $_REQUEST['email'];
- $email_type = $_REQUEST['email_type'];
- if($email) {
- $i = 0;
- foreach($email as $item) {
- if($item) {
- $vcard->add('EMAIL', $item, ['type' => $email_type[$i]]);
- }
- $i++;
- }
- }
-
- $impp = $_REQUEST['impp'];
- $impp_type = $_REQUEST['impp_type'];
- if($impp) {
- $i = 0;
- foreach($impp as $item) {
- if($item) {
- $vcard->add('IMPP', $item, ['type' => $impp_type[$i]]);
- }
- $i++;
- }
- }
-
- $url = $_REQUEST['url'];
- $url_type = $_REQUEST['url_type'];
- if($url) {
- $i = 0;
- foreach($url as $item) {
- if($item) {
- $vcard->add('URL', $item, ['type' => $url_type[$i]]);
- }
- $i++;
- }
- }
-
- $adr = $_REQUEST['adr'];
- $adr_type = $_REQUEST['adr_type'];
-
- if($adr) {
- $i = 0;
- foreach($adr as $item) {
- if($item) {
- $vcard->add('ADR', $item, ['type' => $adr_type[$i]]);
- }
- $i++;
- }
- }
-
- $note = $_REQUEST['note'];
- if($note) {
- $vcard->NOTE = $note;
- }
+ process_cdav_card($fields, $vcard);
$cardData = $vcard->serialize();
-
$carddavBackend->createCard($id, $uri, $cardData);
+ build_sync_packet($channel['channel_id'], [
+ 'addressbook' => [
+ 'action' => 'import',
+ 'uri' => $cdavdata['uri'],
+ 'ids' => [ $uri ],
+ 'card' => $cardData
+ ]
+ ]);
}
//edit addressbook card
@@ -656,9 +739,11 @@ class Cdav extends Controller {
$id = $_REQUEST['target'];
- if(!cdav_perms($id,$addressbooks))
+ if(! cdav_perms($id,$addressbooks))
return;
+ $cdavdata = $this->get_cdav_data($id, 'addressbooks');
+
$uri = $_REQUEST['uri'];
$object = $carddavBackend->getCard($id, $uri);
@@ -670,113 +755,23 @@ class Cdav extends Controller {
$vcard->N = array_reverse(explode(' ', $fn));
}
- $org = $_REQUEST['org'];
- if($org) {
- $vcard->ORG = $org;
- }
- else {
- unset($vcard->ORG);
- }
-
- $title = $_REQUEST['title'];
- if($title) {
- $vcard->TITLE = $title;
- }
- else {
- unset($vcard->TITLE);
- }
-
- $tel = $_REQUEST['tel'];
- $tel_type = $_REQUEST['tel_type'];
- if($tel) {
- $i = 0;
- unset($vcard->TEL);
- foreach($tel as $item) {
- if($item) {
- $vcard->add('TEL', $item, ['type' => $tel_type[$i]]);
- }
- $i++;
- }
- }
- else {
- unset($vcard->TEL);
- }
-
- $email = $_REQUEST['email'];
- $email_type = $_REQUEST['email_type'];
- if($email) {
- $i = 0;
- unset($vcard->EMAIL);
- foreach($email as $item) {
- if($item) {
- $vcard->add('EMAIL', $item, ['type' => $email_type[$i]]);
- }
- $i++;
- }
- }
- else {
- unset($vcard->EMAIL);
- }
-
- $impp = $_REQUEST['impp'];
- $impp_type = $_REQUEST['impp_type'];
- if($impp) {
- $i = 0;
- unset($vcard->IMPP);
- foreach($impp as $item) {
- if($item) {
- $vcard->add('IMPP', $item, ['type' => $impp_type[$i]]);
- }
- $i++;
- }
- }
- else {
- unset($vcard->IMPP);
- }
-
- $url = $_REQUEST['url'];
- $url_type = $_REQUEST['url_type'];
- if($url) {
- $i = 0;
- unset($vcard->URL);
- foreach($url as $item) {
- if($item) {
- $vcard->add('URL', $item, ['type' => $url_type[$i]]);
- }
- $i++;
- }
- }
- else {
- unset($vcard->URL);
- }
-
- $adr = $_REQUEST['adr'];
- $adr_type = $_REQUEST['adr_type'];
- if($adr) {
- $i = 0;
- unset($vcard->ADR);
- foreach($adr as $item) {
- if($item) {
- $vcard->add('ADR', $item, ['type' => $adr_type[$i]]);
- }
- $i++;
- }
- }
- else {
- unset($vcard->ADR);
- }
+ $fields = $this->request_to_array($_REQUEST);
- $note = $_REQUEST['note'];
- if($note) {
- $vcard->NOTE = $note;
- }
- else {
- unset($vcard->NOTE);
- }
+ process_cdav_card($fields, $vcard, true);
$cardData = $vcard->serialize();
$carddavBackend->updateCard($id, $uri, $cardData);
+
+ build_sync_packet($channel['channel_id'], [
+ 'addressbook' => [
+ 'action' => 'update_card',
+ 'uri' => $cdavdata['uri'],
+ 'carduri' => $uri,
+ 'card' => $cardData
+ ]
+ ]);
+
}
//delete addressbook card
@@ -784,12 +779,22 @@ class Cdav extends Controller {
$id = $_REQUEST['target'];
- if(!cdav_perms($id,$addressbooks))
+ if(! cdav_perms($id,$addressbooks))
return;
+ $cdavdata = $this->get_cdav_data($id, 'addressbooks');
+
$uri = $_REQUEST['uri'];
$carddavBackend->deleteCard($id, $uri);
+
+ build_sync_packet($channel['channel_id'], [
+ 'addressbook' => [
+ 'action' => 'delete_card',
+ 'uri' => $cdavdata['uri'],
+ 'carduri' => $uri
+ ]
+ ]);
}
}
@@ -799,6 +804,8 @@ class Cdav extends Controller {
$src = $_FILES['userfile']['tmp_name'];
if($src) {
+
+ $carddata = @file_get_contents($src);
if($_REQUEST['c_upload']) {
if($_REQUEST['target'] == 'channel_calendar') {
@@ -816,72 +823,38 @@ class Cdav extends Controller {
$ext = 'ics';
$table = 'calendarobjects';
$column = 'calendarid';
- $objects = new \Sabre\VObject\Splitter\ICalendar(@file_get_contents($src));
+ $sync = 'calendar';
+ $objects = new \Sabre\VObject\Splitter\ICalendar($carddata);
$profile = \Sabre\VObject\Node::PROFILE_CALDAV;
$backend = new \Sabre\CalDAV\Backend\PDO($pdo);
+
+ $cdavdata = $this->get_cdav_data($id, 'calendarinstances');
}
if($_REQUEST['a_upload']) {
- $id[] = intval($_REQUEST['target']);
+ $id = intval($_REQUEST['target']);
$ext = 'vcf';
$table = 'cards';
$column = 'addressbookid';
- $objects = new \Sabre\VObject\Splitter\VCard(@file_get_contents($src));
+ $sync = 'addressbook';
+ $objects = new \Sabre\VObject\Splitter\VCard($carddata);
$profile = \Sabre\VObject\Node::PROFILE_CARDDAV;
$backend = new \Sabre\CardDAV\Backend\PDO($pdo);
+
+ $cdavdata = $this->get_cdav_data($id, 'addressbooks');
}
-
- while ($object = $objects->getNext()) {
-
- if($_REQUEST['a_upload']) {
- $object = $object->convert(\Sabre\VObject\Document::VCARD40);
- }
-
- $ret = $object->validate($profile & \Sabre\VObject\Node::REPAIR);
-
- //level 3 Means that the document is invalid,
- //level 2 means a warning. A warning means it's valid but it could cause interopability issues,
- //level 1 means that there was a problem earlier, but the problem was automatically repaired.
-
- if($ret[0]['level'] < 3) {
- do {
- $duplicate = false;
- $objectUri = random_string(40) . '.' . $ext;
-
- $r = q("SELECT uri FROM $table WHERE $column = %d AND uri = '%s' LIMIT 1",
- dbesc($id[0]),
- dbesc($objectUri)
- );
-
- if (count($r))
- $duplicate = true;
- } while ($duplicate == true);
-
- if($_REQUEST['c_upload']) {
- $backend->createCalendarObject($id, $objectUri, $object->serialize());
- }
-
- if($_REQUEST['a_upload']) {
- $backend->createCard($id[0], $objectUri, $object->serialize());
- }
- }
- else {
- if($_REQUEST['c_upload']) {
- notice( '<strong>' . t('INVALID EVENT DISMISSED!') . '</strong>' . EOL .
- '<strong>' . t('Summary: ') . '</strong>' . (($object->VEVENT->SUMMARY) ? $object->VEVENT->SUMMARY : t('Unknown')) . EOL .
- '<strong>' . t('Date: ') . '</strong>' . (($object->VEVENT->DTSTART) ? $object->VEVENT->DTSTART : t('Unknown')) . EOL .
- '<strong>' . t('Reason: ') . '</strong>' . $ret[0]['message'] . EOL
- );
- }
-
- if($_REQUEST['a_upload']) {
- notice( '<strong>' . t('INVALID CARD DISMISSED!') . '</strong>' . EOL .
- '<strong>' . t('Name: ') . '</strong>' . (($object->FN) ? $object->FN : t('Unknown')) . EOL .
- '<strong>' . t('Reason: ') . '</strong>' . $ret[0]['message'] . EOL
- );
- }
- }
- }
+
+ $ids = [];
+ import_cdav_card($id, $ext, $table, $column, $objects, $profile, $backend, $ids, true);
+
+ build_sync_packet($channel['channel_id'], [
+ $sync => [
+ 'action' => 'import',
+ 'uri' => $cdavdata['uri'],
+ 'ids' => $ids,
+ 'card' => $carddata
+ ]
+ ]);
}
@unlink($src);
}
@@ -1190,7 +1163,18 @@ class Cdav extends Controller {
if(! cdav_perms($id,$calendars))
killme();
- set_pconfig(local_channel(), 'cdav_calendar' , argv(3), argv(4));
+ $cdavdata = $this->get_cdav_data($id, 'calendarinstances');
+
+ set_pconfig(local_channel(), 'cdav_calendar', $id, argv(4));
+
+ build_sync_packet(local_channel(), [
+ 'calendar' => [
+ 'action' => 'switch',
+ 'uri' => $cdavdata['uri'],
+ 'switch' => intval(argv(4))
+ ]
+ ]);
+
killme();
}
@@ -1201,7 +1185,18 @@ class Cdav extends Controller {
if(! cdav_perms($id[0],$calendars))
killme();
+ // get metadata before we delete it
+ $cdavdata = $this->get_cdav_data($id[0], 'calendarinstances');
+
$caldavBackend->deleteCalendar($id);
+
+ build_sync_packet($channel['channel_id'], [
+ 'calendar' => [
+ 'action' => 'drop',
+ 'uri' => $cdavdata['uri']
+ ]
+ ]);
+
killme();
}
@@ -1408,7 +1403,19 @@ class Cdav extends Controller {
if(! cdav_perms($id,$addressbooks))
return;
+ // get metadata before we delete it
+ $cdavdata = $this->get_cdav_data($id, 'addressbooks');
+
$carddavBackend->deleteAddressBook($id);
+
+ if($cdavdata)
+ build_sync_packet($channel['channel_id'], [
+ 'addressbook' => [
+ 'action' => 'drop',
+ 'uri' => $cdavdata['uri']
+ ]
+ ]);
+
killme();
}
@@ -1460,4 +1467,36 @@ class Cdav extends Controller {
}
+ function get_cdav_data($id, $table) {
+
+ $r = q("SELECT * FROM $table WHERE id = %d LIMIT 1",
+ intval($id)
+ );
+
+ if(! $r)
+ return false;
+
+ return $r[0];
+ }
+
+ function request_to_array($req) {
+
+ $f = [];
+
+ $f['org'] = $req['org'];
+ $f['title'] = $req['title'];
+ $f['tel'] = $req['tel'];
+ $f['tel_type'] = $req['tel_type'];
+ $f['email'] = $req['email'];
+ $f['email_type'] = $req['email_type'];
+ $f['impp'] = $req['impp'];
+ $f['impp_type'] = $req['impp_type'];
+ $f['url'] = $req['url'];
+ $f['url_type'] = $req['url_type'];
+ $f['adr'] = $req['adr'];
+ $f['adr_type'] = $req['adr_type'];
+ $f['note'] = $req['note'];
+
+ return $f;
+ }
}
diff --git a/Zotlabs/Module/Channel.php b/Zotlabs/Module/Channel.php
index d975ac1bf..307be048a 100644
--- a/Zotlabs/Module/Channel.php
+++ b/Zotlabs/Module/Channel.php
@@ -239,8 +239,12 @@ class Channel extends Controller {
/**
* Get permissions SQL - if $remote_contact is true, our remote user has been pre-verified and we already have fetched his/her groups
*/
-
- $item_normal = item_normal();
+
+ $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_deleted = 0
+ and item.item_unpublished = 0 and item.item_pending_remove = 0
+ and item.item_blocked = 0 ";
+ if (! $is_owner)
+ $item_normal .= "and item.item_delayed = 0 ";
$item_normal_update = item_normal_update();
$sql_extra = item_permissions_sql(App::$profile['profile_uid']);
@@ -330,7 +334,7 @@ class Channel extends Controller {
$itemspage = get_pconfig(local_channel(),'system','itemspage');
- App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20));
+ App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 10));
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start']));
if($noscript_content || $load) {
@@ -419,6 +423,7 @@ class Channel extends Controller {
'$nouveau' => '0',
'$wall' => '1',
'$fh' => '0',
+ '$dm' => '0',
'$static' => $static,
'$page' => ((App::$pager['page'] != 1) ? App::$pager['page'] : 1),
'$search' => $search,
@@ -437,36 +442,11 @@ class Channel extends Controller {
}
- $update_unseen = '';
-
- if($page_mode === 'list') {
-
- /**
- * in "list mode", only mark the parent item and any like activities as "seen".
- * We won't distinguish between comment likes and post likes. The important thing
- * is that the number of unseen comments will be accurate. The SQL to separate the
- * comment likes could also get somewhat hairy.
- */
-
- if($parents_str) {
- $update_unseen = " AND ( id IN ( " . dbesc($parents_str) . " )";
- $update_unseen .= " OR ( parent IN ( " . dbesc($parents_str) . " ) AND verb in ( '" . dbesc(ACTIVITY_LIKE) . "','" . dbesc(ACTIVITY_DISLIKE) . "' ))) ";
- }
- }
- else {
- if($parents_str) {
- $update_unseen = " AND parent IN ( " . dbesc($parents_str) . " )";
- }
- }
-
- if($is_owner && $update_unseen) {
- $x = [ 'channel_id' => local_channel(), 'update' => 'unset' ];
- call_hooks('update_unseen',$x);
- if($x['update'] === 'unset' || intval($x['update'])) {
- $r = q("UPDATE item SET item_unseen = 0 where item_unseen = 1 and item_wall = 1 AND uid = %d $update_unseen",
- intval(local_channel())
- );
- }
+ // Add pinned content
+ if(! x($_REQUEST,'mid') && ! $search) {
+ $pinned = new \Zotlabs\Widget\Pinned;
+ $r = $pinned->widget(intval(App::$profile['profile_uid']), [ITEM_TYPE_POST]);
+ $o .= $r['html'];
}
$mode = (($search) ? 'search' : 'channel');
diff --git a/Zotlabs/Module/Channel_calendar.php b/Zotlabs/Module/Channel_calendar.php
index 7d75a7e41..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');
@@ -16,7 +18,7 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
if(! local_channel())
return;
-
+
$event_id = ((x($_POST,'event_id')) ? intval($_POST['event_id']) : 0);
$event_hash = ((x($_POST,'event_hash')) ? $_POST['event_hash'] : '');
@@ -27,15 +29,19 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
if(($xchan) && ($xchan !== get_observer_hash()))
return;
- $timezone = ((x($_POST,'timezone_select')) ? escape_tags(trim($_POST['timezone_select'])) : '');
- $tz = (($timezone) ? $timezone : date_default_timezone_get());
-
$categories = escape_tags(trim($_POST['categories']));
+ // allday events have adjust = 0, normal events have adjust = 1
$adjust = intval($_POST['adjust']);
- $start = datetime_convert('UTC', 'UTC', escape_tags($_REQUEST['dtstart']));
- $finish = datetime_convert('UTC', 'UTC', escape_tags($_REQUEST['dtend']));
+ $start = datetime_convert((($adjust) ? $tz : 'UTC'), 'UTC', escape_tags($_REQUEST['dtstart']));
+ $finish = datetime_convert((($adjust) ? $tz : 'UTC'), 'UTC', escape_tags($_REQUEST['dtend']));
+
+ $timezone = ((x($_POST,'timezone_select')) ? escape_tags(trim($_POST['timezone_select'])) : '');
+ $tz = (($timezone) ? $timezone : date_default_timezone_get());
+
+ if(! $adjust)
+ $tz = 'UTC';
$summary = escape_tags(trim($_POST['summary']));
$desc = escape_tags(trim($_POST['desc']));
@@ -184,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));
}
}
}
@@ -337,21 +343,16 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
}
$events = [];
-
+
if($r) {
foreach($r as $rr) {
- $tz = get_iconfig($rr, 'event', 'timezone');
-
- if(! $tz)
- $tz = 'UTC';
-
- $start = (($rr['adjust']) ? datetime_convert($tz, date_default_timezone_get(), $rr['dtstart'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtstart'], 'c'));
+ $start = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtstart'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtstart'], 'c'));
if ($rr['nofinish']){
$end = null;
} else {
- $end = (($rr['adjust']) ? datetime_convert($tz, date_default_timezone_get(), $rr['dtend'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtend'], 'c'));
+ $end = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtend'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtend'], 'c'));
}
$catsenabled = feature_enabled(local_channel(),'categories');
@@ -371,6 +372,11 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
$drop = array(z_root().'/events/drop/'.$rr['event_hash'],t('Delete event'),'','');
+ $tz = get_iconfig($rr, 'event', 'timezone');
+
+ if(! $tz)
+ $tz = 'UTC';
+
$events[] = array(
'calendar_id' => 'channel_calendar',
'rw' => true,
@@ -426,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),
@@ -475,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/Chanview.php b/Zotlabs/Module/Chanview.php
index 2e653d030..12e1891d4 100644
--- a/Zotlabs/Module/Chanview.php
+++ b/Zotlabs/Module/Chanview.php
@@ -1,31 +1,35 @@
<?php
namespace Zotlabs\Module;
-require_once('include/zot.php');
+use App;
+use Zotlabs\Lib\Libzot;
+use Zotlabs\Lib\Webfinger;
+use Zotlabs\Lib\Zotfinger;
+
class Chanview extends \Zotlabs\Web\Controller {
function get() {
- $observer = \App::get_observer();
+ $observer = App::get_observer();
$xchan = null;
$r = null;
if($_REQUEST['hash']) {
- $r = q("select * from xchan where xchan_hash = '%s' limit 1",
+ $r = q("select * from xchan where xchan_hash = '%s'",
dbesc($_REQUEST['hash'])
);
}
if($_REQUEST['address']) {
- $r = q("select * from xchan where xchan_addr = '%s' limit 1",
+ $r = q("select * from xchan where xchan_addr = '%s'",
dbesc(punify($_REQUEST['address']))
);
}
elseif(local_channel() && intval($_REQUEST['cid'])) {
$r = q("SELECT abook.*, xchan.*
FROM abook left join xchan on abook_xchan = xchan_hash
- WHERE abook_channel = %d and abook_id = %d LIMIT 1",
+ WHERE abook_channel = %d and abook_id = %d",
intval(local_channel()),
intval($_REQUEST['cid'])
);
@@ -35,12 +39,12 @@ class Chanview extends \Zotlabs\Web\Controller {
// if somebody re-installed they will have more than one xchan, use the most recent name date as this is
// the most useful consistently ascending table item we have.
- $r = q("select * from xchan where xchan_url = '%s' order by xchan_name_date desc limit 1",
+ $r = q("select * from xchan where xchan_url = '%s' order by xchan_name_date desc",
dbesc($_REQUEST['url'])
);
}
if($r) {
- \App::$poi = $r[0];
+ App::$poi = Libzot::zot_record_preferred($r, 'xchan_network');
}
@@ -49,74 +53,63 @@ class Chanview extends \Zotlabs\Web\Controller {
// address, we can and should try to import it. If it's just a hash, we can't continue, but we
// probably wouldn't have a hash if we don't already have an xchan for this channel.
- if(! \App::$poi) {
+ if(! App::$poi) {
logger('mod_chanview: fallback');
- // This is hackish - construct a zot address from the url
- if($_REQUEST['url']) {
- if(preg_match('/https?\:\/\/(.*?)(\/channel\/|\/profile\/)(.*?)$/ism',$_REQUEST['url'],$matches)) {
- $_REQUEST['address'] = $matches[3] . '@' . $matches[1];
+
+ if($_REQUEST['address']) {
+ $href = Webfinger::zot_url(punify($_REQUEST['address']));
+ if($href) {
+ $_REQUEST['url'] = $href;
}
- logger('mod_chanview: constructed address ' . print_r($matches,true));
}
$r = null;
- if($_REQUEST['address']) {
- $j = \Zotlabs\Zot\Finger::run($_REQUEST['address'],null);
- if($j['success']) {
- import_xchan($j);
- $r = q("select * from xchan where xchan_addr = '%s' limit 1",
- dbesc($_REQUEST['address'])
+ if($_REQUEST['url']) {
+
+ $zf = Zotfinger::exec($_REQUEST['url'], null);
+
+ if(array_path_exists('signature/signer',$zf) && $zf['signature']['signer'] === $_REQUEST['url'] && intval($zf['signature']['header_valid'])) {
+ Libzot::import_xchan($j);
+ $r = q("select * from xchan where xchan_url = '%s'",
+ dbesc($_REQUEST['url'])
);
if($r) {
- \App::$poi = $r[0];
+ App::$poi = Libzot::zot_record_preferred($r, 'xchan_network');
}
}
if(! $r) {
- if(discover_by_webbie($_REQUEST['address'])) {
- $r = q("select * from xchan where xchan_addr = '%s' limit 1",
- dbesc($_REQUEST['address'])
+ if(discover_by_webbie($_REQUEST['url'])) {
+ $r = q("select * from xchan where xchan_url = '%s'",
+ dbesc($_REQUEST['url'])
);
if($r) {
- \App::$poi = $r[0];
+ App::$poi = Libzot::zot_record_preferred($r, 'xchan_network');
}
}
}
}
}
- if(! \App::$poi) {
-
- // We don't know who this is, and we can't figure it out from the URL
- // On the plus side, there's a good chance we know somebody else at that
- // hub so sending them there with a Zid will probably work anyway.
-
- $url = ($_REQUEST['url']);
- if(! $url) {
- notice( t('Channel not found.') . EOL);
- return;
- }
- if($observer)
- $url = zid($url);
-
+ if(! App::$poi) {
+ notice( t('Channel not found.') . EOL);
+ return;
}
$is_zot = false;
$connected = false;
- if (\App::$poi) {
- $url = \App::$poi['xchan_url'];
- if(in_array(\App::$poi['xchan_network'], ['zot', 'zot6'])) {
- $is_zot = true;
- }
- if(local_channel()) {
- $c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s' limit 1",
- intval(local_channel()),
- dbesc(\App::$poi['xchan_hash'])
- );
- if($c)
- $connected = true;
- }
+ $url = App::$poi['xchan_url'];
+ if(in_array(App::$poi['xchan_network'], ['zot', 'zot6'])) {
+ $is_zot = true;
+ }
+ if(local_channel()) {
+ $c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s' limit 1",
+ intval(local_channel()),
+ dbesc(App::$poi['xchan_hash'])
+ );
+ if($c)
+ $connected = true;
}
// We will load the chanview template if it's a foreign network,
diff --git a/Zotlabs/Module/Chat.php b/Zotlabs/Module/Chat.php
index db77e2612..28e775f9d 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']);
@@ -199,7 +197,7 @@ class Chat extends Controller {
$cipher = get_pconfig(local_channel(),'system','default_cipher');
if(! $cipher)
- $cipher = 'aes256';
+ $cipher = 'AES-128-CCM';
$o = replace_macros(get_markup_template('chat.tpl'),array(
diff --git a/Zotlabs/Module/Connect.php b/Zotlabs/Module/Connect.php
index 62d3af840..31da42035 100644
--- a/Zotlabs/Module/Connect.php
+++ b/Zotlabs/Module/Connect.php
@@ -28,10 +28,6 @@ class Connect extends Controller {
$channel_id = App::$data['channel']['channel_id'];
- if(! Apps::system_app_installed($channel_id, 'Premium Channel')) {
- return;
- }
-
profile_load($which,'');
}
@@ -42,10 +38,6 @@ class Connect extends Controller {
$channel_id = App::$data['channel']['channel_id'];
- if(! Apps::system_app_installed($channel_id, 'Premium Channel')) {
- return;
- }
-
$edit = ((local_channel() && (local_channel() == $channel_id)) ? true : false);
if($edit) {
@@ -97,15 +89,6 @@ class Connect extends Controller {
$channel_id = App::$data['channel']['channel_id'];
- if(! Apps::system_app_installed($channel_id, 'Premium Channel')) {
- //Do not display any associated widgets at this point
- App::$pdl = '';
-
- $o = '<b>' . t('Premium Channel App') . ' (' . t('Not Installed') . '):</b><br>';
- $o .= t('Allows you to set restrictions and terms on those that connect with your channel');
- return $o;
- }
-
$edit = ((local_channel() && (local_channel() == $channel_id)) ? true : false);
$text = get_pconfig($channel_id,'system','selltext');
diff --git a/Zotlabs/Module/Connections.php b/Zotlabs/Module/Connections.php
index f6133d5f8..7dc301623 100644
--- a/Zotlabs/Module/Connections.php
+++ b/Zotlabs/Module/Connections.php
@@ -34,7 +34,7 @@ class Connections extends \Zotlabs\Web\Controller {
}
nav_set_selected('Connections');
-
+
$active = false;
$blocked = false;
$hidden = false;
@@ -283,6 +283,28 @@ class Connections extends \Zotlabs\Web\Controller {
if(! intval(get_abconfig(local_channel(),$rr['xchan_hash'],'their_perms','post_comments'))) {
$oneway = true;
}
+
+ $perminfo['connpermcount']=0;
+ $perminfo['connperms']=t('Accepts').': ';
+ if(intval(get_abconfig(local_channel(),$rr['xchan_hash'],'their_perms','post_comments'))) {
+ $perminfo['connpermcount']++;
+ $perminfo['connperms'] .= t('Comments');
+ }
+ if(intval(get_abconfig(local_channel(),$rr['xchan_hash'],'their_perms','send_stream'))) {
+ $perminfo['connpermcount']++;
+ $perminfo['connperms'] = ($perminfo['connperms']) ? $perminfo['connperms'] . ', ' : $perminfo['connperms'] ;
+ $perminfo['connperms'] .= t('Stream items');
+ }
+ if(intval(get_abconfig(local_channel(),$rr['xchan_hash'],'their_perms','post_wall'))) {
+ $perminfo['connpermcount']++;
+ $perminfo['connperms'] = ($perminfo['connperms']) ? $perminfo['connperms'] . ', ' : $perminfo['connperms'] ;
+ $perminfo['connperms'] .= t('Wall posts');
+ }
+
+ if ($perminfo['connpermcount'] == 0) {
+ $perminfo['connperms'] .= t('Nothing');
+ }
+
foreach($status as $str) {
if(!$str)
@@ -323,6 +345,7 @@ class Connections extends \Zotlabs\Web\Controller {
'recent_label' => t('Recent activity'),
'recentlink' => z_root() . '/network/?f=&cid=' . intval($rr['abook_id']) . '&name=' . $rr['xchan_name'],
'oneway' => $oneway,
+ 'perminfo' => $perminfo,
'connect' => (intval($rr['abook_not_here']) ? t('Connect') : ''),
'follow' => z_root() . '/follow/?f=&url=' . urlencode($rr['xchan_hash']) . '&interactive=0',
'connect_hover' => t('Connect at this location')
diff --git a/Zotlabs/Module/Connedit.php b/Zotlabs/Module/Connedit.php
index acd7cb769..0fc807d42 100644
--- a/Zotlabs/Module/Connedit.php
+++ b/Zotlabs/Module/Connedit.php
@@ -7,8 +7,16 @@ namespace Zotlabs\Module;
*
*/
+use App;
use Zotlabs\Lib\Apps;
use Zotlabs\Lib\Libzot;
+use Zotlabs\Lib\Libsync;
+use Zotlabs\Daemon\Master;
+use Zotlabs\Web\Controller;
+use Zotlabs\Access\Permissions;
+use Zotlabs\Access\PermissionLimits;
+use Zotlabs\Web\HTTPHeaders;
+use Zotlabs\Lib\Permcat;
require_once('include/socgraph.php');
require_once('include/selectors.php');
@@ -16,7 +24,7 @@ require_once('include/group.php');
require_once('include/photos.php');
-class Connedit extends \Zotlabs\Web\Controller {
+class Connedit extends Controller {
/* @brief Initialize the connection-editor
*
@@ -36,12 +44,12 @@ class Connedit extends \Zotlabs\Web\Controller {
intval(argv(1))
);
if($r) {
- \App::$poi = array_shift($r);
+ App::$poi = array_shift($r);
}
}
- $channel = \App::get_channel();
+ $channel = App::get_channel();
if($channel)
head_set_icon($channel['xchan_photo_s']);
@@ -61,7 +69,7 @@ class Connedit extends \Zotlabs\Web\Controller {
if(! $contact_id)
return;
- $channel = \App::get_channel();
+ $channel = App::get_channel();
// TODO if configured for hassle-free permissions, we'll post the form with ajax as soon as the
// connection enable is toggled to a special autopost url and set permissions immediately, leaving
@@ -140,7 +148,7 @@ class Connedit extends \Zotlabs\Web\Controller {
$rating_text = trim(escape_tags($_REQUEST['rating_text']));
- $all_perms = \Zotlabs\Access\Permissions::Perms();
+ $all_perms = Permissions::Perms();
if($all_perms) {
foreach($all_perms as $perm => $desc) {
@@ -212,7 +220,7 @@ class Connedit extends \Zotlabs\Web\Controller {
$record = $z[0]['xlink_id'];
}
if($record) {
- \Zotlabs\Daemon\Master::Summon(array('Ratenotif','rating',$record));
+ Master::Summon(array('Ratenotif','rating',$record));
}
}
@@ -227,7 +235,7 @@ class Connedit extends \Zotlabs\Web\Controller {
// request. The workaround is to approve the connection, then go back and
// adjust permissions as desired.
- $p = \Zotlabs\Access\Permissions::connect_perms(local_channel());
+ $p = Permissions::connect_perms(local_channel());
$my_perms = $p['perms'];
if($my_perms) {
foreach($my_perms as $k => $v) {
@@ -257,12 +265,12 @@ class Connedit extends \Zotlabs\Web\Controller {
else
notice( t('Failed to update connection record.') . EOL);
- if(! intval(\App::$poi['abook_self'])) {
+ if(! intval(App::$poi['abook_self'])) {
if($new_friend) {
- \Zotlabs\Daemon\Master::Summon( [ 'Notifier', 'permission_accept', $contact_id ] );
+ Master::Summon( [ 'Notifier', 'permission_accept', $contact_id ] );
}
- \Zotlabs\Daemon\Master::Summon( [
+ Master::Summon( [
'Notifier',
(($new_friend) ? 'permission_create' : 'permission_update'),
$contact_id
@@ -275,7 +283,7 @@ class Connedit extends \Zotlabs\Web\Controller {
require_once('include/group.php');
$g = group_rec_byhash(local_channel(),$default_group);
if($g)
- group_add_member(local_channel(),'',\App::$poi['abook_xchan'],$g['id']);
+ group_add_member(local_channel(),'',App::$poi['abook_xchan'],$g['id']);
}
// Check if settings permit ("post new friend activity" is allowed, and
@@ -299,19 +307,19 @@ class Connedit extends \Zotlabs\Web\Controller {
$xarr['item_private'] = (($xarr['allow_cid']||$xarr['allow_gid']||$xarr['deny_cid']||$xarr['deny_gid']) ? 1 : 0);
$obj = array(
'type' => ACTIVITY_OBJ_PERSON,
- 'title' => \App::$poi['xchan_name'],
- 'id' => \App::$poi['xchan_hash'],
+ 'title' => App::$poi['xchan_name'],
+ 'id' => App::$poi['xchan_hash'],
'link' => array(
- array('rel' => 'alternate', 'type' => 'text/html', 'href' => \App::$poi['xchan_url']),
- array('rel' => 'photo', 'type' => \App::$poi['xchan_photo_mimetype'], 'href' => \App::$poi['xchan_photo_l'])
+ array('rel' => 'alternate', 'type' => 'text/html', 'href' => App::$poi['xchan_url']),
+ array('rel' => 'photo', 'type' => App::$poi['xchan_photo_mimetype'], 'href' => App::$poi['xchan_photo_l'])
),
);
$xarr['obj'] = json_encode($obj);
$xarr['obj_type'] = ACTIVITY_OBJ_PERSON;
- $xarr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . t('is now connected to') . ' ' . '[zrl=' . \App::$poi['xchan_url'] . ']' . \App::$poi['xchan_name'] . '[/zrl]';
+ $xarr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . t('is now connected to') . ' ' . '[zrl=' . App::$poi['xchan_url'] . ']' . App::$poi['xchan_name'] . '[/zrl]';
- $xarr['body'] .= "\n\n\n" . '[zrl=' . \App::$poi['xchan_url'] . '][zmg=80x80]' . \App::$poi['xchan_photo_m'] . '[/zmg][/zrl]';
+ $xarr['body'] .= "\n\n\n" . '[zrl=' . App::$poi['xchan_url'] . '][zmg=80x80]' . App::$poi['xchan_photo_m'] . '[/zmg][/zrl]';
post_activity_item($xarr);
@@ -319,7 +327,7 @@ class Connedit extends \Zotlabs\Web\Controller {
// pull in a bit of content if there is any to pull in
- \Zotlabs\Daemon\Master::Summon(array('Onepoll',$contact_id));
+ Master::Summon(array('Onepoll',$contact_id));
}
@@ -332,11 +340,11 @@ class Connedit extends \Zotlabs\Web\Controller {
intval($contact_id)
);
if($r) {
- \App::$poi = $r[0];
+ App::$poi = $r[0];
}
if($new_friend) {
- $arr = array('channel_id' => local_channel(), 'abook' => \App::$poi);
+ $arr = array('channel_id' => local_channel(), 'abook' => App::$poi);
call_hooks('accept_follow', $arr);
}
@@ -356,23 +364,23 @@ class Connedit extends \Zotlabs\Web\Controller {
function connedit_clone(&$a) {
- if(! \App::$poi)
+ if(! App::$poi)
return;
- $channel = \App::get_channel();
+ $channel = App::get_channel();
$r = q("SELECT abook.*, xchan.*
FROM abook left join xchan on abook_xchan = xchan_hash
WHERE abook_channel = %d and abook_id = %d LIMIT 1",
intval(local_channel()),
- intval(\App::$poi['abook_id'])
+ intval(App::$poi['abook_id'])
);
if($r) {
- \App::$poi = array_shift($r);
+ App::$poi = array_shift($r);
}
- $clone = \App::$poi;
+ $clone = App::$poi;
unset($clone['abook_id']);
unset($clone['abook_account']);
@@ -382,7 +390,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
@@ -401,11 +409,11 @@ class Connedit extends \Zotlabs\Web\Controller {
}
$section = ((array_key_exists('section',$_REQUEST)) ? $_REQUEST['section'] : '');
- $channel = \App::get_channel();
+ $channel = App::get_channel();
$yes_no = array(t('No'),t('Yes'));
- $connect_perms = \Zotlabs\Access\Permissions::connect_perms(local_channel());
+ $connect_perms = Permissions::connect_perms(local_channel());
$o .= "<script>function connectDefaultShare() {
\$('.abook-edit-me').each(function() {
@@ -426,7 +434,7 @@ class Connedit extends \Zotlabs\Web\Controller {
return;
$cmd = argv(2);
-
+
$orig_record = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash
WHERE abook_id = %d AND abook_channel = %d AND abook_self = 0 LIMIT 1",
intval($contact_id),
@@ -440,7 +448,7 @@ class Connedit extends \Zotlabs\Web\Controller {
if($cmd === 'update') {
// pull feed and consume it, which should subscribe to the hub.
- \Zotlabs\Daemon\Master::Summon(array('Poller',$contact_id));
+ Master::Summon(array('Poller',$contact_id));
goaway(z_root() . '/connedit/' . $contact_id);
}
@@ -450,7 +458,7 @@ class Connedit extends \Zotlabs\Web\Controller {
$recurse = 0;
$x = z_fetch_url(zid($url),false,$recurse,['session' => true]);
if($x['success']) {
- $h = new \Zotlabs\Web\HTTPHeaders($x['header']);
+ $h = new HTTPHeaders($x['header']);
$fields = $h->fetch();
if($fields) {
foreach($fields as $y) {
@@ -481,17 +489,17 @@ class Connedit extends \Zotlabs\Web\Controller {
if($cmd === 'refresh') {
if($orig_record[0]['xchan_network'] === 'zot') {
- if(! zot_refresh($orig_record[0],\App::get_channel()))
+ if(! zot_refresh($orig_record[0],App::get_channel()))
notice( t('Refresh failed - channel is currently unavailable.') );
}
elseif($orig_record[0]['xchan_network'] === 'zot6') {
- if(! Libzot::refresh($orig_record[0],\App::get_channel()))
+ if(! Libzot::refresh($orig_record[0],App::get_channel()))
notice( t('Refresh failed - channel is currently unavailable.') );
}
else {
// if you are on a different network we'll force a refresh of the connection basic info
- \Zotlabs\Daemon\Master::Summon(array('Notifier','permission_update',$contact_id));
+ Master::Summon(array('Notifier','permission_update',$contact_id));
}
goaway(z_root() . '/connedit/' . $contact_id);
}
@@ -549,16 +557,11 @@ class Connedit extends \Zotlabs\Web\Controller {
if($cmd === 'drop') {
-
- // @FIXME
- // We need to send either a purge or a refresh packet to the other side (the channel being unfriended).
- // The issue is that the abook DB record _may_ get destroyed when we call contact_remove. As the notifier
- // runs in the background there could be a race condition preventing this packet from being sent in all
- // cases.
- // PLACEHOLDER
-
contact_remove(local_channel(), $orig_record[0]['abook_id']);
- build_sync_packet(0 /* use the current local_channel */,
+
+ Master::Summon( [ 'Notifier', 'purge', local_channel(), $orig_record[0]['xchan_hash'] ] );
+
+ Libsync::build_sync_packet(0 /* use the current local_channel */,
array('abook' => array(array(
'abook_xchan' => $orig_record[0]['abook_xchan'],
'entry_deleted' => true))
@@ -573,13 +576,13 @@ class Connedit extends \Zotlabs\Web\Controller {
}
}
- if(\App::$poi) {
+ if(App::$poi) {
$abook_prev = 0;
$abook_next = 0;
- $contact_id = \App::$poi['abook_id'];
- $contact = \App::$poi;
+ $contact_id = App::$poi['abook_id'];
+ $contact = App::$poi;
$cn = q("SELECT abook_id, xchan_name from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_self = 0 and xchan_deleted = 0 order by xchan_name",
intval(local_channel())
@@ -787,9 +790,9 @@ class Connedit extends \Zotlabs\Web\Controller {
$perms = array();
- $channel = \App::get_channel();
+ $channel = App::get_channel();
- $global_perms = \Zotlabs\Access\Permissions::Perms();
+ $global_perms = Permissions::Perms();
$existing = get_all_perms(local_channel(),$contact['abook_xchan'],false);
@@ -821,7 +824,7 @@ class Connedit extends \Zotlabs\Web\Controller {
$thisperm = get_abconfig(local_channel(),$contact['abook_xchan'],'my_perms',$k);
//fixme
- $checkinherited = \Zotlabs\Access\PermissionLimits::Get(local_channel(),$k);
+ $checkinherited = PermissionLimits::Get(local_channel(),$k);
// For auto permissions (when $self is true) we don't want to look at existing
// permissions because they are enabled for the channel owner
@@ -834,7 +837,7 @@ class Connedit extends \Zotlabs\Web\Controller {
$perms[] = array('perms_' . $k, $v, ((array_key_exists($k,$their_perms)) ? intval($their_perms[$k]) : ''),$thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), '', $checkinherited);
}
- $pcat = new \Zotlabs\Lib\Permcat(local_channel());
+ $pcat = new Permcat(local_channel());
$pcatlist = $pcat->listing();
$permcats = [];
if($pcatlist) {
diff --git a/Zotlabs/Module/Cover_photo.php b/Zotlabs/Module/Cover_photo.php
index d97014f9c..dff645f2b 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']));
@@ -291,14 +293,6 @@ class Cover_photo extends \Zotlabs\Web\Controller {
$arr['item_thread_top'] = 1;
$arr['item_origin'] = 1;
$arr['item_wall'] = 1;
- $arr['obj_type'] = ACTIVITY_OBJ_PHOTO;
- $arr['verb'] = ACTIVITY_UPDATE;
-
- $arr['obj'] = json_encode(array(
- 'type' => $arr['obj_type'],
- 'id' => z_root() . '/photo/' . $photo['resource_id'] . '-7',
- 'link' => array('rel' => 'photo', 'type' => $photo['mimetype'], 'href' => z_root() . '/photo/' . $photo['resource_id'] . '-7')
- ));
if($profile && stripos($profile['gender'],t('female')) !== false)
$t = t('%1$s updated her %2$s');
diff --git a/Zotlabs/Module/Dav.php b/Zotlabs/Module/Dav.php
index e8ce6a703..adab25e45 100644
--- a/Zotlabs/Module/Dav.php
+++ b/Zotlabs/Module/Dav.php
@@ -95,7 +95,7 @@ class Dav extends \Zotlabs\Web\Controller {
$auth = new \Zotlabs\Storage\BasicAuth();
- $auth->observer = get_observer_hash();
+ // $auth->observer = get_observer_hash();
$auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . ' ' . 'WebDAV');
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/Dircensor.php b/Zotlabs/Module/Dircensor.php
new file mode 100644
index 000000000..0fa65e948
--- /dev/null
+++ b/Zotlabs/Module/Dircensor.php
@@ -0,0 +1,52 @@
+<?php
+
+namespace Zotlabs\Module;
+
+use App;
+use Zotlabs\Web\Controller;
+
+
+class Dircensor extends Controller {
+
+ function get() {
+ if(! is_site_admin()) {
+ return;
+ }
+
+ $dirmode = intval(get_config('system','directory_mode'));
+
+ if (! ($dirmode == DIRECTORY_MODE_PRIMARY || $dirmode == DIRECTORY_MODE_STANDALONE)) {
+ return;
+ }
+
+ $xchan = argv(1);
+ if(! $xchan) {
+ return;
+ }
+
+ $r = q("select * from xchan where xchan_hash = '%s'",
+ dbesc($xchan)
+ );
+
+ if(! $r) {
+ return;
+ }
+
+ $val = (($r[0]['xchan_censored']) ? 0 : 1);
+
+ q("update xchan set xchan_censored = $val where xchan_hash = '%s'",
+ dbesc($xchan)
+ );
+
+ if($val) {
+ info( t('Entry censored') . EOL);
+ }
+ else {
+ info( t('Entry uncensored') . EOL);
+ }
+
+ goaway(z_root() . '/directory');
+
+ }
+
+}
diff --git a/Zotlabs/Module/Directory.php b/Zotlabs/Module/Directory.php
index b043cea40..e1bf0f6cf 100644
--- a/Zotlabs/Module/Directory.php
+++ b/Zotlabs/Module/Directory.php
@@ -2,15 +2,19 @@
namespace Zotlabs\Module;
+use App;
+use Zotlabs\Web\Controller;
+
require_once('include/socgraph.php');
require_once('include/dir_fns.php');
require_once('include/bbcode.php');
+require_once('include/html2plain.php');
-class Directory extends \Zotlabs\Web\Controller {
+class Directory extends Controller {
function init() {
- \App::set_pager_itemspage(60);
+ App::set_pager_itemspage(30);
if(local_channel() && x($_GET,'ignore')) {
q("insert into xign ( uid, xchan ) values ( %d, '%s' ) ",
@@ -21,7 +25,7 @@ class Directory extends \Zotlabs\Web\Controller {
}
if(local_channel())
- \App::$profile_uid = local_channel();
+ App::$profile_uid = local_channel();
$observer = get_observer_hash();
$global_changed = false;
@@ -140,9 +144,15 @@ class Directory extends \Zotlabs\Web\Controller {
$dirmode = intval(get_config('system','directory_mode'));
+ $directory_admin = false;
+
if(($dirmode == DIRECTORY_MODE_PRIMARY) || ($dirmode == DIRECTORY_MODE_STANDALONE)) {
$url = z_root() . '/dirsearch';
- }
+ if (is_site_admin()) {
+ $directory_admin = true;
+ }
+ }
+
if(! $url) {
$directory = find_upstream_directory($dirmode);
if((! $directory) || (! array_key_exists('url',$directory)) || (! $directory['url']))
@@ -182,7 +192,7 @@ class Directory extends \Zotlabs\Web\Controller {
$query .= '&t=' . $token;
if(! $globaldir)
- $query .= '&hub=' . \App::get_hostname();
+ $query .= '&hub=' . App::get_hostname();
if($search)
$query .= '&name=' . urlencode($search) . '&keywords=' . urlencode($search);
@@ -204,8 +214,8 @@ class Directory extends \Zotlabs\Web\Controller {
if($sort_order)
$query .= '&order=' . urlencode($sort_order);
- if(\App::$pager['page'] != 1)
- $query .= '&p=' . \App::$pager['page'];
+ if(App::$pager['page'] != 1)
+ $query .= '&p=' . App::$pager['page'];
logger('mod_directory: query: ' . $query);
@@ -283,12 +293,15 @@ class Directory extends \Zotlabs\Web\Controller {
$marital = ((x($profile,'marital') == 1) ? t('Status: ') . $profile['marital']: False);
$homepage = ((x($profile,'homepage') == 1) ? t('Homepage: ') : False);
- $homepageurl = ((x($profile,'homepage') == 1) ? $profile['homepage'] : '');
+ $homepageurl = ((x($profile,'homepage') == 1) ? html2plain($profile['homepage']) : '');
- $hometown = ((x($profile,'hometown') == 1) ? $profile['hometown'] : False);
+ $hometown = ((x($profile,'hometown') == 1) ? html2plain($profile['hometown']) : False);
$about = ((x($profile,'about') == 1) ? zidify_links(bbcode($profile['about'], ['tryoembed' => false])) : False);
-
+ if ($about && $safe_mode) {
+ $about = html2plain($about);
+ }
+
$keywords = ((x($profile,'keywords')) ? $profile['keywords'] : '');
@@ -343,9 +356,11 @@ class Directory extends \Zotlabs\Web\Controller {
'canrate' => (($rating_enabled && local_channel()) ? true : false),
'pdesc' => $pdesc,
'pdesc_label' => t('Description:'),
+ 'censor' => (($directory_admin) ? 'dircensor/' . $rr['hash'] : ''),
+ 'censor_label' => (($rr['censored']) ? t('Uncensor') : t('Censor')),
'marital' => $marital,
'homepage' => $homepage,
- 'homepageurl' => linkify($homepageurl, true),
+ 'homepageurl' => (($safe_mode) ? $homepageurl : linkify($homepageurl)),
'hometown' => $hometown,
'hometown_label' => t('Hometown:'),
'about' => $about,
@@ -387,7 +402,7 @@ class Directory extends \Zotlabs\Web\Controller {
ksort($entries); // Sort array by key so that foreach-constructs work as expected
if($j['keywords']) {
- \App::$data['directory_keywords'] = $j['keywords'];
+ App::$data['directory_keywords'] = $j['keywords'];
}
logger('mod_directory: entries: ' . print_r($entries,true), LOGGER_DATA);
@@ -438,7 +453,7 @@ class Directory extends \Zotlabs\Web\Controller {
echo $o;
killme();
}
- if(\App::$pager['page'] == 1 && $j['records'] == 0 && strpos($search,'@')) {
+ if(App::$pager['page'] == 1 && $j['records'] == 0 && strpos($search,'@')) {
goaway(z_root() . '/chanview/?f=&address=' . $search);
}
info( t("No entries (some entries may be hidden).") . EOL);
diff --git a/Zotlabs/Module/Dirsearch.php b/Zotlabs/Module/Dirsearch.php
index 92b33df0c..c15b13a90 100644
--- a/Zotlabs/Module/Dirsearch.php
+++ b/Zotlabs/Module/Dirsearch.php
@@ -1,14 +1,17 @@
<?php
namespace Zotlabs\Module;
+use App;
+use Zotlabs\Web\Controller;
+
require_once('include/dir_fns.php');
-class Dirsearch extends \Zotlabs\Web\Controller {
+class Dirsearch extends Controller {
function init() {
- \App::set_pager_itemspage(60);
+ App::set_pager_itemspage(30);
}
@@ -25,7 +28,8 @@ class Dirsearch extends \Zotlabs\Web\Controller {
$ret['message'] = t('This site is not a directory server');
json_return_and_die($ret);
}
-
+
+
$access_token = $_REQUEST['t'];
$token = get_config('system','realm_token');
@@ -286,29 +290,29 @@ class Dirsearch extends \Zotlabs\Web\Controller {
else
$entry['total_ratings'] = 0;
- $entry['name'] = $rr['xchan_name'];
- $entry['hash'] = $rr['xchan_hash'];
-
+ $entry['name'] = $rr['xchan_name'];
+ $entry['hash'] = $rr['xchan_hash'];
+ $entry['censored'] = $rr['xchan_censored'];
+ $entry['selfcensored'] = $rr['xchan_selfcensored'];
$entry['public_forum'] = (intval($rr['xchan_pubforum']) ? true : false);
-
- $entry['url'] = $rr['xchan_url'];
- $entry['photo_l'] = $rr['xchan_photo_l'];
- $entry['photo'] = $rr['xchan_photo_m'];
- $entry['address'] = $rr['xchan_addr'];
- $entry['description'] = $rr['xprof_desc'];
- $entry['locale'] = $rr['xprof_locale'];
- $entry['region'] = $rr['xprof_region'];
- $entry['postcode'] = $rr['xprof_postcode'];
- $entry['country'] = $rr['xprof_country'];
- $entry['birthday'] = $rr['xprof_dob'];
- $entry['age'] = $rr['xprof_age'];
- $entry['gender'] = $rr['xprof_gender'];
- $entry['marital'] = $rr['xprof_marital'];
- $entry['sexual'] = $rr['xprof_sexual'];
- $entry['about'] = $rr['xprof_about'];
- $entry['homepage'] = $rr['xprof_homepage'];
- $entry['hometown'] = $rr['xprof_hometown'];
- $entry['keywords'] = $rr['xprof_keywords'];
+ $entry['url'] = $rr['xchan_url'];
+ $entry['photo_l'] = $rr['xchan_photo_l'];
+ $entry['photo'] = $rr['xchan_photo_m'];
+ $entry['address'] = $rr['xchan_addr'];
+ $entry['description'] = $rr['xprof_desc'];
+ $entry['locale'] = $rr['xprof_locale'];
+ $entry['region'] = $rr['xprof_region'];
+ $entry['postcode'] = $rr['xprof_postcode'];
+ $entry['country'] = $rr['xprof_country'];
+ $entry['birthday'] = $rr['xprof_dob'];
+ $entry['age'] = $rr['xprof_age'];
+ $entry['gender'] = $rr['xprof_gender'];
+ $entry['marital'] = $rr['xprof_marital'];
+ $entry['sexual'] = $rr['xprof_sexual'];
+ $entry['about'] = $rr['xprof_about'];
+ $entry['homepage'] = $rr['xprof_homepage'];
+ $entry['hometown'] = $rr['xprof_hometown'];
+ $entry['keywords'] = $rr['xprof_keywords'];
$entries[] = $entry;
diff --git a/Zotlabs/Module/Display.php b/Zotlabs/Module/Display.php
index 5983578b3..3d61d7018 100644
--- a/Zotlabs/Module/Display.php
+++ b/Zotlabs/Module/Display.php
@@ -47,7 +47,6 @@ class Display extends \Zotlabs\Web\Controller {
}
$observer_is_owner = false;
- $updateable = false;
if(local_channel() && (! $update)) {
@@ -101,7 +100,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 +158,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']);
}
@@ -200,7 +202,8 @@ class Display extends \Zotlabs\Web\Controller {
// if the target item is not a post (eg a like) we want to address its thread parent
- $mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']);
+ //$mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']);
+ $mid = $target_item['mid'];
// if we got a decoded hash we must encode it again before handing to javascript
if($decoded)
@@ -223,6 +226,7 @@ class Display extends \Zotlabs\Web\Controller {
'$conv' => '0',
'$spam' => '0',
'$fh' => '0',
+ '$dm' => '0',
'$nouveau' => '0',
'$wall' => '0',
'$static' => $static,
@@ -269,9 +273,6 @@ class Display extends \Zotlabs\Web\Controller {
intval(local_channel()),
dbesc($target_item['parent_mid'])
);
- if($r) {
- $updateable = true;
- }
}
if(! $r) {
@@ -313,9 +314,6 @@ class Display extends \Zotlabs\Web\Controller {
intval(local_channel()),
dbesc($target_item['parent_mid'])
);
- if($r) {
- $updateable = true;
- }
}
if($r === null) {
@@ -427,13 +425,6 @@ class Display extends \Zotlabs\Web\Controller {
killme();
}
-
- if($updateable) {
- $x = q("UPDATE item SET item_unseen = 0 where item_unseen = 1 AND uid = %d and parent = %d ",
- intval(local_channel()),
- intval($r[0]['item_id'])
- );
- }
$o .= '<div id="content-complete"></div>';
diff --git a/Zotlabs/Module/Embedphotos.php b/Zotlabs/Module/Embedphotos.php
index 6a88513dc..9b0884197 100644
--- a/Zotlabs/Module/Embedphotos.php
+++ b/Zotlabs/Module/Embedphotos.php
@@ -68,6 +68,8 @@ class Embedphotos extends \Zotlabs\Web\Controller {
$ext = '.png';
elseif($r[0]['mimetype'] === 'image/gif')
$ext = '.gif';
+ elseif($r[0]['mimetype'] === 'image/webp')
+ $exp = '.webp';
else
$ext = EMPTY_STR;
diff --git a/Zotlabs/Module/Event.php b/Zotlabs/Module/Event.php
new file mode 100644
index 000000000..22a1341cc
--- /dev/null
+++ b/Zotlabs/Module/Event.php
@@ -0,0 +1,76 @@
+<?php
+namespace Zotlabs\Module;
+
+use Zotlabs\Web\Controller;
+use Zotlabs\Lib\ActivityStreams;
+use Zotlabs\Lib\Activity;
+use Zotlabs\Lib\LDSignatures;
+use Zotlabs\Web\HTTPSig;
+
+class Event extends Controller {
+
+ function init() {
+
+ if(ActivityStreams::is_as_request()) {
+ $item_id = argv(1);
+
+ if(! $item_id)
+ return;
+
+ $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0
+ and item.item_delayed = 0 and item.item_blocked = 0 ";
+
+ $sql_extra = item_permissions_sql(0);
+
+ $r = q("select * from item where mid like '%s' $item_normal $sql_extra limit 1",
+ dbesc(z_root() . '/activity/' . $item_id . '%')
+ );
+
+ if(! $r) {
+ $r = q("select * from item where mid like '%s' $item_normal limit 1",
+ dbesc(z_root() . '/activity/' . $item_id . '%')
+ );
+
+ if($r) {
+ http_status_exit(403, 'Forbidden');
+ }
+ http_status_exit(404, 'Not found');
+ }
+
+ xchan_query($r,true);
+ $items = fetch_post_tags($r,true);
+
+ $channel = channelx_by_n($items[0]['uid']);
+
+ if(! is_array($items[0]['obj'])) {
+ $obj = json_decode($items[0]['obj'],true);
+ }
+ else {
+ $obj = $items[0]['obj'];
+ }
+
+ $x = array_merge(['@context' => [
+ ACTIVITYSTREAMS_JSONLD_REV,
+ 'https://w3id.org/security/v1',
+ z_root() . ZOT_APSCHEMA_REV
+ ]], $obj );
+
+ $headers = [];
+ $headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ;
+ $x['signature'] = LDSignatures::sign($x,$channel);
+ $ret = json_encode($x, JSON_UNESCAPED_SLASHES);
+ $headers['Date'] = datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T');
+ $headers['Digest'] = HTTPSig::generate_digest_header($ret);
+ $headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
+
+ $h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel));
+ HTTPSig::set_headers($h);
+
+ echo $ret;
+ killme();
+
+ }
+
+ }
+
+} \ No newline at end of file
diff --git a/Zotlabs/Module/Feed.php b/Zotlabs/Module/Feed.php
index 36869abbe..b5e7b28fa 100644
--- a/Zotlabs/Module/Feed.php
+++ b/Zotlabs/Module/Feed.php
@@ -17,7 +17,7 @@ class Feed extends \Zotlabs\Web\Controller {
$params['pages'] = ((x($_REQUEST,'pages')) ? intval($_REQUEST['pages']) : 0);
$params['top'] = ((x($_REQUEST,'top')) ? intval($_REQUEST['top']) : 0);
$params['start'] = ((x($_REQUEST,'start')) ? intval($_REQUEST['start']) : 0);
- $params['records'] = ((x($_REQUEST,'records')) ? intval($_REQUEST['records']) : 40);
+ $params['records'] = ((x($_REQUEST,'records')) ? intval($_REQUEST['records']) : 10);
$params['direction'] = ((x($_REQUEST,'direction')) ? dbesc($_REQUEST['direction']) : 'desc');
$params['cat'] = ((x($_REQUEST,'cat')) ? escape_tags($_REQUEST['cat']) : '');
$params['compat'] = ((x($_REQUEST,'compat')) ? intval($_REQUEST['compat']) : 0);
diff --git a/Zotlabs/Module/Fhubloc_id_url.php b/Zotlabs/Module/Fhubloc_id_url.php
new file mode 100644
index 000000000..a5627a33d
--- /dev/null
+++ b/Zotlabs/Module/Fhubloc_id_url.php
@@ -0,0 +1,79 @@
+<?php
+namespace Zotlabs\Module;
+
+/* fix missing or hubloc_id_url entries */
+
+class Fhubloc_id_url extends \Zotlabs\Web\Controller {
+
+ function get() {
+
+ if(! is_site_admin())
+ return;
+
+ q("START TRANSACTION");
+
+ // remove broken xchan entries
+ $r0 = dbq("DELETE FROM xchan WHERE xchan_hash = ''");
+
+ // remove broken hubloc entries
+ $r1 = dbq("DELETE FROM hubloc WHERE hubloc_hash = ''");
+
+ // fix legacy zot hubloc_id_url
+ $r2 = dbq("UPDATE hubloc
+ SET hubloc_id_url = CONCAT(hubloc_url, '/channel/', SUBSTRING(hubloc_addr FROM 1 FOR POSITION('@' IN hubloc_addr) -1))
+ WHERE hubloc_network = 'zot'
+ AND hubloc_id_url = ''"
+ );
+
+ // fix singleton networks hubloc_id_url
+ if(ACTIVE_DBTYPE == DBTYPE_MYSQL) {
+ // fix entries for activitypub which miss the xchan_url due to an earlier bug
+ $r3 = dbq("UPDATE xchan
+ SET xchan_url = xchan_hash
+ WHERE xchan_network = 'activitypub'
+ AND xchan_url = ''"
+ );
+
+ $r4 = dbq("UPDATE hubloc
+ LEFT JOIN xchan ON hubloc.hubloc_hash = xchan.xchan_hash
+ SET hubloc.hubloc_id_url = xchan.xchan_url
+ WHERE hubloc.hubloc_network IN ('activitypub', 'diaspora', 'friendica-over-diaspora', 'gnusoc')
+ AND hubloc.hubloc_id_url = ''
+ AND xchan.xchan_url IS NOT NULL"
+ );
+
+ }
+ if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
+ // fix entries for activitypub which miss the xchan_url due to an earlier bug
+ $r3 = dbq("UPDATE xchan
+ SET xchan_url = xchan_hash
+ WHERE xchan_network = 'activitypub'
+ AND xchan_url = ''"
+ );
+
+ $r4 = dbq("UPDATE hubloc
+ SET hubloc_id_url = xchan_url
+ FROM xchan
+ WHERE hubloc_hash = xchan_hash
+ AND hubloc_network IN ('activitypub', 'diaspora', 'friendica-over-diaspora', 'gnusoc')
+ AND hubloc_id_url = ''
+ AND xchan_url IS NOT NULL"
+ );
+
+
+ }
+
+ if($r0 && $r1 && $r2 && $r3 && $r4) {
+ // remove hubloc entries where hubloc_id_url could not be fixed
+ $r5 = dbq("DELETE FROM hubloc WHERE hubloc_id_url = ''");
+ }
+
+ if($r0 && $r1 && $r2 && $r3 && $r4 && $r5) {
+ q("COMMIT");
+ return 'Completed';
+ }
+
+ q("ROLLBACK");
+ return 'Failed';
+ }
+}
diff --git a/Zotlabs/Module/Fhublocs.php b/Zotlabs/Module/Fhublocs.php
index 42c119da3..dcd399a1f 100644
--- a/Zotlabs/Module/Fhublocs.php
+++ b/Zotlabs/Module/Fhublocs.php
@@ -1,6 +1,8 @@
<?php
namespace Zotlabs\Module;
+use Zotlabs\Lib\Libzot;
+
require_once('include/zot.php');
require_once('include/crypto.php');
@@ -10,7 +12,7 @@ require_once('include/crypto.php');
class Fhublocs extends \Zotlabs\Web\Controller {
function get() {
-
+
if(! is_site_admin())
return;
@@ -21,9 +23,11 @@ class Fhublocs extends \Zotlabs\Web\Controller {
if($r) {
foreach($r as $rr) {
+
$found = false;
$primary_address = '';
- $x = zot_get_hublocs($rr['channel_hash']);
+ $x = Libzot::get_hublocs($rr['channel_hash']);
+
if($x) {
foreach($x as $xx) {
if($xx['hubloc_url'] === z_root() && $xx['hubloc_sitekey'] === $sitekey) {
@@ -42,13 +46,12 @@ class Fhublocs extends \Zotlabs\Web\Controller {
if($y)
$primary_address = $y[0]['xchan_addr'];
- $hub_address = channel_reddress($rr['channel']);
-
-
+ $hub_address = channel_reddress($rr);
+
$primary = (($hub_address === $primary_address) ? 1 : 0);
if(! $y)
$primary = 1;
-
+
$m = q("delete from hubloc where hubloc_hash = '%s' and hubloc_url = '%s' ",
dbesc($rr['channel_hash']),
dbesc(z_root())
@@ -56,7 +59,7 @@ class Fhublocs extends \Zotlabs\Web\Controller {
// Create a verified hub location pointing to this site.
-
+/*
$h = hubloc_store_lowlevel(
[
'hubloc_guid' => $rr['channel_guid'],
@@ -72,7 +75,26 @@ class Fhublocs extends \Zotlabs\Web\Controller {
'hubloc_sitekey' => $sitekey
]
);
-
+*/
+ $h = hubloc_store_lowlevel(
+ [
+ 'hubloc_guid' => $rr['channel_guid'],
+ 'hubloc_guid_sig' => $rr['channel_guid_sig'],
+ 'hubloc_hash' => $rr['channel_hash'],
+ 'hubloc_id_url' => channel_url($rr),
+ 'hubloc_addr' => channel_reddress($rr),
+ 'hubloc_primary' => intval($primary),
+ 'hubloc_url' => z_root(),
+ 'hubloc_url_sig' => Libzot::sign(z_root(), $rr['channel_prvkey']),
+ 'hubloc_site_id' => Libzot::make_xchan_hash(z_root(), $sitekey),
+ 'hubloc_host' => \App::get_hostname(),
+ 'hubloc_callback' => z_root() . '/zot',
+ 'hubloc_sitekey' => $sitekey,
+ 'hubloc_network' => 'zot6',
+ 'hubloc_updated' => datetime_convert()
+ ]
+ );
+
if($h)
$o . 'local hubloc created for ' . $rr['channel_name'] . EOL;
else
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/Follow.php b/Zotlabs/Module/Follow.php
index cbf9d62c5..11febd8fc 100644
--- a/Zotlabs/Module/Follow.php
+++ b/Zotlabs/Module/Follow.php
@@ -1,31 +1,88 @@
<?php
namespace Zotlabs\Module;
+use App;
+use Zotlabs\Web\Controller;
+use Zotlabs\Lib\Libsync;
+use Zotlabs\Lib\ActivityStreams;
+use Zotlabs\Lib\Activity;
+use Zotlabs\Web\HTTPSig;
+use Zotlabs\Lib\LDSignatures;
+use Zotlabs\Lib\Connect;
+use Zotlabs\Daemon\Master;
-require_once('include/follow.php');
-
-
-class Follow extends \Zotlabs\Web\Controller {
+class Follow extends Controller {
function init() {
- if(! local_channel()) {
+ if (ActivityStreams::is_as_request() && argc() == 2) {
+
+ $abook_id = intval(argv(1));
+ if(! $abook_id)
+ return;
+
+ $r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d",
+ intval($abook_id)
+ );
+ if (! $r) {
+ return;
+ }
+
+ $chan = channelx_by_n($r[0]['abook_channel']);
+
+ if (! $chan) {
+ http_status_exit(404, 'Not found');
+ }
+
+ $actor = Activity::encode_person($chan,true,true);
+ if (! $actor) {
+ http_status_exit(404, 'Not found');
+ }
+
+ $x = array_merge(['@context' => [
+ ACTIVITYSTREAMS_JSONLD_REV,
+ 'https://w3id.org/security/v1',
+ z_root() . ZOT_APSCHEMA_REV
+ ]],
+ [
+ 'id' => z_root() . '/follow/' . $r[0]['abook_id'],
+ 'type' => 'Follow',
+ 'actor' => $actor,
+ 'object' => $r[0]['xchan_url']
+ ]);
+
+ $headers = [];
+ $headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ;
+ $x['signature'] = LDSignatures::sign($x,$chan);
+ $ret = json_encode($x, JSON_UNESCAPED_SLASHES);
+ $headers['Date'] = datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T');
+ $headers['Digest'] = HTTPSig::generate_digest_header($ret);
+ $headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
+ $h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],channel_url($chan));
+ HTTPSig::set_headers($h);
+ echo $ret;
+ killme();
+
+ }
+
+ if (! local_channel()) {
return;
}
-
+
$uid = local_channel();
$url = notags(trim(punify($_REQUEST['url'])));
$return_url = $_SESSION['return_url'];
$confirm = intval($_REQUEST['confirm']);
$interactive = (($_REQUEST['interactive']) ? intval($_REQUEST['interactive']) : 1);
- $channel = \App::get_channel();
+ $channel = App::get_channel();
- $result = new_contact($uid,$url,$channel,$interactive,$confirm);
+ $result = Connect::connect($channel,$url);
- if($result['success'] == false) {
- if($result['message'])
+ if ($result['success'] == false) {
+ if ($result['message']) {
notice($result['message']);
- if($interactive) {
+ }
+ if ($interactive) {
goaway($return_url);
}
else {
@@ -36,8 +93,8 @@ class Follow extends \Zotlabs\Web\Controller {
info( t('Connection added.') . EOL);
$clone = array();
- foreach($result['abook'] as $k => $v) {
- if(strpos($k,'abook_') === 0) {
+ foreach ($result['abook'] as $k => $v) {
+ if (strpos($k,'abook_') === 0) {
$clone[$k] = $v;
}
}
@@ -46,20 +103,21 @@ class Follow extends \Zotlabs\Web\Controller {
unset($clone['abook_channel']);
$abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']);
- if($abconfig)
+ if ($abconfig) {
$clone['abconfig'] = $abconfig;
+ }
+ Libsync::build_sync_packet(0, [ 'abook' => [ $clone ] ], true);
- build_sync_packet(0 /* use the current local_channel */, array('abook' => array($clone)), true);
-
- $can_view_stream = intval(get_abconfig($channel['channel_id'],$clone['abook_xchan'],'their_perms','view_stream'));
+ $can_view_stream = their_perms_contains($channel['channel_id'],$clone['abook_xchan'],'view_stream');
// If we can view their stream, pull in some posts
- if(($can_view_stream) || ($result['abook']['xchan_network'] === 'rss'))
- \Zotlabs\Daemon\Master::Summon(array('Onepoll',$result['abook']['abook_id']));
+ if (($can_view_stream) || ($result['abook']['xchan_network'] === 'rss')) {
+ Master::Summon([ 'Onepoll', $result['abook']['abook_id'] ]);
+ }
- if($interactive) {
- goaway(z_root() . '/connedit/' . $result['abook']['abook_id'] . '?f=&follow=1');
+ if ($interactive) {
+ goaway(z_root() . '/connedit/' . $result['abook']['abook_id'] . '?follow=1');
}
else {
json_return_and_die([ 'success' => true ]);
@@ -68,7 +126,7 @@ class Follow extends \Zotlabs\Web\Controller {
}
function get() {
- if(! local_channel()) {
+ if (! local_channel()) {
return login();
}
}
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/Help.php b/Zotlabs/Module/Help.php
index f1b1acaef..ce05035b3 100644
--- a/Zotlabs/Module/Help.php
+++ b/Zotlabs/Module/Help.php
@@ -66,7 +66,10 @@ class Help extends \Zotlabs\Web\Controller {
case IMAGETYPE_PNG:
header("Content-Type: image/png");
break;
- default:
+ case IMAGETYPE_WEBP:
+ header("Content-Type: image/webp");
+ break;
+ default:
break;
}
header("Content-Length: " . filesize($realpath));
diff --git a/Zotlabs/Module/Hq.php b/Zotlabs/Module/Hq.php
index 848fe3e25..e2678c07f 100644
--- a/Zotlabs/Module/Hq.php
+++ b/Zotlabs/Module/Hq.php
@@ -152,8 +152,8 @@ class Hq extends \Zotlabs\Web\Controller {
if($target_item) {
// if the target item is not a post (eg a like) we want to address its thread parent
- $mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']);
-
+ //$mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']);
+ $mid = $target_item['mid'];
// if we got a decoded hash we must encode it again before handing to javascript
if($decoded)
$mid = 'b64.' . base64url_encode($mid);
@@ -179,6 +179,7 @@ class Hq extends \Zotlabs\Web\Controller {
'$conv' => '0',
'$spam' => '0',
'$fh' => '0',
+ '$dm' => '0',
'$nouveau' => '0',
'$wall' => '0',
'$static' => $static,
@@ -198,8 +199,6 @@ class Hq extends \Zotlabs\Web\Controller {
]);
}
- $updateable = false;
-
if($load && $target_item) {
$r = null;
@@ -212,10 +211,6 @@ class Hq extends \Zotlabs\Web\Controller {
dbesc($target_item['parent_mid'])
);
- if($r) {
- $updateable = true;
- }
-
if(!$r) {
$sys_item = true;
@@ -242,10 +237,6 @@ class Hq extends \Zotlabs\Web\Controller {
dbesc($target_item['parent_mid'])
);
- if($r) {
- $updateable = true;
- }
-
if(!$r) {
$sys_item = true;
@@ -282,13 +273,6 @@ class Hq extends \Zotlabs\Web\Controller {
$o .= conversation($items, 'hq', $update, 'client');
- if($updateable) {
- $x = q("UPDATE item SET item_unseen = 0 WHERE item_unseen = 1 AND uid = %d AND parent = %d ",
- intval(local_channel()),
- intval($r[0]['item_id'])
- );
- }
-
$o .= '<div id="content-complete"></div>';
return $o;
diff --git a/Zotlabs/Module/Import.php b/Zotlabs/Module/Import.php
index 18cb5560e..2c6e09fa7 100644
--- a/Zotlabs/Module/Import.php
+++ b/Zotlabs/Module/Import.php
@@ -137,6 +137,11 @@ class Import extends \Zotlabs\Web\Controller {
return;
}
+ if(version_compare($data['compatibility']['version'], '4.7.3', '<=')) {
+ // zot6 transition: cloning is not compatible with older versions
+ notice('Data export format is not compatible with this software (not a zot6 channel)');
+ return;
+ }
if($moving)
$seize = 1;
@@ -212,50 +217,21 @@ class Import extends \Zotlabs\Web\Controller {
// create new hubloc for the new channel at this site
if(array_key_exists('channel',$data)) {
- $r = hubloc_store_lowlevel(
- [
- 'hubloc_guid' => $channel['channel_guid'],
- 'hubloc_guid_sig' => $channel['channel_guid_sig'],
- 'hubloc_hash' => $channel['channel_hash'],
- 'hubloc_addr' => channel_reddress($channel),
- 'hubloc_network' => 'zot',
- 'hubloc_primary' => (($seize) ? 1 : 0),
- 'hubloc_url' => z_root(),
- 'hubloc_url_sig' => base64url_encode(rsa_sign(z_root(),$channel['channel_prvkey'])),
- 'hubloc_host' => \App::get_hostname(),
- 'hubloc_callback' => z_root() . '/post',
- 'hubloc_sitekey' => get_config('system','pubkey'),
- 'hubloc_updated' => datetime_convert()
- ]
- );
-
- // reset the original primary hubloc if it is being seized
- if($seize) {
- $r = q("update hubloc set hubloc_primary = 0 where hubloc_primary = 1 and hubloc_hash = '%s' and hubloc_url != '%s' ",
- dbesc($channel['channel_hash']),
- dbesc(z_root())
- );
- }
-
- // create a new zot6 hubloc if we have got a channel_portable_id
if($channel['channel_portable_id']) {
$r = hubloc_store_lowlevel(
[
'hubloc_guid' => $channel['channel_guid'],
- 'hubloc_guid_sig' => 'sha256.' . $channel['channel_guid_sig'],
+ 'hubloc_guid_sig' => $channel['channel_guid_sig'],
'hubloc_hash' => $channel['channel_portable_id'],
'hubloc_addr' => channel_reddress($channel),
- 'hubloc_network' => 'zot6',
+ 'hubloc_network' => 'zot',
'hubloc_primary' => (($seize) ? 1 : 0),
'hubloc_url' => z_root(),
- 'hubloc_url_sig' => 'sha256.' . base64url_encode(rsa_sign(z_root(),$channel['channel_prvkey'])),
+ 'hubloc_url_sig' => base64url_encode(rsa_sign(z_root(),$channel['channel_prvkey'])),
'hubloc_host' => \App::get_hostname(),
- 'hubloc_callback' => z_root() . '/zot',
+ 'hubloc_callback' => z_root() . '/post',
'hubloc_sitekey' => get_config('system','pubkey'),
- 'hubloc_updated' => datetime_convert(),
- 'hubloc_id_url' => channel_url($channel),
- 'hubloc_site_id' => Libzot::make_xchan_hash(z_root(),get_config('system','pubkey'))
-
+ 'hubloc_updated' => datetime_convert()
]
);
@@ -266,7 +242,35 @@ class Import extends \Zotlabs\Web\Controller {
dbesc(z_root())
);
}
+ }
+ // create a new zot6 hubloc if we have got a channel_portable_id
+
+ $r = hubloc_store_lowlevel(
+ [
+ 'hubloc_guid' => $channel['channel_guid'],
+ 'hubloc_guid_sig' => $channel['channel_guid_sig'],
+ 'hubloc_hash' => $channel['channel_hash'],
+ 'hubloc_addr' => channel_reddress($channel),
+ 'hubloc_network' => 'zot6',
+ 'hubloc_primary' => (($seize) ? 1 : 0),
+ 'hubloc_url' => z_root(),
+ 'hubloc_url_sig' => 'sha256.' . base64url_encode(rsa_sign(z_root(),$channel['channel_prvkey'])),
+ 'hubloc_host' => \App::get_hostname(),
+ 'hubloc_callback' => z_root() . '/zot',
+ 'hubloc_sitekey' => get_config('system','pubkey'),
+ 'hubloc_updated' => datetime_convert(),
+ 'hubloc_id_url' => channel_url($channel),
+ 'hubloc_site_id' => Libzot::make_xchan_hash(z_root(),get_config('system','pubkey'))
+ ]
+ );
+
+ // reset the original primary hubloc if it is being seized
+ if($seize) {
+ $r = q("update hubloc set hubloc_primary = 0 where hubloc_primary = 1 and hubloc_hash = '%s' and hubloc_url != '%s' ",
+ dbesc($channel['channel_hash']),
+ dbesc(z_root())
+ );
}
}
@@ -285,32 +289,12 @@ class Import extends \Zotlabs\Web\Controller {
dbesc($channel['channel_portable_id'])
);
- $r = xchan_store_lowlevel(
- [
- 'xchan_hash' => $channel['channel_hash'],
- 'xchan_guid' => $channel['channel_guid'],
- 'xchan_guid_sig' => $channel['channel_guid_sig'],
- 'xchan_pubkey' => $channel['channel_pubkey'],
- 'xchan_photo_l' => z_root() . "/photo/profile/l/" . $channel['channel_id'],
- 'xchan_photo_m' => z_root() . "/photo/profile/m/" . $channel['channel_id'],
- 'xchan_photo_s' => z_root() . "/photo/profile/s/" . $channel['channel_id'],
- 'xchan_addr' => channel_reddress($channel),
- 'xchan_url' => z_root() . '/channel/' . $channel['channel_address'],
- 'xchan_connurl' => z_root() . '/poco/' . $channel['channel_address'],
- 'xchan_follow' => z_root() . '/follow?f=&url=%s',
- 'xchan_name' => $channel['channel_name'],
- 'xchan_network' => 'zot',
- 'xchan_photo_date' => datetime_convert(),
- 'xchan_name_date' => datetime_convert()
- ]
- );
-
if($channel['channel_portable_id']) {
$r = xchan_store_lowlevel(
[
- 'xchan_hash' => \Zotlabs\Lib\Libzot::make_xchan_hash($channel['channel_guid'],$channel['channel_pubkey']),
+ 'xchan_hash' => $channel['channel_portable_id'],
'xchan_guid' => $channel['channel_guid'],
- 'xchan_guid_sig' => 'sha256.' . $channel['channel_guid_sig'],
+ 'xchan_guid_sig' => $channel['channel_guid_sig'],
'xchan_pubkey' => $channel['channel_pubkey'],
'xchan_photo_l' => z_root() . "/photo/profile/l/" . $channel['channel_id'],
'xchan_photo_m' => z_root() . "/photo/profile/m/" . $channel['channel_id'],
@@ -320,13 +304,32 @@ class Import extends \Zotlabs\Web\Controller {
'xchan_connurl' => z_root() . '/poco/' . $channel['channel_address'],
'xchan_follow' => z_root() . '/follow?f=&url=%s',
'xchan_name' => $channel['channel_name'],
- 'xchan_network' => 'zot6',
+ 'xchan_network' => 'zot',
'xchan_photo_date' => datetime_convert(),
'xchan_name_date' => datetime_convert()
]
);
}
+ $r = xchan_store_lowlevel(
+ [
+ 'xchan_hash' => $channel['channel_hash'],
+ 'xchan_guid' => $channel['channel_guid'],
+ 'xchan_guid_sig' => $channel['channel_guid_sig'],
+ 'xchan_pubkey' => $channel['channel_pubkey'],
+ 'xchan_photo_l' => z_root() . "/photo/profile/l/" . $channel['channel_id'],
+ 'xchan_photo_m' => z_root() . "/photo/profile/m/" . $channel['channel_id'],
+ 'xchan_photo_s' => z_root() . "/photo/profile/s/" . $channel['channel_id'],
+ 'xchan_addr' => channel_reddress($channel),
+ 'xchan_url' => z_root() . '/channel/' . $channel['channel_address'],
+ 'xchan_connurl' => z_root() . '/poco/' . $channel['channel_address'],
+ 'xchan_follow' => z_root() . '/follow?f=&url=%s',
+ 'xchan_name' => $channel['channel_name'],
+ 'xchan_network' => 'zot6',
+ 'xchan_photo_date' => datetime_convert(),
+ 'xchan_name_date' => datetime_convert()
+ ]
+ );
}
@@ -346,7 +349,7 @@ class Import extends \Zotlabs\Web\Controller {
}
if($xchan['xchan_network'] === 'zot6') {
- $zhash = \Zotlabs\Lib\Libzot::make_xchan_hash($xchan['xchan_guid'],$xchan['xchan_pubkey']);
+ $zhash = Libzot::make_xchan_hash($xchan['xchan_guid'],$xchan['xchan_pubkey']);
if($zhash !== $xchan['xchan_hash']) {
logger('forged xchan: ' . print_r($xchan,true));
continue;
diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php
index 14881844d..922a2ef06 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;
@@ -11,7 +12,9 @@ use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\LDSignatures;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Lib\Libzot;
+use Zotlabs\Lib\Libsync;
use Zotlabs\Lib\ThreadListener;
+use Zotlabs\Access\PermissionRoles;
use App;
require_once('include/crypto.php');
@@ -46,7 +49,7 @@ class Item extends Controller {
$item_id = argv(1);
- if (! $item_id)
+ if(! $item_id)
http_status_exit(404, 'Not found');
$portable_id = EMPTY_STR;
@@ -67,32 +70,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
@@ -112,7 +107,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)
);
@@ -123,43 +118,112 @@ 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) {
+ if(! $items)
+ http_status_exit(404, 'Not found');
- $mids = [];
+ $chan = channelx_by_n($items[0]['uid']);
- 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(! $chan)
+ http_status_exit(404, 'Not found');
- if((! $to) || (! in_array($observer['xchan_url'],$to))) {
- continue;
- }
+ if(! perm_is_allowed($chan['channel_id'],get_observer_hash(),'view_stream'))
+ http_status_exit(403, 'Forbidden');
- }
- $nitems[] = $i;
+
+ $i = Activity::encode_item_collection($items, 'conversation/' . $item_id, 'OrderedCollection');
+ if($portable_id) {
+ ThreadListener::store(z_root() . '/item/' . $item_id,$portable_id);
}
- if(! $nitems)
+ if(! $i)
+ http_status_exit(404, 'Not found');
+
+ $x = array_merge(['@context' => [
+ ACTIVITYSTREAMS_JSONLD_REV,
+ 'https://w3id.org/security/v1',
+ z_root() . ZOT_APSCHEMA_REV
+ ]], $i);
+
+ $headers = [];
+ $headers['Content-Type'] = 'application/x-zot+json' ;
+ $x['signature'] = LDSignatures::sign($x,$chan);
+ $ret = json_encode($x, JSON_UNESCAPED_SLASHES);
+ $headers['Digest'] = HTTPSig::generate_digest_header($ret);
+ $headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
+ $h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],channel_url($chan));
+ HTTPSig::set_headers($h);
+ echo $ret;
+ killme();
+
+ }
+
+ if(ActivityStreams::is_as_request()) {
+
+ $item_id = argv(1);
+ if(! $item_id)
http_status_exit(404, 'Not found');
- $chan = channelx_by_n($nitems[0]['uid']);
+ $portable_id = EMPTY_STR;
+
+ $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 ";
+
+ $i = null;
+
+ // do we have the item (at all)?
+ // add preferential bias to item owners (item_wall = 1)
+
+ $r = q("select * from item where mid = '%s' or uuid = '%s' $item_normal order by item_wall desc limit 1",
+ dbesc(z_root() . '/item/' . $item_id),
+ dbesc($item_id)
+ );
+
+ if (! $r) {
+ http_status_exit(404,'Not found');
+ }
+
+ // process an authenticated fetch
+
+ $sigdata = HTTPSig::verify(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);
+
+ $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)
+ );
+ }
+ 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
+ // with a bias towards those items owned by channels on this site (item_wall = 1)
+
+ $sql_extra = item_permissions_sql(0);
+
+ if (! $i) {
+ $i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1",
+ dbesc($r[0]['parent_mid'])
+ );
+ }
+
+ if(! $i) {
+ http_status_exit(403,'Forbidden');
+ }
+
+ // If we get to this point we have determined we can access the original in $r (fetched much further above), so use it.
+
+ xchan_query($r,true);
+ $items = fetch_post_tags($r,false);
+
+ $chan = channelx_by_n($items[0]['uid']);
if(! $chan)
http_status_exit(404, 'Not found');
@@ -167,10 +231,7 @@ 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');
- if($portable_id) {
- ThreadListener::store(z_root() . '/item/' . $item_id,$portable_id);
- }
+ $i = Activity::encode_item($items[0],true);
if(! $i)
http_status_exit(404, 'Not found');
@@ -182,9 +243,10 @@ class Item extends Controller {
]], $i);
$headers = [];
- $headers['Content-Type'] = 'application/x-zot+json' ;
+ $headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ;
$x['signature'] = LDSignatures::sign($x,$chan);
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
+ $headers['Date'] = datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T');
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
$h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],channel_url($chan));
@@ -194,9 +256,11 @@ 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) {
@@ -273,7 +337,9 @@ class Item extends Controller {
$consensus = intval($_REQUEST['consensus']);
$nocomment = intval($_REQUEST['nocomment']);
-
+
+ $is_poll = ((trim($_REQUEST['poll_answers'][0]) != '' && trim($_REQUEST['poll_answers'][1]) != '') ? true : false);
+
// 'origin' (if non-zero) indicates that this network is where the message originated,
// for the purpose of relaying comments to other conversation members.
// If using the API from a device (leaf node) you must set origin to 1 (default) or leave unset.
@@ -711,6 +777,27 @@ class Item extends Controller {
$str_group_allow = $gacl['allow_gid'];
$str_contact_deny = $gacl['deny_cid'];
$str_group_deny = $gacl['deny_gid'];
+
+
+ $groupww = false;
+
+ // if this is a wall-to-wall post to a group, turn it into a direct message
+
+ $role = get_pconfig($profile_uid,'system','permissions_role');
+
+ $rolesettings = PermissionRoles::role_perms($role);
+
+ $channel_type = isset($rolesettings['channel_type']) ? $rolesettings['channel_type'] : 'normal';
+
+ $is_group = (($channel_type === 'group') ? true : false);
+
+ if (($is_group) && ($walltowall) && (! $walltowall_comment)) {
+ $groupww = true;
+ $str_contact_allow = $owner_xchan['xchan_hash'];
+ $str_group_allow = '';
+ }
+
+ $post_tags = [];
if($mimetype === 'text/bbcode') {
@@ -720,19 +807,18 @@ class Item extends Controller {
// BBCODE alert: the following functions assume bbcode input
// and will require alternatives for alternative content-types (text/html, text/markdown, text/plain, etc.)
// we may need virtual or template classes to implement the possible alternatives
-
if(strpos($body,'[/summary]') !== false) {
- $match = '';
- $cnt = preg_match("/\[summary\](.*?)\[\/summary\]/ism",$body,$match);
- if($cnt) {
- $summary .= $match[1];
- }
- $body_content = preg_replace("/^(.*?)\[summary\](.*?)\[\/summary\](.*?)$/ism", '',$body);
- $body = trim($body_content);
- }
-
- $summary = cleanup_bbcode($summary);
+ $match = '';
+ $cnt = preg_match("/\[summary\](.*?)\[\/summary\]/ism",$body,$match);
+ if($cnt) {
+ $summary .= $match[1];
+ }
+ $body_content = preg_replace("/\[summary\](.*?)\[\/summary\]/ism", '',$body);
+ $body = trim($body_content);
+ }
+
+ $summary = cleanup_bbcode($summary);
$body = cleanup_bbcode($body);
@@ -746,7 +832,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 +844,7 @@ class Item extends Controller {
);
}
}
+
}
if(($str_contact_allow) && (! $str_group_allow)) {
@@ -830,8 +916,6 @@ class Item extends Controller {
$i = 0;
foreach($match[2] as $mtch) {
$reshare = new \Zotlabs\Lib\Share($mtch);
- $datarray['obj'] = $reshare->obj();
- $datarray['obj_type'] = $datarray['obj']['type'];
$body = str_replace($match[1][$i],$reshare->bbcode(),$body);
$i++;
}
@@ -924,6 +1008,27 @@ class Item extends Controller {
}
+ if($is_poll) {
+ $poll = [
+ 'question' => $body,
+ 'answers' => $_REQUEST['poll_answers'],
+ 'multiple_answers' => $_REQUEST['poll_multiple_answers'],
+ 'expire_value' => $_REQUEST['poll_expire_value'],
+ 'expire_unit' => $_REQUEST['poll_expire_unit']
+ ];
+ $obj = $this->extract_poll_data($poll, [ 'item_private' => $private, 'allow_cid' => $str_contact_allow, 'allow_gid' => $str_contact_deny ]);
+ }
+ else {
+ $obj = $this->extract_bb_poll_data($body,[ 'item_private' => $private, 'allow_cid' => $str_contact_allow, 'allow_gid' => $str_contact_deny ]);
+ }
+
+ if ($obj) {
+ $obj['url'] = $mid;
+ $obj['attributedTo'] = channel_url($channel);
+ $datarray['obj'] = $obj;
+ $obj_type = 'Question';
+ }
+
if(! $parent_mid) {
$parent_mid = $mid;
}
@@ -969,10 +1074,15 @@ 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']) {
+ $datarray['obj']['id'] = $mid;
+ }
+
$datarray['aid'] = $channel['channel_account_id'];
$datarray['uid'] = $profile_uid;
$datarray['uuid'] = $uuid;
@@ -1030,10 +1140,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
@@ -1131,7 +1240,7 @@ class Item extends Controller {
if($r) {
xchan_query($r);
$sync_item = fetch_post_tags($r);
- build_sync_packet($profile_uid,array('item' => array(encode_item($sync_item[0],true))));
+ Libsync::build_sync_packet($profile_uid,array('item' => array(encode_item($sync_item[0],true))));
}
}
if(! $nopush)
@@ -1234,7 +1343,7 @@ class Item extends Controller {
if($r) {
xchan_query($r);
$sync_item = fetch_post_tags($r);
- build_sync_packet($profile_uid,array('item' => array(encode_item($sync_item[0],true))));
+ Libsync::build_sync_packet($profile_uid,array('item' => array(encode_item($sync_item[0],true))));
}
}
@@ -1242,7 +1351,11 @@ class Item extends Controller {
$datarray['llink'] = z_root() . '/display/' . gen_link_id($datarray['mid']);
call_hooks('post_local_end', $datarray);
-
+
+ if ($groupww) {
+ $nopush = false;
+ }
+
if(! $nopush)
Master::Summon([ 'Notifier', $notify_type, $post_id ]);
@@ -1336,7 +1449,7 @@ class Item extends Controller {
if($r) {
xchan_query($r);
$sync_item = fetch_post_tags($r);
- 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) {
@@ -1389,5 +1502,104 @@ class Item extends Controller {
return $ret;
}
-
+ function extract_bb_poll_data(&$body,$item) {
+
+ $multiple = false;
+
+ if (strpos($body,'[/question]') === false && strpos($body,'[/answer]') === false) {
+ return false;
+ }
+ if (strpos($body,'[nobb]') !== false) {
+ return false;
+ }
+
+
+ $obj = [];
+ $ptr = [];
+ $matches = null;
+ $obj['type'] = 'Question';
+
+ if (preg_match_all('/\[answer\](.*?)\[\/answer\]/ism',$body,$matches,PREG_SET_ORDER)) {
+ foreach ($matches as $match) {
+ $ptr[] = [ 'name' => $match[1], 'type' => 'Note', 'replies' => [ 'type' => 'Collection', 'totalItems' => 0 ]];
+ $body = str_replace('[answer]' . $match[1] . '[/answer]', EMPTY_STR, $body);
+ }
+ }
+
+ $matches = null;
+
+ if (preg_match('/\[question\](.*?)\[\/question\]/ism',$body,$matches)) {
+ $obj['content'] = bbcode($matches[1]);
+ $body = str_replace('[question]' . $matches[1] . '[/question]', $matches[1], $body);
+ $obj['oneOf'] = $ptr;
+ }
+
+ $matches = null;
+
+ if (preg_match('/\[question=multiple\](.*?)\[\/question\]/ism',$body,$matches)) {
+ $obj['content'] = bbcode($matches[1]);
+ $body = str_replace('[question=multiple]' . $matches[1] . '[/question]', $matches[1], $body);
+ $obj['anyOf'] = $ptr;
+ }
+
+ $matches = null;
+
+ if (preg_match('/\[ends\](.*?)\[\/ends\]/ism',$body,$matches)) {
+ $obj['endTime'] = datetime_convert(date_default_timezone_get(),'UTC', $matches[1],ATOM_TIME);
+ $body = str_replace('[ends]' . $matches[1] . '[/ends]', EMPTY_STR, $body);
+ }
+
+
+ if ($item['item_private']) {
+ $obj['to'] = Activity::map_acl($item);
+ }
+ else {
+ $obj['to'] = [ ACTIVITY_PUBLIC_INBOX ];
+ }
+
+ return $obj;
+
+ }
+
+
+ function extract_poll_data($poll, $item) {
+
+ $multiple = intval($poll['multiple_answers']);
+ $expire_value = intval($poll['expire_value']);
+ $expire_unit = $poll['expire_unit'];
+ $question = $poll['question'];
+ $answers = $poll['answers'];
+
+ $obj = [];
+ $ptr = [];
+ $obj['type'] = 'Question';
+ $obj['content'] = bbcode($question);
+
+ foreach($answers as $answer) {
+ if(trim($answer))
+ $ptr[] = [ 'name' => escape_tags($answer), 'type' => 'Note', 'replies' => [ 'type' => 'Collection', 'totalItems' => 0 ]];
+ }
+
+ if($multiple) {
+ $obj['anyOf'] = $ptr;
+ }
+ else {
+ $obj['oneOf'] = $ptr;
+ }
+
+ $obj['endTime'] = datetime_convert(date_default_timezone_get(), 'UTC', 'now + ' . $expire_value . ' ' . $expire_unit, ATOM_TIME);
+
+ if ($item['item_private']) {
+ $obj['to'] = Activity::map_acl($item);
+ }
+ else {
+ $obj['to'] = [ ACTIVITY_PUBLIC_INBOX ];
+ }
+
+ return $obj;
+
+ }
+
+
+
}
diff --git a/Zotlabs/Module/Like.php b/Zotlabs/Module/Like.php
index 052d51d43..8ffa7f66c 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');
@@ -75,7 +76,12 @@ class Like extends \Zotlabs\Web\Controller {
return EMPTY_STR;
}
-
+ $is_rsvp = false;
+ if (in_array($activity, [ ACTIVITY_ATTEND, ACTIVITY_ATTENDNO, ACTIVITY_ATTENDMAYBE ])) {
+ $is_rsvp = true;
+ }
+
+
$extended_like = false;
$object = $target = null;
$post_type = EMPTY_STR;
@@ -204,20 +210,8 @@ class Like extends \Zotlabs\Web\Controller {
if(! $plink)
$plink = '[zrl=' . z_root() . '/profile/' . $ch[0]['channel_address'] . ']' . $post_type . '[/zrl]';
- $links = array();
- $links[] = array('rel' => 'alternate', 'type' => 'text/html',
- 'href' => z_root() . '/profile/' . $ch[0]['channel_address']);
- $links[] = array('rel' => 'photo', 'type' => $ch[0]['xchan_photo_mimetype'],
- 'href' => $ch[0]['xchan_photo_l']);
-
- $object = json_encode(array(
- 'type' => ACTIVITY_OBJ_PROFILE,
- 'title' => $ch[0]['channel_name'],
- 'id' => $ch[0]['xchan_url'] . '/' . $ch[0]['xchan_hash'],
- 'link' => $links
- ));
-
-
+ $object = json_encode(Activity::fetch_profile([ 'id' => channel_url($ch[0]) ]));
+
// second like of the same thing is "undo" for the first like
$z = q("select * from likes where channel_id = %d and liker = '%s' and verb = '%s' and target_type = '%s' and target_id = '%s' limit 1",
@@ -230,7 +224,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'])
@@ -381,7 +375,7 @@ class Like extends \Zotlabs\Web\Controller {
$arr = array();
$arr['uuid'] = $uuid;
- $arr['mid'] = z_root() . '/item/' . $uuid;
+ $arr['mid'] = z_root() . (($is_rsvp) ? '/activity/' : '/item/') . $uuid;
if($extended_like) {
$arr['item_thread_top'] = 1;
@@ -402,27 +396,8 @@ class Like extends \Zotlabs\Web\Controller {
$body = $item['body'];
- $object = json_encode(array(
- 'type' => $objtype,
- 'id' => $item['mid'],
- 'asld' => Activity::fetch_item( [ 'id' => $item['mid'] ] ),
- 'parent' => (($item['thr_parent']) ? $item['thr_parent'] : $item['parent_mid']),
- 'link' => $links,
- 'title' => $item['title'],
- 'content' => $item['body'],
- 'created' => $item['created'],
- 'edited' => $item['edited'],
- 'author' => array(
- 'name' => $item_author['xchan_name'],
- 'address' => $item_author['xchan_addr'],
- 'guid' => $item_author['xchan_guid'],
- 'guid_sig' => $item_author['xchan_guid_sig'],
- 'link' => array(
- array('rel' => 'alternate', 'type' => 'text/html', 'href' => $item_author['xchan_url']),
- array('rel' => 'photo', 'type' => $item_author['xchan_photo_mimetype'], 'href' => $item_author['xchan_photo_m'])),
- ),
- ));
-
+ $object = json_encode(Activity::fetch_item( [ 'id' => $item['mid'] ]));
+
if(! intval($item['item_thread_top']))
$post_type = 'comment';
@@ -466,15 +441,15 @@ class Like extends \Zotlabs\Web\Controller {
if($extended_like) {
- $ulink = '[zrl=' . $ch[0]['xchan_url'] . ']' . $ch[0]['xchan_name'] . '[/zrl]';
- $alink = '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]';
+ $ulink = '[zrl=' . $ch[0]['xchan_url'] . '][bdi]' . $ch[0]['xchan_name'] . '[/bdi][/zrl]';
+ $alink = '[zrl=' . $observer['xchan_url'] . '][bdi]' . $observer['xchan_name'] . '[/bdi][/zrl]';
$private = (($public) ? 0 : 1);
}
else {
$arr['parent'] = $item['id'];
$arr['thr_parent'] = $item['mid'];
- $ulink = '[zrl=' . $item_author['xchan_url'] . ']' . $item_author['xchan_name'] . '[/zrl]';
- $alink = '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]';
+ $ulink = '[zrl=' . $item_author['xchan_url'] . '][bdi]' . $item_author['xchan_name'] . '[/bdi][/zrl]';
+ $alink = '[zrl=' . $observer['xchan_url'] . '][bdi]' . $observer['xchan_name'] . '[/bdi][/zrl]';
$plink = '[zrl=' . z_root() . '/display/' . gen_link_id($item['mid']) . ']' . $post_type . '[/zrl]';
$allow_cid = $item['allow_cid'];
$allow_gid = $item['allow_gid'];
@@ -561,7 +536,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/Locs.php b/Zotlabs/Module/Locs.php
index 47ece8041..4c935a6a2 100644
--- a/Zotlabs/Module/Locs.php
+++ b/Zotlabs/Module/Locs.php
@@ -1,22 +1,24 @@
<?php
namespace Zotlabs\Module; /** @file */
+use App;
+use Zotlabs\Web\Controller;
+use Zotlabs\Daemon\Master;
-
-class Locs extends \Zotlabs\Web\Controller {
+class Locs extends Controller {
function post() {
if(! local_channel())
return;
- $channel = \App::get_channel();
+ $channel = App::get_channel();
if($_REQUEST['primary']) {
$hubloc_id = intval($_REQUEST['primary']);
if($hubloc_id) {
- $r = q("select hubloc_id from hubloc where hubloc_id = %d and hubloc_hash = '%s' limit 1",
+ $r = q("select * from hubloc where hubloc_id = %d and hubloc_hash = '%s' limit 1",
intval($hubloc_id),
dbesc($channel['channel_hash'])
);
@@ -26,15 +28,16 @@ class Locs extends \Zotlabs\Web\Controller {
return;
}
- $r = q("update hubloc set hubloc_primary = 0 where hubloc_primary = 1 and hubloc_hash = '%s' ",
- dbesc($channel['channel_hash'])
+ q("UPDATE hubloc SET hubloc_primary = 0 WHERE hubloc_primary = 1 AND (hubloc_hash = '%s' OR hubloc_hash = '%s')",
+ dbesc($channel['channel_hash']),
+ dbesc($channel['channel_portable_id'])
);
- $r = q("update hubloc set hubloc_primary = 1 where hubloc_id = %d and hubloc_hash = '%s'",
+ q("UPDATE hubloc SET hubloc_primary = 1 WHERE hubloc_id = %d AND hubloc_hash = '%s'",
intval($hubloc_id),
dbesc($channel['channel_hash'])
);
-
- \Zotlabs\Daemon\Master::Summon(array('Notifier','location',$channel['channel_id']));
+
+ Master::Summon( [ 'Notifier', 'refresh_all', $channel['channel_id'] ] );
return;
}
}
@@ -68,11 +71,12 @@ class Locs extends \Zotlabs\Web\Controller {
}
}
- $r = q("update hubloc set hubloc_deleted = 1 where hubloc_id = %d and hubloc_hash = '%s'",
- intval($hubloc_id),
- dbesc($channel['channel_hash'])
+ q("UPDATE hubloc SET hubloc_deleted = 1 WHERE hubloc_id_url = '%s' AND (hubloc_hash = '%s' OR hubloc_hash = '%s')",
+ dbesc($r[0]['hubloc_id_url']),
+ dbesc($channel['channel_hash']),
+ dbesc($channel['channel_portable_id'])
);
- \Zotlabs\Daemon\Master::Summon(array('Notifier','location',$channel['channel_id']));
+ Master::Summon( [ 'Notifier', 'refresh_all', $channel['channel_id'] ] );
return;
}
}
@@ -88,10 +92,10 @@ class Locs extends \Zotlabs\Web\Controller {
return;
}
- $channel = \App::get_channel();
+ $channel = App::get_channel();
if($_REQUEST['sync']) {
- \Zotlabs\Daemon\Master::Summon(array('Notifier','location',$channel['channel_id']));
+ Master::Summon( [ 'Notifier', 'refresh_all', $channel['channel_id'] ] );
info( t('Syncing locations') . EOL);
goaway(z_root() . '/locs');
}
diff --git a/Zotlabs/Module/Magic.php b/Zotlabs/Module/Magic.php
index 6ac656a04..b4372e26d 100644
--- a/Zotlabs/Module/Magic.php
+++ b/Zotlabs/Module/Magic.php
@@ -1,214 +1,133 @@
<?php
namespace Zotlabs\Module;
+use App;
+use Zotlabs\Web\Controller;
use Zotlabs\Web\HTTPSig;
+use Zotlabs\Lib\Libzot;
+use Zotlabs\Lib\SConfig;
-@require_once('include/zot.php');
-
-
-class Magic extends \Zotlabs\Web\Controller {
+class Magic extends Controller {
function init() {
+
+ $ret = [
+ 'success' => false,
+ 'url' => '',
+ 'message' => ''
+ ];
- $ret = array('success' => false, 'url' => '', 'message' => '');
logger('mod_magic: invoked', LOGGER_DEBUG);
-
- logger('mod_magic: args: ' . print_r($_REQUEST,true),LOGGER_DATA);
-
- $addr = ((x($_REQUEST,'addr')) ? $_REQUEST['addr'] : '');
- $bdest = ((x($_REQUEST,'bdest')) ? $_REQUEST['bdest'] : '');
- $dest = ((x($_REQUEST,'dest')) ? $_REQUEST['dest'] : '');
- $test = ((x($_REQUEST,'test')) ? intval($_REQUEST['test']) : 0);
- $rev = ((x($_REQUEST,'rev')) ? intval($_REQUEST['rev']) : 0);
- $owa = ((x($_REQUEST,'owa')) ? intval($_REQUEST['owa']) : 0);
- $delegate = ((x($_REQUEST,'delegate')) ? $_REQUEST['delegate'] : '');
-
- if($bdest)
+
+ logger('args: ' . print_r($_REQUEST,true),LOGGER_DATA);
+
+ $addr = ((x($_REQUEST,'addr')) ? $_REQUEST['addr'] : '');
+ $bdest = ((x($_REQUEST,'bdest')) ? $_REQUEST['bdest'] : '');
+ $dest = ((x($_REQUEST,'dest')) ? $_REQUEST['dest'] : '');
+ $rev = ((x($_REQUEST,'rev')) ? intval($_REQUEST['rev']) : 0);
+ $owa = ((x($_REQUEST,'owa')) ? intval($_REQUEST['owa']) : 0);
+ $delegate = ((x($_REQUEST,'delegate')) ? $_REQUEST['delegate'] : '');
+
+ // bdest is preferred as it is hex-encoded and can survive url rewrite and argument parsing
+
+ if ($bdest) {
$dest = hex2bin($bdest);
+ }
$parsed = parse_url($dest);
- if(! $parsed) {
- if($test) {
- $ret['message'] .= 'could not parse ' . $dest . EOL;
- return($ret);
- }
+
+ if (! $parsed) {
goaway($dest);
}
-
+
$basepath = $parsed['scheme'] . '://' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : '');
-
- $x = q("select * from hubloc where hubloc_url = '%s' order by hubloc_connected desc limit 1",
- dbesc($basepath)
- );
-
- if(! $x) {
-
- /*
- * We have no records for, or prior communications with this hub.
- * If an address was supplied, let's finger them to create a hub record.
- * Otherwise we'll use the special address '[system]' which will return
- * either a system channel or the first available normal channel. We don't
- * really care about what channel is returned - we need the hub information
- * from that response so that we can create signed auth packets destined
- * for that hub.
- *
- */
-
- $j = \Zotlabs\Zot\Finger::run((($addr) ? $addr : '[system]@' . $parsed['host']),null);
- if($j['success']) {
- import_xchan($j);
-
- // Now try again
-
- $x = q("select * from hubloc where hubloc_url = '%s' order by hubloc_connected desc limit 1",
- dbesc($basepath)
- );
- }
- }
-
- if(! $x) {
- if($rev)
- goaway($dest);
- else {
- logger('mod_magic: no channels found for requested hub.' . print_r($_REQUEST,true));
- if($test) {
- $ret['message'] .= 'This site has no previous connections with ' . $basepath . EOL;
- return $ret;
- }
- notice( t('Hub not found.') . EOL);
- return;
- }
- }
-
+ $owapath = SConfig::get($basepath,'system','openwebauth', $basepath . '/owa');
+
// This is ready-made for a plugin that provides a blacklist or "ask me" before blindly authenticating.
// By default, we'll proceed without asking.
-
- $arr = array(
- 'channel_id' => local_channel(),
- 'xchan' => $x[0],
+
+ $arr = [
+ 'channel_id' => local_channel(),
'destination' => $dest,
- 'proceed' => true
- );
-
+ 'proceed' => true
+ ];
+
call_hooks('magic_auth',$arr);
$dest = $arr['destination'];
- if(! $arr['proceed']) {
- if($test) {
- $ret['message'] .= 'cancelled by plugin.' . EOL;
- return $ret;
- }
+ if (! $arr['proceed']) {
goaway($dest);
}
-
- if((get_observer_hash()) && ($x[0]['hubloc_url'] === z_root())) {
+
+ if((get_observer_hash()) && (stripos($dest,z_root()) === 0)) {
+
// We are already authenticated on this site and a registered observer.
- // Just redirect.
- if($test) {
- $ret['success'] = true;
- $ret['message'] .= 'Local site - you are already authenticated.' . EOL;
- return $ret;
- }
-
- $delegation_success = false;
- if($delegate) {
+ // First check if this is a delegate request on the local system and process accordingly.
+ // Otherwise redirect.
+
+ if ($delegate) {
+
$r = q("select * from channel left join hubloc on channel_hash = hubloc_hash where hubloc_addr = '%s' limit 1",
dbesc($delegate)
);
-
- if($r && intval($r[0]['channel_id'])) {
- $allowed = perm_is_allowed($r[0]['channel_id'],get_observer_hash(),'delegate');
- if($allowed) {
+
+ if ($r) {
+ $c = array_shift($r);
+ if (perm_is_allowed($c['channel_id'],get_observer_hash(),'delegate')) {
$tmp = $_SESSION;
- $_SESSION['delegate_push'] = $tmp;
- $_SESSION['delegate_channel'] = $r[0]['channel_id'];
- $_SESSION['delegate'] = get_observer_hash();
- $_SESSION['account_id'] = intval($r[0]['channel_account_id']);
- change_channel($r[0]['channel_id']);
-
- $delegation_success = true;
+ $_SESSION['delegate_push'] = $tmp;
+ $_SESSION['delegate_channel'] = $c['channel_id'];
+ $_SESSION['delegate'] = get_observer_hash();
+ $_SESSION['account_id'] = intval($c['channel_account_id']);
+
+ change_channel($c['channel_id']);
}
}
}
-
-
-
- // FIXME: check and honour local delegation
-
-
+
goaway($dest);
}
-
- if(local_channel()) {
- $channel = \App::get_channel();
-
+
+ if (local_channel()) {
+ $channel = App::get_channel();
+
// OpenWebAuth
- if($owa) {
+ if ($owa) {
$dest = strip_zids($dest);
$dest = strip_query_param($dest,'f');
+ // We now post to the OWA endpoint. This improves security by providing a signed digest
+
$data = json_encode([ 'OpenWebAuth' => random_string() ]);
$headers = [];
$headers['Accept'] = 'application/x-zot+json' ;
+ $headers['Content-Type'] = 'application/x-zot+json' ;
$headers['X-Open-Web-Auth'] = random_string();
- $headers['Host'] = $parsed['host'];
$headers['Digest'] = HTTPSig::generate_digest_header($data);
+ $headers['Host'] = $parsed['host'];
+ $headers['(request-target)'] = 'post ' . '/owa';
- $headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], 'acct:' . channel_reddress($channel),true,'sha512');
- $x = z_post_url($basepath . '/owa',$data,$redirects,[ 'headers' => $headers ]);
-
- if($x['success']) {
+ $headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], channel_url($channel),true,'sha512');
+ $x = z_post_url($owapath,$data,$redirects,[ 'headers' => $headers ]);
+ logger('owa fetch returned: ' . print_r($x,true),LOGGER_DATA);
+ if ($x['success']) {
$j = json_decode($x['body'],true);
- if($j['success']) {
+ if ($j['success'] && $j['encrypted_token']) {
+ // decrypt the token using our private key
$token = '';
- if($j['encrypted_token']) {
- openssl_private_decrypt(base64url_decode($j['encrypted_token']),$token,$channel['channel_prvkey']);
- }
- else {
- $token = $j['token'];
- }
-
- $strp = strpbrk($dest,'?&');
- $args = (($strp) ? '&owt=' . $token : '?f=&owt=' . $token) . (($delegate) ? '&delegate=1' : '');
+ openssl_private_decrypt(base64url_decode($j['encrypted_token']),$token,$channel['channel_prvkey']);
+ $x = strpbrk($dest,'?&');
+ // redirect using the encrypted token which will be exchanged for an authenticated session
+ $args = (($x) ? '&owt=' . $token : '?f=&owt=' . $token) . (($delegate) ? '&delegate=1' : '');
goaway($dest . $args);
}
}
- goaway($dest);
- }
-
-
- $token = random_string();
-
- \Zotlabs\Lib\Verify::create('auth',$channel['channel_id'],$token,$x[0]['hubloc_url']);
-
- $target_url = $x[0]['hubloc_callback'] . '/?f=&auth=' . urlencode(channel_reddress($channel))
- . '&sec=' . $token . '&dest=' . urlencode($dest) . '&version=' . ZOT_REVISION;
-
- if($delegate)
- $target_url .= '&delegate=' . urlencode($delegate);
-
- logger('mod_magic: redirecting to: ' . $target_url, LOGGER_DEBUG);
-
- if($test) {
- $ret['success'] = true;
- $ret['url'] = $target_url;
- $ret['message'] = 'token ' . $token . ' created for channel ' . $channel['channel_id'] . ' for url ' . $x[0]['hubloc_url'] . EOL;
- return $ret;
}
-
- goaway($target_url);
-
}
-
- if($test) {
- $ret['message'] = 'Not authenticated or invalid arguments to mod_magic' . EOL;
- return $ret;
- }
-
+
goaway($dest);
-
}
-
+
}
diff --git a/Zotlabs/Module/Mail.php b/Zotlabs/Module/Mail.php
deleted file mode 100644
index 7c344966b..000000000
--- a/Zotlabs/Module/Mail.php
+++ /dev/null
@@ -1,449 +0,0 @@
-<?php
-namespace Zotlabs\Module;
-
-require_once('include/acl_selectors.php');
-require_once('include/message.php');
-require_once('include/zot.php');
-require_once("include/bbcode.php");
-
-
-
-
-class Mail extends \Zotlabs\Web\Controller {
-
- function post() {
-
- if(! local_channel())
- return;
-
- $replyto = ((x($_REQUEST,'replyto')) ? notags(trim($_REQUEST['replyto'])) : '');
- $subject = ((x($_REQUEST,'subject')) ? notags(trim($_REQUEST['subject'])) : '');
- $body = ((x($_REQUEST,'body')) ? escape_tags(trim($_REQUEST['body'])) : '');
- $recipient = ((x($_REQUEST,'messageto')) ? notags(trim(urldecode($_REQUEST['messageto']))) : '');
- $rstr = ((x($_REQUEST,'messagerecip')) ? notags(trim($_REQUEST['messagerecip'])) : '');
- $preview = ((x($_REQUEST,'preview')) ? intval($_REQUEST['preview']) : 0);
- $expires = ((x($_REQUEST,'expires')) ? datetime_convert(date_default_timezone_get(),'UTC', $_REQUEST['expires']) : NULL_DATE);
- $raw = ((x($_REQUEST,'raw')) ? intval($_REQUEST['raw']) : 0);
- $mimetype = ((x($_REQUEST,'mimetype')) ? notags(trim($_REQUEST['mimetype'])) : 'text/bbcode');
-
- $sig = ((x($_REQUEST,'signature')) ? trim($_REQUEST['signature']) : '');
- if(strpos($sig,'b64.') === 0)
- $sig = base64_decode(str_replace('b64.', '', $sig));
-
- if($preview) {
-
- if($raw) {
- $body = mail_prepare_binary(['id' => 'M0']);
- echo json_encode(['preview' => $body]);
- }
- else {
- $body = cleanup_bbcode($body);
- $results = linkify_tags($body, local_channel());
-
- if(preg_match_all('/(\[attachment\](.*?)\[\/attachment\])/',$body,$match)) {
- $attachments = array();
- foreach($match[2] as $mtch) {
- $hash = substr($mtch,0,strpos($mtch,','));
- $rev = intval(substr($mtch,strpos($mtch,',')));
- $r = attach_by_hash_nodata($hash,get_observer_hash(),$rev);
- if($r['success']) {
- $attachments[] = array(
- 'href' => z_root() . '/attach/' . $r['data']['hash'],
- 'length' => $r['data']['filesize'],
- 'type' => $r['data']['filetype'],
- 'title' => urlencode($r['data']['filename']),
- 'revision' => $r['data']['revision']
- );
- }
- $body = trim(str_replace($match[1],'',$body));
- }
- }
- echo json_encode(['preview' => zidify_links(smilies(bbcode($body)))]);
- }
- killme();
- }
-
- // If we have a raw string for a recipient which hasn't been auto-filled,
- // it means they probably aren't in our address book, hence we don't know
- // if we have permission to send them private messages.
- // finger them and find out before we try and send it.
-
- if(! $recipient) {
- $channel = \App::get_channel();
-
- $j = \Zotlabs\Zot\Finger::run(punify($rstr),$channel);
-
- if(! $j['success']) {
- notice( t('Unable to lookup recipient.') . EOL);
- return;
- }
-
- logger('message_post: lookup: ' . $rstr . ' ' . print_r($j,true));
-
- if(! $j['guid']) {
- notice( t('Unable to communicate with requested channel.'));
- return;
- }
-
- $x = import_xchan($j);
-
- if(! $x['success']) {
- notice( t('Cannot verify requested channel.'));
- return;
- }
-
- $recipient = $x['hash'];
-
- $their_perms = 0;
-
- if($j['permissions']['data']) {
- $permissions = crypto_unencapsulate($j['permissions'],$channel['channel_prvkey']);
- if($permissions)
- $permissions = json_decode($permissions, true);
- logger('decrypted permissions: ' . print_r($permissions,true), LOGGER_DATA);
- }
- else
- $permissions = $j['permissions'];
-
- if(! ($permissions['post_mail'])) {
- notice( t('Selected channel has private message restrictions. Send failed.'));
- // reported issue: let's still save the message and continue. We'll just tell them
- // that nothing useful is likely to happen. They might have spent hours on it.
- // return;
-
- }
- }
-
- require_once('include/text.php');
- linkify_tags($body, local_channel());
-
-
- if(! $recipient) {
- notice('No recipient found.');
- \App::$argc = 2;
- \App::$argv[1] = 'new';
- return;
- }
-
- // We have a local_channel, let send_message use the session channel and save a lookup
-
- $ret = send_message(0, $recipient, $body, $subject, $replyto, $expires, $mimetype, $raw, $sig);
-
- if($ret['success']) {
- xchan_mail_query($ret['mail']);
- build_sync_packet(0,array('conv' => array($ret['conv']),'mail' => array(encode_mail($ret['mail'],true))));
- }
- else {
- notice($ret['message']);
- }
-
- goaway(z_root() . '/mail/combined');
-
- }
-
- function get() {
-
- $o = '';
- nav_set_selected('Mail');
-
- if(! local_channel()) {
- notice( t('Permission denied.') . EOL);
- return login();
- }
-
- $channel = \App::get_channel();
-
- head_set_icon($channel['xchan_photo_s']);
-
- $cipher = get_pconfig(local_channel(),'system','default_cipher');
- if(! $cipher)
- $cipher = 'aes256';
-
- $tpl = get_markup_template('mail_head.tpl');
- $header = replace_macros($tpl, array(
- '$header' => t('Messages'),
- ));
-
- if(argc() == 3 && intval(argv(1)) && argv(2) === 'download') {
-
- $r = q("select * from mail where id = %d and channel_id = %d",
- intval(argv(1)),
- intval(local_channel())
- );
-
- if($r) {
-
- header('Content-type: ' . $r[0]['mail_mimetype']);
- header('Content-disposition: attachment; filename="' . t('message') . '-' . $r[0]['id'] . '"' );
- $body = (($r[0]['mail_obscured']) ? base64url_decode(str_rot47($r[0]['body'])) : $r[0]['body']);
- echo $body;
- killme();
- }
-
- }
-
-
- if((argc() == 4) && (argv(2) === 'drop')) {
- if(! intval(argv(3)))
- return;
- $cmd = argv(2);
- $mailbox = argv(1);
- $r = private_messages_drop(local_channel(), argv(3));
- if($r) {
- //info( t('Message deleted.') . EOL );
- }
- goaway(z_root() . '/mail/' . $mailbox);
- }
-
- if((argc() == 4) && (argv(2) === 'recall')) {
- if(! intval(argv(3)))
- return;
- $cmd = argv(2);
- $mailbox = argv(1);
- $r = q("update mail set mail_recalled = 1 where id = %d and channel_id = %d",
- intval(argv(3)),
- intval(local_channel())
- );
- $x = q("select * from mail where id = %d and channel_id = %d",
- intval(argv(3)),
- intval(local_channel())
- );
- if($x) {
- build_sync_packet(local_channel(),array('mail' => encode_mail($x[0],true)));
- }
-
- \Zotlabs\Daemon\Master::Summon(array('Notifier','mail',intval(argv(3))));
-
- if($r) {
- info( t('Message recalled.') . EOL );
- }
- goaway(z_root() . '/mail/' . $mailbox . '/' . argv(3));
-
- }
-
- if((argc() == 4) && (argv(2) === 'dropconv')) {
- if(! intval(argv(3)))
- return;
- $cmd = argv(2);
- $mailbox = argv(1);
- $r = private_messages_drop(local_channel(), argv(3), true);
- if($r)
- info( t('Conversation removed.') . EOL );
- goaway(z_root() . '/mail/' . $mailbox);
- }
-
- if((argc() > 1) && (argv(1) === 'new')) {
-
- $plaintext = true;
-
- $tpl = get_markup_template('msg-header.tpl');
-
- $header = replace_macros($tpl, array(
- '$baseurl' => z_root(),
- '$editselect' => (($plaintext) ? 'none' : '/(profile-jot-text|prvmail-text)/'),
- '$nickname' => $channel['channel_address'],
- '$linkurl' => t('Please enter a link URL:'),
- '$expireswhen' => t('Expires YYYY-MM-DD HH:MM')
- ));
-
- \App::$page['htmlhead'] .= $header;
-
- $prename = '';
- $preid = '';
-
- if(x($_REQUEST,'hash')) {
-
- $r = q("select abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash
- where abook_channel = %d and abook_xchan = '%s' limit 1",
- intval(local_channel()),
- dbesc($_REQUEST['hash'])
- );
-
- if(!$r) {
- $r = q("select * from xchan where xchan_hash = '%s' and xchan_network = 'zot' limit 1",
- dbesc($_REQUEST['hash'])
- );
- }
-
- if($r) {
- $prename = (($r[0]['abook_id']) ? $r[0]['xchan_name'] : $r[0]['xchan_addr']);
- $preurl = $r[0]['xchan_url'];
- $preid = (($r[0]['abook_id']) ? ($r[0]['xchan_hash']) : '');
- }
- else {
- notice( t('Requested channel is not in this network') . EOL );
- }
-
- }
-
- $tpl = get_markup_template('prv_message.tpl');
- $o .= replace_macros($tpl,array(
- '$new' => true,
- '$header' => t('Send Private Message'),
- '$to' => t('To:'),
- '$prefill' => $prename,
- '$preid' => $preid,
- '$subject' => t('Subject:'),
- '$subjtxt' => ((x($_REQUEST,'subject')) ? strip_tags($_REQUEST['subject']) : ''),
- '$text' => ((x($_REQUEST,'body')) ? htmlspecialchars($_REQUEST['body'], ENT_COMPAT, 'UTF-8') : ''),
- '$yourmessage' => t('Your message:'),
- '$parent' => '',
- '$attach' => t('Attach file'),
- '$insert' => t('Insert web link'),
- '$submit' => t('Send'),
- '$defexpire' => '',
- '$feature_expire' => ((feature_enabled(local_channel(),'content_expire')) ? true : false),
- '$expires' => t('Set expiration date'),
- '$feature_encrypt' => ((feature_enabled(local_channel(),'content_encrypt')) ? true : false),
- '$encrypt' => t('Encrypt text'),
- '$cipher' => $cipher,
- ));
-
- return $o;
- }
-
- $direct_mid = 0;
-
- switch(argv(1)) {
- case 'combined':
- $mailbox = 'combined';
- break;
- case 'inbox':
- $mailbox = 'inbox';
- break;
- case 'outbox':
- $mailbox = 'outbox';
- break;
- default:
- $mailbox = 'combined';
-
- // notifications direct to mail/nn
-
- if(intval(argv(1)))
- $direct_mid = intval(argv(1));
- break;
- }
-
-
- $last_message = private_messages_list(local_channel(), $mailbox, 0, 1);
-
- $mid = ((argc() > 2) && (intval(argv(2)))) ? argv(2) : $last_message[0]['id'];
-
- if($direct_mid)
- $mid = $direct_mid;
-
-
- $plaintext = true;
-
- // if( local_channel() && feature_enabled(local_channel(),'richtext') )
- // $plaintext = false;
-
-
-
- if($mailbox == 'combined') {
- $messages = private_messages_fetch_conversation(local_channel(), $mid, true);
- }
- else {
- $messages = private_messages_fetch_message(local_channel(), $mid, true);
- }
-
- if(! $messages) {
- //info( t('Message not found.') . EOL);
- return;
- }
-
- if($messages[0]['to_xchan'] === $channel['channel_hash'])
- \App::$poi = $messages[0]['from'];
- else
- \App::$poi = $messages[0]['to'];
-
- $tpl = get_markup_template('msg-header.tpl');
-
- \App::$page['htmlhead'] .= replace_macros($tpl, array(
- '$nickname' => $channel['channel_address'],
- '$baseurl' => z_root(),
- '$editselect' => (($plaintext) ? 'none' : '/(profile-jot-text|prvmail-text)/'),
- '$linkurl' => t('Please enter a link URL:'),
- '$expireswhen' => t('Expires YYYY-MM-DD HH:MM')
- ));
-
- $mails = array();
-
- $seen = 0;
- $unknown = false;
-
- foreach($messages as $message) {
-
- $s = theme_attachments($message);
-
- if($message['mail_raw'])
- $message['body'] = mail_prepare_binary([ 'id' => $message['id'] ]);
- else
- $message['body'] = zidify_links(smilies(bbcode($message['body'])));
-
- $mails[] = array(
- 'mailbox' => $mailbox,
- 'id' => $message['id'],
- 'mid' => $message['mid'],
- 'from_name' => $message['from']['xchan_name'],
- 'from_url' => chanlink_hash($message['from_xchan']),
- 'from_photo' => $message['from']['xchan_photo_s'],
- 'to_name' => $message['to']['xchan_name'],
- 'to_url' => chanlink_hash($message['to_xchan']),
- 'to_photo' => $message['to']['xchan_photo_s'],
- 'subject' => $message['title'],
- 'body' => $message['body'],
- 'attachments' => $s,
- 'delete' => t('Delete message'),
- 'dreport' => t('Delivery report'),
- 'recall' => t('Recall message'),
- 'can_recall' => ($channel['channel_hash'] == $message['from_xchan']),
- 'is_recalled' => (intval($message['mail_recalled']) ? t('Message has been recalled.') : ''),
- 'date' => datetime_convert('UTC',date_default_timezone_get(),$message['created'], 'c'),
- 'sig' => base64_encode($message['sig'])
- );
-
- $seen = $message['seen'];
-
- }
-
- $recp = (($message['from_xchan'] === $channel['channel_hash']) ? 'to' : 'from');
-
- $tpl = get_markup_template('mail_display.tpl');
- $o = replace_macros($tpl, array(
- '$mailbox' => $mailbox,
- '$prvmsg_header' => $message['title'],
- '$thread_id' => $mid,
- '$thread_subject' => $message['title'],
- '$thread_seen' => $seen,
- '$delete' => t('Delete Conversation'),
- '$canreply' => (($unknown) ? false : '1'),
- '$unknown_text' => t("No secure communications available. You <strong>may</strong> be able to respond from the sender's profile page."),
- '$mails' => $mails,
-
- // reply
- '$header' => t('Send Reply'),
- '$to' => t('To:'),
- '$reply' => true,
- '$subject' => t('Subject:'),
- '$subjtxt' => $message['title'],
- '$yourmessage' => sprintf(t('Your message for %s (%s):'), $message[$recp]['xchan_name'], $message[$recp]['xchan_addr']),
- '$text' => '',
- '$parent' => $message['parent_mid'],
- '$recphash' => $message[$recp]['xchan_hash'],
- '$attach' => t('Attach file'),
- '$insert' => t('Insert web link'),
- '$submit' => t('Submit'),
- '$defexpire' => '',
- '$feature_expire' => ((feature_enabled(local_channel(),'content_expire')) ? true : false),
- '$expires' => t('Set expiration date'),
- '$feature_encrypt' => ((feature_enabled(local_channel(),'content_encrypt')) ? true : false),
- '$encrypt' => t('Encrypt text'),
- '$cipher' => $cipher,
- ));
-
- return $o;
-
- }
-
-}
diff --git a/Zotlabs/Module/Moderate.php b/Zotlabs/Module/Moderate.php
index a7c98e05e..b66b052a6 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');
@@ -14,7 +16,7 @@ class Moderate extends \Zotlabs\Web\Controller {
return;
}
- \App::set_pager_itemspage(60);
+ \App::set_pager_itemspage(30);
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(\App::$pager['itemspage']), intval(\App::$pager['start']));
//show all items
@@ -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/Network.php b/Zotlabs/Module/Network.php
index 1c16e34ef..bbacbb21e 100644
--- a/Zotlabs/Module/Network.php
+++ b/Zotlabs/Module/Network.php
@@ -69,6 +69,7 @@ class Network extends \Zotlabs\Web\Controller {
$category = ((x($_REQUEST,'cat')) ? $_REQUEST['cat'] : '');
$hashtags = ((x($_REQUEST,'tag')) ? $_REQUEST['tag'] : '');
$verb = ((x($_REQUEST,'verb')) ? $_REQUEST['verb'] : '');
+ $dm = ((x($_REQUEST,'dm')) ? $_REQUEST['dm'] : 0);
$order = get_pconfig(local_channel(), 'mod_network', 'order', 0);
@@ -132,8 +133,6 @@ class Network extends \Zotlabs\Web\Controller {
$pf = ((x($_GET,'pf')) ? $_GET['pf'] : '');
$unseen = ((x($_GET,'unseen')) ? $_GET['unseen'] : '');
- $deftag = '';
-
if (Apps::system_app_installed(local_channel(),'Affinity Tool')) {
$affinity_locked = intval(get_pconfig(local_channel(),'affinity','lock',1));
if ($affinity_locked) {
@@ -159,10 +158,7 @@ class Network extends \Zotlabs\Web\Controller {
goaway(z_root() . '/network');
// NOTREACHED
}
- if($pf)
- $deftag = '!{' . (($cid_r[0]['xchan_addr']) ? $cid_r[0]['xchan_addr'] : $cid_r[0]['xchan_url']) . '}';
- else
- $def_acl = [ 'allow_cid' => '<' . $cid_r[0]['abook_xchan'] . '>', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ];
+ $def_acl = [ 'allow_cid' => '<' . $cid_r[0]['abook_xchan'] . '>', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ];
}
if(! $update) {
@@ -176,6 +172,17 @@ class Network extends \Zotlabs\Web\Controller {
nav_set_selected('Network');
+ $bang = '!';
+
+ if($cid_r) {
+ $forums = get_forum_channels($channel['channel_id']);
+ if($forums) {
+ $forum_xchans = ids_to_array($forums, 'xchan_hash');
+ if(in_array($cid_r[0]['abook_xchan'], $forum_xchans))
+ $bang = $cid_r[0]['abook_xchan'];
+ }
+ }
+
$channel_acl = array(
'allow_cid' => $channel['channel_allow_cid'],
'allow_gid' => $channel['channel_allow_gid'],
@@ -183,7 +190,7 @@ class Network extends \Zotlabs\Web\Controller {
'deny_gid' => $channel['channel_deny_gid']
);
- $private_editing = ((($group || $cid) && (! intval($_GET['pf']))) ? true : false);
+ $private_editing = (($group || $cid) ? true : false);
$x = array(
'is_owner' => true,
@@ -193,7 +200,7 @@ class Network extends \Zotlabs\Web\Controller {
'lockstate' => (($private_editing || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
'acl' => populate_acl((($private_editing) ? $def_acl : $channel_acl), true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'),
'permissions' => (($private_editing) ? $def_acl : $channel_acl),
- 'bang' => (($private_editing) ? '!' : ''),
+ 'bang' => (($private_editing) ? $bang : ''),
'visitor' => true,
'profile_uid' => local_channel(),
'editor_autocomplete' => true,
@@ -202,9 +209,6 @@ class Network extends \Zotlabs\Web\Controller {
'jotnets' => true,
'reset' => t('Reset form')
);
- if($deftag)
- $x['pretext'] = $deftag;
-
$status_editor = status_editor($a,$x,false,'Network');
$o .= $status_editor;
@@ -339,7 +343,7 @@ class Network extends \Zotlabs\Web\Controller {
// The special div is needed for liveUpdate to kick in for this page.
// We only launch liveUpdate if you aren't filtering in some incompatible
// way and also you aren't writing a comment (discovered in javascript).
-
+
$maxheight = get_pconfig(local_channel(),'system','network_divmore_height');
if(! $maxheight)
$maxheight = 400;
@@ -363,6 +367,7 @@ class Network extends \Zotlabs\Web\Controller {
'$conv' => (($conv) ? $conv : '0'),
'$spam' => (($spam) ? $spam : '0'),
'$fh' => '0',
+ '$dm' => (($dm) ? $dm : '0'),
'$nouveau' => (($nouveau) ? $nouveau : '0'),
'$wall' => '0',
'$static' => $static,
@@ -409,15 +414,33 @@ class Network extends \Zotlabs\Web\Controller {
}
}
- if($verb) {
- $sql_extra .= sprintf(" AND item.verb like '%s' ",
- dbesc(protect_sprintf('%' . $verb . '%'))
- );
+ if ($verb) {
+
+ // the presence of a leading dot in the verb determines
+ // whether to match the type of activity or the child object.
+ // The name 'verb' is a holdover from the earlier XML
+ // ActivityStreams specification.
+
+ if (substr($verb,0,1) === '.') {
+ $verb = substr($verb,1);
+ $sql_extra .= sprintf(" AND item.obj_type like '%s' ",
+ dbesc(protect_sprintf('%' . $verb . '%'))
+ );
+ }
+ else {
+ $sql_extra .= sprintf(" AND item.verb like '%s' ",
+ dbesc(protect_sprintf('%' . $verb . '%'))
+ );
+ }
}
if(strlen($file)) {
$sql_extra .= term_query('item',$file,TERM_FILE);
}
+
+ if ($dm) {
+ $sql_extra .= " AND item_private = 2 ";
+ }
if($conv) {
$item_thread_top = '';
@@ -432,7 +455,7 @@ class Network extends \Zotlabs\Web\Controller {
}
else {
$itemspage = get_pconfig(local_channel(),'system','itemspage');
- App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20));
+ App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 10));
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start']));
}
@@ -470,7 +493,6 @@ class Network extends \Zotlabs\Web\Controller {
$page_mode = 'client';
$parents_str = '';
- $update_unseen = '';
$simple_update = (($update) ? " and item_unseen = 1 " : '');
@@ -509,9 +531,6 @@ class Network extends \Zotlabs\Web\Controller {
);
$parents_str = ids_to_querystr($items,'item_id');
- if($parents_str) {
- $update_unseen = " AND id IN ( " . dbesc($parents_str) . " )";
- }
require_once('include/items.php');
@@ -575,35 +594,6 @@ class Network extends \Zotlabs\Web\Controller {
$items = array();
}
- if($page_mode === 'list') {
-
- /**
- * in "list mode", only mark the parent item and any like activities as "seen".
- * We won't distinguish between comment likes and post likes. The important thing
- * is that the number of unseen comments will be accurate. The SQL to separate the
- * comment likes could also get somewhat hairy.
- */
-
- if($parents_str) {
- $update_unseen = " AND ( id IN ( " . dbesc($parents_str) . " )";
- $update_unseen .= " OR ( parent IN ( " . dbesc($parents_str) . " ) AND verb in ( '" . dbesc(ACTIVITY_LIKE) . "','" . dbesc(ACTIVITY_DISLIKE) . "' ))) ";
- }
- }
- else {
- if($parents_str) {
- $update_unseen = " AND parent IN ( " . dbesc($parents_str) . " )";
- }
- }
- }
-
- if($update_unseen) {
- $x = [ 'channel_id' => local_channel(), 'update' => 'unset' ];
- call_hooks('update_unseen',$x);
- if($x['update'] === 'unset' || intval($x['update'])) {
- $r = q("UPDATE item SET item_unseen = 0 WHERE item_unseen = 1 AND uid = %d $update_unseen ",
- intval(local_channel())
- );
- }
}
$mode = (($nouveau) ? 'network-new' : 'network');
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/Oep.php b/Zotlabs/Module/Oep.php
index 3977ac8dd..75304161b 100644
--- a/Zotlabs/Module/Oep.php
+++ b/Zotlabs/Module/Oep.php
@@ -125,7 +125,7 @@ class Oep extends \Zotlabs\Web\Controller {
"' profile='".$p[0]['author']['xchan_url'] .
"' avatar='".$p[0]['author']['xchan_photo_s'].
"' link='".$p[0]['plink'].
- "' auth='".(($p[0]['author']['network'] === 'zot') ? 'true' : 'false') .
+ "' auth='".((in_array($p[0]['author']['xchan_network'], ['zot6','zot'])) ? 'true' : 'false') .
"' posted='".$p[0]['created'].
"' message_id='".$p[0]['mid']."']";
if($p[0]['title'])
@@ -213,7 +213,7 @@ class Oep extends \Zotlabs\Web\Controller {
"' profile='".$p[0]['author']['xchan_url'] .
"' avatar='".$p[0]['author']['xchan_photo_s'].
"' link='".$p[0]['plink'].
- "' auth='".(($p[0]['author']['network'] === 'zot') ? 'true' : 'false') .
+ "' auth='".((in_array($p[0]['author']['xchan_network'], ['zot6','zot'])) ? 'true' : 'false') .
"' posted='".$p[0]['created'].
"' message_id='".$p[0]['mid']."']";
if($p[0]['title'])
@@ -299,7 +299,7 @@ class Oep extends \Zotlabs\Web\Controller {
"' profile='".$p[0]['author']['xchan_url'] .
"' avatar='".$p[0]['author']['xchan_photo_s'].
"' link='".$p[0]['plink'].
- "' auth='".(($p[0]['author']['network'] === 'zot') ? 'true' : 'false') .
+ "' auth='".((in_array($p[0]['author']['xchan_network'], ['zot6','zot'])) ? 'true' : 'false') .
"' posted='".$p[0]['created'].
"' message_id='".$p[0]['mid']."']";
if($p[0]['title'])
@@ -374,7 +374,7 @@ class Oep extends \Zotlabs\Web\Controller {
"' profile='".$p[0]['author']['xchan_url'] .
"' avatar='".$p[0]['author']['xchan_photo_s'].
"' link='".$p[0]['plink'].
- "' auth='".(($p[0]['author']['network'] === 'zot') ? 'true' : 'false') .
+ "' auth='".((in_array($p[0]['author']['xchan_network'], ['zot6','zot'])) ? 'true' : 'false') .
"' posted='".$p[0]['created'].
"' message_id='".$p[0]['mid']."']";
if($p[0]['title'])
diff --git a/Zotlabs/Module/Owa.php b/Zotlabs/Module/Owa.php
index 89f83bf8f..561e35754 100644
--- a/Zotlabs/Module/Owa.php
+++ b/Zotlabs/Module/Owa.php
@@ -3,10 +3,12 @@
namespace Zotlabs\Module;
use Zotlabs\Web\HTTPSig;
+use Zotlabs\Lib\Verify;
+use Zotlabs\Web\Controller;
/**
* OpenWebAuth verifier and token generator
- * See https://macgirvin.com/wiki/mike/OpenWebAuth/Home
+ * See spec/OpenWebAuth/Home.md
* Requests to this endpoint should be signed using HTTP Signatures
* using the 'Authorization: Signature' authentication method
* If the signature verifies a token is returned.
@@ -14,74 +16,51 @@ use Zotlabs\Web\HTTPSig;
* This token may be exchanged for an authenticated cookie.
*/
-class Owa extends \Zotlabs\Web\Controller {
+class Owa extends Controller {
function init() {
$ret = [ 'success' => false ];
- foreach([ 'REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION' ] as $head) {
- if(array_key_exists($head,$_SERVER) && substr(trim($_SERVER[$head]),0,9) === 'Signature') {
- if($head !== 'HTTP_AUTHORIZATION') {
- $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER[$head];
- continue;
- }
-
- $sigblock = HTTPSig::parse_sigheader($_SERVER[$head]);
- if($sigblock) {
- $keyId = $sigblock['keyId'];
-
- if($keyId) {
-
- // Hubzilla connections can have both zot and zot6 hublocs
- // The connections will usually be zot so match those first
-
- $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash
- where ( hubloc_addr = '%s' or hubloc_id_url = '%s' ) and hubloc_network = 'zot' ",
- dbesc(str_replace('acct:','',$keyId)),
- dbesc($keyId)
- );
+ if (array_key_exists('REDIRECT_REMOTE_USER',$_SERVER) && (! array_key_exists('HTTP_AUTHORIZATION',$_SERVER))) {
+ $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['REDIRECT_REMOTE_USER'];
+ }
- // If nothing was found, try searching on any network
-
- if (! $r) {
+ if (array_key_exists('HTTP_AUTHORIZATION',$_SERVER) && substr(trim($_SERVER['HTTP_AUTHORIZATION']),0,9) === 'Signature') {
+ $sigblock = HTTPSig::parse_sigheader($_SERVER['HTTP_AUTHORIZATION']);
+ if ($sigblock) {
+ $keyId = $sigblock['keyId'];
+ if ($keyId) {
+ $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash
+ where ( hubloc_addr = '%s' or hubloc_id_url = '%s' ) ",
+ dbesc(str_replace('acct:','',$keyId)),
+ dbesc($keyId)
+ );
+ if (! $r) {
+ $found = discover_by_webbie(str_replace('acct:','',$keyId));
+ if ($found) {
$r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash
- where ( hubloc_addr = '%s' or hubloc_id_url = '%s' )",
+ where ( hubloc_addr = '%s' or hubloc_id_url = '%s' ) ",
dbesc(str_replace('acct:','',$keyId)),
dbesc($keyId)
);
}
-
- // If nothing was found on any network, use network discovery and create a new record
-
- if (! $r) {
- $found = discover_by_webbie(str_replace('acct:','',$keyId));
- if($found) {
- $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash
- where ( hubloc_addr = '%s' or hubloc_id_url = '%s' ) ",
- dbesc(str_replace('acct:','',$keyId)),
- dbesc($keyId)
- );
- }
- }
-
- if ($r) {
- foreach($r as $hubloc) {
- $verified = HTTPSig::verify(file_get_contents('php://input'),$hubloc['xchan_pubkey']);
- if($verified && $verified['header_signed'] && $verified['header_valid']) {
- logger('OWA header: ' . print_r($verified,true),LOGGER_DATA);
- logger('OWA success: ' . $hubloc['hubloc_addr'],LOGGER_DATA);
- $ret['success'] = true;
- $token = random_string(32);
- \Zotlabs\Lib\Verify::create('owt',0,$token,$hubloc['hubloc_network'] . ',' . $hubloc['hubloc_addr']);
- $result = '';
- openssl_public_encrypt($token,$result,$hubloc['xchan_pubkey']);
- $ret['encrypted_token'] = base64url_encode($result);
- break;
- }
- else {
- logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_addr']);
- }
+ }
+ if ($r) {
+ foreach ($r as $hubloc) {
+ $verified = HTTPSig::verify(file_get_contents('php://input'));
+ if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) {
+ logger('OWA header: ' . print_r($verified,true),LOGGER_DATA);
+ logger('OWA success: ' . $hubloc['hubloc_addr'],LOGGER_DATA);
+ $ret['success'] = true;
+ $token = random_string(32);
+ Verify::create('owt',0,$token,$hubloc['hubloc_addr']);
+ $result = '';
+ openssl_public_encrypt($token,$result,$hubloc['xchan_pubkey']);
+ $ret['encrypted_token'] = base64url_encode($result);
+ break;
+ } else {
+ logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_addr']);
}
}
}
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/Photo.php b/Zotlabs/Module/Photo.php
index 48e2bf4a5..c88696578 100644
--- a/Zotlabs/Module/Photo.php
+++ b/Zotlabs/Module/Photo.php
@@ -67,18 +67,20 @@ class Photo extends \Zotlabs\Web\Controller {
$data = '';
- $r = q("SELECT * FROM photo WHERE imgscale = %d AND uid = %d AND photo_usage = %d LIMIT 1",
- intval($resolution),
- intval($uid),
- intval(PHOTO_PROFILE)
- );
- if($r) {
- $modified = strtotime($r[0]['edited'] . "Z");
- $mimetype = $r[0]['mimetype'];
- if(intval($r[0]['os_storage']))
- $data = file_get_contents(dbunescbin($r[0]['content']));
- else
- $data = dbunescbin($r[0]['content']);
+ if ($uid > 0) {
+ $r = q("SELECT * FROM photo WHERE imgscale = %d AND uid = %d AND photo_usage = %d LIMIT 1",
+ intval($resolution),
+ intval($uid),
+ intval(PHOTO_PROFILE)
+ );
+ if($r) {
+ $modified = strtotime($r[0]['edited'] . "Z");
+ $mimetype = $r[0]['mimetype'];
+ if(intval($r[0]['os_storage']))
+ $data = file_get_contents(dbunescbin($r[0]['content']));
+ else
+ $data = dbunescbin($r[0]['content']);
+ }
}
if(! $data) {
@@ -213,7 +215,7 @@ class Photo extends \Zotlabs\Web\Controller {
if(! $data)
killme();
-
+
$etag = '"' . md5($data . $modified) . '"';
if($modified == 0)
@@ -269,7 +271,7 @@ class Photo extends \Zotlabs\Web\Controller {
// in the event that infrastructure caching is present.
$smaxage = intval($maxage/12);
- header("Cache-Control: s-maxage=" . $smaxage . ", max-age=" . $maxage . $cachecontrol);
+ header("Cache-Control: no-cache, s-maxage=" . $smaxage . ", max-age=" . $maxage . $cachecontrol);
}
diff --git a/Zotlabs/Module/Photos.php b/Zotlabs/Module/Photos.php
index 43c9f86ee..fa9216c97 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
@@ -208,9 +210,9 @@ class Photos extends \Zotlabs\Web\Controller {
if(($m) && ($m[0]['folder'] != $_POST['move_to_album'])) {
attach_move($page_owner_uid,argv(2),$_POST['move_to_album']);
- $sync = attach_export_data(\App::$data['channel'],argv(2),true);
+ $sync = attach_export_data(\App::$data['channel'], argv(2), false);
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
@@ -706,7 +708,7 @@ class Photos extends \Zotlabs\Web\Controller {
]);
if($x = photos_album_exists($owner_uid, get_observer_hash(), $datum)) {
- \App::set_pager_itemspage(60);
+ \App::set_pager_itemspage(30);
$album = $x['display_path'];
}
else {
@@ -1287,7 +1289,7 @@ class Photos extends \Zotlabs\Web\Controller {
\App::$page['htmlhead'] .= "\r\n" . '<link rel="alternate" type="application/json+oembed" href="' . z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$cmd) . '" title="oembed" />' . "\r\n";
- \App::set_pager_itemspage(60);
+ \App::set_pager_itemspage(30);
$r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.album, p.imgscale, p.created, p.display_path
FROM photo p
diff --git a/Zotlabs/Module/Pin.php b/Zotlabs/Module/Pin.php
new file mode 100644
index 000000000..63b28754b
--- /dev/null
+++ b/Zotlabs/Module/Pin.php
@@ -0,0 +1,69 @@
+<?php
+namespace Zotlabs\Module;
+
+/*
+ * Pinned post processing
+ */
+
+use App;
+
+class Pin extends \Zotlabs\Web\Controller {
+
+
+ function init() {
+
+ if(argc() !== 2)
+ http_status_exit(400, 'Bad request');
+ }
+
+
+ function post() {
+
+ $item_id = intval($_POST['id']);
+
+ if ($item_id <= 0)
+ http_status_exit(404, 'Not found');
+
+ $observer = \App::get_observer();
+ if(! $observer)
+ http_status_exit(403, 'Forbidden');
+
+ $r = q("SELECT * FROM item WHERE id = %d AND id = parent AND item_private = 0 LIMIT 1",
+ $item_id
+ );
+ if(! $r) {
+ notice(t('Unable to locate original post.'));
+ http_status_exit(404, 'Not found');
+ }
+
+ $midb64 = 'b64.' . base64url_encode($r[0]['mid']);
+ $pinned = (in_array($midb64, get_pconfig($r[0]['uid'], 'pinned', $r[0]['item_type'], [])) ? true : false);
+
+ switch(argv(1)) {
+
+ case 'pin':
+ if(! local_channel() || (local_channel() != $r[0]['uid'] && local_channel() != is_site_admin()))
+ http_status_exit(403, 'Forbidden');
+ // Currently allow only one pinned item for each type
+ set_pconfig($r[0]['uid'], 'pinned', $r[0]['item_type'], ($pinned ? [] : [ $midb64 ]));
+ if($pinned)
+ del_pconfig($r[0]['uid'], 'pinned_hide', $midb64);
+ break;
+
+ case 'hide':
+ if($pinned) {
+ $hidden = get_pconfig($r[0]['uid'], 'pinned_hide', $midb64, []);
+ if(! in_array($observer['xchan_hash'], $hidden)) {
+ $hidden[] = $observer['xchan_hash'];
+ set_pconfig($r[0]['uid'], 'pinned_hide', $midb64, $hidden);
+ }
+ }
+ break;
+
+ default:
+ http_status_exit(404, 'Not found');
+ }
+
+ build_sync_packet($r[0]['uid'], [ 'config' ]);
+ }
+}
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..9ac0e725e 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,16 +601,16 @@ 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();
if($namechanged && $is_default) {
- $r = q("UPDATE xchan SET xchan_name = '%s', xchan_name_date = '%s' WHERE xchan_hash = '%s'",
+ $r = q("UPDATE xchan SET xchan_name = '%s', xchan_name_date = '%s' WHERE xchan_url = '%s'",
dbesc($name),
dbesc(datetime_convert()),
- dbesc($channel['xchan_hash'])
+ dbesc(z_root() . '/channel/' . $channel['channel_address'])
);
$r = q("UPDATE channel SET channel_name = '%s' WHERE channel_hash = '%s'",
dbesc($name),
diff --git a/Zotlabs/Module/Pubstream.php b/Zotlabs/Module/Pubstream.php
index 84ac42f72..55c96b23d 100644
--- a/Zotlabs/Module/Pubstream.php
+++ b/Zotlabs/Module/Pubstream.php
@@ -62,6 +62,11 @@ class Pubstream extends \Zotlabs\Web\Controller {
$static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0);
$net = ((array_key_exists('net',$_REQUEST)) ? escape_tags($_REQUEST['net']) : '');
+ $title = replace_macros(get_markup_template("section_title.tpl"),array(
+ '$title' => (($hashtags) ? '#' . htmlspecialchars($hashtags, ENT_COMPAT,'UTF-8') : '')
+ ));
+
+ $o = (($hashtags) ? $title : '');
if(local_channel() && (! $update)) {
@@ -94,7 +99,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
'reset' => t('Reset form')
);
- $o = '<div id="jot-popup">';
+ $o .= '<div id="jot-popup">';
$o .= status_editor($a,$x,false,'Pubstream');
$o .= '</div>';
}
@@ -139,6 +144,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
'$conv' => '0',
'$spam' => '0',
'$fh' => '1',
+ '$dm' => '0',
'$nouveau' => '0',
'$wall' => '0',
'$list' => '0',
@@ -163,7 +169,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
$pager_sql = '';
}
else {
- \App::set_pager_itemspage(20);
+ \App::set_pager_itemspage(10);
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(\App::$pager['itemspage']), intval(\App::$pager['start']));
}
@@ -258,7 +264,6 @@ class Pubstream extends \Zotlabs\Web\Controller {
// Then fetch all the children of the parents that are on this page
$parents_str = '';
- $update_unseen = '';
if($r) {
@@ -285,7 +290,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
}
// fake it
- $mode = ('pubstream');
+ $mode = (($hashtags) ? 'search' : 'pubstream');
$o .= conversation($items,$mode,$update,$page_mode);
diff --git a/Zotlabs/Module/Regdir.php b/Zotlabs/Module/Regdir.php
index f4d16c562..e49f89231 100644
--- a/Zotlabs/Module/Regdir.php
+++ b/Zotlabs/Module/Regdir.php
@@ -1,6 +1,9 @@
<?php
namespace Zotlabs\Module;
+use Zotlabs\Lib\Zotfinger;
+use Zotlabs\Web\Controller;
+
/**
* With args, register a directory server for this realm.
* With no args, return a JSON array of directory servers for this realm.
@@ -14,7 +17,7 @@ namespace Zotlabs\Module;
* @param App &$a
*/
-class Regdir extends \Zotlabs\Web\Controller {
+class Regdir extends Controller {
function init() {
@@ -25,7 +28,7 @@ class Regdir extends \Zotlabs\Web\Controller {
$valid = 0;
// we probably don't need the realm as we will find out in the probe.
- // What we may want to die is throw an error if you're trying to register in a different realm
+ // What we may want to do is throw an error if you're trying to register in a different realm
// so this configuration issue can be discovered.
$realm = $_REQUEST['realm'];
@@ -59,34 +62,28 @@ class Regdir extends \Zotlabs\Web\Controller {
json_return_and_die($result);
}
- $j = \Zotlabs\Zot\Finger::run('[system]@' . $m['host']);
- if($j['success'] && $j['guid']) {
- $x = import_xchan($j);
- if($x['success']) {
- $result['success'] = true;
- }
+ $j = Zotfinger::exec($url);
+ if($j) {
+ $result['success'] = true;
}
-
- if(! $result['success'])
+ else {
$valid = 0;
-
+ }
+
q("update site set site_valid = %d where site_url = '%s'",
intval($valid),
strtolower($url)
);
-
+
json_return_and_die($result);
- } else {
-
- // We can put this in the sql without the condition after 31 august 2015 assuming
- // most directory servers will have updated by then
- // This just makes sure it happens if I forget
+
+ }
+ else {
- $sql_extra = ((datetime_convert() > datetime_convert('UTC','UTC','2015-08-31')) ? ' and site_valid = 1 ' : '' );
if ($dirmode == DIRECTORY_MODE_STANDALONE) {
$r = array(array('site_url' => z_root()));
} else {
- $r = q("select site_url from site where site_flags in ( 1, 2 ) and site_realm = '%s' and site_type = %d $sql_extra ",
+ $r = q("select site_url from site where site_flags in ( 1, 2 ) and site_realm = '%s' and site_type = %d and site_valid = 1 ",
dbesc(get_directory_realm()),
intval(SITE_TYPE_ZOT)
);
diff --git a/Zotlabs/Module/Register.php b/Zotlabs/Module/Register.php
index bc813f8e1..278cf15ca 100644
--- a/Zotlabs/Module/Register.php
+++ b/Zotlabs/Module/Register.php
@@ -118,7 +118,7 @@ class Register extends Controller {
$invite_code = ((x($_POST,'invite_code')) ? notags(trim($_POST['invite_code'])) : '');
if($using_invites && $invite_code) {
- q("delete * from register where hash = '%s'", dbesc($invite_code));
+ q("delete from register where hash = '%s'", dbesc($invite_code));
// @FIXME - this also needs to be considered when using 'invites_remaining' in mod/invite.php
set_aconfig($result['account']['account_id'],'system','invites_remaining',$num_invites);
}
diff --git a/Zotlabs/Module/Removeaccount.php b/Zotlabs/Module/Removeaccount.php
index 9d2bbd0de..cd18b79c0 100644
--- a/Zotlabs/Module/Removeaccount.php
+++ b/Zotlabs/Module/Removeaccount.php
@@ -37,7 +37,7 @@ class Removeaccount extends \Zotlabs\Web\Controller {
}
}
- $global_remove = intval($_POST['global']);
+ $global_remove = 0; //intval($_POST['global']);
account_remove($account_id, 1 - $global_remove);
}
@@ -57,7 +57,7 @@ class Removeaccount extends \Zotlabs\Web\Controller {
'$title' => t('Remove This Account'),
'$desc' => array(t('WARNING: '), t('This account and all its channels will be completely removed from the network. '), t('This action is permanent and can not be undone!')),
'$passwd' => t('Please enter your password for verification:'),
- '$global' => array('global', t('Remove this account, all its channels and all its channel clones from the network'), false, t('By default only the instances of the channels located on this hub will be removed from the network')),
+ // '$global' => array('global', t('Remove this account, all its channels and all its channel clones from the network'), false, t('By default only the instances of the channels located on this hub will be removed from the network')),
'$submit' => t('Remove Account')
));
diff --git a/Zotlabs/Module/Removeme.php b/Zotlabs/Module/Removeme.php
index 451e280c3..876d61ca6 100644
--- a/Zotlabs/Module/Removeme.php
+++ b/Zotlabs/Module/Removeme.php
@@ -37,7 +37,7 @@ class Removeme extends \Zotlabs\Web\Controller {
}
}
- $global_remove = intval($_POST['global']);
+ $global_remove = 0; //intval($_POST['global']);
channel_remove(local_channel(),1 - $global_remove,true);
@@ -60,7 +60,7 @@ class Removeme extends \Zotlabs\Web\Controller {
'$title' => t('Remove This Channel'),
'$desc' => [ t('WARNING: '), t('This channel will be completely removed from the network. '), t('This action is permanent and can not be undone!') ],
'$passwd' => t('Please enter your password for verification:'),
- '$global' => [ 'global', t('Remove this channel and all its clones from the network'), false, t('By default only the instance of the channel located on this hub will be removed from the network'), [ t('No'),t('Yes') ] ],
+ // '$global' => [ 'global', t('Remove this channel and all its clones from the network'), false, t('By default only the instance of the channel located on this hub will be removed from the network'), [ t('No'),t('Yes') ] ],
'$submit' => t('Remove Channel')
));
diff --git a/Zotlabs/Module/Rmagic.php b/Zotlabs/Module/Rmagic.php
index 8c1e5cdab..ab9ad059e 100644
--- a/Zotlabs/Module/Rmagic.php
+++ b/Zotlabs/Module/Rmagic.php
@@ -1,6 +1,7 @@
<?php
namespace Zotlabs\Module;
+use Zotlabs\Lib\Libzot;
class Rmagic extends \Zotlabs\Web\Controller {
@@ -11,23 +12,24 @@ class Rmagic extends \Zotlabs\Web\Controller {
$me = get_my_address();
if($me) {
- $r = q("select hubloc_url from hubloc where hubloc_addr = '%s' limit 1",
+ $r = q("select hubloc_url from hubloc where hubloc_addr = '%s'",
dbesc($me)
);
if(! $r) {
$w = discover_by_webbie($me);
if($w) {
- $r = q("select hubloc_url from hubloc where hubloc_addr = '%s' limit 1",
+ $r = q("select hubloc_url from hubloc where hubloc_addr = '%s'",
dbesc($me)
);
}
}
- if($r) {
- if($r[0]['hubloc_url'] === z_root())
+ if($r) {
+ $r = Libzot::zot_record_preferred($r);
+ if($r['hubloc_url'] === z_root())
goaway(z_root() . '/login');
$dest = bin2hex(z_root() . '/' . str_replace(['rmagic','zid='],['','zid_='],\App::$query_string));
- goaway($r[0]['hubloc_url'] . '/magic' . '?f=&owa=1&bdest=' . $dest);
+ goaway($r['hubloc_url'] . '/magic' . '?f=&owa=1&bdest=' . $dest);
}
}
}
@@ -55,13 +57,13 @@ class Rmagic extends \Zotlabs\Web\Controller {
$r = null;
if($address) {
- $r = q("select hubloc_url from hubloc where hubloc_addr = '%s' limit 1",
+ $r = q("select hubloc_url from hubloc where hubloc_addr = '%s'",
dbesc($address)
);
if(! $r) {
$w = discover_by_webbie($address);
if($w) {
- $r = q("select hubloc_url from hubloc where hubloc_addr = '%s' limit 1",
+ $r = q("select hubloc_url from hubloc where hubloc_addr = '%s'",
dbesc($address)
);
}
@@ -69,7 +71,8 @@ class Rmagic extends \Zotlabs\Web\Controller {
}
if($r) {
- $url = $r[0]['hubloc_url'];
+ $r = Libzot::zot_record_preferred($r);
+ $url = $r['hubloc_url'];
}
else {
$url = 'https://' . substr($address,strpos($address,'@')+1);
diff --git a/Zotlabs/Module/Search.php b/Zotlabs/Module/Search.php
index 214ece9a3..d586ae12f 100644
--- a/Zotlabs/Module/Search.php
+++ b/Zotlabs/Module/Search.php
@@ -128,6 +128,7 @@ class Search extends \Zotlabs\Web\Controller {
'$conv' => '0',
'$spam' => '0',
'$fh' => '0',
+ '$dm' => '0',
'$nouveau' => '0',
'$wall' => '0',
'$static' => $static,
@@ -158,7 +159,7 @@ class Search extends \Zotlabs\Web\Controller {
if(($update) && ($load)) {
$itemspage = get_pconfig(local_channel(),'system','itemspage');
- \App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20));
+ \App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 10));
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(\App::$pager['itemspage']), intval(\App::$pager['start']));
// in case somebody turned off public access to sys channel content with permissions
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..2eed1efc9 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');
@@ -273,10 +274,11 @@ class Channel {
}
if($name_change) {
- $r = q("update xchan set xchan_name = '%s', xchan_name_date = '%s' where xchan_hash = '%s'",
+ // change name on all associated xchans by matching the url
+ $r = q("update xchan set xchan_name = '%s', xchan_name_date = '%s' where xchan_url = '%s'",
dbesc($username),
dbesc(datetime_convert()),
- dbesc($channel['channel_hash'])
+ dbesc(z_root() . '/channel/' . $channel['channel_address'])
);
$r = q("update profile set fullname = '%s' where uid = %d and is_default = 1",
dbesc($username),
@@ -286,7 +288,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..01ae8652a 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 {
@@ -35,9 +36,9 @@ class Display {
if($browser_update < 10000)
$browser_update = 10000;
- $itemspage = ((x($_POST,'itemspage')) ? intval($_POST['itemspage']) : 20);
- if($itemspage > 100)
- $itemspage = 100;
+ $itemspage = ((x($_POST,'itemspage')) ? intval($_POST['itemspage']) : 10);
+ if($itemspage > 30)
+ $itemspage = 30;
set_pconfig(local_channel(),'system','preload_images',$preload_images);
@@ -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
}
@@ -158,7 +159,7 @@ class Display {
$browser_update = (($browser_update == 0) ? 80 : $browser_update / 1000); // default if not set: 40 seconds
$itemspage = intval(get_pconfig(local_channel(), 'system','itemspage'));
- $itemspage = (($itemspage > 0 && $itemspage < 101) ? $itemspage : 20); // default if not set: 20 items
+ $itemspage = (($itemspage > 0 && $itemspage <= 30) ? $itemspage : 10); // default if not set: 10 items
$nosmile = get_pconfig(local_channel(),'system','no_smilies');
$nosmile = (($nosmile===false)? '0': $nosmile); // default if not set: 0
@@ -196,7 +197,7 @@ class Display {
'$preload_images' => array('preload_images', t("Preload images before rendering the page"), $preload_images, t("The subjective page load time will be longer but the page will be ready when displayed"), $yes_no),
'$user_scalable' => array('user_scalable', t("Enable user zoom on mobile devices"), $user_scalable, '', $yes_no),
'$ajaxint' => array('browser_update', t("Update browser every xx seconds"), $browser_update, t('Minimum of 10 seconds, no maximum')),
- '$itemspage' => array('itemspage', t("Maximum number of conversations to load at any time:"), $itemspage, t('Maximum of 100 items')),
+ '$itemspage' => array('itemspage', t("Maximum number of conversations to load at any time:"), $itemspage, t('Maximum of 30 items')),
'$nosmile' => array('nosmile', t("Show emoticons (smilies) as images"), 1-intval($nosmile), '', $yes_no),
'$channel_menu' => [ 'channel_menu', t('Provide channel menu in navigation bar'), get_pconfig(local_channel(),'system','channel_menu',get_config('system','channel_menu',0)), t('Default: channel menu located in app menu'),$yes_no ],
'$manual_update' => array('manual_update', t('Manual conversation updates'), channel_manual_conv_update(local_channel()), t('Default is on, turning this off may increase screen jumping'), $yes_no),
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.php b/Zotlabs/Module/Sse.php
new file mode 100644
index 000000000..b68fe6705
--- /dev/null
+++ b/Zotlabs/Module/Sse.php
@@ -0,0 +1,121 @@
+<?php
+
+namespace Zotlabs\Module;
+
+use App;
+use Zotlabs\Lib\Apps;
+use Zotlabs\Web\Controller;
+use Zotlabs\Lib\Enotify;
+use Zotlabs\Lib\XConfig;
+
+class Sse extends Controller {
+
+ public static $uid;
+ public static $ob_hash;
+ public static $sse_id;
+ public static $vnotify;
+
+ function init() {
+
+ if((observer_prohibited(true))) {
+ killme();
+ }
+
+ if(! intval(get_config('system','open_pubstream',1))) {
+ if(! get_observer_hash()) {
+ killme();
+ }
+ }
+
+ // this is important!
+ session_write_close();
+
+ self::$uid = local_channel();
+ self::$ob_hash = get_observer_hash();
+ self::$sse_id = false;
+
+ if(! self::$ob_hash) {
+ if(session_id()) {
+ self::$sse_id = true;
+ self::$ob_hash = 'sse_id.' . session_id();
+ }
+ else {
+ return;
+ }
+ }
+
+ self::$vnotify = get_pconfig(self::$uid, 'system', 'vnotify');
+
+ $sys = get_sys_channel();
+ $sleep_seconds = 3;
+
+ header("Content-Type: text/event-stream");
+ header("Cache-Control: no-cache");
+ header("Connection: keep-alive");
+ header("X-Accel-Buffering: no");
+
+ while(true) {
+
+ /**
+ * Update chat presence indication (if applicable)
+ */
+
+ if(! self::$sse_id) {
+ $r = q("select cp_id, cp_room from chatpresence where cp_xchan = '%s' and cp_client = '%s' and cp_room = 0 limit 1",
+ dbesc(self::$ob_hash),
+ dbesc($_SERVER['REMOTE_ADDR'])
+ );
+ $basic_presence = false;
+ if($r) {
+ $basic_presence = true;
+ q("update chatpresence set cp_last = '%s' where cp_id = %d",
+ dbesc(datetime_convert()),
+ intval($r[0]['cp_id'])
+ );
+ }
+ if(! $basic_presence) {
+ q("insert into chatpresence ( cp_xchan, cp_last, cp_status, cp_client)
+ values( '%s', '%s', '%s', '%s' ) ",
+ dbesc(self::$ob_hash),
+ dbesc(datetime_convert()),
+ dbesc('online'),
+ dbesc($_SERVER['REMOTE_ADDR'])
+ );
+ }
+ }
+
+ XConfig::Load(self::$ob_hash);
+
+ $result = XConfig::Get(self::$ob_hash, 'sse', 'notifications', []);
+ $lock = XConfig::Get(self::$ob_hash, 'sse', 'lock');
+
+ if($result && !$lock) {
+ echo "event: notifications\n";
+ echo 'data: ' . json_encode($result);
+ echo "\n\n";
+
+ XConfig::Set(self::$ob_hash, 'sse', 'notifications', []);
+ unset($result);
+ }
+
+ // always send heartbeat to detect disconnected clients
+ echo "event: heartbeat\n";
+ echo 'data: {}';
+ echo "\n\n";
+
+ ob_end_flush();
+ flush();
+
+ if(connection_status() != CONNECTION_NORMAL || connection_aborted()) {
+ //TODO: this does not seem to be triggered
+ XConfig::Set(self::$ob_hash, 'sse', 'timestamp', NULL_DATE);
+ break;
+ }
+
+ sleep($sleep_seconds);
+
+ }
+
+ }
+
+}
diff --git a/Zotlabs/Module/Sse_bs.php b/Zotlabs/Module/Sse_bs.php
new file mode 100644
index 000000000..287c24829
--- /dev/null
+++ b/Zotlabs/Module/Sse_bs.php
@@ -0,0 +1,691 @@
+<?php
+
+namespace Zotlabs\Module;
+
+use App;
+use Zotlabs\Lib\Apps;
+use Zotlabs\Web\Controller;
+use Zotlabs\Lib\Enotify;
+
+class Sse_bs extends Controller {
+
+ public static $uid;
+ public static $ob_hash;
+ public static $sse_id;
+ public static $vnotify;
+ public static $evdays;
+ public static $limit;
+ public static $offset;
+ public static $xchans;
+
+ function init() {
+
+ self::$uid = local_channel();
+ self::$ob_hash = get_observer_hash();
+ self::$sse_id = false;
+
+ if(! self::$ob_hash) {
+ if(session_id()) {
+ self::$sse_id = true;
+ self::$ob_hash = 'sse_id.' . session_id();
+ }
+ else {
+ return;
+ }
+ }
+
+ self::$vnotify = get_pconfig(self::$uid, 'system', 'vnotify', -1);
+ self::$evdays = intval(get_pconfig(self::$uid, 'system', 'evdays'));
+ self::$limit = 50;
+ self::$offset = 0;
+ self::$xchans = '';
+
+ if($_REQUEST['sse_rmids'])
+ self::mark_read($_REQUEST['sse_rmids']);
+
+ if(!empty($_REQUEST['nquery']) && $_REQUEST['nquery'] !== '%') {
+ $nquery = $_REQUEST['nquery'];
+
+ $x = q("SELECT xchan_hash FROM xchan WHERE xchan_name LIKE '%s' OR xchan_addr LIKE '%s'",
+ dbesc($nquery . '%'),
+ dbesc($nquery . '%')
+ );
+
+ self::$xchans = ids_to_querystr($x, 'xchan_hash', true);
+ }
+
+ if(intval(argv(2)) > 0)
+ self::$offset = argv(2);
+ else
+ $_SESSION['sse_loadtime'] = datetime_convert();
+
+ $network = false;
+ $dm = false;
+ $home = false;
+ $pubs = false;
+ $f = '';
+
+ switch (argv(1)) {
+ case 'network':
+ $network = true;
+ $f = 'bs_network';
+ break;
+ case 'dm':
+ $dm = true;
+ $f = 'bs_dm';
+ break;
+ case 'home':
+ $home = true;
+ $f = 'bs_home';
+ break;
+ case 'pubs':
+ $pubs = true;
+ $f = 'bs_pubs';
+ break;
+ default:
+ }
+
+ if(self::$offset && $f) {
+ $result = self::$f(true);
+ json_return_and_die($result);
+ }
+
+ $result = array_merge(
+ self::bs_network($network),
+ self::bs_dm($dm),
+ self::bs_home($home),
+ self::bs_notify(),
+ self::bs_intros(),
+ self::bs_forums(),
+ self::bs_pubs($pubs),
+ self::bs_files(),
+ self::bs_mail(),
+ self::bs_all_events(),
+ self::bs_register()
+ );
+
+ set_xconfig(self::$ob_hash, 'sse', 'timestamp', datetime_convert());
+ set_xconfig(self::$ob_hash, 'sse', 'notifications', []); // reset the cache
+ set_xconfig(self::$ob_hash, 'sse', 'language', App::$language);
+
+ json_return_and_die($result);
+ }
+
+ function mark_read($arr) {
+
+ if(! self::$uid)
+ return;
+
+ $mids = [];
+ $str = '';
+
+ foreach($arr as $a) {
+ $mids[] = '\'' . dbesc(@base64url_decode(substr($a,4))) . '\'';
+ }
+
+ $str = implode($mids, ',');
+
+ $x = [ 'channel_id' => self::$uid, 'update' => 'unset' ];
+ call_hooks('update_unseen',$x);
+
+ if($x['update'] === 'unset' || intval($x['update'])) {
+ q("UPDATE item SET item_unseen = 0 WHERE uid = %d AND mid in (%s) AND item_unseen = 1",
+ intval(self::$uid),
+ $str // this is dbesc() in the above foreach loop
+ );
+ }
+
+ }
+
+ function bs_network($notifications) {
+
+ $result['network']['notifications'] = [];
+ $result['network']['count'] = 0;
+
+ if(! self::$uid)
+ return $result;
+
+ if(! (self::$vnotify & VNOTIFY_NETWORK))
+ return $result;
+
+ $limit = intval(self::$limit);
+ $offset = self::$offset;
+
+ $sql_extra = '';
+ if(! (self::$vnotify & VNOTIFY_LIKE))
+ $sql_extra = " AND verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
+
+ $sql_extra2 = '';
+ if(self::$xchans)
+ $sql_extra2 = " AND CASE WHEN verb = '" . ACTIVITY_SHARE . "' THEN owner_xchan ELSE author_xchan END IN (" . self::$xchans . ") ";
+
+ $item_normal = item_normal();
+
+ if ($notifications) {
+ $items = q("SELECT * FROM item
+ WHERE uid = %d
+ AND created <= '%s'
+ AND item_unseen = 1 AND item_wall = 0 AND item_private IN (0, 1)
+ AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
+ AND author_xchan != '%s'
+ $item_normal
+ $sql_extra
+ $sql_extra2
+ ORDER BY created DESC LIMIT $limit OFFSET $offset",
+ intval(self::$uid),
+ dbescdate($_SESSION['sse_loadtime']),
+ dbesc(self::$ob_hash)
+ );
+
+ if($items) {
+ $result['network']['offset'] = ((count($items) == $limit) ? intval($offset + $limit) : -1);
+ xchan_query($items);
+ foreach($items as $item) {
+ $result['network']['notifications'][] = Enotify::format($item);
+ }
+ }
+ else {
+ $result['network']['offset'] = -1;
+ }
+
+ }
+
+ $r = q("SELECT count(id) as total FROM item
+ WHERE uid = %d and item_unseen = 1 AND item_wall = 0 AND item_private IN (0, 1)
+ AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
+ AND author_xchan != '%s'
+ $item_normal
+ $sql_extra",
+ intval(self::$uid),
+ dbesc(self::$ob_hash)
+ );
+
+ if($r)
+ $result['network']['count'] = intval($r[0]['total']);
+
+ return $result;
+ }
+
+ function bs_dm($notifications) {
+
+ $result['dm']['notifications'] = [];
+ $result['dm']['count'] = 0;
+
+ if(! self::$uid)
+ return $result;
+
+ if(! (self::$vnotify & VNOTIFY_MAIL))
+ return $result;
+
+ $limit = intval(self::$limit);
+ $offset = self::$offset;
+
+ $sql_extra = '';
+ if(! (self::$vnotify & VNOTIFY_LIKE))
+ $sql_extra = " AND verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
+
+ $sql_extra2 = '';
+ if(self::$xchans)
+ $sql_extra2 = " AND CASE WHEN verb = '" . ACTIVITY_SHARE . "' THEN owner_xchan ELSE author_xchan END IN (" . self::$xchans . ") ";
+
+ $item_normal = item_normal();
+
+ if ($notifications) {
+ $items = q("SELECT * FROM item
+ WHERE uid = %d
+ AND created <= '%s'
+ AND item_unseen = 1 AND item_wall = 0 AND item_private = 2
+ AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
+ AND author_xchan != '%s'
+ $item_normal
+ $sql_extra
+ $sql_extra2
+ ORDER BY created DESC LIMIT $limit OFFSET $offset",
+ intval(self::$uid),
+ dbescdate($_SESSION['sse_loadtime']),
+ dbesc(self::$ob_hash)
+ );
+
+ if($items) {
+ $result['dm']['offset'] = ((count($items) == $limit) ? intval($offset + $limit) : -1);
+ xchan_query($items);
+ foreach($items as $item) {
+ $result['dm']['notifications'][] = Enotify::format($item);
+ }
+ }
+ else {
+ $result['dm']['offset'] = -1;
+ }
+
+ }
+
+ $r = q("SELECT count(id) as total FROM item
+ WHERE uid = %d and item_unseen = 1 AND item_wall = 0 AND item_private = 2
+ $item_normal
+ $sql_extra
+ AND author_xchan != '%s'",
+ intval(self::$uid),
+ dbesc(self::$ob_hash)
+ );
+
+ if($r)
+ $result['dm']['count'] = intval($r[0]['total']);
+
+ return $result;
+ }
+
+ function bs_home($notifications) {
+
+ $result['home']['notifications'] = [];
+ $result['home']['count'] = 0;
+
+ if(! self::$uid)
+ return $result;
+
+ if(! (self::$vnotify & VNOTIFY_CHANNEL))
+ return $result;
+
+ $limit = intval(self::$limit);
+ $offset = self::$offset;
+
+ $sql_extra = '';
+ if(! (self::$vnotify & VNOTIFY_LIKE))
+ $sql_extra = " AND verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
+
+ $sql_extra2 = '';
+ if(self::$xchans)
+ $sql_extra2 = " AND CASE WHEN verb = '" . ACTIVITY_SHARE . "' THEN owner_xchan ELSE author_xchan END IN (" . self::$xchans . ") ";
+
+
+ $item_normal = item_normal();
+
+ if ($notifications) {
+ $items = q("SELECT * FROM item
+ 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
+ $sql_extra2
+ ORDER BY created DESC LIMIT $limit OFFSET $offset",
+ intval(self::$uid),
+ dbescdate($_SESSION['sse_loadtime']),
+ dbesc(self::$ob_hash)
+ );
+
+ if($items) {
+ $result['home']['offset'] = ((count($items) == $limit) ? intval($offset + $limit) : -1);
+ xchan_query($items);
+ foreach($items as $item) {
+ $result['home']['notifications'][] = Enotify::format($item);
+ }
+ }
+ else {
+ $result['home']['offset'] = -1;
+ }
+
+ }
+
+ $r = q("SELECT count(id) as total FROM item
+ WHERE uid = %d and item_unseen = 1 AND item_wall = 1
+ $item_normal
+ $sql_extra
+ AND author_xchan != '%s'",
+ intval(self::$uid),
+ dbesc(self::$ob_hash)
+ );
+
+ if($r)
+ $result['home']['count'] = intval($r[0]['total']);
+
+ return $result;
+ }
+
+ function bs_pubs($notifications) {
+
+ $result['pubs']['notifications'] = [];
+ $result['pubs']['count'] = 0;
+
+ if(! (self::$vnotify & VNOTIFY_PUBS))
+ return $result;
+
+ if((observer_prohibited(true))) {
+ return $result;
+ }
+
+ if(! intval(get_config('system','open_pubstream',1))) {
+ if(! get_observer_hash()) {
+ return $result;
+ }
+ }
+
+ if(! isset($_SESSION['static_loadtime']))
+ $_SESSION['static_loadtime'] = datetime_convert();
+
+ $limit = intval(self::$limit);
+ $offset = self::$offset;
+
+ $sys = get_sys_channel();
+ $sql_extra = '';
+ if(! (self::$vnotify & VNOTIFY_LIKE))
+ $sql_extra = " AND verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
+
+ $sql_extra2 = '';
+ if(self::$xchans)
+ $sql_extra2 = " AND CASE WHEN verb = '" . ACTIVITY_SHARE . "' THEN owner_xchan ELSE author_xchan END IN (" . self::$xchans . ") ";
+
+ $item_normal = item_normal();
+
+ if ($notifications) {
+ $items = q("SELECT * FROM item
+ 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
+ $sql_extra
+ $sql_extra2
+ ORDER BY created DESC LIMIT $limit OFFSET $offset",
+ intval($sys['channel_id']),
+ dbescdate($_SESSION['sse_loadtime']),
+ dbesc(self::$ob_hash),
+ dbescdate($_SESSION['static_loadtime'])
+ );
+
+ if($items) {
+ $result['pubs']['offset'] = ((count($items) == $limit) ? intval($offset + $limit) : -1);
+ xchan_query($items);
+ foreach($items as $item) {
+ $result['pubs']['notifications'][] = Enotify::format($item);
+ }
+ }
+ else {
+ $result['pubs']['offset'] = -1;
+ }
+
+
+ }
+
+ $r = q("SELECT count(id) as total FROM item
+ WHERE uid = %d AND item_unseen = 1
+ AND created > '%s'
+ $item_normal
+ $sql_extra
+ AND author_xchan != '%s'",
+ intval($sys['channel_id']),
+ dbescdate($_SESSION['static_loadtime']),
+ dbesc(self::$ob_hash)
+ );
+
+ if($r)
+ $result['pubs']['count'] = intval($r[0]['total']);
+
+ return $result;
+ }
+
+
+ function bs_notify() {
+
+ $result['notify']['notifications'] = [];
+ $result['notify']['count'] = 0;
+ $result['notify']['offset'] = -1;
+
+ if(! self::$uid)
+ return $result;
+
+ if(! (self::$vnotify & VNOTIFY_SYSTEM))
+ return $result;
+
+ $r = q("SELECT * FROM notify WHERE uid = %d AND seen = 0 ORDER BY created DESC",
+ intval(self::$uid)
+ );
+
+ if($r) {
+ foreach($r as $rr) {
+ $result['notify']['notifications'][] = Enotify::format_notify($rr);
+ }
+ $result['notify']['count'] = count($r);
+ }
+
+ return $result;
+
+ }
+
+ function bs_intros() {
+
+ $result['intros']['notifications'] = [];
+ $result['intros']['count'] = 0;
+ $result['intros']['offset'] = -1;
+
+ if(! self::$uid)
+ return $result;
+
+ if(! (self::$vnotify & VNOTIFY_INTRO))
+ return $result;
+
+ $r = q("SELECT * FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ORDER BY abook_created DESC LIMIT 50",
+ intval(self::$uid)
+ );
+
+ if($r) {
+ foreach($r as $rr) {
+ $result['intros']['notifications'][] = Enotify::format_intros($rr);
+ }
+ $result['intros']['count'] = count($r);
+ }
+
+ return $result;
+
+ }
+
+ function bs_forums() {
+
+ $result['forums']['notifications'] = [];
+ $result['forums']['count'] = 0;
+ $result['forums']['offset'] = -1;
+
+ if(! self::$uid)
+ return $result;
+
+ if(! (self::$vnotify & VNOTIFY_FORUMS))
+ return $result;
+
+ $forums = get_forum_channels(self::$uid);
+
+ if($forums) {
+ $item_normal = item_normal();
+
+ $sql_extra = '';
+ if(! (self::$vnotify & VNOTIFY_LIKE))
+ $sql_extra = " AND verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
+
+ $fcount = count($forums);
+ $i = 0;
+
+ for($x = 0; $x < $fcount; $x ++) {
+ $p = q("SELECT oid AS parent FROM term WHERE uid = %d AND ttype = %d AND term = '%s'",
+ intval(self::$uid),
+ intval(TERM_FORUM),
+ dbesc($forums[$x]['xchan_name'])
+ );
+
+ $p_str = ids_to_querystr($p, 'parent');
+ $p_sql = (($p_str) ? "OR parent IN ( $p_str )" : '');
+
+ $r = q("select mid from item
+ where uid = %d and ( owner_xchan = '%s' OR author_xchan = '%s' $p_sql ) and item_unseen = 1 $sql_extra $item_normal",
+ intval(self::$uid),
+ dbesc($forums[$x]['xchan_hash']),
+ dbesc($forums[$x]['xchan_hash'])
+ );
+
+ if($r) {
+ $mids = flatten_array_recursive($r);
+ $b64mids = [];
+
+ foreach($mids as $mid)
+ $b64mids[] = 'b64.' . base64url_encode($mid);
+
+ $forums[$x]['notify_link'] = z_root() . '/network/?f=&pf=1&unseen=1&cid=' . $forums[$x]['abook_id'];
+ $forums[$x]['name'] = $forums[$x]['xchan_name'];
+ $forums[$x]['addr'] = $forums[$x]['xchan_addr'];
+ $forums[$x]['url'] = $forums[$x]['xchan_url'];
+ $forums[$x]['photo'] = $forums[$x]['xchan_photo_s'];
+ $forums[$x]['unseen'] = count($b64mids);
+ $forums[$x]['private_forum'] = (($forums[$x]['private_forum']) ? 'lock' : '');
+ $forums[$x]['message'] = (($forums[$x]['private_forum']) ? t('Private forum') : t('Public forum'));
+ $forums[$x]['mids'] = json_encode($b64mids);
+
+ unset($forums[$x]['abook_id']);
+ unset($forums[$x]['xchan_hash']);
+ unset($forums[$x]['xchan_name']);
+ unset($forums[$x]['xchan_url']);
+ unset($forums[$x]['xchan_photo_s']);
+
+ $i = $i + count($mids);
+
+ }
+ else {
+ unset($forums[$x]);
+ }
+ }
+
+ $result['forums']['count'] = $i;
+ $result['forums']['notifications'] = array_values($forums);
+
+ }
+
+ return $result;
+
+ }
+
+ function bs_files() {
+
+ $result['files']['notifications'] = [];
+ $result['files']['count'] = 0;
+ $result['files']['offset'] = -1;
+
+ if(! self::$uid)
+ return $result;
+
+ if(! (self::$vnotify & VNOTIFY_FILES))
+ return $result;
+
+ $item_normal = item_normal();
+
+ $r = q("SELECT * FROM item
+ WHERE verb = '%s'
+ AND obj_type IN ('Document', 'Video', 'Audio', 'Image')
+ AND uid = %d
+ AND author_xchan != '%s'
+ AND item_unseen = 1
+ $item_normal
+ ORDER BY created DESC",
+ dbesc(ACTIVITY_POST),
+ intval(self::$uid),
+ dbesc(self::$ob_hash)
+ );
+ if($r) {
+ xchan_query($r);
+ foreach($r as $rr) {
+ $result['files']['notifications'][] = Enotify::format($rr);
+ }
+ $result['files']['count'] = count($r);
+ }
+
+ return $result;
+
+ }
+
+ function bs_mail() {
+
+ $result['mail']['notifications'] = [];
+ $result['mail']['count'] = 0;
+ $result['mail']['offset'] = -1;
+
+ if(! self::$uid)
+ return $result;
+
+ if(! (self::$vnotify & VNOTIFY_MAIL))
+ return $result;
+
+ $r = q("select mail.*, xchan.* from mail left join xchan on xchan_hash = from_xchan
+ where channel_id = %d and mail_seen = 0 and mail_deleted = 0
+ and from_xchan != '%s' order by created desc",
+ intval(self::$uid),
+ dbesc(self::$ob_hash)
+ );
+
+ if($r) {
+ foreach($r as $rr) {
+ $result['mail']['notifications'][] = Enotify::format_mail($rr);
+ }
+ $result['mail']['count'] = count($r);
+ }
+
+ return $result;
+
+ }
+
+ function bs_all_events() {
+
+ $result['all_events']['notifications'] = [];
+ $result['all_events']['count'] = 0;
+ $result['all_events']['offset'] = -1;
+
+ if(! self::$uid)
+ return $result;
+
+ if(! (self::$vnotify & VNOTIFY_EVENT))
+ return $result;
+
+ $r = q("SELECT * FROM event left join xchan on event_xchan = xchan_hash
+ WHERE event.uid = %d AND dtstart < '%s' AND dtstart > '%s' and dismissed = 0
+ and etype in ( 'event', 'birthday' )
+ ORDER BY dtstart DESC",
+ intval(self::$uid),
+ dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + ' . intval(self::$evdays) . ' days')),
+ dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days'))
+ );
+
+ if($r) {
+ foreach($r as $rr) {
+ $result['all_events']['notifications'][] = Enotify::format_all_events($rr);
+ }
+ $result['all_events']['count'] = count($r);
+ }
+
+ return $result;
+ }
+
+ function bs_register() {
+
+ $result['register']['notifications'] = [];
+ $result['register']['count'] = 0;
+ $result['register']['offset'] = -1;
+
+ if(! self::$uid && ! is_site_admin())
+ return $result;
+
+ if(! (self::$vnotify & VNOTIFY_REGISTER))
+ return $result;
+
+ $r = q("SELECT account_email, account_created from account where (account_flags & %d) > 0",
+ intval(ACCOUNT_PENDING)
+ );
+ if($r) {
+ foreach($r as $rr) {
+ $result['register']['notifications'][] = Enotify::format_register($rr);
+ }
+ $result['register']['count'] = count($r);
+ }
+
+ return $result;
+
+ }
+
+}
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/Viewconnections.php b/Zotlabs/Module/Viewconnections.php
index 30df0b9e4..a0c293ddf 100644
--- a/Zotlabs/Module/Viewconnections.php
+++ b/Zotlabs/Module/Viewconnections.php
@@ -74,7 +74,29 @@ class Viewconnections extends \Zotlabs\Web\Controller {
if(! intval(get_abconfig(\App::$profile['uid'],$rr['xchan_hash'],'their_perms','post_comments'))) {
$oneway = true;
}
-
+
+ $perminfo=[];
+ $perminfo['connpermcount']=0;
+ $perminfo['connperms']=t('Accepts').': ';
+ if(intval(get_abconfig(\App::$profile['uid'],$rr['xchan_hash'],'their_perms','post_comments'))) {
+ $perminfo['connpermcount']++;
+ $perminfo['connperms'] .= t('Comments');
+ }
+ if(intval(get_abconfig(\App::$profile['uid'],$rr['xchan_hash'],'their_perms','send_stream'))) {
+ $perminfo['connpermcount']++;
+ $perminfo['connperms'] = ($perminfo['connperms']) ? $perminfo['connperms'] . ', ' : $perminfo['connperms'] ;
+ $perminfo['connperms'] .= t('Stream items');
+ }
+ if(intval(get_abconfig(\App::$profile['uid'],$rr['xchan_hash'],'their_perms','post_wall'))) {
+ $perminfo['connpermcount']++;
+ $perminfo['connperms'] = ($perminfo['connperms']) ? $perminfo['connperms'] . ', ' : $perminfo['connperms'] ;
+ $perminfo['connperms'] .= t('Wall posts');
+ }
+
+ if ($perminfo['connpermcount'] == 0) {
+ $perminfo['connperms'] .= t('Nothing');
+ }
+
$url = chanlink_hash($rr['xchan_hash']);
if($url) {
$contacts[] = array(
@@ -88,12 +110,12 @@ class Viewconnections extends \Zotlabs\Web\Controller {
'sparkle' => '',
'itemurl' => $rr['url'],
'network' => '',
+ 'perminfo' => (($is_owner) ? $perminfo : (($perminfo['connpermcount'] === 0) ? $perminfo : [])),
'oneway' => $oneway
);
}
}
-
-
+
if($_REQUEST['aj']) {
if($contacts) {
$o = replace_macros(get_markup_template('viewcontactsajax.tpl'),array(
diff --git a/Zotlabs/Module/Vote.php b/Zotlabs/Module/Vote.php
new file mode 100644
index 000000000..d67a6f176
--- /dev/null
+++ b/Zotlabs/Module/Vote.php
@@ -0,0 +1,143 @@
+<?php
+namespace Zotlabs\Module;
+
+use App;
+use Zotlabs\Web\Controller;
+use Zotlabs\Lib\Activity;
+use Zotlabs\Daemon\Master;
+use Zotlabs\Lib\Libsync;
+
+class Vote extends Controller {
+
+ function init() {
+
+ $ret = [ 'success' => false, 'message' => EMPTY_STR ];
+
+ $channel = App::get_channel();
+
+ if (! $channel) {
+ $ret['message'] = t('Permission denied.');
+ json_return_and_die($ret);
+ }
+
+
+ $fetch = null;
+ $id = argv(1);
+ $response = $_REQUEST['answer'];
+
+ if ($id) {
+ $fetch = q("select * from item where id = %d limit 1",
+ intval($id)
+ );
+ }
+
+
+ if ($fetch && $fetch[0]['obj_type'] === 'Question') {
+ $obj = json_decode($fetch[0]['obj'],true);
+
+ }
+ else {
+ $ret['message'] = t('Poll not found.');
+ json_return_and_die($ret);
+ }
+
+ $valid = false;
+
+ if ($obj['oneOf']) {
+ foreach($obj['oneOf'] as $selection) {
+ // logger('selection: ' . $selection);
+ // logger('response: ' . $response);
+ if($selection['name'] && $selection['name'] === $response) {
+ $valid = true;
+ }
+ }
+ }
+
+ $choices = [];
+ if ($obj['anyOf']) {
+ foreach ($obj['anyOf'] as $selection) {
+ $choices[] = $selection['name'];
+ }
+ foreach ($response as $res) {
+ if (! in_array($res,$choices)) {
+ $valid = false;
+ break;
+ }
+ $valid = true;
+ }
+ }
+
+ if (! $valid) {
+ $ret['message'] = t('Invalid response.');
+ json_return_and_die($ret);
+ }
+
+ if (! is_array($response)) {
+ $response = [ $response ];
+ }
+
+ foreach ($response as $res) {
+
+ $item = [];
+
+
+ $item['aid'] = $channel['channel_account_id'];
+ $item['uid'] = $channel['channel_id'];
+ $item['item_origin'] = 1;
+ $item['parent'] = $fetch[0]['id'];
+ $item['parent_mid'] = $fetch[0]['mid'];
+ $item['thr_parent'] = $fetch[0]['mid'];
+ $item['uuid'] = new_uuid();
+ $item['mid'] = z_root() . '/item/' . $item['uuid'];
+ $item['verb'] = 'Create';
+ $item['title'] = $res;
+ $item['author_xchan'] = $channel['channel_hash'];
+ $item['owner_xchan'] = $fetch[0]['author_xchan'];
+ $item['allow_cid'] = '<' . $fetch[0]['author_xchan'] . '>';
+ $item['item_private'] = 1;
+
+
+ $item['obj_type'] = 'Note';
+ $item['author'] = channelx_by_n($channel['channel_id']);
+
+ $item['obj'] = Activity::encode_item($item);
+
+ // now reset the placeholders
+
+ $item['verb'] = ACTIVITY_POST;
+ $item['obj_type'] = 'Answer';
+ unset($item['author']);
+
+
+ $x = item_store($item);
+
+
+ retain_item($fetch[0]['id']);
+
+ if($x['success']) {
+ $itemid = $x['item_id'];
+ Master::Summon( [ 'Notifier', 'like', $itemid ] );
+ }
+
+ $r = q("select * from item where id = %d",
+ intval($itemid)
+ );
+ if ($r) {
+ xchan_query($r);
+ $sync_item = fetch_post_tags($r);
+ Libsync::build_sync_packet($channel['channel_id'], [ 'item' => [ encode_item($sync_item[0],true) ] ]);
+ }
+ }
+ $ret['success'] = true;
+ $ret['message'] = t('Response submitted. Updates may not appear instantly.');
+ json_return_and_die($ret);
+ }
+}
+
+
+
+
+
+
+
+
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/Module/Well_known.php b/Zotlabs/Module/Well_known.php
index 140ab260d..0d7b222b8 100644
--- a/Zotlabs/Module/Well_known.php
+++ b/Zotlabs/Module/Well_known.php
@@ -65,11 +65,6 @@ class Well_known extends \Zotlabs\Web\Controller {
killme();
case 'caldav':
- if ($_SERVER['REQUEST_METHOD'] == 'PROPFIND') {
- http_status('301', 'moved permanently');
- goaway(z_root() . '/cdav');
- };
-
case 'carddav':
if ($_SERVER['REQUEST_METHOD'] == 'PROPFIND') {
http_status('301', 'moved permanently');
diff --git a/Zotlabs/Module/Wfinger.php b/Zotlabs/Module/Wfinger.php
index a19bdbedc..d24a31a15 100644
--- a/Zotlabs/Module/Wfinger.php
+++ b/Zotlabs/Module/Wfinger.php
@@ -3,6 +3,7 @@ namespace Zotlabs\Module;
require_once('include/zot.php');
+use Zotlabs\Lib\Libzot;
class Wfinger extends \Zotlabs\Web\Controller {
@@ -128,7 +129,7 @@ class Wfinger extends \Zotlabs\Web\Controller {
'http://webfinger.net/ns/name' => $r[0]['channel_name'],
'http://xmlns.com/foaf/0.1/name' => $r[0]['channel_name'],
'https://w3id.org/security/v1#publicKeyPem' => $r[0]['xchan_pubkey'],
- 'http://purl.org/zot/federation' => 'zot,zot6'
+ 'http://purl.org/zot/federation' => 'zot6,zot'
];
foreach($aliases as $alias)
@@ -142,7 +143,7 @@ class Wfinger extends \Zotlabs\Web\Controller {
[
'rel' => 'http://webfinger.net/rel/avatar',
'type' => $r[0]['xchan_photo_mimetype'],
- 'href' => $r[0]['xchan_photo_l']
+ 'href' => $r[0]['xchan_photo_l']
],
[
@@ -162,13 +163,13 @@ class Wfinger extends \Zotlabs\Web\Controller {
else {
$result['links'] = [
-
+
[
'rel' => 'http://webfinger.net/rel/avatar',
'type' => $r[0]['xchan_photo_mimetype'],
'href' => $r[0]['xchan_photo_l']
],
-
+
[
'rel' => 'http://microformats.org/profile/hcard',
'type' => 'text/html',
@@ -180,12 +181,11 @@ class Wfinger extends \Zotlabs\Web\Controller {
'href' => z_root()
],
-
[
'rel' => 'http://webfinger.net/rel/profile-page',
'href' => z_root() . '/profile/' . $r[0]['channel_address'],
],
-
+
[
'rel' => 'http://schemas.google.com/g/2010#updates-from',
'type' => 'application/atom+xml',
@@ -196,16 +196,11 @@ class Wfinger extends \Zotlabs\Web\Controller {
'rel' => 'http://webfinger.net/rel/blog',
'href' => z_root() . '/channel/' . $r[0]['channel_address'],
],
-
+
[
'rel' => 'http://ostatus.org/schema/1.0/subscribe',
'template' => z_root() . '/follow?f=&url={uri}',
],
-
- [
- 'rel' => 'http://purl.org/zot/protocol',
- 'href' => z_root() . '/.well-known/zot-info' . '?address=' . $r[0]['xchan_addr'],
- ],
[
'rel' => 'http://purl.org/zot/protocol/6.0',
@@ -214,12 +209,16 @@ class Wfinger extends \Zotlabs\Web\Controller {
],
[
+ 'rel' => 'http://purl.org/zot/protocol',
+ 'href' => z_root() . '/.well-known/zot-info' . '?address=' . $r[0]['xchan_addr'],
+ ],
+
+ [
'rel' => 'http://purl.org/openwebauth/v1',
'type' => 'application/x-zot+json',
'href' => z_root() . '/owa',
],
-
[
'rel' => 'magic-public-key',
'href' => 'data:application/magic-public-key,' . salmon_key($r[0]['channel_pubkey']),
@@ -229,7 +228,7 @@ class Wfinger extends \Zotlabs\Web\Controller {
if($zot) {
// get a zotinfo packet and return it with webfinger
- $result['zot'] = zotinfo( [ 'address' => $r[0]['xchan_addr'] ]);
+ $result['zot'] = Libzot::zotinfo( [ 'address' => $r[0]['xchan_addr'] ]);
}
}
@@ -241,7 +240,6 @@ class Wfinger extends \Zotlabs\Web\Controller {
$arr = [ 'channel' => $r[0], 'pchan' => $pchan, 'request' => $_REQUEST, 'result' => $result ];
call_hooks('webfinger',$arr);
-
json_return_and_die($arr['result'],'application/jrd+json');
}
diff --git a/Zotlabs/Module/Z6trans.php b/Zotlabs/Module/Z6trans.php
new file mode 100644
index 000000000..72667316f
--- /dev/null
+++ b/Zotlabs/Module/Z6trans.php
@@ -0,0 +1,161 @@
+<?php
+/**
+ * @file Zotlabs/Module/Z6trans.php
+ *
+ * @brief replace all occurances of an zot xchan with the zot6 xchan in DB.
+ *
+ */
+
+namespace Zotlabs\Module;
+
+use Zotlabs\Web\Controller;
+
+class Z6trans extends Controller {
+
+ function get() {
+ if(!is_site_admin())
+ return '<h1>Not Allowed</h1>';
+
+ $o = '<h2>' . t('Update to Hubzilla 5.0 step 2') . '</h2><br>';
+
+ $o .= '<h3>' . t('To complete the update please run') . '</h3>';
+
+ $o .= '<code>' . t('php util/z6convert.php') . '</code>';
+
+ $o .= '<h3>' . t('from the terminal.') . '</h3>';
+
+ return $o;
+
+/* this code is outdated use util/z6convert.php instead
+
+ $path = 'store/z6trans.sql';
+
+ $r = q("SELECT channel.channel_name, channel.channel_portable_id, xchan.xchan_network FROM channel
+ LEFT JOIN xchan ON channel_portable_id = xchan_hash
+ WHERE xchan.xchan_network = 'zot'
+ AND channel.channel_removed = 0"
+ );
+
+ $q = '';
+
+ foreach($r as $rr) {
+
+ $zot_xchan = $rr['channel_portable_id'];
+
+ $r = q("SELECT xchan_guid FROM xchan WHERE xchan_hash = '%s' AND xchan_network = 'zot'",
+ dbesc($zot_xchan)
+ );
+
+ if(!$r) {
+ $q .= '-- ' . $zot_xchan . 'failed: zot xchan not found' . "\r\n";
+ continue;
+ }
+
+ $guid = $r[0]['xchan_guid'];
+
+ $r = q("SELECT xchan_hash, xchan_guid_sig FROM xchan WHERE xchan_guid = '%s' AND xchan_network = 'zot6'",
+ dbesc($guid)
+ );
+
+ if(!$r) {
+ $q .= '-- ' . $zot_xchan . 'failed: zot6 xchan not found' . "\r\n";
+ continue;
+ }
+
+ $zot6_xchan = $r[0]['xchan_hash'];
+
+ $core = self::get_core_cols();
+
+ $q .= '-- Transforming ' . $rr['channel_name'] . "\r\n";
+
+ foreach($core as $table => $cols) {
+
+ foreach($cols as $col) {
+
+ $q .= sprintf("UPDATE %s SET %s = replace(%s, '%s', '%s');\r\n",
+ dbesc($table),
+ dbesc($col),
+ dbesc($col),
+ dbesc($zot_xchan),
+ dbesc($zot6_xchan)
+ );
+
+ }
+
+ }
+
+ $zot = dbesc($zot_xchan);
+ $zot6 = dbesc($zot6_xchan);
+
+ // Item table
+ foreach(['owner_xchan', 'author_xchan'] as $x) {
+ $q .= sprintf("UPDATE item SET $x = '%s' WHERE $x = '%s';\r\n",
+ $zot6,
+ $zot
+ );
+ }
+ $q .= "UPDATE item SET source_xchan = replace(source_xchan, '$zot', '$zot6'), route = replace(route, '$zot', '$zot6'), allow_cid = replace(allow_cid, '$zot', '$zot6'), deny_cid = replace(deny_cid, '$zot', '$zot6');\r\n";
+
+ // photo table
+ $q .= "UPDATE photo SET xchan = replace(xchan, '$zot', '$zot6'), allow_cid = replace(allow_cid, '$zot', '$zot6'), deny_cid = replace(deny_cid, '$zot', '$zot6');\r\n";
+
+ // dreport table
+ $q .= "UPDATE dreport SET dreport_recip = '$zot6' WHERE dreport_recip = '$zot';\r\n";
+ $q .= "UPDATE dreport SET dreport_xchan = '$zot6' WHERE dreport_xchan = '$zot';\r\n";
+ }
+
+ if($q)
+ file_put_contents($path, $q);
+
+ $o = '<h2>' . t('Update to Hubzilla 5.0 step 2') . '</h2><br>';
+
+ $o .= '<h3>' . t('To complete the update please run') . '</h3>';
+ if(ACTIVE_DBTYPE == DBTYPE_MYSQL)
+ $o .= '<code>source ' . $_SERVER["DOCUMENT_ROOT"] . '/' . $path . '</code><h3>from the mysql console.</h3>';
+ else
+ $o .= '<code>\i ' . $_SERVER["DOCUMENT_ROOT"] . '/' . $path . '</code><h3>from the postgresql console.</h3>';
+
+ $o .= '<br><h3>' . t('INFO: this command can take a very long time depending on your DB size.') . '</h3>';
+
+ return $o;
+*/
+
+ }
+
+ function get_core_cols() {
+
+ $core = [
+ 'abconfig' => ['xchan'],
+ 'abook' => ['abook_xchan'],
+ 'app' => ['app_author'],
+ 'attach' => ['creator', 'allow_cid', 'deny_cid'],
+ 'channel' => ['channel_allow_cid', 'channel_deny_cid'],
+ 'chat' => ['chat_xchan'],
+ 'chatpresence' => ['cp_xchan'],
+ 'chatroom' => ['allow_cid', 'deny_cid'],
+ 'config' => ['v'],
+// 'dreport' => ['dreport_recip', 'dreport_xchan'],
+ 'event' => ['event_xchan', 'allow_cid', 'deny_cid'],
+ 'iconfig' => ['v'],
+// 'item' => ['owner_xchan', 'author_xchan', 'source_xchan', 'route', 'allow_cid', 'deny_cid'],
+ 'mail' => ['from_xchan', 'to_xchan'],
+ 'menu_item' => ['allow_cid', 'deny_cid'],
+ 'obj' => ['allow_cid', 'deny_cid'],
+ 'pconfig' => ['v'],
+ 'pgrp_member' => ['xchan'],
+// 'photo' => ['xchan', 'allow_cid', 'deny_cid'],
+ 'source' => ['src_channel_xchan', 'src_xchan'],
+ 'updates' => ['ud_hash'],
+ 'xchat' => ['xchat_xchan'],
+ 'xconfig' => ['xchan', 'v'],
+ 'xign' => ['xchan'],
+ 'xlink' => ['xlink_xchan', 'xlink_link'],
+// 'xprof' => ['xprof_hash'],
+ 'xtag' => ['xtag_hash'],
+ ];
+
+ return $core;
+
+ }
+
+}
diff --git a/Zotlabs/Module/Zfinger.php b/Zotlabs/Module/Zfinger.php
index 3a20144a5..533f0a5db 100644
--- a/Zotlabs/Module/Zfinger.php
+++ b/Zotlabs/Module/Zfinger.php
@@ -2,6 +2,7 @@
namespace Zotlabs\Module;
use Zotlabs\Web\HTTPSig;
+use Zotlabs\Lib\Libzot;
class Zfinger extends \Zotlabs\Web\Controller {
@@ -9,7 +10,7 @@ class Zfinger extends \Zotlabs\Web\Controller {
require_once('include/zot.php');
require_once('include/crypto.php');
-
+
$x = zotinfo($_REQUEST);
if($x && $x['guid'] && $x['guid_sig']) {
diff --git a/Zotlabs/Photo/PhotoGd.php b/Zotlabs/Photo/PhotoGd.php
index 4054e1866..c54fa6a7d 100644
--- a/Zotlabs/Photo/PhotoGd.php
+++ b/Zotlabs/Photo/PhotoGd.php
@@ -13,12 +13,16 @@ class PhotoGd extends PhotoDriver {
* @see \Zotlabs\Photo\PhotoDriver::supportedTypes()
*/
public function supportedTypes() {
+
$t = [];
+
$t['image/jpeg'] = 'jpg';
if(imagetypes() & IMG_PNG)
$t['image/png'] = 'png';
if(imagetypes() & IMG_GIF)
$t['image/gif'] = 'gif';
+ if(imagetypes() & IMG_WEBP)
+ $t['image/webp'] = 'webp';
return $t;
}
@@ -142,6 +146,7 @@ class PhotoGd extends PhotoDriver {
* @see \Zotlabs\Photo\PhotoDriver::imageString()
*/
public function imageString() {
+
if(! $this->is_valid())
return false;
@@ -150,23 +155,32 @@ class PhotoGd extends PhotoDriver {
ob_start();
switch($this->getType()){
+
case 'image/png':
$quality = get_config('system', 'png_quality');
if((! $quality) || ($quality > 9))
$quality = PNG_QUALITY;
-
\imagepng($this->image, NULL, $quality);
break;
+
+ case 'image/webp':
+ $quality = get_config('system', 'webp_quality');
+ if((! $quality) || ($quality > 100))
+ $quality = WEBP_QUALITY;
+ \imagewebp($this->image, NULL, $quality);
+ break;
+
case 'image/jpeg':
// gd can lack imagejpeg(), but we verify during installation it is available
+
default:
$quality = get_config('system', 'jpeg_quality');
if((! $quality) || ($quality > 100))
$quality = JPEG_QUALITY;
-
\imagejpeg($this->image, NULL, $quality);
break;
}
+
$string = ob_get_contents();
ob_end_clean();
diff --git a/Zotlabs/Photo/PhotoImagick.php b/Zotlabs/Photo/PhotoImagick.php
index a7026e8ca..0a08d19e6 100644
--- a/Zotlabs/Photo/PhotoImagick.php
+++ b/Zotlabs/Photo/PhotoImagick.php
@@ -8,19 +8,16 @@ namespace Zotlabs\Photo;
class PhotoImagick extends PhotoDriver {
public function supportedTypes() {
- return [
+
+ $ret = [
'image/jpeg' => 'jpg',
'image/png' => 'png',
- 'image/gif' => 'gif',
+ 'image/gif' => 'gif'
];
- }
+ if(\Imagick::queryFormats("WEBP"))
+ $ret['image/webp'] = 'webp';
- private function get_FormatsMap() {
- return [
- 'image/jpeg' => 'JPG',
- 'image/png' => 'PNG',
- 'image/gif' => 'GIF',
- ];
+ return $ret;
}
@@ -42,8 +39,8 @@ class PhotoImagick extends PhotoDriver {
* Setup the image to the format it will be saved to
*/
- $map = $this->get_FormatsMap();
- $format = $map[$type];
+ $map = $this->supportedTypes();
+ $format = strtoupper($map[$type]);
if($this->image) {
$this->image->setFormat($format);
@@ -58,6 +55,7 @@ class PhotoImagick extends PhotoDriver {
* setup the compression here, so we'll do it only once
*/
switch($this->getType()) {
+
case 'image/png':
$quality = get_config('system', 'png_quality');
if((! $quality) || ($quality > 9))
@@ -73,11 +71,21 @@ class PhotoImagick extends PhotoDriver {
$quality = $quality * 10;
$this->image->setCompressionQuality($quality);
break;
+
case 'image/jpeg':
$quality = get_config('system', 'jpeg_quality');
if((! $quality) || ($quality > 100))
$quality = JPEG_QUALITY;
$this->image->setCompressionQuality($quality);
+ break;
+
+ case 'image/webp':
+ $quality = get_config('system', 'webp_quality');
+ if((! $quality) || ($quality > 100))
+ $quality = WEBP_QUALITY;
+ $this->image->setCompressionQuality($quality);
+ break;
+
default:
break;
}
diff --git a/Zotlabs/Storage/BasicAuth.php b/Zotlabs/Storage/BasicAuth.php
index a5c01fbb7..3a48f5004 100644
--- a/Zotlabs/Storage/BasicAuth.php
+++ b/Zotlabs/Storage/BasicAuth.php
@@ -2,6 +2,7 @@
namespace Zotlabs\Storage;
+use App;
use Sabre\DAV;
use Sabre\HTTP\RequestInterface;
use Sabre\HTTP\ResponseInterface;
@@ -128,6 +129,16 @@ class BasicAuth extends DAV\Auth\Backend\AbstractBasic {
$this->channel_name = $r['channel_address'];
$this->channel_id = $r['channel_id'];
$this->channel_hash = $this->observer = $r['channel_hash'];
+
+ if ($this->observer) {
+ $r = q("select * from xchan where xchan_hash = '%s' limit 1",
+ dbesc($this->observer)
+ );
+ if ($r) {
+ App::set_observer(array_shift($r));
+ }
+ }
+
$_SESSION['uid'] = $r['channel_id'];
$_SESSION['account_id'] = $r['channel_account_id'];
$_SESSION['authenticated'] = true;
diff --git a/Zotlabs/Storage/Directory.php b/Zotlabs/Storage/Directory.php
index ae36fc1c0..1231dfa25 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;
@@ -280,8 +281,19 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
$xpath = attach_syspaths($this->auth->owner_id, $hash);
- // returns the number of bytes that were written to the file, or FALSE on failure
- $size = file_put_contents($f, $data);
+
+ if (is_resource($data)) {
+ $fp = fopen($f,'wb');
+ if ($fp) {
+ pipe_streams($data,$fp);
+ fclose($fp);
+ }
+ $size = filesize($f);
+ }
+ else {
+ $size = file_put_contents($f, $data);
+ }
+
// delete attach entry if file_put_contents() failed
if ($size === false) {
logger('file_put_contents() failed to ' . $f);
@@ -314,7 +326,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
$d = q("UPDATE attach SET filesize = '%s', os_path = '%s', display_path = '%s', is_photo = %d, edited = '%s' WHERE hash = '%s' AND uid = %d",
dbesc($size),
dbesc($xpath['os_path']),
- dbesc($xpath['display_path']),
+ dbesc($xpath['path']),
intval($is_photo),
dbesc($edited),
dbesc($hash),
@@ -363,12 +375,12 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
$p = photo_upload($c[0], \App::get_observer(), $args);
}
- \Zotlabs\Daemon\Master::Summon([ 'Thumbnail' , $this->folder_hash ]);
+ \Zotlabs\Daemon\Master::Summon([ 'Thumbnail' , $hash ]);
$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 +413,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 +444,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 4610aceb7..76295d922 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.
@@ -26,7 +27,7 @@ class File extends DAV\Node implements DAV\IFile {
* * filename (string)
* * filetype (string)
*/
- private $data;
+ public $data;
/**
* @see \\Sabre\\DAV\\Auth\\Backend\\BackendInterface
* @var \\Zotlabs\\Storage\\BasicAuth $auth
@@ -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)));
}
}
@@ -120,6 +121,11 @@ class File extends DAV\Node implements DAV\IFile {
logger('put file: ' . basename($this->name), LOGGER_DEBUG);
$size = 0;
+ if ((! $this->auth->owner_id) || (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) {
+ logger('permission denied for put operation');
+ throw new DAV\Exception\Forbidden('Permission denied.');
+ }
+
// @todo only 3 values are needed
$c = q("SELECT * FROM channel WHERE channel_id = %d AND channel_removed = 0 LIMIT 1",
intval($this->auth->owner_id)
@@ -169,7 +175,7 @@ class File extends DAV\Node implements DAV\IFile {
}
$gis = @getimagesize($f);
logger('getimagesize: ' . print_r($gis,true), LOGGER_DATA);
- if(($gis) && ($gis[2] === IMAGETYPE_GIF || $gis[2] === IMAGETYPE_JPEG || $gis[2] === IMAGETYPE_PNG)) {
+ if(($gis) && ($gis[2] === IMAGETYPE_GIF || $gis[2] === IMAGETYPE_JPEG || $gis[2] === IMAGETYPE_PNG || $gis[2] === IMAGETYPE_WEBP)) {
$is_photo = 1;
}
@@ -254,7 +260,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 +384,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/_1235.php b/Zotlabs/Update/_1235.php
new file mode 100644
index 000000000..e457a35d2
--- /dev/null
+++ b/Zotlabs/Update/_1235.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace Zotlabs\Update;
+
+class _1235 {
+
+ function run() {
+
+ q("START TRANSACTION");
+
+ $r = q("DELETE FROM app WHERE app_name = '%s' AND app_system = 1",
+ dbesc('Mail')
+ );
+
+ if($r) {
+ q("COMMIT");
+ return UPDATE_SUCCESS;
+ }
+
+ q("ROLLBACK");
+ return UPDATE_FAILED;
+
+ }
+
+}
diff --git a/Zotlabs/Update/_1236.php b/Zotlabs/Update/_1236.php
new file mode 100644
index 000000000..e57338e16
--- /dev/null
+++ b/Zotlabs/Update/_1236.php
@@ -0,0 +1,137 @@
+<?php
+
+namespace Zotlabs\Update;
+
+use Zotlabs\Lib\Libzot;
+
+class _1236 {
+
+ function run() {
+
+ $r = q("SELECT channel.channel_address, channel.channel_hash, xchan.xchan_guid, channel.channel_pubkey, channel.channel_portable_id FROM channel
+ LEFT JOIN xchan ON channel_hash = xchan_hash
+ WHERE xchan.xchan_network = 'zot'
+ AND channel.channel_removed = 0"
+ );
+
+ $i = 0;
+
+ foreach($r as $rr) {
+
+ $zot_xchan = $rr['channel_hash'];
+ $guid = $rr['xchan_guid'];
+
+ $xchan = q("SELECT xchan_hash, xchan_guid_sig FROM xchan WHERE xchan_guid = '%s' AND xchan_network = 'zot6'",
+ dbesc($guid)
+ );
+
+ if(!$xchan) {
+ // This should not actually happen.
+ // A zot6 xchan for every channel should have been
+ // created in update _1226.
+
+ // In case this failed, we will try to fix it here.
+ logger('No zot6 xchan found for: ' . $rr['channel_hash']);
+
+ $zhash = $rr['channel_portable_id'];
+
+ if(!$zhash) {
+ $zhash = Libzot::make_xchan_hash($rr['xchan_guid'], $rr['channel_pubkey']);
+
+ q("UPDATE channel SET channel_portable_id = '%s' WHERE channel_hash = '%s'",
+ dbesc($zhash),
+ dbesc($zot_xchan)
+ );
+ }
+
+ if(!$zhash) {
+ logger('Could not create zot6 xchan_hash for: ' . $rr['channel_hash']);
+ continue;
+ }
+
+ $x = q("SELECT * FROM xchan WHERE xchan_hash = '%s' LIMIT 1",
+ dbesc($rr['channel_hash'])
+ );
+
+ if($x) {
+ $rec = $x[0];
+ $rec['xchan_hash'] = $zhash;
+ $rec['xchan_guid_sig'] = 'sha256.' . $rec['xchan_guid_sig'];
+ $rec['xchan_network'] = 'zot6';
+ 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())
+ );
+
+ if($h) {
+ $rec = $h[0];
+ $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 = hubloc_store_lowlevel($rec);
+ }
+
+ if(! $hubloc) {
+ logger('Could not create local zot6 hubloc record for: ' . $zot_xchan);
+ continue;
+ }
+ }
+
+ 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),
+ dbesc($zot_xchan),
+ dbesc($zot6_xchan_guid_sig),
+ dbesc($zot_xchan)
+ );
+
+ $i++;
+
+ }
+
+ if(count($r) == $i) {
+ z6trans_connections();
+ return UPDATE_SUCCESS;
+ }
+
+ return UPDATE_FAILED;
+
+ }
+
+}
diff --git a/Zotlabs/Update/_1237.php b/Zotlabs/Update/_1237.php
new file mode 100644
index 000000000..6c998ba4f
--- /dev/null
+++ b/Zotlabs/Update/_1237.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace Zotlabs\Update;
+
+class _1237 {
+
+ function run() {
+
+ q("START TRANSACTION");
+
+ $r = q("DELETE FROM app WHERE app_name = '%s'",
+ dbesc('Premium Channel')
+ );
+
+ if($r) {
+ q("COMMIT");
+ return UPDATE_SUCCESS;
+ }
+
+ q("ROLLBACK");
+ return UPDATE_FAILED;
+
+ }
+
+}
diff --git a/Zotlabs/Update/_1238.php b/Zotlabs/Update/_1238.php
new file mode 100644
index 000000000..1c79cc36e
--- /dev/null
+++ b/Zotlabs/Update/_1238.php
@@ -0,0 +1,78 @@
+<?php
+
+namespace Zotlabs\Update;
+
+class _1238 {
+
+ function run() {
+
+ q("START TRANSACTION");
+
+ $r = q("DELETE FROM app WHERE app_name = '%s'",
+ dbesc('Premium Channel')
+ );
+
+ // remove broken xchan entries
+ $r0 = dbq("DELETE FROM xchan WHERE xchan_hash = ''");
+
+ // remove broken hubloc entries
+ $r1 = dbq("DELETE FROM hubloc WHERE hubloc_hash = ''");
+
+ // fix legacy zot hubloc_id_url
+ $r2 = dbq("UPDATE hubloc
+ SET hubloc_id_url = CONCAT(hubloc_url, '/channel/', SUBSTRING(hubloc_addr FROM 1 FOR POSITION('@' IN hubloc_addr) -1))
+ WHERE hubloc_network = 'zot'
+ AND hubloc_id_url = ''"
+ );
+
+ // fix singleton networks hubloc_id_url
+ if(ACTIVE_DBTYPE == DBTYPE_MYSQL) {
+ // fix entries for activitypub which miss the xchan_url due to an earlier bug
+ $r3 = dbq("UPDATE xchan
+ SET xchan_url = xchan_hash
+ WHERE xchan_network = 'activitypub'
+ AND xchan_url = ''"
+ );
+
+ $r4 = dbq("UPDATE hubloc
+ LEFT JOIN xchan ON hubloc.hubloc_hash = xchan.xchan_hash
+ SET hubloc.hubloc_id_url = xchan.xchan_url
+ WHERE hubloc.hubloc_network IN ('activitypub', 'diaspora', 'friendica-over-diaspora', 'gnusoc')
+ AND hubloc.hubloc_id_url = ''
+ AND xchan.xchan_url IS NOT NULL"
+ );
+ }
+ if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
+ // fix entries for activitypub which miss the xchan_url due to an earlier bug
+ $r3 = dbq("UPDATE xchan
+ SET xchan_url = xchan_hash
+ WHERE xchan_network = 'activitypub'
+ AND xchan_url = ''"
+ );
+
+ $r4 = dbq("UPDATE hubloc
+ SET hubloc_id_url = xchan_url
+ FROM xchan
+ WHERE hubloc_hash = xchan_hash
+ AND hubloc_network IN ('activitypub', 'diaspora', 'friendica-over-diaspora', 'gnusoc')
+ AND hubloc_id_url = ''
+ AND xchan_url IS NOT NULL"
+ );
+ }
+
+ if($r0 && $r1 && $r2 && $r3 && $r4) {
+ // remove hubloc entries where hubloc_id_url could not be fixed
+ $r5 = dbq("DELETE FROM hubloc WHERE hubloc_id_url = ''");
+ }
+
+ if($r0 && $r1 && $r2 && $r3 && $r4 && $r5) {
+ q("COMMIT");
+ return UPDATE_SUCCESS;
+ }
+
+ q("ROLLBACK");
+ return UPDATE_FAILED;
+
+ }
+
+}
diff --git a/Zotlabs/Web/HTTPSig.php b/Zotlabs/Web/HTTPSig.php
index 3d050fd9b..827e0d779 100644
--- a/Zotlabs/Web/HTTPSig.php
+++ b/Zotlabs/Web/HTTPSig.php
@@ -243,13 +243,15 @@ class HTTPSig {
$url = ((strpos($id,'#')) ? substr($id,0,strpos($id,'#')) : $id);
- $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' limit 1",
+ $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s'",
dbesc(str_replace('acct:','',$url)),
dbesc($url)
);
- if($x && $x[0]['xchan_pubkey']) {
- return [ 'portable_id' => $x[0]['xchan_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
+ $x = Libzot::zot_record_preferred($x);
+
+ if($x && $x['xchan_pubkey']) {
+ return [ 'portable_id' => $x['xchan_hash'], 'public_key' => $x['xchan_pubkey'] , 'hubloc' => $x ];
}
$r = ActivityStreams::fetch($id);
@@ -268,13 +270,15 @@ class HTTPSig {
function get_webfinger_key($id) {
- $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' limit 1",
+ $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s'",
dbesc(str_replace('acct:','',$id)),
dbesc($id)
);
- if($x && $x[0]['xchan_pubkey']) {
- return [ 'portable_id' => $x[0]['xchan_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
+ $x = Libzot::zot_record_preferred($x);
+
+ if($x && $x['xchan_pubkey']) {
+ return [ 'portable_id' => $x['xchan_hash'], 'public_key' => $x['xchan_pubkey'] , 'hubloc' => $x ];
}
$wf = Webfinger::exec($id);
@@ -302,12 +306,15 @@ class HTTPSig {
function get_zotfinger_key($id) {
- $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' limit 1",
+ $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s'",
dbesc(str_replace('acct:','',$id)),
dbesc($id)
);
- if($x && $x[0]['xchan_pubkey']) {
- return [ 'portable_id' => $x[0]['xchan_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
+
+ $x = Libzot::zot_record_preferred($x);
+
+ if($x && $x['xchan_pubkey']) {
+ return [ 'portable_id' => $x['xchan_hash'], 'public_key' => $x['xchan_pubkey'] , 'hubloc' => $x ];
}
$wf = Webfinger::exec($id);
diff --git a/Zotlabs/Web/WebServer.php b/Zotlabs/Web/WebServer.php
index 1c3ea29d0..ac792dd69 100644
--- a/Zotlabs/Web/WebServer.php
+++ b/Zotlabs/Web/WebServer.php
@@ -62,7 +62,8 @@ class WebServer {
$_SESSION['my_address'] = $_GET['zid'];
$_SESSION['authenticated'] = 0;
}
- zid_init();
+ if(! $_SESSION['authenticated'])
+ zid_init();
}
}
@@ -82,14 +83,6 @@ class WebServer {
if((x($_SESSION, 'authenticated')) || (x($_POST, 'auth-params')) || (\App::$module === 'login'))
require('include/auth.php');
- if(! x($_SESSION, 'sysmsg'))
- $_SESSION['sysmsg'] = array();
-
- if(! x($_SESSION, 'sysmsg_info'))
- $_SESSION['sysmsg_info'] = array();
-
-
-
if(\App::$install) {
/* Allow an exception for the view module so that pcss will be interpreted during installation */
if(\App::$module != 'view')
diff --git a/Zotlabs/Widget/Activity_filter.php b/Zotlabs/Widget/Activity_filter.php
index 32ab10c77..002a642cb 100644
--- a/Zotlabs/Widget/Activity_filter.php
+++ b/Zotlabs/Widget/Activity_filter.php
@@ -2,6 +2,7 @@
namespace Zotlabs\Widget;
+use App;
use Zotlabs\Lib\Apps;
class Activity_filter {
@@ -16,6 +17,46 @@ class Activity_filter {
$tabs = [];
+ if(x($_GET,'dm')) {
+ $dm_active = (($_GET['dm'] == 1) ? 'active' : '');
+ $filter_active = 'dm';
+ }
+
+ if(x($_GET,'verb')) {
+ $events_active = (($_GET['verb'] == '.Event') ? 'active' : '');
+ $polls_active = (($_GET['verb'] == '.Question') ? 'active' : '');
+ $filter_active = (($events_active) ? 'events' : 'polls');
+ }
+
+
+ $tabs[] = [
+ 'label' => t('Direct Messages'),
+ 'icon' => 'envelope-o',
+ 'url' => z_root() . '/' . $cmd . '/?f=&dm=1',
+ 'sel' => $dm_active,
+ 'title' => t('Show direct (private) messages')
+ ];
+
+ if(feature_enabled(local_channel(),'events_tab')) {
+ $tabs[] = [
+ 'label' => t('Events'),
+ 'icon' => 'calendar',
+ 'url' => z_root() . '/' . $cmd . '/?verb=%2EEvent',
+ 'sel' => $events_active,
+ 'title' => t('Show posts that include events')
+ ];
+ }
+
+ if(feature_enabled(local_channel(),'polls_tab')) {
+ $tabs[] = [
+ 'label' => t('Polls'),
+ 'icon' => 'bar-chart',
+ 'url' => z_root() . '/' . $cmd . '/?verb=%2EQuestion',
+ 'sel' => $polls_active,
+ 'title' => t('Show posts that include polls')
+ ];
+ }
+
if(Apps::system_app_installed(local_channel(), 'Privacy Groups')) {
$groups = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
@@ -51,6 +92,7 @@ class Activity_filter {
if(feature_enabled(local_channel(),'forums_tab')) {
$forums = get_forum_channels(local_channel());
+ $channel = App::get_channel();
if($forums) {
foreach($forums as $f) {
@@ -61,7 +103,7 @@ class Activity_filter {
$fsub[] = [
'label' => $f['xchan_name'],
'img' => $f['xchan_photo_s'],
- 'url' => (($f['private_forum']) ? $f['xchan_url'] : z_root() . '/' . $cmd . '/?f=&pf=1&cid=' . $f['abook_id']),
+ 'url' => (($f['private_forum']) ? $f['xchan_url'] . '/?f=&zid=' . $channel['xchan_addr'] : z_root() . '/' . $cmd . '/?f=&pf=1&cid=' . $f['abook_id']),
'sel' => $forum_active,
'title' => t('Show posts to this forum'),
'lock' => (($f['private_forum']) ? 'lock' : '')
diff --git a/Zotlabs/Widget/Notifications.php b/Zotlabs/Widget/Notifications.php
index 077949b4e..e2a543f80 100644
--- a/Zotlabs/Widget/Notifications.php
+++ b/Zotlabs/Widget/Notifications.php
@@ -28,6 +28,7 @@ class Notifications {
]
];
+
$notifications[] = [
'type' => 'home',
'icon' => 'home',
@@ -48,6 +49,25 @@ class Notifications {
];
$notifications[] = [
+ 'type' => 'dm',
+ 'icon' => 'envelope',
+ 'severity' => 'danger',
+ 'label' => t('New Direct Messages'),
+ 'title' => t('New Direct Messages Notifications'),
+ 'viewall' => [
+ 'url' => 'network/?dm=1',
+ 'label' => t('View your direct messages')
+ ],
+ 'markall' => [
+ 'label' => t('Mark all notifications read')
+ ],
+ 'filter' => [
+ 'posts_label' => t('Show new posts only'),
+ 'name_label' => t('Filter by name or address')
+ ]
+ ];
+
+ $notifications[] = [
'type' => 'mail',
'icon' => 'envelope',
'severity' => 'danger',
diff --git a/Zotlabs/Widget/Pinned.php b/Zotlabs/Widget/Pinned.php
new file mode 100644
index 000000000..0a7806908
--- /dev/null
+++ b/Zotlabs/Widget/Pinned.php
@@ -0,0 +1,280 @@
+<?php
+namespace Zotlabs\Widget;
+
+/*
+ * Show pinned content
+ *
+ */
+
+class Pinned {
+
+ private $allowed_types = 0;
+ private $uid = 0;
+
+
+ /*
+ * @brief Displays pinned items
+ *
+ * @param $uid
+ * @param $types
+ * @return array of results: 'html' string, 'ids' array
+ *
+ */
+ function widget($uid, $types) {
+
+ $ret = [ 'html' => EMPTY_STR, 'ids' => [] ];
+
+ $this->uid = intval($uid);
+ if(! $this->uid)
+ return $ret;
+
+ $this->allowed_types = get_config('system', 'pin_types', [ ITEM_TYPE_POST ]);
+
+ $items = $this->list($types);
+
+ if(empty($items))
+ return $ret;
+
+ $ret['ids'] = array_column($items, 'id');
+
+ $observer = \App::get_observer();
+
+ foreach($items as $item) {
+
+ $midb64 = 'b64.' . base64url_encode($item['mid']);
+
+ if(in_array($observer['xchan_hash'], get_pconfig($item['uid'], 'pinned_hide', $midb64, [])))
+ continue;
+
+ $author = channelx_by_hash($item['author_xchan']);
+ $owner = channelx_by_hash($item['owner_xchan']);
+
+ $profile_avatar = $author['xchan_photo_m'];
+ $profile_link = chanlink_hash($item['author_xchan']);
+ $profile_name = $author['xchan_name'];
+
+ $commentable = ($item['item_nocomment'] == 0 && $item['comments_closed'] == NULL_DATE ? true : false);
+
+ $location = format_location($item);
+ $isevent = false;
+ $attend = null;
+ $canvote = false;
+
+ $conv_responses = [];
+
+ if($item['obj_type'] === ACTIVITY_OBJ_EVENT) {
+ $conv_responses['attendyes'] = [ 'title' => t('Attending','title') ];
+ $conv_responses['attendno'] = [ 'title' => t('Not attending','title') ];
+ $conv_responses['attendmaybe'] = [ 'title' => t('Might attend','title') ];
+ if($commentable && $observer) {
+ $attend = array( t('I will attend'), t('I will not attend'), t('I might attend'));
+ $isevent = true;
+ }
+ }
+
+ $consensus = (intval($item['item_consensus']) ? true : false);
+ if($consensus) {
+ $conv_responses['agree'] = [ 'title' => t('Agree','title') ];
+ $conv_responses['disagree'] = [ 'title' => t('Disagree','title') ];
+ $conv_responses['abstain'] = [ 'title' => t('Abstain','title') ];
+ if($commentable && $observer) {
+ $conlabels = array( t('I agree'), t('I disagree'), t('I abstain'));
+ $canvote = true;
+ }
+ }
+
+ $this->activity($item, $conv_responses);
+
+ $verified = (intval($item['item_verified']) ? t('Message signature validated') : '');
+ $forged = ((! intval($item['item_verified']) && $item['sig']) ? t('Message signature incorrect') : '');
+
+ $shareable = ((local_channel() && \App::$profile_uid == local_channel() && $item['item_private'] != 1) ? true : false);
+ if ($shareable) {
+ // This actually turns out not to be possible in some protocol stacks without opening up hundreds of new issues.
+ // Will allow it only for uri resolvable sources.
+ if(strpos($item['mid'],'http') === 0) {
+ $share = []; //Not yet ready for primetime
+ //$share = array( t('Repeat This'), t('repeat'));
+ }
+ $embed = array( t('Share This'), t('share'));
+ }
+
+ if(strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC','now - 12 hours')) > 0)
+ $is_new = true;
+
+ $body = prepare_body($item,true);
+
+ $str = [
+ 'item_type' => intval($item['item_type']),
+ 'body' => $body['html'],
+ 'tags' => $body['tags'],
+ 'categories' => $body['categories'],
+ 'mentions' => $body['mentions'],
+ 'attachments' => $body['attachments'],
+ 'folders' => $body['folders'],
+ 'text' => strip_tags($body['html']),
+ 'id' => $item['id'],
+ 'mids' => json_encode([ $midb64 ]),
+ 'isevent' => $isevent,
+ 'attend' => $attend,
+ 'consensus' => $consensus,
+ 'conlabels' => $conlabels,
+ 'canvote' => $canvote,
+ 'linktitle' => sprintf( t('View %s\'s profile - %s'), $profile_name, ($author['xchan_addr'] ? $author['xchan_addr'] : $author['xchan_url']) ),
+ 'olinktitle' => sprintf( t('View %s\'s profile - %s'), $owner['xchan_name'], ($owner['xchan_addr'] ? $owner['xchan_addr'] : $owner['xchan_url']) ),
+ 'profile_url' => $profile_link,
+ 'name' => $profile_name,
+ 'thumb' => $profile_avatar,
+ 'via' => t('via'),
+ 'title' => $item['title'],
+ 'title_tosource' => get_pconfig($item['uid'],'system','title_tosource'),
+ 'ago' => relative_date($item['created']),
+ 'app' => $item['app'],
+ 'str_app' => sprintf( t('from %s'), $item['app'] ),
+ 'isotime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'c'),
+ 'localtime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'r'),
+ 'editedtime' => (($item['edited'] != $item['created']) ? sprintf( t('last edited: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['edited'], 'r') ) : ''),
+ 'expiretime' => ($item['expires'] > NULL_DATE ? sprintf( t('Expires: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['expires'], 'r') ) : ''),
+ 'lock' => $lock,
+ 'verified' => $verified,
+ 'forged' => $forged,
+ 'location' => $location,
+ 'divider' => get_pconfig($item['uid'],'system','item_divider'),
+ 'attend_title' => t('Attendance Options'),
+ 'vote_title' => t('Voting Options'),
+ 'is_new' => $is_new,
+ 'owner_url' => ($owner['xchan_addr'] != $author['xchan_addr'] ? chanlink_hash($owner['xchan_hash']) : ''),
+ 'owner_photo'=> $owner['xchan_photo_m'],
+ 'owner_name' => $owner['xchan_name'],
+ 'photo' => $body['photo'],
+ 'event' => $body['event'],
+ 'has_tags' => (($body['tags'] || $body['categories'] || $body['mentions'] || $body['attachments'] || $body['folders']) ? true : false),
+ // Item toolbar buttons
+ 'share' => $share,
+ 'embed' => $embed,
+ 'plink' => get_plink($item),
+ 'pinned' => t('Pinned post'),
+ 'pinme' => (($observer['xchan_hash'] == $owner['xchan_hash']) ? t('Unpin from the top') : ''),
+ 'hide' => (! $is_new && $observer && ($observer['xchan_hash'] != $owner['xchan_hash']) ? t("Don't show") : ''),
+ // end toolbar buttons
+ 'modal_dismiss' => t('Close'),
+ 'responses' => $conv_responses
+ ];
+
+ $tpl = get_markup_template('pinned_item.tpl');
+ $ret['html'] .= replace_macros($tpl, $str);
+ }
+
+ return $ret;
+ }
+
+
+ /*
+ * @brief List pinned items depend on type
+ *
+ * @param $types
+ * @return array of pinned items
+ *
+ */
+ private function list($types) {
+
+ if(empty($types) || (! is_array($types)))
+ return [];
+
+ $item_types = array_intersect($this->allowed_types, $types);
+ if(empty($item_types))
+ return [];
+
+ $mids_list = [];
+
+ foreach($item_types as $type) {
+
+ $mids = get_pconfig($this->uid, 'pinned', $type, []);
+ foreach($mids as $mid) {
+ if(! empty($mid) && strpos($mid,'b64.') === 0)
+ $mids_list[] = @base64url_decode(substr($mid,4));
+ }
+ }
+ if(empty($mids_list))
+ return [];
+
+ $r = q("SELECT * FROM item WHERE mid IN ( '%s' ) AND uid = %d AND id = parent AND item_private = 0 ORDER BY created DESC",
+ dbesc(implode(",", $mids_list)),
+ intval($this->uid)
+ );
+ if($r)
+ return $r;
+
+ return [];
+ }
+
+
+ /*
+ * @brief List activities on item
+ *
+ * @param array $item
+ * @param array $conv_responses
+ * @return array
+ *
+ */
+ private function activity($item, &$conv_responses) {
+
+ foreach(array_keys($conv_responses) as $verb) {
+
+ switch($verb) {
+ case 'like':
+ $v = ACTIVITY_LIKE;
+ break;
+ case 'dislike':
+ $v = ACTIVITY_DISLIKE;
+ break;
+ case 'agree':
+ $v = ACTIVITY_AGREE;
+ break;
+ case 'disagree':
+ $v = ACTIVITY_DISAGREE;
+ break;
+ case 'abstain':
+ $v = ACTIVITY_ABSTAIN;
+ break;
+ case 'attendyes':
+ $v = ACTIVITY_ATTEND;
+ break;
+ case 'attendno':
+ $v = ACTIVITY_ATTENDNO;
+ break;
+ case 'attendmaybe':
+ $v = ACTIVITY_ATTENDMAYBE;
+ break;
+ default:
+ break;
+ }
+
+ $r = q("SELECT * FROM item WHERE parent = %d AND id <> parent AND verb = '%s' AND item_deleted = 0",
+ intval($item['id']),
+ dbesc($v)
+ );
+ if(! $r) {
+ unset($conv_responses[$verb]);
+ continue;
+ }
+
+ $conv_responses[$verb]['count'] = count($r);
+ $conv_responses[$verb]['button'] = get_response_button_text($verb, $conv_responses[$verb]['count']);
+
+ foreach($r as $rr) {
+
+ $author = q("SELECT * FROM xchan WHERE xchan_hash = '%s' LIMIT 1",
+ dbesc($rr['author_xchan'])
+ );
+ $name = (($author && $author[0]['xchan_name']) ? $author[0]['xchan_name'] : t('Unknown'));
+ $conv_responses[$verb]['list'][] = (($rr['author_xchan'] && $author && $author[0]['xchan_photo_s']) ?
+ '<a class="dropdown-item" href="' . chanlink_hash($rr['author_xchan']) . '">' . '<img class="menu-img-1" src="' . zid($author[0]['xchan_photo_s']) . '" alt="' . urlencode($name) . '" /> ' . $name . '</a>' :
+ '<a class="dropdown-item" href="#" class="disabled">' . $name . '</a>'
+ );
+ }
+ }
+
+ $conv_responses['count'] = count($conv_responses);
+ }
+}
diff --git a/Zotlabs/Zot6/Zot6Handler.php b/Zotlabs/Zot6/Zot6Handler.php
index 37ce11980..d717b147b 100644
--- a/Zotlabs/Zot6/Zot6Handler.php
+++ b/Zotlabs/Zot6/Zot6Handler.php
@@ -71,7 +71,7 @@ class Zot6Handler implements IHandler {
foreach ($recipients as $recip) {
$r = q("select channel.*,xchan.* from channel
- left join xchan on channel_portable_id = xchan_hash
+ left join xchan on channel_hash = xchan_hash
where xchan_hash ='%s' limit 1",
dbesc($recip)
);
@@ -139,7 +139,7 @@ class Zot6Handler implements IHandler {
$arr = $data['recipients'][0];
- $c = q("select * from channel left join xchan on channel_portable_id = xchan_hash where channel_portable_id = '%s' limit 1",
+ $c = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_hash = '%s' limit 1",
dbesc($arr['portable_id'])
);
if (! $c) {
@@ -227,8 +227,8 @@ class Zot6Handler implements IHandler {
// basically this means "unfriend"
foreach ($recipients as $recip) {
$r = q("select channel.*,xchan.* from channel
- left join xchan on channel_portable_id = xchan_hash
- where channel_portable_id = '%s' limit 1",
+ left join xchan on channel_hash = xchan_hash
+ where channel_hash = '%s' limit 1",
dbesc($recip)
);
if ($r) {