diff --git a/.gitignore b/.gitignore old mode 100755 new mode 100644 diff --git a/.homeinstall/zotserver-setup.sh b/.homeinstall/zotserver-setup.sh old mode 100755 new mode 100644 diff --git a/.openshift/action_hooks/deploy b/.openshift/action_hooks/deploy old mode 100755 new mode 100644 diff --git a/.openshift/cron/weekly/chronograph b/.openshift/cron/weekly/chronograph old mode 100755 new mode 100644 diff --git a/CHANGELOG b/CHANGELOG index e526536eb..1e4b28abf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,7 +1,3 @@ -Hubzilla 5.2.9 (2021-01-23) - - Update and enhance Account, Invite, Register - - Hubzilla 5.2.2 (2021-02-13) - Fix issue with ping_site() diff --git a/Zotlabs/Access/AccessList.php b/Zotlabs/Access/AccessList.php index 7cf7b5587..af6c4b7a6 100644 --- a/Zotlabs/Access/AccessList.php +++ b/Zotlabs/Access/AccessList.php @@ -54,7 +54,7 @@ class AccessList { * * \e string \b channel_deny_gid => string of denied gids */ function __construct($channel) { - if($channel) { + if ($channel) { $this->allow_cid = $channel['channel_allow_cid']; $this->allow_gid = $channel['channel_allow_gid']; $this->deny_cid = $channel['channel_deny_cid']; @@ -99,7 +99,6 @@ class AccessList { $this->allow_gid = $arr['allow_gid']; $this->deny_cid = $arr['deny_cid']; $this->deny_gid = $arr['deny_gid']; - $this->explicit = $explicit; } diff --git a/Zotlabs/Access/PermissionLimits.php b/Zotlabs/Access/PermissionLimits.php index c11dc95e6..fb5fe6133 100644 --- a/Zotlabs/Access/PermissionLimits.php +++ b/Zotlabs/Access/PermissionLimits.php @@ -2,6 +2,7 @@ namespace Zotlabs\Access; +use App; use Zotlabs\Lib\PConfig; /** @@ -39,10 +40,10 @@ class PermissionLimits { */ static public function Std_Limits() { $limits = []; - $perms = Permissions::Perms(); + $perms = Permissions::Perms(); - foreach($perms as $k => $v) { - if(strstr($k, 'view')) + foreach ($perms as $k => $v) { + if (strstr($k, 'view')) $limits[$k] = PERMS_PUBLIC; else $limits[$k] = PERMS_SPECIFIC; @@ -77,14 +78,14 @@ class PermissionLimits { * * \b array with all permission limits, if $perm is not set */ static public function Get($channel_id, $perm = '') { - if($perm) { + if ($perm) { return intval(PConfig::Get($channel_id, 'perm_limits', $perm)); } PConfig::Load($channel_id); - if(array_key_exists($channel_id, \App::$config) - && array_key_exists('perm_limits', \App::$config[$channel_id])) - return \App::$config[$channel_id]['perm_limits']; + if (array_key_exists($channel_id, App::$config) + && array_key_exists('perm_limits', App::$config[$channel_id])) + return App::$config[$channel_id]['perm_limits']; return false; } diff --git a/Zotlabs/Access/PermissionRoles.php b/Zotlabs/Access/PermissionRoles.php index 82df0c34b..2bcce4eb4 100644 --- a/Zotlabs/Access/PermissionRoles.php +++ b/Zotlabs/Access/PermissionRoles.php @@ -218,13 +218,13 @@ class PermissionRoles { // set permissionlimits for this permission here, for example: // if($perm === 'mynewperm') - // \Zotlabs\Access\PermissionLimits::Set($uid,$perm,1); + // PermissionLimits::Set($uid,$perm,1); if($perm === 'view_wiki') - \Zotlabs\Access\PermissionLimits::Set($uid, $perm, PERMS_PUBLIC); + PermissionLimits::Set($uid, $perm, PERMS_PUBLIC); if($perm === 'write_wiki') - \Zotlabs\Access\PermissionLimits::Set($uid, $perm, PERMS_SPECIFIC); + PermissionLimits::Set($uid, $perm, PERMS_SPECIFIC); // set autoperms here if applicable @@ -262,11 +262,11 @@ class PermissionRoles { case 'view_wiki': set_abconfig($uid,$ab['abook_xchan'],'my_perms',$perm, intval(get_abconfig($uid,$ab['abook_xchan'],'my_perms','view_pages'))); - + break; case 'write_wiki': set_abconfig($uid,$ab['abook_xchan'],'my_perms',$perm, intval(get_abconfig($uid,$ab['abook_xchan'],'my_perms','write_pages'))); - + break; default: break; } diff --git a/Zotlabs/Access/Permissions.php b/Zotlabs/Access/Permissions.php index 35016ed57..df5472cc3 100644 --- a/Zotlabs/Access/Permissions.php +++ b/Zotlabs/Access/Permissions.php @@ -75,7 +75,7 @@ class Permissions { $x = [ 'permissions' => $perms, - 'filter' => $filter + 'filter' => $filter ]; /** * @hooks permissions_list @@ -84,7 +84,7 @@ class Permissions { */ call_hooks('permissions_list', $x); - return($x['permissions']); + return ($x['permissions']); } /** @@ -96,10 +96,10 @@ class Permissions { */ static public function BlockedAnonPerms() { - $res = []; + $res = []; $perms = PermissionLimits::Std_limits(); - foreach($perms as $perm => $limit) { - if($limit != PERMS_PUBLIC) { + foreach ($perms as $perm => $limit) { + if ($limit != PERMS_PUBLIC) { $res[] = $perm; } } @@ -111,7 +111,7 @@ class Permissions { */ call_hooks('write_perms', $x); - return($x['permissions']); + return ($x['permissions']); } /** @@ -120,20 +120,20 @@ class Permissions { * Converts [ 0 => 'view_stream', ... ] * to [ 'view_stream' => 1 ] for any permissions in $arr; * Undeclared permissions which exist in Perms() are added and set to 0. - * + * * @param array $arr * @return array */ static public function FilledPerms($arr) { - if(is_null($arr)) { + if (is_null($arr)) { btlogger('FilledPerms: null'); $arr = []; } $everything = self::Perms(); - $ret = []; - foreach($everything as $k => $v) { - if(in_array($k, $arr)) + $ret = []; + foreach ($everything as $k => $v) { + if (in_array($k, $arr)) $ret[$k] = 1; else $ret[$k] = 0; @@ -155,9 +155,9 @@ class Permissions { */ static public function OPerms($arr) { $ret = []; - if($arr) { - foreach($arr as $k => $v) { - $ret[] = [ 'name' => $k, 'value' => $v ]; + if ($arr) { + foreach ($arr as $k => $v) { + $ret[] = ['name' => $k, 'value' => $v]; } } return $ret; @@ -170,15 +170,16 @@ class Permissions { * @return boolean|array */ static public function FilledAutoperms($channel_id) { - if(! intval(get_pconfig($channel_id,'system','autoperms'))) + if (!intval(get_pconfig($channel_id, 'system', 'autoperms'))) return false; $arr = []; + $r = q("select * from pconfig where uid = %d and cat = 'autoperms'", intval($channel_id) ); - if($r) { - foreach($r as $rr) { + if ($r) { + foreach ($r as $rr) { $arr[$rr['k']] = intval($rr['v']); } } @@ -193,11 +194,11 @@ class Permissions { * @return boolean true if all perms from $p1 exist also in $p2 */ static public function PermsCompare($p1, $p2) { - foreach($p1 as $k => $v) { - if(! array_key_exists($k, $p2)) + foreach ($p1 as $k => $v) { + if (!array_key_exists($k, $p2)) return false; - if($p1[$k] != $p2[$k]) + if ($p1[$k] != $p2[$k]) return false; } @@ -214,18 +215,18 @@ class Permissions { */ static public function connect_perms($channel_id) { - $my_perms = []; - $permcat = null; + $my_perms = []; + $permcat = null; $automatic = 0; // If a default permcat exists, use that - $pc = ((feature_enabled($channel_id,'permcats')) ? get_pconfig($channel_id,'system','default_permcat') : 'default'); - if(! in_array($pc, [ '','default' ])) { - $pcp = new Zlib\Permcat($channel_id); + $pc = ((feature_enabled($channel_id, 'permcats')) ? get_pconfig($channel_id, 'system', 'default_permcat') : 'default'); + if (!in_array($pc, ['', 'default'])) { + $pcp = new Zlib\Permcat($channel_id); $permcat = $pcp->fetch($pc); - if($permcat && $permcat['perms']) { - foreach($permcat['perms'] as $p) { + if ($permcat && $permcat['perms']) { + foreach ($permcat['perms'] as $p) { $my_perms[$p['name']] = $p['value']; } } @@ -235,15 +236,15 @@ class Permissions { // and if there was no permcat or a default permcat, set the perms // from the role - $role = get_pconfig($channel_id,'system','permissions_role'); - if($role) { + $role = get_pconfig($channel_id, 'system', 'permissions_role'); + if ($role) { $xx = PermissionRoles::role_perms($role); - if($xx['perms_auto']) + if ($xx['perms_auto']) $automatic = 1; - if((! $my_perms) && ($xx['perms_connect'])) { + if ((!$my_perms) && ($xx['perms_connect'])) { $default_perms = $xx['perms_connect']; - $my_perms = Permissions::FilledPerms($default_perms); + $my_perms = Permissions::FilledPerms($default_perms); } } @@ -251,11 +252,11 @@ class Permissions { // it is likely a custom permissions role. First see if there are any // automatic permissions. - if(! $my_perms) { + if (!$my_perms) { $m = Permissions::FilledAutoperms($channel_id); - if($m) { + if ($m) { $automatic = 1; - $my_perms = $m; + $my_perms = $m; } } @@ -263,35 +264,35 @@ class Permissions { // custom perms but they are not automatic. They will be stored in abconfig with // the channel's channel_hash (the 'self' connection). - if(! $my_perms) { + if (!$my_perms) { $r = q("select channel_hash from channel where channel_id = %d", intval($channel_id) ); - if($r) { + if ($r) { $x = q("select * from abconfig where chan = %d and xchan = '%s' and cat = 'my_perms'", intval($channel_id), dbesc($r[0]['channel_hash']) ); - if($x) { - foreach($x as $xv) { + if ($x) { + foreach ($x as $xv) { $my_perms[$xv['k']] = intval($xv['v']); } } } } - return ( [ 'perms' => $my_perms, 'automatic' => $automatic ] ); + return (['perms' => $my_perms, 'automatic' => $automatic]); } static public function serialise($p) { $n = []; - if($p) { - foreach($p as $k => $v) { - if(intval($v)) { + if ($p) { + foreach ($p as $k => $v) { + if (intval($v)) { $n[] = $k; } } } - return implode(',',$n); + return implode(',', $n); } } diff --git a/Zotlabs/Daemon/Addon.php b/Zotlabs/Daemon/Addon.php index c2889e596..c6778750d 100644 --- a/Zotlabs/Daemon/Addon.php +++ b/Zotlabs/Daemon/Addon.php @@ -2,13 +2,12 @@ namespace Zotlabs\Daemon; -require_once('include/zot.php'); - class Addon { - static public function run($argc,$argv) { + static public function run($argc, $argv) { - call_hooks('daemon_addon',$argv); + call_hooks('daemon_addon', $argv); } + } diff --git a/Zotlabs/Daemon/Cache_embeds.php b/Zotlabs/Daemon/Cache_embeds.php index 08088abd6..9e5b8d2bb 100644 --- a/Zotlabs/Daemon/Cache_embeds.php +++ b/Zotlabs/Daemon/Cache_embeds.php @@ -2,7 +2,6 @@ namespace Zotlabs\Daemon; - class Cache_embeds { static public function run($argc,$argv) { diff --git a/Zotlabs/Daemon/Cache_query.php b/Zotlabs/Daemon/Cache_query.php new file mode 100644 index 000000000..5f92ae6d0 --- /dev/null +++ b/Zotlabs/Daemon/Cache_query.php @@ -0,0 +1,36 @@ + 1) && ($argv[1])) + + if (($argc > 1) && ($argv[1])) $site_id = $argv[1]; - if($site_id) + if ($site_id) $sql_options = " and site_url = '" . dbesc($argv[1]) . "' "; - $days = intval(get_config('system','sitecheckdays')); - if($days < 1) + $days = intval(get_config('system', 'sitecheckdays')); + if ($days < 1) $days = 30; $r = q("select * from site where site_dead = 0 and site_update < %s - INTERVAL %s and site_type = %d $sql_options ", - db_utcnow(), db_quoteinterval($days . ' DAY'), + db_utcnow(), + db_quoteinterval($days . ' DAY'), intval(SITE_TYPE_ZOT) ); - if(! $r) + if (!$r) return; - foreach($r as $rr) { - if(! strcasecmp($rr['site_url'],z_root())) + foreach ($r as $rr) { + if (!strcasecmp($rr['site_url'], z_root())) continue; $x = ping_site($rr['site_url']); - if($x['success']) { + if ($x['success']) { logger('checksites: ' . $rr['site_url']); q("update site set site_update = '%s' where site_url = '%s' ", dbesc(datetime_convert()), diff --git a/Zotlabs/Daemon/Convo.php b/Zotlabs/Daemon/Convo.php new file mode 100644 index 000000000..940216b2c --- /dev/null +++ b/Zotlabs/Daemon/Convo.php @@ -0,0 +1,58 @@ +get(); + + if ($messages) { + foreach ($messages as $message) { + if (is_string($message)) { + $message = Activity::fetch($message, $channel); + } + // set client flag because comments will probably just be objects and not full blown activities + // and that lets us use implied_create + $AS = new ActivityStreams($message); + if ($AS->is_valid() && is_array($AS->obj)) { + $item = Activity::decode_note($AS); + Activity::store($channel, $contact['abook_xchan'], $AS, $item); + } + } + } + } +} diff --git a/Zotlabs/Daemon/Cron.php b/Zotlabs/Daemon/Cron.php index 703d6ce08..4732dfa75 100644 --- a/Zotlabs/Daemon/Cron.php +++ b/Zotlabs/Daemon/Cron.php @@ -6,14 +6,14 @@ use Zotlabs\Lib\Libsync; class Cron { - static public function run($argc,$argv) { + static public function run($argc, $argv) { - $maxsysload = intval(get_config('system','maxloadavg')); - if($maxsysload < 1) + $maxsysload = intval(get_config('system', 'maxloadavg')); + if ($maxsysload < 1) $maxsysload = 50; - if(function_exists('sys_getloadavg')) { + if (function_exists('sys_getloadavg')) { $load = sys_getloadavg(); - if(intval($load[0]) > $maxsysload) { + if (intval($load[0]) > $maxsysload) { logger('system: load ' . $load . ' too high. Cron deferred to next scheduled run.'); return; } @@ -21,17 +21,18 @@ class Cron { // Check for a lockfile. If it exists, but is over an hour old, it's stale. Ignore it. $lockfile = 'store/[data]/cron'; - if((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 3600)) - && (! get_config('system','override_cron_lockfile'))) { + if ((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 3600)) + && (!get_config('system', 'override_cron_lockfile'))) { logger("cron: Already running"); return; } - + // Create a lockfile. Needs two vars, but $x doesn't need to contain anything. + $x = ''; file_put_contents($lockfile, $x); logger('cron: start'); - + // run queue delivery process in the background Master::Summon(array('Queue')); @@ -46,7 +47,7 @@ class Cron { db_utcnow(), db_quoteinterval('3 MINUTE') ); - + // expire any expired mail q("delete from mail where expires > '%s' and expires < %s ", @@ -54,19 +55,23 @@ class Cron { db_utcnow() ); + $interval = get_config('system', 'delivery_interval', 3); + // expire any expired items $r = q("select id,item_wall from item where expires > '2001-01-01 00:00:00' and expires < %s and item_deleted = 0 ", db_utcnow() ); - if($r) { + if ($r) { require_once('include/items.php'); - foreach($r as $rr) { - drop_item($rr['id'],false,(($rr['item_wall']) ? DROPITEM_PHASE1 : DROPITEM_NORMAL)); - if($rr['item_wall']) { + foreach ($r as $rr) { + drop_item($rr['id'], false, (($rr['item_wall']) ? DROPITEM_PHASE1 : DROPITEM_NORMAL)); + if ($rr['item_wall']) { // The notifier isn't normally invoked unless item_drop is interactive. - Master::Summon( [ 'Notifier', 'drop', $rr['id'] ] ); + Master::Summon(['Notifier', 'drop', $rr['id']]); + if ($interval) + @time_sleep_until(microtime(true) + (float)$interval); } } } @@ -78,9 +83,9 @@ class Cron { dbesc(NULL_DATE), db_utcnow() ); - if($r) { + if ($r) { require_once('include/security.php'); - foreach($r as $rr) { + foreach ($r as $rr) { atoken_delete($rr['atoken_id']); } } @@ -90,33 +95,33 @@ class Cron { // or dead entries. $r = q("select channel_id from channel where channel_dirdate < %s - INTERVAL %s and channel_removed = 0", - db_utcnow(), + db_utcnow(), db_quoteinterval('30 DAY') ); - if($r) { - foreach($r as $rr) { - Master::Summon(array('Directory',$rr['channel_id'],'force')); - if($interval) - @time_sleep_until(microtime(true) + (float) $interval); + if ($r) { + foreach ($r as $rr) { + Master::Summon(array('Directory', $rr['channel_id'], 'force')); + if ($interval) + @time_sleep_until(microtime(true) + (float)$interval); } } - + // Clean expired photos from cache - + $r = q("SELECT DISTINCT xchan, content FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s", intval(PHOTO_CACHE), db_utcnow(), - db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY') + db_quoteinterval(get_config('system', 'active_expire_days', '30') . ' DAY') ); - if($r) { + if ($r) { q("DELETE FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s", intval(PHOTO_CACHE), db_utcnow(), - db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY') + db_quoteinterval(get_config('system', 'active_expire_days', '30') . ' DAY') ); - foreach($r as $rr) { + foreach ($r as $rr) { $file = dbunescbin($rr['content']); - if(is_file($file)) { + if (is_file($file)) { @unlink($file); @rmdir(dirname($file)); logger('info: deleted cached photo file ' . $file, LOGGER_DEBUG); @@ -130,27 +135,29 @@ class Cron { $r = q("select id from item where item_delayed = 1 and created <= %s and created > '%s' ", db_utcnow(), - dbesc(datetime_convert('UTC','UTC','now - 2 days')) + dbesc(datetime_convert('UTC', 'UTC', 'now - 2 days')) ); - if($r) { - foreach($r as $rr) { + if ($r) { + foreach ($r as $rr) { $x = q("update item set item_delayed = 0 where id = %d", intval($rr['id']) ); - if($x) { + if ($x) { $z = q("select * from item where id = %d", - intval($message_id) + intval($rr['id']) ); - if($z) { + if ($z) { xchan_query($z); $sync_item = fetch_post_tags($z); Libsync::build_sync_packet($sync_item[0]['uid'], - [ - 'item' => [ encode_item($sync_item[0],true) ] + [ + 'item' => [encode_item($sync_item[0], true)] ] ); } - Master::Summon(array('Notifier','wall-new',$rr['id'])); + Master::Summon(array('Notifier', 'wall-new', $rr['id'])); + if ($interval) + @time_sleep_until(microtime(true) + (float)$interval); } } } @@ -163,27 +170,22 @@ class Cron { require_once('include/attach.php'); attach_upgrade(); - $abandon_days = intval(get_config('system','account_abandon_days')); - if($abandon_days < 1) - $abandon_days = 0; - - // once daily run birthday_updates and then expire in background // FIXME: add birthday updates, both locally and for xprof for use // by directory servers - $d1 = intval(get_config('system','last_expire_day')); - $d2 = intval(datetime_convert('UTC','UTC','now','d')); + $d1 = intval(get_config('system', 'last_expire_day')); + $d2 = intval(datetime_convert('UTC', 'UTC', 'now', 'd')); // Allow somebody to staggger daily activities if they have more than one site on their server, // or if it happens at an inconvenient (busy) hour. - $h1 = intval(get_config('system','cron_hour')); - $h2 = intval(datetime_convert('UTC','UTC','now','G')); + $h1 = intval(get_config('system', 'cron_hour')); + $h2 = intval(datetime_convert('UTC', 'UTC', 'now', 'G')); - if(($d2 != $d1) && ($h1 == $h2)) { + if (($d2 != $d1) && ($h1 == $h2)) { Master::Summon(array('Cron_daily')); } @@ -192,14 +194,14 @@ class Cron { $r = q("select xchan_photo_l, xchan_hash from xchan where xchan_photo_l != '' and xchan_photo_m = '' and xchan_photo_date < %s - INTERVAL %s", - db_utcnow(), + db_utcnow(), db_quoteinterval('1 DAY') ); - if($r) { + if ($r) { require_once('include/photo/photo_driver.php'); - foreach($r as $rr) { + foreach ($r as $rr) { $photos = import_xchan_photo($rr['xchan_photo_l'], $rr['xchan_hash'], false, true); - $x = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' + q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'", dbesc($photos[0]), dbesc($photos[1]), @@ -213,31 +215,28 @@ class Cron { // pull in some public posts - $disable_discover_tab = get_config('system','disable_discover_tab') || get_config('system','disable_discover_tab') === false; - if(! $disable_discover_tab) +/* $disable_discover_tab = get_config('system', 'disable_discover_tab') || get_config('system', 'disable_discover_tab') === false; + if (!$disable_discover_tab) Master::Summon(array('Externals')); +*/ - $generation = 0; + $restart = false; - $restart = false; - - if(($argc > 1) && ($argv[1] == 'restart')) { - $restart = true; + if (($argc > 1) && ($argv[1] == 'restart')) { + $restart = true; $generation = intval($argv[2]); - if(! $generation) + if (!$generation) return; } reload_plugins(); - $d = datetime_convert(); - // TODO check to see if there are any cronhooks before wasting a process - if(! $restart) + if (!$restart) Master::Summon(array('Cronhooks')); - set_config('system','lastcron',datetime_convert()); + set_config('system', 'lastcron', datetime_convert()); //All done - clear the lockfile @unlink($lockfile); diff --git a/Zotlabs/Daemon/Cron_daily.php b/Zotlabs/Daemon/Cron_daily.php index a6daad051..1983c68e6 100644 --- a/Zotlabs/Daemon/Cron_daily.php +++ b/Zotlabs/Daemon/Cron_daily.php @@ -6,7 +6,7 @@ use Zotlabs\Lib\Libzotdir; class Cron_daily { - static public function run($argc,$argv) { + static public function run($argc, $argv) { logger('cron_daily: start'); @@ -15,14 +15,12 @@ class Cron_daily { * */ - Libzotdir::check_upstream_directory(); - // Fire off the Cron_weekly process if it's the correct day. - $d3 = intval(datetime_convert('UTC','UTC','now','N')); - if($d3 == 7) { + $d3 = intval(datetime_convert('UTC', 'UTC', 'now', 'N')); + if ($d3 == 7) { Master::Summon(array('Cron_weekly')); } @@ -53,8 +51,8 @@ class Cron_daily { // Clean up emdedded content cache q("DELETE FROM cache WHERE updated < %s - INTERVAL %s", - db_utcnow(), - db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY') + db_utcnow(), + db_quoteinterval(get_config('system', 'active_expire_days', '30') . ' DAY') ); //update statistics in config @@ -68,8 +66,8 @@ class Cron_daily { // expire old delivery reports - $keep_reports = intval(get_config('system','expire_delivery_reports')); - if($keep_reports === 0) + $keep_reports = intval(get_config('system', 'expire_delivery_reports')); + if ($keep_reports === 0) $keep_reports = 10; q("delete from dreport where dreport_time < %s - INTERVAL %s", @@ -85,13 +83,12 @@ class Cron_daily { // Pull remote changes and push local changes. // potential issue: how do we keep from creating an endless update loop? - $dirmode = get_config('system','directory_mode'); + $dirmode = get_config('system', 'directory_mode'); - if($dirmode == DIRECTORY_MODE_SECONDARY || $dirmode == DIRECTORY_MODE_PRIMARY) { + if ($dirmode == DIRECTORY_MODE_SECONDARY || $dirmode == DIRECTORY_MODE_PRIMARY) { Libzotdir::sync_directories($dirmode); } - Master::Summon(array('Expire')); Master::Summon(array('Cli_suggest')); @@ -99,9 +96,10 @@ class Cron_daily { z6_discover(); - call_hooks('cron_daily',datetime_convert()); + $date = datetime_convert(); + call_hooks('cron_daily', $date); - set_config('system','last_expire_day',intval(datetime_convert('UTC','UTC','now','d'))); + set_config('system', 'last_expire_day', intval(datetime_convert('UTC', 'UTC', 'now', 'd'))); /** * End Cron Daily diff --git a/Zotlabs/Daemon/Cron_weekly.php b/Zotlabs/Daemon/Cron_weekly.php index d44400767..407aa40ef 100644 --- a/Zotlabs/Daemon/Cron_weekly.php +++ b/Zotlabs/Daemon/Cron_weekly.php @@ -4,21 +4,22 @@ namespace Zotlabs\Daemon; class Cron_weekly { - static public function run($argc,$argv) { + static public function run($argc, $argv) { /** * Cron Weekly - * + * * Actions in the following block are executed once per day only on Sunday (once per week). * */ - call_hooks('cron_weekly',datetime_convert()); + $date = datetime_convert(); + call_hooks('cron_weekly', $date); z_check_cert(); prune_hub_reinstalls(); - + mark_orphan_hubsxchans(); // Find channels that were removed in the last three weeks, but @@ -31,8 +32,8 @@ class Cron_weekly { db_utcnow(), db_quoteinterval('21 DAY'), db_utcnow(), db_quoteinterval('10 DAY') ); - if($r) { - foreach($r as $rv) { + if ($r) { + foreach ($r as $rv) { channel_remove_final($rv['channel_id']); } } @@ -43,14 +44,14 @@ class Cron_weekly { db_utcnow(), db_quoteinterval('14 DAY') ); - $dirmode = intval(get_config('system','directory_mode')); - if($dirmode === DIRECTORY_MODE_SECONDARY || $dirmode === DIRECTORY_MODE_PRIMARY) { - logger('regdir: ' . print_r(z_fetch_url(get_directory_primary() . '/regdir?f=&url=' . urlencode(z_root()) . '&realm=' . urlencode(get_directory_realm())),true)); + $dirmode = intval(get_config('system', 'directory_mode')); + if ($dirmode === DIRECTORY_MODE_SECONDARY || $dirmode === DIRECTORY_MODE_PRIMARY) { + logger('regdir: ' . print_r(z_fetch_url(get_directory_primary() . '/regdir?f=&url=' . urlencode(z_root()) . '&realm=' . urlencode(get_directory_realm())), true)); } // Check for dead sites Master::Summon(array('Checksites')); - + // update searchable doc indexes Master::Summon(array('Importdoc')); diff --git a/Zotlabs/Daemon/CurlAuth.php b/Zotlabs/Daemon/CurlAuth.php index de41382e3..2396da9aa 100644 --- a/Zotlabs/Daemon/CurlAuth.php +++ b/Zotlabs/Daemon/CurlAuth.php @@ -2,6 +2,8 @@ namespace Zotlabs\Daemon; +use App; + // generate a curl compatible cookie file with an authenticated session for the given channel_id. // If this file is then used with curl and the destination url is sent through zid() or manually // manipulated to add a zid, it should allow curl to provide zot magic-auth across domains. @@ -10,15 +12,15 @@ namespace Zotlabs\Daemon; class CurlAuth { - static public function run($argc,$argv) { + static public function run($argc, $argv) { - if($argc != 2) + if ($argc != 2) return; - \App::$session->start(); + App::$session->start(); $_SESSION['authenticated'] = 1; - $_SESSION['uid'] = $argv[1]; + $_SESSION['uid'] = $argv[1]; $x = session_id(); @@ -29,14 +31,14 @@ class CurlAuth { $output = ''; - if($e) { + if ($e) { $lines = file($f); - if($lines) { - foreach($lines as $line) { - if(strlen($line) > 0 && $line[0] != '#' && substr_count($line, "\t") == 6) { + if ($lines) { + foreach ($lines as $line) { + if (strlen($line) > 0 && $line[0] != '#' && substr_count($line, "\t") == 6) { $tokens = explode("\t", $line); $tokens = array_map('trim', $tokens); - if($tokens[4] > time()) { + if ($tokens[4] > time()) { $output .= $line . "\n"; } } @@ -46,9 +48,9 @@ class CurlAuth { } } $t = time() + (24 * 3600); - file_put_contents($f, $output . 'HttpOnly_' . \App::get_hostname() . "\tFALSE\t/\tTRUE\t$t\tPHPSESSID\t" . $x, (($e) ? FILE_APPEND : 0)); + file_put_contents($f, $output . 'HttpOnly_' . App::get_hostname() . "\tFALSE\t/\tTRUE\t$t\tPHPSESSID\t" . $x, (($e) ? FILE_APPEND : 0)); - file_put_contents($c,$x); + file_put_contents($c, $x); return; } diff --git a/Zotlabs/Daemon/Deliver.php b/Zotlabs/Daemon/Deliver.php index c853af6a8..f8149ee69 100644 --- a/Zotlabs/Daemon/Deliver.php +++ b/Zotlabs/Daemon/Deliver.php @@ -5,25 +5,25 @@ namespace Zotlabs\Daemon; require_once('include/queue_fn.php'); class Deliver { - - static public function run($argc,$argv) { - if($argc < 2) + static public function run($argc, $argv) { + + if ($argc < 2) return; - logger('deliver: invoked: ' . print_r($argv,true), LOGGER_DATA); + logger('deliver: invoked: ' . print_r($argv, true), LOGGER_DATA); - for($x = 1; $x < $argc; $x ++) { + for ($x = 1; $x < $argc; $x++) { - if(! $argv[$x]) + if (!$argv[$x]) continue; $r = q("select * from outq where outq_hash = '%s'", dbesc($argv[$x]) ); - if($r) { - queue_deliver($r[0],true); + if ($r) { + queue_deliver($r[0], true); } } diff --git a/Zotlabs/Daemon/Deliver_hooks.php b/Zotlabs/Daemon/Deliver_hooks.php index e8b5acef0..4d3ce4e1d 100644 --- a/Zotlabs/Daemon/Deliver_hooks.php +++ b/Zotlabs/Daemon/Deliver_hooks.php @@ -2,21 +2,18 @@ namespace Zotlabs\Daemon; -require_once('include/zot.php'); - class Deliver_hooks { - static public function run($argc,$argv) { + static public function run($argc, $argv) { - if($argc < 2) + if ($argc < 2) return; - $r = q("select * from item where id = '%d'", intval($argv[1]) ); - if($r) - call_hooks('notifier_normal',$r[0]); + if ($r) + call_hooks('notifier_normal', $r[0]); } } diff --git a/Zotlabs/Daemon/Directory.php b/Zotlabs/Daemon/Directory.php index ab58432de..1f307b273 100644 --- a/Zotlabs/Daemon/Directory.php +++ b/Zotlabs/Daemon/Directory.php @@ -8,40 +8,40 @@ use Zotlabs\Lib\Queue; class Directory { - static public function run($argc,$argv){ + static public function run($argc, $argv) { - if($argc < 2) + if ($argc < 2) return; - $force = false; + $force = false; $pushall = true; - if($argc > 2) { - if($argv[2] === 'force') + if ($argc > 2) { + if ($argv[2] === 'force') $force = true; - if($argv[2] === 'nopush') + if ($argv[2] === 'nopush') $pushall = false; - } + } logger('directory update', LOGGER_DEBUG); - $dirmode = get_config('system','directory_mode'); - if($dirmode === false) + $dirmode = get_config('system', 'directory_mode'); + if ($dirmode === false) $dirmode = DIRECTORY_MODE_NORMAL; $x = q("select * from channel where channel_id = %d limit 1", intval($argv[1]) ); - if(! $x) + if (!$x) return; $channel = $x[0]; - if($dirmode != DIRECTORY_MODE_NORMAL) { + if ($dirmode != DIRECTORY_MODE_NORMAL) { // this is an in-memory update and we don't need to send a network packet. - Libzotdir::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()), @@ -49,8 +49,8 @@ class Directory { ); // Now update all the connections - if($pushall) - Master::Summon(array('Notifier','refresh_all',$channel['channel_id'])); + if ($pushall) + Master::Summon(array('Notifier', 'refresh_all', $channel['channel_id'])); return; } @@ -63,14 +63,12 @@ class Directory { // ensure the upstream directory is updated - - $packet = Libzot::build_packet($channel,(($force) ? 'force_refresh' : 'refresh')); - $z = Libzot::zot($url,$packet,$channel); - + $packet = Libzot::build_packet($channel, (($force) ? 'force_refresh' : 'refresh')); + $z = Libzot::zot($url, $packet, $channel); // re-queue if unsuccessful - if(! $z['success']) { + if (!$z['success']) { /** @FIXME we aren't updating channel_dirdate if we have to queue * the directory packet. That means we'll try again on the next poll run. @@ -95,8 +93,8 @@ class Directory { } // Now update all the connections - if($pushall) - Master::Summon(array('Notifier','refresh_all',$channel['channel_id'])); + if ($pushall) + Master::Summon(array('Notifier', 'refresh_all', $channel['channel_id'])); } } diff --git a/Zotlabs/Daemon/Expire.php b/Zotlabs/Daemon/Expire.php index a688d6f97..c4ff8aec6 100644 --- a/Zotlabs/Daemon/Expire.php +++ b/Zotlabs/Daemon/Expire.php @@ -5,23 +5,24 @@ namespace Zotlabs\Daemon; class Expire { - static public function run($argc,$argv){ + static public function run($argc, $argv) { cli_startup(); - - $pid = get_config('expire', 'procid', false); + + $pid = get_config('procid', 'expire', false); if ($pid && (function_exists('posix_kill') ? posix_kill($pid, 0) : true)) { - logger('Expire: procedure already run with pid ' . $pid, LOGGER_DEBUG); - return; + logger('procedure already run with pid ' . $pid, LOGGER_DEBUG); + return; } - + $pid = getmypid(); - set_config('expire', 'procid', $pid); + set_config('procid', 'expire', $pid); // perform final cleanup on previously delete items $r = q("select id from item where item_deleted = 1 and item_pending_remove = 0 and changed < %s - INTERVAL %s", - db_utcnow(), db_quoteinterval('10 DAY') + db_utcnow(), + db_quoteinterval('10 DAY') ); if ($r) { foreach ($r as $rr) { @@ -32,23 +33,22 @@ class Expire { // physically remove anything that has been deleted for more than two months /** @FIXME - this is a wretchedly inefficient query */ - $r = q("delete from item where item_pending_remove = 1 and changed < %s - INTERVAL %s", - db_utcnow(), db_quoteinterval('36 DAY') + q("delete from item where item_pending_remove = 1 and changed < %s - INTERVAL %s", + db_utcnow(), + db_quoteinterval('36 DAY') ); - /** @FIXME make this optional as it could have a performance impact on large sites */ - if (intval(get_config('system', 'optimize_items'))) q("optimize table item"); 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')); + $site_expire = intval(get_config('system', 'default_expire_days')); + $commented_days = intval(get_config('system', 'active_expire_days')); logger('site_expire: ' . $site_expire); - $r = q("SELECT channel_id, channel_system, channel_address, channel_expire_days from channel where true"); + $r = dbq("SELECT channel_id, channel_system, channel_address, channel_expire_days from channel where true"); if ($r) { foreach ($r as $rr) { @@ -64,11 +64,12 @@ class Expire { $channel_expire = $service_class_expire; else $channel_expire = $site_expire; - + if (intval($channel_expire) && (intval($channel_expire) < intval($rr['channel_expire_days'])) || intval($rr['channel_expire_days'] == 0)) { $expire_days = $channel_expire; - } else { + } + else { $expire_days = $rr['channel_expire_days']; } @@ -93,13 +94,13 @@ class Expire { } logger('Expire: sys interval: ' . $expire_days, LOGGER_DEBUG); - + if ($expire_days) item_expire($x['channel_id'], $expire_days, $commented_days); logger('Expire: sys: done', LOGGER_DEBUG); } - - del_config('expire', 'procid'); + + del_config('procid', 'expire'); } } diff --git a/Zotlabs/Daemon/Externals.php b/Zotlabs/Daemon/Externals.php index a9988a509..064b3f71d 100644 --- a/Zotlabs/Daemon/Externals.php +++ b/Zotlabs/Daemon/Externals.php @@ -2,97 +2,180 @@ namespace Zotlabs\Daemon; -require_once('include/zot.php'); +use Zotlabs\Lib\Activity; +use Zotlabs\Lib\ActivityStreams; +use Zotlabs\Lib\ASCollection; + require_once('include/channel.php'); class Externals { - static public function run($argc,$argv){ + static public function run($argc, $argv) { - $total = 0; + logger('externals: start'); + + $importer = get_sys_channel(); + $total = 0; $attempts = 0; logger('externals: startup', LOGGER_DEBUG); // pull in some public posts + while ($total == 0 && $attempts < 3) { + $arr = ['url' => '']; + call_hooks('externals_url_select', $arr); - while($total == 0 && $attempts < 3) { - $arr = array('url' => ''); - call_hooks('externals_url_select',$arr); - - if($arr['url']) { + if ($arr['url']) { $url = $arr['url']; - } + } else { $randfunc = db_getfunc('RAND'); - // fixme this query does not deal with directory realms. + // fixme this query does not deal with directory realms. - $r = q("select site_url, site_pull from site where site_url != '%s' and site_flags != %d and site_type = %d and site_dead = 0 order by $randfunc limit 1", + $r = q("select site_url, site_pull from site where site_url != '%s' + and site_flags != %d and site_type = %d + and site_dead = 0 and site_project like '%s' and site_version > '5.3.1' order by $randfunc limit 1", dbesc(z_root()), intval(DIRECTORY_MODE_STANDALONE), - intval(SITE_TYPE_ZOT) + intval(SITE_TYPE_ZOT), + dbesc('hubzilla%') ); - if($r) + if ($r) $url = $r[0]['site_url']; } $blacklisted = false; - if(! check_siteallowed($url)) { + if (!check_siteallowed($url)) { logger('blacklisted site: ' . $url); $blacklisted = true; } - $attempts ++; + $attempts++; // make sure we can eventually break out if somebody blacklists all known sites - if($blacklisted) { - if($attempts > 20) + if ($blacklisted) { + if ($attempts > 20) break; - $attempts --; + $attempts--; continue; } - if($url) { - if($r[0]['site_pull'] > NULL_DATE) - $mindate = urlencode(datetime_convert('','',$r[0]['site_pull'] . ' - 1 day')); - else { - $days = get_config('externals','since_days'); - if($days === false) - $days = 15; - $mindate = urlencode(datetime_convert('','','now - ' . intval($days) . ' days')); - } + if ($url) { - $feedurl = $url . '/zotfeed?f=&mindate=' . $mindate; + $max = intval(get_config('system', 'max_imported_posts', 30)); + if (intval($max)) { + logger('externals: fetching outbox'); - logger('externals: pulling public content from ' . $feedurl, LOGGER_DEBUG); + $feed_url = $url . '/zotfeed'; + $obj = new ASCollection($feed_url, $importer, 0, $max); + $messages = $obj->get(); - $x = z_fetch_url($feedurl); - if(($x) && ($x['success'])) { - - q("update site set site_pull = '%s' where site_url = '%s'", - dbesc(datetime_convert()), - dbesc($url) - ); - - $j = json_decode($x['body'],true); - if($j['success'] && $j['messages']) { - $sys = get_sys_channel(); - foreach($j['messages'] as $message) { - // on these posts, clear any route info. - $message['route'] = ''; - $results = process_delivery(array('hash' => 'undefined'), get_item_elements($message), - array(array('hash' => $sys['xchan_hash'])), false, true); - $total ++; + if ($messages) { + foreach ($messages as $message) { + if (is_string($message)) { + $message = Activity::fetch($message, $importer); + } + $AS = new ActivityStreams($message); + if ($AS->is_valid() && is_array($AS->obj)) { + $item = Activity::decode_note($AS); + Activity::store($importer, $importer['xchan_hash'], $AS, $item, true); + $total++; + } } - logger('externals: import_public_posts: ' . $total . ' messages imported', LOGGER_DEBUG); } + logger('externals: import_public_posts: ' . $total . ' messages imported', LOGGER_DEBUG); } } } + return; + + /* $total = 0; + $attempts = 0; + + logger('externals: startup', LOGGER_DEBUG); + + // pull in some public posts + + while ($total == 0 && $attempts < 3) { + $arr = ['url' => '']; + call_hooks('externals_url_select', $arr); + + if ($arr['url']) { + $url = $arr['url']; + } + else { + $randfunc = db_getfunc('RAND'); + + // fixme this query does not deal with directory realms. + + $r = q("select site_url, site_pull from site where site_url != '%s' and site_flags != %d and site_type = %d and site_dead = 0 order by $randfunc limit 1", + dbesc(z_root()), + intval(DIRECTORY_MODE_STANDALONE), + intval(SITE_TYPE_ZOT) + ); + if ($r) + $url = $r[0]['site_url']; + } + + $blacklisted = false; + + if (!check_siteallowed($url)) { + logger('blacklisted site: ' . $url); + $blacklisted = true; + } + + $attempts++; + + // make sure we can eventually break out if somebody blacklists all known sites + + if ($blacklisted) { + if ($attempts > 20) + break; + $attempts--; + continue; + } + + if ($url) { + if ($r[0]['site_pull'] > NULL_DATE) + $mindate = urlencode(datetime_convert('', '', $r[0]['site_pull'] . ' - 1 day')); + else { + $days = get_config('externals', 'since_days'); + if ($days === false) + $days = 15; + $mindate = urlencode(datetime_convert('', '', 'now - ' . intval($days) . ' days')); + } + + $feedurl = $url . '/zotfeed?f=&mindate=' . $mindate; + + logger('externals: pulling public content from ' . $feedurl, LOGGER_DEBUG); + + $x = z_fetch_url($feedurl); + if (($x) && ($x['success'])) { + + q("update site set site_pull = '%s' where site_url = '%s'", + dbesc(datetime_convert()), + dbesc($url) + ); + + $j = json_decode($x['body'], true); + if ($j['success'] && $j['messages']) { + $sys = get_sys_channel(); + foreach ($j['messages'] as $message) { + // on these posts, clear any route info. + $message['route'] = ''; + process_delivery(['hash' => 'undefined'], get_item_elements($message), + [['hash' => $sys['xchan_hash']]], false, true); + $total++; + } + logger('externals: import_public_posts: ' . $total . ' messages imported', LOGGER_DEBUG); + } + } + } + }*/ } } diff --git a/Zotlabs/Daemon/Gprobe.php b/Zotlabs/Daemon/Gprobe.php index 9e74eb8b5..29efcf475 100644 --- a/Zotlabs/Daemon/Gprobe.php +++ b/Zotlabs/Daemon/Gprobe.php @@ -9,27 +9,27 @@ use Zotlabs\Lib\Zotfinger; // performs zot_finger on $argv[1], which is a hex_encoded webbie/reddress class Gprobe { - static public function run($argc,$argv) { + static public function run($argc, $argv) { - if($argc != 2) + if ($argc != 2) return; $url = hex2bin($argv[1]); - if(! strpos($url,'@')) + if (!strpos($url, '@')) return; $r = q("select * from hubloc where hubloc_addr = '%s' and hubloc_network = 'zot6' limit 1", dbesc($url) ); - if(! $r) { + if (!$r) { $href = Webfinger::zot_url(punify($url)); - if($href) { + 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']); + if (is_array($zf) && array_path_exists('signature/signer', $zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) { + Libzot::import_xchan($zf['data']); } } diff --git a/Zotlabs/Daemon/Importdoc.php b/Zotlabs/Daemon/Importdoc.php old mode 100755 new mode 100644 index 0ca589e4a..9e818e2b3 --- a/Zotlabs/Daemon/Importdoc.php +++ b/Zotlabs/Daemon/Importdoc.php @@ -5,7 +5,7 @@ namespace Zotlabs\Daemon; class Importdoc { - static public function run($argc,$argv) { + static public function run($argc, $argv) { require_once('include/help.php'); @@ -16,20 +16,20 @@ class Importdoc { static public function update_docs_dir($s) { $f = basename($s); $d = dirname($s); - if($s === 'doc/html') + if ($s === 'doc/html') return; $files = glob("$d/$f"); - if($files) { - foreach($files as $fi) { - if($fi === 'doc/html') { + if ($files) { + foreach ($files as $fi) { + if ($fi === 'doc/html') { continue; } - if(is_dir($fi)) { + if (is_dir($fi)) { self::update_docs_dir("$fi/*"); } else { // don't update media content - if(strpos(z_mime_content_type($fi),'text') === 0) { + if (strpos(z_mime_content_type($fi), 'text') === 0) { store_doc_file($fi); } } diff --git a/Zotlabs/Daemon/Importfile.php b/Zotlabs/Daemon/Importfile.php index 749949679..299fb1ee5 100644 --- a/Zotlabs/Daemon/Importfile.php +++ b/Zotlabs/Daemon/Importfile.php @@ -6,22 +6,21 @@ use Zotlabs\Lib\Libsync; class Importfile { - static public function run($argc,$argv){ + static public function run($argc, $argv) { - logger('Importfile: ' . print_r($argv,true)); + logger('Importfile: ' . print_r($argv, true)); - if($argc < 3) + if ($argc < 3) return; $channel = channelx_by_n($argv[1]); - if(! $channel) + if (!$channel) return; $srcfile = $argv[2]; $folder = (($argc > 3) ? $argv[3] : ''); $dstname = (($argc > 4) ? $argv[4] : ''); - - $hash = random_string(); + $hash = random_string(); $arr = [ 'src' => $srcfile, @@ -35,15 +34,15 @@ class Importfile { 'replace' => true ]; - if($folder) + if ($folder) $arr['folder'] = $folder; - attach_store($channel,$channel['channel_hash'],'import',$arr); + attach_store($channel, $channel['channel_hash'], 'import', $arr); + + $sync = attach_export_data($channel, $hash); + if ($sync) + Libsync::build_sync_packet($channel['channel_id'], ['file' => [$sync]]); - $sync = attach_export_data($channel,$hash); - if($sync) - Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync))); - return; } } diff --git a/Zotlabs/Daemon/Master.php b/Zotlabs/Daemon/Master.php index 8c3a7e570..6fa656be5 100644 --- a/Zotlabs/Daemon/Master.php +++ b/Zotlabs/Daemon/Master.php @@ -2,58 +2,57 @@ namespace Zotlabs\Daemon; -if(array_search( __file__ , get_included_files()) === 0) { +if (array_search(__file__, get_included_files()) === 0) { require_once('include/cli_startup.php'); array_shift($argv); $argc = count($argv); - if($argc) - Master::Release($argc,$argv); + if ($argc) + Master::Release($argc, $argv); return; } - class Master { static public function Summon($arr) { $hookinfo = [ - 'argv'=>$arr + 'argv' => $arr ]; - call_hooks ('daemon_master_summon',$hookinfo); + call_hooks('daemon_master_summon', $hookinfo); - $arr = $hookinfo['argv']; + $arr = $hookinfo['argv']; $argc = count($arr); - if ((!is_array($arr) || (count($arr) < 1))) { - logger("Summon handled by hook.",LOGGER_DEBUG); + if ((!is_array($arr) || ($argc < 1))) { + logger("Summon handled by hook.", LOGGER_DEBUG); return; } - $phpbin = get_config('system','phpbin','php'); - proc_run($phpbin,'Zotlabs/Daemon/Master.php',$arr); + $phpbin = get_config('system', 'phpbin', 'php'); + proc_run($phpbin, 'Zotlabs/Daemon/Master.php', $arr); } - static public function Release($argc,$argv) { + static public function Release($argc, $argv) { cli_startup(); $hookinfo = [ - 'argv'=>$argv + 'argv' => $argv ]; - call_hooks ('daemon_master_release',$hookinfo); + call_hooks('daemon_master_release', $hookinfo); $argv = $hookinfo['argv']; $argc = count($argv); - if ((!is_array($argv) || (count($argv) < 1))) { - logger("Release handled by hook.",LOGGER_DEBUG); + if ((!is_array($argv) || ($argc < 1))) { + logger("Release handled by hook.", LOGGER_DEBUG); return; } - logger('Master: release: ' . json_encode($argv), LOGGER_ALL,LOG_DEBUG); - $cls = '\\Zotlabs\\Daemon\\' . $argv[0]; - $cls::run($argc,$argv); + logger('Master: release: ' . json_encode($argv), LOGGER_ALL, LOG_DEBUG); + $cls = '\\Zotlabs\\Daemon\\' . $argv[0]; + $cls::run($argc, $argv); } } diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php index 626299661..02a0e155f 100644 --- a/Zotlabs/Daemon/Notifier.php +++ b/Zotlabs/Daemon/Notifier.php @@ -14,7 +14,6 @@ require_once('include/items.php'); require_once('include/bbcode.php'); - /* * This file was at one time responsible for doing all deliveries, but this caused * big problems on shared hosting systems, where the process might get killed by the @@ -81,198 +80,198 @@ require_once('include/bbcode.php'); */ - class Notifier { - static public function run($argc,$argv){ + static public function run($argc, $argv) { - if($argc < 3) + if ($argc < 3) return; - logger('notifier: invoked: ' . print_r($argv,true), LOGGER_DEBUG); + logger('notifier: invoked: ' . print_r($argv, true), LOGGER_DEBUG); $cmd = $argv[1]; $item_id = $argv[2]; - if(! $item_id) + if (!$item_id) return; $sys = get_sys_channel(); - $deliveries = array(); + $deliveries = []; - $request = false; - $mail = false; - $top_level = false; - $location = false; - $recipients = array(); - $url_recipients = array(); - $normal_mode = true; - $packet_type = 'undefined'; + $request = false; + $mail = false; + $location = false; + $recipients = []; + $normal_mode = true; + $packet_type = 'undefined'; - if($cmd === 'mail' || $cmd === 'single_mail') { + if ($cmd === 'mail' || $cmd === 'single_mail') { $normal_mode = false; - $mail = true; - $private = true; - $message = q("SELECT * FROM mail WHERE id = %d LIMIT 1", - intval($item_id) + $mail = true; + $private = true; + $message = q("SELECT * FROM mail WHERE id = %d LIMIT 1", + intval($item_id) ); - if(! $message) { + if (!$message) { return; } xchan_mail_query($message[0]); - $uid = $message[0]['channel_id']; + $uid = $message[0]['channel_id']; $recipients[] = $message[0]['from_xchan']; // include clones $recipients[] = $message[0]['to_xchan']; - $item = $message[0]; - + $item = $message[0]; $encoded_item = encode_mail($item); $s = q("select * from channel where channel_id = %d limit 1", - intval($item['channel_id']) + intval($uid) ); - if($s) + if ($s) $channel = $s[0]; } - elseif($cmd === 'request') { - $channel_id = $item_id; - $xchan = $argv[3]; + elseif ($cmd === 'request') { + $channel_id = $item_id; + $xchan = $argv[3]; $request_message_id = $argv[4]; $s = q("select * from channel where channel_id = %d limit 1", intval($channel_id) ); - if($s) + if ($s) $channel = $s[0]; - $private = true; + $private = true; $recipients[] = $xchan; - $packet_type = 'request'; - $normal_mode = false; + $packet_type = 'request'; + $normal_mode = false; } - elseif($cmd === 'keychange') { + elseif ($cmd === 'keychange') { $channel = channelx_by_n($item_id); - $r = q("select abook_xchan from abook where abook_channel = %d", + + $r = q("select abook_xchan from abook where abook_channel = %d", intval($item_id) ); - if($r) { - foreach($r as $rr) { + if ($r) { + foreach ($r as $rr) { $recipients[] = $rr['abook_xchan']; } } - $private = false; + $private = false; $packet_type = 'keychange'; $normal_mode = false; } - elseif(in_array($cmd, [ 'permission_update', 'permission_reject', 'permission_accept', 'permission_create' ])) { + elseif (in_array($cmd, ['permission_update', 'permission_reject', 'permission_accept', 'permission_create'])) { // Get the (single) recipient $r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_self = 0", intval($item_id) ); - if($r) { + if ($r) { $uid = $r[0]['abook_channel']; // Get the sender $channel = channelx_by_n($uid); - if($channel) { - $perm_update = array('sender' => $channel, 'recipient' => $r[0], 'success' => false, 'deliveries' => ''); + if ($channel) { + $perm_update = ['sender' => $channel, 'recipient' => $r[0], 'success' => false, 'deliveries' => '']; - if($cmd === 'permission_create') - call_hooks('permissions_create',$perm_update); - elseif($cmd === 'permission_accept') - call_hooks('permissions_accept',$perm_update); - elseif($cmd === 'permission_reject') - call_hooks('permissions_reject',$perm_update); + if ($cmd === 'permission_create') + call_hooks('permissions_create', $perm_update); + elseif ($cmd === 'permission_accept') + call_hooks('permissions_accept', $perm_update); + elseif ($cmd === 'permission_reject') + call_hooks('permissions_reject', $perm_update); else - call_hooks('permissions_update',$perm_update); + call_hooks('permissions_update', $perm_update); - if($perm_update['success']) { - if($perm_update['deliveries']) { + if ($perm_update['success']) { + if ($perm_update['deliveries']) { $deliveries[] = $perm_update['deliveries']; do_delivery($deliveries); } return; } else { - $recipients[] = $r[0]['abook_xchan']; - $private = false; - $packet_type = 'refresh'; - $packet_recips = array(array('guid' => $r[0]['xchan_guid'],'guid_sig' => $r[0]['xchan_guid_sig'],'hash' => $r[0]['xchan_hash'])); + $recipients[] = $r[0]['abook_xchan']; + $private = false; + $packet_type = 'refresh'; + $packet_recips = [['guid' => $r[0]['xchan_guid'], 'guid_sig' => $r[0]['xchan_guid_sig'], 'hash' => $r[0]['xchan_hash']]]; } } } } - elseif($cmd === 'refresh_all') { + elseif ($cmd === 'refresh_all') { logger('notifier: refresh_all: ' . $item_id); - $uid = $item_id; + $uid = $item_id; $channel = channelx_by_n($item_id); - $r = q("select abook_xchan from abook where abook_channel = %d", - intval($item_id) + + $r = q("select abook_xchan from abook where abook_channel = %d", + intval($uid) ); - if($r) { - foreach($r as $rr) { + if ($r) { + foreach ($r as $rr) { $recipients[] = $rr['abook_xchan']; } } - $private = false; + $private = false; $packet_type = 'refresh'; } - elseif($cmd === 'location') { + elseif ($cmd === 'location') { logger('notifier: location: ' . $item_id); $s = q("select * from channel where channel_id = %d limit 1", intval($item_id) ); - if($s) + if ($s) $channel = $s[0]; - $uid = $item_id; - $recipients = array(); - $r = q("select abook_xchan from abook where abook_channel = %d", - intval($item_id) + + $uid = $item_id; + $recipients = []; + + $r = q("select abook_xchan from abook where abook_channel = %d", + intval($uid) ); - if($r) { - foreach($r as $rr) { + if ($r) { + foreach ($r as $rr) { $recipients[] = $rr['abook_xchan']; } } - $encoded_item = array('locations' => Libzot::encode_locations($channel),'type' => 'location', 'encoding' => 'zot'); - $target_item = array('aid' => $channel['channel_account_id'],'uid' => $channel['channel_id']); - $private = false; - $packet_type = 'location'; - $location = true; + $encoded_item = ['locations' => Libzot::encode_locations($channel), 'type' => 'location', 'encoding' => 'zot']; + $target_item = ['aid' => $channel['channel_account_id'], 'uid' => $channel['channel_id']]; + $private = false; + $packet_type = 'location'; + $location = true; } - elseif($cmd === 'purge') { + elseif ($cmd === 'purge') { $xchan = $argv[3]; logger('notifier: purge: ' . $item_id . ' => ' . $xchan); - if (! $xchan) { + if (!$xchan) { return; } - $channel = channelx_by_n($item_id); - $recipients[] = $xchan; - $private = true; - $packet_type = 'purge'; + $channel = channelx_by_n($item_id); + $recipients[] = $xchan; + $private = true; + $packet_type = 'purge'; $packet_recips[] = ['hash' => $xchan]; } - elseif($cmd === 'purge_all') { + elseif ($cmd === 'purge_all') { logger('notifier: purge_all: ' . $item_id); $channel = channelx_by_n($item_id); $recipients = []; - $r = q("select abook_xchan from abook where abook_channel = %d and abook_self = 0", + $r = q("select abook_xchan from abook where abook_channel = %d and abook_self = 0", intval($item_id) ); - if (! $r) { + if (!$r) { return; } foreach ($r as $rr) { - $recipients[] = $rr['abook_xchan']; + $recipients[] = $rr['abook_xchan']; $packet_recips[] = ['hash' => $rr['abook_xchan']]; } - $private = false; + $private = false; $packet_type = 'purge'; @@ -287,7 +286,7 @@ class Notifier { intval($item_id) ); - if(! $r) + if (!$r) return; xchan_query($r); @@ -296,25 +295,22 @@ class Notifier { $target_item = $r[0]; - if(in_array($target_item['author']['xchan_network'], ['rss', 'anon'])) { + 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'])) { + if (intval($target_item['item_deleted'])) { logger('notifier: target item ITEM_DELETED', LOGGER_DEBUG); - $deleted_item = true; } - if(! in_array(intval($target_item['item_type']), [ ITEM_TYPE_POST ] )) { - $hookinfo=[ - 'targetitem'=>$target_item, - 'deliver'=>false + if (!in_array(intval($target_item['item_type']), [ITEM_TYPE_POST])) { + $hookinfo = [ + 'targetitem' => $target_item, + 'deliver' => false ]; if (intval($target_item['item_type'] == ITEM_TYPE_CUSTOM)) { - call_hooks('customitem_deliver',$hookinfo); + call_hooks('customitem_deliver', $hookinfo); } if (!$hookinfo['deliver']) { @@ -328,14 +324,14 @@ class Notifier { // Check for non published items, but allow an exclusion for transmitting hidden file activities - if(intval($target_item['item_unpublished']) || intval($target_item['item_delayed']) || + if (intval($target_item['item_unpublished']) || intval($target_item['item_delayed']) || intval($target_item['item_blocked']) || - ( intval($target_item['item_hidden']) && ($target_item['obj_type'] !== ACTIVITY_OBJ_FILE))) { + (intval($target_item['item_hidden']) && ($target_item['obj_type'] !== ACTIVITY_OBJ_FILE))) { logger('notifier: target item not published, so not forwardable', LOGGER_DEBUG); return; } - if(strpos($target_item['postopts'],'nodeliver') !== false) { + if (strpos($target_item['postopts'], 'nodeliver') !== false) { logger('notifier: target item is undeliverable', LOGGER_DEBUG); return; } @@ -343,17 +339,16 @@ class Notifier { $s = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1", intval($target_item['uid']) ); - if($s) + if ($s) $channel = $s[0]; - if($channel['channel_hash'] !== $target_item['author_xchan'] && $channel['channel_hash'] !== $target_item['owner_xchan']) { + if ($channel['channel_hash'] !== $target_item['author_xchan'] && $channel['channel_hash'] !== $target_item['owner_xchan']) { logger("notifier: Sending channel {$channel['channel_hash']} is not owner {$target_item['owner_xchan']} or author {$target_item['author_xchan']}", LOGGER_NORMAL, LOG_WARNING); return; } - - if($target_item['mid'] === $target_item['parent_mid']) { - $parent_item = $target_item; + if ($target_item['mid'] === $target_item['parent_mid']) { + $parent_item = $target_item; $top_level_post = true; } else { @@ -362,10 +357,10 @@ class Notifier { intval($target_item['parent']) ); - if(! $r) + if (!$r) return; - if(strpos($r[0]['postopts'],'nodeliver') !== false) { + if (strpos($r[0]['postopts'], 'nodeliver') !== false) { logger('notifier: target item is undeliverable', LOGGER_DEBUG, LOG_NOTICE); return; } @@ -373,34 +368,34 @@ class Notifier { xchan_query($r); $r = fetch_post_tags($r); - $parent_item = $r[0]; + $parent_item = $r[0]; $top_level_post = false; } // avoid looping of discover items 12/4/2014 - if($sys && $parent_item['uid'] == $sys['channel_id']) + if ($sys && $parent_item['uid'] == $sys['channel_id']) return; $encoded_item = encode_item($target_item); // 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')); + $m = ((intval($target_item['item_deleted'])) ? '' : get_iconfig($target_item, 'activitypub', 'signed_data')); - if($m) { - $activity = json_decode($m,true); + if ($m) { + $activity = json_decode($m, true); } else { $activity = array_merge(['@context' => [ ACTIVITYSTREAMS_JSONLD_REV, 'https://w3id.org/security/v1', z_root() . ZOT_APSCHEMA_REV - ]], Activity::encode_activity($target_item) + ]], Activity::encode_activity($target_item) ); } - logger('target_item: ' . print_r($target_item,true), LOGGER_DEBUG); - logger('encoded: ' . print_r($activity,true), LOGGER_DEBUG); + 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. @@ -411,9 +406,7 @@ class Notifier { // flag on comments for an extended period. So we'll also call comment_local_origin() which looks at // the hostname in the message_id and provides a second (fallback) opinion. - $relay_to_owner = (((! $top_level_post) && (intval($target_item['item_origin'])) && comment_local_origin($target_item)) ? true : false); - - + $relay_to_owner = (((!$top_level_post) && (intval($target_item['item_origin'])) && comment_local_origin($target_item)) ? true : false); $uplink = false; @@ -425,43 +418,42 @@ class Notifier { // tag_deliver'd post which needs to be sent back to the original author - if(($cmd === 'uplink') && intval($parent_item['item_uplink']) && (! $top_level_post)) { + if (($cmd === 'uplink') && intval($parent_item['item_uplink']) && (!$top_level_post)) { logger('notifier: uplink'); $uplink = true; } - if(($relay_to_owner || $uplink) && ($cmd !== 'relay')) { + if (($relay_to_owner || $uplink) && ($cmd !== 'relay')) { logger('notifier: followup relay', LOGGER_DEBUG); - $recipients = array(($uplink) ? $parent_item['source_xchan'] : $parent_item['owner_xchan']); - $private = true; - if(! $encoded_item['flags']) - $encoded_item['flags'] = array(); + $recipients = [($uplink) ? $parent_item['source_xchan'] : $parent_item['owner_xchan']]; + $private = true; + if (!$encoded_item['flags']) + $encoded_item['flags'] = []; $encoded_item['flags'][] = 'relay'; - $upstream = true; + $upstream = true; } else { logger('notifier: normal distribution', LOGGER_DEBUG); - if($cmd === 'relay') + if ($cmd === 'relay') logger('notifier: owner relay'); $upstream = false; // if our parent is a tag_delivery recipient, uplink to the original author causing // a delivery fork. - if(($parent_item) && intval($parent_item['item_uplink']) && (! $top_level_post) && ($cmd !== 'uplink')) { + if (($parent_item) && intval($parent_item['item_uplink']) && (!$top_level_post) && ($cmd !== 'uplink')) { // don't uplink a relayed post to the relay owner - if($parent_item['source_xchan'] !== $parent_item['owner_xchan']) { + if ($parent_item['source_xchan'] !== $parent_item['owner_xchan']) { logger('notifier: uplinking this item'); - Master::Summon(array('Notifier','uplink',$item_id)); + Master::Summon(['Notifier', 'uplink', $item_id]); } } - $private = false; - $recipients = collect_recipients($parent_item,$private); - + $private = false; + $recipients = collect_recipients($parent_item, $private); if ($top_level_post) { // remove clones who will receive the post via sync - $recipients = array_diff($recipients, [ $target_item['owner_xchan'] ]); + $recipients = array_diff($recipients, [$target_item['owner_xchan']]); } // FIXME add any additional recipients such as mentions, etc. @@ -474,32 +466,31 @@ class Notifier { // Generic delivery section, we have an encoded item and recipients // Now start the delivery process - $x = $encoded_item; + $x = $encoded_item; $x['title'] = 'private'; - $x['body'] = 'private'; - logger('notifier: encoded item: ' . print_r($x,true), LOGGER_DATA, LOG_DEBUG); + $x['body'] = 'private'; + logger('notifier: encoded item: ' . print_r($x, true), LOGGER_DATA, LOG_DEBUG); //logger('notifier: encoded activity: ' . print_r($activity,true), LOGGER_DATA, LOG_DEBUG); stringify_array_elms($recipients); - if(! $recipients) { + if (!$recipients) { logger('no recipients'); return; } // logger('notifier: recipients: ' . print_r($recipients,true), LOGGER_NORMAL, LOG_DEBUG); - $env_recips = (($private) ? array() : null); + $env_recips = (($private) ? [] : null); - $details = q("select xchan_hash, xchan_network, xchan_addr, xchan_guid, xchan_guid_sig from xchan where xchan_hash in (" . protect_sprintf(implode(',',$recipients)) . ")"); + $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) { - foreach($details as $d) { + $recip_list = []; + if ($details) { + foreach ($details as $d) { $recip_list[] = $d['xchan_addr'] . ' (' . $d['xchan_hash'] . ')'; - if($private) { + if ($private) { $env_recips[] = [ 'guid' => $d['xchan_guid'], 'guid_sig' => $d['xchan_guid_sig'], @@ -535,8 +526,8 @@ class Notifier { ]; call_hooks('notifier_process', $narr); - if($narr['queued']) { - foreach($narr['queued'] as $pq) + if ($narr['queued']) { + foreach ($narr['queued'] as $pq) $deliveries[] = $pq; } @@ -546,26 +537,26 @@ class Notifier { $env_recips = $narr['env_recips']; $packet_recips = $narr['packet_recips']; - if(($private) && (! $env_recips)) { + if (($private) && (!$env_recips)) { // shouldn't happen - logger('notifier: private message with no envelope recipients.' . print_r($argv,true), LOGGER_NORMAL, LOG_NOTICE); + logger('notifier: private message with no envelope recipients.' . print_r($argv, true), LOGGER_NORMAL, LOG_NOTICE); } - logger('notifier: recipients (may be delivered to more if public): ' . print_r($recip_list,true), LOGGER_DEBUG); + logger('notifier: recipients (may be delivered to more if public): ' . print_r($recip_list, true), LOGGER_DEBUG); // 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. $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)) . ") + 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) { + if (!$private) { $found_localhost = false; if ($hubs) { foreach ($hubs as $h) { @@ -575,7 +566,7 @@ class Notifier { } } } - if (! $found_localhost) { + 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') @@ -586,7 +577,7 @@ class Notifier { } } - if(! $hubs) { + if (!$hubs) { logger('notifier: no hubs', LOGGER_NORMAL, LOG_NOTICE); return; } @@ -605,17 +596,17 @@ class Notifier { $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) { + 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']) { - if(! array_key_exists($hub['hubloc_host'] . $hub['hubloc_sitekey'], $hub_env)) { + if ($env_recips) { + foreach ($env_recips as $er) { + if ($hub['hubloc_hash'] === $er['hash']) { + if (!array_key_exists($hub['hubloc_host'] . $hub['hubloc_sitekey'], $hub_env)) { $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']] = []; } $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']][] = $er; @@ -624,36 +615,36 @@ class Notifier { } - if($hub['hubloc_network'] == 'zot') { - if(! in_array($hub['hubloc_sitekey'],$keys)) { + if ($hub['hubloc_network'] == 'zot') { + if (!in_array($hub['hubloc_sitekey'], $keys)) { $hublist[] = $hub['hubloc_host'] . ' ' . $hub['hubloc_network']; $dhubs[] = $hub; $keys[] = $hub['hubloc_sitekey']; } } else { - if(! in_array($hub['hubloc_url'],$urls)) { - if($hub['hubloc_url'] === z_root()) { + if (!in_array($hub['hubloc_url'], $urls)) { + if ($hub['hubloc_url'] === z_root()) { //deliver to local hub first array_unshift($hublist, $hub['hubloc_host'] . ' ' . $hub['hubloc_network']); array_unshift($dhubs, $hub); } else { $hublist[] = $hub['hubloc_host'] . ' ' . $hub['hubloc_network']; - $dhubs[] = $hub; + $dhubs[] = $hub; } $urls[] = $hub['hubloc_url']; } } } - logger('notifier: will notify/deliver to these hubs: ' . print_r($hublist,true), LOGGER_DEBUG, LOG_DEBUG); + logger('notifier: will notify/deliver to these hubs: ' . print_r($hublist, true), LOGGER_DEBUG, LOG_DEBUG); - foreach($dhubs as $hub) { + foreach ($dhubs as $hub) { - logger('notifier_hub: ' . $hub['hubloc_url'],LOGGER_DEBUG); + logger('notifier_hub: ' . $hub['hubloc_url'], LOGGER_DEBUG); - if(! in_array($hub['hubloc_network'], [ 'zot','zot6' ])) { + if (!in_array($hub['hubloc_network'], ['zot', 'zot6'])) { $narr = [ 'channel' => $channel, 'upstream' => $upstream, @@ -680,9 +671,9 @@ class Notifier { ]; - call_hooks('notifier_hub',$narr); - if($narr['queued']) { - foreach($narr['queued'] as $pq) + call_hooks('notifier_hub', $narr); + if ($narr['queued']) { + foreach ($narr['queued'] as $pq) $deliveries[] = $pq; } continue; @@ -698,11 +689,11 @@ class Notifier { // will invoke a delivery to those connections which are connected to just that // hub instance. - if($cmd === 'single_mail' || $cmd === 'single_activity') { + if ($cmd === 'single_mail' || $cmd === 'single_activity') { continue; } - if(! in_array($hub['hubloc_network'], [ 'zot','zot6' ])) { + if (!in_array($hub['hubloc_network'], ['zot', 'zot6'])) { continue; } @@ -710,31 +701,31 @@ class Notifier { // in the loop. The signature verification step can't handle dashes in the // hashes. - $hash = random_string(48); + $hash = random_string(48); $packet = null; $pmsg = ''; - if($packet_type === 'refresh' || $packet_type === 'purge') { - if($hub['hubloc_network'] === 'zot6') { - $packet = Libzot::build_packet($channel, $packet_type, ids_to_array($packet_recips,'hash')); + if ($packet_type === 'refresh' || $packet_type === 'purge') { + if ($hub['hubloc_network'] === 'zot6') { + $packet = Libzot::build_packet($channel, $packet_type, ids_to_array($packet_recips, 'hash')); } else { - $packet = zot_build_packet($channel,$packet_type,(($packet_recips) ? $packet_recips : null)); + $packet = zot_build_packet($channel, $packet_type, (($packet_recips) ? $packet_recips : null)); } } - if($packet_type === 'keychange' && $hub['hubloc_network'] === 'zot') { - $pmsg = get_pconfig($channel['channel_id'],'system','keychange'); - $packet = zot_build_packet($channel,$packet_type,(($packet_recips) ? $packet_recips : null)); + if ($packet_type === 'keychange' && $hub['hubloc_network'] === 'zot') { + $pmsg = get_pconfig($channel['channel_id'], 'system', 'keychange'); + $packet = zot_build_packet($channel, $packet_type, (($packet_recips) ? $packet_recips : null)); } - elseif($packet_type === 'request' && $hub['hubloc_network'] === 'zot') { - $env = (($hub_env && $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']]) ? $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']] : ''); - $packet = zot_build_packet($channel,$packet_type,$env,$hub['hubloc_sitekey'],$hub['site_crypto'], - $hash, array('message_id' => $request_message_id) + elseif ($packet_type === 'request' && $hub['hubloc_network'] === 'zot') { + $env = (($hub_env && $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']]) ? $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']] : ''); + $packet = zot_build_packet($channel, $packet_type, $env, $hub['hubloc_sitekey'], $hub['site_crypto'], + $hash, ['message_id' => $request_message_id] ); } - if($packet) { + if ($packet) { Queue::insert( [ 'hash' => $hash, @@ -750,11 +741,10 @@ class Notifier { else { $env = (($hub_env && $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']]) ? $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']] : ''); - - if($hub['hubloc_network'] === 'zot6') { + if ($hub['hubloc_network'] === 'zot6') { $zenv = []; - if($env) { - foreach($env as $e) { + if ($env) { + foreach ($env as $e) { $zenv[] = $e['hash']; } } @@ -767,11 +757,11 @@ class Notifier { // For public reshares, some comments to the reshare on the zot fork will not make it to zot6 // due to these different message models. This cannot be prevented at this time. - if($packet_type === 'activity' && $activity['type'] === 'Announce' && intval($target_item['item_private'])) { + if ($packet_type === 'activity' && $activity['type'] === 'Announce' && intval($target_item['item_private'])) { continue; } - $packet = Libzot::build_packet($channel,$packet_type,$zenv,$activity,'activitystreams',(($private) ? $hub['hubloc_sitekey'] : null),$hub['site_crypto']); + $packet = Libzot::build_packet($channel, $packet_type, $zenv, $activity, 'activitystreams', (($private) ? $hub['hubloc_sitekey'] : null), $hub['site_crypto']); } else { // currently zot6 delivery is only performed on normal items and not sync items or mail or anything else @@ -779,28 +769,28 @@ class Notifier { // with before switching to zot6 as the primary zot6 handler checks for the existence of a message delivery report // to trigger dequeue'ing - $z6 = (($encoded_item && $encoded_item['type'] === 'activity' && (! array_key_exists('allow_cid',$encoded_item))) ? true : false); - if($z6) { - $packet = zot6_build_packet($channel,'notify',$env, json_encode($encoded_item), (($private) ? $hub['hubloc_sitekey'] : null), $hub['site_crypto'],$hash); + $z6 = (($encoded_item && $encoded_item['type'] === 'activity' && (!array_key_exists('allow_cid', $encoded_item))) ? true : false); + if ($z6) { + $packet = zot6_build_packet($channel, 'notify', $env, json_encode($encoded_item), (($private) ? $hub['hubloc_sitekey'] : null), $hub['site_crypto'], $hash); } else { - $packet = zot_build_packet($channel,'notify',$env, (($private) ? $hub['hubloc_sitekey'] : null), $hub['site_crypto'],$hash); + $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'; + 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']['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'; + 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']); } } @@ -819,7 +809,7 @@ class Notifier { ); // only create delivery reports for normal undeleted items - if(is_array($target_item) && array_key_exists('postopts',$target_item) && (! $target_item['item_deleted']) && (! get_config('system','disable_dreport'))) { + if (is_array($target_item) && array_key_exists('postopts', $target_item) && (!$target_item['item_deleted']) && (!get_config('system', 'disable_dreport'))) { q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_result, dreport_time, dreport_xchan, dreport_queue ) values ( '%s','%s','%s','%s','%s','%s','%s' ) ", dbesc($target_item['mid']), dbesc($hub['hubloc_host']), @@ -835,21 +825,21 @@ class Notifier { $deliveries[] = $hash; } - if($normal_mode) { + if ($normal_mode) { $x = q("select * from hook where hook = 'notifier_normal'"); - if($x) { - Master::Summon( [ 'Deliver_hooks', $target_item['id'] ] ); + if ($x) { + Master::Summon(['Deliver_hooks', $target_item['id']]); } } - if($deliveries) + if ($deliveries) do_delivery($deliveries); 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'))) { + 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']), @@ -865,7 +855,7 @@ class Notifier { } } - call_hooks('notifier_end',$target_item); + call_hooks('notifier_end', $target_item); logger('notifer: complete.'); return; diff --git a/Zotlabs/Daemon/Onedirsync.php b/Zotlabs/Daemon/Onedirsync.php index a952b8117..f29fbe5b8 100644 --- a/Zotlabs/Daemon/Onedirsync.php +++ b/Zotlabs/Daemon/Onedirsync.php @@ -11,14 +11,14 @@ require_once('include/dir_fns.php'); class Onedirsync { - static public function run($argc,$argv) { + static public function run($argc, $argv) { logger('onedirsync: start ' . intval($argv[1])); - if(($argc > 1) && (intval($argv[1]))) + if (($argc > 1) && (intval($argv[1]))) $update_id = intval($argv[1]); - if(! $update_id) { + if (!$update_id) { logger('onedirsync: no update'); return; } @@ -27,9 +27,9 @@ class Onedirsync { intval($update_id) ); - if(! $r) + if (!$r) return; - if(($r[0]['ud_flags'] & UPDATE_FLAGS_UPDATED) || (! $r[0]['ud_addr'])) + if (($r[0]['ud_flags'] & UPDATE_FLAGS_UPDATED) || (!$r[0]['ud_addr'])) return; // Have we probed this channel more recently than the other directory server @@ -41,8 +41,8 @@ class Onedirsync { dbesc($r[0]['ud_date']), intval(UPDATE_FLAGS_UPDATED) ); - if($x) { - $y = q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and ( ud_flags & %d ) = 0 and ud_date != '%s'", + if ($x) { + q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and ( ud_flags & %d ) = 0 and ud_date != '%s'", intval(UPDATE_FLAGS_UPDATED), dbesc($r[0]['ud_addr']), intval(UPDATE_FLAGS_UPDATED), @@ -59,8 +59,8 @@ class Onedirsync { $h = Libzot::zot_record_preferred($h); - if(($h) && ($h['hubloc_status'] & HUBLOC_OFFLINE)) { - $y = q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and ( ud_flags & %d ) = 0 ", + if (($h) && ($h['hubloc_status'] & HUBLOC_OFFLINE)) { + q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and ( ud_flags & %d ) = 0 ", intval(UPDATE_FLAGS_UPDATED), dbesc($r[0]['ud_addr']), intval(UPDATE_FLAGS_UPDATED) @@ -72,7 +72,7 @@ class Onedirsync { // we might have to pull this out some day, but for now update_directory_entry() // runs zot_finger() and is kind of zot specific - if($h && ! in_array($h['hubloc_network'], ['zot6', 'zot'])) + if ($h && !in_array($h['hubloc_network'], ['zot6', 'zot'])) return; Libzotdir::update_directory_entry($r[0]); diff --git a/Zotlabs/Daemon/Onepoll.php b/Zotlabs/Daemon/Onepoll.php index 93a5412b0..598cf28e4 100644 --- a/Zotlabs/Daemon/Onepoll.php +++ b/Zotlabs/Daemon/Onepoll.php @@ -2,68 +2,70 @@ namespace Zotlabs\Daemon; +use Zotlabs\Lib\Activity; +use Zotlabs\Lib\ActivityStreams; +use Zotlabs\Lib\ASCollection; use Zotlabs\Lib\Libzot; -require_once('include/zot.php'); require_once('include/socgraph.php'); - class Onepoll { - static public function run($argc,$argv) { + static public function run($argc, $argv) { logger('onepoll: start'); - - if(($argc > 1) && (intval($argv[1]))) + + if (($argc > 1) && (intval($argv[1]))) $contact_id = intval($argv[1]); - if(! $contact_id) { + if (!$contact_id) { logger('onepoll: no contact'); return; } - $d = datetime_convert(); + $sql_extra = ''; + $allow_feeds = get_config('system', 'feed_contacts'); + if(!$allow_feeds) { + $sql_extra = ' and abook_feed = 0 '; + } $contacts = q("SELECT abook.*, xchan.*, account.* - FROM abook LEFT JOIN account on abook_account = account_id left join xchan on xchan_hash = abook_xchan - where abook_id = %d + FROM abook LEFT JOIN account on abook_account = account_id left join xchan on xchan_hash = abook_xchan + where abook_id = %d $sql_extra and abook_pending = 0 and abook_archived = 0 and abook_blocked = 0 and abook_ignored = 0 AND (( account_flags = %d ) OR ( account_flags = %d )) limit 1", intval($contact_id), intval(ACCOUNT_OK), intval(ACCOUNT_UNVERIFIED) - ); + ); - if(! $contacts) { + if (!$contacts) { logger('onepoll: abook_id not found: ' . $contact_id); return; } - $contact = $contacts[0]; - - $t = $contact['abook_updated']; - + $contact = array_shift($contacts); $importer_uid = $contact['abook_channel']; - + $r = q("SELECT * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1", intval($importer_uid) ); - if(! $r) + if (!$r) return; $importer = $r[0]; logger("onepoll: poll: ({$contact['id']}) IMPORTER: {$importer['xchan_name']}, CONTACT: {$contact['xchan_name']}"); - $last_update = ((($contact['abook_updated'] === $contact['abook_created']) || ($contact['abook_updated'] <= NULL_DATE)) - ? datetime_convert('UTC','UTC','now - 7 days') - : datetime_convert('UTC','UTC',$contact['abook_updated'] . ' - 2 days') + $last_update = ((($contact['abook_updated'] === $contact['abook_created']) || ($contact['abook_updated'] <= NULL_DATE)) + ? datetime_convert('UTC', 'UTC', 'now - 7 days') + : datetime_convert('UTC', 'UTC', $contact['abook_updated'] . ' - 2 days') ); - if($contact['xchan_network'] === 'rss') { + if ($contact['xchan_network'] === 'rss') { logger('onepoll: processing feed ' . $contact['xchan_name'], LOGGER_DEBUG); - $alive = handle_feed($importer['channel_id'],$contact_id,$contact['xchan_hash']); + $alive = handle_feed($importer['channel_id'], $contact_id, $contact['xchan_hash']); if ($alive) { q("update abook set abook_connected = '%s' where abook_id = %d", dbesc(datetime_convert()), @@ -72,22 +74,22 @@ class Onepoll { } return; } - - if(! in_array($contact['xchan_network'],['zot','zot6'])) + + if (!in_array($contact['xchan_network'], ['zot', 'zot6'])) return; // update permissions - if($contact['xchan_network'] === 'zot6') - $x = Libzot::refresh($contact,$importer); + if ($contact['xchan_network'] === 'zot6') + $x = Libzot::refresh($contact, $importer); - if($contact['xchan_network'] === 'zot') - $x = zot_refresh($contact,$importer); + if ($contact['xchan_network'] === 'zot') + $x = zot_refresh($contact, $importer); $responded = false; $updated = datetime_convert(); $connected = datetime_convert(); - if(! $x) { + if (!$x) { // mark for death by not updating abook_connected, this is caught in include/poller.php q("update abook set abook_updated = '%s' where abook_id = %d", dbesc($updated), @@ -103,83 +105,112 @@ class Onepoll { $responded = true; } - if(! $responded) + if (!$responded) return; - if($contact['xchan_connurl']) { - $fetch_feed = true; - $x = null; + $fetch_feed = true; + $x = null; - // They haven't given us permission to see their stream + // They haven't given us permission to see their stream - $can_view_stream = intval(get_abconfig($importer_uid,$contact['abook_xchan'],'their_perms','view_stream')); + $can_view_stream = intval(get_abconfig($importer_uid, $contact['abook_xchan'], 'their_perms', 'view_stream')); - if(! $can_view_stream) - $fetch_feed = false; + if (!$can_view_stream) + $fetch_feed = false; - // we haven't given them permission to send us their stream + // we haven't given them permission to send us their stream - $can_send_stream = intval(get_abconfig($importer_uid,$contact['abook_xchan'],'my_perms','send_stream')); - - if(! $can_send_stream) - $fetch_feed = false; + $can_send_stream = intval(get_abconfig($importer_uid, $contact['abook_xchan'], 'my_perms', 'send_stream')); - if($fetch_feed) { + if (!$can_send_stream) + $fetch_feed = false; - if(strpos($contact['xchan_connurl'],z_root()) === 0) { - // local channel - save a network fetch - $c = channelx_by_hash($contact['xchan_hash']); - if($c) { - $x = [ - 'success' => true, - 'body' => json_encode( [ - 'success' => true, - 'messages' => zot_feed($c['channel_id'], $importer['xchan_hash'], [ 'mindate' => $last_update ]) - ]) - ]; - } + if ($fetch_feed && $contact['xchan_network'] !== 'zot') { + + $max = intval(get_config('system', 'max_imported_posts', 30)); + + if (intval($max)) { + $cl = get_xconfig($contact['abook_xchan'], 'activitypub', 'collections'); + + if (is_array($cl) && $cl) { + $url = ((array_key_exists('outbox', $cl)) ? $cl['outbox'] : ''); } else { - // remote fetch - - $feedurl = str_replace('/poco/','/zotfeed/',$contact['xchan_connurl']); - $feedurl .= '?f=&mindate=' . urlencode($last_update) . '&zid=' . $importer['channel_address'] . '@' . \App::get_hostname(); - $recurse = 0; - $x = z_fetch_url($feedurl, false, $recurse, [ 'session' => true ]); + $url = str_replace('/poco/', '/zotfeed/', $contact['xchan_connurl']); } - logger('feed_update: ' . print_r($x,true), LOGGER_DATA); - } - - if(($x) && ($x['success'])) { - $total = 0; - logger('onepoll: feed update ' . $contact['xchan_name'] . ' ' . $feedurl); - - $j = json_decode($x['body'],true); - if($j['success'] && $j['messages']) { - foreach($j['messages'] as $message) { - $results = process_delivery(array('hash' => $contact['xchan_hash']), get_item_elements($message), - array(array('hash' => $importer['xchan_hash'])), false); - logger('onepoll: feed_update: process_delivery: ' . print_r($results,true), LOGGER_DATA); - $total ++; + if ($url) { + logger('fetching outbox'); + $url = $url . '?date_begin=' . urlencode($last_update); + $obj = new ASCollection($url, $importer, 0, $max); + $messages = $obj->get(); + if ($messages) { + foreach ($messages as $message) { + if (is_string($message)) { + $message = Activity::fetch($message, $importer); + } + $AS = new ActivityStreams($message); + if ($AS->is_valid() && is_array($AS->obj)) { + $item = Activity::decode_note($AS); + Activity::store($importer, $contact['abook_xchan'], $AS, $item); + } + } } - logger("onepoll: $total messages processed"); } } } - + + /* if ($fetch_feed) { + + if (strpos($contact['xchan_connurl'], z_root()) === 0) { + // local channel - save a network fetch + $c = channelx_by_hash($contact['xchan_hash']); + if ($c) { + $x = [ + 'success' => true, + 'body' => json_encode([ + 'success' => true, + 'messages' => zot_feed($c['channel_id'], $importer['xchan_hash'], ['mindate' => $last_update]) + ]) + ]; + } + } + else { + // remote fetch + + $feedurl = str_replace('/poco/', '/zotfeed/', $contact['xchan_connurl']); + $feedurl .= '?f=&mindate=' . urlencode($last_update) . '&zid=' . $importer['channel_address'] . '@' . App::get_hostname(); + $recurse = 0; + $x = z_fetch_url($feedurl, false, $recurse, ['session' => true]); + } + + logger('feed_update: ' . print_r($x, true), LOGGER_DATA); + } + + if (($x) && ($x['success'])) { + $total = 0; + logger('onepoll: feed update ' . $contact['xchan_name'] . ' ' . $feedurl); + + $j = json_decode($x['body'], true); + if ($j['success'] && $j['messages']) { + foreach ($j['messages'] as $message) { + $results = process_delivery(['hash' => $contact['xchan_hash']], get_item_elements($message), + [['hash' => $importer['xchan_hash']]], false); + logger('onepoll: feed_update: process_delivery: ' . print_r($results, true), LOGGER_DATA); + $total++; + } + logger("onepoll: $total messages processed"); + } + } + */ // update the poco details for this connection - - if($contact['xchan_connurl']) { - $r = q("SELECT xlink_id from xlink - where xlink_xchan = '%s' and xlink_updated > %s - INTERVAL %s and xlink_static = 0 limit 1", - intval($contact['xchan_hash']), - db_utcnow(), db_quoteinterval('1 DAY') - ); - if(! $r) { - poco_load($contact['xchan_hash'],$contact['xchan_connurl']); - } + $r = q("SELECT xlink_id from xlink where xlink_xchan = '%s' and xlink_updated > %s - INTERVAL %s and xlink_static = 0 limit 1", + intval($contact['xchan_hash']), + db_utcnow(), db_quoteinterval('1 DAY') + ); + if (!$r) { + poco_load($contact['xchan_hash'], $contact['xchan_connurl']); } return; diff --git a/Zotlabs/Daemon/Poller.php b/Zotlabs/Daemon/Poller.php index dfa628193..762f1349c 100644 --- a/Zotlabs/Daemon/Poller.php +++ b/Zotlabs/Daemon/Poller.php @@ -4,53 +4,50 @@ namespace Zotlabs\Daemon; class Poller { - static public function run($argc,$argv) { + static public function run($argc, $argv) { - $maxsysload = intval(get_config('system','maxloadavg')); - if($maxsysload < 1) + $maxsysload = intval(get_config('system', 'maxloadavg')); + if ($maxsysload < 1) $maxsysload = 50; - if(function_exists('sys_getloadavg')) { + if (function_exists('sys_getloadavg')) { $load = sys_getloadavg(); - if(intval($load[0]) > $maxsysload) { + if (intval($load[0]) > $maxsysload) { logger('system: load ' . $load . ' too high. Poller deferred to next scheduled run.'); return; } } - $interval = intval(get_config('system','poll_interval')); - if(! $interval) - $interval = ((get_config('system','delivery_interval') === false) ? 3 : intval(get_config('system','delivery_interval'))); + $interval = intval(get_config('system', 'poll_interval')); + if (!$interval) + $interval = ((get_config('system', 'delivery_interval') === false) ? 3 : intval(get_config('system', 'delivery_interval'))); // Check for a lockfile. If it exists, but is over an hour old, it's stale. Ignore it. $lockfile = 'store/[data]/poller'; - if((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 3600)) - && (! get_config('system','override_poll_lockfile'))) { + if ((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 3600)) + && (!get_config('system', 'override_poll_lockfile'))) { logger("poller: Already running"); return; } - + // Create a lockfile. Needs two vars, but $x doesn't need to contain anything. + $x = ''; file_put_contents($lockfile, $x); logger('poller: start'); - + $manual_id = 0; - $generation = 0; + $force = false; - $force = false; - $restart = false; - - if(($argc > 1) && ($argv[1] == 'force')) + if (($argc > 1) && ($argv[1] == 'force')) $force = true; - if(($argc > 1) && ($argv[1] == 'restart')) { - $restart = true; + if (($argc > 1) && ($argv[1] == 'restart')) { $generation = intval($argv[2]); - if(! $generation) + if (!$generation) return; } - if(($argc > 1) && intval($argv[1])) { + if (($argc > 1) && intval($argv[1])) { $manual_id = intval($argv[1]); $force = true; } @@ -59,17 +56,15 @@ class Poller { reload_plugins(); - $d = datetime_convert(); - // Only poll from those with suitable relationships - - $abandon_sql = (($abandon_days) - ? sprintf(" AND account_lastlog > %s - INTERVAL %s ", db_utcnow(), db_quoteinterval(intval($abandon_days).' DAY')) - : '' + $abandon_days = intval(get_config('system', 'account_abandon_days', 0)); + $abandon_sql = (($abandon_days) + ? sprintf(" AND account_lastlog > %s - INTERVAL %s ", db_utcnow(), db_quoteinterval(intval($abandon_days) . ' DAY')) + : '' ); $randfunc = db_getfunc('RAND'); - + $contacts = q("SELECT abook.abook_updated, abook.abook_connected, abook.abook_feed, abook.abook_channel, abook.abook_id, abook.abook_archived, abook.abook_pending, abook.abook_ignored, abook.abook_blocked, @@ -84,119 +79,117 @@ class Poller { intval(ACCOUNT_UNVERIFIED) // FIXME ); - if($contacts) { - foreach($contacts as $contact) { + if ($contacts) { + foreach ($contacts as $contact) { - $update = false; + $update = false; $t = $contact['abook_updated']; $c = $contact['abook_connected']; - if(intval($contact['abook_feed'])) { - $min = service_class_fetch($contact['abook_channel'],'minimum_feedcheck_minutes'); - if(! $min) - $min = intval(get_config('system','minimum_feedcheck_minutes')); - if(! $min) + if (intval($contact['abook_feed'])) { + $min = service_class_fetch($contact['abook_channel'], 'minimum_feedcheck_minutes'); + if (!$min) + $min = intval(get_config('system', 'minimum_feedcheck_minutes')); + if (!$min) $min = 60; - $x = datetime_convert('UTC','UTC',"now - $min minutes"); - if($c < $x) { - Master::Summon(array('Onepoll',$contact['abook_id'])); - if($interval) - @time_sleep_until(microtime(true) + (float) $interval); + $x = datetime_convert('UTC', 'UTC', "now - $min minutes"); + if ($c < $x) { + Master::Summon(['Onepoll', $contact['abook_id']]); + if ($interval) + @time_sleep_until(microtime(true) + (float)$interval); } continue; } - if(! in_array($contact['xchan_network'],['zot','zot6'])) + if (!in_array($contact['xchan_network'], ['zot', 'zot6'])) continue; - if($c == $t) { - if(datetime_convert('UTC','UTC', 'now') > datetime_convert('UTC','UTC', $t . " + 1 day")) + if ($c == $t) { + if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 1 day")) $update = true; } else { - + // if we've never connected with them, start the mark for death countdown from now - - if($c <= NULL_DATE) { - $r = q("update abook set abook_connected = '%s' where abook_id = %d", + + if ($c <= NULL_DATE) { + q("update abook set abook_connected = '%s' where abook_id = %d", dbesc(datetime_convert()), intval($contact['abook_id']) ); - $c = datetime_convert(); + $c = datetime_convert(); $update = true; } // He's dead, Jim - if(strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $c . " + 30 day")) > 0) { - $r = q("update abook set abook_archived = 1 where abook_id = %d", + if (strcmp(datetime_convert('UTC', 'UTC', 'now'), datetime_convert('UTC', 'UTC', $c . " + 30 day")) > 0) { + q("update abook set abook_archived = 1 where abook_id = %d", intval($contact['abook_id']) ); - $update = false; continue; } - if(intval($contact['abook_archived'])) { - $update = false; + if (intval($contact['abook_archived'])) { continue; } // might be dead, so maybe don't poll quite so often - + // recently deceased, so keep up the regular schedule for 3 days - - if((strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $c . " + 3 day")) > 0) - && (strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $t . " + 1 day")) > 0)) + + if ((strcmp(datetime_convert('UTC', 'UTC', 'now'), datetime_convert('UTC', 'UTC', $c . " + 3 day")) > 0) + && (strcmp(datetime_convert('UTC', 'UTC', 'now'), datetime_convert('UTC', 'UTC', $t . " + 1 day")) > 0)) $update = true; // After that back off and put them on a morphine drip - if(strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $t . " + 2 day")) > 0) { + if (strcmp(datetime_convert('UTC', 'UTC', 'now'), datetime_convert('UTC', 'UTC', $t . " + 2 day")) > 0) { $update = true; } } - if(intval($contact['abook_pending']) || intval($contact['abook_archived']) || intval($contact['abook_ignored']) || intval($contact['abook_blocked'])) + if (intval($contact['abook_pending']) || intval($contact['abook_archived']) || intval($contact['abook_ignored']) || intval($contact['abook_blocked'])) continue; - if((! $update) && (! $force)) - continue; + if ((!$update) && (!$force)) + continue; - Master::Summon(array('Onepoll',$contact['abook_id'])); - if($interval) - @time_sleep_until(microtime(true) + (float) $interval); + Master::Summon(['Onepoll', $contact['abook_id']]); + if ($interval) + @time_sleep_until(microtime(true) + (float)$interval); } } $dirmode = intval(get_config('system', 'directory_mode')); - if($dirmode == DIRECTORY_MODE_SECONDARY || $dirmode == DIRECTORY_MODE_PRIMARY) { + if ($dirmode == DIRECTORY_MODE_SECONDARY || $dirmode == DIRECTORY_MODE_PRIMARY) { $r = q("SELECT u.ud_addr, u.ud_id, u.ud_last FROM updates AS u INNER JOIN (SELECT ud_addr, max(ud_id) AS ud_id FROM updates WHERE ( ud_flags & %d ) = 0 AND ud_addr != '' AND ( ud_last <= '%s' OR ud_last > %s - INTERVAL %s ) GROUP BY ud_addr) AS s ON s.ud_id = u.ud_id ", intval(UPDATE_FLAGS_UPDATED), dbesc(NULL_DATE), db_utcnow(), db_quoteinterval('7 DAY') ); - if($r) { - foreach($r as $rr) { + if ($r) { + foreach ($r as $rr) { // If they didn't respond when we attempted before, back off to once a day // After 7 days we won't bother anymore - if($rr['ud_last'] > NULL_DATE) - if($rr['ud_last'] > datetime_convert('UTC','UTC', 'now - 1 day')) + if ($rr['ud_last'] > NULL_DATE) + if ($rr['ud_last'] > datetime_convert('UTC', 'UTC', 'now - 1 day')) continue; - Master::Summon(array('Onedirsync',$rr['ud_id'])); - if($interval) - @time_sleep_until(microtime(true) + (float) $interval); + Master::Summon(['Onedirsync', $rr['ud_id']]); + if ($interval) + @time_sleep_until(microtime(true) + (float)$interval); } } - } + } - set_config('system','lastpoll',datetime_convert()); + set_config('system', 'lastpoll', datetime_convert()); //All done - clear the lockfile diff --git a/Zotlabs/Daemon/Queue.php b/Zotlabs/Daemon/Queue.php index 814148404..36bdcfe81 100644 --- a/Zotlabs/Daemon/Queue.php +++ b/Zotlabs/Daemon/Queue.php @@ -7,12 +7,12 @@ require_once('include/zot.php'); class Queue { - static public function run($argc,$argv) { + static public function run($argc, $argv) { require_once('include/items.php'); require_once('include/bbcode.php'); - if($argc > 1) + if ($argc > 1) $queue_id = $argv[1]; else $queue_id = EMPTY_STR; @@ -25,10 +25,9 @@ class Queue { $r = q("select outq_posturl from outq where outq_created < %s - INTERVAL %s", db_utcnow(), db_quoteinterval('3 DAY') ); - if($r) { - foreach($r as $rr) { - $site_url = ''; - $h = parse_url($rr['outq_posturl']); + if ($r) { + foreach ($r as $rr) { + $h = parse_url($rr['outq_posturl']); $desturl = $h['scheme'] . '://' . $h['host'] . (($h['port']) ? ':' . $h['port'] : ''); q("update site set site_dead = 1 where site_dead = 0 and site_url = '%s' and site_update < %s - INTERVAL %s", dbesc($desturl), @@ -37,11 +36,11 @@ class Queue { } } - $r = q("DELETE FROM outq WHERE outq_created < %s - INTERVAL %s", + q("DELETE FROM outq WHERE outq_created < %s - INTERVAL %s", db_utcnow(), db_quoteinterval('3 DAY') ); - if($queue_id) { + if ($queue_id) { $r = q("SELECT * FROM outq WHERE outq_hash = '%s' LIMIT 1", dbesc($queue_id) ); @@ -54,7 +53,7 @@ class Queue { // so that we don't start off a thousand deliveries for a couple of dead hubs. // The zot driver will deliver everything destined for a single hub once contact is made (*if* contact is made). // Other drivers will have to do something different here and may need their own query. - + // Note: this requires some tweaking as new posts to long dead hubs once a day will keep them in the // "every 15 minutes" category. We probably need to prioritise them when inserted into the queue // or just prior to this query based on recent and long-term delivery history. If we have good reason to believe @@ -67,7 +66,7 @@ class Queue { db_utcnow() ); while ($r) { - foreach($r as $rv) { + foreach ($r as $rv) { queue_deliver($rv); } $r = q("SELECT *,$sqlrandfunc as rn FROM outq WHERE outq_delivered = 0 and outq_scheduled < %s order by rn limit 1", @@ -75,10 +74,10 @@ class Queue { ); } } - if(! $r) + if (!$r) return; - foreach($r as $rv) { + foreach ($r as $rv) { queue_deliver($rv); } } diff --git a/Zotlabs/Daemon/Thumbnail.php b/Zotlabs/Daemon/Thumbnail.php index e1f17c304..72034b870 100644 --- a/Zotlabs/Daemon/Thumbnail.php +++ b/Zotlabs/Daemon/Thumbnail.php @@ -5,30 +5,30 @@ namespace Zotlabs\Daemon; class Thumbnail { - static public function run($argc,$argv) { + static public function run($argc, $argv) { - if(! $argc == 2) + if (!$argc == 2) return; $c = q("select * from attach where hash = '%s' ", dbesc($argv[1]) ); - if(! $c) + if (!$c) return; $attach = $c[0]; - $preview_style = intval(get_config('system','thumbnail_security',0)); - $preview_width = intval(get_config('system','thumbnail_width',300)); - $preview_height = intval(get_config('system','thumbnail_height',300)); + $preview_style = intval(get_config('system', 'thumbnail_security', 0)); + $preview_width = intval(get_config('system', 'thumbnail_width', 300)); + $preview_height = intval(get_config('system', 'thumbnail_height', 300)); $p = [ 'attach' => $attach, 'preview_style' => $preview_style, 'preview_width' => $preview_width, 'preview_height' => $preview_height, - 'thumbnail' => null + 'thumbnail' => null ]; /** @@ -40,39 +40,39 @@ class Thumbnail { * * \e string \b thumbnail */ - call_hooks('thumbnail',$p); - if($p['thumbnail']) { + call_hooks('thumbnail', $p); + if ($p['thumbnail']) { return; } $default_controller = null; - + $files = glob('Zotlabs/Thumbs/*.php'); - if($files) { - foreach($files as $f) { - $clsname = '\\Zotlabs\\Thumbs\\' . ucfirst(basename($f,'.php')); - if(class_exists($clsname)) { + if ($files) { + foreach ($files as $f) { + $clsname = '\\Zotlabs\\Thumbs\\' . ucfirst(basename($f, '.php')); + if (class_exists($clsname)) { $x = new $clsname(); - if(method_exists($x,'Match')) { + if (method_exists($x, 'Match')) { $matched = $x->Match($attach['filetype']); - if($matched) { - $x->Thumb($attach,$preview_style,$preview_width,$preview_height); + if ($matched) { + $x->Thumb($attach, $preview_style, $preview_width, $preview_height); } } - if(method_exists($x,'MatchDefault')) { - $default_matched = $x->MatchDefault(substr($attach['filetype'],0,strpos($attach['filetype'],'/'))); - if($default_matched) { + if (method_exists($x, 'MatchDefault')) { + $default_matched = $x->MatchDefault(substr($attach['filetype'], 0, strpos($attach['filetype'], '/'))); + if ($default_matched) { $default_controller = $x; } } } } } - if(($default_controller) - && ((! file_exists(dbunescbin($attach['content']) . '.thumb')) + if (($default_controller) + && ((!file_exists(dbunescbin($attach['content']) . '.thumb')) || (filectime(dbunescbin($attach['content']) . 'thumb') < (time() - 60)))) { - $default_controller->Thumb($attach,$preview_style,$preview_width,$preview_height); + $default_controller->Thumb($attach, $preview_style, $preview_width, $preview_height); } } } diff --git a/Zotlabs/Lib/ASCollection.php b/Zotlabs/Lib/ASCollection.php new file mode 100644 index 000000000..392dd5d4e --- /dev/null +++ b/Zotlabs/Lib/ASCollection.php @@ -0,0 +1,150 @@ +get() to return an array of collection members. + */ +class ASCollection { + + private $channel = null; + private $nextpage = null; + private $limit = 0; + private $direction = 0; // 0 = forward, 1 = reverse + private $data = []; + private $history = []; + + function __construct($obj, $channel = null, $direction = 0, $limit = 0) { + + $this->channel = $channel; + $this->direction = $direction; + $this->limit = $limit; + + if (is_array($obj)) { + $data = $obj; + } + + if (is_string($obj)) { + $data = Activity::fetch($obj, $channel); + $this->history[] = $obj; + } + + if (!is_array($data)) { + return; + } + + if (!in_array($data['type'], ['Collection', 'OrderedCollection', 'OrderedCollectionPage'])) { + return false; + } + + if ($this->direction) { + if (array_key_exists('last', $data) && $data['last']) { + $this->nextpage = $data['last']; + } + } + else { + if (array_key_exists('first', $data) && $data['first']) { + $this->nextpage = $data['first']; + } + } + + if (isset($data['items']) && is_array($data['items'])) { + $this->data = (($this->direction) ? array_reverse($data['items']) : $data['items']); + } + elseif (isset($data['orderedItems']) && is_array($data['orderedItems'])) { + $this->data = (($this->direction) ? array_reverse($data['orderedItems']) : $data['orderedItems']); + } + + if ($this->limit) { + if (count($this->data) > $limit) { + $this->data = array_slice($this->data, 0, $limit); + return; + } + } + + do { + $x = $this->next(); + } while ($x); + } + + function get() { + return $this->data; + } + + function next() { + + if (!$this->nextpage) { + return false; + } + + if (is_array($this->nextpage)) { + $data = $this->nextpage; + } + + if (is_string($this->nextpage)) { + if (in_array($this->nextpage, $this->history)) { + // recursion detected + return false; + } + $data = Activity::fetch($this->nextpage, $this->channel); + $this->history[] = $this->nextpage; + } + + if (!is_array($data)) { + return false; + } + + if (!in_array($data['type'], ['CollectionPage', 'OrderedCollectionPage'])) { + return false; + } + + $this->setnext($data); + + if (isset($data['items']) && is_array($data['items'])) { + $this->data = array_merge($this->data, (($this->direction) ? array_reverse($data['items']) : $data['items'])); + } + elseif (isset($data['orderedItems']) && is_array($data['orderedItems'])) { + $this->data = array_merge($this->data, (($this->direction) ? array_reverse($data['orderedItems']) : $data['orderedItems'])); + } + + if ($this->limit) { + if (count($this->data) > $this->limit) { + $this->data = array_slice($this->data, 0, $this->limit); + $this->nextpage = false; + return true; + } + } + + return true; + } + + function setnext($data) { + if ($this->direction) { + if (array_key_exists('prev', $data) && $data['prev']) { + $this->nextpage = $data['prev']; + } + elseif (array_key_exists('first', $data) && $data['first']) { + $this->nextpage = $data['first']; + } + else { + $this->nextpage = false; + } + } + else { + if (array_key_exists('next', $data) && $data['next']) { + $this->nextpage = $data['next']; + } + elseif (array_key_exists('last', $data) && $data['last']) { + $this->nextpage = $data['last']; + } + else { + $this->nextpage = false; + } + } + logger('nextpage: ' . $this->nextpage, LOGGER_DEBUG); + } +} \ No newline at end of file diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 807216400..5fefb2979 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -2,7 +2,10 @@ namespace Zotlabs\Lib; +use App; use Zotlabs\Access\PermissionLimits; +use Zotlabs\Access\PermissionRoles; +use Zotlabs\Access\Permissions; use Zotlabs\Daemon\Master; use Zotlabs\Web\HTTPSig; @@ -13,71 +16,70 @@ class Activity { static function encode_object($x) { - - if(($x) && (! is_array($x)) && (substr(trim($x),0,1)) === '{' ) { - $x = json_decode($x,true); + if (($x) && (!is_array($x)) && (substr(trim($x), 0, 1)) === '{') { + $x = json_decode($x, true); } - if(is_array($x)) { + if (is_array($x)) { - if(array_key_exists('asld',$x)) { + if (array_key_exists('asld', $x)) { return $x['asld']; } - if($x['type'] === ACTIVITY_OBJ_PERSON) { - return self::fetch_person($x); + if ($x['type'] === ACTIVITY_OBJ_PERSON) { + return self::fetch_person($x); } - if($x['type'] === ACTIVITY_OBJ_PROFILE) { - return self::fetch_profile($x); + if ($x['type'] === ACTIVITY_OBJ_PROFILE) { + return self::fetch_profile($x); } - if(in_array($x['type'], [ ACTIVITY_OBJ_NOTE, ACTIVITY_OBJ_ARTICLE ] )) { - return self::fetch_item($x); + if (in_array($x['type'], [ACTIVITY_OBJ_NOTE, ACTIVITY_OBJ_ARTICLE])) { + return self::fetch_item($x); } - if($x['type'] === ACTIVITY_OBJ_THING) { - return self::fetch_thing($x); + if ($x['type'] === ACTIVITY_OBJ_THING) { + return self::fetch_thing($x); } - if($x['type'] === ACTIVITY_OBJ_EVENT) { - return self::fetch_event($x); + if ($x['type'] === ACTIVITY_OBJ_EVENT) { + return self::fetch_event($x); } - if($x['type'] === ACTIVITY_OBJ_PHOTO) { - return self::fetch_image($x); + if ($x['type'] === ACTIVITY_OBJ_PHOTO) { + return self::fetch_image($x); } - call_hooks('encode_object',$x); + call_hooks('encode_object', $x); } return $x; } - static function fetch($url,$channel = null) { + static function fetch($url, $channel = null) { $redirects = 0; - if(! check_siteallowed($url)) { + if (!check_siteallowed($url)) { logger('blacklisted: ' . $url); return null; } - if(! $channel) { + if (!$channel) { $channel = get_sys_channel(); } logger('fetch: ' . $url, LOGGER_DEBUG); - if(strpos($url,'x-zot:') === 0) { - $x = ZotURL::fetch($url,$channel); + if (strpos($url, 'x-zot:') === 0) { + $x = ZotURL::fetch($url, $channel); } else { $m = parse_url($url); // handle bearcaps if ($m['scheme'] === 'bear') { - $params = explode('&',$m['query']); + $params = explode('&', $m['query']); if ($params) { foreach ($params as $p) { - if (substr($p,0,2) === 'u=') { - $url = substr($p,2); + if (substr($p, 0, 2) === 'u=') { + $url = substr($p, 2); } - if (substr($p,0,2) === 't=') { - $token = substr($p,2); + if (substr($p, 0, 2) === 't=') { + $token = substr($p, 2); } } $m = parse_url($url); @@ -85,21 +87,34 @@ class Activity { } $headers = [ - 'Accept' => 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"', + 'Accept' => ActivityStreams::get_accept_header_string($channel), 'Host' => $m['host'], - 'Date' => datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T'), + 'Date' => datetime_convert('UTC', 'UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T'), '(request-target)' => 'get ' . get_request_string($url) ]; + if (isset($token)) { $headers['Authorization'] = 'Bearer ' . $token; } - $h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false); - $x = z_fetch_url($url, true, $redirects, [ 'headers' => $h ] ); + + $h = HTTPSig::create_sig($headers, $channel['channel_prvkey'], channel_url($channel), false); + $x = z_fetch_url($url, true, $redirects, ['headers' => $h]); } - if($x['success']) { - $y = json_decode($x['body'],true); - logger('returned: ' . json_encode($y,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES), LOGGER_DEBUG); + if ($x['success']) { + $m = parse_url($url); + if ($m) { + $site_url = unparse_url(['scheme' => $m['scheme'], 'host' => $m['host'], 'port' => $m['port'] ]); + q("UPDATE site SET site_update = '%s', site_dead = 0 WHERE site_url = '%s' AND site_update < %s - INTERVAL %s", + dbesc(datetime_convert()), + dbesc($site_url), + db_utcnow(), + db_quoteinterval('1 DAY') + ); + } + + $y = json_decode($x['body'], true); + logger('returned: ' . json_encode($y, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES), LOGGER_DEBUG); return json_decode($x['body'], true); } else { @@ -109,9 +124,6 @@ class Activity { return null; } - - - static function fetch_person($x) { return self::fetch_profile($x); } @@ -120,13 +132,13 @@ class Activity { $r = q("select * from xchan where xchan_url like '%s' limit 1", dbesc($x['id'] . '/%') ); - if(! $r) { + if (!$r) { $r = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($x['id']) ); - } - if(! $r) + } + if (!$r) return []; return self::encode_person($r[0]); @@ -140,7 +152,7 @@ class Activity { dbesc($x['id']) ); - if(! $r) + if (!$r) return []; $x = [ @@ -149,7 +161,7 @@ class Activity { 'name' => $r[0]['obj_term'] ]; - if($r[0]['obj_image']) + if ($r[0]['obj_image']) $x['image'] = $r[0]['obj_image']; return $x; @@ -158,7 +170,7 @@ class Activity { static function fetch_item($x) { - if (array_key_exists('source',$x)) { + if (array_key_exists('source', $x)) { // This item is already processed and encoded return $x; } @@ -166,8 +178,8 @@ class Activity { $r = q("select * from item where mid = '%s' limit 1", dbesc($x['id']) ); - if($r) { - xchan_query($r,true); + if ($r) { + xchan_query($r, true); $r = fetch_post_tags($r); if (in_array($r[0]['verb'], ['Create', 'Invite']) && $r[0]['obj_type'] === ACTIVITY_OBJ_EVENT) { $r[0]['verb'] = 'Invite'; @@ -177,22 +189,21 @@ class Activity { } } - static function fetch_image($x) { $ret = [ - 'type' => 'Image', - 'id' => $x['id'], - 'name' => $x['title'], - 'content' => bbcode($x['body'], [ 'cache' => true ]), - 'source' => [ 'mediaType' => 'text/bbcode', 'content' => $x['body'] ], - 'published' => datetime_convert('UTC','UTC',$x['created'],ATOM_TIME), - 'updated' => datetime_convert('UTC','UTC', $x['edited'],ATOM_TIME), - 'url' => [ - 'type' => 'Link', - 'mediaType' => $x['link'][0]['type'], - 'href' => $x['link'][0]['href'], - 'width' => $x['link'][0]['width'], - 'height' => $x['link'][0]['height'] + 'type' => 'Image', + 'id' => $x['id'], + 'name' => $x['title'], + 'content' => bbcode($x['body'], ['cache' => true]), + 'source' => ['mediaType' => 'text/bbcode', 'content' => $x['body']], + 'published' => datetime_convert('UTC', 'UTC', $x['created'], ATOM_TIME), + 'updated' => datetime_convert('UTC', 'UTC', $x['edited'], ATOM_TIME), + 'url' => [ + 'type' => 'Link', + 'mediaType' => $x['link'][0]['type'], + 'href' => $x['link'][0]['href'], + 'width' => $x['link'][0]['width'], + 'height' => $x['link'][0]['height'] ] ]; return $ret; @@ -202,42 +213,42 @@ class Activity { // convert old Zot event objects to ActivityStreams Event objects - if (array_key_exists('content',$x) && array_key_exists('dtstart',$x)) { + if (array_key_exists('content', $x) && array_key_exists('dtstart', $x)) { $ev = bbtoevent($x['content']); - if($ev) { + if ($ev) { - if (! $ev['timezone']) { + if (!$ev['timezone']) { $ev['timezone'] = 'UTC'; } $actor = null; - if(array_key_exists('author',$x) && array_key_exists('link',$x['author'])) { + if (array_key_exists('author', $x) && array_key_exists('link', $x['author'])) { $actor = $x['author']['link'][0]['href']; } - $y = [ + $y = [ 'type' => 'Event', 'id' => z_root() . '/event/' . $ev['event_hash'], 'name' => $ev['summary'], -// 'summary' => bbcode($ev['summary'], [ 'cache' => true ]), + // 'summary' => bbcode($ev['summary'], [ 'cache' => true ]), // RFC3339 Section 4.3 - '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,true), 'mediaType' => 'text/bbcode' ], + '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, true), 'mediaType' => 'text/bbcode'], 'actor' => $actor, ]; - if(! $ev['nofinish']) { - $y['endTime'] = (($ev['adjust']) ? datetime_convert($ev['timezone'],'UTC',$ev['dtend'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtend'],'Y-m-d\\TH:i:s-00:00')); + if (!$ev['nofinish']) { + $y['endTime'] = (($ev['adjust']) ? datetime_convert($ev['timezone'], 'UTC', $ev['dtend'], ATOM_TIME) : datetime_convert('UTC', 'UTC', $ev['dtend'], 'Y-m-d\\TH:i:s-00:00')); } - + // copy attachments from the passed object - these are already formatted for ActivityStreams - if($x['attachment']) { + if ($x['attachment']) { $y['attachment'] = $x['attachment']; } - if($actor) { + if ($actor) { return $y; } } @@ -247,52 +258,112 @@ class Activity { } - - static function encode_item_collection($items,$id,$type,$extra = null) { + static function paged_collection_init($total, $id, $type = 'OrderedCollection') { $ret = [ - 'id' => z_root() . '/' . $id, - 'type' => $type, - 'totalItems' => count($items), + 'id' => z_root() . '/' . $id, + 'type' => $type, + 'totalItems' => $total, ]; - if($extra) - $ret = array_merge($ret,$extra); - if($items) { - $x = []; - foreach($items as $i) { - $t = self::encode_activity($i); - if($t) - $x[] = $t; + $numpages = $total / App::$pager['itemspage']; + $lastpage = (($numpages > intval($numpages)) ? intval($numpages) + 1 : $numpages); + + $ret['first'] = z_root() . '/' . App::$query_string . '?page=1'; + $ret['last'] = z_root() . '/' . App::$query_string . '?page=' . $lastpage; + + return $ret; + + } + + static function encode_item_collection($items, $id, $type, $total = 0) { + + if ($total > 30) { + $ret = [ + 'id' => z_root() . '/' . $id, + 'type' => $type . 'Page', + ]; + + $numpages = $total / App::$pager['itemspage']; + $lastpage = (($numpages > intval($numpages)) ? intval($numpages) + 1 : $numpages); + $url_parts = parse_url($id); + + $ret['partOf'] = z_root() . '/' . $url_parts['path']; + + $extra_query_args = ''; + $query_args = null; + if(isset($url_parts['query'])) { + parse_str($url_parts['query'], $query_args); } - if($type === 'OrderedCollection') + + if(is_array($query_args)) { + unset($query_args['page']); + foreach($query_args as $k => $v) + $extra_query_args .= '&' . urlencode($k) . '=' . urlencode($v); + } + + if (App::$pager['page'] < $lastpage) { + $ret['next'] = z_root() . '/' . $url_parts['path'] . '?page=' . (intval(App::$pager['page']) + 1) . $extra_query_args; + } + if (App::$pager['page'] > 1) { + $ret['prev'] = z_root() . '/' . $url_parts['path'] . '?page=' . (intval(App::$pager['page']) - 1) . $extra_query_args; + } + } + else { + $ret = [ + 'id' => z_root() . '/' . $id, + 'type' => $type, + 'totalItems' => $total, + ]; + } + + if ($items) { + $x = []; + foreach ($items as $i) { + $m = get_iconfig($i['id'], 'activitypub', 'rawmsg'); + if ($m) { + if (is_string($m)) + $t = json_decode($m, true); + else + $t = $m; + } + else { + $t = self::encode_activity($i); + } + if ($t) { + $x[] = $t; + } + } + if ($type === 'OrderedCollection') { $ret['orderedItems'] = $x; - else + } + else { $ret['items'] = $x; + } } return $ret; } - static function encode_follow_collection($items,$id,$type,$extra = null) { + static function encode_follow_collection($items, $id, $type, $extra = null) { $ret = [ - 'id' => z_root() . '/' . $id, - 'type' => $type, + 'id' => z_root() . '/' . $id, + 'type' => $type, 'totalItems' => count($items), ]; - if($extra) - $ret = array_merge($ret,$extra); + if ($extra) + $ret = array_merge($ret, $extra); - if($items) { + if ($items) { $x = []; - foreach($items as $i) { - if($i['xchan_url']) { + foreach ($items as $i) { + if ($i['xchan_url']) { $x[] = $i['xchan_url']; } } - if($type === 'OrderedCollection') + if ($type === 'OrderedCollection') $ret['orderedItems'] = $x; else $ret['items'] = $x; @@ -301,18 +372,15 @@ class Activity { return $ret; } - - - static function encode_item($i) { $ret = []; - if($i['verb'] === ACTIVITY_FRIEND) { + if ($i['verb'] === ACTIVITY_FRIEND) { // Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note $objtype = 'Note'; } - else { + else { $objtype = self::activity_obj_mapper($i['obj_type']); } @@ -321,13 +389,13 @@ class Activity { } if (intval($i['item_deleted'])) { - $ret['type'] = 'Tombstone'; + $ret['type'] = 'Tombstone'; $ret['formerType'] = $objtype; - $ret['id'] = $i['mid']; - if($i['id'] != $i['parent']) + $ret['id'] = $i['mid']; + if ($i['id'] != $i['parent']) $ret['inReplyTo'] = $i['thr_parent']; - $ret['to'] = [ ACTIVITY_PUBLIC_INBOX ]; + $ret['to'] = [ACTIVITY_PUBLIC_INBOX]; return $ret; } @@ -336,7 +404,7 @@ class Activity { $ret = $i['obj']; } else { - $ret = json_decode($i['obj'],true); + $ret = json_decode($i['obj'], true); } } @@ -348,96 +416,95 @@ class Activity { $ret = $i['obj']; } else { - $ret = json_decode($i['obj'],true); + $ret = json_decode($i['obj'], true); } - - if(array_path_exists('actor/id',$ret)) { + + 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['id'] = ((strpos($i['mid'], 'http') === 0) ? $i['mid'] : z_root() . '/item/' . urlencode($i['mid'])); $ret['diaspora:guid'] = $i['uuid']; - if($i['title']) + if ($i['title']) $ret['name'] = $i['title']; - $ret['published'] = datetime_convert('UTC','UTC',$i['created'],ATOM_TIME); - if($i['created'] !== $i['edited']) - $ret['updated'] = datetime_convert('UTC','UTC',$i['edited'],ATOM_TIME); - if ($i['expires'] <= NULL_DATE) { - $ret['expires'] = datetime_convert('UTC','UTC',$i['expires'],ATOM_TIME); + $ret['published'] = datetime_convert('UTC', 'UTC', $i['created'], ATOM_TIME); + if ($i['created'] !== $i['edited']) + $ret['updated'] = datetime_convert('UTC', 'UTC', $i['edited'], ATOM_TIME); + if ($i['expires'] > NULL_DATE) { + $ret['expires'] = datetime_convert('UTC', 'UTC', $i['expires'], ATOM_TIME); } - if($i['app']) { - $ret['generator'] = [ 'type' => 'Application', 'name' => $i['app'] ]; + if ($i['app']) { + $ret['generator'] = ['type' => 'Application', 'name' => $i['app']]; } - if($i['location'] || $i['coord']) { - $ret['location'] = [ 'type' => 'Place' ]; - if($i['location']) { + if ($i['location'] || $i['coord']) { + $ret['location'] = ['type' => 'Place']; + if ($i['location']) { $ret['location']['name'] = $i['location']; } - if($i['coord']) { - $l = explode(' ',$i['coord']); - $ret['location']['latitude'] = $l[0]; + if ($i['coord']) { + $l = explode(' ', $i['coord']); + $ret['location']['latitude'] = $l[0]; $ret['location']['longitude'] = $l[1]; } } if (intval($i['item_wall']) && $i['mid'] === $i['parent_mid']) { - $ret['commentPolicy'] = map_scope(PermissionLimits::Get($i['uid'],'post_comments')); + $ret['commentPolicy'] = map_scope(PermissionLimits::Get($i['uid'], 'post_comments')); } if (intval($i['item_private']) === 2) { $ret['directMessage'] = true; } - if (array_key_exists('comments_closed',$i) && $i['comments_closed'] !== EMPTY_STR && $i['comments_closed'] !== NULL_DATE) { - if($ret['commentPolicy']) { + if (array_key_exists('comments_closed', $i) && $i['comments_closed'] !== EMPTY_STR && $i['comments_closed'] > NULL_DATE) { + if ($ret['commentPolicy']) { $ret['commentPolicy'] .= ' '; } - $ret['commentPolicy'] .= 'until=' . datetime_convert('UTC','UTC',$i['comments_closed'],ATOM_TIME); + $ret['commentPolicy'] .= 'until=' . datetime_convert('UTC', 'UTC', $i['comments_closed'], ATOM_TIME); } $ret['attributedTo'] = $i['author']['xchan_url']; - if($i['id'] != $i['parent']) { - $ret['inReplyTo'] = ((strpos($i['thr_parent'],'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent'])); + if ($i['id'] != $i['parent']) { + $ret['inReplyTo'] = ((strpos($i['thr_parent'], 'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent'])); } - if($i['mimetype'] === 'text/bbcode') { - if($i['title']) - $ret['name'] = bbcode($i['title'], [ 'cache' => true ]); - if($i['summary']) - $ret['summary'] = bbcode($i['summary'], [ 'cache' => true ]); - $ret['content'] = bbcode($i['body'], [ 'cache' => true ]); - $ret['source'] = [ 'content' => $i['body'], 'mediaType' => 'text/bbcode' ]; + if ($i['mimetype'] === 'text/bbcode') { + if ($i['title']) + $ret['name'] = bbcode($i['title'], ['cache' => true]); + if ($i['summary']) + $ret['summary'] = bbcode($i['summary'], ['cache' => true]); + $ret['content'] = bbcode($i['body'], ['cache' => true]); + $ret['source'] = ['content' => $i['body'], 'mediaType' => 'text/bbcode']; } - $actor = self::encode_person($i['author'],false); - if($actor) + $actor = self::encode_person($i['author'], false); + if ($actor) $ret['actor'] = $actor; else return []; $t = self::encode_taxonomy($i); - if($t) { - $ret['tag'] = $t; + if ($t) { + $ret['tag'] = $t; } $a = self::encode_attachment($i); - if($a) { + if ($a) { $ret['attachment'] = $a; } - $public = (($i['item_private']) ? false : true); + $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'],'@')) ]; + $ret['to'] = [ACTIVITY_PUBLIC_INBOX]; + $ret['cc'] = [z_root() . '/followers/' . substr($i['author']['xchan_addr'], 0, strpos($i['author']['xchan_addr'], '@'))]; } else { @@ -450,7 +517,7 @@ class Activity { $ret['to'] = []; if ($ret['tag']) { foreach ($ret['tag'] as $mention) { - if (is_array($mention) && array_key_exists('href',$mention) && $mention['href']) { + 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']) ); @@ -461,7 +528,7 @@ class Activity { else { $addr = $h[0]['hubloc_id_url']; } - if (! in_array($addr,$ret['to'])) { + if (!in_array($addr, $ret['to'])) { $ret['to'][] = $addr; } } @@ -478,7 +545,7 @@ class Activity { else { $addr = $d[0]['hubloc_id_url']; } - if (! in_array($addr,$ret['to'])) { + if (!in_array($addr, $ret['to'])) { $ret['cc'][] = $addr; } } @@ -487,7 +554,7 @@ class Activity { $mentions = self::map_mentions($i); if (count($mentions) > 0) { - if (! $ret['to']) { + if (!$ret['to']) { $ret['to'] = $mentions; } else { @@ -505,25 +572,25 @@ class Activity { if ($item['tag'] && is_array($item['tag'])) { $ptr = $item['tag']; - if (! array_key_exists(0,$ptr)) { - $ptr = [ $ptr ]; + if (!array_key_exists(0, $ptr)) { + $ptr = [$ptr]; } foreach ($ptr as $t) { - if (! array_key_exists('type',$t)) + if (!array_key_exists('type', $t)) $t['type'] = 'Hashtag'; - switch($t['type']) { + switch ($t['type']) { case 'Hashtag': - $ret[] = [ 'ttype' => TERM_HASHTAG, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'],0,1) === '#') ? substr($t['name'],1) : $t['name']) ]; + $ret[] = ['ttype' => TERM_HASHTAG, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'], 0, 1) === '#') ? substr($t['name'], 1) : $t['name'])]; break; case 'Mention': - $mention_type = substr($t['name'],0,1); + $mention_type = substr($t['name'], 0, 1); if ($mention_type === '!') { - $ret[] = [ 'ttype' => TERM_FORUM, 'url' => $t['href'], 'term' => escape_tags(substr($t['name'],1)) ]; + $ret[] = ['ttype' => TERM_FORUM, 'url' => $t['href'], 'term' => escape_tags(substr($t['name'], 1))]; } else { - $ret[] = [ 'ttype' => TERM_MENTION, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'],0,1) === '@') ? substr($t['name'],1) : $t['name']) ]; + $ret[] = ['ttype' => TERM_MENTION, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'], 0, 1) === '@') ? substr($t['name'], 1) : $t['name'])]; } break; @@ -536,30 +603,28 @@ class Activity { return $ret; } - - static function encode_taxonomy($item) { $ret = []; - if($item['term']) { - foreach($item['term'] as $t) { - switch($t['ttype']) { + if ($item['term']) { + foreach ($item['term'] as $t) { + switch ($t['ttype']) { case TERM_HASHTAG: // href is required so if we don't have a url in the taxonomy, ignore it and keep going. - if($t['url']) { - $ret[] = [ 'type' => 'Hashtag', 'href' => $t['url'], 'name' => '#' . $t['term'] ]; + if ($t['url']) { + $ret[] = ['type' => 'Hashtag', 'href' => $t['url'], 'name' => '#' . $t['term']]; } break; case TERM_FORUM: - $ret[] = [ 'type' => 'Mention', 'href' => $t['url'], 'name' => '!' . $t['term'] ]; + $ret[] = ['type' => 'Mention', 'href' => $t['url'], 'name' => '!' . $t['term']]; break; case TERM_MENTION: - $ret[] = [ 'type' => 'Mention', 'href' => $t['url'], 'name' => '@' . $t['term'] ]; + $ret[] = ['type' => 'Mention', 'href' => $t['url'], 'name' => '@' . $t['term']]; break; - + default: break; } @@ -573,15 +638,15 @@ class Activity { $ret = []; - if($item['attach']) { - $atts = ((is_array($item['attach'])) ? $item['attach'] : json_decode($item['attach'],true)); - if($atts) { - foreach($atts as $att) { - if(strpos($att['type'],'image')) { - $ret[] = [ 'type' => 'Image', 'url' => $att['href'] ]; + if ($item['attach']) { + $atts = ((is_array($item['attach'])) ? $item['attach'] : json_decode($item['attach'], true)); + if ($atts) { + foreach ($atts as $att) { + if (strpos($att['type'], 'image')) { + $ret[] = ['type' => 'Image', 'url' => $att['href']]; } else { - $ret[] = [ 'type' => 'Link', 'mediaType' => $att['type'], 'href' => $att['href'] ]; + $ret[] = ['type' => 'Link', 'mediaType' => $att['type'], 'href' => $att['href']]; } } } @@ -590,11 +655,11 @@ class Activity { 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 ]; + $ret[] = ['type' => 'PropertyValue', 'name' => 'zot.' . $att['cat'] . '.' . $att['k'], 'value' => $value]; } } } - + return $ret; } @@ -604,20 +669,20 @@ class Activity { if (is_array($item['attachment']) && $item['attachment']) { $ptr = $item['attachment']; - if (! array_key_exists(0,$ptr)) { - $ptr = [ $ptr ]; + 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 (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['cat'] = $key[1]; + $entry['k'] = $key[2]; + $entry['v'] = $att['value']; $entry['sharing'] = '1'; - $ret[] = $entry; + $ret[] = $entry; } } } @@ -626,24 +691,22 @@ class Activity { return $ret; } - - static function decode_attachment($item) { $ret = []; - if($item['attachment']) { - foreach($item['attachment'] as $att) { + if ($item['attachment']) { + foreach ($item['attachment'] as $att) { $entry = []; - if($att['href']) + if ($att['href']) $entry['href'] = $att['href']; - elseif($att['url']) + elseif ($att['url']) $entry['href'] = $att['url']; - if($att['mediaType']) + if ($att['mediaType']) $entry['type'] = $att['mediaType']; - elseif($att['type'] === 'Image') + elseif ($att['type'] === 'Image') $entry['type'] = 'image/jpeg'; - if($entry) + if ($entry) $ret[] = $entry; } } @@ -651,211 +714,187 @@ class Activity { return $ret; } - - static function encode_activity($i, $recurse = false) { $ret = []; $reply = false; - if($i['verb'] === ACTIVITY_FRIEND) { + if ($i['verb'] === ACTIVITY_FRIEND) { // Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note $ret['obj'] = []; } $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'; + $fragment = 'undo'; $is_response = true; } else { $ret['type'] = 'Delete'; - $fragment = 'delete'; + $fragment = 'delete'; } - $ret['id'] = str_replace('/item/','/activity/',$i['mid']) . '#' . $fragment; - $actor = self::encode_person($i['author'],false); + $ret['id'] = str_replace('/item/', '/activity/', $i['mid']) . '#' . $fragment; + $actor = self::encode_person($i['author'], false); if ($actor) $ret['actor'] = $actor; else - return []; + return []; - $obj = (($is_response) ? self::encode_activity($i,true) : self::encode_item($i,true)); + $obj = (($is_response) ? self::encode_activity($i, true) : self::encode_item($i)); if ($obj) { - if (array_path_exists('object/id',$obj)) { + if (array_path_exists('object/id', $obj)) { $obj['object'] = $obj['object']['id']; } unset($obj['cc']); - $obj['to'] = [ ACTIVITY_PUBLIC_INBOX ]; + $obj['to'] = [ACTIVITY_PUBLIC_INBOX]; $ret['object'] = $obj; } else return []; - $ret['to'] = [ ACTIVITY_PUBLIC_INBOX ]; + $ret['to'] = [ACTIVITY_PUBLIC_INBOX]; return $ret; } - if($ret['type'] === 'emojiReaction') { + if ($ret['type'] === 'emojiReaction') { // There may not be an object for these items for legacy reasons - it should be the conversation parent. $p = q("select * from item where mid = '%s' and uid = %d", dbesc($i['parent_mid']), intval($i['uid']) ); - if($p) { - xchan_query($p,true); - $p = fetch_post_tags($p); + if ($p) { + xchan_query($p, true); + $p = fetch_post_tags($p); $i['obj'] = self::encode_item($p[0]); // convert to zot6 emoji reaction encoding which uses the target object to indicate the // specific emoji instead of overloading the verb or type. - - $im = explode('#',$i['verb']); - if($im && count($im) > 1) + + $im = explode('#', $i['verb']); + if ($im && count($im) > 1) $emoji = $im[1]; - if(preg_match("/\[img(.*?)\](.*?)\[\/img\]/ism", $i['body'], $match)) { + if (preg_match("/\[img(.*?)\](.*?)\[\/img\]/ism", $i['body'], $match)) { $ln = $match[2]; } $i['tgt_type'] = 'Image'; - + $i['target'] = [ 'type' => 'Image', 'name' => $emoji, 'url' => (($ln) ? $ln : z_root() . '/images/emoji/' . $emoji . '.png') ]; - + } } - if (strpos($i['mid'],z_root() . '/item/') !== false) { - $ret['id'] = str_replace('/item/','/activity/',$i['mid']); + 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']); + 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 ])); + if ($i['title']) + $ret['name'] = html2plain(bbcode($i['title'], ['cache' => true])); - if($i['summary']) - $ret['summary'] = bbcode($i['summary'], [ 'cache' => true ]); + if ($i['summary']) + $ret['summary'] = bbcode($i['summary'], ['cache' => true]); - if($ret['type'] === 'Announce') { - $tmp = preg_replace('/\[share(.*?)\[\/share\]/ism',EMPTY_STR, $i['body']); - $ret['content'] = bbcode($tmp, [ 'cache' => true ]); - $ret['source'] = [ - 'content' => $i['body'], + if ($ret['type'] === 'Announce') { + $tmp = preg_replace('/\[share(.*?)\[\/share\]/ism', EMPTY_STR, $i['body']); + $ret['content'] = bbcode($tmp, ['cache' => true]); + $ret['source'] = [ + 'content' => $i['body'], 'mediaType' => 'text/bbcode' ]; } - $ret['published'] = datetime_convert('UTC','UTC',$i['created'],ATOM_TIME); - if($i['created'] !== $i['edited']) - $ret['updated'] = datetime_convert('UTC','UTC',$i['edited'],ATOM_TIME); - if($i['app']) { - $ret['generator'] = [ 'type' => 'Application', 'name' => $i['app'] ]; + $ret['published'] = datetime_convert('UTC', 'UTC', $i['created'], ATOM_TIME); + if ($i['created'] !== $i['edited']) + $ret['updated'] = datetime_convert('UTC', 'UTC', $i['edited'], ATOM_TIME); + if ($i['app']) { + $ret['generator'] = ['type' => 'Application', 'name' => $i['app']]; } - if($i['location'] || $i['coord']) { - $ret['location'] = [ 'type' => 'Place' ]; - if($i['location']) { + if ($i['location'] || $i['coord']) { + $ret['location'] = ['type' => 'Place']; + if ($i['location']) { $ret['location']['name'] = $i['location']; } - if($i['coord']) { - $l = explode(' ',$i['coord']); - $ret['location']['latitude'] = $l[0]; + if ($i['coord']) { + $l = explode(' ', $i['coord']); + $ret['location']['latitude'] = $l[0]; $ret['location']['longitude'] = $l[1]; } } - if($i['id'] != $i['parent']) { + if ($i['id'] != $i['parent']) { $reply = true; // 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'])); + + 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'])); } - - if($i['item_private']) { - $d = q("select xchan_url, xchan_addr, xchan_name from item left join xchan on xchan_hash = author_xchan where id = %d limit 1", - intval($i['parent']) - ); - if($d) { - $is_directmessage = false; - $recips = get_iconfig($i['parent'], 'activitypub', 'recips'); - - if(array_path_exists('to', $recips) && in_array($i['author']['xchan_url'], $recips['to'])) { - $reply_url = $d[0]['xchan_url']; - $is_directmessage = true; - } - else { - $reply_url = z_root() . '/followers/' . substr($i['author']['xchan_addr'],0,strpos($i['author']['xchan_addr'],'@')); - } - - $reply_addr = (($d[0]['xchan_addr']) ? $d[0]['xchan_addr'] : $d[0]['xchan_name']); - } - } - } - $actor = self::encode_person($i['author'],false); - if($actor) + $actor = self::encode_person($i['author'], false); + if ($actor) $ret['actor'] = $actor; else - return []; + return []; - if(strpos($i['body'],'[/share]') !== false) { + if (strpos($i['body'], '[/share]') !== false) { $i['obj'] = null; } - if($i['obj']) { - if(! is_array($i['obj'])) { - $i['obj'] = json_decode($i['obj'],true); + if ($i['obj']) { + if (!is_array($i['obj'])) { + $i['obj'] = json_decode($i['obj'], true); } - if($i['obj']['type'] === ACTIVITY_OBJ_PHOTO) { + if ($i['obj']['type'] === ACTIVITY_OBJ_PHOTO) { $i['obj']['id'] = $i['mid']; } $obj = self::encode_object($i['obj']); - if($obj) + if ($obj) $ret['object'] = $obj; else return []; } else { $obj = self::encode_item($i); - if($obj) + if ($obj) $ret['object'] = $obj; else return []; } - if(array_path_exists('object/type',$ret) && $ret['object']['type'] === 'Event' && $ret['type'] === 'Create') { + 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'])) { - $i['target'] = json_decode($i['target'],true); + if ($i['target']) { + if (!is_array($i['target'])) { + $i['target'] = json_decode($i['target'], true); } $tgt = self::encode_object($i['target']); - if($tgt) + if ($tgt) $ret['target'] = $tgt; else return []; @@ -868,12 +907,12 @@ class Activity { // addressing madness - $public = (($i['item_private']) ? false : true); + $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'],'@')) ]; + $ret['to'] = [ACTIVITY_PUBLIC_INBOX]; + $ret['cc'] = [z_root() . '/followers/' . substr($i['author']['xchan_addr'], 0, strpos($i['author']['xchan_addr'], '@'))]; } else { @@ -886,7 +925,7 @@ class Activity { $ret['to'] = []; if ($ret['tag']) { foreach ($ret['tag'] as $mention) { - if (is_array($mention) && array_key_exists('href',$mention) && $mention['href']) { + 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']) ); @@ -897,7 +936,7 @@ class Activity { else { $addr = $h[0]['hubloc_id_url']; } - if (! in_array($addr,$ret['to'])) { + if (!in_array($addr, $ret['to'])) { $ret['to'][] = $addr; } } @@ -915,7 +954,7 @@ class Activity { else { $addr = $d[0]['hubloc_id_url']; } - if (! in_array($addr,$ret['to'])) { + if (!in_array($addr, $ret['to'])) { $ret['cc'][] = $addr; } } @@ -924,7 +963,7 @@ class Activity { $mentions = self::map_mentions($i); if (count($mentions) > 0) { - if (! $ret['to']) { + if (!$ret['to']) { $ret['to'] = $mentions; } else { @@ -936,21 +975,20 @@ class Activity { } // 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['url']) { + if (!$t['url']) { continue; } if ($t['ttype'] == TERM_MENTION) { - $url = self::lookup_term_url($t['url']); + $url = self::lookup_term_url($t['url']); $list[] = (($url) ? $url : $t['url']); } } @@ -959,11 +997,10 @@ class Activity { } // Returns an array of all recipients targeted by private item array $i. - static function map_acl($i) { $ret = []; - if (! $i['item_private']) { + if (!$i['item_private']) { return $ret; } @@ -977,8 +1014,8 @@ class Activity { } if ($i['allow_cid']) { - $tmp = expand_acl($i['allow_cid']); - $list = stringify_array($tmp,true); + $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) { @@ -1013,22 +1050,22 @@ class Activity { static function encode_person($p, $extended = true) { - if(! $p['xchan_url']) + if (!$p['xchan_url']) return []; - if(! $extended) { + if (!$extended) { return $p['xchan_url']; } $ret = []; - $c = ((array_key_exists('channel_id',$p)) ? $p : channelx_by_hash($p['xchan_hash'])); + $c = ((array_key_exists('channel_id', $p)) ? $p : channelx_by_hash($p['xchan_hash'])); - $ret['type'] = 'Person'; + $ret['type'] = 'Person'; if ($c) { - $role = get_pconfig($c['channel_id'],'system','permissions_role'); - if (strpos($role,'forum') !== false) { + $role = get_pconfig($c['channel_id'], 'system', 'permissions_role'); + if (strpos($role, 'forum') !== false) { $ret['type'] = 'Group'; } } @@ -1037,23 +1074,24 @@ class Activity { $ret['id'] = channel_url($c); } else { - $ret['id'] = ((strpos($p['xchan_hash'],'http') === 0) ? $p['xchan_hash'] : $p['xchan_url']); + $ret['id'] = ((strpos($p['xchan_hash'], 'http') === 0) ? $p['xchan_hash'] : $p['xchan_url']); } - if($p['xchan_addr'] && strpos($p['xchan_addr'],'@')) - $ret['preferredUsername'] = substr($p['xchan_addr'],0,strpos($p['xchan_addr'],'@')); - $ret['name'] = $p['xchan_name']; - $ret['updated'] = datetime_convert('UTC','UTC',$p['xchan_name_date'],ATOM_TIME); - $ret['icon'] = [ + if ($p['xchan_addr'] && strpos($p['xchan_addr'], '@')) + $ret['preferredUsername'] = substr($p['xchan_addr'], 0, strpos($p['xchan_addr'], '@')); + + $ret['name'] = $p['xchan_name']; + $ret['updated'] = datetime_convert('UTC', 'UTC', $p['xchan_name_date'], ATOM_TIME); + $ret['icon'] = [ 'type' => 'Image', - 'mediaType' => (($p['xchan_photo_mimetype']) ? $p['xchan_photo_mimetype'] : 'image/png' ), - 'updated' => datetime_convert('UTC','UTC',$p['xchan_photo_date'],ATOM_TIME), + 'mediaType' => (($p['xchan_photo_mimetype']) ? $p['xchan_photo_mimetype'] : 'image/png'), + 'updated' => datetime_convert('UTC', 'UTC', $p['xchan_photo_date'], ATOM_TIME), 'url' => $p['xchan_photo_l'], 'height' => 300, 'width' => 300, ]; - $ret['url'] = [ - [ + $ret['url'] = [ + [ 'type' => 'Link', 'mediaType' => 'text/html', 'href' => $p['xchan_url'] @@ -1071,98 +1109,120 @@ class Activity { 'publicKeyPem' => $p['xchan_pubkey'] ]; - $arr = [ 'xchan' => $p, 'encoded' => $ret ]; + $arr = [ + 'xchan' => $p, + 'encoded' => $ret + ]; + call_hooks('encode_person', $arr); $ret = $arr['encoded']; - return $ret; } + static function encode_item_object($item, $elm = 'obj') { + $ret = []; + + if ($item[$elm]) { + if (! is_array($item[$elm])) { + $item[$elm] = json_decode($item[$elm],true); + } + if ($item[$elm]['type'] === ACTIVITY_OBJ_PHOTO) { + $item[$elm]['id'] = $item['mid']; + } + $obj = self::encode_object($item[$elm]); + if ($obj) + return $obj; + else + return []; + } + else { + $obj = self::encode_item($item); + if ($obj) + return $obj; + else + return []; + } - - - + } static function activity_mapper($verb) { - if(strpos($verb,'/') === false) { + if (strpos($verb, '/') === false) { return $verb; } $acts = [ - 'http://activitystrea.ms/schema/1.0/post' => 'Create', - 'http://activitystrea.ms/schema/1.0/share' => 'Announce', - 'http://activitystrea.ms/schema/1.0/update' => 'Update', - 'http://activitystrea.ms/schema/1.0/like' => 'Like', - 'http://activitystrea.ms/schema/1.0/favorite' => 'Like', - 'http://purl.org/zot/activity/dislike' => 'Dislike', - 'http://activitystrea.ms/schema/1.0/tag' => 'Add', - 'http://activitystrea.ms/schema/1.0/follow' => 'Follow', - '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', - 'Invite' => 'Invite', - 'Delete' => 'Delete', - 'Undo' => 'Undo' + 'http://activitystrea.ms/schema/1.0/post' => 'Create', + 'http://activitystrea.ms/schema/1.0/share' => 'Announce', + 'http://activitystrea.ms/schema/1.0/update' => 'Update', + 'http://activitystrea.ms/schema/1.0/like' => 'Like', + 'http://activitystrea.ms/schema/1.0/favorite' => 'Like', + 'http://purl.org/zot/activity/dislike' => 'Dislike', + 'http://activitystrea.ms/schema/1.0/tag' => 'Add', + 'http://activitystrea.ms/schema/1.0/follow' => 'Follow', + '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', + 'Invite' => 'Invite', + 'Delete' => 'Delete', + 'Undo' => 'Undo' ]; - call_hooks('activity_mapper',$acts); + call_hooks('activity_mapper', $acts); - if(array_key_exists($verb,$acts) && $acts[$verb]) { + if (array_key_exists($verb, $acts) && $acts[$verb]) { return $acts[$verb]; } // Reactions will just map to normal activities - if(strpos($verb,ACTIVITY_REACT) !== false) + if (strpos($verb, ACTIVITY_REACT) !== false) return 'emojiReaction'; - if(strpos($verb,ACTIVITY_MOOD) !== false) + if (strpos($verb, ACTIVITY_MOOD) !== false) return 'Create'; - if(strpos($verb,ACTIVITY_FRIEND) !== false) + if (strpos($verb, ACTIVITY_FRIEND) !== false) return 'Create'; - if(strpos($verb,ACTIVITY_POKE) !== false) + if (strpos($verb, ACTIVITY_POKE) !== false) return 'Activity'; - // We should return false, however this will trigger an uncaught execption and crash + // We should return false, however this will trigger an uncaught execption and crash // the delivery system if encountered by the JSON-LDSignature library - + logger('Unmapped activity: ' . $verb); return 'Create'; - // return false; -} - - + // return false; + } static function activity_decode_mapper($verb) { $acts = [ - 'http://activitystrea.ms/schema/1.0/post' => 'Create', - 'http://activitystrea.ms/schema/1.0/share' => 'Announce', - 'http://activitystrea.ms/schema/1.0/update' => 'Update', - 'http://activitystrea.ms/schema/1.0/like' => 'Like', - 'http://activitystrea.ms/schema/1.0/favorite' => 'Like', - 'http://purl.org/zot/activity/dislike' => 'Dislike', - 'http://activitystrea.ms/schema/1.0/tag' => 'Add', - 'http://activitystrea.ms/schema/1.0/follow' => 'Follow', - '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', - 'Invite' => 'Invite', - 'Delete' => 'Delete', - 'Undo' => 'Undo' + 'http://activitystrea.ms/schema/1.0/post' => 'Create', + 'http://activitystrea.ms/schema/1.0/share' => 'Announce', + 'http://activitystrea.ms/schema/1.0/update' => 'Update', + 'http://activitystrea.ms/schema/1.0/like' => 'Like', + 'http://activitystrea.ms/schema/1.0/favorite' => 'Like', + 'http://purl.org/zot/activity/dislike' => 'Dislike', + 'http://activitystrea.ms/schema/1.0/tag' => 'Add', + 'http://activitystrea.ms/schema/1.0/follow' => 'Follow', + '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', + 'Invite' => 'Invite', + 'Delete' => 'Delete', + 'Undo' => 'Undo' ]; - call_hooks('activity_decode_mapper',$acts); + call_hooks('activity_decode_mapper', $acts); - foreach($acts as $k => $v) { - if($verb === $v) { + foreach ($acts as $k => $v) { + if ($verb === $v) { return $k; } } @@ -1175,33 +1235,33 @@ class Activity { static function activity_obj_decode_mapper($obj) { $objs = [ - 'http://activitystrea.ms/schema/1.0/note' => 'Note', - 'http://activitystrea.ms/schema/1.0/note' => 'Article', - 'http://activitystrea.ms/schema/1.0/comment' => 'Note', - 'http://activitystrea.ms/schema/1.0/person' => 'Person', - 'http://purl.org/zot/activity/profile' => 'Profile', - '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://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' + 'http://activitystrea.ms/schema/1.0/note' => 'Note', + 'http://activitystrea.ms/schema/1.0/note' => 'Article', + 'http://activitystrea.ms/schema/1.0/comment' => 'Note', + 'http://activitystrea.ms/schema/1.0/person' => 'Person', + 'http://purl.org/zot/activity/profile' => 'Profile', + '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://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); + call_hooks('activity_obj_decode_mapper', $objs); - foreach($objs as $k => $v) { - if($obj === $v) { + foreach ($objs as $k => $v) { + if ($obj === $v) { return $k; } } @@ -1210,45 +1270,42 @@ class Activity { return 'Note'; } - - - static function activity_obj_mapper($obj) { $objs = [ - 'http://activitystrea.ms/schema/1.0/note' => 'Note', - 'http://activitystrea.ms/schema/1.0/comment' => 'Note', - 'http://activitystrea.ms/schema/1.0/person' => 'Person', - 'http://purl.org/zot/activity/profile' => 'Profile', - '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://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' + 'http://activitystrea.ms/schema/1.0/note' => 'Note', + 'http://activitystrea.ms/schema/1.0/comment' => 'Note', + 'http://activitystrea.ms/schema/1.0/person' => 'Person', + 'http://purl.org/zot/activity/profile' => 'Profile', + '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://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); + call_hooks('activity_obj_mapper', $objs); if ($obj === 'Answer') { return 'Note'; } - if (strpos($obj,'/') === false) { + if (strpos($obj, '/') === false) { return $obj; } - if(array_key_exists($obj,$objs)) { + if (array_key_exists($obj, $objs)) { return $objs[$obj]; } @@ -1259,108 +1316,104 @@ class Activity { } + static function follow($channel, $act) { - static function follow($channel,$act) { - - $contact = null; + $contact = null; $their_follow_id = null; /* - * - * if $act->type === 'Follow', actor is now following $channel - * if $act->type === 'Accept', actor has approved a follow request from $channel - * + * + * if $act->type === 'Follow', actor is now following $channel + * if $act->type === 'Accept', actor has approved a follow request from $channel + * */ $person_obj = $act->actor; - if($act->type === 'Follow') { - $their_follow_id = $act->id; + if ($act->type === 'Follow') { + $their_follow_id = $act->id; } - elseif($act->type === 'Accept') { - $my_follow_id = z_root() . '/follow/' . $contact['id']; - } - - if(is_array($person_obj)) { + + if (is_array($person_obj)) { // store their xchan and hubloc - self::actor_store($person_obj['id'],$person_obj); + self::actor_store($person_obj['id'], $person_obj); - // Find any existing abook record + // Find any existing abook record $r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_xchan = '%s' and abook_channel = %d limit 1", dbesc($person_obj['id']), intval($channel['channel_id']) ); - if($r) { + if ($r) { $contact = $r[0]; } } - $x = \Zotlabs\Access\PermissionRoles::role_perms('social'); - $p = \Zotlabs\Access\Permissions::FilledPerms($x['perms_connect']); - $their_perms = \Zotlabs\Access\Permissions::serialise($p); + $x = PermissionRoles::role_perms('social'); + $p = Permissions::FilledPerms($x['perms_connect']); + $their_perms = Permissions::serialise($p); - if($contact && $contact['abook_id']) { + if ($contact && $contact['abook_id']) { - // A relationship of some form already exists on this site. + // A relationship of some form already exists on this site. - switch($act->type) { + switch ($act->type) { case 'Follow': // A second Follow request, but we haven't approved the first one - if($contact['abook_pending']) { + if ($contact['abook_pending']) { return; } // We've already approved them or followed them first // Send an Accept back to them - set_abconfig($channel['channel_id'],$person_obj['id'],'pubcrawl','their_follow_id', $their_follow_id); - Master::Summon([ 'Notifier', 'permissions_accept', $contact['abook_id'] ]); + set_abconfig($channel['channel_id'], $person_obj['id'], 'pubcrawl', 'their_follow_id', $their_follow_id); + Master::Summon(['Notifier', 'permissions_accept', $contact['abook_id']]); return; case 'Accept': // They accepted our Follow request - set default permissions - - set_abconfig($channel['channel_id'],$contact['abook_xchan'],'system','their_perms',$their_perms); + + set_abconfig($channel['channel_id'], $contact['abook_xchan'], 'system', 'their_perms', $their_perms); $abook_instance = $contact['abook_instance']; - - if(strpos($abook_instance,z_root()) === false) { - if($abook_instance) + + if (strpos($abook_instance, z_root()) === false) { + if ($abook_instance) $abook_instance .= ','; $abook_instance .= z_root(); - $r = q("update abook set abook_instance = '%s', abook_not_here = 0 + q("update abook set abook_instance = '%s', abook_not_here = 0 where abook_id = %d and abook_channel = %d", dbesc($abook_instance), intval($contact['abook_id']), intval($channel['channel_id']) ); } - + return; default: return; - + } } // No previous relationship exists. - if($act->type === 'Accept') { + if ($act->type === 'Accept') { // This should not happen unless we deleted the connection before it was accepted. return; } // From here on out we assume a Follow activity to somebody we have no existing relationship with - set_abconfig($channel['channel_id'],$person_obj['id'],'pubcrawl','their_follow_id', $their_follow_id); + set_abconfig($channel['channel_id'], $person_obj['id'], 'pubcrawl', 'their_follow_id', $their_follow_id); // The xchan should have been created by actor_store() above @@ -1368,17 +1421,17 @@ class Activity { dbesc($person_obj['id']) ); - if(! $r) { + if (!$r) { logger('xchan not found for ' . $person_obj['id']); return; } $ret = $r[0]; - $p = \Zotlabs\Access\Permissions::connect_perms($channel['channel_id']); - $my_perms = \Zotlabs\Access\Permissions::serialise($p['perms']); + $p = Permissions::connect_perms($channel['channel_id']); + $my_perms = Permissions::serialise($p['perms']); $automatic = $p['automatic']; - $closeness = get_pconfig($channel['channel_id'],'system','new_abook_closeness',80); + $closeness = get_pconfig($channel['channel_id'], 'system', 'new_abook_closeness', 80); $r = abook_store_lowlevel( [ @@ -1394,64 +1447,64 @@ class Activity { 'abook_instance' => z_root() ] ); - - if($my_perms) - set_abconfig($channel['channel_id'],$ret['xchan_hash'],'system','my_perms',$my_perms); - if($their_perms) - set_abconfig($channel['channel_id'],$ret['xchan_hash'],'system','their_perms',$their_perms); + if ($my_perms) + set_abconfig($channel['channel_id'], $ret['xchan_hash'], 'system', 'my_perms', $my_perms); + + if ($their_perms) + set_abconfig($channel['channel_id'], $ret['xchan_hash'], 'system', 'their_perms', $their_perms); - if($r) { + if ($r) { logger("New ActivityPub follower for {$channel['channel_name']}"); $new_connection = q("select * from abook left join xchan on abook_xchan = xchan_hash left join hubloc on hubloc_hash = xchan_hash where abook_channel = %d and abook_xchan = '%s' order by abook_created desc limit 1", intval($channel['channel_id']), dbesc($ret['xchan_hash']) ); - if($new_connection) { - \Zotlabs\Lib\Enotify::submit( + if ($new_connection) { + Enotify::submit( [ - 'type' => NOTIFY_INTRO, - 'from_xchan' => $ret['xchan_hash'], - 'to_xchan' => $channel['channel_hash'], - 'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id'], + 'type' => NOTIFY_INTRO, + 'from_xchan' => $ret['xchan_hash'], + 'to_xchan' => $channel['channel_hash'], + 'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id'], ] ); - if($my_perms && $automatic) { + if ($my_perms && $automatic) { // send an Accept for this Follow activity - Master::Summon([ 'Notifier', 'permissions_accept', $new_connection[0]['abook_id'] ]); + Master::Summon(['Notifier', 'permissions_accept', $new_connection[0]['abook_id']]); // Send back a Follow notification to them - Master::Summon([ 'Notifier', 'permissions_create', $new_connection[0]['abook_id'] ]); + Master::Summon(['Notifier', 'permissions_create', $new_connection[0]['abook_id']]); } - $clone = array(); - foreach($new_connection[0] as $k => $v) { - if(strpos($k,'abook_') === 0) { + $clone = []; + foreach ($new_connection[0] as $k => $v) { + if (strpos($k, 'abook_') === 0) { $clone[$k] = $v; } } unset($clone['abook_id']); unset($clone['abook_account']); unset($clone['abook_channel']); - - $abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']); - if($abconfig) + $abconfig = load_abconfig($channel['channel_id'], $clone['abook_xchan']); + + if ($abconfig) $clone['abconfig'] = $abconfig; - Libsync::build_sync_packet($channel['channel_id'], [ 'abook' => array($clone) ] ); + Libsync::build_sync_packet($channel['channel_id'], ['abook' => [$clone]]); } } /* If there is a default group for this channel and permissions are automatic, add this member to it */ - if($channel['channel_default_group'] && $automatic) { - $g = Group::rec_byhash($channel['channel_id'],$channel['channel_default_group']); - if($g) - Group::member_add($channel['channel_id'],'',$ret['xchan_hash'],$g['id']); + if ($channel['channel_default_group'] && $automatic) { + $g = Group::rec_byhash($channel['channel_id'], $channel['channel_default_group']); + if ($g) + Group::member_add($channel['channel_id'], '', $ret['xchan_hash'], $g['id']); } @@ -1459,8 +1512,7 @@ class Activity { } - - static function unfollow($channel,$act) { + static function unfollow($channel, $act) { $contact = null; @@ -1470,46 +1522,43 @@ class Activity { $person_obj = $act->actor; - if(is_array($person_obj)) { + if (is_array($person_obj)) { $r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_xchan = '%s' and abook_channel = %d limit 1", dbesc($person_obj['id']), intval($channel['channel_id']) ); - if($r) { + if ($r) { // remove all permissions they provided - del_abconfig($channel['channel_id'],$r[0]['xchan_hash'],'system','their_perms',EMPTY_STR); + del_abconfig($channel['channel_id'], $r[0]['xchan_hash'], 'system', 'their_perms'); } } return; } + static function actor_store($url, $person_obj) { - - - static function actor_store($url,$person_obj) { - - if(! is_array($person_obj)) + if (!is_array($person_obj)) return; $inbox = $person_obj['inbox']; // invalid identity - if (! $inbox || strpos($inbox,z_root()) !== false) { + if (!$inbox || strpos($inbox, z_root()) !== false) { return; } $name = $person_obj['name']; - if(! $name) + if (!$name) $name = $person_obj['preferredUsername']; - if(! $name) + if (!$name) $name = t('Unknown'); - if($person_obj['icon']) { - if(is_array($person_obj['icon'])) { - if(array_key_exists('url',$person_obj['icon'])) + if ($person_obj['icon']) { + if (is_array($person_obj['icon'])) { + if (array_key_exists('url', $person_obj['icon'])) $icon = $person_obj['icon']['url']; else $icon = $person_obj['icon'][0]['url']; @@ -1518,12 +1567,12 @@ class Activity { $icon = $person_obj['icon']; } - $links = false; + $links = false; $profile = false; if (is_array($person_obj['url'])) { - if (! array_key_exists(0,$person_obj['url'])) { - $links = [ $person_obj['url'] ]; + if (!array_key_exists(0, $person_obj['url'])) { + $links = [$person_obj['url']]; } else { $links = $person_obj['url']; @@ -1532,11 +1581,11 @@ class Activity { if ($links) { foreach ($links as $link) { - if (array_key_exists('mediaType',$link) && $link['mediaType'] === 'text/html') { + if (array_key_exists('mediaType', $link) && $link['mediaType'] === 'text/html') { $profile = $link['href']; } } - if (! $profile) { + if (!$profile) { $profile = $links[0]['href']; } } @@ -1544,29 +1593,29 @@ class Activity { $profile = $person_obj['url']; } - if (! $profile) { + if (!$profile) { $profile = $url; } $collections = []; - if($inbox) { + if ($inbox) { $collections['inbox'] = $inbox; - if($person_obj['outbox']) + if ($person_obj['outbox']) $collections['outbox'] = $person_obj['outbox']; - if($person_obj['followers']) + if ($person_obj['followers']) $collections['followers'] = $person_obj['followers']; - if($person_obj['following']) + if ($person_obj['following']) $collections['following'] = $person_obj['following']; - if($person_obj['endpoints'] && $person_obj['endpoints']['sharedInbox']) + if ($person_obj['endpoints'] && $person_obj['endpoints']['sharedInbox']) $collections['sharedInbox'] = $person_obj['endpoints']['sharedInbox']; } - if(array_key_exists('publicKey',$person_obj) && array_key_exists('publicKeyPem',$person_obj['publicKey'])) { - if($person_obj['id'] === $person_obj['publicKey']['owner']) { + if (array_key_exists('publicKey', $person_obj) && array_key_exists('publicKeyPem', $person_obj['publicKey'])) { + if ($person_obj['id'] === $person_obj['publicKey']['owner']) { $pubkey = $person_obj['publicKey']['publicKeyPem']; - if(strstr($pubkey,'RSA ')) { - $pubkey = rsatopem($pubkey); + if (strstr($pubkey, 'RSA ')) { + $pubkey = Keyutils::rsaToPem($pubkey); } } } @@ -1574,33 +1623,33 @@ class Activity { $r = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($url) ); - if(! $r) { + if (!$r) { // create a new record - $r = xchan_store_lowlevel( + xchan_store_lowlevel( [ - 'xchan_hash' => $url, - 'xchan_guid' => $url, - 'xchan_pubkey' => $pubkey, - 'xchan_addr' => '', - 'xchan_url' => $profile, - 'xchan_name' => $name, - 'xchan_name_date' => datetime_convert(), - 'xchan_network' => 'activitypub' + 'xchan_hash' => $url, + 'xchan_guid' => $url, + 'xchan_pubkey' => $pubkey, + 'xchan_addr' => '', + 'xchan_url' => $profile, + 'xchan_name' => $name, + 'xchan_name_date' => datetime_convert(), + 'xchan_network' => 'activitypub' ] ); } else { // Record exists. Cache existing records for one week at most - // then refetch to catch updated profile photos, names, etc. + // then refetch to catch updated profile photos, names, etc. - $d = datetime_convert('UTC','UTC','now - 1 week'); - if($r[0]['xchan_name_date'] > $d) + $d = datetime_convert('UTC', 'UTC', 'now - 1 week'); + if ($r[0]['xchan_name_date'] > $d) return; // update existing record - $r = q("update xchan set xchan_name = '%s', xchan_pubkey = '%s', xchan_network = '%s', xchan_name_date = '%s' where xchan_hash = '%s'", + q("update xchan set xchan_name = '%s', xchan_pubkey = '%s', xchan_network = '%s', xchan_name_date = '%s' where xchan_hash = '%s'", dbesc($name), dbesc($pubkey), dbesc('activitypub'), @@ -1609,29 +1658,28 @@ class Activity { ); } - if($collections) { - set_xconfig($url,'activitypub','collections',$collections); + if ($collections) { + set_xconfig($url, 'activitypub', 'collections', $collections); } $r = q("select * from hubloc where hubloc_hash = '%s' limit 1", dbesc($url) ); - $m = parse_url($url); - if($m) { + if ($m) { $hostname = $m['host']; - $baseurl = $m['scheme'] . '://' . $m['host'] . (($m['port']) ? ':' . $m['port'] : ''); + $site_url = $m['scheme'] . '://' . $m['host'] . (($m['port']) ? ':' . $m['port'] : ''); } - if(! $r) { - $r = hubloc_store_lowlevel( + if (!$r) { + hubloc_store_lowlevel( [ 'hubloc_guid' => $url, 'hubloc_hash' => $url, 'hubloc_addr' => '', 'hubloc_network' => 'activitypub', - 'hubloc_url' => $baseurl, + 'hubloc_url' => $site_url, 'hubloc_host' => $hostname, 'hubloc_callback' => $inbox, 'hubloc_updated' => datetime_convert(), @@ -1641,12 +1689,19 @@ class Activity { ); } - if(! $icon) + q("UPDATE site SET site_update = '%s', site_dead = 0 WHERE site_url = '%s' AND site_update < %s - INTERVAL %s", + dbesc(datetime_convert()), + dbesc($site_url), + db_utcnow(), + db_quoteinterval('1 DAY') + ); + + if (!$icon) $icon = z_root() . '/' . get_default_profile_photo(300); - $photos = import_xchan_photo($icon,$url); - $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'", - dbescdate(datetime_convert('UTC','UTC',$photos[5])), + $photos = import_xchan_photo($icon, $url); + q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'", + dbescdate(datetime_convert('UTC', 'UTC', $photos[5])), dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), @@ -1656,54 +1711,51 @@ class Activity { } + static function create_action($channel, $observer_hash, $act) { - static function create_action($channel,$observer_hash,$act) { - - if(in_array($act->obj['type'], [ 'Note', 'Article', 'Video' ])) { - self::create_note($channel,$observer_hash,$act); + if (in_array($act->obj['type'], ['Note', 'Article', 'Video'])) { + self::create_note($channel, $observer_hash, $act); } } - static function announce_action($channel,$observer_hash,$act) { + static function announce_action($channel, $observer_hash, $act) { - if(in_array($act->type, [ 'Announce' ])) { - self::announce_note($channel,$observer_hash,$act); + if (in_array($act->type, ['Announce'])) { + self::announce_note($channel, $observer_hash, $act); } } + static function like_action($channel, $observer_hash, $act) { - static function like_action($channel,$observer_hash,$act) { - - if(in_array($act->obj['type'], [ 'Note', 'Article', 'Video' ])) { - self::like_note($channel,$observer_hash,$act); + if (in_array($act->obj['type'], ['Note', 'Article', 'Video'])) { + self::like_note($channel, $observer_hash, $act); } } // sort function width decreasing - - static function vid_sort($a,$b) { - if($a['width'] === $b['width']) + static function vid_sort($a, $b) { + if ($a['width'] === $b['width']) return 0; return (($a['width'] > $b['width']) ? -1 : 1); } - static function create_note($channel,$observer_hash,$act) { + static function create_note($channel, $observer_hash, $act) { $s = []; // Mastodon only allows visibility in public timelines if the public inbox is listed in the 'to' field. // They are hidden in the public timeline if the public inbox is listed in the 'cc' field. // This is not part of the activitypub protocol - we might change this to show all public posts in pubstream at some point. - $pubstream = ((is_array($act->obj) && array_key_exists('to', $act->obj) && in_array(ACTIVITY_PUBLIC_INBOX, $act->obj['to'])) ? true : false); + $pubstream = ((is_array($act->obj) && array_key_exists('to', $act->obj) && in_array(ACTIVITY_PUBLIC_INBOX, $act->obj['to'])) ? true : false); $is_sys_channel = is_sys_channel($channel['channel_id']); - $parent = ((array_key_exists('inReplyTo',$act->obj)) ? urldecode($act->obj['inReplyTo']) : ''); - if($parent) { + $parent = ((array_key_exists('inReplyTo', $act->obj)) ? urldecode($act->obj['inReplyTo']) : ''); + if ($parent) { $r = q("select * from item where uid = %d and ( mid = '%s' or mid = '%s' ) limit 1", intval($channel['channel_id']), @@ -1711,39 +1763,39 @@ class Activity { dbesc(basename($parent)) ); - if(! $r) { + if (!$r) { logger('parent not found.'); return; } - if($r[0]['owner_xchan'] === $channel['channel_hash']) { - if(! perm_is_allowed($channel['channel_id'],$observer_hash,'send_stream') && ! ($is_sys_channel && $pubstream)) { + if ($r[0]['owner_xchan'] === $channel['channel_hash']) { + if (!perm_is_allowed($channel['channel_id'], $observer_hash, 'send_stream') && !($is_sys_channel && $pubstream)) { logger('no comment permission.'); return; } } - $s['parent_mid'] = $r[0]['mid']; - $s['owner_xchan'] = $r[0]['owner_xchan']; + $s['parent_mid'] = $r[0]['mid']; + $s['owner_xchan'] = $r[0]['owner_xchan']; $s['author_xchan'] = $observer_hash; } else { - if(! perm_is_allowed($channel['channel_id'],$observer_hash,'send_stream') && ! ($is_sys_channel && $pubstream)) { + if (!perm_is_allowed($channel['channel_id'], $observer_hash, 'send_stream') && !($is_sys_channel && $pubstream)) { logger('no permission'); return; } $s['owner_xchan'] = $s['author_xchan'] = $observer_hash; } - + $abook = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1", dbesc($observer_hash), intval($channel['channel_id']) ); - + $content = self::get_content($act->obj); - if(! $content) { + if (!$content) { logger('no content'); return; } @@ -1756,105 +1808,105 @@ class Activity { $s['author_xchan'] = self::find_best_identity($s['author_xchan']); $s['owner_xchan'] = self::find_best_identity($s['owner_xchan']); - if(!$s['author_xchan']) { + if (!$s['author_xchan']) { logger('No author: ' . print_r($act, true)); } - if(!$s['owner_xchan']) { + if (!$s['owner_xchan']) { logger('No owner: ' . print_r($act, true)); } - if(!$s['author_xchan'] || !$s['owner_xchan']) + if (!$s['author_xchan'] || !$s['owner_xchan']) return; - $s['mid'] = urldecode($act->obj['id']); - $s['uuid'] = $act->obj['diaspora:guid']; + $s['mid'] = urldecode($act->obj['id']); + $s['uuid'] = $act->obj['diaspora:guid']; $s['plink'] = urldecode($act->obj['id']); - if($act->data['published']) { - $s['created'] = datetime_convert('UTC','UTC',$act->data['published']); + if ($act->data['published']) { + $s['created'] = datetime_convert('UTC', 'UTC', $act->data['published']); } - elseif($act->obj['published']) { - $s['created'] = datetime_convert('UTC','UTC',$act->obj['published']); + elseif ($act->obj['published']) { + $s['created'] = datetime_convert('UTC', 'UTC', $act->obj['published']); } - if($act->data['updated']) { - $s['edited'] = datetime_convert('UTC','UTC',$act->data['updated']); + if ($act->data['updated']) { + $s['edited'] = datetime_convert('UTC', 'UTC', $act->data['updated']); } - elseif($act->obj['updated']) { - $s['edited'] = datetime_convert('UTC','UTC',$act->obj['updated']); + elseif ($act->obj['updated']) { + $s['edited'] = datetime_convert('UTC', 'UTC', $act->obj['updated']); } if ($act->data['expires']) { - $s['expires'] = datetime_convert('UTC','UTC',$act->data['expires']); + $s['expires'] = datetime_convert('UTC', 'UTC', $act->data['expires']); } elseif ($act->obj['expires']) { - $s['expires'] = datetime_convert('UTC','UTC',$act->obj['expires']); + $s['expires'] = datetime_convert('UTC', 'UTC', $act->obj['expires']); } - if(! $s['created']) + if (!$s['created']) $s['created'] = datetime_convert(); - if(! $s['edited']) + if (!$s['edited']) $s['edited'] = $s['created']; - if(! $s['parent_mid']) + if (!$s['parent_mid']) $s['parent_mid'] = $s['mid']; - - $s['title'] = self::bb_content($content,'name'); - $s['summary'] = self::bb_content($content,'summary'); - $s['body'] = self::bb_content($content,'content'); + + $s['title'] = self::bb_content($content, 'name'); + $s['summary'] = self::bb_content($content, 'summary'); + $s['body'] = self::bb_content($content, 'content'); $s['verb'] = ACTIVITY_POST; $s['obj_type'] = ACTIVITY_OBJ_NOTE; $generator = $act->get_property_obj('generator'); - if(! $generator) - $generator = $act->get_property_obj('generator',$act->obj); + if (!$generator) + $generator = $act->get_property_obj('generator', $act->obj); - if($generator && array_key_exists('type',$generator) - && in_array($generator['type'], [ 'Application','Service' ] ) && array_key_exists('name',$generator)) { + if ($generator && array_key_exists('type', $generator) + && in_array($generator['type'], ['Application', 'Service']) && array_key_exists('name', $generator)) { $s['app'] = escape_tags($generator['name']); } - if($channel['channel_system']) { - if(! \Zotlabs\Lib\MessageFilter::evaluate($s,get_config('system','pubstream_incl'),get_config('system','pubstream_excl'))) { + if ($channel['channel_system']) { + if (!MessageFilter::evaluate($s, get_config('system', 'pubstream_incl'), get_config('system', 'pubstream_excl'))) { logger('post is filtered'); return; } } - if($abook) { - if(! post_is_importable($s,$abook[0])) { + if ($abook) { + if (!post_is_importable($s, $abook[0])) { logger('post is filtered'); return; } } - if($act->obj['conversation']) { - set_iconfig($s,'ostatus','conversation',$act->obj['conversation'],1); + if ($act->obj['conversation']) { + set_iconfig($s, 'ostatus', 'conversation', $act->obj['conversation'], 1); } $a = self::decode_taxonomy($act->obj); - if($a) { + if ($a) { $s['term'] = $a; } $a = self::decode_attachment($act->obj); - if($a) { + if ($a) { $s['attach'] = $a; } - if($act->obj['type'] === 'Note' && $s['attach']) { - $s['body'] .= self::bb_attach($s['attach'],$s['body']); + if ($act->obj['type'] === 'Note' && $s['attach']) { + $s['body'] .= self::bb_attach($s['attach'], $s['body']); } // 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 // standard content region - if($act->obj['type'] === 'Video') { + if ($act->obj['type'] === 'Video') { $vtypes = [ 'video/mp4', @@ -1863,20 +1915,20 @@ class Activity { ]; $mps = []; - if(array_key_exists('url',$act->obj) && is_array($act->obj['url'])) { - foreach($act->obj['url'] as $vurl) { - if(in_array($vurl['mimeType'], $vtypes)) { - if(! array_key_exists('width',$vurl)) { + if (array_key_exists('url', $act->obj) && is_array($act->obj['url'])) { + foreach ($act->obj['url'] as $vurl) { + if (in_array($vurl['mimeType'], $vtypes)) { + if (!array_key_exists('width', $vurl)) { $vurl['width'] = 0; } $mps[] = $vurl; } } } - if($mps) { - usort($mps,[ __CLASS__, 'vid_sort' ]); - foreach($mps as $m) { - if(intval($m['width']) < 500) { + if ($mps) { + usort($mps, [__CLASS__, 'vid_sort']); + foreach ($mps as $m) { + if (intval($m['width']) < 500) { $s['body'] .= "\n\n" . '[video]' . $m['href'] . '[/video]'; break; } @@ -1884,17 +1936,17 @@ class Activity { } } - if($act->recips && (! in_array(ACTIVITY_PUBLIC_INBOX,$act->recips))) + if ($act->recips && (!in_array(ACTIVITY_PUBLIC_INBOX, $act->recips))) $s['item_private'] = 1; - if (array_key_exists('directMessage',$act->obj) && intval($act->obj['directMessage'])) { + if (array_key_exists('directMessage', $act->obj) && intval($act->obj['directMessage'])) { $s['item_private'] = 2; } - set_iconfig($s,'activitypub','recips',$act->raw_recips); - if($parent) { - set_iconfig($s,'activitypub','rawmsg',$act->raw,1); + set_iconfig($s, 'activitypub', 'recips', $act->raw_recips); + if ($parent) { + set_iconfig($s, 'activitypub', 'rawmsg', $act->raw, 1); } $x = null; @@ -1903,8 +1955,8 @@ class Activity { dbesc($s['mid']), intval($s['uid']) ); - if($r) { - if($s['edited'] > $r[0]['edited']) { + if ($r) { + if ($s['edited'] > $r[0]['edited']) { $x = item_store_update($s); } else { @@ -1915,20 +1967,20 @@ class Activity { $x = item_store($s); } - if(is_array($x) && $x['item_id']) { - if($parent) { - if($s['owner_xchan'] === $channel['channel_hash']) { + if (is_array($x) && $x['item_id']) { + if ($parent) { + if ($s['owner_xchan'] === $channel['channel_hash']) { // We are the owner of this conversation, so send all received comments back downstream - Master::Summon(array('Notifier','comment-import',$x['item_id'])); + Master::Summon(['Notifier', 'comment-import', $x['item_id']]); } $r = q("select * from item where id = %d limit 1", intval($x['item_id']) ); - if($r) { - send_status_notifications($x['item_id'],$r[0]); + if ($r) { + send_status_notifications($x['item_id'], $r[0]); } } - sync_an_item($channel['channel_id'],$x['item_id']); + sync_an_item($channel['channel_id'], $x['item_id']); } } @@ -1940,26 +1992,24 @@ class Activity { dbesc($id) ); - if($x) { - return sprintf('@[zrl=%s]%s[/zrl]',$x[0]['xchan_url'],$x[0]['xchan_name']); + if ($x) { + return sprintf('@[zrl=%s]%s[/zrl]', $x[0]['xchan_url'], $x[0]['xchan_name']); } return '@{' . $id . '}'; } - - - static function update_poll($item,$post) { - $multi = false; - $mid = $post['mid']; + static function update_poll($item, $post) { + $multi = false; + $mid = $post['mid']; $content = $post['title']; - - if (! $item) { + + if (!$item) { return false; } - $o = json_decode($item['obj'],true); - if ($o && array_key_exists('anyOf',$o)) { + $o = json_decode($item['obj'], true); + if ($o && array_key_exists('anyOf', $o)) { $multi = true; } @@ -1969,7 +2019,7 @@ class Activity { ); // 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) { @@ -1986,103 +2036,101 @@ class Activity { } } } - + $answer_found = false; - $found = false; + $found = false; if ($multi) { - for ($c = 0; $c < count($o['anyOf']); $c ++) { + 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) { + 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' ]; + 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 ++) { + 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) { + 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' ]; + 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", + logger('updated_poll: ' . print_r($o, true), LOGGER_DATA); + if ($answer_found && !$found) { + 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'] ] ); + Master::Summon(['Notifier', 'wall-new', $item['id']]); return true; } return false; } - - static function decode_note($act) { $response_activity = false; $s = []; - if(is_array($act->obj)) { + if (is_array($act->obj)) { $content = self::get_content($act->obj); } - + $s['owner_xchan'] = $act->actor['id']; $s['author_xchan'] = $act->actor['id']; // ensure we store the original actor - self::actor_store($act->actor['id'],$act->actor); + self::actor_store($act->actor['id'], $act->actor); $s['mid'] = $act->obj['id']; - $s['uuid'] = $act->obj['diaspora:guid']; + $s['uuid'] = $act->obj['diaspora:guid']; $s['parent_mid'] = $act->parent_id; - if($act->data['published']) { - $s['created'] = datetime_convert('UTC','UTC',$act->data['published']); + if ($act->data['published']) { + $s['created'] = datetime_convert('UTC', 'UTC', $act->data['published']); } - elseif($act->obj['published']) { - $s['created'] = datetime_convert('UTC','UTC',$act->obj['published']); + elseif ($act->obj['published']) { + $s['created'] = datetime_convert('UTC', 'UTC', $act->obj['published']); } - if($act->data['updated']) { - $s['edited'] = datetime_convert('UTC','UTC',$act->data['updated']); + if ($act->data['updated']) { + $s['edited'] = datetime_convert('UTC', 'UTC', $act->data['updated']); } - elseif($act->obj['updated']) { - $s['edited'] = datetime_convert('UTC','UTC',$act->obj['updated']); + elseif ($act->obj['updated']) { + $s['edited'] = datetime_convert('UTC', 'UTC', $act->obj['updated']); } if ($act->data['expires']) { - $s['expires'] = datetime_convert('UTC','UTC',$act->data['expires']); + $s['expires'] = datetime_convert('UTC', 'UTC', $act->data['expires']); } elseif ($act->obj['expires']) { - $s['expires'] = datetime_convert('UTC','UTC',$act->obj['expires']); + $s['expires'] = datetime_convert('UTC', 'UTC', $act->obj['expires']); } - if(ActivityStreams::is_response_activity($act->type)) { + if (ActivityStreams::is_response_activity($act->type)) { $response_activity = true; @@ -2092,85 +2140,86 @@ class Activity { // over-ride the object timestamp with the activity - if($act->data['published']) { - $s['created'] = datetime_convert('UTC','UTC',$act->data['published']); + if ($act->data['published']) { + $s['created'] = datetime_convert('UTC', 'UTC', $act->data['published']); } - if($act->data['updated']) { - $s['edited'] = datetime_convert('UTC','UTC',$act->data['updated']); + if ($act->data['updated']) { + $s['edited'] = datetime_convert('UTC', 'UTC', $act->data['updated']); } $obj_actor = ((isset($act->obj['actor'])) ? $act->obj['actor'] : $act->get_actor('attributedTo', $act->obj)); // ensure we store the original actor - self::actor_store($obj_actor['id'],$obj_actor); + + self::actor_store($obj_actor['id'], $obj_actor); $mention = self::get_actor_bbmention($obj_actor['id']); - if($act->type === 'Like') { - $content['content'] = sprintf( t('Likes %1$s\'s %2$s'),$mention,$act->obj['type']) . "\n\n" . $content['content']; + if ($act->type === 'Like') { + $content['content'] = sprintf(t('Likes %1$s\'s %2$s'), $mention, $act->obj['type']) . "\n\n" . $content['content']; } - 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 === 'Dislike') { + $content['content'] = sprintf(t('Doesn\'t like %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->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']; + $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']; + $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']; + $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']; + $content['content'] = sprintf(t('May not attend %s\'s event'), $mention) . EOL . EOL . $content['content']; } } - if($act->type === 'Announce') { - $content['content'] = sprintf( t('🔁 Repeated %1$s\'s %2$s'), $mention, $act->obj['type']); + if ($act->type === 'Announce') { + $content['content'] = sprintf(t('🔁 Repeated %1$s\'s %2$s'), $mention, $act->obj['type']); } if ($act->type === 'emojiReaction') { $content['content'] = (($act->tgt && $act->tgt['type'] === 'Image') ? '[img=32x32]' . $act->tgt['url'] . '[/img]' : '' . $act->tgt['name'] . ';'); - } + } } - if(! $s['created']) + if (!$s['created']) $s['created'] = datetime_convert(); - if(! $s['edited']) + if (!$s['edited']) $s['edited'] = $s['created']; - $s['title'] = (($response_activity) ? EMPTY_STR : self::bb_content($content,'name')); - $s['summary'] = self::bb_content($content,'summary'); - $s['body'] = ((self::bb_content($content,'bbcode') && (! $response_activity)) ? self::bb_content($content,'bbcode') : self::bb_content($content,'content')); + $s['title'] = (($response_activity) ? EMPTY_STR : self::bb_content($content, 'name')); + $s['summary'] = self::bb_content($content, 'summary'); + $s['body'] = ((self::bb_content($content, 'bbcode') && (!$response_activity)) ? self::bb_content($content, 'bbcode') : self::bb_content($content, 'content')); - $s['verb'] = self::activity_decode_mapper($act->type); + $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(in_array($act->type, [ 'Delete', 'Undo', 'Tombstone' ]) || ($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; } $s['obj_type'] = self::activity_obj_decode_mapper($act->obj['type']); - if($s['obj_type'] === ACTIVITY_OBJ_NOTE && $s['mid'] !== $s['parent_mid']) { + if ($s['obj_type'] === ACTIVITY_OBJ_NOTE && $s['mid'] !== $s['parent_mid']) { $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') { + 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->obj['type'] === 'Event') { if ($act->type === 'Invite') { $s['mid'] = $s['parent_mid'] = $act->id; } @@ -2179,52 +2228,52 @@ class Activity { if ($eventptr) { - $s['obj'] = []; - $s['obj']['asld'] = $eventptr; - $s['obj']['type'] = ACTIVITY_OBJ_EVENT; - $s['obj']['id'] = $eventptr['id']; + $s['obj'] = []; + $s['obj']['asld'] = $eventptr; + $s['obj']['type'] = ACTIVITY_OBJ_EVENT; + $s['obj']['id'] = $eventptr['id']; $s['obj']['title'] = $eventptr['name']; - if(strpos($act->obj['startTime'],'Z')) + if (strpos($act->obj['startTime'], 'Z')) $s['obj']['adjust'] = true; else $s['obj']['adjust'] = false; - $s['obj']['dtstart'] = datetime_convert('UTC','UTC',$eventptr['startTime']); - if($act->obj['endTime']) - $s['obj']['dtend'] = datetime_convert('UTC','UTC',$eventptr['endTime']); + $s['obj']['dtstart'] = datetime_convert('UTC', 'UTC', $eventptr['startTime']); + if ($act->obj['endTime']) + $s['obj']['dtend'] = datetime_convert('UTC', 'UTC', $eventptr['endTime']); else $s['obj']['nofinish'] = true; $s['obj']['description'] = $eventptr['content']; - if(array_path_exists('location/content',$eventptr)) + if (array_path_exists('location/content', $eventptr)) $s['obj']['location'] = $eventptr['location']['content']; } else { - $s['obj'] = $act->obj; + $s['obj'] = $act->obj; } $generator = $act->get_property_obj('generator'); - if((! $generator) && (! $response_activity)) { - $generator = $act->get_property_obj('generator',$act->obj); + if ((!$generator) && (!$response_activity)) { + $generator = $act->get_property_obj('generator', $act->obj); } - if($generator && array_key_exists('type',$generator) - && in_array($generator['type'], [ 'Application', 'Service' ] ) && array_key_exists('name',$generator)) { + if ($generator && array_key_exists('type', $generator) + && in_array($generator['type'], ['Application', 'Service']) && array_key_exists('name', $generator)) { $s['app'] = escape_tags($generator['name']); } - if(! $response_activity) { + if (!$response_activity) { $a = self::decode_taxonomy($act->obj); - if($a) { + if ($a) { $s['term'] = $a; - foreach($a as $b) { - if($b['ttype'] === TERM_EMOJI) { - $s['title'] = str_replace($b['term'],'[img=16x16]' . $b['url'] . '[/img]',$s['title']); - $s['summary'] = str_replace($b['term'],'[img=16x16]' . $b['url'] . '[/img]',$s['summary']); - $s['body'] = str_replace($b['term'],'[img=16x16]' . $b['url'] . '[/img]',$s['body']); + foreach ($a as $b) { + if ($b['ttype'] === TERM_EMOJI) { + $s['title'] = str_replace($b['term'], '[img=16x16]' . $b['url'] . '[/img]', $s['title']); + $s['summary'] = str_replace($b['term'], '[img=16x16]' . $b['url'] . '[/img]', $s['summary']); + $s['body'] = str_replace($b['term'], '[img=16x16]' . $b['url'] . '[/img]', $s['body']); } } } @@ -2241,28 +2290,27 @@ class Activity { $s['iconfig'] = $a; } - if($act->obj['type'] === 'Note' && $s['attach']) { - $s['body'] .= self::bb_attach($s['attach'],$s['body']); + 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['type'] === 'Question' && in_array($act->type, ['Create', 'Update'])) { if ($act->obj['endTime']) { - $s['comments_closed'] = datetime_convert('UTC','UTC', $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']); - } - + $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 // standard content region - if(! $response_activity) { - if($act->obj['type'] === 'Video') { + if (!$response_activity) { + if ($act->obj['type'] === 'Video') { $vtypes = [ 'video/mp4', @@ -2273,27 +2321,27 @@ class Activity { $mps = []; $ptr = null; - if(array_key_exists('url',$act->obj)) { - if(is_array($act->obj['url'])) { - if(array_key_exists(0,$act->obj['url'])) { + if (array_key_exists('url', $act->obj)) { + if (is_array($act->obj['url'])) { + if (array_key_exists(0, $act->obj['url'])) { $ptr = $act->obj['url']; } else { - $ptr = [ $act->obj['url'] ]; + $ptr = [$act->obj['url']]; } - foreach($ptr as $vurl) { + foreach ($ptr as $vurl) { // peertube uses the non-standard element name 'mimeType' here - if(array_key_exists('mimeType',$vurl)) { - if(in_array($vurl['mimeType'], $vtypes)) { - if(! array_key_exists('width',$vurl)) { + if (array_key_exists('mimeType', $vurl)) { + if (in_array($vurl['mimeType'], $vtypes)) { + if (!array_key_exists('width', $vurl)) { $vurl['width'] = 0; } $mps[] = $vurl; } } - elseif(array_key_exists('mediaType',$vurl)) { - if(in_array($vurl['mediaType'], $vtypes)) { - if(! array_key_exists('width',$vurl)) { + elseif (array_key_exists('mediaType', $vurl)) { + if (in_array($vurl['mediaType'], $vtypes)) { + if (!array_key_exists('width', $vurl)) { $vurl['width'] = 0; } $mps[] = $vurl; @@ -2301,22 +2349,22 @@ class Activity { } } } - if($mps) { - usort($mps,[ __CLASS__, 'vid_sort' ]); - foreach($mps as $m) { - if(intval($m['width']) < 500 && self::media_not_in_body($m['href'],$s['body'])) { + if ($mps) { + usort($mps, [__CLASS__, 'vid_sort']); + foreach ($mps as $m) { + if (intval($m['width']) < 500 && self::media_not_in_body($m['href'], $s['body'])) { $s['body'] .= "\n\n" . '[video]' . $m['href'] . '[/video]'; break; } } } - elseif(is_string($act->obj['url']) && self::media_not_in_body($act->obj['url'],$s['body'])) { + elseif (is_string($act->obj['url']) && self::media_not_in_body($act->obj['url'], $s['body'])) { $s['body'] .= "\n\n" . '[video]' . $act->obj['url'] . '[/video]'; } } } - if($act->obj['type'] === 'Audio') { + if ($act->obj['type'] === 'Audio') { $atypes = [ 'audio/mpeg', @@ -2326,50 +2374,50 @@ class Activity { $ptr = null; - if(array_key_exists('url',$act->obj)) { - if(is_array($act->obj['url'])) { - if(array_key_exists(0,$act->obj['url'])) { + if (array_key_exists('url', $act->obj)) { + if (is_array($act->obj['url'])) { + if (array_key_exists(0, $act->obj['url'])) { $ptr = $act->obj['url']; } else { - $ptr = [ $act->obj['url'] ]; + $ptr = [$act->obj['url']]; } - foreach($ptr as $vurl) { - if(in_array($vurl['mediaType'], $atypes) && self::media_not_in_body($vurl['href'],$s['body'])) { + foreach ($ptr as $vurl) { + if (in_array($vurl['mediaType'], $atypes) && self::media_not_in_body($vurl['href'], $s['body'])) { $s['body'] .= "\n\n" . '[audio]' . $vurl['href'] . '[/audio]'; break; } } } - elseif(is_string($act->obj['url']) && self::media_not_in_body($act->obj['url'],$s['body'])) { + elseif (is_string($act->obj['url']) && self::media_not_in_body($act->obj['url'], $s['body'])) { $s['body'] .= "\n\n" . '[audio]' . $act->obj['url'] . '[/audio]'; } } } - if($act->obj['type'] === 'Image') { + if ($act->obj['type'] === 'Image') { $ptr = null; - if(array_key_exists('url',$act->obj)) { - if(is_array($act->obj['url'])) { - if(array_key_exists(0,$act->obj['url'])) { + if (array_key_exists('url', $act->obj)) { + if (is_array($act->obj['url'])) { + if (array_key_exists(0, $act->obj['url'])) { $ptr = $act->obj['url']; } else { - $ptr = [ $act->obj['url'] ]; + $ptr = [$act->obj['url']]; } - foreach($ptr as $vurl) { - if(strpos($s['body'],$vurl['href']) === false) { - $bb_imgs .= '[zmg]' . $vurl['href'] . '[/zmg]' . "\n\n"; + foreach ($ptr as $vurl) { + if (strpos($s['body'], $vurl['href']) === false) { + $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) { + elseif (is_string($act->obj['url'])) { + if (strpos($s['body'], $act->obj['url']) === false) { $s['body'] .= '[zmg]' . $act->obj['url'] . '[/zmg]' . "\n\n" . $s['body']; } } @@ -2377,36 +2425,36 @@ class Activity { } - if($act->obj['type'] === 'Page' && ! $s['body']) { + if ($act->obj['type'] === 'Page' && !$s['body']) { $ptr = null; $purl = EMPTY_STR; - if(array_key_exists('url',$act->obj)) { - if(is_array($act->obj['url'])) { - if(array_key_exists(0,$act->obj['url'])) { + if (array_key_exists('url', $act->obj)) { + if (is_array($act->obj['url'])) { + if (array_key_exists(0, $act->obj['url'])) { $ptr = $act->obj['url']; } else { - $ptr = [ $act->obj['url'] ]; + $ptr = [$act->obj['url']]; } - foreach($ptr as $vurl) { - if(array_key_exists('mediaType',$vurl) && $vurl['mediaType'] === 'text/html') { + foreach ($ptr as $vurl) { + if (array_key_exists('mediaType', $vurl) && $vurl['mediaType'] === 'text/html') { $purl = $vurl['href']; break; } - elseif(array_key_exists('mimeType',$vurl) && $vurl['mimeType'] === 'text/html') { + elseif (array_key_exists('mimeType', $vurl) && $vurl['mimeType'] === 'text/html') { $purl = $vurl['href']; break; } } } - elseif(is_string($act->obj['url'])) { + elseif (is_string($act->obj['url'])) { $purl = $act->obj['url']; } - if($purl) { + if ($purl) { $li = z_fetch_url(z_root() . '/linkinfo?binurl=' . bin2hex($purl)); - if($li['success'] && $li['body']) { + if ($li['success'] && $li['body']) { $s['body'] .= "\n" . $li['body']; } else { @@ -2418,32 +2466,31 @@ class Activity { } - - if(in_array($act->obj['type'],[ 'Note','Article','Page' ])) { + if (in_array($act->obj['type'], ['Note', 'Article', 'Page'])) { $ptr = null; - if(array_key_exists('url',$act->obj)) { - if(is_array($act->obj['url'])) { - if(array_key_exists(0,$act->obj['url'])) { + if (array_key_exists('url', $act->obj)) { + if (is_array($act->obj['url'])) { + if (array_key_exists(0, $act->obj['url'])) { $ptr = $act->obj['url']; } else { - $ptr = [ $act->obj['url'] ]; + $ptr = [$act->obj['url']]; } - foreach($ptr as $vurl) { - if(array_key_exists('mediaType',$vurl) && $vurl['mediaType'] === 'text/html') { + foreach ($ptr as $vurl) { + if (array_key_exists('mediaType', $vurl) && $vurl['mediaType'] === 'text/html') { $s['plink'] = $vurl['href']; break; } } } - elseif(is_string($act->obj['url'])) { + elseif (is_string($act->obj['url'])) { $s['plink'] = $act->obj['url']; } } } - if(! $s['plink']) { + if (!$s['plink']) { $s['plink'] = $s['mid']; } @@ -2456,24 +2503,24 @@ class Activity { } if (is_array($act->obj)) { - if (array_key_exists('directMessage',$act->obj) && intval($act->obj['directMessage'])) { + if (array_key_exists('directMessage', $act->obj) && intval($act->obj['directMessage'])) { $s['item_private'] = 2; } } - set_iconfig($s,'activitypub','recips',$act->raw_recips); + set_iconfig($s, 'activitypub', 'recips', $act->raw_recips); $parent = (($s['parent_mid'] && $s['parent_mid'] === $s['mid']) ? true : false); - if($parent) { - set_iconfig($s,'activitypub','rawmsg',$act->raw,1); + if ($parent) { + set_iconfig($s, 'activitypub', 'rawmsg', $act->raw, 1); } $hookinfo = [ 'act' => $act, - 's' => $s + 's' => $s ]; - call_hooks('decode_note',$hookinfo); + call_hooks('decode_note', $hookinfo); $s = $hookinfo['s']; @@ -2481,51 +2528,177 @@ class Activity { } - static function store($channel,$observer_hash,$act,$item,$fetch_parents = true) { - + static function store($channel, $observer_hash, $act, $item, $fetch_parents = true, $force = false) { $is_sys_channel = is_sys_channel($channel['channel_id']); + $is_child_node = false; + + // TODO: not implemented + // Pleroma scrobbles can be really noisy and contain lots of duplicate activities. Disable them by default. + /*if (($act->type === 'Listen') && ($is_sys_channel || get_pconfig($channel['channel_id'], 'system', 'allow_scrobbles', false))) { + return; + }*/ // Mastodon only allows visibility in public timelines if the public inbox is listed in the 'to' field. // They are hidden in the public timeline if the public inbox is listed in the 'cc' field. // This is not part of the activitypub protocol - we might change this to show all public posts in pubstream at some point. $pubstream = ((is_array($act->obj) && array_key_exists('to', $act->obj) && in_array(ACTIVITY_PUBLIC_INBOX, $act->obj['to'])) ? true : false); - $is_parent = (($item['parent_mid'] && $item['parent_mid'] === $item['mid']) ? true : false); - if($is_parent && (! perm_is_allowed($channel['channel_id'],$observer_hash,'send_stream') && ! ($is_sys_channel && $pubstream))) { + // TODO: this his handled in pubcrawl atm. + // very unpleasant and imperfect way of determining a Mastodon DM + /*if ($act->raw_recips && array_key_exists('to',$act->raw_recips) && is_array($act->raw_recips['to']) && count($act->raw_recips['to']) === 1 && $act->raw_recips['to'][0] === channel_url($channel) && ! $act->raw_recips['cc']) { + $item['item_private'] = 2; + }*/ + + if ($item['parent_mid'] && $item['parent_mid'] !== $item['mid']) { + $is_child_node = true; + } + + $allowed = false; + + // TODO: not implemented + // $permit_mentions = intval(PConfig::Get($channel['channel_id'], 'system','permit_all_mentions') && i_am_mentioned($channel,$item)); + + if ($is_child_node) { + + $p = q("select * from item where mid = '%s' and uid = %d and item_wall = 1", + dbesc($item['parent_mid']), + intval($channel['channel_id']) + ); + if ($p) { + // set the owner to the owner of the parent + $item['owner_xchan'] = $p[0]['owner_xchan']; + + // check permissions against the author, not the sender + $allowed = perm_is_allowed($channel['channel_id'], $item['author_xchan'], 'post_comments'); + if ((!$allowed)/* && $permit_mentions*/) { + if ($p[0]['owner_xchan'] === $channel['channel_hash']) { + $allowed = false; + } + else { + $allowed = true; + } + } + + // TODO: not implemented + /*if (absolutely_no_comments($p[0])) { + $allowed = false; + }*/ + + if (!$allowed) { + logger('rejected comment from ' . $item['author_xchan'] . ' for ' . $channel['channel_address']); + logger('rejected: ' . print_r($item, true), LOGGER_DATA); + + // TODO: not implemented + // let the sender know we received their comment but we don't permit spam here. + // self::send_rejection_activity($channel,$item['author_xchan'],$item); + return; + } + + // TODO: not implemented + /*if (perm_is_allowed($channel['channel_id'],$item['author_xchan'],'moderated')) { + $item['item_blocked'] = ITEM_MODERATED; + }*/ + } + else { + + $allowed = true; + // reject public stream comments that weren't sent by the conversation owner + if ($is_sys_channel && $pubstream && $item['owner_xchan'] !== $observer_hash && !$fetch_parents) { + $allowed = false; + } + } + + if ($p && $p[0]['obj_type'] === 'Question') { + if ($item['obj_type'] === 'Note' && $item['title'] && (!$item['content'])) { + $item['obj_type'] = 'Answer'; + } + } + } + else { + + // The $item['item_fetched'] flag is set in fetch_and_store_parents(). + // In this case we should check against author permissions because sender is not owner. + if (perm_is_allowed($channel['channel_id'], (($item['item_fetched']) ? $item['author_xchan'] : $observer_hash), 'send_stream') || ($is_sys_channel && $pubstream)) { + $allowed = true; + } + // TODO: not implemented + /*if ($permit_mentions) { + $allowed = true; + }*/ + } + + if (tgroup_check($channel['channel_id'], $item) && (!$is_child_node)) { + // for forum deliveries, make sure we keep a copy of the signed original + set_iconfig($item, 'activitypub', 'rawmsg', $act->raw, 1); + $allowed = true; + } + + + if ($is_sys_channel) { + + /* TODO: not implemented + if (! check_pubstream_channelallowed($observer_hash)) { + $allowed = false; + } + + // don't allow pubstream posts if the sender even has a clone on a pubstream denied site + + $h = q("select hubloc_url from hubloc where hubloc_hash = '%s'", + dbesc($observer_hash) + ); + if ($h) { + foreach ($h as $hub) { + if (! check_pubstream_siteallowed($hub['hubloc_url'])) { + $allowed = false; + break; + } + } + } + */ + + if (intval($item['item_private'])) { + $allowed = false; + } + } + + // TODO: not implemented + /*$blocked = LibBlock::fetch($channel['channel_id'],BLOCKTYPE_SERVER); + if ($blocked) { + foreach($blocked as $b) { + if (strpos($observer_hash,$b['block_entity']) !== false) { + $allowed = false; + } + } + }*/ + + if (!$allowed && !$force) { logger('no permission'); return; } - if(is_array($act->obj)) { - $content = self::get_content($act->obj); - } - if(! $content) { - logger('no content'); - return; - } - $item['aid'] = $channel['channel_account_id']; $item['uid'] = $channel['channel_id']; - // Make sure we use the zot6 identity where applicable + // Some authors may be zot6 authors in which case we want to store their nomadic identity + // instead of their ActivityPub identity $item['author_xchan'] = self::find_best_identity($item['author_xchan']); $item['owner_xchan'] = self::find_best_identity($item['owner_xchan']); - if(!$item['author_xchan']) { + if (!$item['author_xchan']) { logger('No author: ' . print_r($act, true)); } - if(!$item['owner_xchan']) { + if (!$item['owner_xchan']) { logger('No owner: ' . print_r($act, true)); } - if(!$item['author_xchan'] || !$item['owner_xchan']) + 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'))) { + if ($channel['channel_system']) { + if (!MessageFilter::evaluate($item, get_config('system', 'pubstream_incl'), get_config('system', 'pubstream_excl'))) { logger('post is filtered'); return; } @@ -2536,81 +2709,90 @@ class Activity { intval($channel['channel_id']) ); - if($abook) { - if(! post_is_importable($item,$abook[0])) { + if ($abook) { + if (!post_is_importable($item, $abook[0])) { logger('post is filtered'); return; } } - - if($act->obj['conversation']) { - set_iconfig($item,'ostatus','conversation',$act->obj['conversation'],1); + if ($act->obj['conversation']) { + set_iconfig($item, 'ostatus', 'conversation', $act->obj['conversation'], 1); } // This isn't perfect but the best we can do for now. + $item['comment_policy'] = ((isset($act->data['commentPolicy'])) ? $act->data['commentPolicy'] : 'authenticated'); - $item['comment_policy'] = 'authenticated'; + set_iconfig($item, 'activitypub', 'recips', $act->raw_recips); - set_iconfig($item,'activitypub','recips',$act->raw_recips); + // TODO: inheritPrivacy should probably be set in encode activity. Zap does not do so yet - check what this is about + if (!(isset($act->data['inheritPrivacy']) && $act->data['inheritPrivacy'])) { + if ($item['item_private']) { + $item['item_restrict'] = $item['item_restrict'] & 1; + if ($is_child_node) { + $item['allow_cid'] = '<' . $channel['channel_hash'] . '>'; + $item['allow_gid'] = $item['deny_cid'] = $item['deny_gid'] = ''; + } + logger('restricted'); + } + } - if(! $is_parent) { - $p = q("select parent_mid, id, obj_type from item where mid = '%s' and uid = %d limit 1", + if (intval($act->sigok)) { + $item['item_verified'] = 1; + } + + $parent = null; + + if ($is_child_node) { + + $parent = q("select * from item where mid = '%s' and uid = %d limit 1", dbesc($item['parent_mid']), intval($item['uid']) ); - if(! $p) { - $a = (($fetch_parents) ? self::fetch_and_store_parents($channel,$act,$item) : false); - if($a) { - $p = q("select parent_mid from item where mid = '%s' and uid = %d limit 1", - dbesc($item['parent_mid']), - intval($item['uid']) - ); + if (!$parent) { + if (!plugin_is_installed('pubcrawl')) { + return; } else { - logger('could not fetch parents'); - return; - - // @TODO we maybe could accept these is we formatted the body correctly with share_bb() - // or at least provided a link to the object - // if(in_array($act->type,[ 'Like','Dislike' ])) { - // return; - // } - - // @TODO do we actually want that? - // if no parent was fetched, turn into a top-level post - - // turn into a top level post - // $s['parent_mid'] = $s['mid']; - // $s['thr_parent'] = $s['mid']; + $fetch = false; + // TODO: debug + // if (perm_is_allowed($channel['channel_id'],$observer_hash,'send_stream') && (PConfig::Get($channel['channel_id'],'system','hyperdrive',true) || $act->type === 'Announce')) { + if (perm_is_allowed($channel['channel_id'], $observer_hash, 'send_stream') || ($is_sys_channel && $pubstream)) { + $fetch = (($fetch_parents) ? self::fetch_and_store_parents($channel, $observer_hash, $item, $force) : false); + } + if ($fetch) { + $parent = q("select * from item where mid = '%s' and uid = %d limit 1", + dbesc($item['parent_mid']), + intval($item['uid']) + ); + } + else { + logger('no parent'); + return; + } } } - - 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']) { + if ($parent[0]['parent_mid'] !== $item['parent_mid']) { $item['thr_parent'] = $item['parent_mid']; } else { - $item['thr_parent'] = $p[0]['parent_mid']; + $item['thr_parent'] = $parent[0]['parent_mid']; } - $item['parent_mid'] = $p[0]['parent_mid']; + $item['parent_mid'] = $parent[0]['parent_mid']; } + // TODO: not implemented + // self::rewrite_mentions($item); + $r = q("select id, created, edited from item where mid = '%s' and uid = %d limit 1", dbesc($item['mid']), intval($item['uid']) ); - if($r) { - if($item['edited'] > $r[0]['edited']) { + if ($r) { + if ($item['edited'] > $r[0]['edited']) { $item['id'] = $r[0]['id']; - $x = item_store_update($item); + $x = item_store_update($item); } else { return; @@ -2620,99 +2802,122 @@ class Activity { $x = item_store($item); } - if(is_array($x) && $x['item_id']) { - if($is_parent) { - if($item['owner_xchan'] === $channel['channel_hash']) { + if ($fetch_parents && $parent && !intval($parent[0]['item_private'])) { + logger('topfetch', LOGGER_DEBUG); + // if the thread owner is a connnection, we will already receive any additional comments to their posts + // but if they are not we can try to fetch others in the background + $x = 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($channel['channel_id']), + dbesc($parent[0]['owner_xchan']) + ); + if (!$x) { + // determine if the top-level post provides a replies collection + if ($parent[0]['obj']) { + $parent[0]['obj'] = json_decode($parent[0]['obj'], true); + } + logger('topfetch: ' . print_r($parent[0], true), LOGGER_ALL); + $id = ((array_path_exists('obj/replies/id', $parent[0])) ? $parent[0]['obj']['replies']['id'] : false); + if (!$id) { + $id = ((array_path_exists('obj/replies', $parent[0]) && is_string($parent[0]['obj']['replies'])) ? $parent[0]['obj']['replies'] : false); + } + if ($id) { + Master::Summon(['Convo', $id, $channel['channel_id'], $observer_hash]); + } + } + } + + if (is_array($x) && $x['item_id']) { + if ($is_child_node) { + if ($item['owner_xchan'] === $channel['channel_hash']) { // We are the owner of this conversation, so send all received comments back downstream - Master::Summon(array('Notifier','comment-import',$x['item_id'])); + Master::Summon(['Notifier', 'comment-import', $x['item_id']]); } $r = q("select * from item where id = %d limit 1", intval($x['item_id']) ); - if($r) { - send_status_notifications($x['item_id'],$r[0]); + if ($r) { + send_status_notifications($x['item_id'], $r[0]); } } - sync_an_item($channel['channel_id'],$x['item_id']); + sync_an_item($channel['channel_id'], $x['item_id']); } } - static public function fetch_and_store_parents($channel,$act,$item) { - + static public function fetch_and_store_parents($channel, $observer_hash, $item, $force = false) { logger('fetching parents'); $p = []; - $current_act = $act; $current_item = $item; - while($current_item['parent_mid'] !== $current_item['mid']) { + while ($current_item['parent_mid'] !== $current_item['mid']) { $n = self::fetch($current_item['parent_mid'], $channel); - if(! $n) { + + if (!$n) { break; } + $a = new ActivityStreams($n); + if ($a->type === 'Announce' && is_array($a->obj) + && array_key_exists('object', $a->obj) && array_key_exists('actor', $a->obj)) { + // This is a relayed/forwarded Activity (as opposed to a shared/boosted object) + // Reparse the encapsulated Activity and use that instead + logger('relayed activity', LOGGER_DEBUG); + $a = new ActivityStreams($a->obj); + } - //logger($a->debug()); + logger($a->debug(), LOGGER_DATA); - if(! $a->is_valid()) { + if (!$a->is_valid()) { + logger('not a valid activity'); break; } - if (is_array($a->actor) && array_key_exists('id',$a->actor)) { - self::actor_store($a->actor['id'],$a->actor); - } - - $replies = null; - if(isset($a->obj['replies']['first']['items'])) { - $replies = $a->obj['replies']['first']['items']; - // we already have this one - array_diff($replies, [$current_item['mid']]); - } - - $item = null; - - switch($a->type) { - case 'Create': - case 'Update': - //case 'Like': - //case 'Dislike': - case 'Announce': - $item = self::decode_note($a); - break; - default: - break; + $item = Activity::decode_note($a); + if (!$item) { + break; } $hookinfo = [ - 'a' => $a, + 'a' => $a, 'item' => $item ]; - call_hooks('fetch_and_store',$hookinfo); + call_hooks('fetch_and_store', $hookinfo); $item = $hookinfo['item']; - if($item) { + if ($item) { + $item['item_fetched'] = 1; - array_unshift($p,[ $a, $item, $replies]); - - if($item['parent_mid'] === $item['mid'] || count($p) > 20) { + if (intval($channel['channel_system']) && intval($item['item_private'])) { + $p = []; break; } + if (count($p) > 100) { + $p = []; + break; + } + + array_unshift($p, [$a, $item]); + + if ($item['parent_mid'] === $item['mid']) { + break; + } } - $current_act = $a; + $current_item = $item; } - if($p) { - foreach($p as $pv) { - self::store($channel,$pv[0]->actor['id'],$pv[0],$pv[1],false); - if($pv[2]) - self::fetch_and_store_replies($channel, $pv[2]); + if ($p) { + foreach ($p as $pv) { + if ($pv[0]->is_valid()) { + Activity::store($channel, $observer_hash, $pv[0], $pv[1], false, $force); + } } return true; } @@ -2720,29 +2925,110 @@ class Activity { return false; } + /* + static public function fetch_and_store_parents($channel, $item) { + + logger('fetching parents'); + + $p = []; + + $current_item = $item; + + while ($current_item['parent_mid'] !== $current_item['mid']) { + $n = self::fetch($current_item['parent_mid'], $channel); + if (!$n) { + break; + } + $a = new ActivityStreams($n); + + //logger($a->debug()); + + if (!$a->is_valid()) { + break; + } + + if (is_array($a->actor) && array_key_exists('id', $a->actor)) { + self::actor_store($a->actor['id'], $a->actor); + } + + $replies = null; + if (isset($a->obj['replies']['first']['items'])) { + $replies = $a->obj['replies']['first']['items']; + // we already have this one + array_diff($replies, [$current_item['mid']]); + } + + $item = null; + + switch ($a->type) { + case 'Create': + case 'Update': + //case 'Like': + //case 'Dislike': + case 'Announce': + $item = self::decode_note($a); + break; + default: + break; + + } + + $hookinfo = [ + 'a' => $a, + 'item' => $item + ]; + + call_hooks('fetch_and_store', $hookinfo); + + $item = $hookinfo['item']; + + if ($item) { + + array_unshift($p, [$a, $item, $replies]); + + if ($item['parent_mid'] === $item['mid'] || count($p) > 20) { + break; + } + + } + $current_item = $item; + } + + if ($p) { + foreach ($p as $pv) { + self::store($channel, $pv[0]->actor['id'], $pv[0], $pv[1], false); + if ($pv[2]) + self::fetch_and_store_replies($channel, $pv[2]); + } + return true; + } + + return false; + } + */ static public function fetch_and_store_replies($channel, $arr) { logger('fetching replies'); - logger(print_r($arr,true)); + logger(print_r($arr, true)); $p = []; - foreach($arr as $url) { + foreach ($arr as $url) { $n = self::fetch($url, $channel); - if(! $n) { + if (!$n) { break; } $a = new ActivityStreams($n); - if(! $a->is_valid()) { + if (!$a->is_valid()) { break; } $item = null; - switch($a->type) { + switch ($a->type) { case 'Create': case 'Update': case 'Like': @@ -2755,29 +3041,29 @@ class Activity { } $hookinfo = [ - 'a' => $a, + 'a' => $a, 'item' => $item ]; - call_hooks('fetch_and_store',$hookinfo); + call_hooks('fetch_and_store', $hookinfo); $item = $hookinfo['item']; - if($item) { - array_unshift($p,[ $a, $item ]); + if ($item) { + array_unshift($p, [$a, $item]); } } - if($p) { - foreach($p as $pv) { - self::store($channel,$pv[0]->actor['id'],$pv[0],$pv[1],false); + if ($p) { + foreach ($p as $pv) { + self::store($channel, $pv[0]->actor['id'], $pv[0], $pv[1], false); } } } - static function announce_note($channel,$observer_hash,$act) { + static function announce_note($channel, $observer_hash, $act) { $s = []; @@ -2788,29 +3074,29 @@ class Activity { // This is not part of the activitypub protocol - we might change this to show all public posts in pubstream at some point. $pubstream = ((is_array($act->obj) && array_key_exists('to', $act->obj) && in_array(ACTIVITY_PUBLIC_INBOX, $act->obj['to'])) ? true : false); - if(! perm_is_allowed($channel['channel_id'],$observer_hash,'send_stream') && ! ($is_sys_channel && $pubstream)) { + if (!perm_is_allowed($channel['channel_id'], $observer_hash, 'send_stream') && !($is_sys_channel && $pubstream)) { logger('no permission'); return; } $content = self::get_content($act->obj); - if(! $content) { + if (!$content) { logger('no content'); return; } $s['owner_xchan'] = $s['author_xchan'] = $observer_hash; - $s['aid'] = $channel['channel_account_id']; - $s['uid'] = $channel['channel_id']; - $s['mid'] = urldecode($act->obj['id']); + $s['aid'] = $channel['channel_account_id']; + $s['uid'] = $channel['channel_id']; + $s['mid'] = urldecode($act->obj['id']); $s['plink'] = urldecode($act->obj['id']); - if(! $s['created']) + if (!$s['created']) $s['created'] = datetime_convert(); - if(! $s['edited']) + if (!$s['edited']) $s['edited'] = $s['created']; @@ -2820,8 +3106,8 @@ class Activity { $s['obj_type'] = ACTIVITY_OBJ_NOTE; $s['app'] = t('ActivityPub'); - if($channel['channel_system']) { - if(! \Zotlabs\Lib\MessageFilter::evaluate($s,get_config('system','pubstream_incl'),get_config('system','pubstream_excl'))) { + if ($channel['channel_system']) { + if (!MessageFilter::evaluate($s, get_config('system', 'pubstream_incl'), get_config('system', 'pubstream_excl'))) { logger('post is filtered'); return; } @@ -2832,61 +3118,61 @@ class Activity { intval($channel['channel_id']) ); - if($abook) { - if(! post_is_importable($s,$abook[0])) { + if ($abook) { + if (!post_is_importable($s, $abook[0])) { logger('post is filtered'); return; } } - if($act->obj['conversation']) { - set_iconfig($s,'ostatus','conversation',$act->obj['conversation'],1); + if ($act->obj['conversation']) { + set_iconfig($s, 'ostatus', 'conversation', $act->obj['conversation'], 1); } $a = self::decode_taxonomy($act->obj); - if($a) { + if ($a) { $s['term'] = $a; } $a = self::decode_attachment($act->obj); - if($a) { + if ($a) { $s['attach'] = $a; } - $body = "[share author='" . urlencode($act->sharee['name']) . - "' profile='" . $act->sharee['url'] . - "' avatar='" . $act->sharee['photo_s'] . - "' link='" . ((is_array($act->obj['url'])) ? $act->obj['url']['href'] : $act->obj['url']) . - "' auth='" . ((is_matrix_url($act->obj['url'])) ? 'true' : 'false' ) . - "' posted='" . $act->obj['published'] . - "' message_id='" . $act->obj['id'] . - "']"; + $body = "[share author='" . urlencode($act->sharee['name']) . + "' profile='" . $act->sharee['url'] . + "' avatar='" . $act->sharee['photo_s'] . + "' link='" . ((is_array($act->obj['url'])) ? $act->obj['url']['href'] : $act->obj['url']) . + "' auth='" . ((is_matrix_url($act->obj['url'])) ? 'true' : 'false') . + "' posted='" . $act->obj['published'] . + "' message_id='" . $act->obj['id'] . + "']"; - if($content['name']) - $body .= self::bb_content($content,'name') . "\r\n"; + if ($content['name']) + $body .= self::bb_content($content, 'name') . "\r\n"; - $body .= self::bb_content($content,'content'); + $body .= self::bb_content($content, 'content'); - if($act->obj['type'] === 'Note' && $s['attach']) { - $body .= self::bb_attach($s['attach'],$body); + if ($act->obj['type'] === 'Note' && $s['attach']) { + $body .= self::bb_attach($s['attach'], $body); } $body .= "[/share]"; - $s['title'] = self::bb_content($content,'name'); - $s['body'] = $body; + $s['title'] = self::bb_content($content, 'name'); + $s['body'] = $body; - if($act->recips && (! in_array(ACTIVITY_PUBLIC_INBOX,$act->recips))) + if ($act->recips && (!in_array(ACTIVITY_PUBLIC_INBOX, $act->recips))) $s['item_private'] = 1; - set_iconfig($s,'activitypub','recips',$act->raw_recips); + set_iconfig($s, 'activitypub', 'recips', $act->raw_recips); $r = q("select created, edited from item where mid = '%s' and uid = %d limit 1", dbesc($s['mid']), intval($s['uid']) ); - if($r) { - if($s['edited'] > $r[0]['edited']) { + if ($r) { + if ($s['edited'] > $r[0]['edited']) { $x = item_store_update($s); } else { @@ -2897,35 +3183,35 @@ class Activity { $x = item_store($s); } - if(is_array($x) && $x['item_id']) { - if($s['owner_xchan'] === $channel['channel_hash']) { + if (is_array($x) && $x['item_id']) { + if ($s['owner_xchan'] === $channel['channel_hash']) { // We are the owner of this conversation, so send all received comments back downstream - Master::Summon(array('Notifier','comment-import',$x['item_id'])); + Master::Summon(['Notifier', 'comment-import', $x['item_id']]); } $r = q("select * from item where id = %d limit 1", intval($x['item_id']) ); - if($r) { - send_status_notifications($x['item_id'],$r[0]); + if ($r) { + send_status_notifications($x['item_id'], $r[0]); } - sync_an_item($channel['channel_id'],$x['item_id']); + sync_an_item($channel['channel_id'], $x['item_id']); } } - static function like_note($channel,$observer_hash,$act) { + static function like_note($channel, $observer_hash, $act) { $s = []; $parent = $act->obj['id']; - - if($act->type === 'Like') + + if ($act->type === 'Like') $s['verb'] = ACTIVITY_LIKE; - if($act->type === 'Dislike') + if ($act->type === 'Dislike') $s['verb'] = ACTIVITY_DISLIKE; - if(! $parent) + if (!$parent) return; $r = q("select * from item where uid = %d and ( mid = '%s' or mid = '%s' ) limit 1", @@ -2934,7 +3220,7 @@ class Activity { dbesc(urldecode(basename($parent))) ); - if(! $r) { + if (!$r) { logger('parent not found.'); return; } @@ -2942,14 +3228,14 @@ class Activity { xchan_query($r); $parent_item = $r[0]; - if($parent_item['owner_xchan'] === $channel['channel_hash']) { - if(! perm_is_allowed($channel['channel_id'],$observer_hash,'post_comments')) { + if ($parent_item['owner_xchan'] === $channel['channel_hash']) { + if (!perm_is_allowed($channel['channel_id'], $observer_hash, 'post_comments')) { logger('no comment permission.'); return; } } - if($parent_item['mid'] === $parent_item['parent_mid']) { + if ($parent_item['mid'] === $parent_item['parent_mid']) { $s['parent_mid'] = $parent_item['mid']; } else { @@ -2957,31 +3243,29 @@ class Activity { $s['parent_mid'] = $parent_item['parent_mid']; } - $s['owner_xchan'] = $parent_item['owner_xchan']; + $s['owner_xchan'] = $parent_item['owner_xchan']; $s['author_xchan'] = $observer_hash; - + $s['aid'] = $channel['channel_account_id']; $s['uid'] = $channel['channel_id']; $s['mid'] = $act->id; - if(! $s['parent_mid']) + if (!$s['parent_mid']) $s['parent_mid'] = $s['mid']; - + $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 ); - - $body = $parent_item['body']; + $links = [['rel' => 'alternate', 'type' => 'text/html', 'href' => $parent_item['plink']]]; + $objtype = (($parent_item['resource_type'] === 'photo') ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE); $z = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($parent_item['author_xchan']) ); - if($z) - $item_author = $z[0]; + if ($z) + $item_author = $z[0]; - $object = json_encode(array( + $object = json_encode([ 'type' => $post_type, 'id' => $parent_item['mid'], 'parent' => (($parent_item['thr_parent']) ? $parent_item['thr_parent'] : $parent_item['parent_mid']), @@ -2990,77 +3274,75 @@ class Activity { 'content' => $parent_item['body'], 'created' => $parent_item['created'], 'edited' => $parent_item['edited'], - 'author' => array( + 'author' => [ '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'])), - ), - ), JSON_UNESCAPED_SLASHES + 'link' => [ + ['rel' => 'alternate', 'type' => 'text/html', 'href' => $item_author['xchan_url']], + ['rel' => 'photo', 'type' => $item_author['xchan_photo_mimetype'], 'href' => $item_author['xchan_photo_m']]], + ], + ], JSON_UNESCAPED_SLASHES ); - if($act->type === 'Like') + if ($act->type === 'Like') $bodyverb = t('%1$s likes %2$s\'s %3$s'); - if($act->type === 'Dislike') + if ($act->type === 'Dislike') $bodyverb = t('%1$s doesn\'t like %2$s\'s %3$s'); - $ulink = '[url=' . $item_author['xchan_url'] . ']' . $item_author['xchan_name'] . '[/url]'; - $alink = '[url=' . $parent_item['author']['xchan_url'] . ']' . $parent_item['author']['xchan_name'] . '[/url]'; - $plink = '[url='. z_root() . '/display/' . urlencode($act->id) . ']' . $post_type . '[/url]'; - $s['body'] = sprintf( $bodyverb, $ulink, $alink, $plink ); + $ulink = '[url=' . $item_author['xchan_url'] . ']' . $item_author['xchan_name'] . '[/url]'; + $alink = '[url=' . $parent_item['author']['xchan_url'] . ']' . $parent_item['author']['xchan_name'] . '[/url]'; + $plink = '[url=' . z_root() . '/display/' . urlencode($act->id) . ']' . $post_type . '[/url]'; + $s['body'] = sprintf($bodyverb, $ulink, $alink, $plink); - $s['app'] = t('ActivityPub'); + $s['app'] = t('ActivityPub'); // set the route to that of the parent so downstream hubs won't reject it. - $s['route'] = $parent_item['route']; + $s['route'] = $parent_item['route']; $s['item_private'] = $parent_item['item_private']; - $s['obj_type'] = $objtype; - $s['obj'] = $object; + $s['obj_type'] = $objtype; + $s['obj'] = $object; - if($act->obj['conversation']) { - set_iconfig($s,'ostatus','conversation',$act->obj['conversation'],1); + if ($act->obj['conversation']) { + set_iconfig($s, 'ostatus', 'conversation', $act->obj['conversation'], 1); } - if($act->recips && (! in_array(ACTIVITY_PUBLIC_INBOX,$act->recips))) + if ($act->recips && (!in_array(ACTIVITY_PUBLIC_INBOX, $act->recips))) $s['item_private'] = 1; - set_iconfig($s,'activitypub','recips',$act->raw_recips); + set_iconfig($s, 'activitypub', 'recips', $act->raw_recips); $result = item_store($s); - if($result['success']) { + if ($result['success']) { // if the message isn't already being relayed, notify others - if(intval($parent_item['item_origin'])) - Master::Summon(array('Notifier','comment-import',$result['item_id'])); - sync_an_item($channel['channel_id'],$result['item_id']); + if (intval($parent_item['item_origin'])) + Master::Summon(['Notifier', 'comment-import', $result['item_id']]); + sync_an_item($channel['channel_id'], $result['item_id']); } return; } - - - static function bb_attach($attach,$body) { + static function bb_attach($attach, $body) { $ret = false; - foreach($attach as $a) { - if(strpos($a['type'],'image') !== false) { - if(self::media_not_in_body($a['href'],$body)) { + foreach ($attach as $a) { + if (array_key_exists('type',$a) && stripos($a['type'], 'image') !== false) { + if (self::media_not_in_body($a['href'], $body)) { $ret .= "\n\n" . '[img]' . $a['href'] . '[/img]'; } } - if(array_key_exists('type',$a) && strpos($a['type'], 'video') === 0) { - if(self::media_not_in_body($a['href'],$body)) { + if (array_key_exists('type', $a) && stripos($a['type'], 'video') !== false) { + if (self::media_not_in_body($a['href'], $body)) { $ret .= "\n\n" . '[video]' . $a['href'] . '[/video]'; } } - if(array_key_exists('type',$a) && strpos($a['type'], 'audio') === 0) { - if(self::media_not_in_body($a['href'],$body)) { + if (array_key_exists('type', $a) && stripos($a['type'], 'audio') !== false) { + if (self::media_not_in_body($a['href'], $body)) { $ret .= "\n\n" . '[audio]' . $a['href'] . '[/audio]'; } } @@ -3069,116 +3351,109 @@ class Activity { return $ret; } - // check for the existence of existing media link in body + static function media_not_in_body($s, $body) { - static function media_not_in_body($s,$body) { - - if((strpos($body,']' . $s . '[/img]') === false) && - (strpos($body,']' . $s . '[/zmg]') === false) && - (strpos($body,']' . $s . '[/video]') === false) && - (strpos($body,']' . $s . '[/audio]') === false)) { + if ((strpos($body, ']' . $s . '[/img]') === false) && + (strpos($body, ']' . $s . '[/zmg]') === false) && + (strpos($body, ']' . $s . '[/video]') === false) && + (strpos($body, ']' . $s . '[/audio]') === false)) { return true; } return false; } - - static function bb_content($content,$field) { + static function bb_content($content, $field) { require_once('include/html2bbcode.php'); require_once('include/event.php'); $ret = false; - if(is_array($content[$field])) { - foreach($content[$field] as $k => $v) { + if (is_array($content[$field])) { + foreach ($content[$field] as $k => $v) { $ret .= html2bbcode($v); // save this for auto-translate or dynamic filtering // $ret .= '[language=' . $k . ']' . html2bbcode($v) . '[/language]'; } } else { - if($field === 'bbcode' && array_key_exists('bbcode',$content)) { + if ($field === 'bbcode' && array_key_exists('bbcode', $content)) { $ret = $content[$field]; } else { $ret = html2bbcode($content[$field]); } } - if($field === 'content' && $content['event'] && (! strpos($ret,'[event'))) { + if ($field === 'content' && $content['event'] && (!strpos($ret, '[event'))) { $ret .= format_event_bbcode($content['event']); } return $ret; } - static function get_content($act) { $content = []; - $event = null; + $event = null; - if ((! $act) || (! is_array($act))) { + if ((!$act) || (!is_array($act))) { return $content; } - if($act['type'] === 'Event') { - $adjust = false; - $event = []; - $event['event_hash'] = $act['id']; - if(array_key_exists('startTime',$act) && strpos($act['startTime'],-1,1) === 'Z') { - $adjust = true; - $event['adjust'] = 1; - $event['dtstart'] = datetime_convert('UTC','UTC',$event['startTime'] . (($adjust) ? '' : 'Z')); - } - if(array_key_exists('endTime',$act)) { - $event['dtend'] = datetime_convert('UTC','UTC',$event['endTime'] . (($adjust) ? '' : 'Z')); - } - else { - $event['nofinish'] = true; - } - } + if ($act['type'] === 'Event') { + $adjust = false; + $event = []; + $event['event_hash'] = $act['id']; + if (array_key_exists('startTime', $act) && strpos($act['startTime'], -1, 1) === 'Z') { + $adjust = true; + $event['adjust'] = 1; + $event['dtstart'] = datetime_convert('UTC', 'UTC', $event['startTime'] . (($adjust) ? '' : 'Z')); + } + if (array_key_exists('endTime', $act)) { + $event['dtend'] = datetime_convert('UTC', 'UTC', $event['endTime'] . (($adjust) ? '' : 'Z')); + } + else { + $event['nofinish'] = true; + } + } - foreach ([ 'name', 'summary', 'content' ] as $a) { - if (($x = self::get_textfield($act,$a)) !== false) { + foreach (['name', 'summary', 'content'] as $a) { + if (($x = self::get_textfield($act, $a)) !== false) { $content[$a] = $x; } } - if($event) { + if ($event) { $event['summary'] = $content['name']; - if(! $event['summary']) { - if($content['summary']) { + if (!$event['summary']) { + if ($content['summary']) { $event['summary'] = html2plain($content['summary']); } } $event['description'] = html2bbcode($content['content']); - if($event['summary'] && $event['dtstart']) { + if ($event['summary'] && $event['dtstart']) { $content['event'] = $event; } } - if (array_path_exists('source/mediaType',$act) && array_path_exists('source/content',$act)) { + 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']); } } - - return $content; } + static function get_textfield($act, $field) { - static function get_textfield($act,$field) { - $content = false; - if(array_key_exists($field,$act) && $act[$field]) + if (array_key_exists($field, $act) && $act[$field]) $content = purify_html($act[$field]); - elseif(array_key_exists($field . 'Map',$act) && $act[$field . 'Map']) { - foreach($act[$field . 'Map'] as $k => $v) { + elseif (array_key_exists($field . 'Map', $act) && $act[$field . 'Map']) { + foreach ($act[$field . 'Map'] as $k => $v) { $content[escape_tags($k)] = purify_html($v); } } @@ -3187,11 +3462,10 @@ class Activity { // 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) + 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 ); @@ -3200,8 +3474,8 @@ class Activity { } } - if (! $auth) { - if (array_key_exists('token',$_REQUEST) && $_REQUEST['token']) { + if (!$auth) { + if (array_key_exists('token', $_REQUEST) && $_REQUEST['token']) { $auth = $_REQUEST['token']; } } @@ -3211,7 +3485,7 @@ class Activity { static function find_best_identity($xchan) { - if(filter_var($xchan, FILTER_VALIDATE_URL)) { + 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) ); diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php index f877fbb45..ba7ec0c65 100644 --- a/Zotlabs/Lib/ActivityStreams.php +++ b/Zotlabs/Lib/ActivityStreams.php @@ -7,25 +7,24 @@ namespace Zotlabs\Lib; * * Parses an ActivityStream JSON string. */ - class ActivityStreams { - public $raw = null; - public $data = null; - public $valid = false; - public $deleted = false; - public $id = ''; - public $parent_id = ''; - public $type = ''; - public $actor = null; - public $obj = null; - public $tgt = null; - public $origin = null; - public $owner = null; - public $signer = null; - public $ldsig = null; - public $sigok = false; - public $recips = null; + public $raw = null; + public $data = null; + public $valid = false; + public $deleted = false; + public $id = ''; + public $parent_id = ''; + public $type = ''; + public $actor = null; + public $obj = null; + public $tgt = null; + public $origin = null; + public $owner = null; + public $signer = null; + public $ldsig = null; + public $sigok = false; + public $recips = null; public $raw_recips = null; /** @@ -37,29 +36,29 @@ class ActivityStreams { */ function __construct($string) { - $this->raw = $string; + $this->raw = $string; - if(is_array($string)) { + if (is_array($string)) { $this->data = $string; } else { $this->data = json_decode($string, true); } - if($this->data) { + if ($this->data) { // verify and unpack JSalmon signature if present - if(is_array($this->data) && array_key_exists('signed',$this->data)) { + if (is_array($this->data) && array_key_exists('signed', $this->data)) { $ret = JSalmon::verify($this->data); $tmp = JSalmon::unpack($this->data['data']); - if($ret && $ret['success']) { - if($ret['signer']) { - $saved = json_encode($this->data,JSON_UNESCAPED_SLASHES); - $this->data = $tmp; - $this->data['signer'] = $ret['signer']; + if ($ret && $ret['success']) { + if ($ret['signer']) { + $saved = json_encode($this->data, JSON_UNESCAPED_SLASHES); + $this->data = $tmp; + $this->data['signer'] = $ret['signer']; $this->data['signed_data'] = $saved; - if($ret['hubloc']) { + if ($ret['hubloc']) { $this->data['hubloc'] = $ret['hubloc']; } } @@ -68,57 +67,57 @@ class ActivityStreams { $this->valid = true; - if(array_key_exists('type',$this->data) && array_key_exists('actor',$this->data) && array_key_exists('object',$this->data)) { - if($this->data['type'] === 'Delete' && $this->data['actor'] === $this->data['object']) { + if (array_key_exists('type', $this->data) && array_key_exists('actor', $this->data) && array_key_exists('object', $this->data)) { + if ($this->data['type'] === 'Delete' && $this->data['actor'] === $this->data['object']) { $this->deleted = $this->data['actor']; - $this->valid = false; + $this->valid = false; } } } - if($this->is_valid()) { + if ($this->is_valid()) { $this->id = $this->get_property_obj('id'); $this->type = $this->get_primary_type(); - $this->actor = $this->get_actor('actor','',''); + $this->actor = $this->get_actor('actor', '', ''); $this->obj = $this->get_compound_property('object'); $this->tgt = $this->get_compound_property('target'); $this->origin = $this->get_compound_property('origin'); $this->recips = $this->collect_recips(); $this->ldsig = $this->get_compound_property('signature'); - if($this->ldsig) { - $this->signer = $this->get_compound_property('creator',$this->ldsig); - if($this->signer && is_array($this->signer) && array_key_exists('publicKey',$this->signer) && is_array($this->signer['publicKey']) && $this->signer['publicKey']['publicKeyPem']) { - $this->sigok = LDSignatures::verify($this->data,$this->signer['publicKey']['publicKeyPem']); + if ($this->ldsig) { + $this->signer = $this->get_compound_property('creator', $this->ldsig); + if ($this->signer && is_array($this->signer) && array_key_exists('publicKey', $this->signer) && is_array($this->signer['publicKey']) && $this->signer['publicKey']['publicKeyPem']) { + $this->sigok = LDSignatures::verify($this->data, $this->signer['publicKey']['publicKeyPem']); } } - if(! $this->obj) { - $this->obj = $this->data; + if (!$this->obj) { + $this->obj = $this->data; $this->type = 'Create'; - if(! $this->actor) { - $this->actor = $this->get_actor('attributedTo',$this->obj); + if (!$this->actor) { + $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)) { + 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']) - $this->tgt['actor'] = $this->get_actor('actor',$this->tgt); + 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']) + $this->tgt['actor'] = $this->get_actor('actor', $this->tgt); $this->parent_id = $this->get_property_obj('inReplyTo'); - if((! $this->parent_id) && is_array($this->obj)) { + if ((!$this->parent_id) && is_array($this->obj)) { $this->parent_id = $this->obj['inReplyTo']; } - if((! $this->parent_id) && is_array($this->obj)) { + if ((!$this->parent_id) && is_array($this->obj)) { $this->parent_id = $this->obj['id']; } } @@ -147,19 +146,19 @@ class ActivityStreams { function collect_recips($base = '', $namespace = '') { $x = []; - $fields = [ 'to', 'cc', 'bto', 'bcc', 'audience']; - foreach($fields as $f) { + $fields = ['to', 'cc', 'bto', 'bcc', 'audience']; + foreach ($fields as $f) { $y = $this->get_compound_property($f, $base, $namespace); - if($y) { - if (! is_array($this->raw_recips)) { + if ($y) { + if (!is_array($this->raw_recips)) { $this->raw_recips = []; } - if (! is_array($y)) { - $y = [ $y ]; + if (!is_array($y)) { + $y = [$y]; } $this->raw_recips[$f] = $y; - $x = array_merge($x, $y); + $x = array_merge($x, $y); } } // not yet ready for prime time @@ -167,21 +166,21 @@ class ActivityStreams { return $x; } - function expand($arr,$base = '',$namespace = '') { + function expand($arr, $base = '', $namespace = '') { $ret = []; // right now use a hardwired recursion depth of 5 - for($z = 0; $z < 5; $z ++) { - if(is_array($arr) && $arr) { - foreach($arr as $a) { - if(is_array($a)) { + for ($z = 0; $z < 5; $z++) { + if (is_array($arr) && $arr) { + foreach ($arr as $a) { + if (is_array($a)) { $ret[] = $a; } else { - $x = $this->get_compound_property($a,$base,$namespace); - if($x) { - $ret = array_merge($ret,$x); + $x = $this->get_compound_property($a, $base, $namespace); + if ($x) { + $ret = array_merge($ret, $x); } } } @@ -202,33 +201,33 @@ class ActivityStreams { */ function get_namespace($base, $namespace) { - if(! $namespace) + if (!$namespace) return ''; $key = null; - foreach( [ $this->data, $base ] as $b ) { - if(! $b) + foreach ([$this->data, $base] as $b) { + if (!$b) continue; - if(array_key_exists('@context', $b)) { - if(is_array($b['@context'])) { - foreach($b['@context'] as $ns) { - if(is_array($ns)) { - foreach($ns as $k => $v) { - if($namespace === $v) + if (array_key_exists('@context', $b)) { + if (is_array($b['@context'])) { + foreach ($b['@context'] as $ns) { + if (is_array($ns)) { + foreach ($ns as $k => $v) { + if ($namespace === $v) $key = $k; } } else { - if($namespace === $ns) { + if ($namespace === $ns) { $key = ''; } } } } else { - if($namespace === $b['@context']) { + if ($namespace === $b['@context']) { $key = ''; } } @@ -248,14 +247,14 @@ class ActivityStreams { */ function get_property_obj($property, $base = '', $namespace = '') { $prefix = $this->get_namespace($base, $namespace); - if($prefix === null) + if ($prefix === null) return null; - $base = (($base) ? $base : $this->data); + $base = (($base) ? $base : $this->data); $propname = (($prefix) ? $prefix . ':' : '') . $property; - if(! is_array($base)) { - btlogger('not an array: ' . print_r($base,true)); + if (!is_array($base)) { + btlogger('not an array: ' . print_r($base, true)); return null; } @@ -279,14 +278,14 @@ class ActivityStreams { } 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) { + if (!$s) { return false; } - return (in_array($s, [ 'Like', 'Dislike', 'Flag', 'Block', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject', 'emojiReaction', 'EmojiReaction', 'EmojiReact' ])); + return (in_array($s, ['Like', 'Dislike', 'Flag', 'Block', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject', 'emojiReaction', 'EmojiReaction', 'EmojiReact'])); } /** @@ -298,9 +297,9 @@ class ActivityStreams { * @return NULL|mixed */ - function get_actor($property,$base='',$namespace = '') { + function get_actor($property, $base = '', $namespace = '') { $x = $this->get_property_obj($property, $base, $namespace); - if($this->is_url($x)) { + if ($this->is_url($x)) { // SECURITY: If we have already stored the actor profile, re-generate it // from cached data - don't refetch it from the network @@ -308,15 +307,15 @@ class ActivityStreams { $r = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_id_url = '%s' limit 1", dbesc($x) ); - if($r) { - $y = Activity::encode_person($r[0]); + if ($r) { + $y = Activity::encode_person($r[0]); $y['cached'] = true; return $y; } } - $actor = $this->get_compound_property($property,$base,$namespace,true); - if(is_array($actor) && self::is_an_actor($actor['type'])) { - if(array_key_exists('id',$actor) && (! array_key_exists('inbox',$actor))) { + $actor = $this->get_compound_property($property, $base, $namespace, true); + if (is_array($actor) && self::is_an_actor($actor['type'])) { + if (array_key_exists('id', $actor) && (!array_key_exists('inbox', $actor))) { $actor = $this->fetch_property($actor['id']); } return $actor; @@ -336,7 +335,7 @@ class ActivityStreams { */ function get_compound_property($property, $base = '', $namespace = '', $first = false) { $x = $this->get_property_obj($property, $base, $namespace); - if($this->is_url($x)) { + if ($this->is_url($x)) { $y = $this->fetch_property($x); if (is_array($y)) { $x = $y; @@ -345,22 +344,22 @@ class ActivityStreams { // verify and unpack JSalmon signature if present - if(is_array($x) && array_key_exists('signed',$x)) { + if (is_array($x) && array_key_exists('signed', $x)) { $ret = JSalmon::verify($x); $tmp = JSalmon::unpack($x['data']); - if($ret && $ret['success']) { - if($ret['signer']) { - $saved = json_encode($x,JSON_UNESCAPED_SLASHES); - $x = $tmp; - $x['signer'] = $ret['signer']; + if ($ret && $ret['success']) { + if ($ret['signer']) { + $saved = json_encode($x, JSON_UNESCAPED_SLASHES); + $x = $tmp; + $x['signer'] = $ret['signer']; $x['signed_data'] = $saved; - if($ret['hubloc']) { + if ($ret['hubloc']) { $x['hubloc'] = $ret['hubloc']; } } } } - if($first && is_array($x) && array_key_exists(0,$x)) { + if ($first && is_array($x) && array_key_exists(0, $x)) { return $x[0]; } @@ -374,7 +373,7 @@ class ActivityStreams { * @return boolean */ function is_url($url) { - if(($url) && (! is_array($url)) && (strpos($url, 'http') === 0)) { + if (($url) && (!is_array($url)) && (strpos($url, 'http') === 0)) { return true; } @@ -389,13 +388,13 @@ class ActivityStreams { * @return NULL|mixed */ function get_primary_type($base = '', $namespace = '') { - if(! $base) + if (!$base) $base = $this->data; $x = $this->get_property_obj('type', $base, $namespace); - if(is_array($x)) { - foreach($x as $y) { - if(strpos($y, ':') === false) { + if (is_array($x)) { + foreach ($x as $y) { + if (strpos($y, ':') === false) { return $y; } } @@ -409,15 +408,32 @@ class ActivityStreams { return $x; } - static function is_as_request() { + static function is_as_request($channel = null) { - $x = getBestSupportedMimeType([ - 'application/ld+json;profile="https://www.w3.org/ns/activitystreams"', - 'application/activity+json', - 'application/ld+json;profile="http://www.w3.org/ns/activitystreams"' - ]); + $hookdata = []; + if ($channel) + $hookdata['channel'] = $channel; - return(($x) ? true : false); + $hookdata['data'] = ['application/x-zot-activity+json']; + + call_hooks('is_as_request', $hookdata); + + $x = getBestSupportedMimeType($hookdata['data']); + return (($x) ? true : false); + + } + + static function get_accept_header_string($channel = null) { + + $hookdata = []; + if ($channel) + $hookdata['channel'] = $channel; + + $hookdata['data'] = 'application/x-zot-activity+json'; + + call_hooks('get_accept_header_string', $hookdata); + + return $hookdata['data']; } diff --git a/Zotlabs/Lib/Apps.php b/Zotlabs/Lib/Apps.php index 7b980b8d3..d77a3fda2 100644 --- a/Zotlabs/Lib/Apps.php +++ b/Zotlabs/Lib/Apps.php @@ -307,7 +307,7 @@ class Apps { } } } - if($ret) { + if(isset($ret)) { if($translate) self::translate_system_apps($ret); @@ -524,7 +524,7 @@ class Apps { } elseif(remote_channel()) { $observer = \App::get_observer(); - if($observer && $observer['xchan_network'] === 'zot') { + if($observer && in_array($observer['xchan_network'], ['zot6', 'zot'])) { // some folks might have xchan_url redirected offsite, use the connurl $x = parse_url($observer['xchan_connurl']); if($x) { diff --git a/Zotlabs/Lib/Crypto.php b/Zotlabs/Lib/Crypto.php new file mode 100644 index 000000000..f1794ae64 --- /dev/null +++ b/Zotlabs/Lib/Crypto.php @@ -0,0 +1,206 @@ + 'sha1', + 'private_key_bits' => $bits, + 'encrypt_key' => false + ]; + + $conf = get_config('system', 'openssl_conf_file'); + + if ($conf) { + $openssl_options['config'] = $conf; + } + + $result = openssl_pkey_new($openssl_options); + + if (empty($result)) { + return false; + } + + // Get private key + + $response = ['prvkey' => '', 'pubkey' => '']; + + openssl_pkey_export($result, $response['prvkey']); + + // Get public key + $pkey = openssl_pkey_get_details($result); + $response['pubkey'] = $pkey["key"]; + + return $response; + + } + + public static function sign($data, $key, $alg = 'sha256') { + + if (!$key) { + return false; + } + + $sig = ''; + openssl_sign($data, $sig, $key, $alg); + return $sig; + } + + public static function verify($data, $sig, $key, $alg = 'sha256') { + + if (!$key) { + return false; + } + + try { + $verify = openssl_verify($data, $sig, $key, $alg); + } catch (Exception $e) { + $verify = (-1); + } + + if ($verify === (-1)) { + while ($msg = openssl_error_string()) { + logger('openssl_verify: ' . $msg, LOGGER_NORMAL, LOG_ERR); + } + btlogger('openssl_verify: key: ' . $key, LOGGER_DEBUG, LOG_ERR); + } + + return (($verify > 0) ? true : false); + } + + public static function encapsulate($data, $pubkey, $alg) { + + if (!($alg && $pubkey)) { + return $data; + } + + $alg_base = $alg; + $padding = OPENSSL_PKCS1_PADDING; + + $exts = explode('.', $alg); + if (count($exts) > 1) { + switch ($exts[1]) { + case 'oaep': + $padding = OPENSSL_PKCS1_OAEP_PADDING; + break; + default: + break; + } + $alg_base = $exts[0]; + } + + $method = null; + + foreach (self::$openssl_algorithms as $ossl) { + if ($ossl[0] === $alg_base) { + $method = $ossl; + break; + } + } + + if ($method) { + $result = ['encrypted' => true]; + + $key = openssl_random_pseudo_bytes(256); + $iv = openssl_random_pseudo_bytes(256); + + $key1 = substr($key, 0, $method[2]); + $iv1 = substr($iv, 0, $method[3]); + + $result['data'] = base64url_encode(openssl_encrypt($data, $method[1], $key1, OPENSSL_RAW_DATA, $iv1), true); + + openssl_public_encrypt($key, $k, $pubkey, $padding); + openssl_public_encrypt($iv, $i, $pubkey, $padding); + + $result['alg'] = $alg; + $result['key'] = base64url_encode($k, true); + $result['iv'] = base64url_encode($i, true); + return $result; + + } + else { + $x = ['data' => $data, 'pubkey' => $pubkey, 'alg' => $alg, 'result' => $data]; + call_hooks('crypto_encapsulate', $x); + return $x['result']; + } + } + + public static function unencapsulate($data, $prvkey) { + + if (!(is_array($data) && array_key_exists('encrypted', $data) && array_key_exists('alg', $data) && $data['alg'])) { + logger('not encrypted'); + + return $data; + } + + $alg_base = $data['alg']; + $padding = OPENSSL_PKCS1_PADDING; + + $exts = explode('.', $data['alg']); + if (count($exts) > 1) { + switch ($exts[1]) { + case 'oaep': + $padding = OPENSSL_PKCS1_OAEP_PADDING; + break; + default: + break; + } + $alg_base = $exts[0]; + } + + $method = null; + + foreach (self::$openssl_algorithms as $ossl) { + if ($ossl[0] === $alg_base) { + $method = $ossl; + break; + } + } + + if ($method) { + openssl_private_decrypt(base64url_decode($data['key']), $k, $prvkey, $padding); + openssl_private_decrypt(base64url_decode($data['iv']), $i, $prvkey, $padding); + return openssl_decrypt(base64url_decode($data['data']), $method[1], substr($k, 0, $method[2]), OPENSSL_RAW_DATA, substr($i, 0, $method[3])); + } + else { + $x = ['data' => $data, 'prvkey' => $prvkey, 'alg' => $data['alg'], 'result' => $data]; + call_hooks('crypto_unencapsulate', $x); + return $x['result']; + } + } +} diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php index 3a24cd349..d2a0f0abc 100644 --- a/Zotlabs/Lib/Enotify.php +++ b/Zotlabs/Lib/Enotify.php @@ -43,7 +43,7 @@ class Enotify { dbesc($params['to_xchan']) ); } - if ($x & $y) { + if ($x && $y) { $sender = $x[0]; $recip = $y[0]; } else { diff --git a/Zotlabs/Lib/Hashpath.php b/Zotlabs/Lib/Hashpath.php new file mode 100644 index 000000000..f3b25d2b6 --- /dev/null +++ b/Zotlabs/Lib/Hashpath.php @@ -0,0 +1,55 @@ + true, @@ -54,7 +54,7 @@ class JSalmon { $key = HTTPSig::get_key(EMPTY_STR,'zot6',base64url_decode($x['sigs']['key_id'])); logger('key: ' . print_r($key,true)); if($key['portable_id'] && $key['public_key']) { - if(rsa_verify($signed_data,base64url_decode($x['sigs']['value']),$key['public_key'])) { + if(Crypto::verify($signed_data,base64url_decode($x['sigs']['value']),$key['public_key'])) { logger('verified'); $ret = [ 'success' => true, 'signer' => $key['portable_id'], 'hubloc' => $key['hubloc'] ]; } diff --git a/Zotlabs/Lib/Keyutils.php b/Zotlabs/Lib/Keyutils.php new file mode 100644 index 000000000..616ecfcf6 --- /dev/null +++ b/Zotlabs/Lib/Keyutils.php @@ -0,0 +1,99 @@ +loadKey([ + 'e' => new BigInteger($e, 256), + 'n' => new BigInteger($m, 256) + ]); + return $rsa->getPublicKey(); + + } + + /** + * @param string key + * @return string + */ + public static function rsaToPem($key) { + + $rsa = new RSA(); + $rsa->setPublicKey($key); + + return $rsa->getPublicKey(RSA::PUBLIC_FORMAT_PKCS8); + + } + + /** + * @param string key + * @return string + */ + public static function pemToRsa($key) { + + $rsa = new RSA(); + $rsa->setPublicKey($key); + + return $rsa->getPublicKey(RSA::PUBLIC_FORMAT_PKCS1); + + } + + /** + * @param string $key key + * @param string $m reference modulo + * @param string $e reference exponent + */ + public static function pemToMe($key, &$m, &$e) { + + $rsa = new RSA(); + $rsa->loadKey($key); + $rsa->setPublicKey(); + + $m = $rsa->modulus->toBytes(); + $e = $rsa->exponent->toBytes(); + + } + + /** + * @param string $pubkey + * @return string + */ + public static function salmonKey($pubkey) { + self::pemToMe($pubkey, $m, $e); + return 'RSA' . '.' . base64url_encode($m, true) . '.' . base64url_encode($e, true); + } + + /** + * @param string $key + * @return string + */ + public static function convertSalmonKey($key) { + if (strstr($key, ',')) + $rawkey = substr($key, strpos($key, ',') + 1); + else + $rawkey = substr($key, 5); + + $key_info = explode('.', $rawkey); + + $m = base64url_decode($key_info[1]); + $e = base64url_decode($key_info[2]); + + return self::meToPem($m, $e); + } + +} \ No newline at end of file diff --git a/Zotlabs/Lib/LDSignatures.php b/Zotlabs/Lib/LDSignatures.php index 2eba66ccf..1c2095f10 100644 --- a/Zotlabs/Lib/LDSignatures.php +++ b/Zotlabs/Lib/LDSignatures.php @@ -12,7 +12,7 @@ class LDSignatures { $ohash = self::hash(self::signable_options($data['signature'])); $dhash = self::hash(self::signable_data($data)); - $x = rsa_verify($ohash . $dhash,base64_decode($data['signature']['signatureValue']), $pubkey); + $x = Crypto::verify($ohash . $dhash,base64_decode($data['signature']['signatureValue']), $pubkey); logger('LD-verify: ' . intval($x)); return $x; @@ -35,11 +35,11 @@ class LDSignatures { $ohash = self::hash(self::signable_options($options)); $dhash = self::hash(self::signable_data($data)); - $options['signatureValue'] = base64_encode(rsa_sign($ohash . $dhash,$channel['channel_prvkey'])); + $options['signatureValue'] = base64_encode(Crypto::sign($ohash . $dhash,$channel['channel_prvkey'])); $signed = array_merge([ - '@context' => [ - ACTIVITYSTREAMS_JSONLD_REV, + '@context' => [ + ACTIVITYSTREAMS_JSONLD_REV, 'https://w3id.org/security/v1' ], ],$options); @@ -88,7 +88,7 @@ class LDSignatures { return ''; jsonld_set_document_loader('jsonld_document_loader'); - + try { $d = jsonld_normalize($data,[ 'algorithm' => 'URDNA2015', 'format' => 'application/nquads' ]); } @@ -117,7 +117,7 @@ class LDSignatures { $precomputed = '.' . base64url_encode($data_type,false) . '.YmFzZTY0dXJs.UlNBLVNIQTI1Ng=='; - $signature = base64url_encode(rsa_sign($data . $precomputed,$channel['channel_prvkey'])); + $signature = base64url_encode(Crypto::sign($data . $precomputed,$channel['channel_prvkey'])); return ([ 'id' => $arr['id'], diff --git a/Zotlabs/Lib/Libsync.php b/Zotlabs/Lib/Libsync.php index 7b968532a..e16b68cf8 100644 --- a/Zotlabs/Lib/Libsync.php +++ b/Zotlabs/Lib/Libsync.php @@ -2,9 +2,9 @@ namespace Zotlabs\Lib; -use Zotlabs\Lib\Libzot; -use Zotlabs\Lib\Queue; +use App; +use Zotlabs\Daemon\Master; class Libsync { @@ -23,21 +23,21 @@ class Libsync { logger('build_sync_packet'); - $keychange = (($packet && array_key_exists('keychange',$packet)) ? true : false); - if($keychange) { + $keychange = (($packet && array_key_exists('keychange', $packet)) ? true : false); + if ($keychange) { logger('keychange sync'); } - if(! $uid) + if (!$uid) $uid = local_channel(); - if(! $uid) + if (!$uid) return; $r = q("select * from channel where channel_id = %d limit 1", intval($uid) ); - if(! $r) + if (!$r) return; $channel = $r[0]; @@ -49,103 +49,103 @@ class Libsync { unset($channel['channel_salt']); - if(intval($channel['channel_removed'])) + if (intval($channel['channel_removed'])) return; $h = q("select hubloc.*, site.site_crypto from hubloc left join site on site_url = hubloc_url where hubloc_hash = '%s' and hubloc_deleted = 0", dbesc(($keychange) ? $packet['keychange']['old_hash'] : $channel['channel_hash']) ); - if(! $h) + if (!$h) return; - $synchubs = array(); + $synchubs = []; - foreach($h as $x) { - if($x['hubloc_host'] == \App::get_hostname()) + foreach ($h as $x) { + if ($x['hubloc_host'] == App::get_hostname()) continue; $y = q("select site_dead from site where site_url = '%s' limit 1", dbesc($x['hubloc_url']) ); - if((! $y) || ($y[0]['site_dead'] == 0)) + if ((!$y) || ($y[0]['site_dead'] == 0)) $synchubs[] = $x; } - if(! $synchubs) + if (!$synchubs) return; - $env_recips = [ $channel['channel_hash'] ]; + $env_recips = [$channel['channel_hash']]; - if($packet) - logger('packet: ' . print_r($packet, true),LOGGER_DATA, LOG_DEBUG); + if ($packet) + logger('packet: ' . print_r($packet, true), LOGGER_DATA, LOG_DEBUG); - $info = (($packet) ? $packet : array()); - $info['type'] = 'sync'; + $info = (($packet) ? $packet : []); + $info['type'] = 'sync'; $info['encoding'] = 'hz'; // note: not zot, this packet is very platform specific - $info['relocate'] = ['channel_address' => $channel['channel_address'], 'url' => z_root() ]; + $info['relocate'] = ['channel_address' => $channel['channel_address'], 'url' => z_root()]; - if(array_key_exists($uid,\App::$config) && array_key_exists('transient',\App::$config[$uid])) { - $settings = \App::$config[$uid]['transient']; - if($settings) { + if (array_key_exists($uid, App::$config) && array_key_exists('transient', App::$config[$uid])) { + $settings = App::$config[$uid]['transient']; + if ($settings) { $info['config'] = $settings; } } - if($channel) { - $info['channel'] = array(); - foreach($channel as $k => $v) { + if ($channel) { + $info['channel'] = []; + foreach ($channel as $k => $v) { // filter out any joined tables like xchan - if(strpos($k,'channel_') !== 0) + if (strpos($k, 'channel_') !== 0) continue; // don't pass these elements, they should not be synchronised $disallowed = [ - 'channel_id','channel_account_id','channel_primary','channel_address', - 'channel_deleted','channel_removed','channel_system' + 'channel_id', 'channel_account_id', 'channel_primary', 'channel_address', + 'channel_deleted', 'channel_removed', 'channel_system' ]; - if(! $keychange) { + if (!$keychange) { $disallowed[] = 'channel_prvkey'; } - if(in_array($k,$disallowed)) + if (in_array($k, $disallowed)) continue; $info['channel'][$k] = $v; } } - if($groups_changed) { + if ($groups_changed) { $r = q("select hash as collection, visible, deleted, gname as name from pgrp where uid = %d", intval($uid) ); - if($r) + if ($r) $info['collections'] = $r; $r = q("select pgrp.hash as collection, pgrp_member.xchan as member from pgrp left join pgrp_member on pgrp.id = pgrp_member.gid where pgrp_member.uid = %d", intval($uid) ); - if($r) + if ($r) $info['collection_members'] = $r; } - $interval = ((get_config('system','delivery_interval') !== false) - ? intval(get_config('system','delivery_interval')) : 2 ); + $interval = ((get_config('system', 'delivery_interval') !== false) + ? intval(get_config('system', 'delivery_interval')) : 2); - logger('Packet: ' . print_r($info,true), LOGGER_DATA, LOG_DEBUG); + logger('Packet: ' . print_r($info, true), LOGGER_DATA, LOG_DEBUG); $total = count($synchubs); - foreach($synchubs as $hub) { + foreach ($synchubs as $hub) { $hash = random_string(); - $n = Libzot::build_packet($channel,'sync',$env_recips,json_encode($info),'hz',$hub['hubloc_sitekey'],$hub['site_crypto']); - Queue::insert(array( + $n = Libzot::build_packet($channel, 'sync', $env_recips, json_encode($info), 'hz', $hub['hubloc_sitekey'], $hub['site_crypto']); + Queue::insert([ 'hash' => $hash, 'account_id' => $channel['channel_account_id'], 'channel_id' => $channel['channel_id'], @@ -153,29 +153,29 @@ class Libsync { 'driver' => $hub['hubloc_network'], 'notify' => $n, 'msg' => EMPTY_STR - )); + ]); $x = q("select count(outq_hash) as total from outq where outq_delivered = 0"); - if(intval($x[0]['total']) > intval(get_config('system','force_queue_threshold',3000))) { + if (intval($x[0]['total']) > intval(get_config('system', 'force_queue_threshold', 3000))) { logger('immediate delivery deferred.', LOGGER_DEBUG, LOG_INFO); Queue::update($hash); continue; } - \Zotlabs\Daemon\Master::Summon(array('Deliver', $hash)); + Master::Summon(['Deliver', $hash]); $total = $total - 1; - if($interval && $total) - @time_sleep_until(microtime(true) + (float) $interval); + if ($interval && $total) + @time_sleep_until(microtime(true) + (float)$interval); } } /** * @brief * - * @param array $sender + * @param string $sender * @param array $arr * @param array $deliveries * @return array @@ -187,16 +187,16 @@ class Libsync { $result = []; - $keychange = ((array_key_exists('keychange',$arr)) ? true : false); + $keychange = ((array_key_exists('keychange', $arr)) ? true : false); foreach ($deliveries as $d) { $r = q("select * from channel where channel_hash = '%s' limit 1", dbesc($sender) ); - $DR = new \Zotlabs\Lib\DReport(z_root(),$sender,$d,'sync'); + $DR = new DReport(z_root(), $sender, $d, 'sync'); - if (! $r) { + if (!$r) { $DR->update('recipient not found'); $result[] = $DR->get(); continue; @@ -206,153 +206,152 @@ class Libsync { $DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>'); - $max_friends = service_class_fetch($channel['channel_id'],'total_channels'); - $max_feeds = account_service_class_fetch($channel['channel_account_id'],'total_feeds'); + $max_friends = service_class_fetch($channel['channel_id'], 'total_channels'); + $max_feeds = account_service_class_fetch($channel['channel_account_id'], 'total_feeds'); - if($channel['channel_hash'] != $sender) { + if ($channel['channel_hash'] != $sender) { logger('Possible forgery. Sender ' . $sender . ' is not ' . $channel['channel_hash']); $DR->update('channel mismatch'); $result[] = $DR->get(); continue; } - if($keychange) { - self::keychange($channel,$arr); + if ($keychange) { + self::keychange($channel, $arr); continue; } // if the clone is active, so are we - if(substr($channel['channel_active'],0,10) !== substr(datetime_convert(),0,10)) { + if (substr($channel['channel_active'], 0, 10) !== substr(datetime_convert(), 0, 10)) { q("UPDATE channel set channel_active = '%s' where channel_id = %d", dbesc(datetime_convert()), intval($channel['channel_id']) ); } - if(array_key_exists('config',$arr) && is_array($arr['config']) && count($arr['config'])) { - foreach($arr['config'] as $cat => $k) { - foreach($arr['config'][$cat] as $k => $v) - set_pconfig($channel['channel_id'],$cat,$k,$v); + if (array_key_exists('config', $arr) && is_array($arr['config']) && count($arr['config'])) { + foreach ($arr['config'] as $cat => $k) { + foreach ($arr['config'][$cat] as $k => $v) + set_pconfig($channel['channel_id'], $cat, $k, $v); } } - if(array_key_exists('obj',$arr) && $arr['obj']) - sync_objs($channel,$arr['obj']); + if (array_key_exists('obj', $arr) && $arr['obj']) + sync_objs($channel, $arr['obj']); - if(array_key_exists('likes',$arr) && $arr['likes']) - import_likes($channel,$arr['likes']); + if (array_key_exists('likes', $arr) && $arr['likes']) + import_likes($channel, $arr['likes']); - if(array_key_exists('app',$arr) && $arr['app']) - sync_apps($channel,$arr['app']); + 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('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('calendar', $arr) && $arr['calendar']) + sync_calendar($channel, $arr['calendar']); - if(array_key_exists('chatroom',$arr) && $arr['chatroom']) - sync_chatrooms($channel,$arr['chatroom']); + if (array_key_exists('chatroom', $arr) && $arr['chatroom']) + sync_chatrooms($channel, $arr['chatroom']); - if(array_key_exists('conv',$arr) && $arr['conv']) - import_conv($channel,$arr['conv']); + if (array_key_exists('conv', $arr) && $arr['conv']) + import_conv($channel, $arr['conv']); - if(array_key_exists('mail',$arr) && $arr['mail']) - sync_mail($channel,$arr['mail']); + if (array_key_exists('mail', $arr) && $arr['mail']) + sync_mail($channel, $arr['mail']); - if(array_key_exists('event',$arr) && $arr['event']) - sync_events($channel,$arr['event']); + if (array_key_exists('event', $arr) && $arr['event']) + sync_events($channel, $arr['event']); - if(array_key_exists('event_item',$arr) && $arr['event_item']) - sync_items($channel,$arr['event_item'],((array_key_exists('relocate',$arr)) ? $arr['relocate'] : null)); + if (array_key_exists('event_item', $arr) && $arr['event_item']) + sync_items($channel, $arr['event_item'], ((array_key_exists('relocate', $arr)) ? $arr['relocate'] : null)); - if(array_key_exists('item',$arr) && $arr['item']) - sync_items($channel,$arr['item'],((array_key_exists('relocate',$arr)) ? $arr['relocate'] : null)); + if (array_key_exists('item', $arr) && $arr['item']) + sync_items($channel, $arr['item'], ((array_key_exists('relocate', $arr)) ? $arr['relocate'] : null)); // deprecated, maintaining for a few months for upward compatibility // this should sync webpages, but the logic is a bit subtle - if(array_key_exists('item_id',$arr) && $arr['item_id']) - sync_items($channel,$arr['item_id']); + if (array_key_exists('item_id', $arr) && $arr['item_id']) + sync_items($channel, $arr['item_id']); - if(array_key_exists('menu',$arr) && $arr['menu']) - sync_menus($channel,$arr['menu']); + if (array_key_exists('menu', $arr) && $arr['menu']) + sync_menus($channel, $arr['menu']); - if(array_key_exists('file',$arr) && $arr['file']) - sync_files($channel,$arr['file']); + if (array_key_exists('file', $arr) && $arr['file']) + sync_files($channel, $arr['file']); - if(array_key_exists('wiki',$arr) && $arr['wiki']) - sync_items($channel,$arr['wiki'],((array_key_exists('relocate',$arr)) ? $arr['relocate'] : null)); + if (array_key_exists('wiki', $arr) && $arr['wiki']) + sync_items($channel, $arr['wiki'], ((array_key_exists('relocate', $arr)) ? $arr['relocate'] : null)); - if(array_key_exists('channel',$arr) && is_array($arr['channel']) && count($arr['channel'])) { + if (array_key_exists('channel', $arr) && is_array($arr['channel']) && count($arr['channel'])) { - $remote_channel = $arr['channel']; + $remote_channel = $arr['channel']; $remote_channel['channel_id'] = $channel['channel_id']; - if(array_key_exists('channel_pageflags',$arr['channel']) && intval($arr['channel']['channel_pageflags'])) { + if (array_key_exists('channel_pageflags', $arr['channel']) && intval($arr['channel']['channel_pageflags'])) { // Several pageflags are site-specific and cannot be sync'd. // Only allow those bits which are shareable from the remote and then // logically OR with the local flags - $arr['channel']['channel_pageflags'] = $arr['channel']['channel_pageflags'] & (PAGE_HIDDEN|PAGE_AUTOCONNECT|PAGE_APPLICATION|PAGE_PREMIUM|PAGE_ADULT); + $arr['channel']['channel_pageflags'] = $arr['channel']['channel_pageflags'] & (PAGE_HIDDEN | PAGE_AUTOCONNECT | PAGE_APPLICATION | PAGE_PREMIUM | PAGE_ADULT); $arr['channel']['channel_pageflags'] = $arr['channel']['channel_pageflags'] | $channel['channel_pageflags']; } $disallowed = [ - 'channel_id', 'channel_account_id', 'channel_primary', 'channel_prvkey', - 'channel_address', 'channel_notifyflags', 'channel_removed', 'channel_deleted', - 'channel_system', 'channel_r_stream', 'channel_r_profile', 'channel_r_abook', - 'channel_r_storage', 'channel_r_pages', 'channel_w_stream', 'channel_w_wall', - 'channel_w_comment', 'channel_w_mail', 'channel_w_like', 'channel_w_tagwall', - 'channel_w_chat', 'channel_w_storage', 'channel_w_pages', 'channel_a_republish', + 'channel_id', 'channel_account_id', 'channel_primary', 'channel_prvkey', + 'channel_address', 'channel_notifyflags', 'channel_removed', 'channel_deleted', + 'channel_system', 'channel_r_stream', 'channel_r_profile', 'channel_r_abook', + 'channel_r_storage', 'channel_r_pages', 'channel_w_stream', 'channel_w_wall', + 'channel_w_comment', 'channel_w_mail', 'channel_w_like', 'channel_w_tagwall', + 'channel_w_chat', 'channel_w_storage', 'channel_w_pages', 'channel_a_republish', 'channel_a_delegate' ]; - $clean = array(); - foreach($arr['channel'] as $k => $v) { - if(in_array($k,$disallowed)) + $clean = []; + foreach ($arr['channel'] as $k => $v) { + if (in_array($k, $disallowed)) continue; $clean[$k] = $v; } - if(count($clean)) { - foreach($clean as $k => $v) { - $r = dbq("UPDATE channel set " . dbesc($k) . " = '" . dbesc($v) - . "' where channel_id = " . intval($channel['channel_id']) ); + if (count($clean)) { + foreach ($clean as $k => $v) { + dbq("UPDATE channel set " . dbesc($k) . " = '" . dbesc($v) . "' where channel_id = " . intval($channel['channel_id'])); } } } - if(array_key_exists('abook',$arr) && is_array($arr['abook']) && count($arr['abook'])) { + if (array_key_exists('abook', $arr) && is_array($arr['abook']) && count($arr['abook'])) { $total_friends = 0; - $total_feeds = 0; + $total_feeds = 0; $r = q("select abook_id, abook_feed from abook where abook_channel = %d", intval($channel['channel_id']) ); - if($r) { + if ($r) { // don't count yourself $total_friends = ((count($r) > 0) ? count($r) - 1 : 0); - foreach($r as $rr) - if(intval($rr['abook_feed'])) - $total_feeds ++; + foreach ($r as $rr) + if (intval($rr['abook_feed'])) + $total_feeds++; } - $disallowed = array('abook_id','abook_account','abook_channel','abook_rating','abook_rating_text','abook_not_here'); + $disallowed = ['abook_id', 'abook_account', 'abook_channel', 'abook_rating', 'abook_rating_text', 'abook_not_here']; $fields = db_columns('abook'); - foreach($arr['abook'] as $abook) { + foreach ($arr['abook'] as $abook) { $abconfig = null; - if(array_key_exists('abconfig',$abook) && is_array($abook['abconfig']) && count($abook['abconfig'])) + if (array_key_exists('abconfig', $abook) && is_array($abook['abconfig']) && count($abook['abconfig'])) $abconfig = $abook['abconfig']; - if(! array_key_exists('abook_blocked',$abook)) { + if (!array_key_exists('abook_blocked', $abook)) { // convert from redmatrix $abook['abook_blocked'] = (($abook['abook_flags'] & 0x0001) ? 1 : 0); $abook['abook_ignored'] = (($abook['abook_flags'] & 0x0002) ? 1 : 0); @@ -364,20 +363,20 @@ class Libsync { $abook['abook_feed'] = (($abook['abook_flags'] & 0x0100) ? 1 : 0); } - $clean = array(); - if($abook['abook_xchan'] && $abook['entry_deleted']) { + $clean = []; + if ($abook['abook_xchan'] && $abook['entry_deleted']) { logger('Removing abook entry for ' . $abook['abook_xchan']); $r = q("select abook_id, abook_feed from abook where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 limit 1", dbesc($abook['abook_xchan']), intval($channel['channel_id']) ); - if($r) { - contact_remove($channel['channel_id'],$r[0]['abook_id']); - if($total_friends) - $total_friends --; - if(intval($r[0]['abook_feed'])) - $total_feeds --; + if ($r) { + contact_remove($channel['channel_id'], $r[0]['abook_id']); + if ($total_friends) + $total_friends--; + if (intval($r[0]['abook_feed'])) + $total_feeds--; } continue; } @@ -386,31 +385,31 @@ class Libsync { // This relies on the undocumented behaviour that red sites send xchan info with the abook // and import_author_xchan will look them up on all federated networks - if($abook['abook_xchan'] && $abook['xchan_addr']) { + if ($abook['abook_xchan'] && $abook['xchan_addr']) { $h = Libzot::get_hublocs($abook['abook_xchan']); - if(! $h) { + if (!$h) { $xhash = import_author_xchan(encode_item_xchan($abook)); - if(! $xhash) { + if (!$xhash) { logger('Import of ' . $abook['xchan_addr'] . ' failed.'); continue; } } } - foreach($abook as $k => $v) { - if(in_array($k,$disallowed) || (strpos($k,'abook') !== 0)) { + foreach ($abook as $k => $v) { + if (in_array($k, $disallowed) || (strpos($k, 'abook') !== 0)) { continue; } - if(! in_array($k,$fields)) { + if (!in_array($k, $fields)) { continue; } $clean[$k] = $v; } - if(! array_key_exists('abook_xchan',$clean)) + if (!array_key_exists('abook_xchan', $clean)) continue; - if(array_key_exists('abook_instance',$clean) && $clean['abook_instance'] && strpos($clean['abook_instance'],z_root()) === false) { + if (array_key_exists('abook_instance', $clean) && $clean['abook_instance'] && strpos($clean['abook_instance'], z_root()) === false) { $clean['abook_not_here'] = 1; } @@ -422,12 +421,12 @@ class Libsync { // make sure we have an abook entry for this xchan on this system - if(! $r) { - if($max_friends !== false && $total_friends > $max_friends) { + if (!$r) { + if ($max_friends !== false && $total_friends > $max_friends) { logger('total_channels service class limit exceeded'); continue; } - if($max_feeds !== false && intval($clean['abook_feed']) && $total_feeds > $max_feeds) { + if ($max_feeds !== false && intval($clean['abook_feed']) && $total_feeds > $max_feeds) { logger('total_feeds service class limit exceeded'); continue; } @@ -438,18 +437,16 @@ class Libsync { 'abook_channel' => $channel['channel_id'] ] ); - $total_friends ++; - if(intval($clean['abook_feed'])) - $total_feeds ++; + $total_friends++; + if (intval($clean['abook_feed'])) + $total_feeds++; } - if(count($clean)) { - foreach($clean as $k => $v) { - if($k == 'abook_dob') + if (count($clean)) { + foreach ($clean as $k => $v) { + if ($k == 'abook_dob') $v = dbescdate($v); - - $r = dbq("UPDATE abook set " . dbesc($k) . " = '" . dbesc($v) - . "' where abook_xchan = '" . dbesc($clean['abook_xchan']) . "' and abook_channel = " . intval($channel['channel_id'])); + dbq("UPDATE abook set " . dbesc($k) . " = '" . dbesc($v) . "' where abook_xchan = '" . dbesc($clean['abook_xchan']) . "' and abook_channel = " . intval($channel['channel_id'])); } } @@ -459,10 +456,10 @@ class Libsync { // translate_abook_perms_inbound($channel,$abook); - if($abconfig) { + if ($abconfig) { /// @fixme does not handle sync of del_abconfig - foreach($abconfig as $abc) { - set_abconfig($channel['channel_id'],$abc['xchan'],$abc['cat'],$abc['k'],$abc['v']); + foreach ($abconfig as $abc) { + set_abconfig($channel['channel_id'], $abc['xchan'], $abc['cat'], $abc['k'], $abc['v']); } } } @@ -470,21 +467,21 @@ class Libsync { // sync collections (privacy groups) oh joy... - if(array_key_exists('collections',$arr) && is_array($arr['collections']) && count($arr['collections'])) { + if (array_key_exists('collections', $arr) && is_array($arr['collections']) && count($arr['collections'])) { $x = q("select * from pgrp where uid = %d", intval($channel['channel_id']) ); - foreach($arr['collections'] as $cl) { + foreach ($arr['collections'] as $cl) { $found = false; - if($x) { - foreach($x as $y) { - if($cl['collection'] == $y['hash']) { + if ($x) { + foreach ($x as $y) { + if ($cl['collection'] == $y['hash']) { $found = true; break; } } - if($found) { - if(($y['gname'] != $cl['name']) + if ($found) { + if (($y['gname'] != $cl['name']) || ($y['visible'] != $cl['visible']) || ($y['deleted'] != $cl['deleted'])) { q("update pgrp set gname = '%s', visible = %d, deleted = %d where hash = '%s' and uid = %d", @@ -495,15 +492,15 @@ class Libsync { intval($channel['channel_id']) ); } - if(intval($cl['deleted']) && (! intval($y['deleted']))) { + if (intval($cl['deleted']) && (!intval($y['deleted']))) { q("delete from pgrp_member where gid = %d", intval($y['id']) ); } } } - if(! $found) { - $r = q("INSERT INTO pgrp ( hash, uid, visible, deleted, gname ) + if (!$found) { + q("INSERT INTO pgrp ( hash, uid, visible, deleted, gname ) VALUES( '%s', %d, %d, %d, '%s' ) ", dbesc($cl['collection']), intval($channel['channel_id']), @@ -517,16 +514,16 @@ class Libsync { // They need to be removed by marking deleted and removing the members. // This shouldn't happen except for clones created before this function was written. - if($x) { + if ($x) { $found_local = false; - foreach($x as $y) { - foreach($arr['collections'] as $cl) { - if($cl['collection'] == $y['hash']) { + foreach ($x as $y) { + foreach ($arr['collections'] as $cl) { + if ($cl['collection'] == $y['hash']) { $found_local = true; break; } } - if(! $found_local) { + if (!$found_local) { q("delete from pgrp_member where gid = %d", intval($y['id']) ); @@ -546,38 +543,38 @@ class Libsync { // now sync the members - if(array_key_exists('collection_members', $arr) + if (array_key_exists('collection_members', $arr) && is_array($arr['collection_members']) && count($arr['collection_members'])) { // first sort into groups keyed by the group hash - $members = array(); - foreach($arr['collection_members'] as $cm) { - if(! array_key_exists($cm['collection'],$members)) - $members[$cm['collection']] = array(); + $members = []; + foreach ($arr['collection_members'] as $cm) { + if (!array_key_exists($cm['collection'], $members)) + $members[$cm['collection']] = []; $members[$cm['collection']][] = $cm['member']; } // our group list is already synchronised - if($x) { - foreach($x as $y) { + if ($x) { + foreach ($x as $y) { // for each group, loop on members list we just received - if(isset($y['hash']) && isset($members[$y['hash']])) { - foreach($members[$y['hash']] as $member) { + if (isset($y['hash']) && isset($members[$y['hash']])) { + foreach ($members[$y['hash']] as $member) { $found = false; - $z = q("select xchan from pgrp_member where gid = %d and uid = %d and xchan = '%s' limit 1", + $z = q("select xchan from pgrp_member where gid = %d and uid = %d and xchan = '%s' limit 1", intval($y['id']), intval($channel['channel_id']), dbesc($member) ); - if($z) + if ($z) $found = true; // if somebody is in the group that wasn't before - add them - if(! $found) { + if (!$found) { q("INSERT INTO pgrp_member (uid, gid, xchan) VALUES( %d, %d, '%s' ) ", intval($channel['channel_id']), @@ -593,10 +590,10 @@ class Libsync { intval($y['id']), intval($channel['channel_id']) ); - if($m) { - foreach($m as $mm) { + if ($m) { + foreach ($m as $mm) { // if the local existing member isn't in the list we just received - remove them - if(! in_array($mm['xchan'],$members[$y['hash']])) { + if (!in_array($mm['xchan'], $members[$y['hash']])) { q("delete from pgrp_member where xchan = '%s' and gid = %d and uid = %d", dbesc($mm['xchan']), intval($y['id']), @@ -610,17 +607,17 @@ class Libsync { } } - if(array_key_exists('profile',$arr) && is_array($arr['profile']) && count($arr['profile'])) { + if (array_key_exists('profile', $arr) && is_array($arr['profile']) && count($arr['profile'])) { - $disallowed = array('id','aid','uid','guid'); + $disallowed = ['id', 'aid', 'uid', 'guid']; - foreach($arr['profile'] as $profile) { + foreach ($arr['profile'] as $profile) { $x = q("select * from profile where profile_guid = '%s' and uid = %d limit 1", dbesc($profile['profile_guid']), intval($channel['channel_id']) ); - if(! $x) { + if (!$x) { profile_store_lowlevel( [ 'aid' => $channel['channel_account_id'], @@ -633,24 +630,24 @@ class Libsync { dbesc($profile['profile_guid']), intval($channel['channel_id']) ); - if(! $x) + if (!$x) continue; } - $clean = array(); - foreach($profile as $k => $v) { - if(in_array($k,$disallowed)) + $clean = []; + foreach ($profile as $k => $v) { + if (in_array($k, $disallowed)) continue; - if($profile['is_default'] && in_array($k,['photo','thumb'])) + if ($profile['is_default'] && in_array($k, ['photo', 'thumb'])) continue; - if($k === 'name') + if ($k === 'name') $clean['fullname'] = $v; - elseif($k === 'with') + elseif ($k === 'with') $clean['partner'] = $v; - elseif($k === 'work') + elseif ($k === 'work') $clean['employment'] = $v; - elseif(array_key_exists($k,$x[0])) + elseif (array_key_exists($k, $x[0])) $clean[$k] = $v; /** @@ -658,7 +655,7 @@ class Libsync { * We also need to import local photos if a custom photo is selected */ - if((strpos($profile['thumb'],'/photo/profile/l/') !== false) || intval($profile['is_default'])) { + if ((strpos($profile['thumb'], '/photo/profile/l/') !== false) || intval($profile['is_default'])) { $profile['photo'] = z_root() . '/photo/profile/l/' . $channel['channel_id']; $profile['thumb'] = z_root() . '/photo/profile/m/' . $channel['channel_id']; } @@ -668,11 +665,11 @@ class Libsync { } } - if(count($clean)) { - foreach($clean as $k => $v) { - $r = dbq("UPDATE profile set " . TQUOT . dbesc($k) . TQUOT . " = '" . dbesc($v) - . "' where profile_guid = '" . dbesc($profile['profile_guid']) - . "' and uid = " . intval($channel['channel_id'])); + if (count($clean)) { + foreach ($clean as $k => $v) { + dbq("UPDATE profile set " . TQUOT . dbesc($k) . TQUOT . " = '" . dbesc($v) + . "' where profile_guid = '" . dbesc($profile['profile_guid']) + . "' and uid = " . intval($channel['channel_id'])); } } } @@ -687,7 +684,7 @@ class Libsync { */ call_hooks('process_channel_sync_delivery', $addon); - $DR = new \Zotlabs\Lib\DReport(z_root(),$d,$d,'sync','channel sync delivered'); + $DR = new DReport(z_root(), $d, $d, 'sync', 'channel sync delivered'); $DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>'); @@ -708,12 +705,12 @@ class Libsync { static function sync_locations($sender, $arr, $absolute = false) { - $ret = array(); + $ret = []; - if($arr['locations']) { + if ($arr['locations']) { - if($absolute) - Libzot::check_location_move($sender['hash'],$arr['locations']); + if ($absolute) + Libzot::check_location_move($sender['hash'], $arr['locations']); $xisting = q("select * from hubloc where hubloc_hash = '%s'", dbesc($sender['hash']) @@ -722,8 +719,8 @@ class Libsync { // See if a primary is specified $has_primary = false; - foreach($arr['locations'] as $location) { - if($location['primary']) { + foreach ($arr['locations'] as $location) { + if ($location['primary']) { $has_primary = true; break; } @@ -731,32 +728,32 @@ class Libsync { // Ensure that they have one primary hub - if(! $has_primary) + if (!$has_primary) $arr['locations'][0]['primary'] = true; - foreach($arr['locations'] as $location) { - if(! Libzot::verify($location['url'],$location['url_sig'],$sender['public_key'])) { + foreach ($arr['locations'] as $location) { + if (!Libzot::verify($location['url'], $location['url_sig'], $sender['public_key'])) { logger('Unable to verify site signature for ' . $location['url']); - $ret['message'] .= sprintf( t('Unable to verify site signature for %s'), $location['url']) . EOL; + $ret['message'] .= sprintf(t('Unable to verify site signature for %s'), $location['url']) . EOL; continue; } - for($x = 0; $x < count($xisting); $x ++) { - if(($xisting[$x]['hubloc_url'] === $location['url']) + for ($x = 0; $x < count($xisting); $x++) { + if (($xisting[$x]['hubloc_url'] === $location['url']) && ($xisting[$x]['hubloc_sitekey'] === $location['sitekey'])) { $xisting[$x]['updated'] = true; } } - if(! $location['sitekey']) { - logger('Empty hubloc sitekey. ' . print_r($location,true)); + if (!$location['sitekey']) { + logger('Empty hubloc sitekey. ' . print_r($location, true)); continue; } // Catch some malformed entries from the past which still exist - if(strpos($location['address'],'/') !== false) - $location['address'] = substr($location['address'],0,strpos($location['address'],'/')); + if (strpos($location['address'], '/') !== false) + $location['address'] = substr($location['address'], 0, strpos($location['address'], '/')); // match as many fields as possible in case anything at all changed. @@ -773,7 +770,7 @@ class Libsync { dbesc($location['callback']), dbesc($location['sitekey']) ); - if($r) { + if ($r) { logger('Hub exists: ' . $location['url'], LOGGER_DEBUG); // update connection timestamp if this is the site we're talking to @@ -781,9 +778,9 @@ class Libsync { $current_site = false; - $t = datetime_convert('UTC','UTC','now - 15 minutes'); + $t = datetime_convert('UTC', 'UTC', 'now - 15 minutes'); - if(array_key_exists('site',$arr) && $location['url'] == $arr['site']['url']) { + if (array_key_exists('site', $arr) && $location['url'] == $arr['site']['url']) { q("update hubloc set hubloc_connected = '%s', hubloc_updated = '%s' where hubloc_id = %d and hubloc_connected < '%s'", dbesc(datetime_convert()), dbesc(datetime_convert()), @@ -793,11 +790,11 @@ class Libsync { $current_site = true; } - if($current_site && intval($r[0]['hubloc_error'])) { + if ($current_site && intval($r[0]['hubloc_error'])) { q("update hubloc set hubloc_error = 0 where hubloc_id = %d", intval($r[0]['hubloc_id']) ); - if(intval($r[0]['hubloc_orphancheck'])) { + if (intval($r[0]['hubloc_orphancheck'])) { q("update hubloc set hubloc_orphancheck = 0 where hubloc_id = %d", intval($r[0]['hubloc_id']) ); @@ -808,60 +805,60 @@ class Libsync { } // Remove pure duplicates - if(count($r) > 1) { - for($h = 1; $h < count($r); $h ++) { + if (count($r) > 1) { + for ($h = 1; $h < count($r); $h++) { q("delete from hubloc where hubloc_id = %d", intval($r[$h]['hubloc_id']) ); - $what .= 'duplicate_hubloc_removed '; + $what .= 'duplicate_hubloc_removed '; $changed = true; } } - if(intval($r[0]['hubloc_primary']) && (! $location['primary'])) { - $m = q("update hubloc set hubloc_primary = 0, hubloc_updated = '%s' where hubloc_id_url = '%s'", + if (intval($r[0]['hubloc_primary']) && (!$location['primary'])) { + q("update hubloc set hubloc_primary = 0, hubloc_updated = '%s' where hubloc_id_url = '%s'", dbesc(datetime_convert()), dbesc($r[0]['hubloc_id_url']) ); $r[0]['hubloc_primary'] = intval($location['primary']); hubloc_change_primary($r[0]); - $what .= 'primary_hub '; + $what .= 'primary_hub '; $changed = true; } - elseif((! intval($r[0]['hubloc_primary'])) && ($location['primary'])) { - $m = q("update hubloc set hubloc_primary = 1, hubloc_updated = '%s' where hubloc_id = %d", + elseif ((!intval($r[0]['hubloc_primary'])) && ($location['primary'])) { + q("update hubloc set hubloc_primary = 1, hubloc_updated = '%s' where hubloc_id = %d", dbesc(datetime_convert()), intval($r[0]['hubloc_id']) ); // make sure hubloc_change_primary() has current data $r[0]['hubloc_primary'] = intval($location['primary']); hubloc_change_primary($r[0]); - $what .= 'primary_hub '; + $what .= 'primary_hub '; $changed = true; } - elseif($absolute) { + elseif ($absolute) { // Absolute sync - make sure the current primary is correctly reflected in the xchan $pr = hubloc_change_primary($r[0]); - if($pr) { - $what .= 'xchan_primary '; + if ($pr) { + $what .= 'xchan_primary '; $changed = true; } } - if(intval($r[0]['hubloc_deleted']) && (! intval($location['deleted']))) { - $n = q("update hubloc set hubloc_deleted = 0, hubloc_updated = '%s' where hubloc_id_url = '%s'", + if (intval($r[0]['hubloc_deleted']) && (!intval($location['deleted']))) { + q("update hubloc set hubloc_deleted = 0, hubloc_updated = '%s' where hubloc_id_url = '%s'", dbesc(datetime_convert()), dbesc($r[0]['hubloc_id_url']) ); - $what .= 'undelete_hub '; + $what .= 'undelete_hub '; $changed = true; } - elseif((! intval($r[0]['hubloc_deleted'])) && (intval($location['deleted']))) { + 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_url = '%s'", + q("update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id_url = '%s'", dbesc(datetime_convert()), dbesc($r[0]['hubloc_id_url']) ); - $what .= 'delete_hub '; + $what .= 'delete_hub '; $changed = true; } continue; @@ -870,8 +867,8 @@ class Libsync { // Existing hubs are dealt with. Now let's process any new ones. // New hub claiming to be primary. Make it so by removing any existing primaries. - if(intval($location['primary'])) { - $r = q("update hubloc set hubloc_primary = 0, hubloc_updated = '%s' where hubloc_hash = '%s' and hubloc_primary = 1", + if (intval($location['primary'])) { + q("update hubloc set hubloc_primary = 0, hubloc_updated = '%s' where hubloc_hash = '%s' and hubloc_primary = 1", dbesc(datetime_convert()), dbesc($sender['hash']) ); @@ -879,7 +876,7 @@ class Libsync { logger('New hub: ' . $location['url']); - $r = hubloc_store_lowlevel( + hubloc_store_lowlevel( [ 'hubloc_guid' => $sender['id'], 'hubloc_guid_sig' => $sender['id_sig'], @@ -890,7 +887,7 @@ class Libsync { 'hubloc_primary' => intval($location['primary']), 'hubloc_url' => $location['url'], 'hubloc_url_sig' => $location['url_sig'], - 'hubloc_site_id' => Libzot::make_xchan_hash($location['url'],$location['sitekey']), + 'hubloc_site_id' => Libzot::make_xchan_hash($location['url'], $location['sitekey']), 'hubloc_host' => $location['host'], 'hubloc_callback' => $location['callback'], 'hubloc_sitekey' => $location['sitekey'], @@ -899,15 +896,15 @@ class Libsync { ] ); - $what .= 'newhub '; + $what .= 'newhub '; $changed = true; - if($location['primary']) { + if ($location['primary']) { $r = q("select * from hubloc where hubloc_addr = '%s' and hubloc_sitekey = '%s'", dbesc($location['address']), dbesc($location['sitekey']) ); - if($r) { + if ($r) { $r = Libzot::zot_record_preferred($r); hubloc_change_primary($r); } @@ -916,15 +913,15 @@ class Libsync { // get rid of any hubs we have for this channel which weren't reported. - if($absolute && $xisting) { - foreach($xisting as $x) { - if(! array_key_exists('updated',$x)) { + if ($absolute && $xisting) { + 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_url = '%s'", + q("update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id_url = '%s'", dbesc(datetime_convert()), dbesc($x['hubloc_id_url']) ); - $what .= 'removed_hub '; + $what .= 'removed_hub '; $changed = true; } } @@ -935,22 +932,22 @@ class Libsync { } $ret['change_message'] = $what; - $ret['changed'] = $changed; + $ret['changed'] = $changed; return $ret; } - static function keychange($channel,$arr) { + static function keychange($channel, $arr) { // verify the keychange operation - if(! Libzot::verify($arr['channel']['channel_pubkey'],$arr['keychange']['new_sig'],$channel['channel_prvkey'])) { + if (!Libzot::verify($arr['channel']['channel_pubkey'], $arr['keychange']['new_sig'], $channel['channel_prvkey'])) { logger('sync keychange: verification failed'); return; } - $sig = Libzot::sign($channel['channel_guid'],$arr['channel']['channel_prvkey']); - $hash = Libzot::make_xchan_hash($channel['channel_guid'],$arr['channel']['channel_pubkey']); + $sig = Libzot::sign($channel['channel_guid'], $arr['channel']['channel_prvkey']); + $hash = Libzot::make_xchan_hash($channel['channel_guid'], $arr['channel']['channel_pubkey']); $r = q("update channel set channel_prvkey = '%s', channel_pubkey = '%s', channel_guid_sig = '%s', @@ -961,16 +958,16 @@ class Libsync { dbesc($hash), intval($channel['channel_id']) ); - if(! $r) { + if (!$r) { logger('keychange sync: channel update failed'); return; - } + } $r = q("select * from channel where channel_id = %d", intval($channel['channel_id']) ); - if(! $r) { + if (!$r) { logger('keychange sync: channel retrieve failed'); return; } @@ -982,11 +979,11 @@ class Libsync { dbesc(z_root()) ); - if($h) { - foreach($h as $hv) { + if ($h) { + foreach ($h as $hv) { $hv['hubloc_guid_sig'] = $sig; $hv['hubloc_hash'] = $hash; - $hv['hubloc_url_sig'] = Libzot::sign(z_root(),$channel['channel_prvkey']); + $hv['hubloc_url_sig'] = Libzot::sign(z_root(), $channel['channel_prvkey']); hubloc_store_lowlevel($hv); } } @@ -999,12 +996,12 @@ class Libsync { dbesc($hash) ); - if(($x) && (! $check)) { + if (($x) && (!$check)) { $oldxchan = $x[0]; - foreach($x as $xv) { - $xv['xchan_guid_sig'] = $sig; - $xv['xchan_hash'] = $hash; - $xv['xchan_pubkey'] = $channel['channel_pubkey']; + foreach ($x as $xv) { + $xv['xchan_guid_sig'] = $sig; + $xv['xchan_hash'] = $hash; + $xv['xchan_pubkey'] = $channel['channel_pubkey']; xchan_store_lowlevel($xv); $newxchan = $xv; } @@ -1014,14 +1011,14 @@ class Libsync { dbesc($arr['keychange']['old_hash']) ); - if($a) { + if ($a) { q("update abook set abook_xchan = '%s' where abook_id = %d", dbesc($hash), intval($a[0]['abook_id']) ); } - xchan_change_key($oldxchan,$newxchan,$arr['keychange']); + xchan_change_key($oldxchan, $newxchan, $arr['keychange']); } diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index 4bfd8c3fd..6aa49c5a7 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -34,7 +34,7 @@ class Libzot { */ static function new_uid($channel_nick) { $rawstr = z_root() . '/' . $channel_nick . '.' . mt_rand(); - return(base64url_encode(hash('whirlpool', $rawstr, true), true)); + return (base64url_encode(hash('whirlpool', $rawstr, true), true)); } @@ -87,7 +87,7 @@ class Libzot { * packet type: one of 'ping', 'pickup', 'purge', 'refresh', 'keychange', 'force_refresh', 'notify', 'auth_check' * @param array $recipients * envelope recipients, array of portable_id's; empty for public posts - * @param string $msg + * @param array $msg * optional message * @param string $encoding * optional encoding, default 'activitystreams' @@ -98,15 +98,15 @@ class Libzot { * optional comma separated list of encryption methods @ref best_algorithm() * @returns string json encoded zot packet */ - static function build_packet($channel, $type = 'activity', $recipients = null, $msg = '', $encoding = 'activitystreams', $remote_key = null, $methods = '') { + static function build_packet($channel, $type = 'activity', $recipients = null, $msg = [], $encoding = 'activitystreams', $remote_key = null, $methods = '') { - $sig_method = get_config('system','signature_algorithm','sha256'); + $sig_method = get_config('system', 'signature_algorithm', 'sha256'); $data = [ 'type' => $type, 'encoding' => $encoding, 'sender' => $channel['channel_hash'], - 'site_id' => self::make_xchan_hash(z_root(), get_config('system','pubkey')), + 'site_id' => self::make_xchan_hash(z_root(), get_config('system', 'pubkey')), 'version' => System::get_zot_revision(), ]; @@ -116,8 +116,8 @@ class Libzot { if ($msg) { $actor = channel_url($channel); - if ($encoding === 'activitystreams' && array_key_exists('actor',$msg) && is_string($msg['actor']) && $actor === $msg['actor']) { - $msg = JSalmon::sign($msg,$actor,$channel['channel_prvkey']); + if ($encoding === 'activitystreams' && array_key_exists('actor', $msg) && is_string($msg['actor']) && $actor === $msg['actor']) { + $msg = JSalmon::sign($msg, $actor, $channel['channel_prvkey']); } $data['data'] = $msg; } @@ -125,12 +125,12 @@ class Libzot { unset($data['encoding']); } - logger('packet: ' . print_r($data,true), LOGGER_DATA, LOG_DEBUG); + logger('packet: ' . print_r($data, true), LOGGER_DATA, LOG_DEBUG); if ($remote_key) { $algorithm = self::best_algorithm($methods); if ($algorithm) { - $data = crypto_encapsulate(json_encode($data),$remote_key, $algorithm); + $data = Crypto::encapsulate(json_encode($data), $remote_key, $algorithm); } } @@ -143,14 +143,14 @@ class Libzot { * * @param string $methods * Comma separated list of encryption methods - * @return string first match from our site method preferences crypto_methods() array + * @return string first match from our site method preferences Crypto::methods() array * of a method which is common to both sites; or 'aes256cbc' if no matches are found. */ static function best_algorithm($methods) { $x = [ 'methods' => $methods, - 'result' => '' + 'result' => '' ]; /** @@ -161,18 +161,18 @@ class Libzot { */ call_hooks('zot_best_algorithm', $x); - if($x['result']) + if ($x['result']) return $x['result']; - if($methods) { + if ($methods) { $x = explode(',', $methods); - if($x) { - $y = crypto_methods(); - if($y) { - foreach($y as $yv) { + if ($x) { + $y = Crypto::methods(); + if ($y) { + foreach ($y as $yv) { $yv = trim($yv); - if(in_array($yv, $x)) { - return($yv); + if (in_array($yv, $x)) { + return ($yv); } } } @@ -186,17 +186,17 @@ class Libzot { /** * @brief Send a zot message. * - * @see z_post_url() - * * @param string $url - * @param array $data + * @param string $data * @param array $channel (required if using zot6 delivery) * @param array $crypto (required if encrypted httpsig, requires hubloc_sitekey and site_crypto elements) * @return array see z_post_url() for returned data format + * @see z_post_url() + * */ - static function zot($url, $data, $channel = null,$crypto = null) { + static function zot($url, $data, $channel = null, $crypto = null) { - if($channel) { + if ($channel) { $headers = [ 'X-Zot-Token' => random_string(), 'Digest' => HTTPSig::generate_digest_header($data), @@ -204,8 +204,8 @@ class Libzot { '(request-target)' => 'post ' . get_request_string($url) ]; - $h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false,'sha512', - (($crypto) ? [ 'key' => $crypto['hubloc_sitekey'], 'algorithm' => self::best_algorithm($crypto['site_crypto']) ] : false)); + $h = HTTPSig::create_sig($headers, $channel['channel_prvkey'], channel_url($channel), false, 'sha512', + (($crypto) ? ['key' => $crypto['hubloc_sitekey'], 'algorithm' => self::best_algorithm($crypto['site_crypto'])] : false)); } else { $h = []; @@ -213,7 +213,7 @@ class Libzot { $redirects = 0; - return z_post_url($url,$data,$redirects,((empty($h)) ? [] : [ 'headers' => $h ])); + return z_post_url($url, $data, $redirects, ((empty($h)) ? [] : ['headers' => $h])); } @@ -237,7 +237,7 @@ class Libzot { * * @param array $them => xchan structure of sender * @param array $channel => local channel structure of target recipient, required for "friending" operations - * @param array $force (optional) default false + * @param boolean $force (optional) default false * * @return boolean * * \b true if successful @@ -245,9 +245,9 @@ class Libzot { */ static function refresh($them, $channel = null, $force = false) { - logger('them: ' . print_r($them,true), LOGGER_DATA, LOG_DEBUG); + logger('them: ' . print_r($them, true), LOGGER_DATA, LOG_DEBUG); if ($channel) - logger('channel: ' . print_r($channel,true), LOGGER_DATA, LOG_DEBUG); + logger('channel: ' . print_r($channel, true), LOGGER_DATA, LOG_DEBUG); $url = null; @@ -261,12 +261,12 @@ class Libzot { // We'll order by reverse id to try and pick off the newest one first and hopefully end up with the // correct hubloc. If this doesn't work we may have to re-write this section to try them all. - if(array_key_exists('xchan_addr',$them) && $them['xchan_addr']) { + if (array_key_exists('xchan_addr', $them) && $them['xchan_addr']) { $r = q("select hubloc_id_url, hubloc_primary from hubloc where hubloc_addr = '%s' and hubloc_network = 'zot6' order by hubloc_id desc", dbesc($them['xchan_addr']) ); } - if(! $r) { + if (!$r) { $r = q("select hubloc_id_url, hubloc_primary from hubloc where hubloc_hash = '%s' order by hubloc_id desc", dbesc($them['xchan_hash']) ); @@ -275,16 +275,16 @@ class Libzot { if ($r) { foreach ($r as $rr) { if (intval($rr['hubloc_primary'])) { - $url = $rr['hubloc_id_url']; + $url = $rr['hubloc_id_url']; $record = $rr; } } - if (! $url) { + if (!$url) { $url = $r[0]['hubloc_id_url']; } } } - if (! $url) { + if (!$url) { logger('zot_refresh: no url'); return false; } @@ -293,64 +293,64 @@ class Libzot { dbesc($url) ); - if($s && intval($s[0]['site_dead']) && (! $force)) { + if ($s && intval($s[0]['site_dead']) && (!$force)) { logger('zot_refresh: site ' . $url . ' is marked dead and force flag is not set. Cancelling operation.'); return false; } - $record = Zotfinger::exec($url,$channel); + $record = Zotfinger::exec($url, $channel); // Check the HTTP signature $hsig = $record['signature']; - if($hsig && $hsig['signer'] === $url && $hsig['header_valid'] === true && $hsig['content_valid'] === true) + if ($hsig && $hsig['signer'] === $url && $hsig['header_valid'] === true && $hsig['content_valid'] === true) $hsig_valid = true; - if(! $hsig_valid) { - logger('http signature not valid: ' . print_r($hsig,true)); + if (!$hsig_valid) { + logger('http signature not valid: ' . print_r($hsig, true)); return false; } - logger('zot-info: ' . print_r($record,true), LOGGER_DATA, LOG_DEBUG); + logger('zot-info: ' . print_r($record, true), LOGGER_DATA, LOG_DEBUG); $x = self::import_xchan($record['data'], (($force) ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED)); - if(! $x['success']) + if (!$x['success']) return false; - if($channel && $record['data']['permissions']) { - $permissions = explode(',',$record['data']['permissions']); + 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'); + if ($permissions && is_array($permissions)) { + $old_read_stream_perm = get_abconfig($channel['channel_id'], $x['hash'], 'their_perms', 'view_stream'); $permissions = Permissions::FilledPerms($permissions); - foreach($permissions as $k => $v) { - set_abconfig($channel['channel_id'],$x['hash'],'their_perms',$k,$v); + foreach ($permissions as $k => $v) { + set_abconfig($channel['channel_id'], $x['hash'], 'their_perms', $k, $v); } } - if(array_key_exists('profile',$record['data']) && array_key_exists('next_birthday',$record['data']['profile'])) { - $next_birthday = datetime_convert('UTC','UTC',$record['data']['profile']['next_birthday']); + if (array_key_exists('profile', $record['data']) && array_key_exists('next_birthday', $record['data']['profile'])) { + $next_birthday = datetime_convert('UTC', 'UTC', $record['data']['profile']['next_birthday']); } else { $next_birthday = NULL_DATE; } - $profile_assign = get_pconfig($channel['channel_id'],'system','profile_assign',''); + $profile_assign = get_pconfig($channel['channel_id'], 'system', 'profile_assign', ''); // Keep original perms to check if we need to notify them - $previous_perms = get_all_perms($channel['channel_id'],$x['hash']); + $previous_perms = get_all_perms($channel['channel_id'], $x['hash']); $r = q("select * from abook where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 limit 1", dbesc($x['hash']), intval($channel['channel_id']) ); - if($r) { + if ($r) { // connection exists @@ -358,7 +358,7 @@ class Libzot { // we have as we may have updated the year after sending a notification; and resetting // to the one we just received would cause us to create duplicated events. - if(substr($r[0]['abook_dob'],5) == substr($next_birthday,5)) + if (substr($r[0]['abook_dob'], 5) == substr($next_birthday, 5)) $next_birthday = $r[0]['abook_dob']; $y = q("update abook set abook_dob = '%s' @@ -369,30 +369,30 @@ class Libzot { intval($channel['channel_id']) ); - if(! $y) + if (!$y) logger('abook update failed'); else { // if we were just granted read stream permission and didn't have it before, try to pull in some posts - if((! $old_read_stream_perm) && (intval($permissions['view_stream']))) - Master::Summon([ 'Onepoll', $r[0]['abook_id'] ]); + if ((!$old_read_stream_perm) && (intval($permissions['view_stream']))) + Master::Summon(['Onepoll', $r[0]['abook_id']]); } } else { - $p = Permissions::connect_perms($channel['channel_id']); + $p = Permissions::connect_perms($channel['channel_id']); $my_perms = $p['perms']; $automatic = $p['automatic']; // new connection - if($my_perms) { - foreach($my_perms as $k => $v) { - set_abconfig($channel['channel_id'],$x['hash'],'my_perms',$k,$v); + if ($my_perms) { + foreach ($my_perms as $k => $v) { + set_abconfig($channel['channel_id'], $x['hash'], 'my_perms', $k, $v); } } - $closeness = get_pconfig($channel['channel_id'],'system','new_abook_closeness',80); + $closeness = get_pconfig($channel['channel_id'], 'system', 'new_abook_closeness', 80); $y = abook_store_lowlevel( [ @@ -408,9 +408,9 @@ class Libzot { ] ); - if($y) { + if ($y) { logger("New introduction received for {$channel['channel_name']}"); - $new_perms = get_all_perms($channel['channel_id'],$x['hash'],false); + $new_perms = get_all_perms($channel['channel_id'], $x['hash'], false); // Send a clone sync packet and a permissions update if permissions have changed @@ -419,45 +419,45 @@ class Libzot { intval($channel['channel_id']) ); - if($new_connection) { - if(! Permissions::PermsCompare($new_perms,$previous_perms)) - Master::Summon([ 'Notifier', 'permission_create', $new_connection[0]['abook_id'] ]); + if ($new_connection) { + if (!Permissions::PermsCompare($new_perms, $previous_perms)) + Master::Summon(['Notifier', 'permission_create', $new_connection[0]['abook_id']]); Enotify::submit( [ - 'type' => NOTIFY_INTRO, - 'from_xchan' => $x['hash'], - 'to_xchan' => $channel['channel_hash'], - 'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id'] + 'type' => NOTIFY_INTRO, + 'from_xchan' => $x['hash'], + 'to_xchan' => $channel['channel_hash'], + 'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id'] ] ); - if(intval($permissions['view_stream'])) { - if(intval(get_pconfig($channel['channel_id'],'perm_limits','send_stream') & PERMS_PENDING) - || (! intval($new_connection[0]['abook_pending']))) - Master::Summon([ 'Onepoll', $new_connection[0]['abook_id'] ]); + if (intval($permissions['view_stream'])) { + if (intval(get_pconfig($channel['channel_id'], 'perm_limits', 'send_stream') & PERMS_PENDING) + || (!intval($new_connection[0]['abook_pending']))) + Master::Summon(['Onepoll', $new_connection[0]['abook_id']]); } // If there is a default group for this channel, add this connection to it // for pending connections this will happens at acceptance time. - if(! intval($new_connection[0]['abook_pending'])) { + if (!intval($new_connection[0]['abook_pending'])) { $default_group = $channel['channel_default_group']; - if($default_group) { - $g = Group::rec_byhash($channel['channel_id'],$default_group); - if($g) - Group::member_add($channel['channel_id'],'',$x['hash'],$g['id']); + if ($default_group) { + $g = Group::rec_byhash($channel['channel_id'], $default_group); + if ($g) + Group::member_add($channel['channel_id'], '', $x['hash'], $g['id']); } } unset($new_connection[0]['abook_id']); unset($new_connection[0]['abook_account']); unset($new_connection[0]['abook_channel']); - $abconfig = load_abconfig($channel['channel_id'],$new_connection['abook_xchan']); - if($abconfig) + $abconfig = load_abconfig($channel['channel_id'], $new_connection['abook_xchan']); + if ($abconfig) $new_connection['abconfig'] = $abconfig; - Libsync::build_sync_packet($channel['channel_id'], array('abook' => $new_connection)); + Libsync::build_sync_packet($channel['channel_id'], ['abook' => $new_connection]); } } @@ -489,9 +489,9 @@ class Libzot { static function gethub($arr, $multiple = false) { - if($arr['id'] && $arr['id_sig'] && $arr['location'] && $arr['location_sig']) { + if ($arr['id'] && $arr['id_sig'] && $arr['location'] && $arr['location_sig']) { - if(! check_siteallowed($arr['location'])) { + if (!check_siteallowed($arr['location'])) { logger('blacklisted site: ' . $arr['location']); return null; } @@ -509,12 +509,12 @@ class Libzot { dbesc($arr['location_sig']), dbesc($arr['site_id']) ); - if($r) { + if ($r) { logger('Found', LOGGER_DEBUG); return (($multiple) ? $r : $r[0]); } } - logger('Not found: ' . print_r($arr,true), LOGGER_DEBUG); + logger('Not found: ' . print_r($arr, true), LOGGER_DEBUG); return false; } @@ -532,16 +532,16 @@ class Libzot { dbesc($sender), dbesc($site_id) ); - if(! $r) { + if (!$r) { return null; } - if(! check_siteallowed($r[0]['hubloc_url'])) { + if (!check_siteallowed($r[0]['hubloc_url'])) { logger('blacklisted site: ' . $r[0]['hubloc_url']); return null; } - if(! check_channelallowed($r[0]['hubloc_hash'])) { + if (!check_channelallowed($r[0]['hubloc_hash'])) { logger('blacklisted channel: ' . $r[0]['hubloc_hash']); return null; } @@ -567,9 +567,9 @@ class Libzot { $hsig_valid = false; - $result = [ 'success' => false ]; + $result = ['success' => false]; - if(! $id) { + if (!$id) { return $result; } @@ -578,16 +578,16 @@ class Libzot { // Check the HTTP signature $hsig = $record['signature']; - if($hsig['signer'] === $id && $hsig['header_valid'] === true && $hsig['content_valid'] === true) { + if ($hsig['signer'] === $id && $hsig['header_valid'] === true && $hsig['content_valid'] === true) { $hsig_valid = true; } - if(! $hsig_valid) { - logger('http signature not valid: ' . print_r($hsig,true)); + if (!$hsig_valid) { + logger('http signature not valid: ' . print_r($hsig, true)); return $result; } $c = self::import_xchan($record['data']); - if($c['success']) { + if ($c['success']) { $result['success'] = true; } else { @@ -625,26 +625,26 @@ class Libzot { */ call_hooks('import_xchan', $arr); - $ret = array('success' => false); - $dirmode = intval(get_config('system','directory_mode')); + $ret = ['success' => false]; + $dirmode = intval(get_config('system', 'directory_mode')); $changed = false; - $what = ''; + $what = ''; - if(! ($arr['id'] && $arr['id_sig'])) { - logger('No identity information provided. ' . print_r($arr,true)); + if (!($arr['id'] && $arr['id_sig'])) { + logger('No identity information provided. ' . print_r($arr, true)); return $ret; } - $xchan_hash = self::make_xchan_hash($arr['id'],$arr['public_key']); + $xchan_hash = self::make_xchan_hash($arr['id'], $arr['public_key']); $arr['hash'] = $xchan_hash; $import_photos = false; - $sig_methods = ((array_key_exists('signing',$arr) && is_array($arr['signing'])) ? $arr['signing'] : [ 'sha256' ]); - $verified = false; + $sig_methods = ((array_key_exists('signing', $arr) && is_array($arr['signing'])) ? $arr['signing'] : ['sha256']); + $verified = false; - if(! self::verify($arr['id'],$arr['id_sig'],$arr['public_key'])) { + if (!self::verify($arr['id'], $arr['id_sig'], $arr['public_key'])) { logger('Unable to verify channel signature for ' . $arr['address']); return $ret; } @@ -652,7 +652,7 @@ class Libzot { $verified = true; } - if(! $verified) { + if (!$verified) { $ret['message'] = t('Unable to verify channel signature'); return $ret; } @@ -663,40 +663,39 @@ class Libzot { dbesc($xchan_hash) ); - if(! array_key_exists('connect_url', $arr)) + if (!array_key_exists('connect_url', $arr)) $arr['connect_url'] = ''; - if($r) { - if($arr['photo'] && array_key_exists('updated',$arr['photo']) && $r[0]['xchan_photo_date'] != $arr['photo']['updated']) { + if ($r) { + if ($arr['photo'] && array_key_exists('updated', $arr['photo']) && $arr['photo']['updated'] > $r[0]['xchan_photo_date']) $import_photos = true; - } // if we import an entry from a site that's not ours and either or both of us is off the grid - hide the entry. /** @TODO: check if we're the same directory realm, which would mean we are allowed to see it */ - $dirmode = get_config('system','directory_mode'); + $dirmode = get_config('system', 'directory_mode'); - if((($arr['site']['directory_mode'] === 'standalone') || ($dirmode & DIRECTORY_MODE_STANDALONE)) && ($arr['site']['url'] != z_root())) + if ((($arr['site']['directory_mode'] === 'standalone') || ($dirmode & DIRECTORY_MODE_STANDALONE)) && ($arr['site']['url'] != z_root())) $arr['searchable'] = false; $hidden = (1 - intval($arr['searchable'])); $hidden_changed = $adult_changed = $deleted_changed = $pubforum_changed = 0; - if(intval($r[0]['xchan_hidden']) != (1 - intval($arr['searchable']))) + if (intval($r[0]['xchan_hidden']) != (1 - intval($arr['searchable']))) $hidden_changed = 1; - if(intval($r[0]['xchan_selfcensored']) != intval($arr['adult_content'])) + if (intval($r[0]['xchan_selfcensored']) != intval($arr['adult_content'])) $adult_changed = 1; - if(intval($r[0]['xchan_deleted']) != intval($arr['deleted'])) + if (intval($r[0]['xchan_deleted']) != intval($arr['deleted'])) $deleted_changed = 1; // new style 6-MAR-2019 - if(array_key_exists('channel_type',$arr)) { - if($arr['channel_type'] === 'collection') { + if (array_key_exists('channel_type', $arr)) { + if ($arr['channel_type'] === 'collection') { // do nothing at this time. } - elseif($arr['channel_type'] === 'group') { + elseif ($arr['channel_type'] === 'group') { $arr['public_forum'] = 1; } else { @@ -706,27 +705,27 @@ class Libzot { // old style - if(intval($r[0]['xchan_pubforum']) != intval($arr['public_forum'])) + if (intval($r[0]['xchan_pubforum']) != intval($arr['public_forum'])) $pubforum_changed = 1; - if($arr['protocols']) { - $protocols = implode(',',$arr['protocols']); - if($protocols !== 'zot6') { - set_xconfig($xchan_hash,'system','protocols',$protocols); + if ($arr['protocols']) { + $protocols = implode(',', $arr['protocols']); + if ($protocols !== 'zot6') { + set_xconfig($xchan_hash, 'system', 'protocols', $protocols); } else { - del_xconfig($xchan_hash,'system','protocols'); + del_xconfig($xchan_hash, 'system', 'protocols'); } } - if(($r[0]['xchan_name_date'] != $arr['name_updated']) + if (($r[0]['xchan_name_date'] != $arr['name_updated']) || ($r[0]['xchan_connurl'] != $arr['primary_location']['connections_url']) || ($r[0]['xchan_addr'] != $arr['primary_location']['address']) || ($r[0]['xchan_follow'] != $arr['primary_location']['follow_url']) || ($r[0]['xchan_connpage'] != $arr['connect_url']) || ($r[0]['xchan_url'] != $arr['primary_location']['url']) - || $hidden_changed || $adult_changed || $deleted_changed || $pubforum_changed ) { + || $hidden_changed || $adult_changed || $deleted_changed || $pubforum_changed) { $rup = q("update xchan set xchan_name = '%s', xchan_name_date = '%s', xchan_connurl = '%s', xchan_follow = '%s', xchan_connpage = '%s', xchan_hidden = %d, xchan_selfcensored = %d, xchan_deleted = %d, xchan_pubforum = %d, xchan_addr = '%s', xchan_url = '%s' where xchan_hash = '%s'", @@ -744,18 +743,18 @@ class Libzot { dbesc($xchan_hash) ); - logger('Update: existing: ' . print_r($r[0],true), LOGGER_DATA, LOG_DEBUG); - logger('Update: new: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG); - $what .= 'xchan '; + logger('Update: existing: ' . print_r($r[0], true), LOGGER_DATA, LOG_DEBUG); + logger('Update: new: ' . print_r($arr, true), LOGGER_DATA, LOG_DEBUG); + $what .= 'xchan '; $changed = true; } } else { $import_photos = true; - if((($arr['site']['directory_mode'] === 'standalone') + if ((($arr['site']['directory_mode'] === 'standalone') || ($dirmode & DIRECTORY_MODE_STANDALONE)) - && ($arr['site']['url'] != z_root())) + && ($arr['site']['url'] != z_root())) $arr['searchable'] = false; $x = xchan_store_lowlevel( @@ -764,8 +763,8 @@ class Libzot { 'xchan_guid' => $arr['id'], 'xchan_guid_sig' => $arr['id_sig'], 'xchan_pubkey' => $arr['public_key'], - 'xchan_photo_mimetype' => $arr['photo_mimetype'], - 'xchan_photo_l' => $arr['photo'], + 'xchan_photo_mimetype' => $arr['photo']['type'], + 'xchan_photo_l' => $arr['photo']['url'], 'xchan_addr' => escape_tags($arr['primary_location']['address']), 'xchan_url' => escape_tags($arr['primary_location']['url']), 'xchan_connurl' => $arr['primary_location']['connections_url'], @@ -773,7 +772,7 @@ class Libzot { 'xchan_connpage' => $arr['connect_url'], 'xchan_name' => (($arr['name']) ? escape_tags($arr['name']) : '-'), 'xchan_network' => 'zot6', - 'xchan_photo_date' => $arr['photo_updated'], + 'xchan_photo_date' => $arr['photo']['updated'], 'xchan_name_date' => $arr['name_updated'], 'xchan_hidden' => intval(1 - intval($arr['searchable'])), 'xchan_selfcensored' => $arr['adult_content'], @@ -782,11 +781,11 @@ class Libzot { ] ); - $what .= 'new_xchan'; + $what .= 'new_xchan'; $changed = true; } - if($import_photos) { + if ($import_photos) { require_once('include/photo/photo_driver.php'); @@ -795,13 +794,16 @@ class Libzot { $local = q("select channel_account_id, channel_id from channel where channel_hash = '%s' limit 1", dbesc($xchan_hash) ); - if($local) { - $ph = z_fetch_url($arr['photo']['url'], true); - if($ph['success']) { + if ($local) { + + $ph = false; + if (strpos($arr['photo']['url'], z_root()) === false) + $ph = z_fetch_url($arr['photo']['url'], true); + if ($ph['success']) { $hash = import_channel_photo($ph['body'], $arr['photo']['type'], $local[0]['channel_account_id'], $local[0]['channel_id']); - if($hash) { + if ($hash) { // unless proven otherwise $is_default_profile = 1; @@ -809,13 +811,13 @@ class Libzot { intval($local[0]['channel_account_id']), intval($local[0]['channel_id']) ); - if($profile) { - if(! intval($profile[0]['is_default'])) + if ($profile) { + if (!intval($profile[0]['is_default'])) $is_default_profile = 0; } // If setting for the default profile, unset the profile photo flag from any other photos I own - if($is_default_profile) { + if ($is_default_profile) { q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND resource_id != '%s' AND aid = %d AND uid = %d", intval(PHOTO_NORMAL), intval(PHOTO_PROFILE), @@ -827,20 +829,20 @@ class Libzot { } // reset the names in case they got messed up when we had a bug in this function - $photos = array( + $photos = [ z_root() . '/photo/profile/l/' . $local[0]['channel_id'], z_root() . '/photo/profile/m/' . $local[0]['channel_id'], z_root() . '/photo/profile/s/' . $local[0]['channel_id'], $arr['photo_mimetype'], false - ); + ]; } } else { $photos = import_xchan_photo($arr['photo']['url'], $xchan_hash); } - if($photos) { - if($photos[4]) { + if ($photos) { + if ($photos[4]) { // importing the photo failed somehow. Leave the photo_date alone so we can try again at a later date. // This often happens when somebody joins the matrix with a bad cert. $r = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' @@ -855,7 +857,7 @@ class Libzot { else { $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'", - dbescdate(datetime_convert('UTC','UTC',$arr['photo_updated'])), + dbescdate(datetime_convert('UTC', 'UTC', $arr['photo_updated'])), dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), @@ -863,7 +865,7 @@ class Libzot { dbesc($xchan_hash) ); } - $what .= 'photo '; + $what .= 'photo '; $changed = true; } } @@ -873,12 +875,12 @@ class Libzot { $s = Libsync::sync_locations($arr, $arr); - if($s) { - if($s['change_message']) + if ($s) { + if ($s['change_message']) $what .= $s['change_message']; - if($s['changed']) + if ($s['changed']) $changed = $s['changed']; - if($s['message']) + if ($s['message']) $ret['message'] .= $s['message']; } @@ -890,24 +892,24 @@ class Libzot { // Are we a directory server of some kind? $other_realm = false; - $realm = get_directory_realm(); - if(array_key_exists('site',$arr) - && array_key_exists('realm',$arr['site']) - && (strpos($arr['site']['realm'],$realm) === false)) + $realm = get_directory_realm(); + if (array_key_exists('site', $arr) + && array_key_exists('realm', $arr['site']) + && (strpos($arr['site']['realm'], $realm) === false)) $other_realm = true; - if($dirmode != DIRECTORY_MODE_NORMAL) { + if ($dirmode != DIRECTORY_MODE_NORMAL) { // We're some kind of directory server. However we can only add directory information // if the entry is in the same realm (or is a sub-realm). Sub-realms are denoted by // including the parent realm in the name. e.g. 'RED_GLOBAL:foo' would allow an entry to // be in directories for the local realm (foo) and also the RED_GLOBAL realm. - if(array_key_exists('profile',$arr) && is_array($arr['profile']) && (! $other_realm)) { - $profile_changed = Libzotdir::import_directory_profile($xchan_hash,$arr['profile'],$address,$ud_flags, 1); - if($profile_changed) { - $what .= 'profile '; + if (array_key_exists('profile', $arr) && is_array($arr['profile']) && (!$other_realm)) { + $profile_changed = Libzotdir::import_directory_profile($xchan_hash, $arr['profile'], $address, $ud_flags, 1); + if ($profile_changed) { + $what .= 'profile '; $changed = true; } } @@ -923,20 +925,20 @@ class Libzot { } } - if(array_key_exists('site',$arr) && is_array($arr['site'])) { + if (array_key_exists('site', $arr) && is_array($arr['site'])) { $profile_changed = self::import_site($arr['site']); - if($profile_changed) { - $what .= 'site '; + if ($profile_changed) { + $what .= 'site '; $changed = true; } } - if(($changed) || ($ud_flags == UPDATE_FLAGS_FORCED)) { + if (($changed) || ($ud_flags == UPDATE_FLAGS_FORCED)) { $guid = random_string() . '@' . \App::get_hostname(); - Libzotdir::update_modtime($xchan_hash,$guid,$address,$ud_flags); - logger('Changed: ' . $what,LOGGER_DEBUG); + Libzotdir::update_modtime($xchan_hash, $guid, $address, $ud_flags); + logger('Changed: ' . $what, LOGGER_DEBUG); } - elseif(! $ud_flags) { + elseif (!$ud_flags) { // nothing changed but we still need to update the updates record q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and not (ud_flags & %d) > 0 ", intval(UPDATE_FLAGS_UPDATED), @@ -945,12 +947,12 @@ class Libzot { ); } - if(! x($ret,'message')) { + if (!x($ret, 'message')) { $ret['success'] = true; - $ret['hash'] = $xchan_hash; + $ret['hash'] = $xchan_hash; } - logger('Result: ' . print_r($ret,true), LOGGER_DATA, LOG_DEBUG); + logger('Result: ' . print_r($ret, true), LOGGER_DATA, LOG_DEBUG); return $ret; } @@ -967,32 +969,32 @@ class Libzot { */ static function process_response($hub, $arr, $outq) { - logger('remote: ' . print_r($arr,true),LOGGER_DATA); + logger('remote: ' . print_r($arr, true), LOGGER_DATA); - if(! $arr['success']) { + if (!$arr['success']) { logger('Failed: ' . $hub); return; } $x = json_decode($arr['body'], true); - if(! $x) { + if (!$x) { logger('No json from ' . $hub); logger('Headers: ' . print_r($arr['header'], true), LOGGER_DATA, LOG_DEBUG); } - $x = crypto_unencapsulate($x, get_config('system','prvkey')); + $x = Crypto::unencapsulate($x, get_config('system', 'prvkey')); - if(! is_array($x)) { - $x = json_decode($x,true); + if (!is_array($x)) { + $x = json_decode($x, true); } - if(! is_array($x)) { + if (!is_array($x)) { btlogger('failed communication - no response'); } - if($x) { - if(! $x['success']) { + if ($x) { + if (!$x['success']) { // handle remote validation issues @@ -1003,18 +1005,18 @@ class Libzot { ); } - if(is_array($x) && array_key_exists('delivery_report',$x) && is_array($x['delivery_report'])) { + if (is_array($x) && array_key_exists('delivery_report', $x) && is_array($x['delivery_report'])) { - foreach($x['delivery_report'] as $xx) { - call_hooks('dreport_process',$xx); - if(is_array($xx) && array_key_exists('message_id',$xx) && DReport::is_storable($xx)) { + foreach ($x['delivery_report'] as $xx) { + call_hooks('dreport_process', $xx); + if (is_array($xx) && array_key_exists('message_id', $xx) && DReport::is_storable($xx)) { // legacy recipients add a space and their name to the xchan. split those if true. $legacy_recipient = strpos($xx['recipient'], ' '); - if($legacy_recipient !== false) { + if ($legacy_recipient !== false) { $legacy_recipient_parts = explode(' ', $xx['recipient'], 2); - $xx['recipient'] = $legacy_recipient_parts[0]; - $xx['name'] = $legacy_recipient_parts[1]; + $xx['recipient'] = $legacy_recipient_parts[0]; + $xx['name'] = $legacy_recipient_parts[1]; } q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_name, dreport_result, dreport_time, dreport_xchan ) values ( '%s', '%s', '%s','%s','%s','%s','%s' ) ", @@ -1023,7 +1025,7 @@ class Libzot { dbesc($xx['recipient']), dbesc($xx['name']), dbesc($xx['status']), - dbesc(datetime_convert('UTC','UTC',$xx['date'])), + dbesc(datetime_convert('UTC', 'UTC', $xx['date'])), dbesc($xx['sender']) ); } @@ -1046,10 +1048,10 @@ class Libzot { // synchronous message types are handled immediately // async messages remain in the queue until processed. - if(intval($outq['outq_async'])) - Queue::remove($outq['outq_hash'],$outq['outq_channel']); + if (intval($outq['outq_async'])) + Queue::remove($outq['outq_hash'], $outq['outq_channel']); - logger('zot_process_response: ' . print_r($x,true), LOGGER_DEBUG); + logger('zot_process_response: ' . print_r($x, true), LOGGER_DEBUG); } /** @@ -1067,16 +1069,16 @@ class Libzot { * If everything checks out on the remote end, we will receive back a packet containing one or more messages, * which will be processed and delivered before this function ultimately returns. * - * @see zot_import() - * * @param array $arr * decrypted and json decoded notify packet from remote site * @return array from zot_import() + * @see zot_import() + * */ static function fetch($arr) { - logger('zot_fetch: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG); + logger('zot_fetch: ' . print_r($arr, true), LOGGER_DATA, LOG_DEBUG); return self::import($arr); @@ -1101,15 +1103,15 @@ class Libzot { */ static function import($arr) { - $env = $arr; + $env = $arr; $private = false; - $return = []; + $return = []; $result = null; - logger('Notify: ' . print_r($env,true), LOGGER_DATA, LOG_DEBUG); + logger('Notify: ' . print_r($env, true), LOGGER_DATA, LOG_DEBUG); - if(! is_array($env)) { + if (!is_array($env)) { logger('decode error'); return; } @@ -1117,59 +1119,59 @@ class Libzot { $message_request = false; - $has_data = array_key_exists('data',$env) && $env['data']; - $data = (($has_data) ? $env['data'] : false); + $has_data = array_key_exists('data', $env) && $env['data']; + $data = (($has_data) ? $env['data'] : false); $AS = null; - if($env['encoding'] === 'activitystreams') { + if ($env['encoding'] === 'activitystreams') { - $AS = new ActivityStreams($data); - if(! $AS->is_valid()) { - logger('Activity rejected: ' . print_r($data,true)); - return; - } - if (is_array($AS->obj)) { - $arr = Activity::decode_note($AS); - } - else { - $arr = []; - } + $AS = new ActivityStreams($data); + if (!$AS->is_valid()) { + logger('Activity rejected: ' . print_r($data, true)); + return; + } + if (is_array($AS->obj)) { + $arr = Activity::decode_note($AS); + } + else { + $arr = []; + } - logger($AS->debug(),LOGGER_DATA); + logger($AS->debug(), LOGGER_DATA); } $deliveries = null; - if(array_key_exists('recipients',$env) && count($env['recipients'])) { + if (array_key_exists('recipients', $env) && count($env['recipients'])) { logger('specific recipients'); - logger('recipients: ' . print_r($env['recipients'],true),LOGGER_DEBUG); + logger('recipients: ' . print_r($env['recipients'], true), LOGGER_DEBUG); $recip_arr = []; - foreach($env['recipients'] as $recip) { - $recip_arr[] = $recip; + foreach ($env['recipients'] as $recip) { + $recip_arr[] = $recip; } $r = false; - if($recip_arr) { - stringify_array_elms($recip_arr,true); - $recips = implode(',',$recip_arr); - $r = q("select channel_hash as hash from channel where channel_hash in ( " . $recips . " ) and channel_removed = 0 "); + if ($recip_arr) { + stringify_array_elms($recip_arr, true); + $recips = implode(',', $recip_arr); + $r = q("select channel_hash as hash from channel where channel_hash in ( " . $recips . " ) and channel_removed = 0 "); } - if(! $r) { + if (!$r) { logger('recips: no recipients on this site'); return; } // Response messages will inherit the privacy of the parent - if($env['type'] !== 'response') + if ($env['type'] !== 'response') $private = true; - $deliveries = ids_to_array($r,'hash'); + $deliveries = ids_to_array($r, 'hash'); // We found somebody on this site that's in the recipient list. } @@ -1182,33 +1184,33 @@ class Libzot { // and who are allowed to see them based on the sender's permissions // @fixme; - $deliveries = self::public_recips($env,$AS); + $deliveries = self::public_recips($env, $AS); } $deliveries = array_unique($deliveries); - if(! $deliveries) { + if (!$deliveries) { logger('No deliveries on this site'); return; } - if($has_data) { + if ($has_data) { - if(in_array($env['type'],['activity','response'])) { + if (in_array($env['type'], ['activity', 'response'])) { $r = q("select hubloc_hash, hubloc_network from hubloc where hubloc_id_url = '%s' ", dbesc($AS->actor['id']) ); - if($r) { + if ($r) { // selects a zot6 hash if available, otherwise use whatever we have - $r = self::zot_record_preferred($r); + $r = self::zot_record_preferred($r); $arr['author_xchan'] = $r['hubloc_hash']; } - if (! $arr['author_xchan']) { + if (!$arr['author_xchan']) { logger('No author!'); return; } @@ -1218,43 +1220,47 @@ class Libzot { ); // in individual delivery, change owner if needed - if($s) { + if ($s) { $arr['owner_xchan'] = $s[0]['hubloc_hash']; } else { $arr['owner_xchan'] = $env['sender']; } - if ($private && (! intval($arr['item_private']))) { + if ($private && (!intval($arr['item_private']))) { $arr['item_private'] = 1; } if ($arr['mid'] === $arr['parent_mid']) { - if (is_array($AS->obj) && array_key_exists('commentPolicy',$AS->obj)) { - $p = strstr($AS->obj['commentPolicy'],'until='); - if($p !== false) { - $arr['comments_closed'] = datetime_convert('UTC','UTC', substr($p,6)); - $arr['comment_policy'] = trim(str_replace($p,'',$AS->obj['commentPolicy'])); + if (is_array($AS->obj) && array_key_exists('commentPolicy', $AS->obj)) { + $p = strstr($AS->obj['commentPolicy'], 'until='); + if ($p !== false) { + $comments_closed_at = datetime_convert('UTC', 'UTC', substr($p, 6)); + if ($comments_closed_at === $arr['created']) { + $arr['item_nocomment'] = 1; + } + else { + $arr['comments_closed'] = $comments_closed_at; + $arr['comment_policy'] = trim(str_replace($p, '', $AS->obj['commentPolicy'])); + } } else { - $arr['comment_policy'] = $AS->obj['commentPolicy']; + $arr['comment_policy'] = $AS->obj['commentPolicy']; } } } - - /// @FIXME - spoofable - if($AS->data['hubloc']) { + if ($AS->data['hubloc']) { $arr['item_verified'] = true; - if (! array_key_exists('comment_policy',$arr)) { + if (!array_key_exists('comment_policy', $arr)) { // set comment policy depending on source hub. Unknown or osada is ActivityPub. // Anything else we'll say is zot - which could have a range of project names $s = q("select site_project from site where site_url = '%s' limit 1", dbesc($r[0]['hubloc_url']) ); - if ((! $s) || (in_array($s[0]['site_project'],[ '', 'osada' ]))) { + if ((!$s) || (in_array($s[0]['site_project'], ['', 'osada']))) { $arr['comment_policy'] = 'authenticated'; } else { @@ -1262,28 +1268,32 @@ class Libzot { } } } - if($AS->data['signed_data']) { - IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false); + + if ($AS->data['signed_data']) { + IConfig::Set($arr, 'activitypub', 'signed_data', $AS->data['signed_data'], false); + $j = json_decode($AS->data['signed_data'], true); + if ($j) { + IConfig::Set($arr, 'activitypub', 'rawmsg', json_encode(JSalmon::unpack($j['data'])), true); + } } + logger('Activity received: ' . print_r($arr, true), LOGGER_DATA, LOG_DEBUG); + logger('Activity recipients: ' . print_r($deliveries, true), LOGGER_DATA, LOG_DEBUG); - logger('Activity received: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG); - logger('Activity recipients: ' . print_r($deliveries,true), LOGGER_DATA, LOG_DEBUG); + $relay = (($env['type'] === 'response') ? true : false); - $relay = (($env['type'] === 'response') ? true : false ); - - $result = self::process_delivery($env['sender'],$AS,$arr,$deliveries,$relay,false,$message_request); + $result = self::process_delivery($env['sender'], $AS, $arr, $deliveries, $relay, false, $message_request); } - elseif($env['type'] === 'sync') { + elseif ($env['type'] === 'sync') { // $arr = get_channelsync_elements($data); - $arr = json_decode($data,true); + $arr = json_decode($data, true); - logger('Channel sync received: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG); - logger('Channel sync recipients: ' . print_r($deliveries,true), LOGGER_DATA, LOG_DEBUG); + logger('Channel sync received: ' . print_r($arr, true), LOGGER_DATA, LOG_DEBUG); + logger('Channel sync recipients: ' . print_r($deliveries, true), LOGGER_DATA, LOG_DEBUG); if ($env['encoding'] === 'hz') { - $result = Libsync::process_channel_sync_delivery($env['sender'],$arr,$deliveries); + $result = Libsync::process_channel_sync_delivery($env['sender'], $arr, $deliveries); } else { logger('sync packet type not supported.'); @@ -1305,15 +1315,15 @@ class Libzot { * @return boolean */ static function is_top_level($env, $act) { - if($env['encoding'] === 'zot' && array_key_exists('flags',$env) && in_array('thread_parent', $env['flags'])) { + if ($env['encoding'] === 'zot' && array_key_exists('flags', $env) && in_array('thread_parent', $env['flags'])) { return true; } - if($act) { - if(in_array($act->type, ['Like','Dislike'])) { + if ($act) { + if (in_array($act->type, ['Like', 'Dislike'])) { return false; } - $x = self::find_parent($env,$act); - if($x === $act->id || $x === $act->obj['id']) { + $x = self::find_parent($env, $act); + if ($x === $act->id || $x === $act->obj['id']) { return true; } } @@ -1321,12 +1331,12 @@ class Libzot { } - static function find_parent($env,$act) { - if($act) { - if(in_array($act->type, ['Like','Dislike'])) { + static function find_parent($env, $act) { + if ($act) { + if (in_array($act->type, ['Like', 'Dislike'])) { return $act->obj['id']; } - if($act->parent_id) { + if ($act->parent_id) { return $act->parent_id; } } @@ -1355,58 +1365,57 @@ class Libzot { require_once('include/channel.php'); $check_mentions = false; - $include_sys = false; + $include_sys = false; - if($msg['type'] === 'activity') { - $disable_discover_tab = get_config('system','disable_discover_tab') || get_config('system','disable_discover_tab') === false; - if(! $disable_discover_tab) + if ($msg['type'] === 'activity') { + $disable_discover_tab = get_config('system', 'disable_discover_tab') || get_config('system', 'disable_discover_tab') === false; + if (!$disable_discover_tab) $include_sys = true; $perm = 'send_stream'; - if(self::is_top_level($msg,$act)) { + if (self::is_top_level($msg, $act)) { $check_mentions = true; } } - elseif($msg['type'] === 'mail') + elseif ($msg['type'] === 'mail') $perm = 'post_mail'; $r = []; $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)) { + if ($c) { + foreach ($c as $cc) { + if (perm_is_allowed($cc['channel_id'], $msg['sender'], $perm)) { $r[] = $cc['channel_hash']; } } } - if($include_sys) { + if ($include_sys) { $sys = get_sys_channel(); - if($sys) + if ($sys) $r[] = $sys['channel_hash']; } - // look for any public mentions on this site // They will get filtered by tgroup_check() so we don't need to check permissions now - if($check_mentions) { + if ($check_mentions) { // It's a top level post. Look at the tags. See if any of them are mentions and are on this hub. - if($act && $act->obj) { - if(is_array($act->obj['tag']) && $act->obj['tag']) { - foreach($act->obj['tag'] as $tag) { - if($tag['type'] === 'Mention' && (strpos($tag['href'],z_root()) !== false)) { + if ($act && $act->obj) { + if (is_array($act->obj['tag']) && $act->obj['tag']) { + foreach ($act->obj['tag'] as $tag) { + if ($tag['type'] === 'Mention' && (strpos($tag['href'], z_root()) !== false)) { $address = basename($tag['href']); - if($address) { + if ($address) { $z = q("select channel_hash as hash from channel where channel_address = '%s' and channel_removed = 0 limit 1", dbesc($address) ); - if($z) { + if ($z) { $r[] = $z[0]['hash']; } } @@ -1420,15 +1429,15 @@ class Libzot { // everybody that stored a copy of the parent. This way we know we're covered. We'll check the // comment permissions when we deliver them. - $thread_parent = self::find_parent($msg,$act); + $thread_parent = self::find_parent($msg, $act); - if($thread_parent) { + if ($thread_parent) { $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) ); - if($z) { - foreach($z as $zv) { + if ($z) { + foreach ($z as $zv) { $r[] = $zv['hash']; } } @@ -1438,11 +1447,11 @@ class Libzot { // There are probably a lot of duplicates in $r at this point. We need to filter those out. // It's a bit of work since it's a multi-dimensional array - if($r) { + if ($r) { $r = array_values(array_unique($r)); } - logger('public_recips: ' . print_r($r,true), LOGGER_DATA, LOG_DEBUG); + logger('public_recips: ' . print_r($r, true), LOGGER_DATA, LOG_DEBUG); return $r; } @@ -1465,22 +1474,22 @@ class Libzot { // We've validated the sender. Now make sure that the sender is the owner or author - if(! $public) { - if($sender != $arr['owner_xchan'] && $sender != $arr['author_xchan']) { + if (!$public) { + if ($sender != $arr['owner_xchan'] && $sender != $arr['author_xchan']) { logger("Sender $sender is not owner {$arr['owner_xchan']} or author {$arr['author_xchan']} - mid {$arr['mid']}"); return; } } - foreach($deliveries as $d) { + foreach ($deliveries as $d) { $local_public = $public; - $DR = new DReport(z_root(),$sender,$d,$arr['mid']); + $DR = new DReport(z_root(), $sender, $d, $arr['mid']); $channel = channelx_by_hash($d); - if (! $channel) { + if (!$channel) { $DR->update('recipient not found'); $result[] = $DR->get(); continue; @@ -1488,16 +1497,16 @@ class Libzot { $DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>'); - if(($act) && ($act->obj) && (! is_array($act->obj))) { + if (($act) && ($act->obj) && (!is_array($act->obj))) { // The initial object fetch failed using the sys channel credentials. // 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) { + $o = Activity::fetch($act->obj, $channel); + if ($o) { $act->obj = $o; - $arr = array_merge(Activity::decode_note($act),$arr); + $arr = array_merge(Activity::decode_note($act), $arr); } else { @@ -1516,7 +1525,7 @@ class Libzot { * access checks. */ - if($sender === $channel['channel_hash'] && $arr['author_xchan'] === $channel['channel_hash'] && $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; @@ -1526,32 +1535,31 @@ class Libzot { // for comments travelling upstream. Wait and catch them on the way down. // They may have been blocked by the owner. - if(intval($channel['channel_system']) && (! $arr['item_private']) && (! $relay)) { + if (intval($channel['channel_system']) && (!$arr['item_private']) && (!$relay)) { $local_public = true; $r = q("select xchan_selfcensored from xchan where xchan_hash = '%s' limit 1", dbesc($sender) ); // don't import sys channel posts from selfcensored authors - if($r && (intval($r[0]['xchan_selfcensored']))) { + if ($r && (intval($r[0]['xchan_selfcensored']))) { $local_public = false; continue; } - if(! MessageFilter::evaluate($arr,get_config('system','pubstream_incl'),get_config('system','pubstream_excl'))) { + if (!MessageFilter::evaluate($arr, get_config('system', 'pubstream_incl'), get_config('system', 'pubstream_excl'))) { $local_public = false; continue; } } - $tag_delivery = tgroup_check($channel['channel_id'],$arr); - - $perm = 'send_stream'; - if(($arr['mid'] !== $arr['parent_mid']) && ($relay)) + $tag_delivery = tgroup_check($channel['channel_id'], $arr); + $perm = 'send_stream'; + if (($arr['mid'] !== $arr['parent_mid']) && ($relay)) $perm = 'post_comments'; // This is our own post, possibly coming from a channel clone - if($arr['owner_xchan'] == $d) { + if ($arr['owner_xchan'] == $d) { $arr['item_wall'] = 1; } else { @@ -1560,15 +1568,15 @@ class Libzot { $friendofriend = false; - if ((! $tag_delivery) && (! $local_public)) { - $allowed = (perm_is_allowed($channel['channel_id'],$sender,$perm)); - if((! $allowed) && $perm === 'post_comments') { + if ((!$tag_delivery) && (!$local_public)) { + $allowed = (perm_is_allowed($channel['channel_id'], $sender, $perm)); + if (!$allowed) { $parent = q("select * from item where mid = '%s' and uid = %d limit 1", dbesc($arr['parent_mid']), intval($channel['channel_id']) ); if ($parent) { - $allowed = can_comment_on_post($sender,$parent[0]); + $allowed = can_comment_on_post($sender, $parent[0]); } } @@ -1588,7 +1596,7 @@ class Libzot { // doesn't exist. if ($perm === 'send_stream') { - if (get_pconfig($channel['channel_id'],'system','hyperdrive',false) || $arr['verb'] === ACTIVITY_SHARE) { + if (get_pconfig($channel['channel_id'], 'system', 'hyperdrive', false) || $arr['verb'] === ACTIVITY_SHARE) { $allowed = true; } } @@ -1599,7 +1607,7 @@ class Libzot { $friendofriend = true; } - if (! $allowed) { + if (!$allowed) { logger("permission denied for delivery to channel {$channel['channel_id']} {$channel['channel_address']}"); $DR->update('permission denied'); $result[] = $DR->get(); @@ -1609,7 +1617,7 @@ class Libzot { // logger('item: ' . print_r($arr,true), LOGGER_DATA); - if($arr['mid'] !== $arr['parent_mid']) { + if ($arr['mid'] !== $arr['parent_mid']) { logger('checking source: "' . $arr['mid'] . '" != "' . $arr['parent_mid'] . '"'); @@ -1624,7 +1632,7 @@ class Libzot { intval($channel['channel_id']) ); - if(! $r) { + if (!$r) { $DR->update('comment parent not found'); $result[] = $DR->get(); @@ -1639,9 +1647,9 @@ class Libzot { // the top level post is unlikely to be imported and // this is just an exercise in futility. - if((! $relay) && (! $request) && (! $local_public) - && perm_is_allowed($channel['channel_id'],$sender,'send_stream')) { - self::fetch_conversation($channel,$arr['parent_mid']); + if ((!$relay) && (!$request) && (!$local_public) + && perm_is_allowed($channel['channel_id'], $sender, 'send_stream')) { + self::fetch_conversation($channel, $arr['parent_mid']); } continue; } @@ -1650,13 +1658,13 @@ class Libzot { // 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'])) { + 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)) { + 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 // with whatever route our parent has. @@ -1664,7 +1672,7 @@ class Libzot { // but we are now getting comments via listener delivery // and if there is no privacy on this or the parent, we don't care about the route, // so just set the owner and route accordingly. - $arr['route'] = $r[0]['route']; + $arr['route'] = $r[0]['route']; $arr['owner_xchan'] = $r[0]['owner_xchan']; } else { @@ -1676,24 +1684,24 @@ class Libzot { // Always accept empty routes and firehose items (route contains 'undefined') . $existing_route = explode(',', $r[0]['route']); - $routes = count($existing_route); - if($routes) { - $last_hop = array_pop($existing_route); - $last_prior_route = implode(',',$existing_route); + $routes = count($existing_route); + if ($routes) { + $last_hop = array_pop($existing_route); + $last_prior_route = implode(',', $existing_route); } else { - $last_hop = ''; + $last_hop = ''; $last_prior_route = ''; } - if(in_array('undefined',$existing_route) || $last_hop == 'undefined' || $sender == 'undefined') + if (in_array('undefined', $existing_route) || $last_hop == 'undefined' || $sender == 'undefined') $last_hop = ''; $current_route = (($arr['route']) ? $arr['route'] . ',' : '') . $sender; - if($last_hop && $last_hop != $sender) { + if ($last_hop && $last_hop != $sender) { logger('comment route mismatch: parent route = ' . $r[0]['route'] . ' expected = ' . $current_route, LOGGER_DEBUG); - logger('comment route mismatch: parent msg = ' . $r[0]['id'],LOGGER_DEBUG); + logger('comment route mismatch: parent msg = ' . $r[0]['id'], LOGGER_DEBUG); $DR->update('comment route mismatch'); $result[] = $DR->get(); continue; @@ -1706,16 +1714,16 @@ class Libzot { } } - $ab = q("select * from abook where abook_channel = %d and abook_xchan = '%s'", + $ab = q("select * from abook where abook_channel = %d and abook_xchan = '%s'", intval($channel['channel_id']), dbesc($arr['owner_xchan']) ); $abook = (($ab) ? $ab[0] : null); - if(intval($arr['item_deleted'])) { + if (intval($arr['item_deleted'])) { // remove_community_tag is a no-op if this isn't a community tag activity - self::remove_community_tag($sender,$arr,$channel['channel_id']); + self::remove_community_tag($sender, $arr, $channel['channel_id']); // set these just in case we need to store a fresh copy of the deleted post. // This could happen if the delete got here before the original post did. @@ -1723,13 +1731,13 @@ class Libzot { $arr['aid'] = $channel['channel_account_id']; $arr['uid'] = $channel['channel_id']; - $item_id = self::delete_imported_item($sender,$act,$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(); - if($relay && $item_id) { + if ($relay && $item_id) { logger('process_delivery: invoking relay'); - Master::Summon([ 'Notifier', 'relay', intval($item_id) ]); + Master::Summon(['Notifier', 'relay', intval($item_id)]); $DR->update('relayed'); $result[] = $DR->get(); } @@ -1746,11 +1754,11 @@ class Libzot { intval($channel['channel_id']) ); - if($r) { + if ($r) { // We already have this post. $item_id = $r[0]['id']; - if(intval($r[0]['item_deleted'])) { + if (intval($r[0]['item_deleted'])) { // It was deleted locally. $DR->update('update ignored'); $result[] = $DR->get(); @@ -1758,19 +1766,19 @@ class Libzot { continue; } // Maybe it has been edited? - elseif($arr['edited'] > $r[0]['edited']) { - $arr['id'] = $r[0]['id']; + elseif ($arr['edited'] > $r[0]['edited']) { + $arr['id'] = $r[0]['id']; $arr['uid'] = $channel['channel_id']; - if(($arr['mid'] == $arr['parent_mid']) && (! post_is_importable($arr,$abook))) { + if (($arr['mid'] == $arr['parent_mid']) && (!post_is_importable($arr, $abook))) { $DR->update('update ignored'); $result[] = $DR->get(); } else { - $item_result = self::update_imported_item($sender,$arr,$r[0],$channel['channel_id'],$tag_delivery); + $item_result = self::update_imported_item($sender, $arr, $r[0], $channel['channel_id'], $tag_delivery); $DR->update('updated'); $result[] = $DR->get(); - if(! $relay) - add_source_route($item_id,$sender); + if (!$relay) + add_source_route($item_id, $sender); } } else { @@ -1779,7 +1787,7 @@ class Libzot { // We need this line to ensure wall-to-wall comments are relayed (by falling through to the relay bit), // and at the same time not relay any other relayable posts more than once, because to do so is very wasteful. - if(! intval($r[0]['item_origin'])) + if (!intval($r[0]['item_origin'])) continue; } } @@ -1790,7 +1798,7 @@ class Libzot { // if it's a sourced post, call the post_local hooks as if it were // posted locally so that crosspost connectors will be triggered. - if(check_item_source($arr['uid'], $arr) || ($channel['xchan_pubforum'] == 1)) { + if (check_item_source($arr['uid'], $arr) || ($channel['xchan_pubforum'] == 1)) { /** * @hooks post_local * Called when an item has been posted on this machine via mod/item.php (also via API). @@ -1801,19 +1809,19 @@ class Libzot { $item_id = 0; - if(($arr['mid'] == $arr['parent_mid']) && (! post_is_importable($arr,$abook))) { + if (($arr['mid'] == $arr['parent_mid']) && (!post_is_importable($arr, $abook))) { $DR->update('post ignored'); $result[] = $DR->get(); } else { $item_result = item_store($arr); - if($item_result['success']) { + if ($item_result['success']) { $item_id = $item_result['item_id']; - $parr = [ - 'item_id' => $item_id, - 'item' => $arr, - 'sender' => $sender, - 'channel' => $channel + $parr = [ + 'item_id' => $item_id, + 'item' => $arr, + 'sender' => $sender, + 'channel' => $channel ]; /** * @hooks activity_received @@ -1825,8 +1833,8 @@ class Libzot { */ call_hooks('activity_received', $parr); // don't add a source route if it's a relay or later recipients will get a route mismatch - if(! $relay) - add_source_route($item_id,$sender); + if (!$relay) + add_source_route($item_id, $sender); } $DR->update(($item_id) ? 'posted' : 'storage failed: ' . $item_result['message']); $result[] = $DR->get(); @@ -1836,132 +1844,131 @@ class Libzot { // preserve conversations with which you are involved from expiration $stored = (($item_result && $item_result['item']) ? $item_result['item'] : false); - if((is_array($stored)) && ($stored['id'] != $stored['parent']) + if ((is_array($stored)) && ($stored['id'] != $stored['parent']) && ($stored['author_xchan'] === $channel['channel_hash'] || $stored['author_xchan'] === $channel['channel_hash'])) { retain_item($stored['item']['parent']); } - if($relay && $item_id) { + if ($relay && $item_id) { logger('Invoking relay'); - Master::Summon([ 'Notifier', 'relay', intval($item_id) ]); + Master::Summon(['Notifier', 'relay', intval($item_id)]); $DR->addto_update('relayed'); $result[] = $DR->get(); } } - if(! $deliveries) - $result[] = array('', 'no recipients', '', $arr['mid']); + if (!$deliveries) + $result[] = ['', 'no recipients', '', $arr['mid']]; logger('Local results: ' . print_r($result, true), LOGGER_DEBUG); return $result; } - static public function fetch_conversation($channel,$mid) { + static public function fetch_conversation($channel, $mid) { // Use Zotfinger to create a signed request - $a = Zotfinger::exec($mid,$channel); + logger('fetching conversation: ' . $mid, LOGGER_DEBUG); - logger('received conversation: ' . print_r($a,true), LOGGER_DATA); + $a = Zotfinger::exec($mid, $channel); - if($a['data']['type'] !== 'OrderedCollection') { - return; + logger('received conversation: ' . print_r($a, true), LOGGER_DATA); + + if (!$a) { + return false; } - if(! intval($a['data']['totalItems'])) { - return; + if ($a['data']['type'] !== 'OrderedCollection') { + return false; + } + + $obj = new ASCollection($a['data'], $channel); + $items = $obj->get(); + + if (!$items) { + return false; } $ret = []; + $signer = q("select hubloc_hash, hubloc_url from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1", dbesc($a['signature']['signer']) ); - foreach($a['data']['orderedItems'] as $activity) { + foreach ($items as $activity) { $AS = new ActivityStreams($activity); - if(! $AS->is_valid()) { - logger('FOF Activity rejected: ' . print_r($activity,true)); + if ($AS->is_valid() && $AS->type === 'Announce' && is_array($AS->obj) + && array_key_exists('object', $AS->obj) && array_key_exists('actor', $AS->obj)) { + // This is a relayed/forwarded Activity (as opposed to a shared/boosted object) + // Reparse the encapsulated Activity and use that instead + logger('relayed activity', LOGGER_DEBUG); + $AS = new ActivityStreams($AS->obj); + } + + if (!$AS->is_valid()) { + logger('FOF Activity rejected: ' . print_r($activity, true)); continue; } $arr = Activity::decode_note($AS); - logger($AS->debug()); + // logger($AS->debug()); - - $r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1", + $r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' limit 1", dbesc($AS->actor['id']) ); - if(! $r) { - $y = import_author_xchan([ 'url' => $AS->actor['id'] ]); - if($y) { - $r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1", + if (!$r) { + $y = import_author_xchan(['url' => $AS->actor['id']]); + if ($y) { + $r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' limit 1", dbesc($AS->actor['id']) ); } - if(! $r) { + if (!$r) { logger('FOF Activity: no actor'); continue; } } - if($AS->obj['actor'] && $AS->obj['actor']['id'] && $AS->obj['actor']['id'] !== $AS->actor['id']) { - $y = import_author_xchan([ 'url' => $AS->obj['actor']['id'] ]); - if(! $y) { + if ($AS->obj['actor'] && $AS->obj['actor']['id'] && $AS->obj['actor']['id'] !== $AS->actor['id']) { + $y = import_author_xchan(['url' => $AS->obj['actor']['id']]); + if (!$y) { logger('FOF Activity: no object actor'); continue; } } - if($r) { + if ($r) { $arr['author_xchan'] = $r[0]['hubloc_hash']; } - $s = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1", - dbesc($a['signature']['signer']) - ); - - if($s) { - $arr['owner_xchan'] = $s[0]['hubloc_hash']; + if ($signer) { + $arr['owner_xchan'] = $signer[0]['hubloc_hash']; } else { $arr['owner_xchan'] = $a['signature']['signer']; } - - /// @FIXME - spoofable - if($AS->data['hubloc']) { + if ($AS->data['hubloc'] || $arr['author_xchan'] === $arr['owner_xchan']) { $arr['item_verified'] = true; } - // set comment policy depending on source hub. Unknown or osada is ActivityPub. - // Anything else we'll say is zot - which could have a range of project names - - if ($signer) { - $s = q("select site_project from site where site_url = '%s' limit 1", - dbesc($signer[0]['hubloc_url']) - ); - if ((! $s) || (in_array($s[0]['site_project'],[ '', 'osada' ]))) { - $arr['comment_policy'] = 'authenticated'; - } - else { - $arr['comment_policy'] = 'contacts'; + if ($AS->data['signed_data']) { + IConfig::Set($arr, 'activitypub', 'signed_data', $AS->data['signed_data'], false); + $j = json_decode($AS->data['signed_data'], true); + if ($j) { + IConfig::Set($arr, 'activitypub', 'rawmsg', json_encode(JSalmon::unpack($j['data'])), true); } } - - if($AS->data['signed_data']) { - IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false); - } - - logger('FOF Activity received: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG); + logger('FOF Activity received: ' . print_r($arr, true), 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_hash'] ],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); } @@ -1970,7 +1977,6 @@ class Libzot { return $ret; } - /** * @brief Remove community tag. * @@ -1984,12 +1990,12 @@ class Libzot { */ static function remove_community_tag($sender, $arr, $uid) { - if(! (activity_match($arr['verb'], ACTIVITY_TAG) && ($arr['obj_type'] == ACTIVITY_OBJ_TAGTERM))) + if (!(activity_match($arr['verb'], ACTIVITY_TAG) && ($arr['obj_type'] == ACTIVITY_OBJ_TAGTERM))) return; logger('remove_community_tag: invoked'); - if(! get_pconfig($uid,'system','blocktags')) { + if (!get_pconfig($uid, 'system', 'blocktags')) { logger('Permission denied.'); return; } @@ -1998,24 +2004,24 @@ class Libzot { dbesc($arr['mid']), intval($uid) ); - if(! $r) { + if (!$r) { logger('No item'); return; } - if(($sender != $r[0]['owner_xchan']) && ($sender != $r[0]['author_xchan'])) { + if (($sender != $r[0]['owner_xchan']) && ($sender != $r[0]['author_xchan'])) { logger('Sender not authorised.'); return; } $i = $r[0]; - if($i['target']) - $i['target'] = json_decode($i['target'],true); - if($i['object']) - $i['object'] = json_decode($i['object'],true); + if ($i['target']) + $i['target'] = json_decode($i['target'], true); + if ($i['object']) + $i['object'] = json_decode($i['object'], true); - if(! ($i['target'] && $i['object'])) { + if (!($i['target'] && $i['object'])) { logger('No target/object'); return; } @@ -2026,7 +2032,7 @@ class Libzot { dbesc($message_id), intval($uid) ); - if(! $r) { + if (!$r) { logger('No parent message'); return; } @@ -2038,28 +2044,28 @@ class Libzot { intval(TERM_HASHTAG), intval(TERM_COMMUNITYTAG), dbesc($i['object']['title']), - dbesc(get_rel_link($i['object']['link'],'alternate')) + dbesc(get_rel_link($i['object']['link'], 'alternate')) ); } /** * @brief Updates an imported item. * - * @see item_store_update() - * * @param string $sender * @param array $item * @param array $orig * @param int $uid * @param boolean $tag_delivery * @return void|array + * @see item_store_update() + * */ static function update_imported_item($sender, $item, $orig, $uid, $tag_delivery) { // If this is a comment being updated, remove any privacy information // so that item_store_update will set it from the original. - if($item['mid'] !== $item['parent_mid']) { + if ($item['mid'] !== $item['parent_mid']) { unset($item['allow_cid']); unset($item['allow_gid']); unset($item['deny_cid']); @@ -2070,7 +2076,7 @@ class Libzot { // we need the tag_delivery check for downstream flowing posts as the stored post // may have a different owner than the one being transmitted. - if(($sender != $orig['owner_xchan'] && $sender != $orig['author_xchan']) && (! $tag_delivery)) { + if (($sender != $orig['owner_xchan'] && $sender != $orig['author_xchan']) && (!$tag_delivery)) { logger('sender is not owner or author'); return; } @@ -2081,13 +2087,13 @@ class Libzot { // If we're updating an event that we've saved locally, we store the item info first // because event_addtocal will parse the body to get the 'new' event details - if($orig['resource_type'] === 'event') { + if ($orig['resource_type'] === 'event') { $res = event_addtocal($orig['id'], $uid); - if(! $res) + if (!$res) logger('update event: failed'); } - if(! $x['item_id']) + if (!$x['item_id']) logger('update_imported_item: failed: ' . $x['message']); else logger('update_imported_item'); @@ -2111,8 +2117,8 @@ class Libzot { logger('invoked', LOGGER_DEBUG); $ownership_valid = false; - $item_found = false; - $post_id = 0; + $item_found = false; + $post_id = 0; if ($item['verb'] === 'Tombstone') { // The id of the deleted thing is the item mid (activity id) @@ -2131,17 +2137,17 @@ class Libzot { dbesc($sender), dbesc($sender), dbesc($mid), - dbesc(str_replace('/activity/','/item/',$mid)), + dbesc(str_replace('/activity/', '/item/', $mid)), intval($uid) ); - if($r) { + if ($r) { $stored = $r[0]; // we proved ownership in the sql query $ownership_valid = true; - $post_id = $stored['id']; + $post_id = $stored['id']; $item_found = true; } else { @@ -2149,7 +2155,7 @@ class Libzot { logger('delete received for non-existent item or not owned by sender - ignoring.'); } - if($ownership_valid === false) { + if ($ownership_valid === false) { logger('delete_imported_item: failed: ownership issue'); return false; } @@ -2173,10 +2179,10 @@ class Libzot { } } - if($item_found) { - if(intval($stored['item_deleted'])) { + if ($item_found) { + if (intval($stored['item_deleted'])) { logger('delete_imported_item: item was already deleted'); - if(! $relay) + if (!$relay) return false; // This is a bit hackish, but may have to suffice until the notification/delivery loop is optimised @@ -2207,22 +2213,22 @@ class Libzot { static function process_mail_delivery($sender, $arr, $deliveries) { - $result = array(); + $result = []; - if($sender != $arr['from_xchan']) { + if ($sender != $arr['from_xchan']) { logger('process_mail_delivery: sender is not mail author'); return; } - foreach($deliveries as $d) { + foreach ($deliveries as $d) { - $DR = new DReport(z_root(),$sender,$d,$arr['mid']); + $DR = new DReport(z_root(), $sender, $d, $arr['mid']); $r = q("select * from channel where channel_hash = '%s' limit 1", dbesc($d['hash']) ); - if(! $r) { + if (!$r) { $DR->update('recipient not found'); $result[] = $DR->get(); continue; @@ -2232,7 +2238,7 @@ class Libzot { $DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>'); - if(! perm_is_allowed($channel['channel_id'],$sender,'post_mail')) { + if (!perm_is_allowed($channel['channel_id'], $sender, 'post_mail')) { /* * Always allow somebody to reply if you initiated the conversation. It's anti-social @@ -2241,13 +2247,13 @@ class Libzot { */ $return = false; - if($arr['parent_mid']) { + if ($arr['parent_mid']) { $return = q("select * from mail where mid = '%s' and channel_id = %d limit 1", dbesc($arr['parent_mid']), intval($channel['channel_id']) ); } - if(! $return) { + if (!$return) { logger("permission denied for mail delivery {$channel['channel_id']}"); $DR->update('permission denied'); $result[] = $DR->get(); @@ -2260,8 +2266,8 @@ class Libzot { dbesc($arr['mid']), intval($channel['channel_id']) ); - if($r) { - if(intval($arr['mail_recalled'])) { + if ($r) { + if (intval($arr['mail_recalled'])) { $x = q("delete from mail where id = %d and channel_id = %d", intval($r[0]['id']), intval($channel['channel_id']) @@ -2280,7 +2286,7 @@ class Libzot { else { $arr['account_id'] = $channel['channel_account_id']; $arr['channel_id'] = $channel['channel_id']; - $item_id = mail_store($arr); + $item_id = mail_store($arr); $DR->update('mail delivered'); $result[] = $DR->get(); } @@ -2293,12 +2299,12 @@ class Libzot { /** * @brief Processes delivery of profile. * - * @see import_directory_profile() - * * @param string $sender * @param array $arr * @param array $deliveries (unused) * @return void + * @see import_directory_profile() + * */ static function process_profile_delivery($sender, $arr, $deliveries) { @@ -2307,7 +2313,7 @@ class Libzot { $r = q("select xchan_addr from xchan where xchan_hash = '%s' limit 1", dbesc($sender) ); - if($r) { + if ($r) { Libzotdir::import_directory_profile($sender, $arr, $r[0]['xchan_addr'], UPDATE_FLAGS_UPDATED, 0); } } @@ -2329,16 +2335,16 @@ class Libzot { $r = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($sender) ); - if($r) { - $xchan = [ 'id' => $r[0]['xchan_guid'], 'id_sig' => $r[0]['xchan_guid_sig'], - 'hash' => $r[0]['xchan_hash'], 'public_key' => $r[0]['xchan_pubkey'] ]; + if ($r) { + $xchan = ['id' => $r[0]['xchan_guid'], 'id_sig' => $r[0]['xchan_guid_sig'], + 'hash' => $r[0]['xchan_hash'], 'public_key' => $r[0]['xchan_pubkey']]; } - if(array_key_exists('locations',$arr) && $arr['locations']) { - $x = Libsync::sync_locations($xchan,$arr,true); - logger('results: ' . print_r($x,true), LOGGER_DEBUG); - if($x['changed']) { + if (array_key_exists('locations', $arr) && $arr['locations']) { + $x = Libsync::sync_locations($xchan, $arr, true); + logger('results: ' . print_r($x, true), LOGGER_DEBUG); + if ($x['changed']) { //$guid = random_string() . '@' . App::get_hostname(); - Libzotdir::update_modtime($sender,$r[0]['xchan_guid'],$arr['locations'][0]['address'],UPDATE_FLAGS_UPDATED); + Libzotdir::update_modtime($sender, $r[0]['xchan_guid'], $arr['locations'][0]['address'], UPDATE_FLAGS_UPDATED); } } } @@ -2365,10 +2371,10 @@ class Libzot { */ static function check_location_move($sender_hash, $locations) { - if(! $locations) + if (!$locations) return; - if(count($locations) != 1) + if (count($locations) != 1) return; $loc = $locations[0]; @@ -2377,10 +2383,10 @@ class Libzot { dbesc($sender_hash) ); - if(! $r) + if (!$r) return; - if($loc['url'] !== z_root()) { + if ($loc['url'] !== z_root()) { $x = q("update channel set channel_moved = '%s' where channel_hash = '%s' limit 1", dbesc($loc['url']), dbesc($sender_hash) @@ -2390,7 +2396,7 @@ class Libzot { // of the move on singleton networks $arr = [ - 'channel' => $r[0], + 'channel' => $r[0], 'locations' => $locations ]; /** @@ -2407,23 +2413,23 @@ class Libzot { /** * @brief Returns an array with all known distinct hubs for this channel. * - * @see self::get_hublocs() * @param array $channel an associative array which must contain * * \e string \b channel_hash the hash of the channel * @return array an array with associative arrays + * @see self::get_hublocs() */ static function encode_locations($channel) { $ret = []; $x = self::get_hublocs($channel['channel_hash']); - if($x && count($x)) { - foreach($x as $hub) { + if ($x && count($x)) { + foreach ($x as $hub) { // if this is a local channel that has been deleted, the hubloc is no good - make sure it is marked deleted // so that nobody tries to use it. - if(intval($channel['channel_removed']) && $hub['hubloc_url'] === z_root()) + if (intval($channel['channel_removed']) && $hub['hubloc_url'] === z_root()) $hub['hubloc_deleted'] = 1; @@ -2442,15 +2448,15 @@ class Libzot { // version compatibility tweaks - if(! strpos($z['url_sig'],'.')) { + if (!strpos($z['url_sig'], '.')) { $z['url_sig'] = 'sha256.' . $z['url_sig']; } - if(! $z['id_url']) { - $z['id_url'] = $z['url'] . '/channel/' . substr($z['address'],0,strpos($z['address'],'@')); + if (!$z['id_url']) { + $z['id_url'] = $z['url'] . '/channel/' . substr($z['address'], 0, strpos($z['address'], '@')); } - if(! $z['site_id']) { - $z['site_id'] = Libzot::make_xchan_hash($z['url'],$z['sitekey']); + if (!$z['site_id']) { + $z['site_id'] = Libzot::make_xchan_hash($z['url'], $z['sitekey']); } $ret[] = $z; @@ -2469,10 +2475,10 @@ class Libzot { */ static function import_site($arr) { - if( (! is_array($arr)) || (! $arr['url']) || (! $arr['site_sig'])) + if ((!is_array($arr)) || (!$arr['url']) || (!$arr['site_sig'])) return false; - if(! self::verify($arr['url'], $arr['site_sig'], $arr['sitekey'])) { + if (!self::verify($arr['url'], $arr['site_sig'], $arr['sitekey'])) { logger('Bad url_sig'); return false; } @@ -2483,66 +2489,66 @@ class Libzot { $r = q("select * from site where site_url = '%s' limit 1", dbesc($arr['url']) ); - if($r) { - $exists = true; + if ($r) { + $exists = true; $siterecord = $r[0]; } $site_directory = 0; - if($arr['directory_mode'] == 'normal') + if ($arr['directory_mode'] == 'normal') $site_directory = DIRECTORY_MODE_NORMAL; - if($arr['directory_mode'] == 'primary') + if ($arr['directory_mode'] == 'primary') $site_directory = DIRECTORY_MODE_PRIMARY; - if($arr['directory_mode'] == 'secondary') + if ($arr['directory_mode'] == 'secondary') $site_directory = DIRECTORY_MODE_SECONDARY; - if($arr['directory_mode'] == 'standalone') + if ($arr['directory_mode'] == 'standalone') $site_directory = DIRECTORY_MODE_STANDALONE; $register_policy = 0; - if($arr['register_policy'] == 'closed') + if ($arr['register_policy'] == 'closed') $register_policy = REGISTER_CLOSED; - if($arr['register_policy'] == 'open') + if ($arr['register_policy'] == 'open') $register_policy = REGISTER_OPEN; - if($arr['register_policy'] == 'approve') + if ($arr['register_policy'] == 'approve') $register_policy = REGISTER_APPROVE; $access_policy = 0; - if(array_key_exists('access_policy',$arr)) { - if($arr['access_policy'] === 'private') + if (array_key_exists('access_policy', $arr)) { + if ($arr['access_policy'] === 'private') $access_policy = ACCESS_PRIVATE; - if($arr['access_policy'] === 'paid') + if ($arr['access_policy'] === 'paid') $access_policy = ACCESS_PAID; - if($arr['access_policy'] === 'free') + if ($arr['access_policy'] === 'free') $access_policy = ACCESS_FREE; - if($arr['access_policy'] === 'tiered') + if ($arr['access_policy'] === 'tiered') $access_policy = ACCESS_TIERED; } // don't let insecure sites register as public hubs - if(strpos($arr['url'],'https://') === false) + if (strpos($arr['url'], 'https://') === false) $access_policy = ACCESS_PRIVATE; - if($access_policy != ACCESS_PRIVATE) { + if ($access_policy != ACCESS_PRIVATE) { $x = z_fetch_url($arr['url'] . '/siteinfo.json'); - if(! $x['success']) + if (!$x['success']) $access_policy = ACCESS_PRIVATE; } - $directory_url = htmlspecialchars($arr['directory_url'],ENT_COMPAT,'UTF-8',false); - $url = htmlspecialchars(strtolower($arr['url']),ENT_COMPAT,'UTF-8',false); - $sellpage = htmlspecialchars($arr['sellpage'],ENT_COMPAT,'UTF-8',false); - $site_location = htmlspecialchars($arr['location'],ENT_COMPAT,'UTF-8',false); - $site_realm = htmlspecialchars($arr['realm'],ENT_COMPAT,'UTF-8',false); - $site_project = htmlspecialchars($arr['project'],ENT_COMPAT,'UTF-8',false); - $site_crypto = ((array_key_exists('encryption',$arr) && is_array($arr['encryption'])) ? htmlspecialchars(implode(',',$arr['encryption']),ENT_COMPAT,'UTF-8',false) : ''); - $site_version = ((array_key_exists('version',$arr)) ? htmlspecialchars($arr['version'],ENT_COMPAT,'UTF-8',false) : ''); + $directory_url = htmlspecialchars($arr['directory_url'], ENT_COMPAT, 'UTF-8', false); + $url = htmlspecialchars(strtolower($arr['url']), ENT_COMPAT, 'UTF-8', false); + $sellpage = htmlspecialchars($arr['sellpage'], ENT_COMPAT, 'UTF-8', false); + $site_location = htmlspecialchars($arr['location'], ENT_COMPAT, 'UTF-8', false); + $site_realm = htmlspecialchars($arr['realm'], ENT_COMPAT, 'UTF-8', false); + $site_project = htmlspecialchars($arr['project'], ENT_COMPAT, 'UTF-8', false); + $site_crypto = ((array_key_exists('encryption', $arr) && is_array($arr['encryption'])) ? htmlspecialchars(implode(',', $arr['encryption']), ENT_COMPAT, 'UTF-8', false) : ''); + $site_version = ((array_key_exists('version', $arr)) ? htmlspecialchars($arr['version'], ENT_COMPAT, 'UTF-8', false) : ''); // You can have one and only one primary directory per realm. // Downgrade any others claiming to be primary. As they have // flubbed up this badly already, don't let them be directory servers at all. - if(($site_directory === DIRECTORY_MODE_PRIMARY) + if (($site_directory === DIRECTORY_MODE_PRIMARY) && ($site_realm === get_directory_realm()) && ($arr['url'] != get_directory_primary())) { $site_directory = DIRECTORY_MODE_NORMAL; @@ -2550,12 +2556,12 @@ class Libzot { $site_flags = $site_directory; - if(array_key_exists('zot',$arr)) { - set_sconfig($arr['url'],'system','zot_version',$arr['zot']); + if (array_key_exists('zot', $arr)) { + set_sconfig($arr['url'], 'system', 'zot_version', $arr['zot']); } - if($exists) { - if(($siterecord['site_flags'] != $site_flags) + if ($exists) { + if (($siterecord['site_flags'] != $site_flags) || ($siterecord['site_access'] != $access_policy) || ($siterecord['site_directory'] != $directory_url) || ($siterecord['site_sellpage'] != $sellpage) @@ -2564,12 +2570,12 @@ class Libzot { || ($siterecord['site_project'] != $site_project) || ($siterecord['site_realm'] != $site_realm) || ($siterecord['site_crypto'] != $site_crypto) - || ($siterecord['site_version'] != $site_version) ) { + || ($siterecord['site_version'] != $site_version)) { $update = true; - // logger('import_site: input: ' . print_r($arr,true)); - // logger('import_site: stored: ' . print_r($siterecord,true)); + // logger('import_site: input: ' . print_r($arr,true)); + // logger('import_site: stored: ' . print_r($siterecord,true)); $r = q("update site set site_dead = 0, site_location = '%s', site_flags = %d, site_access = %d, site_directory = '%s', site_register = %d, site_update = '%s', site_sellpage = '%s', site_realm = '%s', site_type = %d, site_project = '%s', site_version = '%s', site_crypto = '%s' where site_url = '%s'", @@ -2587,8 +2593,8 @@ class Libzot { dbesc($site_crypto), dbesc($url) ); - if(! $r) { - logger('Update failed. ' . print_r($arr,true)); + if (!$r) { + logger('Update failed. ' . print_r($arr, true)); } } else { @@ -2620,8 +2626,8 @@ class Libzot { ] ); - if(! $r) { - logger('Record create failed. ' . print_r($arr,true)); + if (!$r) { + logger('Record create failed. ' . print_r($arr, true)); } } @@ -2631,14 +2637,14 @@ class Libzot { /** * @brief Returns path to /rpost * - * @todo We probably should make rpost discoverable. - * * @param array $observer * * \e string \b xchan_url * @return string + * @todo We probably should make rpost discoverable. + * */ static function get_rpost_path($observer) { - if(! $observer) + if (!$observer) return ''; $parsed = parse_url($observer['xchan_url']); @@ -2659,11 +2665,11 @@ class Libzot { // we may only end up with one; which results in posts with no author name or photo and are a bit // of a hassle to repair. If either or both are missing, do a full discovery probe. - if(! array_key_exists('id',$x)) { + if (!array_key_exists('id', $x)) { return import_author_activitypub($x); } - $hash = self::make_xchan_hash($x['id'],$x['key']); + $hash = self::make_xchan_hash($x['id'], $x['key']); $desturl = $x['url']; @@ -2680,18 +2686,18 @@ class Libzot { $site_dead = false; - if($r1 && intval($r1[0]['site_dead'])) { + if ($r1 && intval($r1[0]['site_dead'])) { $site_dead = true; } // We have valid and somewhat fresh information. Always true if it is our own site. - if($r1 && $r2 && ( $r1[0]['hubloc_updated'] > datetime_convert('UTC','UTC','now - 1 week') || $r1[0]['hubloc_url'] === z_root() ) ) { + if ($r1 && $r2 && ($r1[0]['hubloc_updated'] > datetime_convert('UTC', 'UTC', 'now - 1 week') || $r1[0]['hubloc_url'] === z_root())) { logger('in cache', LOGGER_DEBUG); return $hash; } - logger('not in cache or cache stale - probing: ' . print_r($x,true), LOGGER_DEBUG,LOG_INFO); + logger('not in cache or cache stale - probing: ' . print_r($x, true), LOGGER_DEBUG, LOG_INFO); // The primary hub may be dead. Try to find another one associated with this identity that is // still alive. If we find one, use that url for the discovery/refresh probe. Otherwise, the dead site @@ -2699,15 +2705,15 @@ class Libzot { // cached entry and the identity is valid. It's just unreachable until they bring back their // server from the grave or create another clone elsewhere. - if($site_dead) { - logger('dead site - ignoring', LOGGER_DEBUG,LOG_INFO); + if ($site_dead) { + logger('dead site - ignoring', LOGGER_DEBUG, LOG_INFO); $r = q("select hubloc_id_url from hubloc left join site on hubloc_url = site_url where hubloc_hash = '%s' and site_dead = 0", dbesc($hash) ); - if($r) { - logger('found another site that is not dead: ' . $r[0]['hubloc_url'], LOGGER_DEBUG,LOG_INFO); + if ($r) { + logger('found another site that is not dead: ' . $r[0]['hubloc_url'], LOGGER_DEBUG, LOG_INFO); $desturl = $r[0]['hubloc_url']; } else { @@ -2715,8 +2721,8 @@ class Libzot { } } - $them = [ 'hubloc_id_url' => $desturl ]; - if(self::refresh($them)) + $them = ['hubloc_id_url' => $desturl]; + if (self::refresh($them)) return $hash; return false; @@ -2724,27 +2730,27 @@ class Libzot { static function zotinfo($arr) { - logger('arr: ' . print_r($arr,true)); + logger('arr: ' . print_r($arr, true)); $ret = []; - $zhash = ((x($arr,'guid_hash')) ? $arr['guid_hash'] : ''); - $zguid = ((x($arr,'guid')) ? $arr['guid'] : ''); - $zguid_sig = ((x($arr,'guid_sig')) ? $arr['guid_sig'] : ''); - $zaddr = ((x($arr,'address')) ? $arr['address'] : ''); - $ztarget = ((x($arr,'target_url')) ? $arr['target_url'] : ''); - $zsig = ((x($arr,'target_sig')) ? $arr['target_sig'] : ''); - $zkey = ((x($arr,'key')) ? $arr['key'] : ''); - $mindate = ((x($arr,'mindate')) ? $arr['mindate'] : ''); - $token = ((x($arr,'token')) ? $arr['token'] : ''); - $feed = ((x($arr,'feed')) ? intval($arr['feed']) : 0); + $zhash = ((x($arr, 'guid_hash')) ? $arr['guid_hash'] : ''); + $zguid = ((x($arr, 'guid')) ? $arr['guid'] : ''); + $zguid_sig = ((x($arr, 'guid_sig')) ? $arr['guid_sig'] : ''); + $zaddr = ((x($arr, 'address')) ? $arr['address'] : ''); + $ztarget = ((x($arr, 'target_url')) ? $arr['target_url'] : ''); + $zsig = ((x($arr, 'target_sig')) ? $arr['target_sig'] : ''); + $zkey = ((x($arr, 'key')) ? $arr['key'] : ''); + $mindate = ((x($arr, 'mindate')) ? $arr['mindate'] : ''); + $token = ((x($arr, 'token')) ? $arr['token'] : ''); + $feed = ((x($arr, 'feed')) ? intval($arr['feed']) : 0); - if($ztarget) { + if ($ztarget) { $t = q("select * from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1", dbesc($ztarget) ); - if($t) { + if ($t) { $ztarget_hash = $t[0]['hubloc_hash']; @@ -2762,21 +2768,21 @@ class Libzot { $r = null; - if(strlen($zhash)) { + if (strlen($zhash)) { $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)) { + elseif (strlen($zguid) && strlen($zguid_sig)) { $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) ); } - elseif(strlen($zaddr)) { - if(strpos($zaddr,'[system]') === false) { /* normal address lookup */ + elseif (strlen($zaddr)) { + if (strpos($zaddr, '[system]') === false) { /* normal address lookup */ $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash where ( channel_address = '%s' or xchan_addr = '%s' ) limit 1", dbesc($zaddr), @@ -2799,7 +2805,7 @@ class Libzot { $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) { + if (!$r) { $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"); } @@ -2807,45 +2813,45 @@ class Libzot { } else { $ret['message'] = 'Invalid request'; - return($ret); + return ($ret); } - if(! $r) { + if (!$r) { $ret['message'] = 'Item not found.'; - return($ret); + return ($ret); } $e = $r[0]; $id = $e['channel_id']; - $sys_channel = (intval($e['channel_system']) ? true : false); - $special_channel = (($e['channel_pageflags'] & PAGE_PREMIUM) ? true : false); - $adult_channel = (($e['channel_pageflags'] & PAGE_ADULT) ? true : false); + $sys_channel = (intval($e['channel_system']) ? true : false); + $special_channel = (($e['channel_pageflags'] & PAGE_PREMIUM) ? true : false); + $adult_channel = (($e['channel_pageflags'] & PAGE_ADULT) ? true : false); $censored = (($e['channel_pageflags'] & PAGE_CENSORED) ? true : false); - $searchable = (($e['channel_pageflags'] & PAGE_HIDDEN) ? false : true); + $searchable = (($e['channel_pageflags'] & PAGE_HIDDEN) ? false : true); $deleted = (intval($e['xchan_deleted']) ? true : false); - if($deleted || $censored || $sys_channel) + if ($deleted || $censored || $sys_channel) $searchable = false; $public_forum = false; - $role = get_pconfig($e['channel_id'],'system','permissions_role'); - if($role === 'forum' || $role === 'repository') { + $role = get_pconfig($e['channel_id'], 'system', 'permissions_role'); + if ($role === 'forum' || $role === 'repository') { $public_forum = true; } else { // check if it has characteristics of a public forum based on custom permissions. $m = Permissions::FilledAutoperms($e['channel_id']); - if($m) { - foreach($m as $k => $v) { - if($k == 'tag_deliver' && intval($v) == 1) - $ch ++; - if($k == 'send_stream' && intval($v) == 0) - $ch ++; + if ($m) { + foreach ($m as $k => $v) { + if ($k == 'tag_deliver' && intval($v) == 1) + $ch++; + if ($k == 'send_stream' && intval($v) == 0) + $ch++; } - if($ch == 2) + if ($ch == 2) $public_forum = true; } } @@ -2856,128 +2862,128 @@ class Libzot { intval($e['channel_id']) ); - $profile = array(); + $profile = []; - if($p) { + if ($p) { - if(! intval($p[0]['publish'])) + if (!intval($p[0]['publish'])) $searchable = false; - $profile['description'] = $p[0]['pdesc']; - $profile['birthday'] = $p[0]['dob']; - if(($profile['birthday'] != '0000-00-00') && (($bd = z_birthday($p[0]['dob'],'UTC')) !== '')) + $profile['description'] = $p[0]['pdesc']; + $profile['birthday'] = $p[0]['dob']; + if (($profile['birthday'] != '0000-00-00') && (($bd = z_birthday($p[0]['dob'], 'UTC')) !== '')) $profile['next_birthday'] = $bd; - if($age = age($p[0]['dob'],$e['channel_timezone'],'')) + if ($age = age($p[0]['dob'], $e['channel_timezone'], '')) $profile['age'] = $age; - $profile['gender'] = $p[0]['gender']; - $profile['marital'] = $p[0]['marital']; - $profile['sexual'] = $p[0]['sexual']; - $profile['locale'] = $p[0]['locality']; - $profile['region'] = $p[0]['region']; - $profile['postcode'] = $p[0]['postal_code']; - $profile['country'] = $p[0]['country_name']; - $profile['about'] = $p[0]['about']; - $profile['homepage'] = $p[0]['homepage']; - $profile['hometown'] = $p[0]['hometown']; + $profile['gender'] = $p[0]['gender']; + $profile['marital'] = $p[0]['marital']; + $profile['sexual'] = $p[0]['sexual']; + $profile['locale'] = $p[0]['locality']; + $profile['region'] = $p[0]['region']; + $profile['postcode'] = $p[0]['postal_code']; + $profile['country'] = $p[0]['country_name']; + $profile['about'] = $p[0]['about']; + $profile['homepage'] = $p[0]['homepage']; + $profile['hometown'] = $p[0]['hometown']; - if($p[0]['keywords']) { - $tags = array(); - $k = explode(' ',$p[0]['keywords']); - if($k) { - foreach($k as $kk) { - if(trim($kk," \t\n\r\0\x0B,")) { - $tags[] = trim($kk," \t\n\r\0\x0B,"); + if ($p[0]['keywords']) { + $tags = []; + $k = explode(' ', $p[0]['keywords']); + if ($k) { + foreach ($k as $kk) { + if (trim($kk, " \t\n\r\0\x0B,")) { + $tags[] = trim($kk, " \t\n\r\0\x0B,"); } } } - if($tags) + if ($tags) $profile['keywords'] = $tags; } } // Communication details - $ret['id'] = $e['xchan_guid']; - $ret['id_sig'] = self::sign($e['xchan_guid'], $e['channel_prvkey']); + $ret['id'] = $e['xchan_guid']; + $ret['id_sig'] = self::sign($e['xchan_guid'], $e['channel_prvkey']); $ret['primary_location'] = [ - 'address' => $e['xchan_addr'], - 'url' => $e['xchan_url'], - 'connections_url' => $e['xchan_connurl'], - 'follow_url' => $e['xchan_follow'], + 'address' => $e['xchan_addr'], + 'url' => $e['xchan_url'], + 'connections_url' => $e['xchan_connurl'], + 'follow_url' => $e['xchan_follow'], ]; - $ret['public_key'] = $e['xchan_pubkey']; - $ret['username'] = $e['channel_address']; - $ret['name'] = $e['xchan_name']; - $ret['name_updated'] = $e['xchan_name_date']; - $ret['photo'] = [ + $ret['public_key'] = $e['xchan_pubkey']; + $ret['username'] = $e['channel_address']; + $ret['name'] = $e['xchan_name']; + $ret['name_updated'] = $e['xchan_name_date']; + $ret['photo'] = [ 'url' => $e['xchan_photo_l'], 'type' => $e['xchan_photo_mimetype'], 'updated' => $e['xchan_photo_date'] ]; - $ret['channel_role'] = get_pconfig($e['channel_id'],'system','permissions_role','custom'); - $ret['protocols'] = [ 'zot6', 'zot' ]; - $ret['searchable'] = $searchable; - $ret['adult_content'] = $adult_channel; - $ret['public_forum'] = $public_forum; + $ret['channel_role'] = get_pconfig($e['channel_id'], 'system', 'permissions_role', 'custom'); + $ret['protocols'] = ['zot6', 'zot']; + $ret['searchable'] = $searchable; + $ret['adult_content'] = $adult_channel; + $ret['public_forum'] = $public_forum; - $ret['comments'] = map_scope(PermissionLimits::Get($e['channel_id'],'post_comments')); - $ret['mail'] = map_scope(PermissionLimits::Get($e['channel_id'],'post_mail')); + $ret['comments'] = map_scope(PermissionLimits::Get($e['channel_id'], 'post_comments')); + $ret['mail'] = map_scope(PermissionLimits::Get($e['channel_id'], 'post_mail')); - if($deleted) - $ret['deleted'] = $deleted; + if ($deleted) + $ret['deleted'] = $deleted; - if(intval($e['channel_removed'])) + if (intval($e['channel_removed'])) $ret['deleted_locally'] = true; // premium or other channel desiring some contact with potential followers before connecting. // This is a template - %s will be replaced with the follow_url we discover for the return channel. - if($special_channel) { + if ($special_channel) { $ret['connect_url'] = (($e['xchan_connpage']) ? $e['xchan_connpage'] : z_root() . '/connect/' . $e['channel_address']); } // This is a template for our follow url, %s will be replaced with a webbie - if(! $ret['follow_url']) + if (!$ret['follow_url']) $ret['follow_url'] = z_root() . '/follow?f=&url=%s'; - $permissions = get_all_perms($e['channel_id'],$ztarget_hash,false,false); + $permissions = get_all_perms($e['channel_id'], $ztarget_hash, false, false); - if($ztarget_hash) { + if ($ztarget_hash) { $permissions['connected'] = false; - $b = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1", + $b = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1", dbesc($ztarget_hash), intval($e['channel_id']) ); - if($b) + if ($b) $permissions['connected'] = true; } - if($permissions['view_profile']) - $ret['profile'] = $profile; + if ($permissions['view_profile']) + $ret['profile'] = $profile; $concise_perms = []; - if($permissions) { - foreach($permissions as $k => $v) { - if($v) { + if ($permissions) { + foreach ($permissions as $k => $v) { + if ($v) { $concise_perms[] = $k; } } - $permissions = implode(',',$concise_perms); + $permissions = implode(',', $concise_perms); } - $ret['permissions'] = $permissions; - $ret['permissions_for'] = $ztarget; + $ret['permissions'] = $permissions; + $ret['permissions_for'] = $ztarget; // array of (verified) hubs this channel uses $x = self::encode_locations($e); - if($x) + if ($x) $ret['locations'] = $x; $ret['site'] = self::site_info(); @@ -2997,58 +3003,58 @@ class Libzot { */ static function site_info() { - $signing_key = get_config('system','prvkey'); - $sig_method = get_config('system','signature_algorithm','sha256'); + $signing_key = get_config('system', 'prvkey'); + $sig_method = get_config('system', 'signature_algorithm', 'sha256'); - $ret = []; - $ret['site'] = []; - $ret['site']['url'] = z_root(); - $ret['site']['site_sig'] = self::sign(z_root(), $signing_key); - $ret['site']['post'] = z_root() . '/zot'; + $ret = []; + $ret['site'] = []; + $ret['site']['url'] = z_root(); + $ret['site']['site_sig'] = self::sign(z_root(), $signing_key); + $ret['site']['post'] = z_root() . '/zot'; $ret['site']['openWebAuth'] = z_root() . '/owa'; $ret['site']['authRedirect'] = z_root() . '/magic'; - $ret['site']['sitekey'] = get_config('system','pubkey'); + $ret['site']['sitekey'] = get_config('system', 'pubkey'); - $dirmode = get_config('system','directory_mode'); - if(($dirmode === false) || ($dirmode == DIRECTORY_MODE_NORMAL)) + $dirmode = get_config('system', 'directory_mode'); + if (($dirmode === false) || ($dirmode == DIRECTORY_MODE_NORMAL)) $ret['site']['directory_mode'] = 'normal'; - if($dirmode == DIRECTORY_MODE_PRIMARY) + if ($dirmode == DIRECTORY_MODE_PRIMARY) $ret['site']['directory_mode'] = 'primary'; - elseif($dirmode == DIRECTORY_MODE_SECONDARY) + elseif ($dirmode == DIRECTORY_MODE_SECONDARY) $ret['site']['directory_mode'] = 'secondary'; - elseif($dirmode == DIRECTORY_MODE_STANDALONE) + elseif ($dirmode == DIRECTORY_MODE_STANDALONE) $ret['site']['directory_mode'] = 'standalone'; - if($dirmode != DIRECTORY_MODE_NORMAL) + if ($dirmode != DIRECTORY_MODE_NORMAL) $ret['site']['directory_url'] = z_root() . '/dirsearch'; - $ret['site']['encryption'] = crypto_methods(); - $ret['site']['zot'] = System::get_zot_revision(); + $ret['site']['encryption'] = Crypto::methods(); + $ret['site']['zot'] = System::get_zot_revision(); // hide detailed site information if you're off the grid - if($dirmode != DIRECTORY_MODE_STANDALONE) { + if ($dirmode != DIRECTORY_MODE_STANDALONE) { - $register_policy = intval(get_config('system','register_policy')); + $register_policy = intval(get_config('system', 'register_policy')); - if($register_policy == REGISTER_CLOSED) + if ($register_policy == REGISTER_CLOSED) $ret['site']['register_policy'] = 'closed'; - if($register_policy == REGISTER_APPROVE) + if ($register_policy == REGISTER_APPROVE) $ret['site']['register_policy'] = 'approve'; - if($register_policy == REGISTER_OPEN) + if ($register_policy == REGISTER_OPEN) $ret['site']['register_policy'] = 'open'; - $access_policy = intval(get_config('system','access_policy')); + $access_policy = intval(get_config('system', 'access_policy')); - if($access_policy == ACCESS_PRIVATE) + if ($access_policy == ACCESS_PRIVATE) $ret['site']['access_policy'] = 'private'; - if($access_policy == ACCESS_PAID) + if ($access_policy == ACCESS_PAID) $ret['site']['access_policy'] = 'paid'; - if($access_policy == ACCESS_FREE) + if ($access_policy == ACCESS_FREE) $ret['site']['access_policy'] = 'free'; - if($access_policy == ACCESS_TIERED) + if ($access_policy == ACCESS_TIERED) $ret['site']['access_policy'] = 'tiered'; $ret['site']['accounts'] = account_total(); @@ -3056,24 +3062,24 @@ class Libzot { require_once('include/channel.php'); $ret['site']['channels'] = channel_total(); - $ret['site']['admin'] = get_config('system','admin_email'); + $ret['site']['admin'] = get_config('system', 'admin_email'); - $visible_plugins = array(); - if(is_array(\App::$plugins) && count(\App::$plugins)) { + $visible_plugins = []; + if (is_array(\App::$plugins) && count(\App::$plugins)) { $r = q("select * from addon where hidden = 0"); - if($r) - foreach($r as $rr) + if ($r) + foreach ($r as $rr) $visible_plugins[] = $rr['aname']; } - $ret['site']['plugins'] = $visible_plugins; - $ret['site']['sitehash'] = get_config('system','location_hash'); - $ret['site']['sitename'] = get_config('system','sitename'); - $ret['site']['sellpage'] = get_config('system','sellpage'); - $ret['site']['location'] = get_config('system','site_location'); - $ret['site']['realm'] = get_directory_realm(); - $ret['site']['project'] = System::get_platform_name(); - $ret['site']['version'] = System::get_project_version(); + $ret['site']['plugins'] = $visible_plugins; + $ret['site']['sitehash'] = get_config('system', 'location_hash'); + $ret['site']['sitename'] = get_config('system', 'sitename'); + $ret['site']['sellpage'] = get_config('system', 'sellpage'); + $ret['site']['location'] = get_config('system', 'site_location'); + $ret['site']['realm'] = get_directory_realm(); + $ret['site']['project'] = System::get_platform_name(); + $ret['site']['version'] = System::get_project_version(); } @@ -3159,36 +3165,36 @@ class Libzot { * @param string $alg (optional) default 'sha256' * @return string */ - static function sign($data,$key,$alg = 'sha256') { - if(! $key) + static function sign($data, $key, $alg = 'sha256') { + if (!$key) return 'no key'; $sig = ''; - openssl_sign($data,$sig,$key,$alg); + openssl_sign($data, $sig, $key, $alg); return $alg . '.' . base64url_encode($sig); } - static function verify($data,$sig,$key) { + static function verify($data, $sig, $key) { $verify = 0; - $x = explode('.',$sig,2); + $x = explode('.', $sig, 2); if ($key && count($x) === 2) { - $alg = $x[0]; + $alg = $x[0]; $signature = base64url_decode($x[1]); - $verify = @openssl_verify($data,$signature,$key,$alg); + $verify = @openssl_verify($data, $signature, $key, $alg); if ($verify === (-1)) { while ($msg = openssl_error_string()) { - logger('openssl_verify: ' . $msg,LOGGER_NORMAL,LOG_ERR); + logger('openssl_verify: ' . $msg, LOGGER_NORMAL, LOG_ERR); } btlogger('openssl_verify: key: ' . $key, LOGGER_DEBUG, LOG_ERR); } } - return(($verify > 0) ? true : false); + return (($verify > 0) ? true : false); } /** @@ -3197,25 +3203,25 @@ class Libzot { * @return boolean */ static function is_zot_request() { - $x = getBestSupportedMimeType([ 'application/x-zot+json' ]); + $x = getBestSupportedMimeType(['application/x-zot+json']); - return(($x) ? true : false); + return (($x) ? true : false); } static public function zot_record_preferred($arr, $check = 'hubloc_network') { - if(! $arr) { + if (!$arr) { return $arr; } - foreach($arr as $v) { - if($v[$check] === 'zot6') { + foreach ($arr as $v) { + if ($v[$check] === 'zot6') { return $v; } } - foreach($arr as $v) { - if($v[$check] === 'zot') { + foreach ($arr as $v) { + if ($v[$check] === 'zot') { return $v; } } diff --git a/Zotlabs/Lib/Libzotdir.php b/Zotlabs/Lib/Libzotdir.php index d4c5398ee..41c0a54e9 100644 --- a/Zotlabs/Lib/Libzotdir.php +++ b/Zotlabs/Lib/Libzotdir.php @@ -311,12 +311,13 @@ class Libzotdir { if ($ud['ud_addr'] && (! ($ud['ud_flags'] & UPDATE_FLAGS_DELETED))) { $success = false; + $zf = []; $href = Webfinger::zot_url(punify($ud['ud_addr'])); if($href) { $zf = Zotfinger::exec($href); } - if(is_array($zf) && array_path_exists('signature/signer',$zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) { + if(array_path_exists('signature/signer',$zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) { $xc = Libzot::import_xchan($zf['data'], 0, $ud); } else { diff --git a/Zotlabs/Lib/NativeWikiPage.php b/Zotlabs/Lib/NativeWikiPage.php index d84cc50a8..71f193b70 100644 --- a/Zotlabs/Lib/NativeWikiPage.php +++ b/Zotlabs/Lib/NativeWikiPage.php @@ -163,7 +163,7 @@ class NativeWikiPage { return [ 'success' => true, 'page' => $page ]; } - return [ 'success' => false, 'item_id' => $c['item_id'], 'message' => t('Page not found') ]; + return [ 'success' => false, 'message' => t('Page not found') ]; } @@ -339,7 +339,6 @@ class NativeWikiPage { } static public function save_page($arr) { - $pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : ''); $content = ((array_key_exists('content',$arr)) ? $arr['content'] : ''); $resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : ''); @@ -385,7 +384,7 @@ class NativeWikiPage { $ret = item_store($item, false, false); if($ret['item_id']) - return array('message' => '', 'item_id' => $ret['item_id'], 'filename' => $filename, 'success' => true); + return array('message' => '', 'item_id' => $ret['item_id'], 'filename' => $pageUrlName, 'success' => true); else return array('message' => t('Page update failed.'), 'success' => false); } @@ -432,12 +431,12 @@ class NativeWikiPage { $channel_id = ((array_key_exists('channel_id',$arr)) ? $arr['channel_id'] : 0); if (! $commitHash) { - return array('content' => $content, 'message' => 'No commit was provided', 'success' => false); + return array('message' => 'No commit was provided', 'success' => false); } $w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id); if (!$w['wiki']) { - return array('content' => $content, 'message' => 'Error reading wiki', 'success' => false); + return array('message' => 'Error reading wiki', 'success' => false); } $x = $arr; @@ -451,7 +450,7 @@ class NativeWikiPage { $content = $loaded['body']; return [ 'content' => $content, 'success' => true ]; } - return [ 'content' => $content, 'success' => false ]; + return [ 'success' => false ]; } } diff --git a/Zotlabs/Lib/Queue.php b/Zotlabs/Lib/Queue.php index 6acc58bc5..779719d8b 100644 --- a/Zotlabs/Lib/Queue.php +++ b/Zotlabs/Lib/Queue.php @@ -2,9 +2,6 @@ namespace Zotlabs\Lib; -use Zotlabs\Lib\Libzot; - - class Queue { static function update($id, $add_priority = 0) { @@ -39,7 +36,7 @@ class Queue { // queue item is less than 12 hours old, we'll schedule for fifteen // minutes. - $r = q("UPDATE outq SET outq_scheduled = '%s' WHERE outq_posturl = '%s'", + q("UPDATE outq SET outq_scheduled = '%s' WHERE outq_posturl = '%s'", dbesc(datetime_convert('UTC','UTC','now + 5 days')), dbesc($x[0]['outq_posturl']) ); @@ -88,7 +85,7 @@ class Queue { static function set_delivered($id,$channel = 0) { logger('queue: set delivered ' . $id,LOGGER_DEBUG); - $sql_extra = (($channel_id) ? " and outq_channel = " . intval($channel_id) . " " : ''); + $sql_extra = (($channel['channel_id']) ? " and outq_channel = " . intval($channel['channel_id']) . " " : ''); // Set the next scheduled run date so far in the future that it will be expired // long before it ever makes it back into the delivery chain. @@ -230,11 +227,10 @@ class Queue { logger('deliver: dest: ' . $outq['outq_posturl'], LOGGER_DEBUG); - if($outq['outq_posturl'] === z_root() . '/zot') { // local delivery $zot = new \Zotlabs\Zot6\Receiver(new \Zotlabs\Zot6\Zot6Handler(),$outq['outq_notify']); - $result = $zot->run(true); + $result = $zot->run(); logger('returned_json: ' . json_encode($result,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES), LOGGER_DATA); logger('deliver: local zot delivery succeeded to ' . $outq['outq_posturl']); Libzot::process_response($outq['outq_posturl'],[ 'success' => true, 'body' => json_encode($result) ], $outq); diff --git a/Zotlabs/Lib/Share.php b/Zotlabs/Lib/Share.php index d34c0eaba..b4cd5a194 100644 --- a/Zotlabs/Lib/Share.php +++ b/Zotlabs/Lib/Share.php @@ -2,8 +2,6 @@ namespace Zotlabs\Lib; -use Zotlabs\Lib\Activity; - class Share { private $item = null; diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php index 024502d2a..2fb07c1cb 100644 --- a/Zotlabs/Lib/ThreadItem.php +++ b/Zotlabs/Lib/ThreadItem.php @@ -35,7 +35,7 @@ class ThreadItem { public function __construct($data) { - + $this->data = $data; $this->toplevel = ($this->get_id() == $this->get_data_value('parent')); $this->threaded = get_config('system','thread_allow'); @@ -98,10 +98,11 @@ class ThreadItem { $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']) + $lock = (((intval($item['item_private'])) || (($item['uid'] == local_channel()) && (strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid'])))) ? t('Private Message') : false); + $locktype = $item['item_private']; $shareable = ((($conv->get_profile_owner() == local_channel() && local_channel()) && ($item['item_private'] != 1)) ? true : false); @@ -151,9 +152,9 @@ class ThreadItem { if($observer && $observer['xchan_hash'] - && ($observer['xchan_hash'] == $this->get_data_value('author_xchan') - || $observer['xchan_hash'] == $this->get_data_value('owner_xchan') - || $observer['xchan_hash'] == $this->get_data_value('source_xchan') + && ($observer['xchan_hash'] == $this->get_data_value('author_xchan') + || $observer['xchan_hash'] == $this->get_data_value('owner_xchan') + || $observer['xchan_hash'] == $this->get_data_value('source_xchan') || $this->get_data_value('uid') == local_channel())) $dropping = true; @@ -169,15 +170,15 @@ class ThreadItem { 'dropping' => $dropping, 'delete' => t('Delete'), ); - } + } elseif(is_site_admin()) { $drop = [ 'dropping' => true, 'delete' => t('Admin Delete') ]; } // FIXME - if($observer_is_pageowner) { + if($observer_is_pageowner) { $multidrop = array( - 'select' => t('Select'), + 'select' => t('Select'), ); } @@ -223,7 +224,7 @@ class ThreadItem { if(! feature_enabled($conv->get_profile_owner(),'dislike')) unset($conv_responses['dislike']); - + $responses = get_responses($conv_responses,$response_verbs,$this,$item); $my_responses = []; @@ -254,7 +255,7 @@ class ThreadItem { } $showlike = ((x($conv_responses['like'],$item['mid'])) ? format_like($conv_responses['like'][$item['mid']],$conv_responses['like'][$item['mid'] . '-l'],'like',$item['mid']) : ''); - $showdislike = ((x($conv_responses['dislike'],$item['mid']) && feature_enabled($conv->get_profile_owner(),'dislike')) + $showdislike = ((x($conv_responses['dislike'],$item['mid']) && feature_enabled($conv->get_profile_owner(),'dislike')) ? format_like($conv_responses['dislike'][$item['mid']],$conv_responses['dislike'][$item['mid'] . '-l'],'dislike',$item['mid']) : ''); /* @@ -264,7 +265,7 @@ class ThreadItem { */ $this->check_wall_to_wall(); - + if($this->is_toplevel()) { // FIXME check this permission if(($conv->get_profile_owner() == local_channel()) && (! array_key_exists('real_uid',$item))) { @@ -275,7 +276,7 @@ class ThreadItem { ); } - } + } else { $is_comment = true; } @@ -349,7 +350,7 @@ class ThreadItem { // $viewthread (below) is only valid in list mode. If this is a channel page, build the thread viewing link // since we can't depend on llink or plink pointing to the right local location. - + $owner_address = substr($item['owner']['xchan_addr'],0,strpos($item['owner']['xchan_addr'],'@')); $viewthread = $item['llink']; if($conv->get_mode() === 'channel') @@ -357,7 +358,7 @@ class ThreadItem { $comment_count_txt = sprintf( tt('%d comment','%d comments',$total_children),$total_children ); $list_unseen_txt = (($unseen_comments) ? sprintf( t('%d unseen'),$unseen_comments) : ''); - + $children = $this->get_children(); $has_tags = (($body['tags'] || $body['categories'] || $body['mentions'] || $body['attachments'] || $body['folders']) ? true : false); @@ -386,7 +387,7 @@ class ThreadItem { $tmp_item = array( 'template' => $this->get_template(), 'mode' => $mode, - 'item_type' => intval($item['item_type']), + 'item_type' => intval($item['item_type']), //'type' => implode("",array_slice(explode("/",$item['verb']),-1)), 'body' => $body['html'], 'tags' => $body['tags'], @@ -432,6 +433,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, + 'locktype' => $locktype, 'delayed' => $item['item_delayed'], 'privacy_warning' => $privacy_warning, 'verified' => $verified, @@ -518,8 +520,8 @@ class ThreadItem { // needed for scroll to comment from notification but needs more work // as we do not want to open all comments unless there is actually an #item_xx anchor -// and the url fragment is not sent to the server. -// if(in_array(\App::$module,['display','update_display'])) +// and the url fragment is not sent to the server. +// if(in_array(\App::$module,['display','update_display'])) // $visible_comments = 99999; if(($this->get_display_mode() === 'normal') && ($nb_children > 0)) { @@ -539,7 +541,7 @@ class ThreadItem { } } } - + $result['private'] = $item['item_private']; $result['toplevel'] = ($this->is_toplevel() ? 'toplevel_item' : ''); @@ -554,7 +556,7 @@ class ThreadItem { return $result; } - + public function get_id() { return $this->get_data_value('id'); } @@ -609,7 +611,7 @@ class ThreadItem { if(activity_match($item->get_data_value('verb'),ACTIVITY_LIKE) || activity_match($item->get_data_value('verb'),ACTIVITY_DISLIKE)) { return false; } - + $item->set_parent($this); $this->children[] = $item; return end($this->children); @@ -683,7 +685,7 @@ class ThreadItem { */ public function set_conversation($conv) { $previous_mode = ($this->conversation ? $this->conversation->get_mode() : ''); - + $this->conversation = $conv; // Set it on our children too @@ -792,7 +794,7 @@ class ThreadItem { if(!$this->is_toplevel() && !get_config('system','thread_allow')) { return ''; } - + $comment_box = ''; $conv = $this->get_conversation(); @@ -808,7 +810,7 @@ class ThreadItem { $arr = array('comment_buttons' => '','id' => $this->get_id()); call_hooks('comment_buttons',$arr); $comment_buttons = $arr['comment_buttons']; - + $comment_box = replace_macros($template,array( '$return_path' => '', '$threaded' => $this->is_threaded(), @@ -865,7 +867,7 @@ class ThreadItem { if($conv->get_mode() === 'channel') return; - + if($this->is_toplevel() && ($this->get_data_value('author_xchan') != $this->get_data_value('owner_xchan'))) { $this->owner_url = chanlink_hash($this->data['owner']['xchan_hash']); $this->owner_photo = $this->data['owner']['xchan_photo_m']; diff --git a/Zotlabs/Lib/Verify.php b/Zotlabs/Lib/Verify.php index 8703e29e6..f8dc8f8d4 100644 --- a/Zotlabs/Lib/Verify.php +++ b/Zotlabs/Lib/Verify.php @@ -5,7 +5,7 @@ namespace Zotlabs\Lib; class Verify { - function create($type,$channel_id,$token,$meta) { + public static function create($type,$channel_id,$token,$meta) { return q("insert into verify ( vtype, channel, token, meta, created ) values ( '%s', %d, '%s', '%s', '%s' )", dbesc($type), intval($channel_id), @@ -15,7 +15,7 @@ class Verify { ); } - function match($type,$channel_id,$token,$meta) { + public static function match($type,$channel_id,$token,$meta) { $r = q("select id from verify where vtype = '%s' and channel = %d and token = '%s' and meta = '%s' limit 1", dbesc($type), intval($channel_id), @@ -31,7 +31,7 @@ class Verify { return false; } - function get_meta($type,$channel_id,$token) { + public static function get_meta($type,$channel_id,$token) { $r = q("select id, meta from verify where vtype = '%s' and channel = %d and token = '%s' limit 1", dbesc($type), intval($channel_id), @@ -52,7 +52,7 @@ class Verify { * @param string $type Verify type * @param string $interval SQL compatible time interval */ - function purge($type, $interval) { + public static function purge($type, $interval) { q("delete from verify where vtype = '%s' and created < %s - INTERVAL %s", dbesc($type), db_utcnow(), diff --git a/Zotlabs/Lib/ZotURL.php b/Zotlabs/Lib/ZotURL.php index 98d1febe5..6bb01fd7a 100644 --- a/Zotlabs/Lib/ZotURL.php +++ b/Zotlabs/Lib/ZotURL.php @@ -21,9 +21,8 @@ class ZotURL { } $portable_url = substr($url,6); - $u = explode('/',$portable_url); + $u = explode('/',$portable_url); $portable_id = $u[0]; - $hosts = self::lookup($portable_id); if(! $hosts) { @@ -39,8 +38,8 @@ class ZotURL { if($channel && $m) { - $headers = [ - 'Accept' => 'application/x-zot+json', + $headers = [ + 'Accept' => 'application/x-zot+json', 'Content-Type' => 'application/x-zot+json', 'X-Zot-Token' => random_string(), 'Digest' => HTTPSig::generate_digest_header($data), @@ -50,9 +49,9 @@ class ZotURL { $h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false); } else { - $h = [ 'Accept: application/x-zot+json' ]; + $h = [ 'Accept: application/x-zot+json' ]; } - + $result = []; $redirects = 0; diff --git a/Zotlabs/Lib/Zotfinger.php b/Zotlabs/Lib/Zotfinger.php index e853d6ebc..840d91403 100644 --- a/Zotlabs/Lib/Zotfinger.php +++ b/Zotlabs/Lib/Zotfinger.php @@ -18,8 +18,8 @@ class Zotfinger { if($channel && $m) { - $headers = [ - 'Accept' => 'application/x-zot+json', + $headers = [ + 'Accept' => 'application/x-zot+json', 'Content-Type' => 'application/x-zot+json', 'X-Zot-Token' => random_string(), 'Digest' => HTTPSig::generate_digest_header($data), @@ -29,11 +29,10 @@ class Zotfinger { $h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false); } else { - $h = [ 'Accept: application/x-zot+json' ]; + $h = [ 'Accept: application/x-zot+json' ]; } - - $result = []; + $result = []; $redirects = 0; $x = z_post_url($resource,$data,$redirects, [ 'headers' => $h ] ); @@ -44,11 +43,11 @@ class Zotfinger { if ($verify) { $result['signature'] = HTTPSig::verify($x, EMPTY_STR, 'zot6'); } - + $result['data'] = json_decode($x['body'],true); if($result['data'] && is_array($result['data']) && array_key_exists('encrypted',$result['data']) && $result['data']['encrypted']) { - $result['data'] = json_decode(crypto_unencapsulate($result['data'],get_config('system','prvkey')),true); + $result['data'] = json_decode(Crypto::unencapsulate($result['data'],get_config('system','prvkey')),true); } logger('decrypted: ' . print_r($result,true)); diff --git a/Zotlabs/Module/Activity.php b/Zotlabs/Module/Activity.php index b75f0b245..48f2663cf 100644 --- a/Zotlabs/Module/Activity.php +++ b/Zotlabs/Module/Activity.php @@ -143,8 +143,8 @@ class Activity extends Controller { 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($portable_id && (! intval($items[0]['item_private']))) { + ThreadListener::store(z_root() . '/activity/' . $item_id, $portable_id); } if(! $i) @@ -239,6 +239,16 @@ class Activity extends Controller { xchan_query($r,true); $items = fetch_post_tags($r,false); + if ($portable_id && (! intval($items[0]['item_private']))) { + $c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'", + intval($items[0]['uid']), + dbesc($portable_id) + ); + if (! $c) { + ThreadListener::store(z_root() . '/activity/' . $item_id, $portable_id); + } + } + $channel = channelx_by_n($items[0]['uid']); $x = array_merge( ['@context' => [ diff --git a/Zotlabs/Module/Article_edit.php b/Zotlabs/Module/Article_edit.php index 635b3ce2a..efa02e1c1 100644 --- a/Zotlabs/Module/Article_edit.php +++ b/Zotlabs/Module/Article_edit.php @@ -63,9 +63,9 @@ class Article_edit extends \Zotlabs\Web\Controller { if ($catsenabled){ $itm = fetch_post_tags($itm); - + $cats = get_terms_oftype($itm[0]['term'], TERM_CATEGORY); - + foreach ($cats as $cat) { if (strlen($category)) $category .= ', '; @@ -113,6 +113,7 @@ class Article_edit extends \Zotlabs\Web\Controller { 'post_id' => $post_id, 'visitor' => true, 'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'), + 'summary' => htmlspecialchars($itm[0]['summary'],ENT_COMPAT,'UTF-8'), 'placeholdertitle' => t('Title (optional)'), 'pagetitle' => $card_title, 'profile_uid' => (intval($channel['channel_id'])), diff --git a/Zotlabs/Module/Articles.php b/Zotlabs/Module/Articles.php index 3f726ebb9..9152f0e0e 100644 --- a/Zotlabs/Module/Articles.php +++ b/Zotlabs/Module/Articles.php @@ -15,7 +15,7 @@ require_once('include/opengraph.php'); class Articles extends Controller { function init() { - + if(argc() > 1) $which = argv(1); @@ -28,13 +28,13 @@ class Articles extends Controller { return; } } - + profile_load($which); - + } - + function get($update = 0, $load = false) { - + if(observer_prohibited(true)) { return login(); } @@ -56,7 +56,7 @@ class Articles extends Controller { nav_set_selected('Articles'); - head_add_link([ + head_add_link([ 'rel' => 'alternate', 'type' => 'application/json+oembed', 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . App::$query_string), @@ -65,7 +65,7 @@ class Articles extends Controller { $category = (($_REQUEST['cat']) ? escape_tags(trim($_REQUEST['cat'])) : ''); - + if($category) { $sql_extra2 .= protect_sprintf(term_item_parent_query(App::$profile['profile_uid'],'item', $category, TERM_CATEGORY)); } @@ -74,24 +74,24 @@ class Articles extends Controller { $datequery2 = ((x($_GET,'dbegin') && is_a_date_arg($_GET['dbegin'])) ? notags($_GET['dbegin']) : ''); $which = argv(1); - + $selected_card = ((argc() > 2) ? argv(2) : ''); $_SESSION['return_url'] = App::$query_string; - + $uid = local_channel(); $owner = App::$profile_uid; $observer = App::get_observer(); - + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); - + if(! perm_is_allowed($owner,$ob_hash,'view_pages')) { notice( t('Permission denied.') . EOL); return; } - + $is_owner = ($uid && $uid == $owner); - + $channel = channelx_by_n($owner); if($channel) { @@ -105,7 +105,7 @@ class Articles extends Controller { else { $channel_acl = [ 'allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ]; } - + if(perm_is_allowed($owner,$ob_hash,'write_pages')) { @@ -114,16 +114,15 @@ class Articles extends Controller { 'webpage' => ITEM_TYPE_ARTICLE, 'is_owner' => true, 'content_label' => t('Add Article'), - 'button' => t('Create'), + 'button' => t('Save'), 'nickname' => $channel['channel_address'], - 'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] + 'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), - 'acl' => (($is_owner) ? populate_acl($channel_acl, false, + 'acl' => (($is_owner) ? populate_acl($channel_acl, false, PermissionDescription::fromGlobalPermission('view_pages')) : ''), 'permissions' => $channel_acl, 'showacl' => (($is_owner) ? true : false), 'visitor' => true, - 'body' => '[summary][/summary]', 'hide_location' => false, 'hide_voting' => false, 'profile_uid' => intval($owner), @@ -147,12 +146,12 @@ class Articles extends Controller { else { $editor = ''; } - + $itemspage = get_pconfig(local_channel(),'system','itemspage'); App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 10)); $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); - + $sql_extra = item_permissions_sql($owner); $sql_item = ''; @@ -176,8 +175,8 @@ class Articles extends Controller { $sql_extra2 .= " and item.item_thread_top != 0 "; } - $r = q("select * from item - where item.uid = %d and item_type = %d + $r = q("select * from item + where item.uid = %d and item_type = %d $sql_extra $sql_extra2 $sql_item order by item.created desc $pager_sql", intval($owner), intval(ITEM_TYPE_ARTICLE) @@ -214,7 +213,7 @@ class Articles extends Controller { opengraph_add_meta((! empty($items) ? $r[0] : []), $channel); $mode = 'articles'; - + if(get_pconfig(local_channel(),'system','articles_list_mode') && (! $selected_card)) $page_mode = 'pager_list'; else diff --git a/Zotlabs/Module/Attach.php b/Zotlabs/Module/Attach.php index 172f6a4bc..5f5779b51 100644 --- a/Zotlabs/Module/Attach.php +++ b/Zotlabs/Module/Attach.php @@ -1,4 +1,5 @@ $zip_filename, - 'zip_path' => $zip_path + 'zip_path' => $zip_path ]; Verify::create('zip_token', 0, $token, json_encode($meta)); json_return_and_die([ 'success' => true, - 'token' => $token + 'token' => $token ]); } @@ -63,28 +64,28 @@ class Attach extends Controller { function get() { - if(argc() < 2) { - notice( t('Item not available.') . EOL); + if (argc() < 2) { + notice(t('Item not available.') . EOL); return; } $token = ((x($_REQUEST, 'token')) ? $_REQUEST['token'] : ''); - if(argv(1) === 'download') { + if (argv(1) === 'download') { $meta = Verify::get_meta('zip_token', 0, $token); - if(! $meta) + if (!$meta) killme(); $meta = json_decode($meta, true); header('Content-Type: application/zip'); - header('Content-Disposition: attachment; filename="'. $meta['zip_filename'] . '"'); + header('Content-Disposition: attachment; filename="' . $meta['zip_filename'] . '"'); header('Content-Length: ' . filesize($meta['zip_path'])); $istream = fopen($meta['zip_path'], 'rb'); $ostream = fopen('php://output', 'wb'); - if($istream && $ostream) { + if ($istream && $ostream) { pipe_streams($istream, $ostream); fclose($istream); fclose($ostream); @@ -94,10 +95,10 @@ class Attach extends Controller { killme(); } - $r = attach_by_hash(argv(1),get_observer_hash(),((argc() > 2) ? intval(argv(2)) : 0)); + $r = attach_by_hash(argv(1), get_observer_hash(), ((argc() > 2) ? intval(argv(2)) : 0)); - if(! $r['success']) { - notice( $r['message'] . EOL); + if (!$r['success']) { + notice($r['message'] . EOL); return; } @@ -105,27 +106,27 @@ class Attach extends Controller { intval($r['data']['uid']) ); - if(! $c) + if (!$c) return; - $unsafe_types = array('text/html','text/css','application/javascript'); + $unsafe_types = array('text/html', 'text/css', 'application/javascript'); - if(in_array($r['data']['filetype'],$unsafe_types) && (! channel_codeallowed($r['data']['uid']))) { - header('Content-Type: text/plain'); + if (in_array($r['data']['filetype'], $unsafe_types) && (!channel_codeallowed($r['data']['uid']))) { + header('Content-Type: text/plain'); } else { header('Content-Type: ' . $r['data']['filetype']); } header('Content-Disposition: attachment; filename="' . $r['data']['filename'] . '"'); - if(intval($r['data']['os_storage'])) { + if (intval($r['data']['os_storage'])) { $fname = $r['data']['content']; - if(strpos($fname,'store') !== false) - $istream = fopen($fname,'rb'); + if (strpos($fname, 'store') !== false) + $istream = fopen($fname, 'rb'); else - $istream = fopen('store/' . $c[0]['channel_address'] . '/' . $fname,'rb'); - $ostream = fopen('php://output','wb'); - if($istream && $ostream) { + $istream = fopen('store/' . $c[0]['channel_address'] . '/' . $fname, 'rb'); + $ostream = fopen('php://output', 'wb'); + if ($istream && $ostream) { pipe_streams($istream, $ostream); fclose($istream); fclose($ostream); @@ -140,14 +141,14 @@ class Attach extends Controller { public function zip_archive_handler($zip, $attach_ids, $attach_path, $pass = 1) { $observer_hash = get_observer_hash(); - $single = ((count($attach_ids) == 1) ? true : false); + $single = ((count($attach_ids) == 1) ? true : false); $download_name = 'download.zip'; - foreach($attach_ids as $attach_id) { + foreach ($attach_ids as $attach_id) { $r = attach_by_id($attach_id, $observer_hash); - if (! $r['success']) { + if (!$r['success']) { continue; } @@ -158,8 +159,8 @@ class Attach extends Controller { if ($attach_path) { $strip_str = $attach_path . '/'; - $count = strlen($strip_str); - $zip_path = substr($r['data']['display_path'], $count); + $count = strlen($strip_str); + $zip_path = substr($r['data']['display_path'], $count); } if ($r['data']['is_dir']) { diff --git a/Zotlabs/Module/Cal.php b/Zotlabs/Module/Cal.php index 07bee38bd..65dba927b 100644 --- a/Zotlabs/Module/Cal.php +++ b/Zotlabs/Module/Cal.php @@ -37,8 +37,6 @@ class Cal extends Controller { $observer = App::get_observer(); App::$data['observer'] = $observer; - $observer_xchan = (($observer) ? $observer['xchan_hash'] : ''); - head_set_icon(App::$data['channel']['xchan_photo_s']); App::$page['htmlhead'] .= "" ; @@ -159,10 +157,10 @@ class Cal extends Controller { 'timezone' => $tz, 'start'=> $start, 'end' => $end, - 'drop' => $drop, + 'drop' => false, 'allDay' => (($rr['adjust']) ? 0 : 1), 'title' => html_entity_decode($rr['summary'], ENT_COMPAT, 'UTF-8'), - 'editable' => $edit ? true : false, + 'editable' => false, 'item' => $rr, 'plink' => [$rr['plink'], t('Link to source')], 'description' => html_entity_decode($rr['description'], ENT_COMPAT, 'UTF-8'), @@ -205,9 +203,9 @@ class Cal extends Controller { '$prev' => t('Previous'), '$next' => t('Next'), '$today' => t('Today'), - '$title' => $title, - '$dtstart' => $dtstart, - '$dtend' => $dtend, + '$title' => '', + '$dtstart' => '', + '$dtend' => '', '$nick' => $nick ]); diff --git a/Zotlabs/Module/Card_edit.php b/Zotlabs/Module/Card_edit.php index e01e70fdb..c57a0f043 100644 --- a/Zotlabs/Module/Card_edit.php +++ b/Zotlabs/Module/Card_edit.php @@ -63,9 +63,9 @@ class Card_edit extends \Zotlabs\Web\Controller { if ($catsenabled){ $itm = fetch_post_tags($itm); - + $cats = get_terms_oftype($itm[0]['term'], TERM_CATEGORY); - + foreach ($cats as $cat) { if (strlen($category)) $category .= ', '; @@ -114,6 +114,7 @@ class Card_edit extends \Zotlabs\Web\Controller { 'post_id' => $post_id, 'visitor' => true, 'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'), + 'summary' => htmlspecialchars($itm[0]['summary'],ENT_COMPAT,'UTF-8'), 'placeholdertitle' => t('Title (optional)'), 'pagetitle' => $card_title, 'profile_uid' => (intval($channel['channel_id'])), diff --git a/Zotlabs/Module/Cards.php b/Zotlabs/Module/Cards.php index c44f7942b..8f47208ce 100644 --- a/Zotlabs/Module/Cards.php +++ b/Zotlabs/Module/Cards.php @@ -110,7 +110,7 @@ class Cards extends Controller { 'webpage' => ITEM_TYPE_CARD, 'is_owner' => true, 'content_label' => t('Add Card'), - 'button' => t('Create'), + 'button' => t('Save'), 'nickname' => $channel['channel_address'], 'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), diff --git a/Zotlabs/Module/Cdav.php b/Zotlabs/Module/Cdav.php index f5c5f4384..fe697a526 100644 --- a/Zotlabs/Module/Cdav.php +++ b/Zotlabs/Module/Cdav.php @@ -284,7 +284,7 @@ class Cdav extends Controller { $server->addPlugin(new \Sabre\CardDAV\VCFExportPlugin()); // And off we go! - $server->exec(); + $server->start(); killme(); diff --git a/Zotlabs/Module/Channel.php b/Zotlabs/Module/Channel.php index 7ff394750..a513523a7 100644 --- a/Zotlabs/Module/Channel.php +++ b/Zotlabs/Module/Channel.php @@ -4,10 +4,13 @@ namespace Zotlabs\Module; use App; -use Zotlabs\Web\Controller; -use Zotlabs\Lib\PermissionDescription; -use Zotlabs\Web\HTTPSig; +use Zotlabs\Lib\Activity; +use Zotlabs\Lib\ActivityStreams; +use Zotlabs\Lib\Crypto; use Zotlabs\Lib\Libzot; +use Zotlabs\Lib\PermissionDescription; +use Zotlabs\Web\Controller; +use Zotlabs\Web\HTTPSig; require_once('include/items.php'); require_once('include/security.php'); @@ -20,88 +23,117 @@ require_once('include/opengraph.php'); * @brief Channel Controller * */ - class Channel extends Controller { function init() { - if(in_array(substr($_GET['search'],0,1),[ '@', '!', '?'])) + if (in_array(substr($_GET['search'], 0, 1), ['@', '!', '?']) || strpos($_GET['search'], 'https://') === 0) goaway('search' . '?f=&search=' . $_GET['search']); $which = null; - if(argc() > 1) + if (argc() > 1) $which = argv(1); - if(! $which) { - if(local_channel()) { + if (!$which) { + if (local_channel()) { $channel = App::get_channel(); - if($channel && $channel['channel_address']) - $which = $channel['channel_address']; + if ($channel && $channel['channel_address']) + $which = $channel['channel_address']; } } - if(! $which) { - notice( t('You must be logged in to see this page.') . EOL ); + if (!$which) { + notice(t('You must be logged in to see this page.') . EOL); return; } $profile = 0; $channel = App::get_channel(); - if((local_channel()) && (argc() > 2) && (argv(2) === 'view')) { - $which = $channel['channel_address']; + if ((local_channel()) && (argc() > 2) && (argv(2) === 'view')) { + $which = $channel['channel_address']; $profile = argv(1); } $channel = channelx_by_nick($which); - if(! $channel) { + if (!$channel) { http_status_exit(404, 'Not found'); } - // handle zot6 channel discovery + // handle zot6 channel discovery + + if (Libzot::is_zot_request()) { - if(Libzot::is_zot_request()) { - $sigdata = HTTPSig::verify(file_get_contents('php://input'), EMPTY_STR, 'zot6'); - if($sigdata && $sigdata['signer'] && $sigdata['header_valid']) { - $data = json_encode(Libzot::zotinfo([ 'address' => $channel['channel_address'], 'target_url' => $sigdata['signer'] ])); - $s = q("select site_crypto, hubloc_sitekey from site left join hubloc on hubloc_url = site_url where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1", + if ($sigdata && $sigdata['signer'] && $sigdata['header_valid']) { + $data = json_encode(Libzot::zotinfo(['address' => $channel['channel_address'], 'target_url' => $sigdata['signer']])); + $s = q("select site_crypto, hubloc_sitekey from site left join hubloc on hubloc_url = site_url where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1", dbesc($sigdata['signer']) ); - if($s) { - $data = json_encode(crypto_encapsulate($data,$s[0]['hubloc_sitekey'],Libzot::best_algorithm($s[0]['site_crypto']))); + if ($s) { + $data = json_encode(Crypto::encapsulate($data, $s[0]['hubloc_sitekey'], Libzot::best_algorithm($s[0]['site_crypto']))); } } else { - $data = json_encode(Libzot::zotinfo([ 'address' => $channel['channel_address'] ])); + $data = json_encode(Libzot::zotinfo(['guid_hash' => $channel['channel_hash']])); } - $headers = [ - 'Content-Type' => 'application/x-zot+json', + $headers = [ + 'Content-Type' => 'application/x-zot+json', 'Digest' => HTTPSig::generate_digest_header($data), '(request-target)' => strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'] - ]; - $h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel)); + ]; + $h = HTTPSig::create_sig($headers, $channel['channel_prvkey'], channel_url($channel)); HTTPSig::set_headers($h); echo $data; killme(); } + if (ActivityStreams::is_as_request($channel)) { - if((local_channel()) && (argc() > 2) && (argv(2) === 'view')) { - $which = $channel['channel_address']; + // Somebody may attempt an ActivityStreams fetch on one of our message permalinks + // Make it do the right thing. + + $mid = ((x($_REQUEST, 'mid')) ? $_REQUEST['mid'] : ''); + if ($mid && strpos($mid, 'b64.') === 0) { + $decoded = @base64url_decode(substr($mid, 4)); + if ($decoded) { + $mid = $decoded; + } + } + if ($mid) { + $obj = null; + if (strpos($mid, z_root() . '/item/') === 0) { + App::$argc = 2; + App::$argv = ['item', basename($mid)]; + $obj = new Item(); + } + if (strpos($mid, z_root() . '/activity/') === 0) { + App::$argc = 2; + App::$argv = ['activity', basename($mid)]; + $obj = new Activity(); + } + if ($obj) { + $obj->init(); + } + } + as_return_and_die(Activity::encode_person($channel, true), $channel); + } + + if ((local_channel()) && (argc() > 2) && (argv(2) === 'view')) { + $which = $channel['channel_address']; $profile = argv(1); } - head_add_link( [ - 'rel' => 'alternate', + head_add_link([ + 'rel' => 'alternate', 'type' => 'application/atom+xml', 'title' => t('Posts and comments'), 'href' => z_root() . '/feed/' . $which ]); - head_add_link( [ - 'rel' => 'alternate', + head_add_link([ + 'rel' => 'alternate', 'type' => 'application/atom+xml', 'title' => t('Only posts'), 'href' => z_root() . '/feed/' . $which . '?f=&top=1' @@ -110,19 +142,19 @@ class Channel extends Controller { // Run profile_load() here to make sure the theme is set before // we start loading content - profile_load($which,$profile); - + profile_load($which, $profile); + // Add Opengraph markup - $mid = ((x($_REQUEST,'mid')) ? $_REQUEST['mid'] : ''); - if(strpos($mid,'b64.') === 0) - $mid = @base64url_decode(substr($mid,4)); - - if($mid) - $r = q("SELECT * FROM item WHERE mid = '%s' AND uid = %d AND item_private = 0 LIMIT 1", - dbesc($mid), - intval($channel['channel_id']) - ); - + $mid = ((x($_REQUEST, 'mid')) ? $_REQUEST['mid'] : ''); + if (strpos($mid, 'b64.') === 0) + $mid = @base64url_decode(substr($mid, 4)); + + if ($mid) + $r = q("SELECT * FROM item WHERE mid = '%s' AND uid = %d AND item_private = 0 LIMIT 1", + dbesc($mid), + intval($channel['channel_id']) + ); + opengraph_add_meta($r ? $r[0] : [], $channel); } @@ -132,99 +164,99 @@ class Channel extends Controller { $category = $datequery = $datequery2 = ''; - $mid = ((x($_REQUEST,'mid')) ? $_REQUEST['mid'] : ''); + $mid = ((x($_REQUEST, 'mid')) ? $_REQUEST['mid'] : ''); - if(strpos($mid,'b64.') === 0) - $decoded = @base64url_decode(substr($mid,4)); - if($decoded) + if (strpos($mid, 'b64.') === 0) + $decoded = @base64url_decode(substr($mid, 4)); + if ($decoded) $mid = $decoded; - $datequery = ((x($_GET,'dend') && is_a_date_arg($_GET['dend'])) ? notags($_GET['dend']) : ''); - $datequery2 = ((x($_GET,'dbegin') && is_a_date_arg($_GET['dbegin'])) ? notags($_GET['dbegin']) : ''); + $datequery = ((x($_GET, 'dend') && is_a_date_arg($_GET['dend'])) ? notags($_GET['dend']) : ''); + $datequery2 = ((x($_GET, 'dbegin') && is_a_date_arg($_GET['dbegin'])) ? notags($_GET['dbegin']) : ''); - if(observer_prohibited(true)) { + if (observer_prohibited(true)) { return login(); } - $category = ((x($_REQUEST,'cat')) ? $_REQUEST['cat'] : ''); - $hashtags = ((x($_REQUEST,'tag')) ? $_REQUEST['tag'] : ''); - $order = ((x($_GET,'order')) ? notags($_GET['order']) : 'post'); - $search = ((x($_GET,'search')) ? $_GET['search'] : EMPTY_STR); + $category = ((x($_REQUEST, 'cat')) ? $_REQUEST['cat'] : ''); + $hashtags = ((x($_REQUEST, 'tag')) ? $_REQUEST['tag'] : ''); + $order = ((x($_GET, 'order')) ? notags($_GET['order']) : 'post'); + $search = ((x($_GET, 'search')) ? $_GET['search'] : EMPTY_STR); - $groups = array(); + $groups = []; $o = ''; - if($update) { + if ($update) { // Ensure we've got a profile owner if updating. App::$profile['profile_uid'] = App::$profile_uid = $update; } $is_owner = (((local_channel()) && (App::$profile['profile_uid'] == local_channel())) ? true : false); - $channel = App::get_channel(); + $channel = App::get_channel(); $observer = App::get_observer(); - $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); - $perms = get_all_perms(App::$profile['profile_uid'],$ob_hash); + $perms = get_all_perms(App::$profile['profile_uid'], $ob_hash); - if(! $perms['view_stream']) { + if (!$perms['view_stream']) { // We may want to make the target of this redirect configurable - if($perms['view_profile']) { - notice( t('Insufficient permissions. Request redirected to profile page.') . EOL); - goaway (z_root() . "/profile/" . App::$profile['channel_address']); + if ($perms['view_profile']) { + notice(t('Insufficient permissions. Request redirected to profile page.') . EOL); + goaway(z_root() . "/profile/" . App::$profile['channel_address']); } - notice( t('Permission denied.') . EOL); + notice(t('Permission denied.') . EOL); return; } - if(! $update) { + if (!$update) { nav_set_selected('Channel Home'); // search terms header - if($search) { - $o .= replace_macros(get_markup_template("section_title.tpl"),array( - '$title' => t('Search Results For:') . ' ' . htmlspecialchars($search, ENT_COMPAT,'UTF-8') - )); + if ($search) { + $o .= replace_macros(get_markup_template("section_title.tpl"), [ + '$title' => t('Search Results For:') . ' ' . htmlspecialchars($search, ENT_COMPAT, 'UTF-8') + ]); } - if($channel && $is_owner) { - $channel_acl = array( + if ($channel && $is_owner) { + $channel_acl = [ 'allow_cid' => $channel['channel_allow_cid'], 'allow_gid' => $channel['channel_allow_gid'], - 'deny_cid' => $channel['channel_deny_cid'], - 'deny_gid' => $channel['channel_deny_gid'] - ); + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ]; } else { - $channel_acl = [ 'allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ]; + $channel_acl = ['allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '']; } - if($perms['post_wall']) { + if ($perms['post_wall']) { - $x = array( - 'is_owner' => $is_owner, - 'allow_location' => ((($is_owner || $observer) && (intval(get_pconfig(App::$profile['profile_uid'],'system','use_browser_location')))) ? true : false), - 'default_location' => (($is_owner) ? App::$profile['channel_location'] : ''), - 'nickname' => App::$profile['channel_address'], - 'lockstate' => (((strlen(App::$profile['channel_allow_cid'])) || (strlen(App::$profile['channel_allow_gid'])) || (strlen(App::$profile['channel_deny_cid'])) || (strlen(App::$profile['channel_deny_gid']))) ? 'lock' : 'unlock'), - 'acl' => (($is_owner) ? populate_acl($channel_acl,true, PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post') : ''), - 'permissions' => $channel_acl, - 'showacl' => (($is_owner) ? 'yes' : ''), - 'bang' => '', - 'visitor' => (($is_owner || $observer) ? true : false), - 'profile_uid' => App::$profile['profile_uid'], + $x = [ + 'is_owner' => $is_owner, + 'allow_location' => ((($is_owner || $observer) && (intval(get_pconfig(App::$profile['profile_uid'], 'system', 'use_browser_location')))) ? true : false), + 'default_location' => (($is_owner) ? App::$profile['channel_location'] : ''), + 'nickname' => App::$profile['channel_address'], + 'lockstate' => (((strlen(App::$profile['channel_allow_cid'])) || (strlen(App::$profile['channel_allow_gid'])) || (strlen(App::$profile['channel_deny_cid'])) || (strlen(App::$profile['channel_deny_gid']))) ? 'lock' : 'unlock'), + 'acl' => (($is_owner) ? populate_acl($channel_acl, true, PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post') : ''), + 'permissions' => $channel_acl, + 'showacl' => (($is_owner) ? 'yes' : ''), + 'bang' => '', + 'visitor' => (($is_owner || $observer) ? true : false), + 'profile_uid' => App::$profile['profile_uid'], 'editor_autocomplete' => true, - 'bbco_autocomplete' => 'bbcode', - 'bbcode' => true, - 'jotnets' => true, - 'reset' => t('Reset form') - ); + 'bbco_autocomplete' => 'bbcode', + 'bbcode' => true, + 'jotnets' => true, + 'reset' => t('Reset form') + ]; - $o .= status_editor($a,$x,false,'Channel'); + $o .= status_editor($a, $x, false, 'Channel'); } } @@ -233,16 +265,16 @@ 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 = " and item.item_hidden = 0 and item.item_type = 0 and item.item_deleted = 0 + + $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 "; + 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']); + $sql_extra = item_permissions_sql(App::$profile['profile_uid']); - if(feature_enabled(App::$profile['profile_uid'], 'channel_list_mode') && (! $mid)) + if (feature_enabled(App::$profile['profile_uid'], 'channel_list_mode') && (!$mid)) $page_mode = 'list'; else $page_mode = 'client'; @@ -250,13 +282,13 @@ class Channel extends Controller { $abook_uids = " and abook.abook_channel = " . intval(App::$profile['profile_uid']) . " "; $simple_update = ''; - if($update && $_SESSION['loadtime']) - $simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) "; + if ($update && $_SESSION['loadtime']) + $simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC', 'UTC', $_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC', 'UTC', $_SESSION['loadtime']) . "' ) "; - if($search) { + if ($search) { $search = escape_tags($search); - if(strpos($search,'#') === 0) { - $sql_extra .= term_query('item',substr($search,1),TERM_HASHTAG,TERM_COMMUNITYTAG); + if (strpos($search, '#') === 0) { + $sql_extra .= term_query('item', substr($search, 1), TERM_HASHTAG, TERM_COMMUNITYTAG); } else { $sql_extra .= sprintf(" AND (item.body like '%s' OR item.title like '%s') ", @@ -266,16 +298,16 @@ class Channel extends Controller { } } - head_add_link([ + head_add_link([ 'rel' => 'alternate', 'type' => 'application/json+oembed', 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . App::$query_string), 'title' => 'oembed' ]); - if(($update) && (! $load)) { + if (($update) && (!$load)) { - if($mid) { + if ($mid) { $r = q("SELECT parent AS item_id from item where mid like '%s' and uid = %d $item_normal_update AND item_wall = 1 $simple_update $sql_extra limit 1", dbesc($mid . '%'), @@ -296,61 +328,61 @@ class Channel extends Controller { } else { - if(x($category)) { - $sql_extra2 .= protect_sprintf(term_item_parent_query(App::$profile['profile_uid'],'item', $category, TERM_CATEGORY)); + if (x($category)) { + $sql_extra2 .= protect_sprintf(term_item_parent_query(App::$profile['profile_uid'], 'item', $category, TERM_CATEGORY)); } - if(x($hashtags)) { - $sql_extra2 .= protect_sprintf(term_item_parent_query(App::$profile['profile_uid'],'item', $hashtags, TERM_HASHTAG, TERM_COMMUNITYTAG)); + if (x($hashtags)) { + $sql_extra2 .= protect_sprintf(term_item_parent_query(App::$profile['profile_uid'], 'item', $hashtags, TERM_HASHTAG, TERM_COMMUNITYTAG)); } - if($datequery) { - $sql_extra2 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery)))); - $order = 'post'; + if ($datequery) { + $sql_extra2 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert(date_default_timezone_get(), '', $datequery)))); + $order = 'post'; } - if($datequery2) { - $sql_extra2 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery2)))); + if ($datequery2) { + $sql_extra2 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(), '', $datequery2)))); } - if($order === 'post') + if ($order === 'post') $ordering = "created"; else $ordering = "commented"; - $itemspage = get_pconfig(local_channel(),'system','itemspage'); + $itemspage = get_pconfig(local_channel(), 'system', 'itemspage'); 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) { - if($mid) { + if ($noscript_content || $load) { + if ($mid) { $r = q("SELECT parent AS item_id from item where mid like '%s' and uid = %d $item_normal AND item_wall = 1 $sql_extra limit 1", dbesc($mid . '%'), intval(App::$profile['profile_uid']) ); - if (! $r) { - notice( t('Permission denied.') . EOL); + if (!$r) { + notice(t('Permission denied.') . EOL); } } else { - $r = q("SELECT DISTINCT item.parent AS item_id, $ordering FROM item + $r = q("SELECT DISTINCT item.parent AS item_id, $ordering FROM item left join abook on ( item.author_xchan = abook.abook_xchan $abook_uids ) WHERE true and item.uid = %d $item_normal AND (abook.abook_blocked = 0 or abook.abook_flags is null) AND item.item_wall = 1 AND item.item_thread_top = 1 - $sql_extra $sql_extra2 + $sql_extra $sql_extra2 ORDER BY $ordering DESC, item_id $pager_sql ", intval(App::$profile['profile_uid']) ); } } else { - $r = array(); + $r = []; } } - if($r) { + if ($r) { - $parents_str = ids_to_querystr($r,'item_id'); + $parents_str = ids_to_querystr($r, 'item_id'); $r = q("SELECT item.*, item.id AS item_id FROM item @@ -363,28 +395,38 @@ class Channel extends Controller { xchan_query($r); $items = fetch_post_tags($r, true); - $items = conv_sort($items,$ordering); + $items = conv_sort($items, $ordering); - if($load && $mid && (! count($items))) { + if ($load && $mid && (!count($items))) { // This will happen if we don't have sufficient permissions // to view the parent item (or the item itself if it is toplevel) - notice( t('Permission denied.') . EOL); + notice(t('Permission denied.') . EOL); } - } else { - $items = array(); + } + else { + $items = []; } - if((! $update) && (! $load)) { + // 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']; + } - if($decoded) + $mode = (($search) ? 'search' : 'channel'); + + if ((!$update) && (!$load)) { + + if ($decoded) $mid = 'b64.' . base64url_encode($mid); // This is ugly, but we can't pass the profile_uid through the session to the ajax updater, // because browser prefetching might change it on us. We have to deliver it with the page. - $maxheight = get_pconfig(App::$profile['profile_uid'],'system','channel_divmore_height'); - if(! $maxheight) + $maxheight = get_pconfig(App::$profile['profile_uid'], 'system', 'channel_divmore_height'); + if (!$maxheight) $maxheight = 400; $o .= '
' . "\r\n"; @@ -392,57 +434,48 @@ class Channel extends Controller { . "; var netargs = '?f='; var profile_page = " . App::$pager['page'] . "; divmore_height = " . intval($maxheight) . ";\r\n"; - App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),array( - '$baseurl' => z_root(), - '$pgtype' => 'channel', - '$uid' => ((App::$profile['profile_uid']) ? App::$profile['profile_uid'] : '0'), - '$gid' => '0', - '$cid' => '0', - '$cmin' => '(-1)', - '$cmax' => '(-1)', - '$star' => '0', - '$liked' => '0', - '$conv' => '0', - '$spam' => '0', - '$nouveau' => '0', - '$wall' => '1', - '$fh' => '0', - '$dm' => '0', - '$page' => ((App::$pager['page'] != 1) ? App::$pager['page'] : 1), - '$search' => $search, - '$xchan' => '', - '$order' => (($order) ? urlencode($order) : ''), - '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0), - '$file' => '', - '$cats' => (($category) ? urlencode($category) : ''), - '$tags' => (($hashtags) ? urlencode($hashtags) : ''), - '$mid' => (($mid) ? urlencode($mid) : ''), - '$verb' => '', - '$net' => '', - '$dend' => $datequery, - '$dbegin' => $datequery2, - '$conv_mode' => 'channel' - )); - + App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"), [ + '$baseurl' => z_root(), + '$pgtype' => 'channel', + '$uid' => ((App::$profile['profile_uid']) ? App::$profile['profile_uid'] : '0'), + '$gid' => '0', + '$cid' => '0', + '$cmin' => '(-1)', + '$cmax' => '(-1)', + '$star' => '0', + '$liked' => '0', + '$conv' => '0', + '$spam' => '0', + '$nouveau' => '0', + '$wall' => '1', + '$fh' => '0', + '$dm' => '0', + '$page' => ((App::$pager['page'] != 1) ? App::$pager['page'] : 1), + '$search' => $search, + '$xchan' => '', + '$order' => (($order) ? urlencode($order) : ''), + '$list' => ((x($_REQUEST, 'list')) ? intval($_REQUEST['list']) : 0), + '$file' => '', + '$cats' => (($category) ? urlencode($category) : ''), + '$tags' => (($hashtags) ? urlencode($hashtags) : ''), + '$mid' => (($mid) ? urlencode($mid) : ''), + '$verb' => '', + '$net' => '', + '$dend' => $datequery, + '$dbegin' => $datequery2, + '$conv_mode' => 'channel', + '$page_mode' => $page_mode + ]); } - // 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'); - - if($update) { - $o .= conversation($items,$mode,$update,$page_mode); + if ($update) { + $o .= conversation($items, $mode, $update, $page_mode); } else { $o .= ''; - $o .= conversation($items,$mode,$update,$page_mode); + $o .= conversation($items, $mode, $update, $page_mode); if ($mid && $items[0]['title']) App::$page['title'] = $items[0]['title'] . " - " . App::$page['title']; } - if($mid) + if ($mid) $o .= ''; $_SESSION['loadtime'] = datetime_convert(); diff --git a/Zotlabs/Module/Channel_calendar.php b/Zotlabs/Module/Channel_calendar.php index ae4afb2f3..ac1545644 100644 --- a/Zotlabs/Module/Channel_calendar.php +++ b/Zotlabs/Module/Channel_calendar.php @@ -1,7 +1,12 @@ set($x[0]); - + $created = $x[0]['created']; - $edited = datetime_convert(); + $edited = datetime_convert(); } else { $created = $edited = datetime_convert(); $acl->set_from_array($_POST); } - + $post_tags = array(); - $channel = \App::get_channel(); - $ac = $acl->get(); + $channel = App::get_channel(); + $ac = $acl->get(); $str_contact_allow = $ac['allow_cid']; $str_group_allow = $ac['allow_gid']; - $str_contact_deny = $ac['deny_cid']; - $str_group_deny = $ac['deny_gid']; + $str_contact_deny = $ac['deny_cid']; + $str_group_deny = $ac['deny_gid']; $private = $acl->is_private(); require_once('include/text.php'); - $results = linkify_tags($desc, local_channel()); + $results = linkify_tags($desc, $uid); - if($results) { + if ($results) { // Set permissions based on tag replacements - set_linkified_perms($results, $str_contact_allow, $str_group_allow, local_channel(), false, $private); + set_linkified_perms($results, $str_contact_allow, $str_group_allow, $uid, false, $private); - foreach($results as $result) { + foreach ($results as $result) { $success = $result['success']; - if($success['replaced']) { + if ($success['replaced']) { $post_tags[] = array( - 'uid' => local_channel(), + 'uid' => $uid, 'ttype' => $success['termtype'], 'otype' => TERM_OBJ_POST, 'term' => $success['term'], 'url' => $success['url'] - ); + ); } } } - if(strlen($categories)) { - $cats = explode(',',$categories); - foreach($cats as $cat) { + if (strlen($categories)) { + $cats = explode(',', $categories); + foreach ($cats as $cat) { $post_tags[] = array( - 'uid' => local_channel(), + 'uid' => $uid, 'ttype' => TERM_CATEGORY, 'otype' => TERM_OBJ_POST, 'term' => trim($cat), @@ -141,175 +144,170 @@ class Channel_calendar extends \Zotlabs\Web\Controller { ); } } - - $datarray = array(); - $datarray['dtstart'] = $start; - $datarray['dtend'] = $finish; - $datarray['summary'] = $summary; - $datarray['description'] = $desc; - $datarray['location'] = $location; - $datarray['etype'] = $type; - $datarray['adjust'] = $adjust; - $datarray['nofinish'] = 0; - $datarray['uid'] = local_channel(); - $datarray['account'] = get_account_id(); - $datarray['event_xchan'] = $channel['channel_hash']; - $datarray['allow_cid'] = $str_contact_allow; - $datarray['allow_gid'] = $str_group_allow; - $datarray['deny_cid'] = $str_contact_deny; - $datarray['deny_gid'] = $str_group_deny; - $datarray['private'] = intval($private); - $datarray['id'] = $event_id; - $datarray['created'] = $created; - $datarray['edited'] = $edited; - $datarray['timezone'] = $tz; - - if(intval($_REQUEST['preview'])) { + $datarray = array(); + $datarray['dtstart'] = $start; + $datarray['dtend'] = $finish; + $datarray['summary'] = $summary; + $datarray['description'] = $desc; + $datarray['location'] = $location; + $datarray['etype'] = $type; + $datarray['adjust'] = $adjust; + $datarray['nofinish'] = 0; + $datarray['uid'] = $uid; + $datarray['account'] = get_account_id(); + $datarray['event_xchan'] = $channel['channel_hash']; + $datarray['allow_cid'] = $str_contact_allow; + $datarray['allow_gid'] = $str_group_allow; + $datarray['deny_cid'] = $str_contact_deny; + $datarray['deny_gid'] = $str_group_deny; + $datarray['private'] = intval($private); + $datarray['id'] = $event_id; + $datarray['created'] = $created; + $datarray['edited'] = $edited; + $datarray['timezone'] = $tz; + + + if (intval($_REQUEST['preview'])) { $html = format_event_html($datarray); echo $html; killme(); } - + $event = event_store_event($datarray); - - if($post_tags) + + if ($post_tags) $datarray['term'] = $post_tags; - - $item_id = event_store_item($datarray,$event); - - if($item_id) { + + $item_id = event_store_item($datarray, $event); + + if ($item_id) { $r = q("select * from item where id = %d", intval($item_id) ); - if($r) { + if ($r) { xchan_query($r); $sync_item = fetch_post_tags($r); - $z = q("select * from event where event_hash = '%s' and uid = %d limit 1", + $z = q("select * from event where event_hash = '%s' and uid = %d limit 1", dbesc($r[0]['resource_id']), intval($channel['channel_id']) ); - if($z) { - Libsync::build_sync_packet($channel['channel_id'],array('event_item' => array(encode_item($sync_item[0],true)),'event' => $z)); + if ($z) { + Libsync::build_sync_packet($channel['channel_id'], array('event_item' => array(encode_item($sync_item[0], true)), 'event' => $z)); } } } - - \Zotlabs\Daemon\Master::Summon(array('Notifier','event',$item_id)); + + Master::Summon(array('Notifier', 'event', $item_id)); killme(); - + } - - - + + function get() { - - if(argc() > 2 && argv(1) == 'ical') { + + if (argc() > 2 && argv(1) == 'ical') { $event_id = argv(2); - + require_once('include/security.php'); $sql_extra = permissions_sql(local_channel()); - + $r = q("select * from event where event_hash = '%s' $sql_extra limit 1", dbesc($event_id) ); - if($r) { + if ($r) { header('Content-type: text/calendar'); - header('content-disposition: attachment; filename="' . t('event') . '-' . $event_id . '.ics"' ); + header('content-disposition: attachment; filename="' . t('event') . '-' . $event_id . '.ics"'); echo ical_wrapper($r); killme(); } else { - notice( t('Event not found.') . EOL ); + notice(t('Event not found.') . EOL); return; } } - - if(! local_channel()) { - notice( t('Permission denied.') . EOL); + + if (!local_channel()) { + notice(t('Permission denied.') . EOL); return; } - if((argc() > 2) && (argv(1) === 'ignore') && intval(argv(2))) { - $r = q("update event set dismissed = 1 where id = %d and uid = %d", - intval(argv(2)), - intval(local_channel()) - ); - } - - if((argc() > 2) && (argv(1) === 'unignore') && intval(argv(2))) { - $r = q("update event set dismissed = 0 where id = %d and uid = %d", + if ((argc() > 2) && (argv(1) === 'ignore') && intval(argv(2))) { + q("update event set dismissed = 1 where id = %d and uid = %d", intval(argv(2)), intval(local_channel()) ); } - $channel = \App::get_channel(); - - $mode = 'view'; - $export = false; - $ignored = ((x($_REQUEST,'ignored')) ? " and dismissed = " . intval($_REQUEST['ignored']) . " " : ''); + if ((argc() > 2) && (argv(1) === 'unignore') && intval(argv(2))) { + q("update event set dismissed = 0 where id = %d and uid = %d", + intval(argv(2)), + intval(local_channel()) + ); + } - if(argc() > 1) { - if(argc() > 2 && argv(1) === 'add') { - $mode = 'add'; + $mode = 'view'; + $export = false; + $ignored = ((x($_REQUEST, 'ignored')) ? " and dismissed = " . intval($_REQUEST['ignored']) . " " : ''); + + if (argc() > 1) { + if (argc() > 2 && argv(1) === 'add') { + $mode = 'add'; $item_id = intval(argv(2)); } - if(argc() > 2 && argv(1) === 'drop') { - $mode = 'drop'; + if (argc() > 2 && argv(1) === 'drop') { + $mode = 'drop'; $event_id = argv(2); } - if(argc() <= 2 && argv(1) === 'export') { + if (argc() <= 2 && argv(1) === 'export') { $export = true; } - if(argc() > 2 && intval(argv(1)) && intval(argv(2))) { + if (argc() > 2 && intval(argv(1)) && intval(argv(2))) { $mode = 'view'; } - if(argc() <= 2) { - $mode = 'view'; + if (argc() <= 2) { + $mode = 'view'; $event_id = argv(1); } } - - if($mode === 'add') { - event_addtocal($item_id,local_channel()); + + if ($mode === 'add') { + event_addtocal($item_id, local_channel()); killme(); } - - if($mode == 'view') { - + + if ($mode == 'view') { + /* edit/create form */ - if($event_id) { - $r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1", + if ($event_id) { + q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1", dbesc($event_id), intval(local_channel()) ); - if(count($r)) - $orig_event = $r[0]; } - - $channel = \App::get_channel(); - if (argv(1) === 'json'){ - if (x($_GET,'start')) $start = $_GET['start']; - if (x($_GET,'end')) $finish = $_GET['end']; + $channel = App::get_channel(); + + if (argv(1) === 'json') { + if (x($_GET, 'start')) $start = $_GET['start']; + if (x($_GET, 'end')) $finish = $_GET['end']; } - - $start = datetime_convert('UTC','UTC',$start); - $finish = datetime_convert('UTC','UTC',$finish); - $adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start); + + $start = datetime_convert('UTC', 'UTC', $start); + $finish = datetime_convert('UTC', 'UTC', $finish); + $adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start); $adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish); - if (x($_GET,'id')){ - $r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan, item.id as item_id + if (x($_GET, 'id')) { + $r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan, item.id as item_id from event left join item on item.resource_id = event.event_hash where item.resource_type = 'event' and event.uid = %d and event.id = %d limit 1", intval(local_channel()), intval($_GET['id']) ); } - elseif($export) { + elseif ($export) { $r = q("SELECT event.*, item.id as item_id from event left join item on item.resource_id = event.event_hash where event.uid = %d and event.dtstart > '%s' and event.dtend > event.dtstart", @@ -335,104 +333,105 @@ class Channel_calendar extends \Zotlabs\Web\Controller { dbesc($adjust_finish) ); } - - if($r && ! $export) { + + if ($r && !$export) { xchan_query($r); - $r = fetch_post_tags($r,true); + $r = fetch_post_tags($r, true); $r = sort_by_date($r); } $events = []; - if($r) { - - foreach($r as $rr) { + if ($r) { + + foreach ($r as $rr) { $start = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtstart'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtstart'], 'c')); - if ($rr['nofinish']){ + if ($rr['nofinish']) { $end = null; - } else { + } + else { $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'); - $categories = ''; - if($catsenabled){ - if($rr['term']) { + $catsenabled = feature_enabled(local_channel(), 'categories'); + $categories = ''; + if ($catsenabled) { + if ($rr['term']) { $cats = get_terms_oftype($rr['term'], TERM_CATEGORY); foreach ($cats as $cat) { - if(strlen($categories)) + if (strlen($categories)) $categories .= ', '; $categories .= $cat['term']; } } } - $edit = ((local_channel() && $rr['author_xchan'] == get_observer_hash()) ? array(z_root().'/events/'.$rr['event_hash'].'?expandform=1',t('Edit event'),'','') : false); - - $drop = array(z_root().'/events/drop/'.$rr['event_hash'],t('Delete event'),'',''); - + $edit = ((local_channel() && $rr['author_xchan'] == get_observer_hash()) ? array(z_root() . '/events/' . $rr['event_hash'] . '?expandform=1', t('Edit event'), '', '') : false); + + $drop = array(z_root() . '/events/drop/' . $rr['event_hash'], t('Delete event'), '', ''); + $tz = get_iconfig($rr, 'event', 'timezone'); - if(! $tz) + if (!$tz) $tz = 'UTC'; $events[] = array( 'calendar_id' => 'channel_calendar', - 'rw' => true, - 'id'=>$rr['id'], - 'uri' => $rr['event_hash'], - 'timezone' => $tz, - 'start'=> $start, - 'end' => $end, - 'drop' => $drop, - 'allDay' => (($rr['adjust']) ? 0 : 1), - 'title' => html_entity_decode($rr['summary'], ENT_COMPAT, 'UTF-8'), - 'editable' => $edit ? true : false, - 'item' => $rr, - 'plink' => [$rr['plink'], t('Link to source')], + 'rw' => true, + 'id' => $rr['id'], + 'uri' => $rr['event_hash'], + 'timezone' => $tz, + 'start' => $start, + 'end' => $end, + 'drop' => $drop, + 'allDay' => (($rr['adjust']) ? 0 : 1), + 'title' => html_entity_decode($rr['summary'], ENT_COMPAT, 'UTF-8'), + 'editable' => $edit ? true : false, + 'item' => $rr, + 'plink' => [$rr['plink'], t('Link to source')], 'description' => html_entity_decode($rr['description'], ENT_COMPAT, 'UTF-8'), - 'location' => html_entity_decode($rr['location'], ENT_COMPAT, 'UTF-8'), - 'allow_cid' => expand_acl($rr['allow_cid']), - 'allow_gid' => expand_acl($rr['allow_gid']), - 'deny_cid' => expand_acl($rr['deny_cid']), - 'deny_gid' => expand_acl($rr['deny_gid']), - 'categories' => $categories + 'location' => html_entity_decode($rr['location'], ENT_COMPAT, 'UTF-8'), + 'allow_cid' => expand_acl($rr['allow_cid']), + 'allow_gid' => expand_acl($rr['allow_gid']), + 'deny_cid' => expand_acl($rr['deny_cid']), + 'deny_gid' => expand_acl($rr['deny_gid']), + 'categories' => $categories ); } } - - if($export) { + + if ($export) { header('Content-type: text/calendar'); - header('content-disposition: attachment; filename="' . t('calendar') . '-' . $channel['channel_address'] . '.ics"' ); + header('content-disposition: attachment; filename="' . t('calendar') . '-' . $channel['channel_address'] . '.ics"'); echo ical_wrapper($r); killme(); } - if (\App::$argv[1] === 'json'){ + if (App::$argv[1] === 'json') { json_return_and_die($events); } } - - if($mode === 'drop' && $event_id) { + + if ($mode === 'drop' && $event_id) { $r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1", dbesc($event_id), intval(local_channel()) ); - + $sync_event = $r[0]; - - if($r) { + + if ($r) { $r = q("delete from event where event_hash = '%s' and uid = %d", dbesc($event_id), intval(local_channel()) ); - if($r) { + if ($r) { $sync_event['event_deleted'] = 1; - Libsync::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), @@ -441,11 +440,11 @@ class Channel_calendar extends \Zotlabs\Web\Controller { if ($i) { - $can_delete = false; + $can_delete = false; $local_delete = true; $ob_hash = get_observer_hash(); - if($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan'])) { + if ($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan'])) { $can_delete = true; } @@ -453,49 +452,49 @@ class Channel_calendar extends \Zotlabs\Web\Controller { // If the item originated on this site+channel the deletion will propagate downstream. // Otherwise just the local copy is removed. - if(is_site_admin()) { + if (is_site_admin()) { $local_delete = true; - if(intval($i[0]['item_origin'])) + if (intval($i[0]['item_origin'])) $can_delete = true; } - if($can_delete || $local_delete) { + if ($can_delete || $local_delete) { // if this is a different page type or it's just a local delete // but not by the item author or owner, do a simple deletion - $complex = false; + $complex = false; - if(intval($i[0]['item_type']) || ($local_delete && (! $can_delete))) { + if (intval($i[0]['item_type']) || ($local_delete && (!$can_delete))) { drop_item($i[0]['id']); } else { // complex deletion that needs to propagate and be performed in phases - drop_item($i[0]['id'],true,DROPITEM_PHASE1); + drop_item($i[0]['id'], true, DROPITEM_PHASE1); $complex = true; } $ii = q("select * from item where id = %d", intval($i[0]['id']) ); - if($ii) { + if ($ii) { xchan_query($ii); $sync_item = fetch_post_tags($ii); - Libsync::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) { - tag_deliver($i[0]['uid'],$i[0]['id']); + if ($complex) { + tag_deliver($i[0]['uid'], $i[0]['id']); } } } killme(); } - notice( t('Failed to remove event' ) . EOL); + notice(t('Failed to remove event') . EOL); killme(); } } - + } - + } diff --git a/Zotlabs/Module/Chanview.php b/Zotlabs/Module/Chanview.php index 12e1891d4..8ae4841b4 100644 --- a/Zotlabs/Module/Chanview.php +++ b/Zotlabs/Module/Chanview.php @@ -70,7 +70,7 @@ class Chanview extends \Zotlabs\Web\Controller { $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); + Libzot::import_xchan($zf['data']); $r = q("select * from xchan where xchan_url = '%s'", dbesc($_REQUEST['url']) ); diff --git a/Zotlabs/Module/Cloud.php b/Zotlabs/Module/Cloud.php index 39ae0f92f..3d1b97980 100644 --- a/Zotlabs/Module/Cloud.php +++ b/Zotlabs/Module/Cloud.php @@ -105,7 +105,7 @@ class Cloud extends Controller { // All we need to do now, is to fire up the server - $server->exec(); + $server->start(); if($browser->build_page) construct_page(); diff --git a/Zotlabs/Module/Connections.php b/Zotlabs/Module/Connections.php index 7dc301623..5025f4e22 100644 --- a/Zotlabs/Module/Connections.php +++ b/Zotlabs/Module/Connections.php @@ -109,6 +109,7 @@ class Connections extends \Zotlabs\Web\Controller { case 'all': $head = t('All'); + break; default: $search_flags = " and abook_blocked = 0 and abook_ignored = 0 and abook_hidden = 0 and abook_archived = 0 and abook_not_here = 0 "; $active = true; @@ -238,7 +239,7 @@ class Connections extends \Zotlabs\Web\Controller { } $r = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash - where abook_channel = %d and abook_self = 0 and xchan_deleted = 0 and xchan_orphan = 0 $sql_extra $sql_extra2 ", + where abook_channel = %d and abook_self = 0 and xchan_deleted = 0 and xchan_orphan = 0 $sql_extra ", intval(local_channel()) ); if($r) { @@ -247,7 +248,7 @@ class Connections extends \Zotlabs\Web\Controller { } $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash - WHERE abook_channel = %d and abook_self = 0 and xchan_deleted = 0 and xchan_orphan = 0 $sql_extra $sql_extra2 ORDER BY $sql_order LIMIT %d OFFSET %d ", + WHERE abook_channel = %d and abook_self = 0 and xchan_deleted = 0 and xchan_orphan = 0 $sql_extra ORDER BY $sql_order LIMIT %d OFFSET %d ", intval(local_channel()), intval(App::$pager['itemspage']), intval(App::$pager['start']) diff --git a/Zotlabs/Module/Connedit.php b/Zotlabs/Module/Connedit.php index becf8460d..44211c8b9 100644 --- a/Zotlabs/Module/Connedit.php +++ b/Zotlabs/Module/Connedit.php @@ -9,6 +9,7 @@ namespace Zotlabs\Module; use App; use Zotlabs\Lib\Apps; +use Zotlabs\Lib\Crypto; use Zotlabs\Lib\Libzot; use Zotlabs\Lib\Libsync; use Zotlabs\Daemon\Master; @@ -32,10 +33,10 @@ class Connedit extends Controller { */ function init() { - + if(! local_channel()) return; - + if((argc() >= 2) && intval(argv(1))) { $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash @@ -47,54 +48,54 @@ class Connedit extends Controller { App::$poi = array_shift($r); } } - + $channel = App::get_channel(); if($channel) head_set_icon($channel['xchan_photo_s']); - + } - + /* @brief Evaluate posted values and set changes * */ - + function post() { - + if(! local_channel()) return; - + $contact_id = intval(argv(1)); if(! $contact_id) return; - + $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 // the other form elements alone pending a manual submit of the form. The downside is that there // will be a window of opportunity when the permissions have been set but before you've had a chance // to review and possibly restrict them. The upside is we won't have to warn you that your connection // can't do anything until you save the bloody form. - + $autopost = (((argc() > 2) && (argv(2) === 'auto')) ? true : false); - + $orig_record = q("SELECT * FROM abook WHERE abook_id = %d AND abook_channel = %d LIMIT 1", intval($contact_id), intval(local_channel()) ); - + if(! $orig_record) { notice( t('Could not access contact record.') . EOL); goaway(z_root() . '/connections'); return; // NOTREACHED } - + call_hooks('contact_edit_post', $_POST); - + $vc = get_abconfig(local_channel(),$orig_record['abook_xchan'],'system','vcard'); - $vcard = (($vc) ? \Sabre\VObject\Reader::read($vc) : null); + $vcard = (($vc) ? \Sabre\VObject\Reader::read($vc) : null); $serialised_vcard = update_vcard($_REQUEST,$vcard); if($serialised_vcard) set_abconfig(local_channel(),$orig_record[0]['abook_xchan'],'system','vcard',$serialised_vcard); @@ -107,8 +108,8 @@ class Connedit extends Controller { $autoperms = null; $is_self = false; } - - + + $profile_id = ((array_key_exists('profile_assign',$_POST)) ? $_POST['profile_assign'] : $orig_record[0]['abook_profile']); if($profile_id) { @@ -121,17 +122,17 @@ class Connedit extends Controller { return; } } - + $abook_incl = ((array_key_exists('abook_incl',$_POST)) ? escape_tags($_POST['abook_incl']) : $orig_record[0]['abook_incl']); $abook_excl = ((array_key_exists('abook_excl',$_POST)) ? escape_tags($_POST['abook_excl']) : $orig_record[0]['abook_excl']); $hidden = intval($_POST['hidden']); - + $priority = intval($_POST['poll']); if($priority > 5 || $priority < 0) $priority = 0; - + if(! array_key_exists('closeness',$_POST)) { $_POST['closeness'] = 80; } @@ -139,15 +140,15 @@ class Connedit extends Controller { if($closeness < 0 || $closeness > 99) { $closeness = 80; } - + $rating = intval($_POST['rating']); if($rating < (-10)) $rating = (-10); if($rating > 10) $rating = 10; - + $rating_text = trim(escape_tags($_REQUEST['rating_text'])); - + $all_perms = Permissions::Perms(); if($all_perms) { @@ -168,27 +169,27 @@ class Connedit extends Controller { } } - if(! is_null($autoperms)) + if(! is_null($autoperms)) set_pconfig($channel['channel_id'],'system','autoperms',$autoperms); - + $new_friend = false; - + // only store a record and notify the directory if the rating changed if(! $is_self) { - + $signed = $orig_record[0]['abook_xchan'] . '.' . $rating . '.' . $rating_text; - $sig = base64url_encode(rsa_sign($signed,$channel['channel_prvkey'])); + $sig = base64url_encode(Crypto::sign($signed,$channel['channel_prvkey'])); $rated = ((intval($rating) || strlen($rating_text)) ? true : false); - + $record = 0; - + $z = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1 limit 1", dbesc($channel['channel_hash']), dbesc($orig_record[0]['abook_xchan']) ); - + if($z) { if(($z[0]['xlink_rating'] != $rating) || ($z[0]['xlink_rating_text'] != $rating_text)) { $record = $z[0]['xlink_id']; @@ -223,18 +224,18 @@ class Connedit extends Controller { Master::Summon(array('Ratenotif','rating',$record)); } } - + if(($_REQUEST['pending']) && intval($orig_record[0]['abook_pending'])) { $new_friend = true; - + // @fixme it won't be common, but when you accept a new connection request // the permissions will now be that of your permissions role and ignore // any you may have set manually on the form. We'll probably see a bug if somebody // tries to set the permissions *and* approve the connection in the same // request. The workaround is to approve the connection, then go back and // adjust permissions as desired. - + $p = Permissions::connect_perms(local_channel()); $my_perms = $p['perms']; if($my_perms) { @@ -247,7 +248,7 @@ class Connedit extends Controller { $abook_pending = (($new_friend) ? 0 : $orig_record[0]['abook_pending']); - + $r = q("UPDATE abook SET abook_profile = '%s', abook_closeness = %d, abook_pending = %d, abook_incl = '%s', abook_excl = '%s' where abook_id = %d AND abook_channel = %d", @@ -259,7 +260,7 @@ class Connedit extends Controller { intval($contact_id), intval(local_channel()) ); - + if($r) info( t('Connection updated.') . EOL); else @@ -267,16 +268,16 @@ class Connedit extends Controller { if(! intval(App::$poi['abook_self'])) { if($new_friend) { - Master::Summon( [ 'Notifier', 'permission_accept', $contact_id ] ); + Master::Summon( [ 'Notifier', 'permission_accept', $contact_id ] ); } - Master::Summon( [ - 'Notifier', - (($new_friend) ? 'permission_create' : 'permission_update'), - $contact_id + Master::Summon( [ + 'Notifier', + (($new_friend) ? 'permission_create' : 'permission_update'), + $contact_id ]); } - + if($new_friend) { $default_group = $channel['channel_default_group']; if($default_group) { @@ -285,11 +286,11 @@ class Connedit extends Controller { if($g) group_add_member(local_channel(),'',App::$poi['abook_xchan'],$g['id']); } - + // Check if settings permit ("post new friend activity" is allowed, and // friends in general or this friend in particular aren't hidden) // and send out a new friend activity - + $pr = q("select * from profile where uid = %d and is_default = 1 and hide_friends = 0", intval($channel['channel_id']) ); @@ -305,23 +306,23 @@ class Connedit extends Controller { $xarr['deny_cid'] = $channel['channel_deny_cid']; $xarr['deny_gid'] = $channel['channel_deny_gid']; $xarr['item_private'] = (($xarr['allow_cid']||$xarr['allow_gid']||$xarr['deny_cid']||$xarr['deny_gid']) ? 1 : 0); - + $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]'; - + post_activity_item($xarr); - + } - - + + // pull in a bit of content if there is any to pull in Master::Summon(array('Onepoll',$contact_id)); - + } - + // Refresh the structure in memory with the new data - + $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", @@ -331,34 +332,34 @@ class Connedit extends Controller { if($r) { App::$poi = $r[0]; } - + if($new_friend) { $arr = array('channel_id' => local_channel(), 'abook' => App::$poi); call_hooks('accept_follow', $arr); } - + $this->connedit_clone($a); - + if(($_REQUEST['pending']) && (!$_REQUEST['done'])) goaway(z_root() . '/connections/ifpending'); - + return; - + } - + /* @brief Clone connection * * */ - + function connedit_clone(&$a) { - + if(! App::$poi) return; - - + + $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", @@ -368,40 +369,40 @@ class Connedit extends Controller { if($r) { App::$poi = array_shift($r); } - + $clone = App::$poi; - + unset($clone['abook_id']); unset($clone['abook_account']); unset($clone['abook_channel']); - + $abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']); if($abconfig) $clone['abconfig'] = $abconfig; - + Libsync::build_sync_packet(0 /* use the current local_channel */, array('abook' => array($clone))); } - + /* @brief Generate content of connection edit page * * */ - + function get() { - + $sort_type = 0; $o = ''; - + if(! local_channel()) { notice( t('Permission denied.') . EOL); return login(); } - + $section = ((array_key_exists('section',$_REQUEST)) ? $_REQUEST['section'] : ''); $channel = App::get_channel(); - + $yes_no = array(t('No'),t('Yes')); - + $connect_perms = Permissions::connect_perms(local_channel()); $o .= "\n"; - + if(argc() == 3) { - + $contact_id = intval(argv(1)); if(! $contact_id) return; - + $cmd = argv(2); $orig_record = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash @@ -429,17 +430,17 @@ class Connedit extends Controller { intval($contact_id), intval(local_channel()) ); - + if(! count($orig_record)) { notice( t('Could not access address book record.') . EOL); goaway(z_root() . '/connections'); } - + if($cmd === 'update') { // pull feed and consume it, which should subscribe to the hub. Master::Summon(array('Poller',$contact_id)); goaway(z_root() . '/connedit/' . $contact_id); - + } if($cmd === 'fetchvc') { @@ -474,7 +475,7 @@ class Connedit extends Controller { dbesc($orig_record[0]['xchan_hash']) ); $cmd = 'refresh'; - } + } if($cmd === 'refresh') { if($orig_record[0]['xchan_network'] === 'zot') { @@ -486,13 +487,13 @@ class Connedit extends Controller { 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 Master::Summon(array('Notifier','permission_update',$contact_id)); } goaway(z_root() . '/connedit/' . $contact_id); } - + if($cmd === 'block') { if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_BLOCKED)) { $this->connedit_clone($a); @@ -501,7 +502,7 @@ class Connedit extends Controller { notice(t('Unable to set address book parameters.') . EOL); goaway(z_root() . '/connedit/' . $contact_id); } - + if($cmd === 'ignore') { if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_IGNORED)) { $this->connedit_clone($a); @@ -510,7 +511,7 @@ class Connedit extends Controller { notice(t('Unable to set address book parameters.') . EOL); goaway(z_root() . '/connedit/' . $contact_id); } - + if($cmd === 'archive') { if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_ARCHIVED)) { $this->connedit_clone($a); @@ -519,7 +520,7 @@ class Connedit extends Controller { notice(t('Unable to set address book parameters.') . EOL); goaway(z_root() . '/connedit/' . $contact_id); } - + if($cmd === 'hide') { if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_HIDDEN)) { $this->connedit_clone($a); @@ -528,10 +529,10 @@ class Connedit extends Controller { notice(t('Unable to set address book parameters.') . EOL); goaway(z_root() . '/connedit/' . $contact_id); } - + // We'll prevent somebody from unapproving an already approved contact. // Though maybe somebody will want this eventually (??) - + if($cmd === 'approve') { if(intval($orig_record[0]['abook_pending'])) { if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_PENDING)) { @@ -542,10 +543,10 @@ class Connedit extends Controller { } goaway(z_root() . '/connedit/' . $contact_id); } - - + + if($cmd === 'drop') { - + contact_remove(local_channel(), $orig_record[0]['abook_id']); Master::Summon( [ 'Notifier', 'purge', local_channel(), $orig_record[0]['xchan_hash'] ] ); @@ -556,17 +557,17 @@ class Connedit extends Controller { 'entry_deleted' => true)) ) ); - + info( t('Connection has been removed.') . EOL ); if(x($_SESSION,'return_url')) goaway(z_root() . '/' . $_SESSION['return_url']); goaway(z_root() . '/contacts'); - + } } - + if(App::$poi) { - + $abook_prev = 0; $abook_next = 0; @@ -595,14 +596,14 @@ class Connedit extends Controller { } $tools = array( - + 'view' => array( 'label' => t('View Profile'), 'url' => chanlink_cid($contact['abook_id']), 'sel' => '', 'title' => sprintf( t('View %s\'s profile'), $contact['xchan_name']), ), - + 'refresh' => array( 'label' => t('Refresh Permissions'), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/refresh', @@ -616,14 +617,14 @@ class Connedit extends Controller { 'sel' => '', 'title' => t('Fetch updated photo'), ), - + 'recent' => array( 'label' => t('Recent Activity'), 'url' => z_root() . '/network/?f=&cid=' . $contact['abook_id'], 'sel' => '', 'title' => t('View recent posts and comments'), ), - + 'block' => array( 'label' => (intval($contact['abook_blocked']) ? t('Unblock') : t('Block')), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/block', @@ -631,7 +632,7 @@ class Connedit extends Controller { 'title' => t('Block (or Unblock) all communications with this connection'), 'info' => (intval($contact['abook_blocked']) ? t('This connection is blocked!') : ''), ), - + 'ignore' => array( 'label' => (intval($contact['abook_ignored']) ? t('Unignore') : t('Ignore')), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/ignore', @@ -639,7 +640,7 @@ class Connedit extends Controller { 'title' => t('Ignore (or Unignore) all inbound communications from this connection'), 'info' => (intval($contact['abook_ignored']) ? t('This connection is ignored!') : ''), ), - + 'archive' => array( 'label' => (intval($contact['abook_archived']) ? t('Unarchive') : t('Archive')), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/archive', @@ -647,7 +648,7 @@ class Connedit extends Controller { 'title' => t('Archive (or Unarchive) this connection - mark channel dead but keep content'), 'info' => (intval($contact['abook_archived']) ? t('This connection is archived!') : ''), ), - + 'hide' => array( 'label' => (intval($contact['abook_hidden']) ? t('Unhide') : t('Hide')), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/hide', @@ -655,18 +656,18 @@ class Connedit extends Controller { 'title' => t('Hide or Unhide this connection from your other connections'), 'info' => (intval($contact['abook_hidden']) ? t('This connection is hidden!') : ''), ), - + 'delete' => array( 'label' => t('Delete'), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/drop', 'sel' => '', 'title' => t('Delete this connection'), ), - + ); - if($contact['xchan_network'] === 'zot') { + if(in_array($contact['xchan_network'], ['zot6', 'zot'])) { $tools['fetchvc'] = [ 'label' => t('Fetch Vcard'), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/fetchvc', @@ -684,24 +685,24 @@ class Connedit extends Controller { 'sel' => '', 'title' => t('Open Individual Permissions section by default'), ]; - + $self = false; - + if(intval($contact['abook_self'])) { $self = true; $abook_prev = $abook_next = 0; } - + $vc = get_abconfig(local_channel(),$contact['abook_xchan'],'system','vcard'); - $vctmp = (($vc) ? \Sabre\VObject\Reader::read($vc) : null); + $vctmp = (($vc) ? \Sabre\VObject\Reader::read($vc) : null); $vcard = (($vctmp) ? get_vcard_array($vctmp,$contact['abook_id']) : [] ); if(! $vcard) $vcard['fn'] = $contact['xchan_name']; $tpl = get_markup_template("abook_edit.tpl"); - + if(Apps::system_app_installed(local_channel(),'Affinity Tool')) { $sections['affinity'] = [ @@ -710,7 +711,7 @@ class Connedit extends Controller { 'sel' => '', 'title' => t('Open Set Affinity section by default'), ]; - + $labels = [ t('Me'), t('Family'), @@ -720,7 +721,7 @@ class Connedit extends Controller { ]; call_hooks('affinity_labels',$labels); $label_str = ''; - + if($labels) { foreach($labels as $l) { if($label_str) { @@ -731,11 +732,11 @@ class Connedit extends Controller { $label_str .= "'" . $l . "'"; } } - + $slider_tpl = get_markup_template('contact_slider.tpl'); - + $slideval = intval($contact['abook_closeness']); - + $slide = replace_macros($slider_tpl,array( '$min' => 1, '$val' => $slideval, @@ -751,22 +752,22 @@ class Connedit extends Controller { 'title' => t('Open Custom Filter section by default'), ]; } - + $rating_val = 0; $rating_text = ''; - + $xl = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1", dbesc($channel['channel_hash']), dbesc($contact['xchan_hash']) ); - + if($xl) { $rating_val = intval($xl[0]['xlink_rating']); $rating_text = $xl[0]['xlink_rating_text']; } - + $rating_enabled = get_config('system','rating_enabled'); - + if($rating_enabled) { $rating = replace_macros(get_markup_template('rating_slider.tpl'),array( '$min' => -10, @@ -776,28 +777,28 @@ class Connedit extends Controller { else { $rating = false; } - - + + $perms = array(); $channel = App::get_channel(); - + $global_perms = Permissions::Perms(); $existing = get_all_perms(local_channel(),$contact['abook_xchan'],false); - + $unapproved = array('pending', t('Approve this connection'), '', t('Accept connection to allow communication'), array(t('No'),('Yes'))); - + $multiprofs = ((feature_enabled(local_channel(),'multi_profiles')) ? true : false); - + if($slide && !$multiprofs) $affinity = t('Set Affinity'); - + if(!$slide && $multiprofs) $affinity = t('Set Profile'); - + if($slide && $multiprofs) $affinity = t('Set Affinity & Profile'); - + $theirs = q("select * from abconfig where chan = %d and xchan = '%s' and cat = 'their_perms'", intval(local_channel()), dbesc($contact['abook_xchan']) @@ -812,20 +813,20 @@ class Connedit extends Controller { foreach($global_perms as $k => $v) { $thisperm = get_abconfig(local_channel(),$contact['abook_xchan'],'my_perms',$k); //fixme - + $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 if((! $self) && ($existing[$k])) $thisperm = "1"; - - + + $perms[] = array('perms_' . $k, $v, ((array_key_exists($k,$their_perms)) ? intval($their_perms[$k]) : ''),$thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), '', $checkinherited); } - + $pcat = new Permcat(local_channel()); $pcatlist = $pcat->listing(); $permcats = []; @@ -838,23 +839,23 @@ class Connedit extends Controller { $locstr = locations_by_netid($contact['xchan_hash']); if(! $locstr) $locstr = unpunify($contact['xchan_url']); - + $clone_warn = ''; $clonable = (in_array($contact['xchan_network'],['zot', 'zot6', 'rss']) ? true : false); if(! $clonable) { $clone_warn = ''; - $clone_warn .= ((intval($contact['abook_not_here'])) + $clone_warn .= ((intval($contact['abook_not_here'])) ? t('This connection is unreachable from this location.') : t('This connection may be unreachable from other channel locations.') ); $clone_warn .= '';
@@ -43,17 +44,17 @@ class Probe extends \Zotlabs\Web\Controller {
$o .= "https connection failed. Trying again with auto failover to http.\r\n\r\n";
$j = \Zotlabs\Zot\Finger::run($addr,$channel,true);
if(! $j['success']) {
- return $o;
+ return $o;
}
}
if($do_import && $j)
$x = import_xchan($j);
if($j && $j['permissions'] && $j['permissions']['iv'])
- $j['permissions'] = json_decode(crypto_unencapsulate($j['permissions'],$channel['channel_prvkey']),true);
+ $j['permissions'] = json_decode(Crypto::unencapsulate($j['permissions'],$channel['channel_prvkey']),true);
$o .= str_replace("\n",'
',print_r($j,true));
$o .= '';
}
return $o;
}
-
+
}
diff --git a/Zotlabs/Module/Profile.php b/Zotlabs/Module/Profile.php
index 4235f0b97..118f11f64 100644
--- a/Zotlabs/Module/Profile.php
+++ b/Zotlabs/Module/Profile.php
@@ -1,5 +1,13 @@
1)
+
+ if (argc() > 1)
$which = argv(1);
else {
- notice( t('Requested profile is not available.') . EOL );
- \App::$error = 404;
+ notice(t('Requested profile is not available.') . EOL);
+ App::$error = 404;
return;
}
- nav_set_selected('Profile');
-
$profile = '';
- $channel = \App::get_channel();
-
- if((local_channel()) && (argc() > 2) && (argv(2) === 'view')) {
- $which = $channel['channel_address'];
- $profile = argv(1);
- $r = q("select profile_guid from profile where id = %d and uid = %d limit 1",
+ $channel = App::get_channel();
+
+ if (!$channel)
+ http_status_exit(404, 'Not found');
+
+ if (ActivityStreams::is_as_request()) {
+ $p = Activity::encode_person($channel, true);
+ as_return_and_die(['type' => 'Profile', 'describes' => $p], $channel);
+ }
+
+ nav_set_selected('Profile');
+
+ if ((local_channel()) && (argc() > 2) && (argv(2) === 'view')) {
+ $which = $channel['channel_address'];
+ $profile = argv(1);
+ $r = q("select profile_guid from profile where id = %d and uid = %d limit 1",
intval($profile),
intval(local_channel())
);
- if(! $r)
+ if (!$r)
$profile = '';
$profile = $r[0]['profile_guid'];
}
-
- head_add_link( [
- 'rel' => 'alternate',
+
+ head_add_link([
+ 'rel' => 'alternate',
'type' => 'application/atom+xml',
'title' => t('Posts and comments'),
'href' => z_root() . '/feed/' . $which
]);
- head_add_link( [
- 'rel' => 'alternate',
+ head_add_link([
+ 'rel' => 'alternate',
'type' => 'application/atom+xml',
'title' => t('Only posts'),
'href' => z_root() . '/feed/' . $which . '?f=&top=1'
]);
- if(! $profile) {
+ if (!$profile) {
$x = q("select channel_id as profile_uid from channel where channel_address = '%s' limit 1",
dbesc(argv(1))
);
- if($x) {
- \App::$profile = $x[0];
+ if ($x) {
+ App::$profile = $x[0];
}
}
-
- profile_load($which,$profile);
-
-
+
+ profile_load($which, $profile);
+
+
}
-
+
function get() {
-
- if(observer_prohibited(true)) {
+
+ if (observer_prohibited(true)) {
return login();
}
-
- $groups = array();
+ $groups = [];
$tab = 'profile';
- $o = '';
-
- if(! (perm_is_allowed(\App::$profile['profile_uid'],get_observer_hash(), 'view_profile'))) {
- notice( t('Permission denied.') . EOL);
+ $o = '';
+
+ if (!(perm_is_allowed(App::$profile['profile_uid'], get_observer_hash(), 'view_profile'))) {
+ notice(t('Permission denied.') . EOL);
return;
}
-
- if(argc() > 2 && argv(2) === 'vcard') {
+ if (argc() > 2 && argv(2) === 'vcard') {
header('Content-type: text/vcard');
- header('content-disposition: attachment; filename="' . t('vcard') . '-' . $profile['channel_address'] . '.vcf"' );
- echo \App::$profile['profile_vcard'];
+ header('content-disposition: attachment; filename="' . t('vcard') . '-' . App::$profile['channel_address'] . '.vcf"');
+ echo App::$profile['profile_vcard'];
killme();
}
-
- $is_owner = ((local_channel()) && (local_channel() == \App::$profile['profile_uid']) ? true : false);
-
- if(\App::$profile['hidewall'] && (! $is_owner) && (! remote_channel())) {
- notice( t('Permission denied.') . EOL);
+
+ $is_owner = ((local_channel()) && (local_channel() == App::$profile['profile_uid']) ? true : false);
+
+ if (App::$profile['hidewall'] && (!$is_owner) && (!remote_channel())) {
+ notice(t('Permission denied.') . EOL);
return;
}
-
- head_add_link([
+
+ head_add_link([
'rel' => 'alternate',
'type' => 'application/json+oembed',
- 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$query_string),
+ 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . App::$query_string),
'title' => 'oembed'
]);
$o .= advanced_profile();
- call_hooks('profile_advanced',$o);
+ call_hooks('profile_advanced', $o);
return $o;
-
+
}
-
+
}
diff --git a/Zotlabs/Module/Profiles.php b/Zotlabs/Module/Profiles.php
index ca6ab435f..9aa342223 100644
--- a/Zotlabs/Module/Profiles.php
+++ b/Zotlabs/Module/Profiles.php
@@ -749,7 +749,7 @@ class Profiles extends \Zotlabs\Web\Controller {
'$default' => t('This is your default profile.') . EOL . translate_scope(map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_profile'))),
'$advanced' => $advanced,
'$name' => array('name', t('Your full name'), $r[0]['fullname'], t('Required'), '*'),
- '$pdesc' => array('pdesc', t('Short title/tescription'), $r[0]['pdesc'], t('Maximal 190 characters'), '', 'maxlength="190"'),
+ '$pdesc' => array('pdesc', t('Short title/description'), $r[0]['pdesc'], t('Maximal 190 characters'), '', 'maxlength="190"'),
'$dob' => dob($r[0]['dob']),
'$hide_friends' => $hide_friends,
'$address' => array('address', t('Street address'), $r[0]['address']),
diff --git a/Zotlabs/Module/Rate.php b/Zotlabs/Module/Rate.php
index c03aaa54f..d29c370fc 100644
--- a/Zotlabs/Module/Rate.php
+++ b/Zotlabs/Module/Rate.php
@@ -3,21 +3,23 @@ namespace Zotlabs\Module;
+use Zotlabs\Lib\Crypto;
+
class Rate extends \Zotlabs\Web\Controller {
function init() {
-
+
if(! local_channel())
return;
-
+
$channel = \App::get_channel();
-
+
$target = $_REQUEST['target'];
if(! $target)
return;
-
+
\App::$data['target'] = $target;
-
+
if($target) {
$r = q("SELECT * FROM xchan where xchan_hash like '%s' LIMIT 1",
dbesc($target)
@@ -36,43 +38,43 @@ class Rate extends \Zotlabs\Web\Controller {
}
}
}
-
-
+
+
return;
-
+
}
-
-
+
+
function post() {
-
+
if(! local_channel())
return;
-
+
if(! \App::$data['target'])
return;
-
+
if(! $_REQUEST['execute'])
return;
-
+
$channel = \App::get_channel();
-
+
$rating = intval($_POST['rating']);
if($rating < (-10))
$rating = (-10);
if($rating > 10)
$rating = 10;
-
+
$rating_text = trim(escape_tags($_REQUEST['rating_text']));
-
+
$signed = \App::$data['target'] . '.' . $rating . '.' . $rating_text;
-
- $sig = base64url_encode(rsa_sign($signed,$channel['channel_prvkey']));
-
+
+ $sig = base64url_encode(Crypto::sign($signed,$channel['channel_prvkey']));
+
$z = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1 limit 1",
dbesc($channel['channel_hash']),
dbesc(\App::$data['target'])
);
-
+
if($z) {
$record = $z[0]['xlink_id'];
$w = q("update xlink set xlink_rating = '%d', xlink_rating_text = '%s', xlink_sig = '%s', xlink_updated = '%s'
@@ -100,39 +102,39 @@ class Rate extends \Zotlabs\Web\Controller {
if($z)
$record = $z[0]['xlink_id'];
}
-
+
if($record) {
\Zotlabs\Daemon\Master::Summon(array('Ratenotif','rating',$record));
}
-
+
}
-
+
function get() {
-
+
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
return;
}
-
+
// if(! \App::$data['target']) {
// notice( t('No recipients.') . EOL);
// return;
// }
-
+
$rating_enabled = get_config('system','rating_enabled');
if(! $rating_enabled) {
notice('Ratings are disabled on this site.');
return;
}
-
+
$channel = \App::get_channel();
-
+
$r = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1",
dbesc($channel['channel_hash']),
dbesc(\App::$data['target'])
);
if($r) {
- \App::$data['xlink'] = $r[0];
+ \App::$data['xlink'] = $r[0];
$rating_val = $r[0]['xlink_rating'];
$rating_text = $r[0]['xlink_rating_text'];
}
@@ -140,7 +142,7 @@ class Rate extends \Zotlabs\Web\Controller {
$rating_val = 0;
$rating_text = '';
}
-
+
if($rating_enabled) {
$rating = replace_macros(get_markup_template('rating_slider.tpl'),array(
'$min' => -10,
@@ -150,7 +152,7 @@ class Rate extends \Zotlabs\Web\Controller {
else {
$rating = false;
}
-
+
$o = replace_macros(get_markup_template('rating_form.tpl'),array(
'$header' => t('Rating'),
'$website' => t('Website:'),
@@ -165,8 +167,8 @@ class Rate extends \Zotlabs\Web\Controller {
'$slide' => $slide,
'$submit' => t('Submit')
));
-
+
return $o;
-
+
}
}
diff --git a/Zotlabs/Module/Regver.php b/Zotlabs/Module/Regver.php
index 82b162f56..c45723063 100644
--- a/Zotlabs/Module/Regver.php
+++ b/Zotlabs/Module/Regver.php
@@ -6,8 +6,6 @@ class Regver extends \Zotlabs\Web\Controller {
function get() {
- global $lang;
-
$_SESSION['return_url'] = \App::$cmd;
if(argc() != 3)
diff --git a/Zotlabs/Module/Search.php b/Zotlabs/Module/Search.php
index c22bf2836..eeeff9613 100644
--- a/Zotlabs/Module/Search.php
+++ b/Zotlabs/Module/Search.php
@@ -1,85 +1,116 @@
' . "\r\n";
$o .= '
+Okno dialogowe uprawnień pozwala wybrać, które kanały albo grupy prywatności +mogą widzieć wpis. Można też wybrać, komu wyraźnie odmawia się dostępu. Załóżmy +na przykład, że planujesz niespodziewane przyjęcie dla znajomego. Możesz wysłać +zaproszenie do wszystkich w swojej grupie Znajomi oprócz znajomego, +któremu chcesz zrobić niespodziankę. W tym przypadku ustawiasz "Pokaż" grupie +Znajomi, ale ""Nie pokazuj" tej jednej osobie. +
+ ++Możesz zmienić uprawnienia do swoich plików, zdjęć i polubień, ale nie do wpisów +po ich zapisaniu. Główny powód jest taki, że po zapisaniu wpisu jest on rozpowszechniany +na kanale publicznym, a stamtąd na inne serwery Hubzilla lub tym, którym chciałeś +go pokazać. Tak jak nie możesz odzyskać czegoś, co przekazałeś innej osobie, nie +możesz zmienić uprawnień do wpisów Hubzilli. Musielibyśmy śledzić wszędzie, gdzie +trafia Twój wpis, śledzić wszystkich, którym pozwoliłeś go zobaczyć, a następnie +śledzić, od kogo go usunąć. +
++Jeśli wpis jest publiczny, jest to jeszcze trudniejsze, ponieważ Hubzilla jest siecią +globalną i nie ma możliwości śledzenia wpisu, nie mówiąc już o jego niezawodnym +odzyskaniu. Inne sieci, które mogą otrzymać Twój wpis, nie mają niezawodnego sposobu +na usunięcie lub odzyskanie wpisu. +
diff --git a/doc/pl/addons.bb b/doc/pl/addons.bb new file mode 100644 index 000000000..6a9cf425b --- /dev/null +++ b/doc/pl/addons.bb @@ -0,0 +1,117 @@ +[h3]Wtyczki/Dodatki[/h3] +[list=1] +[*] abcjsplugin - tworzenie zapisów nitowych w swoich wpisach +[*] adultphotoflag - zapobiega wyświetlaniu zdjęć NSFW w albumach publicznych +[*] authchoose - wysyłanie potwierdzenia tożsamości tylko do witryn znajomych +[*] b2tbtn - zapewnia przycisk powodujący przejście bezpośrednio na górę strony, jeśli przewinie się dużo treści dół okna +[*] bbmath - możliwość używania skomplikowanych wyrażeń matematycznych w swoich wpisach +[*] bookmarker - zamienianie #^ w linkach zakładek we wpisach +[*] buglink - umieszcza ikonę zgłaszania błędów w lewym dolnym rogu każdej strony +[*] calc - kalkulator naukowy +[*] chess - interaktywne gry w szachy z uwzględnieniem tożsamości międzydomenowej +[*] chords - generowanie wykresów palcowania i alternatyw dla każdego znanego akordu gitarowego +[*] custom_home - ustawianie własnej strony jako strony początkowej huba +[*] diaspora - emulator protokołu Diaspora +[*] dirstats - wyświetlanie interesujących statystyk generowanych przez serwer katalogowy +[*] docs - alternatywne strony dokumentacji +[*] donate - dostarcza stronę dofinansowania +[*] dreamhost - zapewnia bardziej niezawodną usługę na hostingu współdzielonym Dreamhost +[*] dwpost - krzyżowe wpisy do Dreamwidth +[*] emojione - zezwala na uzywanie emojis jako emotikonów +[*] extcron - stosowanie zewnętrznej usługi cron do uruchamiania zaplanowanych zadań huba +[*] firefox - dostarcza link do zainstalowania API Sharing Firefoxa +[*] flattrwidget - dostarcza przyciski "Flattr Us" +[*] flip - tworzenie odwróconego tekstu +[*] fortunate - wyświetla losowy cytat (plik cookie fortune). Wymaga skonfigurowania serwera fortune. +[*] friendica - protokół Friendica (DFRN). W tworzeniu. +[*] frphotos - importowanie albumów fotograficznych z Friendica +[*] gnusoc - protokół GNU-Social (OStatus). W tworzeniu. +[*] hexit - narzędzie do konwersji szesnastkowej +[*] hilite - umożliwia podświetlanie bloków kodu, specyficzne dla języka programowania, zawartych we wpisach +[*] hubwall - wysyłanie wiadomosci e-mail administratora na wszystkie konta w hubie +[*] ijpost - krzyżówe wpisy do Insanejournal +[*] irc - połączenie z czatami IRC +[*] jappixmini - czat XMPP +[*] js_upload - przesyłanie jednocześnie wiele zdjęć do albumów fotograficznych +[*] keepout - zapobiega prawie całkowicie korzystaniu z witryny bez zalogowania się, bardziej restrykcyjne niż ustawienie "blokuj publiczne" +[*] ldapauth - logowanie przez konto LDAP lub domenę Windows Active Directory +[*] libertree - publikowanie w Libertree +[*] likebanner - tworzenie obrazu banera "polub nas na red#matrix" +[*] ljpost - publikowanie w LiveJournal +[*] logrot - narzędzie rotowania plik dziennika zdarzeń +[*] mahjongg - gra w chińskie puzzle +[*] mailhost - umożliwienie wyboru jednego kanału dla otrzymywania powiadomień e-mail, gdy używa się wiele sklonowanych kanałów +[*] mailtest - interfejs do testowania systemu wysyłania poczty +[*] metatag - dostarcza strony przyjazne SEO +[*] mayan_places - ustawia pole lokalizacji na losowe miasto w świecie Majów +[*] morechoice - dodatkowe wybór płci i preferencji seksualnych dla profili (nie jest to bezpieczne) +[*] moremoods - dodatkowe opcje nastroju (mood) +[*] morepokes - dodatkowe opcje szturchania (poke) (nie są bezpieczne) +[*] msgfooter - podawanie formuły prawniczej lub innego tekstu w każdym wychodzącym wpisie +[*] noembed - używanie noembed.com jako dodatku do natywnej funkcjonalności oembed w $Projectname (obecnie nie działa) +[*] nofed - zapobiega "federacji" wpisów w kanale, utrzymuje całą interakcję na stronie właściciela kanału +[*] nsabait - dodawaj do swoich wpisów losowe hashtagi związane z terroryzmem +[*] nsfw - bardzo polecana wtyczka do zwijania postów z nieodpowiednimi treściami +[*] openclipatar - wybór zdjęcia profilowego spośród setek obrazów bez tantiem +[*] openid - uwierzytelnianie OpenID i serwer OpenID. Twój adres URL OpenID to [observer.baseurl]/id/[observer.webname] +[*] opensearch - umożliwienie swojej witrynie stania się dostawcą wyszukiwania w przeglądarce +[*] openstreetmap - renderowanie lokalizacji i mapy za pomocą OpenStreetMap +[*] pageheader - wyświetlanie tekstu u góry na każdej stronie serwisu +[*] phpmailer - alternatywny system dostarczania poczty z większą konfigurowalnością +[*] piwik - analityka witryn internetowych typu open source +[*] planets - ustawianie pola lokalizacji na losową planetę z Gwiezdnych Wojen +[*] pong - klasyczna gra w ponga +[*] pubcrawl - emulator protokołu ActivityPub +[*] pubsubhubbub - protokół PuSH dla zoptymalizowanego dostarczania wiadomości do subskrybentów (wymagany przez protokół GNU-Social) +[*] pumpio - publikowanie w Pump.io +[*] qrator - generowanie obrazów kodu QR +[*] rainbowtag - wyświetlanie chmury tagów i kategorii w kolorach +[*] randpost - bot wpis/odpowiedz oparty i wymagający fortunate +[*] redfiles - import magazynu plików z redmatrix +[*] redphotos - import albumów fotograficznych z redmatrix +[*] redred - wpisy krzyzowe do innych kanałów Red Matrix lun Hubzilla +[*] rendezvous - grupowe śledzenie lokalizacji +[*] rtof - publikowanie w Friendica +[*] sendzid - dodawanie parametróe uwierzytelniających "zid" do wszystkich linków wychodzących, nie tylko linków w sieci +[*] skeleton - przykładowa wtyczka pokazująca sposób tworzenia wtyczek +[*] smiley_pack - rozszerzenie wbudowanej obsługi buziek (emotikonów) +[*] smileybutton - zapewnia selektor buźki w oknie wpisu +[*] startpage - umowżliwia ustawienie przekierowania do preferowanej osobistej strony po zalogowaniu +[*] statistics - generator statystyk Diaspora +[*] statusnet - wpisy krzyżówe do GNU-social i StatusNet [zrl=[baseurl]/help/addons_gnusocial]Posting To Gnu Social[/zrl] +[*] std_embeds - umożłiwia niefiltrowane osadzanie dla popularnych dostawców strumieni, takich jak youtube, vimeo i soundcloud +[*] superblock - bardzo zalecane - całkowite blokowanie obraźliwuch kanałów w swoim strumieniu +[*] testdrive - zmienia hub w witrynę testową z kontami, które wygasają po okresie próbnym +[*] tictac - 3D tic-tac-toe +[*] torch - aplikacja podświetlania (flashlight) +[*] tour - prezentacja funkcji dla nowych członków +[*] tripleaes - wtyczka demonstracyjna zapewniająca niestandardowe algorytmy szyfrowania +[*] twitter - publikowanie w Twitter +[*] twitter_api - API kompatybilne z Twitter i Statusnet +[*] upload_limits - odkrywa, jakie ustawienia serwera (jest ich kilka) mogą powodować niepowodzenie przesyłania dużych zdjęć +[*] visage - pokaż odwiedzającym swój kanał +[*] webmention - przetwarzanie stron internetowych +[*] wholikesme - dostarcza stronę wyświetlającą listę kontaktów, które najbardziej "polubiły" Twoje wpisy +[*] webRTC - użycie zewnętrznego serwera (mayfirst.org) do negocjowania połączeń webRTC +[*] wppost - publikowanie w WordPress (lub w innych serwisach stosujących XMLRPC Wordpress) +[*] xmpp - XMPP czat oparty na converse.js +[/list] + +[h3]Repozytoria dodatków[/h3] + +[b]Zdecydowanie zalecamy[/b], aby autorzy dodatków publikowali (przesyłali) je do repozytorium dodatków projektu. Ma to kilka zalet. Programiści projektów mogą łatwo naprawić luki w zabezpieczeniach i wprowadzać zmiany, aby dostosować się do ostatnich zmian w kodzie podstawowym. Dodatki dostarczane w repozytoriach innych firm są uważane za niezaufane. Jeśli podstawowy kod projektu zmieni się w niekompatybilny sposób, może nie być innej alternatywy niż fizyczne usunięcie lub zmiana nazw plików dodatków, aby ponownie uruchomić witrynę. Często tylko autor wtyczki / dodatku może pomóc Ci odzyskać kontrolę nad Twoją witryną, a programiści projektów nie są w stanie Ci pomóc; ponieważ z definicji konfiguracja Twojej witryny została zmodyfikowana w sposób, którego nie możemy łatwo przetestować ani zweryfikować. + +Z tych powodów [b]zdecydowanie zalecamy[/b], aby NIE instalować dodatków z repozytoriów innych firm. + +Zdajemy sobie również sprawę, że niektórzy programiści wolą pracować samodzielnie i nie chcą z różnych powodów, aby ich kod był mieszany z repozytorium projektu. Ci programiści mogą ułatwić rozwiązywanie problemów i debugowanie, udostępniając plik README w odpowiednim repozytorium kodu, w którym opisano proces przesyłania poprawek i poprawek błędów. Zaleca się również, aby te projekty zapewniały zarówno gałąź "dev" (rozwój), jak i "master" (produkcja), która śledzi bieżące gałęzie projektu o tych nazwach. Dzieje się tak, ponieważ dev i master często nie są kompatybilne z punktu widzenia interfejsów bibliotek. Zdecydowanie zaleca się również, aby wersje repozytorium były oznaczone i przeniesione do przodu w ciągu 24 godzin od wydania projektu. Jest to poważna niedogodność dla wszystkich zaangażowanych osób i może powodować przestoje w zakładach produkcyjnych podczas przeprowadzania tego procesu; co jest jeszcze jednym powodem, dla którego [b]zdecydowanie zalecamy[/b], aby dodatki były przesyłane do repozytorium dodatków projektu i aby NIE instalować takich dodatków innych firm. + + +[url=https://framagit.org/hubzilla/addons]https://framagit.org/hubzilla/addons[/url] Główne repozytorium dodatków projektu. + +[url=https://github.com/23n/red-addons]https://github.com/23n/red-addons[/url] Repozytorium Olivera (mayan_places i flip) + + + +#include doc/macros/main_footer.bb; + + diff --git a/doc/pl/addons_gnusocial.bb b/doc/pl/addons_gnusocial.bb new file mode 100644 index 000000000..a35af6e1f --- /dev/null +++ b/doc/pl/addons_gnusocial.bb @@ -0,0 +1,64 @@ +[b]Jak przesyłać wpisy do instancji GNUsocial[/b] + +Zacznij od instancji GNUSocial, w której masz swoje konto. + +W instancji GNUSocial przejdź do Ustawienia > Połączenia. W prawej kolumnie, w sekcji "Programiści", kliknij link "Zarejestruj aplikację kliencką OAuth, która ma być używana z tym wystąpieniem StatusNet". Ten link można znaleźć w Twojej instancji tutaj: + +https://yourgnusocialinstance.org/settings/oauthapps + +Następnie kliknij łącze "Zarejestruj nową aplikację". Pojawi się nowy formularz zgłoszeniowy. Oto, co należy zrobić na każdym polu. + +Ikona. Pobierz ikonę $Projectname znajdującą się pod tym linkiem, po zapisaniu jej na swoim komputerze: + +https://framagit.org/hubzilla/core/blob/master/images/rm-32.png + +Nazwa. Nadaj aplikacji odpowiednią nazwę. Wywołaj swoją witrynę hubzilli. Możesz preferować r2g. + +Opis. Użyj tego pola, aby opisać przeznaczenie aplikacji. Dodaj coś o efekcie użycia krzyżowego wysyłania z $Projectname do GNUsocial. + +Źródłowy adres URL. Wpisz nazwę domeny głównej witryny Red, której używasz. Nie zapomnij wpisać "s" w https://yourhubzillasite.com. Jeśli Twoja instalacja Red jest subdomeną, prawdopodobnie będzie to wymagane. + +Organizacja. Jeśli używasz tej instancji $Projectname dla grupy lub firmy, wypełnij to pole. + +Strona główna. Jeśli Twoja grupa korzysta z subdomeny, prawdopodobnie zechcesz umieścić tutaj identyfikator URI domeny głównej. + +Adres URL wywołania zwrotnego. Pozostaw puste. + +Typ aplikacji: wybierz "desktop." + +Domyślny dostęp: wybierz "Read-write." + +Wszystkie pola oprócz adresu URL wywołania zwrotnego muszą być wypełnione. + +Kliknij przycisk "Zapisz". + +Następnie kliknij ikonę lub nazwę aplikacji, aby wyświetlić informacje, które musisz wstawić w $Projectname. + +***** + +Otwórz teraz nową kartę lub okno i przejdź do swojego konta $Projectname, do ustawień Ustawienia > Właściwości. Znajdź ustawienia publikowania StatusNet. + +Wstaw w $Projectname ciągi liczb, podane na stronie GNUsocial, do pól klucza konsumenta i hasła konsumenta. + +Podstawową ścieżką API (pamiętaj o końcowym znaku /) będzie adres Twojej domeny i ścieżki "/api/". Prawdopodobnie będzie wyglądać tak: + +https://yourgnusocialinstance.org/api/ + +W przypadku wątpliwości sprawdź witrynę instancji GNUsocial, aby znaleźć adresy URL domeny tokenu żądania, tokenu dostępu i autoryzacji. Będzie to pierwsza część adresu URL domene, bez "/oauth/...." + +Nazwa aplikacji StatusNet: Wstaw nazwę, którą nadałeś aplikacji w witrynie GNUsocial. + +Kliknij "Prześlij". + +Pojawi się przycisk "Zaloguj się do StatusNet". Kliknij go, a otworzy się zakładka lub okno w witrynie GNUsocial, w którym możesz kliknąć "Zezwól". Po kliknięciu i pomyślnej autoryzacji pojawi się numer kodu bezpieczeństwa. Skopiuj go i wróć do aplikacji $Projectname, którą właśnie opuściłeś i wstaw ją w polu: "Tutaj skopiuj kod bezpieczeństwa ze StatusNet". Kliknij "Prześlij". + +Jeśli się powiedzie, Twoje informacje z instancji GNUsocial powinny pojawić się w aplikacji $Projectname. + +Jeśli chcesz, masz teraz do wyboru kilka opcji, które należy również potwierdzić, klikając "Prześlij". Najbardziej interesująca jest opcja "Domyślnie wysyłaj publiczne wpisy do StatusNet". Ta opcja automatycznie wysyła wszystkie wpisy, które napisałeś na koncie $Projectname do Twojej instancji GNUsocial. + +Jeśli nie wybierzesz tej opcji, będziesz mieć możliwość ręcznego wysłania wpisu do swojej instancji GNUsocial. W tym celu, najpierw otwórz wpis (klikając w obszarze tekstowym wpisu) i kliknik ikonę kłódki obok przycisku "Udostępnij". Wybierz ikonę GNUsocial składającą się z trzech kolorowych dymków dialogowych. Zamknij to okno, a następnie wykonaj swój wpis. + +Jeśli wszystko pójdzie dobrze, właśnie wysłałeś swój wpis z $Projectname na swoje konto w instancji GNUsocial. + +#include doc/macros/addons_footer.bb; + diff --git a/doc/pl/admin/administrator_guide.md b/doc/pl/admin/administrator_guide.md new file mode 100644 index 000000000..86e5fd80c --- /dev/null +++ b/doc/pl/admin/administrator_guide.md @@ -0,0 +1,385 @@ +### Przegląd + +$Projectname to więcej niż prosta aplikacja internetowa. Jest to złożony system komunikacyjny, który bardziej przypomina serwer poczty elektronicznej niż serwer WWW. Aby zapewnić niezawodność i wydajność, wiadomości są dostarczane w tle i umieszczane w kolejce do późniejszego dostarczenia, gdy lokacje są wyłączone. Ten rodzaj funkcjonalności wymaga nieco więcej zasobów hosta niż typowy dziennik. Nie każdy dostawca hostingu PHP-MySQL będzie w stanie obsługiwać $Projectname. Tak więc, przed instalacją zapoznaj się z wymaganiami i potwierdź je u dostawcy usług hostingowych. + +Bardzo staraliśmy się, aby Hubzilla działała na zwykłych platformach hostingowych, takich jak te używane do hostowania blogów Wordpress i stron internetowych Drupal. Będzie ona działać na większości systemów VPS Linux. Platformy Windows LAMP, takie jak XAMPP i WAMP, nie są obecnie oficjalnie obsługiwane, jednak mile widziane są poprawki, jeśli uda Ci się je uruchomić. + +### Gdzie można znaleźć więcej pomocy + +Jeśli napotkasz problemy lub sam masz jakiś problem, które nie zostały opisane w tej dokumentacji, poinformuj nas o tym za pośrednictwem narzędzia do [śledzenia problemów na Github](https://framagit.org/hubzilla/core/issues). Prosimy o jak najdokładniejsze opisanie swojego środowiska operacyjnego i podanie jak największej ilości informacji o wszelkich komunikatach o błędach, które mogą się pojawić, abyśmy mogli zapobiec ich występowaniu w przyszłości. Ze względu na dużą różnorodność istniejących systemów operacyjnych i platform PHP możemy mieć ograniczone możliwości debugowania instalacji PHP lub pozyskiwania brakujących modułów, ale dołożymy wszelkich starań, aby rozwiązać wszelkie ogólne problemy z kodem. + +### Zanim zaczniesz + +#### Wybierz nazwę domeny lub subdomeny dla swojego serwera + +Platformę $Projectname można zainstalować tylko w katalogu głównym domeny lub subdomeny i nie może ona działać na niestandardowych portach TCP. + +#### Zdecyduj, czy będziesz używać SSL i uzyskaj certyfikat SSL przed instalacją oprogramowania + +POWINNO się używać SSL. Jeśli używasz SSL, MUSISZ użyć certyfikatu uznawanego przez przeglądarki. **NIE WOLNO używać certyfikatów z podpisem własnym!** + +Przetestuj swój certyfikat przed instalacją. Narzędzie internetowe do testowania certyfikatu jest dostępne pod adresem http://www.digicert.com/help/. Odwiedzając witrynę po raz pierwszy, użyj adresu URL SSL (https://), jeśli protokół SSL jest dostępny. Pozwoli to uniknąć późniejszych problemów. Procedura instalacji nie pozwoli na użycie certyfikatu, który nie jest zaufany dla przeglądarki. + +To ograniczenie zostało wprowadzone, ponieważ Twoje publiczne wpisy mogą zawierać odniesienia do obrazów na Twoim hubie. Inni członkowie przeglądający swój strumień w innych centrach otrzymają ostrzeżenia, jeśli Twój certyfikat nie jest zaufany w ich przeglądarce internetowej. To zmyli wiele osób, ponieważ jest to zdecentralizowana sieć i otrzymają ostrzeżenie o Twoim hubie podczas przeglądania własnego huba i mogą pomyśleć, że ich własny hub ma problem. Te ostrzeżenia są bardzo techniczne i przerażające dla niektórych osób, z których wielu nie będzie wiedziało, jak postępować, z wyjątkiem przestrzegania zaleceń przeglądarki. Jest to destrukcyjne dla społeczności. To powiedziawszy, zdajemy sobie sprawę z problemów związanych z obecną infrastrukturą certyfikatów i zgadzamy się, że istnieje wiele problemów, ale to nie zmienia wymagania. + +Bezpłatne certyfikaty zgodne z przeglądarkami są dostępne od dostawców, takich jak StartSSL i LetsEncrypt. + +Jeśli NIE używasz SSL, może wystąpić opóźnienie do minuty dla startowego skryptu instalacyjnego - podczas sprawdzania portu SSL, aby zobaczyć, czy tam jest wszystko w porządku. Podczas komunikowania się z nowymi witrynami Hubzilla zawsze najpierw próbuje połączyć się z portem SSL, zanim powróci do mniej bezpiecznego połączenia. Jeśli nie używasz SSL, twój serwer WWW NIE MOŻE w ogóle nasłuchiwać na porcie 443. + +Jeśli używasz LetsEncrypt do dostarczania certyfikatów i tworzenia pliku pod _well-known_ lub _acme-challenge_, aby LetsEncrypt mógł zweryfikować własność domeny, usuń lub zmień nazwę katalogu _.well-known_ zaraz po wygenerowaniu certyfikatu. $Projectname zapewni własną procedurę obsługi usług *.well-know* po zainstalowaniu, a istniejący katalog w tej lokalizacji może uniemożliwić poprawne działanie niektórych z tych usług. Nie powinno to stanowić problemu w przypadku Apache, ale może to być problem z Nginx lub innymi platformami serwera internetowego. + +### Wdrożenie + +Nowy hub można wdrożyć na kilka sposobów: + +* ręczna inastalaja na istniejącym serwerze; +* automatyczna instalacja na istniejącym serwerze przy użyciu skryptu instalacyjnego; +* automatyczne wdrożenie przy użyciu prywatnego serwera wirtualnego OpenShift (VPS).) + +### Wymagania + +* Apache z włączonym modułem _mod-rewrite_ i ustawioną dyrektywą "AllowOverride All", tak aby można było stosować plik _.htaccess_. Niektóre osoby z powodzeniem stosowały Nginx czy Lighttpd.Przykładowe skrypty konfiguracyjne są dostępne na tej platformie w [doc/install](). Apache and Nginx mają najlepsze wsparcie. + +* PHP 7.1 lub w wersji wyższej. + * _Proszę mieć na uwadze, że w niektórych środowiskach hostinu współdzielonego, wersja wiersza poleceń PHP różni się od wersji serwera internetowego_ + +* Dostęp do wiersza poleceń PHP z ustawionym w pliku php.ini parametrem _register_argc_argv_ na true i bez ograniczeń dostawcy hostingu w zakresie stosowania funkcji _exec()_ i _proc_open()_. + +* Rozszerzenia curl, gd (z obsługą co najmmniej jpeg i png), mysqli, mbstring, mcrypt, zip i openssl. Tozszerzenie imagick nie jest wymagane ale jest zalecane. + +* Wymagane jest rozszerzenie xml, jeśli chce sie mieć działajacą obsługę webdav. + +* Jakaś forma serwera pocztowego lub bramy pocztowej, taka jak działa PHP mail(). + +* Serwer bazy danych Mysql 5.x lub MariaDB lub PostgreSQL. + +* Możliwość planowania zadań dla crona. + +* WYMAGANA jest instalacja w katalogu głównym hosta WWW (wirtualnego hosta w Apache i bloku w Nginx). + +### Instalacja ręczna + +##### Krok 1. + +Rozpakuj pliki $Projectname do katalogu głównego obszaru dokumentów serwera WWW. Jeśli kopiujesz drzewo katalogów na swój serwer WWW, upewnij się, że dołączasz ukryte pliki, takie jak _.htaccess_. + +Jeśli możesz to zrobić, zalecamy użycie Git do sklonowania repozytorium źródłowego zamiast używania spakowanego pliku tar lub zip. To znacznie ułatwia późniejszą aktualizację oprogramowania. Polecenie Linux do sklonowania repozytorium do katalogu "mywebsite: wyglądałoby tak: + + git clone https://framagit.org/hubzilla/core.git mywebsite + +a następnie, w dowolnym momencie, możesz pobrać najnowsze zmiany za pomocą: + + git pull + +upewnij się, że istniejeją foldery `store/[data]/smarty3` i `store` i że są one możliwe do zapisu przez właściciela procesu serwera WWW: + + mkdir -p "store/[data]/smarty3" + chmod -R 777 store + +To uprawnienie (777) jest bardzo niebezpieczne i jeśli masz wystarczające uprawnienia i wiedzę powinieneś umożliwić zapisywanie w tych katalogach tylko przez serwer WWW i użytkownika, który uruchomia crona (patrz poniżej), jeśli jest taki. W wielu współdzielonych środowiskach hostingowych może to być trudne, bez zgłoszenia problemu u dostawcy. Powyższe uprawnienia pozwolą oprogramowaniu działać, ale nie są optymalne. + +Aby działały niektóre internetowe narzędzia administracyjne, serwer WWW musi mieć możliwość zapisu w następujących katalogach: + +* _addon_ +* _extend_ +* _view/theme_ +* _widget_ + +##### Krok 2. + +Utwórz pustą bazę danych i zanotuj szczegóły dostępu (nazwa hosta, nazwa użytkownika, hasło, nazwa bazy danych). Biblioteki bazy danych PDO powracają do komunikacji przez gniazdo uniksowe, gdy nazwą hosta jest _localhost_, ale niektóre osoby zgłosiły problemy z implementacją gniazda. Użyj gniazd, jeśli Twoje uprawnienia na to pozwalają. W przeciwnym razie, jeśli baza danych jest udostępniana na hoście _localhost_, jako nazwę hosta wpisz _127.0.0.1_. + +Wewnętrznie używamy teraz biblioteki PDO do połączeń z bazą danych. Jeśli masz do czynienia z konfigyracją bazy danych, którą nie możesz obsłużyć poprzez formularz konfiguracyjny (ma przykład w przypadku uzywania MySQL z nietypową lokalizacją gniazd) - możesz podać ciąg połączenia PDO jako nazwę hosta. Na przykład: + + :/path/to/socket.file + +W razie potrzeby nadal trzeba wypełnić w formularzu konfiguracyjnym wszystkie inne wartości mające zastosowanie. + +##### Krok 3. + +Utwórz pusty plik o nazwie _.htconfig.php_ i uczyń go możliwymm do zapisania przez serwer WWW. Krok ten wykonaj, jeśli wiesz, że serwer WWW nie będzie mógł sam utworzyć tego pliku. + +##### Krok 4. + +Odwiedź swoją witrynę za pomocą przeglądarki internetowej i postępuj zgodnie z instrukcjami. Zanotuj wszelkie komunikaty o błędach i popraw je przed kontynuowaniem. Jeśli używasz protokołu SSL (od znanego urzędu autoryzacyjnego), użyj schematu _https_ w adresie URL swojej witryny. + +##### Krok 5. + +Jeśli automatyczna instalacja nie powiedzie się z jakiegoś powodu, sprawdź następujące rzeczy: + +* Czy istnieje plik _.htconfig.php_? Jeśli nie, edytuj plik _htconfig.php_ i zmień w nim ustawienia systemowe. Następnie zmień jego nazwę na _.htconfig.php_. +* Czy baza danych jest wypełniona. Jeśli nie, zaimportuj treść skryptu _install/schema_xxxxx.sql_ w phpmyadmin lub wierszu poleceń mysql (zamień 'xxxxx' na własciwy typ bazy danych). + +##### Krok 6. + +Po udanej instalacji odwiedż ponownie swoją witrynę i zarejestruj swoje osobiste konto. Błędy rejestracji powinny dać sie naprawić automatycznie. + +Jeśli w tym momencie wystąpiła jakakolwiek *krytyczna* awaria, to na ogół przyczyna leży w źle funkcjonującej bazie danych. W takim przypadku, aby zacząć od nowa, usuń lub zmień nazwę pliku _.htconfig.php_ i usuń tabele bazy danych. + +Aby Twoje konto miało dostęp administratora, powinno to być utworzone jako pierwsze, a adres e-mail podany podczas rejestracji musi być zgodny z adresem administratora podanym podczas instalacji. Jeśli stało sie inaczej, aby dać dostęp administracyjny jakiemuś kontu, dodaj _4096_ w rekordzie tabeli _account_roles_ tego konta. + +Ze względu na bezpieczeństwo witryny, nie ma możliwości zapewnienia dostępu administracyjnego za pomocą formularzy konfiguracyjnych. + +##### Krok 7. BARDZO WAŻNY! + +Skonfiguruj zadanie Crona lub *zadanie zaplanowane*, tak aby uruchamiać menedżera Crona co 10-15 minut w celu przetwarzania i konserwacji w tle. Przykład: + + cd /base/directory; /path/to/php Zotlabs/Daemon/Master.php Cron + + +Zmień tutaj `/base/directory` i `/path/to/php` na właściwe dla siebie ścieżki. + +Jeśli używasz serwera linuksowego, uruchom polecenie `crontab -e` i dodaj wiersz taki jak poniżej, zmieniając odpowiednio ścieżki i ustawienia: + + */10 * * * * cd /home/myname/mywebsite; /usr/bin/php Zotlabs/Daemon/Master.php Cron > /dev/null 2>&1 + +Lokalizację PHP na ogół można ustalić wykonując polecenie _which php_. Jeśli masz problemy z ustawienie Crona, skontaktuj się z dostawcą hostingu w celu uzyskania pomocy. Hubzilla nie będzie działać prawidłowo bez tego kroku. + +Powinno się również sprawdzić ustawienie parametru _App::$config['system']['php_path']_ w pliku _.htconfig.php_. Powinno to wyglądać tak (zmień to zgodnie z lokalizacją PHP w swoim systemie): + + + App::$config['system']['php_path'] = '/usr/local/php56/bin/php'; + +#### Oficjalne dodatki + +##### Instalacja + +Przejdź do swojej witryny. Następnie sklonuj repozytorium dodatków (osobno). Nadamy temu repozytorium pseudonim `hzaddons`. Możesz pobrać inne repozytoria dodatków Hubzilla, nadając im różne pseudonimy: + + cd mywebsite + util/add_addon_repo https://framagit.org/hubzilla/addons.git hzaddons + +##### Aktualizacja + +W celu aktualizacji drzewa dodatków, powinno się, z poziomu głównego katalogu witryny, wydać polecenie aktualizacji tego repozytorium: + + cd mywebsite + util/update_addon_repo hzaddons + +Stwórz reprezentację dokumentacji online z możliwością wyszukiwania. Możesz to zrobić za każdym razem, gdy dokumentacja jest aktualizowana: + + cd mywebsite + util/importdoc + +### Automatyczna instalacja poprzez skrypt .homeinstall + +Istnieje skrypt powłoki _.homeinstall/hubzilla-setup.sh_, który po uruchomieniu zainstaluje Hubzillę i jego zależności na nowej instalacji stabilnej dystrybucji Debiana 9 (Stetch). Powinien działać na podobnych systemach Linux, ale wyniki mogą się różnić. + +#### Wymagania + +Skrypt instalacyjny został pierwotnie zaprojektowany dla małego serwera sprzętowego za routerem domowym. Jednak został przetestowany też na kilku systemach z Debian 9: + +* Home-PC (Debian-9.2-amd64) i Rapberry-Pi 3 (Rasbian = Debian 9.3) + * Połączenie z Internetem i domowy router + * Mini-PC lub Raspi połaczone z router + * Napęd USB dla kopii zapasowych + * Świeża instalacja Debian na swoim mini-pc + * Router z otwartymi portami 80 i 443 dla Debiana + +#### Etapy instalacji + +1. _apt-get install git_ +1. _mkdir -p /var/www/html_ +1. _cd /var/www/html_ +1. _git clone https://framagit.org/hubzilla/core.git ._ +1. _nano .homeinstall/hubzilla-config.txt_ +1. _cd .homeinstall/_ +1. _./hubzilla-setup.sh_ +1. _service apache2 reload_ +1. Open your domain with a browser and step throught the initial configuration of $Projectname. + +### Zalecane dodatki + +Zalecamy zainstalowanie następujących dodatków we wszystkich publicznych witrynach: + + nsfw - hide inappropriate posts/comments + superblock - block content from offensive channels + +### Dodatki federacyjne + +Kilka społeczności internetowych zaczęło łączyć się przy użyciu wspólnych protokołów. Stosowane protokoły mają nieco ograniczone możliwości. Na przykład protokół GNU-Social nie oferuje żadnych trybów prywatności, a protokół Diaspora +jest nieco bardziej restrykcyjny w zakresie dozwolonych rodzajów komunikacji. Wszystkie komentarze muszą być podpisane w bardzo unikalny sposób przez oryginalnego autora. Rozważany jest również protokół ActivityPub, który może być obsługiwany w przyszłości. Żaden inny istniejący protokół nie obsługuje lokalizacji nomadycznej używanej w tym projekcie. Stwarza to pewne problemy z obsługą, ponieważ niektóre funkcje działają w niektórych sieciach, a w innych nie. Niemniej jednak protokoły federacyjne umożliwiają nawiązywanie połączeń ze znacznie większą społecznością ludzi na całym świecie. Są dostarczane jako dodatki. + +* _diaspora_ - protokół diaspory używany przez Diasporę i Friendica. Najpierw należy włączyć „Diaspora Statistics” (statystyki), aby włączyć wszystkie dostępne funkcje. + +* _gnusoc_ - protokół społecznościowy GNU, używany przez GNU-Social, Mastodon i kilka innych społeczności. Ten dodatek wymaga najpierw zainstalowania usługi _pubsubhubbub_ (także dodatku). + +Każdy członek Twojej siatki musi indywidualnie zdecydować, czy zezwolić na te protokoły, ponieważ mogą one kolidować z kilkoma pożądanymi podstawowymi funkcjami i możliwościami Hubzilla (takimi jak migracja kanałów i klonowanie). Robi się to +na swojej stronie _Ustawienia_ -> _Ustawienia funkcji i dodatków_. Administrator może również ustawić: + + util/config system.diaspora_allowed 1 + util/config system.gnusoc_allowed 1 + +i włączać te protokoły automatycznie dla wszystkich nowo tworzonych kanałów. + +### Klasy usług + +Klasy usług pozwalają na ustawienie limitów zasobów systemowych poprzez ograniczenie tego, co mogą robić poszczególne konta, w tym przechowywania plików i najwyższych limitów wpisów. Zdefiniuj niestandardowe klasy usług zgodnie ze swoimi potrzebami w pliku _.htconfig.php_. Na przykład utwórz klasę standard i premium, używając następujących wierszy: + + // Service classes + + App::$config['system']['default_service_class']='standard'; // this is the default service class that is attached to every new account + + // configuration for standard service class + App::$config['service_class']['standard'] = + array('photo_upload_limit'=>2097152, // total photo storage limit per channel (here 2MB) + 'total_identities' =>1, // number of channels an account can create + 'total_items' =>0, // number of top level posts a channel can create. Applies only to top level posts of the channel user, other posts and comments are unaffected + 'total_pages' =>100, // number of pages a channel can create + 'total_channels' =>100, // number of channels the user can add, other users can still add this channel, even if the limit is reached + 'attach_upload_limit' =>2097152, // total attachment storage limit per channel (here 2MB) + 'chatters_inroom' =>20); + + // configuration for premium service class + App::$config['service_class']['premium'] = + array('photo_upload_limit'=>20000000000, // total photo storage limit per channel (here 20GB) + 'total_identities' =>20, // number of channels an account can create + 'total_items' =>20000, // number of top level posts a channel can create. Applies only to top level posts of the channel user, other posts and comments are unaffected + 'total_pages' =>400, // number of pages a channel can create + 'total_channels' =>2000, // number of channels the user can add, other users can still add this channel, even if the limit is reached + 'attach_upload_limit' =>20000000000, // total attachment storage limit per channel (here 20GB) + 'chatters_inroom' =>100); + +Aby zastosować klasę usług do istniejącego konta, użyj narzędzia wiersza poleceń z katalogu głównego instalacji Hubzilla: + +* uzyskanie listy klas usług: + + util/service_class + + +* ustawienie domyślnej klasy usług na _firstclass_: + + util/config system default_service_class firstclass + +* uzyskanie listy usług, które należą do klasy _firstclass_: + + util/service_class firstclass + +* ustawienie całkowitego użycia dysku ze zdjęciami _firstclass_ na 10 milionów bajtów + + util/service_class firstclass photo_upload_limit 10000000 + +* ustawienie konta z identyfikatorem 5 na klasę _firstclass_ (z potwierdzeniem): + + util/service_class --account=5 firstclass + +* ustawienie konta, które jest właścicielem kanału `bdziennikchan` na klasę _firstclass_ (z potwierdzeniem) + + util/service_class --channel=bdziennikchan firstclass + +**Opcje limitu klas usług** + +##### Opcje limitów klas usług: + +* _photo_upload_limit_ - maksymalna łączna liczba bajtów na zdjęcia +* _total_items_ - maksymalna liczba wpisów na najwyższym poziomie +* _total_pages_ - maksymalna liczba stron comanche +* _total_identities_ - maksymalna liczba kanałów posiadanych na koncie +* _total_channels_ - maksymalna liczba kanałów +* _total_feeds_ - maksymalna liczba kanałów RSS +* _attach_upload_limit_ - maksymalna pojemność przesyłania plików (w bajtach) +* _minimum_feedcheck_minutes_ - najniższe ustawienie dozwolone dla odpytywania kanałów RSS +* _chatrooms_ - maksymalna liczba czatów +* _chatters_inroom_ - maksymalna liczba rozmówców w czacie +* _access_tokens_ - maksymalna liczba tokenów dostępu gościa na kanał + +### Zarządzanie motywami + +#### Przykład zarządzania repozytorium + +1) Przejdź na poziom katalogu głównego serwera: + + ``` + root@hub:/root# cd /var/www + ``` + +2) Dodaj repozytorium motywu i nadaj mu nazwę + + ``` + root@hub:/var/www# util/add_theme_repo https://github.com/DeadSuperHero/redmatrix-themes.git DeadSuperHero + ``` +3) Zaktualizuj repozytorium motywu + + ``` + root@hub:/var/www# util/update_theme_repo DeadSuperHero + ``` + +### Katalog kanałów + +#### Słowa kluczowe + +Na stronie katalogu kanałów może pojawiać się chmura słów kluczowych. Jeśli chcesz ukryć te słowa kluczowe, które są pobierane z serwera katalogów, możesz użyć narzędzia _config_: + + util/config system disable_directory_keywords 1 + +Jeśli twój hub pracuje w trybie autonomicznym, ponieważ nie chcesz łączyć się z globalną siecią, możesz zamiast tego ustawić opcję systemową _directory_server_ na wartość pustą: + + util/config system directory_server "" + +### Administrowanie + +#### Administrowanie witryną + +Administracja witryną jest zwykle wykonywana za pośrednictwem strony administratora znajdującej się na ścieżce _/admin_ adresu URL Twojej witryny. Aby uzyskać dostęp do tej strony, trzeba mieć uprawnienia administratora na serwerze. Prawa administracyjne są przyznawane pierwszemu kontu, które zostało zarejestrowane w witrynie, pod warunkiem, że adres e-mail tego konta dokładnie odpowiada adresowi e-mail podanemu jako adres e-mail administratora podczas konfiguracji. + +Istnieje kilka sposobów, w jakie może to się nie powieść i pozostawić system bez konta administratora, na przykład jeśli pierwsze konto, które zostało utworzone, miało inny adres e-mail niż adres e-mail administratora, który został podany podczas konfiguracji. + +Ze względów bezpieczeństwa w systemie nie ma strony internetowej ani interfejsu, który daje dostęp administratora. Jeśli potrzebujesz poprawić sytuację, w której system nie ma konta administratora, musisz to zrobić edytując tabelę kont w bazie danych. Nie ma innego wyjścia. Aby to zrobić, będziesz musiał zlokalizować wpis w tabeli kont, który należy do żądanego administratora i ustawić _account_roles_ dla tego wpisu na _4096_. Będziesz wtedy mógł uzyskać dostęp do strony administratora z menu profilu twojego systemu lub bezpośrednio na ścieżce _/admin_. + +Hub może mieć wielu administratorów i nie ma ograniczeń co do ich liczby. Powtórz powyższą procedurę dla każdego konta, któremu chcesz przyznać uprawnienia administracyjne. + +### Rozwiązywanie problemów + +#### Pliki dzienników + +Plik dziennika systemowego jest niezwykle przydatnym źródłem informacji do śledzenia błędów. Można to włączyć na stronie konfiguracji _admin/log_. Ustawienie poziomu o wartości *LOGGER_DEBUG* jest preferowany w stabilnej instalacji produkcyjnej. Większość problemów związanych z komunikacją lub przechowywaniem jest tutaj wymieniona. Ustawienie na *LOGGER_DATA* zapewnia znacznie więcej szczegółów, ale może wypełnić dysk. W obu przypadkach zalecamy użycie *logrotate* w systemie operacyjnym do cyklicznego tworzenia dzienników i usuwania starszych wpisów. + +Na dole twojego *.htconfig.php* znajduje się kilka linii (zakomentowanych), które umożliwiają rejestrowanie błędów PHP. Zgłaszane są problemy ze składnią i wykonywaniem kodu i jest to też pierwszym miejscem, w którym należy szukać problemów, które powodują "biały ekran" lub pustą stronę. Zwykle jest to wynikiem problemów z kodem lub składnią. Błędy bazy danych są zgłaszane do pliku dziennika systemowego, ale uznaliśmy, że przydatne jest umieszczenie w katalogu najwyższego poziomu pliku *dbfail.out*, który gromadzi tylko informacje o problemach związanych z bazą danych. Jeśli plik istnieje i można go zapisać, będą rejestrowane w nim błędy bazy danych, a także w pliku dziennika systemowego. + +W przypadku błędów "500: problemy mogą być często rejestrowane w dziennikach serwera internetowego, często w */var/log/apache2/error.log* lub podobnym. Zapoznaj się z dokumentacją systemu operacyjnego. + +Istnieją trzy różne obiekty dziennika. + +**Pierwsza to dziennik błędów bazy danych**. Jest on używane tylko wtedy, gdy tworzy się plik o specyficznej nazwie *dbfail.out* w folderze głównym swojej witryny i pozwala na zapisywanie w nim przez serwer WWW. Jeśli masz jakiekolwiek zapytania do bazy danych, które nie powiodły się, wszystkie są zgłaszane tutaj. Zwykle wskazują na literówki w naszych zapytaniach, ale występują również w przypadku rozłączenia serwera bazy danych lub uszkodzenia tabel. W rzadkich przypadkach zobaczymy tutaj warunki wyścigu, w których dwa procesy próbowały utworzyć wpis *xchan* lub *cache* z tym samym identyfikatorem. Należy zbadać wszelkie inne błędy (zwłaszcza błędy uporczywe). + +**Drugi to dziennik błędów PHP**. Jest tworzony przez procesor języka i zgłasza tylko problemy powstałe w środowisku językowym. Znowu mogą to być błędy składniowe lub błędy programistyczne, ale generalnie są one fatalne i skutkują "białym ekranem"; +na przykład PHP kończy działanie. Prawdopodobnie powinieneś zajrzeć do tego pliku też, jeśli coś pójdzie nie tak, co nie powoduje białego ekranu. Często zdarza się, że plik ten jest pusty przez wiele dni. + +Na dole dostarczonego pliku *.htconfig.php* znajduje się kilka linii, które, jeśli nie są zakomentowane, włączają dziennik PHP (niezwykle przydatny do znajdowania źródła błędów białego ekranu). Nie jest to robione domyślnie ze względu na potencjalne problemy z własnością pliku dziennika i uprawnieniami do zapisu oraz fakt, że domyślnie nie ma rotacji pliku dziennika. + +**Trzeci to "dziennik aplikacji"**. Jest to używane przez Hubzillę do zgłaszania tego, co dzieje się w programie i zwykle zapisywane są tu wszelkie trudności lub nieoczekiwane dane, które otrzymaliśmy. Czasami zgłasza się tu również komunikaty +o stanie "pulsu", aby wskazać, że osiągnęliśmy określony punkt w skrypcie. Jest to dla nas najważniejszy plik dziennika, ponieważ tworzymy go samodzielnie wyłącznie w celu zgłaszania stanu zadań w tle i wszystkiego, co wydaje się dziwne lub nie na miejscu. To może nie być śmiertelne, ale może po prostu nieoczekiwane. Jeśli wykonujesz zadanie i występuje problem, daj nam znać, co znajduje się w tym pliku, gdy wystąpił problem. Proszę nie wysyłaj mi 100 milionów zrzutów, tylko mnie wkurzysz! Tylko kilka odpowiednich wierszy, abym mógł wykluczyć kilkaset tysięcy wierszy kodu i skoncentrować się na tym, gdzie zaczyna się pojawiać problem. + +To są dzienniki Twojej witryny, a nie moje. Zgłaszamy poważne problemy na każdym poziomie dziennika. Gorąco polecam poziom dziennika *DEBUG* dla większości witryn. Dostarcza on trochę dodatkowych informacji i nie tworzy dużych plików dziennika. Kiedy pojawia się problem, który uniemożliwia wszelkie próby śledzenia, możesz wtedy włączyć na krótki czas poziom *DATA*, aby uchwycić wszystkie szczegóły struktur, z którymi mieliśmy do czynienia w tym czasie. Ten poziom dziennika zajmuje dużo miejsca, więc jest zalecany tylko na krótkie okresy lub w przypadku witryn testowych dla programistów. + +Zalecam skonfigurowanie *logrotate* zarówno dla dziennika php, jak i dziennika aplikacji. Zazwyczaj co tydzień lub dwa zaglądam do *dbfail.out*, naprawiam zgłoszone problemy i zaczynam od nowego pliku. Podobnie jest z plikiem dziennika PHP. Odwołuję się do tego od czasu do czasu, aby sprawdzić, czy jest coś, co wymaga naprawy. + +Jeśli coś pójdzie nie tak i nie jest to błąd krytyczny, patrzę na plik dziennika aplikacji. Często robię to: + +``` +tail -f logfile.out +``` + +ponieważ powtarza operację, która ma problemy. Często wstawiam w kodzie dodatkowe instrukcje rejestracji, jeśli nie ma żadnej wskazówki, co się dzieje. Nawet coś tak prostego jak "got here" lub drukuję wartości zmiennej, która może być podejrzana. Ty też możesz to zrobić - wręcz zachęcam Cię do tego. Gdy już znajdziesz to, czego potrzebujesz, możesz wykonać: + +``` +git checkout file.php +``` + +aby natychmiast wyczyścić wszystkie dodane elementy rejestrowania. Skorzystaj z informacji z tego dziennika i wszelkich szczegółów, które możesz podać podczas badania problemu, aby zgłosić błąd - chyba że analiza wskazuje na źródło problemu. W takim przypadku po prostu to napraw. + +##### Rotowanie plików dziennika + +1. Włącz dodatek *Logrot* w [oficjalnym repozytorium dodatków hubzilla](https://framagit.org/hubzilla/addons). +1. Utwórz katalog w swoim katalogu głównym o nazwie `log` z uprawnieniami do zapisu przez serwer WWW. +1. Przejdź do ustawień administratora programu *Logrot* i wprowadź nazwę folderu, a także maksymalny rozmiar i liczbę zachowanych plików dziennika. + +#### Zgłaszanie problemów + +Zgłaszając problemy, staraj się podać jak najwięcej szczegółów, które mogą być potrzebne programistom do odtworzenia problemu i podać pełny tekst wszystkich komunikatów o błędach. + +Zachęcamy do dołożenia wszelkich starań, aby wykorzystać te dzienniki w połączeniu z posiadanym kodem źródłowym w celu rozwiązywania problemów i znajdowania ich przyczyn. Społeczność często jest w stanie pomóc, ale tylko Ty masz dostęp do +plików dziennika swojej witryny i ich udostępnianie jest uważane za zagrożenie bezpieczeństwa. + +Jeśli problem z kodem został odkryty, zgłoś go w bugtrackerze projektu (https://framagit.org/hubzilla/core/issues). Ponownie podaj jak najwięcej szczegółów, aby uniknąć ciągłego zadawania pytań o konfigurację lub powielanie problemu, abyśmy mogli przejść od razu do problemu i dowiedzieć się, co z nim zrobić. Zapraszamy również do oferowania własnych rozwiązań i przesyłania poprawek. W rzeczywistości zachęcamy do tego, ponieważ wszyscy jesteśmy wolontariuszami i mamy mało wolnego czasu. Im więcej osób pomaga, tym łatwiejsze jest obciążenie pracą dla wszystkich. W porządku, jeśli Twoje rozwiązanie nie jest idealne. Wszystko pomaga i być może uda nam się to poprawić. + diff --git a/doc/pl/admin/hub_snapshots.md b/doc/pl/admin/hub_snapshots.md new file mode 100644 index 000000000..fa38be7f8 --- /dev/null +++ b/doc/pl/admin/hub_snapshots.md @@ -0,0 +1,127 @@ +### Hub Snapshot Tools + +Programiści Hubzilli często muszą przełączać się między gałęziami, które mogą +mieć niekompatybilne schematy lub zawartość bazy danych. Poniższe dwa skrypty +tworzą i przywracają pełne migawki instancji Hubzilli, w tym zarówno główny +katalog sieciowy, jak i stan całej bazy danych. Każdy skrypt wymaga pliku +konfiguracyjnego o nazwie *hub-snapshot.conf* znajdującego się w tym samym +folderze i zawiera on określone katalogi i szczegóły bazy danych huba. + +### Konfiguracja + +Format pliku konfiguracyjnego jest bardzo ścisły. Między nazwą zmiennej a +wartością nie może być spacji. Zastąp tylko treść w cudzysłowach swoją +konfiguracją. Zapisz ten plik jako *hub-snapshot.conf* obok skryptów. + + # Location of hub root. Typically this is the location of the Hubzilla repo clone. + HUBROOT="/var/www/" + # MySQL database name + DBNAME="hubzilla" + # MySQL database user + DBUSER="hubzilla" + # MySQL database password + DBPWD="akeufajeuwfb" + # The target snapshot folder where the git repo will be initialized + SNAPSHOTROOT="/root/snapshots/hubzilla/" + +### Migawka + +Przykład użycia: + + sh hub-snapshot.sh my-hub.conf "Commit message for the snapshot" + +**hub-snapshot.sh**: + + #!/bin/bash + + if ! [ -f "$1" ]; then + echo "$1 is not a valid file. Aborting..." + exit 1 + fi + source "$1" + #echo "$DBNAME" + #echo "$DBUSER" + #echo "$DBPWD" + #echo "$HUBROOT" + #echo "$SNAPSHOTROOT" + MESSAGE="snapshot: $2" + + if [ "$DBPWD" == "" -o "$SNAPSHOTROOT" == "" -o "$DBNAME" == "" -o "$DBUSER" == "" -o "$HUBROOT" == "" ]; then + echo "Required variable is not set. Aborting..." + exit 1 + fi + + if [ ! -d "$SNAPSHOTROOT"/db/ ]; then + mkdir -p "$SNAPSHOTROOT"/db/ + fi + if [ ! -d "$SNAPSHOTROOT"/www/ ]; then + mkdir -p "$SNAPSHOTROOT"/www/ + fi + + if [ ! -d "$SNAPSHOTROOT"/www/ ] || [ ! -d "$SNAPSHOTROOT"/db/ ]; then + echo "Error creating snapshot directories. Aborting..." + exit 1 + fi + + echo "Export database..." + mysqldump -u "$DBUSER" -p"$DBPWD" "$DBNAME" > "$SNAPSHOTROOT"/db/"$DBNAME".sql + echo "Copy hub root files..." + rsync -va --delete --exclude=.git* "$HUBROOT"/ "$SNAPSHOTROOT"/www/ + + cd "$SNAPSHOTROOT" + + if [ ! -d ".git" ]; then + git init + fi + if [ ! -d ".git" ]; then + echo "Cannot initialize git repo. Aborting..." + exit 1 + fi + + git add -A + echo "Commit hub snapshot..." + git commit -a -m "$MESSAGE" + + exit 0 + +### Przywracanie + + #!/bin/bash + # Restore hub to a previous state. Input hub config and commit hash + + if ! [ -f "$1" ]; then + echo "$1 is not a valid file. Aborting..." + exit 1 + fi + source "$1" + COMMIT=$2 + + if [ "$DBPWD" == "" -o "$SNAPSHOTROOT" == "" -o "$DBNAME" == "" -o "$DBUSER" == "" -o "$HUBROOT" == "" ]; then + echo "Required variable is not set. Aborting..." + exit 1 + fi + RESTOREDIR="$(mktemp -d)/" + + if [ ! -d "$RESTOREDIR" ]; then + echo "Cannot create restore directory. Aborting..." + exit 1 + fi + echo "Cloning the snapshot repo..." + git clone "$SNAPSHOTROOT" "$RESTOREDIR" + cd "$RESTOREDIR" + echo "Checkout requested snapshot..." + git checkout "$COMMIT" + echo "Restore hub root files..." + rsync -a --delete --exclude=.git* "$RESTOREDIR"/www/ "$HUBROOT"/ + echo "Restore hub database..." + mysql -u "$DBUSER" -p"$DBPWD" "$DBNAME" < "$RESTOREDIR"/db/"$DBNAME".sql + + chown -R www-data:www-data "$HUBROOT"/{store,extend,addon,.htlog,.htconfig.php} + + echo "Restored hub to snapshot $COMMIT" + echo "Removing temporary files..." + + rm -rf "$RESTOREDIR" + + exit 0 + diff --git a/doc/pl/admins.bb b/doc/pl/admins.bb new file mode 100644 index 000000000..e27b3ae73 --- /dev/null +++ b/doc/pl/admins.bb @@ -0,0 +1,15 @@ +[h2]Dokumentacja dla administratorów huba[/h2] +[h3]Wdrozenie swojego huba[/h3] +[zrl=[baseurl]/help/install]Instalacja[/zrl] +[zrl=[baseurl]/help/red2pi]Instalowanie $Projectname na Raspberry Pi[/zrl] +[zrl=[baseurl]/help/Hubzilla_on_OpenShift]$Projectname na OpenShift[/zrl] +[h3]Utrzymywanie swojego huba[/h3] +[zrl=[baseurl]/help/troubleshooting]Wskazówki dotyczące rozwiązywania problemów[/zrl] +[zrl=[baseurl]/help/theme_management]Zarządzanie motywami[/zrl] +[zrl=[baseurl]/help/hidden_configs]Poprawianie ukrytych konfiguracji $Projectname[/zrl] +[zrl=[baseurl]/help/service_classes]Klasy usługi[/zrl] +[zrl=[baseurl]/help/directories]Praca z katalogami i ich konfigurowanie[/zrl] +[h3]Najczęściej zadawane pytania[/h3] +[zrl=[baseurl]/help/faq_admins]FAQ dla administratorów[/zrl] + +#include doc/macros/main_footer.bb; diff --git a/doc/pl/bugs.bb b/doc/pl/bugs.bb new file mode 100644 index 000000000..de1ed03a5 --- /dev/null +++ b/doc/pl/bugs.bb @@ -0,0 +1,31 @@ +[h2]Błędy, problemy i rzeczy, które pojawiają się w nocy ...[/h2] +[h3]Coś poszło nie tak! Kto jest odpowiedzialny za naprawianie tego?[/h3] + +[b]$Projectname Community Server[/b] + +$Projectname Community Server to oprogramowanie typu Open Source, które jest utrzymywane przez "społeczność" - zasadniczo nieopłacanych ochotników. Nikt nie jest odpowiedzialny za naprawianie błędów. Pracujemy razem, aby oprogramowanie i sieć działały płynnie i bez błędów. Jesteś członkiem tej społeczności, więc potrzebujemy również Twojej pomocy, aby zapewnić wysokiej jakości oprogramowanie. Nie ma mitycznych "programistów", którzy w magiczny sposób wszystko naprawiają. Do nas wszystkich należy włączenie się i pomoc. + +Pierwszą rzeczą, którą musisz zrobić, jest porozimieć się z administratorem huba - osobą, która obsługuje Twoją witrynę i zarządza nią. Znajdują się ona w wyjątkowej sytuacji, ponieważ ma dostęp do wewnętrznego oprogramowania i bazy danych oraz [b]plików dziennika[/b] i będzie musiała zaangażować się w naprawę problemu. Inne osoby "w sieci" nie mogą naprawdę Ci tym pomóc. Pierwszą rzeczą, jaką musi zrobić administrator huba, jest przejrzenie dzienników i podjecie próby odtworzenia problemu. Dlatego staraj się być tak pomocny i uprzejmy, jak to tylko możliwe, pomagając mu przyjrzeć się problemowi. + +Aby znaleźć swojego administratora huba (jeśli nie wiesz, kim on jest), zajrzyj na [url=[baseurl]/siteinfo]tą stronę[/url]. Jeśli nie podał on żadnych informacji kontaktowych na tej stronie lub nie podał "Impressum", zobacz [url=[baseurl]/siteinfo.json]podsumowanie informacji o tej witrynie[/url] znajdujące się pod nagłówkiem "admin:". + +Zdecydowanie zaleca się, aby administratorzy huba wypełniali raporty o błędach, tak aby możliwe było dołączenie odpowiedniego plik dziennika i informacji z bazy danych istotnych dla problemu oraz aby byli oni gotowi do wypróbowania rozwiązań i testów uzupełniających. Bez tego poziomu współpracy rozwiązanie problemu może nie być możliwe. + +[h3]Jestem administratorem huba, co mam zrobić?[/h3] + +Oprogramowania zapewniające tą usługę sieciową jest typu Open Source i jest dostępne do wglądu. Zachęcamy wszystkich do zapoznania się z kodem i zobaczenia, jak wszystko działa i sprawdzenia, czy nie robimy nic złego lub niedbałego. Jeśli został zgłoszony komunikat o błędzie, często można przeszukać pliki źródłowe tego komunikatu o błędzie i dowiedzieć się, co go spowodowało. Dzięki tym informacjom i plikom dziennika serwisu możliwe będzie ustalenie sekwencji zdarzeń prowadzących do błędu. Problem mogą powodować również serwisy zewnętrzne i jego źródłem wcale nie musi być Twój serwis, ale inne miejsce w sieci. Spróbuj określić punkty końcowe komunikacji (huby lub serwisy), których dotyczy problem i skontaktuj się z administratorem tego serwisu lub tych serwisów. Spróbuj podać czas zdarzenia, w którym coś poszło nie tak, aby można go było znaleźć w dziennikach. Współpracuj z innymi administratorami, aby spróbować znaleźć przyczynę problemu. Pliki dziennika są Twoim przyjacielem. Kiedy w oprogramowaniu dzieje się coś, czego się nie spodziewaliśmy, prawie zawsze zostało to zarejestrowane. + +[h3]Biały ekran śmierci[/h3] + +Jeśli podczas robienia czegoś pojawia się pusty biały ekran, prawie zawsze jest to błąd kodu lub składni. W pliku .htconfig.php serwisu znajdują się instrukcje, które pozwolą administratorowi witryny na włączenie rejestrowania składni. Zalecamy wszystkim witrynom korzystanie z tego. Po włączeniu rejestrowania składni powtórz sekwencję, która doprowadziła do błędu, a powinna ona zarejestrować nieprawidłową linię kodu. Mamy nadzieję, że dzięki tym informacjom uda Ci się rozwiązać problem. Gdy to zrobisz, prześlij poprawkę "upstream", abyśmy mogli udostępnić poprawkę pozostałym członkom projektu i innym społecznościom. To jest kluczowa zaleta korzystania z oprogramowania Open Source - dzielimy się mim wszyscy. + +[h3]Jestem głupi. Nie wiem, co jest nie tak.[/h3] + +W tej sytuacji warto omówić tę kwestię na jednym z forów internetowych. Może być ich kilka, a niektóre mogą bardziej pasować do Twojego ojczystego języka. W tej chwili kanał "Hubzilla Support" (support@zotadel.net) jest zalecanym forum do omawiania błędów. + +Jeśli członkowie społeczności z wykształceniem i doświadczeniem w zakresie inżynierii oprogramowania nie mogą Ci od razu pomóc, zrozum, że są wolontariuszami i mogą mieć dużo innej pracy i zobowiązań w tym czasie. W tym momencie musisz zgłosić błąd. Aby to zrobić, będziesz potrzebować konta na framagit.org. Zarejestruj się, a następnie odwiedź https://framagit.org/hubzilla/core/issues. Utwórz tutaj problem i podaj wszystkie te same informacje, które podałeś online. Nie pomijaj niczego. + +Następnie musisz zaczekać. Jeśli jest to poważny problem, może zostać szybko rozwiązany, ale nikt nie jest odpowiedzialny za naprawianie błędów. Jeśli problem utrzymuje się bez rozwiązania, poświęć trochę czasu na zbadanie samemu problemu. Zapytaj o wszystko, czego nie rozumiesz a co jest związane z tym problemem. Dowiesz się więcej o tym, jak działa oprogramowanie i prawdopodobnie dowiesz się, dlaczego teraz nie działa. Ostatecznie to ktoś w społeczności ma zamiar to naprawić, a ty jesteś członkiem społeczności. Tak właśnie działa proces Open Source. + +Inne osoby pracujące nad rozwiązaniem problemu mogą potrzebować dowiedzieć się więcej, więc odrób swoją pracę domową i udokumentuj, co się dzieje i wszystko, czego próbowałeś. Nie mów "Zrobiłem xyz i to nie działa". To nam nic nie mówi. Powiedz nam dokładnie, jakie kroki podjąłeś i jaki był rezultat, a także co się w rezultacie wydarzyło. Jaką stronę (URL) przeglądałeś lub jaki formularz wypełniałeś? Jeśli były jakieś komunikaty o błędach, nie mów "wystąpił komunikat o błędzie". Powiedz nam dokładnie, o czym była wiadomość. Powiedz nam również, z jakiego huba korzystasz, jakiej wersji oprogramowania używasz i wszelkie inne szczegóły, które mogą być unikalne na temat konfiguracji Twojej witryny. Rozumie się, że możesz chcieć zachować prywatność niektórych informacji i swoich połączeń, jednak jeśli nie chcesz udostępniać informacji potrzebnych innym osobom do odtworzenia i rozwiązania problemu, może on nie zostać naprawiony. + diff --git a/doc/pl/checking_account_quota_usage.bb b/doc/pl/checking_account_quota_usage.bb new file mode 100644 index 000000000..b2cc0075c --- /dev/null +++ b/doc/pl/checking_account_quota_usage.bb @@ -0,0 +1,20 @@ +[b]Sprawdzanie wykorzystania limitu konta (wykorzystanie limitów usług)[/b] + +Na Twoim hubie mogą zostać zaimplementowane limity klas usług, przypisujące ograniczenia do całkowitego rozmiaru miejsca na plików i zdjęci, ilosci kanałów i postów najwyższego poziomu, jakie może utworzyć właściciel konta dla określonego poziomu usług i inne ograniczenia. + +Oto, jak możesz szybko sprawdzić, ile z przydzielonego limitu aktualnie używasz: + +[b]Sprawdenie poziom limitów przechowywania plików[/b] +Odwiedź nastęþujący adres URL w przeglądarce: +[observer=1][observer.baseurl]/filestorage/[observer.webname][/observer] +[observer=0]example.com/filestorage/username[/observer] + +[b]Sprawdenie poziomu limitów miejsca na przesłane zdjęcia[/b] +[observer=1][observer.baseurl]/photos/[observer.webname][/observer] +[observer=0]example.com/photos/username[/observer] + +Przykład: +[observer=1][observer.baseurl]/filestorage/[observer.webname][/observer] +[observer=0]example.com/filestorage/username[/observer] + +#include doc/macros/main_footer.bb; diff --git a/doc/pl/general.bb b/doc/pl/general.bb new file mode 100644 index 000000000..0dc15ea91 --- /dev/null +++ b/doc/pl/general.bb @@ -0,0 +1,18 @@ +[h2]Informacja o projekcie i serwisie[/h2] +[h3]$Projectname[/h3] +[zrl=[baseurl]/help/Privacy]Polityka prywatności[/zrl] +[zrl=[baseurl]/help/project/governance]Zarządzanie projektem[/zrl] +[zrl=[baseurl]/help/contributor/convenant]Porozumienie projektowe i kodeks postępowania[/zrl] + +[h3]Źródła zewnętrzne[/h3] +[zrl=[baseurl]/help/external-resource-links]Wykaz zasobów zewnętrznych[/zrl] +[url=https://framagit.org/hubzilla/core/]Główna witryna internetowa[/url] +[url=https://framagit.org/hubzilla/addons]Witryna dodatków[/url] +[url=[baseurl]/help/credits]Podziękowania od $Projectname[/url] +[h3]O tym hubie $Projectname[/h3] +[zrl=[baseurl]/help/TermsOfService]Warunki świadczenia usług dla tego huba[/zrl] +[zrl=[baseurl]/siteinfo]Inormacja o hubie (/siteinfo)[/zrl] +[zrl=[baseurl]/siteinfo/json]Szczegółowe informacje techniczne w formacie JSON(/siteinfo/json)[/zrl] + +#include doc/macros/main_footer.bb; + diff --git a/doc/pl/main.bb b/doc/pl/main.bb new file mode 100644 index 000000000..24caa1453 --- /dev/null +++ b/doc/pl/main.bb @@ -0,0 +1,20 @@ +[img][baseurl]/images/hubzilla-banner.png[/img] + +[zrl=[baseurl]/help/about]Co to jest $Projectname?[/zrl] +$Projectname to bezpłatny i otwartoźródłowy zestaw aplikacji i usług internetowych działających na specjalnym serwerze internetowym, zwanym "hubem", który może łączyć się z innymi hubami w sfederalizowanej sieci internetowej. + +[zrl=[baseurl]/help/features]Możliwości $Projectname[/zrl] +$Projectname zapewnia użytkownikom zaawansowaną komunikację, tożsamości i usług kontroli dostępu, które bezproblemowo współpracują w różnych domenach i niezależnych witrynach internetowych. Pozwala użytkownikom [b]publicznie[/b] lub [b]prywatnie[/b] publikować treści za pośrednictwem "kanałów" (ang. channel), które są podstawowymi, zabezpieczonymi kryptograficznie tożsamościami zapewniającymi uwierzytelnianie niezależnie od hubów, które je hostują. To rewolucyjne wyzwolenie tożsamości online z poszczególnych serwerów i domen jest nazywane "tożsamością nomadyczną" i jest oparte na protokole Zot, nowej strukturze zdecentralizowanej kontroli dostępu ze szczegółowymi, rozszerzalnymi uprawnieniami. +Z praktycznego punktu widzenia członków danego huba, korzystających z oprogramowania $Projectname, oferuje ono szereg znanych, zintegrowanych aplikacji i usług internetowych, w tym: +[ul] +[li]wątki dyskusyjne w sieciach społecznościowych[/li] +[li]przechowywanie plików w chmurze[/li] +[li]kalendarz i kontakty (z obsługą CalDAV i CardDAV)[/li] +[li]hosting stron internetowych z systemem zarządzania treścią[/li] +[li]wiki[/li] +[li]i dużo więcej ...[/li][/ul] +Chociaż wszystkie te aplikacje i usługi można znaleźć w innych pakietach oprogramowania, tylko $Projectname pozwala ustawić uprawnienia dla grup i osób, [b]które mogą nawet nie mieć kont na Twoim hubie[/b]! W typowych aplikacjach internetowych, jeśli chcesz udostępniać rzeczy prywatnie w Internecie, osoby, którym udostępniasz dane, muszą mieć konta na serwerze, na którym znajdują się Twoje dane; w przeciwnym razie serwer nie może uwierzytelniać odwiedzających witrynę, aby wiedzieć, czy przyznać im dostęp. $Projectname rozwiązuje ten problem za pomocą zaawansowanego systemu zdalnego uwierzytelniania, który weryfikuje tożsamość odwiedzających, wykorzystując techniki obejmujące kryptografię klucza publicznego. +Dzięki oferowanym aplikacjom, $Projectname świetnie się nadaje do budowy platformy komunikacyjno-publikacyjnej o charkterze społecznościowym dla realnych grup społecznych, takich jak rodziny, lokalne grupy, organizacje społeczne, środowiska szkolne, wspólnoty mieszkańców czy wspólnoty religijne. + +[zrl=[baseurl]/help/what_is_zot]Co to jest Zot?[/zrl] +Jest to nowy protokół, oparty na JSON, do wdrażania bezpiecznej, zdecentralizowanej komunikacji i usług. Różni się od wielu innych protokołów komunikacyjnych, budując komunikację na podstawie zdecentralizowanej struktury tożsamości i uwierzytelniania. Składnik uwierzytelniania jest koncepcyjnie podobny do OpenID, ale jest odizolowany od tożsamości opartej na DNS. Tam, gdzie to możliwe, zdalne uwierzytelnianie jest ciche i niewidoczne. Zapewnia to mechanizm kontroli dostępu rozproszonego na skalę sieci WWW, który jest dyskretny. diff --git a/doc/pl/member/assets/qr_text_to_post.png b/doc/pl/member/assets/qr_text_to_post.png new file mode 100644 index 000000000..887c85492 Binary files /dev/null and b/doc/pl/member/assets/qr_text_to_post.png differ diff --git a/doc/pl/member/assets/zat_dialog.png b/doc/pl/member/assets/zat_dialog.png new file mode 100644 index 000000000..892964e95 Binary files /dev/null and b/doc/pl/member/assets/zat_dialog.png differ diff --git a/doc/pl/member/bbcode.html b/doc/pl/member/bbcode.html new file mode 100644 index 000000000..655c021ee --- /dev/null +++ b/doc/pl/member/bbcode.html @@ -0,0 +1,343 @@ + ++W Hubzilla stosowana jest własna odmiana BBCode. Niniejszy informator jest +treściwym opisem składni tej odmiany BBCode. +
+ +| Składnia BBcode | Tekst formatowany | +
|---|---|
[b]pogrubiony[/b] | pogrubiony | +
[i]pochyły[/i] | pochyły | +
[u]podkreślony[/u] | podkreślony | +
[s]przekreślony[/s] | |
[color=red]czerwony[/color] | czerwony | +
[hl]podświetlony[/hl] | podświetlony | +
[font=courier]jaiś tekst[/font] | jakiś tekst | +
[quote]cytat[/quote] | cytat |
+
[quote=Author]Autor? Ja? Nie, nie, nie...[/quote] | Autor napisał:Autor? Ja? Nie, nie, nie... |
+
+ [size=small]tekst mały (small)[/size]
+ Opcje rozmiaru obejmują: xx-small, small, medium, large, xx-large | tekst mały (small) tekst wielki ()xx-large) tekst z czcionką 20px |
+
Dodanie poziomego paska
+[hr]
+Tak jak to
+ |
+ Dodanie poziomego paska Tak jak to + |
+
To jest
+[center]wyśrodkowany[/center]
+tekst |
+ To jest wyśrodkowany tekst + |
+
| Składnia BBcode | Wyjście | +
|---|---|
[code]funkcja bbcode() { }[/code] | funkcja bbcode() { } |
+
[code=php]funkcja bbcode() { | |
+
[nobb][nobb]W ten sposób [i]możesz[/i]
+[u]pokazać[/u] jak użyć składnię
+[hl]BBcode[/hl][/nobb][/nobb] | [nobb]W ten sposób [i]możesz[/i] [u]pokazać[/u] jak uzyć składnię []hl]BBcode[/hl][/nobb] | +
| Składnia BBcode | Wyrenderowana lista | +
|---|---|
[ul] |
|
+
[ol] |
|
+
[list=A]
+ Elementami listy są 1, i, I, a, A. |
|
+
[dl terms="b"]
+ Opcje stylu hasła mogą być kombinacją tekstu:
+
|
|
+
| Składnia BBcode | Wyrenderowana tabela | +||||||
|---|---|---|---|---|---|---|---|
[table border=0] |
|
+ ||||||
[table border=1] |
|
+ ||||||
[table] |
|
+
| Składnia BBcode | Wyjście | +
|---|---|
[video]URL wideo[/video] | + |
[url=https://hubzilla.org]Hubzilla[/url] | Hubzilla | +
Obraz [img]https://example.org/image.jpg[/img]
+w jakimś tekście |
+ Obraz w jakimś tekście
+ |
+
| Składnia BBcode | Wyjście | +
|---|---|
Wersja tagu [url] wykorzystująca magiczne uwierzytelnianie
+ [zrl=https://hubzilla.org]Link rozpoznający tożsamość[/zrl]
+ | https://hubzilla.org/?zid=[observer=1][observer.address][/observer][observer=0]your_channel@your.home.hub[/observer] |
+
Wersja tagu [img] wykorzystująca magiczną uwierzytelnianie
+ [zmg]https://hubzilla.org/some/photo.jpg[/zmg]
+ | Obraz jest widoczny tylko dla osób uwierzytelnionych i za zgodą właściciela kanału. | +
Wyjście zależne od obserwatora:
+ [nobb][observer=1]Tekst do wyświetlenia, jeśli obserwator JEST uwierzytelniony[/observer][/nobb]
+ | + |
+
+ [nobb][observer=0]Tekst wyświetlany, jeśli obserwator NIE JEST uwierzytelniony[/observer][/nobb]
+
+ |
+ + |
+
+ [nobb][observer.language=en]Tekst wyświetlany, jeśli językiem obserwatora jest angielski[/observer][/nobb]
+
+ |
+ + |
+
+ [nobb][observer.language!=de]Tekst wyświetlany, jeśli językiem obserwatora nie jest język niemiecki[/observer][/nobb]
+
+ |
+ + |
+
+ [nobb][observer.url][/nobb]
+
+ |
+ adres URL kanału obserwatora | +
+
+ [nobb][observer.baseurl][/nobb]
+
+ |
+ witryna WWW obserwatora | +
+
+ [nobb][observer.name][/nobb]
+
+ |
+ nazwa obserwatora | +
+
+ [nobb][observer.webname][/nobb]
+
+ |
+ krótka nazwa w adresie URL obserwatora | +
+
+ [nobb][observer.address][/nobb]
+
+ |
+ adres (ZOT-id) obserwatora | +
+
+ [nobb][observer.photo][/nobb]
+
+ |
+ zdjęcie profilowe obserwatora | +
Co to jest spoiler? |
+ Co to jest spoiler? Kliknij, aby otworzyć/zamknąć
+ |
+
[toc data-toc='div.page-body' data-toc-headings='h1,h2']+Utwórz spis treści na stronie internetowej lub stronie wiki. Proszę zapoznać się z oryginalnym widżetem TOC jQuery aby uzyskać więcej informacji. +
| + |
[nobb][rpost=title]Tekst do publikacji[/rpost][/nobb]+Obserwator wróci do swojego macierzystego huba, aby wprowadzić post z określonym tytułem i treścią. Obie opcje są opcjonalne | [baseurl]/rpost?f=&title=title&body=Text+to+post | +
Wymaga to wtyczki qrator.[qr]tekst do publikacji[/qr] | ![]() |
+
Wymaga to odpowiedniej wtyczki mapy, takiej jak openstreetmap.
+ [map] | Wygenerowanie wbudowanej mapy przy użyciu aktualnych współrzędnych plakatu w przeglądarce, jeśli lokalizacja przeglądarki jest włączona | +
Wymaga to odpowiedniej wtyczki mapy, takiej jak openstreetmap.
+ [map=latitude,longitude] | Wygenerowanie mapy przy wykorzystaniu współrzędnych globalnych. |
Wymaga to odpowiedniej wtyczki mapy, takiej jak openstreetmap.
+ [map]Nazwa miejsca[/map] | +Wygenerowanie mapy dla podanej nazwanej lokalizacji. Zwracana jest pierwsza pasująca lokalizacja. Na przykład „Sydney” zazwyczaj zwraca Sydney w Australii, a nie Sydney w Nowej Szkocji w Kanadzie, chyba że określono dokładniejszą lokalizację. Zdecydowanie zalecamy skorzystanie z narzędzia podglądu posta, aby upewnić się, że masz prawidłową lokalizację przed wysłaniem postu. + | +
[©] | © | +
HTML block content
+ [menu]menuname[/menu] + +[/code] +wytworzy HTML taki jak ten: +[code] + + +[/code] + +Makro [code]$content[/code] umożliwia osadzenie całej treści strony internetowej. W tym celu wystarczy utwórzyć taki blok: +[code] + $content + +[/code] +jako treść. Aby blok pojawił się na stronie internetowej, musi być zdefiniowany w układzie strony wewnątrz regionu. +[code] + [region=aside] + [block]blockname[/block] + [/region] + +[/code] + +Wygląd bloku można zmieniać w układzie strony. + +W regionie można przypisać własne klasy (css). Ten kod: +[code] + [region=aside] + [block=myclass]blockname[/block] + [/region] + +[/code] +wytworzy taki HTML: +[code] +' . bb_code_protect(trim($match[1])) . '';
else
return '' . bb_code_protect(trim($match[1])) . '';
}
function bb_code_options($match) {
- if(strpos($match[0], "' . bb_code_protect(trim($match[2])) . '';
- } else {
+ } else {
return '' . bb_code_protect(trim($match[2])) . '';
}
}
@@ -949,7 +969,7 @@ function bb_fixtable_lf($match) {
// remove extraneous whitespace between table element tags since newlines will all
// be converted to '