diff --git a/README.md b/README.md index d21adc256..3ceb6cfb0 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,11 @@ ZAP === -Zap is a full featured social network application running under the Zot6 protocol. It provides enhanced privacy modes and identity/content mirroring across multiple servers ("nomadic identity"). It does not "federate" with non-nomadic servers, protocols, or projects. +Zap is a decentralised social network server application with a number of powerful features, yet very easy to use. + Installation ============ -Read `/install/INSTALL.txt` for installation instructions. \ No newline at end of file +Read `install/INSTALL.txt` for installation instructions. \ No newline at end of file diff --git a/Zotlabs/Daemon/Cron_weekly.php b/Zotlabs/Daemon/Cron_weekly.php index d44400767..315089f67 100644 --- a/Zotlabs/Daemon/Cron_weekly.php +++ b/Zotlabs/Daemon/Cron_weekly.php @@ -52,7 +52,8 @@ class Cron_weekly { Master::Summon(array('Checksites')); // update searchable doc indexes - Master::Summon(array('Importdoc')); + // disabled until help system regenerated + // Master::Summon(array('Importdoc')); /** * End Cron Weekly diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php index 53cbab0d6..e8bf654fa 100644 --- a/Zotlabs/Daemon/Notifier.php +++ b/Zotlabs/Daemon/Notifier.php @@ -61,6 +61,7 @@ require_once('include/bbcode.php'); * permissions_reject abook_id * permissions_update abook_id * refresh_all channel_id + * purge xchan_hash * purge_all channel_id * expire channel_id * relay item_id (item was relayed to owner, we will deliver it as owner) @@ -228,13 +229,21 @@ class Notifier { self::$private = false; self::$packet_type = 'refresh'; } + elseif($cmd === 'purge') { + $xchan = argv(3); + logger('notifier: purge: ' . $item_id . ' => ' . $xchan); + if (! $xchan) { + return; + } + + self::$channel = channelx_by_n($item_id); + self::$recipients = [ $xchan ]; + self::$private = true; + self::$packet_type = 'purge'; + } elseif($cmd === 'purge_all') { logger('notifier: purge_all: ' . $item_id); - $s = q("select * from channel where channel_id = %d limit 1", - intval($item_id) - ); - if($s) - self::$channel = $s[0]; + self::$channel = channelx_by_n($item_id); self::$recipients = array(); $r = q("select abook_xchan from abook where abook_channel = %d and abook_self = 0", diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 0674ce1c7..74ef0efe7 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -15,19 +15,19 @@ class Activity { static function encode_object($x) { - if(($x) && (! is_array($x)) && (substr(trim($x),0,1)) === '{' ) { + if (($x) && (! is_array($x)) && (substr(trim($x),0,1)) === '{' ) { $x = json_decode($x,true); } - if($x['type'] === ACTIVITY_OBJ_PERSON) { + if ($x['type'] === ACTIVITY_OBJ_PERSON) { return self::fetch_person($x); } - if($x['type'] === ACTIVITY_OBJ_PROFILE) { + if ($x['type'] === ACTIVITY_OBJ_PROFILE) { return self::fetch_profile($x); } - if(in_array($x['type'], [ ACTIVITY_OBJ_NOTE, ACTIVITY_OBJ_ARTICLE ] )) { + if (in_array($x['type'], [ ACTIVITY_OBJ_NOTE, ACTIVITY_OBJ_ARTICLE ] )) { return self::fetch_item($x); } - if($x['type'] === ACTIVITY_OBJ_THING) { + if ($x['type'] === ACTIVITY_OBJ_THING) { return self::fetch_thing($x); } @@ -39,17 +39,17 @@ class Activity { static function fetch($url,$channel = null,$hub = 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) { + if (strpos($url,'x-zot:') === 0) { $x = ZotURL::fetch($url,$channel,$hub); } else { @@ -64,7 +64,7 @@ class Activity { $x = z_fetch_url($url, true, $redirects, [ 'headers' => $h ] ); } - if($x['success']) { + if ($x['success']) { $y = json_decode($x['body'],true); logger('returned: ' . json_encode($y,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)); return json_decode($x['body'], true); @@ -85,17 +85,17 @@ 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],false); - } static function fetch_thing($x) { @@ -105,18 +105,19 @@ class Activity { dbesc($x['id']) ); - if(! $r) + if (! $r) { return []; - + } + $x = [ 'type' => 'Object', 'id' => z_root() . '/thing/' . $r[0]['obj_obj'], 'name' => $r[0]['obj_term'] ]; - if($r[0]['obj_image']) + if ($r[0]['obj_image']) { $x['image'] = $r[0]['obj_image']; - + } return $x; } @@ -131,7 +132,7 @@ class Activity { $r = q("select * from item where mid = '%s' limit 1", dbesc($x['id']) ); - if($r) { + if ($r) { xchan_query($r,true); $r = fetch_post_tags($r,true); return self::encode_item($r[0],((defined('NOMADIC')) ? false : true)); @@ -146,23 +147,26 @@ class Activity { 'totalItems' => count($items), ]; - if($items) { + if ($items) { $x = []; - foreach($items as $i) { + foreach ($items as $i) { $m = get_iconfig($i['id'],'activitypub','rawmsg'); - if($m) { + if ($m) { $t = json_decode($m,true); } else { $t = self::encode_activity($i,$activitypub); } - if($t) + if ($t) { $x[] = $t; + } } - if($type === 'OrderedCollection') + if ($type === 'OrderedCollection') { $ret['orderedItems'] = $x; - else + } + else { $ret['items'] = $x; + } } return $ret; @@ -175,21 +179,24 @@ class Activity { 'type' => $type, 'totalItems' => count($items), ]; - if($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 + } + else { $ret['items'] = $x; + } } return $ret; @@ -206,7 +213,7 @@ class Activity { $objtype = self::activity_obj_mapper($i['obj_type']); - if(intval($i['item_deleted'])) { + if (intval($i['item_deleted'])) { $ret['type'] = 'Tombstone'; $ret['formerType'] = $objtype; $ret['id'] = $i['mid']; @@ -227,13 +234,13 @@ class Activity { $convert_to_article = false; $images = false; - if($activitypub && $ret['type'] === 'Note') { + if ($activitypub && $ret['type'] === 'Note') { $bbtags = false; $num_bbtags = preg_match_all('/\[\/([a-z]+)\]/ism',$i['body'],$bbtags,PREG_SET_ORDER); - if($num_bbtags) { + if ($num_bbtags) { - foreach($bbtags as $t) { + foreach ($bbtags as $t) { if((! $t[1]) || (in_array($t[1],['url','zrl','img','zmg']))) { continue; } @@ -243,10 +250,10 @@ class Activity { $has_images = preg_match_all('/\[[zi]mg(.*?)\](.*?)\[/ism',$i['body'],$images,PREG_SET_ORDER); - if($has_images > 1) { + if ($has_images > 1) { $convert_to_article = true; } - if($convert_to_article) { + if ($convert_to_article) { $ret['type'] = 'Article'; } } @@ -254,18 +261,21 @@ class Activity { $ret['id'] = $i['mid']; $ret['published'] = datetime_convert('UTC','UTC',$i['created'],ATOM_TIME); - if($i['created'] !== $i['edited']) { + if ($i['created'] !== $i['edited']) { $ret['updated'] = datetime_convert('UTC','UTC',$i['edited'],ATOM_TIME); } - if($i['app']) { - $ret['instrument'] = [ 'type' => 'Service', 'name' => $i['app'] ]; + if ($i['expires'] <= NULL_DATE) { + $ret['expires'] = datetime_convert('UTC','UTC',$i['expires'],ATOM_TIME); } - if($i['location'] || $i['coord']) { + 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']) { $ret['location']['name'] = $i['location']; } - if($i['coord']) { + if ($i['coord']) { $l = explode(' ',$i['coord']); $ret['location']['latitude'] = $l[0]; $ret['location']['longitude'] = $l[1]; @@ -274,11 +284,11 @@ class Activity { $ret['inheritPrivacy'] = true; - if(intval($i['item_wall']) && $i['mid'] === $i['parent_mid']) { + if (intval($i['item_wall']) && $i['mid'] === $i['parent_mid']) { $ret['commentPolicy'] = map_scope(PermissionLimits::Get($i['uid'],'post_comments')); } - if(array_key_exists('comments_closed',$i) && $i['comments_closed'] !== EMPTY_STR && $i['comments_closed'] !== NULL_DATE) { + if (array_key_exists('comments_closed',$i) && $i['comments_closed'] !== EMPTY_STR && $i['comments_closed'] !== NULL_DATE) { if($ret['commentPolicy']) { $ret['commentPolicy'] .= ' '; } @@ -287,86 +297,89 @@ class Activity { $ret['attributedTo'] = $i['author']['xchan_url']; - if($i['mid'] !== $i['parent_mid']) { + if ($i['mid'] !== $i['parent_mid']) { $ret['inReplyTo'] = $i['thr_parent']; $cnv = get_iconfig($i['parent'],'ostatus','conversation'); - if(! $cnv) { + if (! $cnv) { $cnv = $ret['parent_mid']; } $reply = true; - if($i['item_private']) { + 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) { + if ($d) { $recips = get_iconfig($i['parent'], 'activitypub', 'recips'); - if(in_array($i['author']['xchan_url'], $recips['to'])) { + if (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'],'@')); + 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']); } } } - if(! $cnv) { + if (! $cnv) { $cnv = get_iconfig($i,'ostatus','conversation'); } - if($cnv) { + if ($cnv) { $ret['conversation'] = $cnv; } - if($i['mimetype'] === 'text/bbcode') { - if($i['title']) + if ($i['mimetype'] === 'text/bbcode') { + if ($i['title']) { $ret['name'] = $i['title']; - if($i['summary']) + } + if ($i['summary']) { $ret['summary'] = bbcode($i['summary'], [ 'export' => true ]); + } $ret['content'] = bbcode($i['body'], [ 'export' => true ]); $ret['source'] = [ 'content' => $i['body'], 'summary' => $i['summary'], 'mediaType' => 'text/bbcode' ]; } $actor = self::encode_person($i['author'],false); - if($actor) + if ($actor) { $ret['actor'] = $actor; - else + } + 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; } - if($activitypub && $has_images && $ret['type'] === 'Note') { + if ($activitypub && $has_images && $ret['type'] === 'Note') { $img = []; - foreach($images as $match) { + foreach ($images as $match) { $img[] = [ 'type' => 'Image', 'url' => $match[2] ]; } - if(! $ret['attachment']) + if (! $ret['attachment']) { $ret['attachment'] = []; - + } $ret['attachment'] = array_merge($img,$ret['attachment']); } - if($activitypub) { - if($i['item_private']) { - if($reply) { - if($i['author_xchan'] === $i['owner_xchan']) { + if ($activitypub) { + if ($i['item_private']) { + if ($reply) { + if ($i['author_xchan'] === $i['owner_xchan']) { $m = self::map_acl($i,(($i['allow_gid']) ? false : true)); $ret['tag'] = (($ret['tag']) ? array_merge($ret['tag'],$m) : $m); } else { - if($is_directmessage) { + if ($is_directmessage) { $m = [ 'type' => 'Mention', 'href' => $reply_url, @@ -386,7 +399,7 @@ class Activity { } } else { - if($reply) { + if ($reply) { $ret['to'] = [ z_root() . '/followers/' . substr($i['author']['xchan_addr'],0,strpos($i['author']['xchan_addr'],'@')) ]; $ret['cc'] = [ ACTIVITY_PUBLIC_INBOX ]; } @@ -396,8 +409,8 @@ class Activity { } } $mentions = self::map_mentions($i); - if(count($mentions) > 0) { - if(! $ret['to']) { + if (count($mentions) > 0) { + if (! $ret['to']) { $ret['to'] = $mentions; } else { @@ -414,9 +427,9 @@ class Activity { $ret = []; - if($item['tag'] && is_array($item['tag'])) { - foreach($item['tag'] as $t) { - if(! array_key_exists('type',$t)) + if ($item['tag'] && is_array($item['tag'])) { + foreach ($item['tag'] as $t) { + if (! array_key_exists('type',$t)) $t['type'] = 'Hashtag'; switch($t['type']) { @@ -430,7 +443,7 @@ class Activity { case 'Mention': $mention_type = substr($t['name'],0,1); - if($mention_type === '!') { + if ($mention_type === '!') { $ret[] = [ 'ttype' => TERM_FORUM, 'url' => $t['href'], 'term' => escape_tags(substr($t['name'],1)) ]; } else { @@ -456,18 +469,18 @@ class Activity { $ret = []; - if($item['term']) { - foreach($item['term'] as $t) { + if ($item['term']) { + foreach ($item['term'] as $t) { switch($t['ttype']) { case TERM_HASHTAG: // An id is required so if we don't have a url in the taxonomy, ignore it and keep going. - if($t['url']) { + if ($t['url']) { $ret[] = [ 'id' => $t['url'], 'name' => '#' . $t['term'] ]; } break; case TERM_PCATEGORY: - if($t['url'] && $t['term']) { + if ($t['url'] && $t['term']) { $ret[] = [ 'type' => 'topicalCollection', 'href' => $t['url'], 'name' => $t['term'] ]; } break; @@ -502,21 +515,21 @@ class Activity { $r = false; - if($url) { + if ($url) { $r = q("select xchan_addr from xchan where ( xchan_url = '%s' OR xchan_hash = '%s' ) limit 1", dbesc($url), dbesc($url) ); - if($r) { + if ($r) { return $r[0]['xchan_addr']; } } - if($name) { + if ($name) { $r = q("select xchan_addr from xchan where xchan_name = '%s' limit 1", dbesc($name) ); - if($r) { + if ($r) { return $r[0]['xchan_addr']; } @@ -536,7 +549,7 @@ class Activity { dbesc($url) ); - if($r) { + if ($r) { return $r[0]['hubloc_id_url']; } @@ -548,11 +561,11 @@ class Activity { $ret = []; - if($item['attach']) { + 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')) { + if ($atts) { + foreach ($atts as $att) { + if (strpos($att['type'],'image')) { $ret[] = [ 'type' => 'Image', 'url' => $att['href'] ]; } else { @@ -570,18 +583,18 @@ class Activity { $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; } } @@ -596,28 +609,28 @@ class Activity { $ret = []; $reply = false; - if(intval($i['item_deleted'])) { + if (intval($i['item_deleted'])) { $ret['type'] = 'Delete'; $ret['id'] = str_replace('/item/','/activity/',$i['mid']) . '#delete'; $actor = self::encode_person($i['author'],false); - if($actor) + if ($actor) $ret['actor'] = $actor; else return []; - if($i['obj']) { - if(! is_array($i['obj'])) { + if ($i['obj']) { + if (! is_array($i['obj'])) { $i['obj'] = json_decode($i['obj'],true); } $obj = self::encode_object($i['obj']); - if($obj) + if ($obj) $ret['object'] = $obj; else return []; } else { $obj = self::encode_item($i,$activitypub); - if($obj) + if ($obj) $ret['object'] = $obj; else return []; @@ -630,25 +643,25 @@ class Activity { $ret['type'] = self::activity_mapper($i['verb']); - if(strpos($i['mid'],z_root() . '/item/') !== false) { + if (strpos($i['mid'],z_root() . '/item/') !== false) { $ret['id'] = str_replace('/item/','/activity/',$i['mid']); } - elseif(strpos($i['mid'],z_root() . '/event/') !== false) { + elseif (strpos($i['mid'],z_root() . '/event/') !== false) { $ret['id'] = str_replace('/event/','/activity/',$i['mid']); } else { $ret['id'] = $i['mid']; } - if($i['title']) { + if ($i['title']) { $ret['name'] = $i['title']; } - if($i['summary']) { + if ($i['summary']) { $ret['summary'] = bbcode($i['summary'], [ 'export' => true ]); } - if($ret['type'] === 'Announce') { + if ($ret['type'] === 'Announce') { $tmp = $i['body']; $ret['content'] = bbcode($tmp, [ 'export' => true ]); $ret['source'] = [ @@ -658,41 +671,41 @@ class Activity { } $ret['published'] = datetime_convert('UTC','UTC',$i['created'],ATOM_TIME); - if($i['created'] !== $i['edited']) + if ($i['created'] !== $i['edited']) $ret['updated'] = datetime_convert('UTC','UTC',$i['edited'],ATOM_TIME); - if($i['app']) { - $ret['instrument'] = [ 'type' => 'Service', 'name' => $i['app'] ]; + if ($i['app']) { + $ret['generator'] = [ 'type' => 'Application', 'name' => $i['app'] ]; } - if($i['location'] || $i['coord']) { + if ($i['location'] || $i['coord']) { $ret['location'] = [ 'type' => 'Place' ]; - if($i['location']) { + if ($i['location']) { $ret['location']['name'] = $i['location']; } - if($i['coord']) { + if ($i['coord']) { $l = explode(' ',$i['coord']); $ret['location']['latitude'] = $l[0]; $ret['location']['longitude'] = $l[1]; } } - if($i['mid'] != $i['parent_mid']) { + if ($i['mid'] != $i['parent_mid']) { $ret['inReplyTo'] = $i['thr_parent']; $cnv = get_iconfig($i['parent'],'ostatus','conversation'); - if(! $cnv) { + if (! $cnv) { $cnv = $ret['parent_mid']; } $reply = true; - if($i['item_private']) { + 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) { + if ($d) { $is_directmessage = false; $recips = get_iconfig($i['parent'], 'activitypub', 'recips'); - if($recips && is_array($recips) and array_key_exists('to', $recips) && is_array($recips['to']) + if ($recips && is_array($recips) and array_key_exists('to', $recips) && is_array($recips['to']) && in_array($i['author']['xchan_url'], $recips['to'])) { $reply_url = $d[0]['xchan_url']; $is_directmessage = true; @@ -707,58 +720,58 @@ class Activity { } - if(! $cnv) { + if (! $cnv) { $cnv = get_iconfig($i,'ostatus','conversation'); } - if($cnv) { + if ($cnv) { $ret['conversation'] = $cnv; } $ret['inheritPrivacy'] = true; $actor = self::encode_person($i['author'],false); - if($actor) + if ($actor) $ret['actor'] = $actor; else return []; - if($i['obj']) { - if(! is_array($i['obj'])) { + if ($i['obj']) { + if (! is_array($i['obj'])) { $i['obj'] = json_decode($i['obj'],true); } $obj = self::encode_object($i['obj']); - if($obj) + if ($obj) $ret['object'] = $obj; else return []; } else { $obj = self::encode_item($i,$activitypub); - if($obj) + if ($obj) $ret['object'] = $obj; else return []; } - if($i['target']) { - if(! is_array($i['target'])) { + 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; } } - if($activitypub) { - if($i['item_private']) { - if($reply) { - if($i['author_xchan'] === $i['owner_xchan']) { + if ($activitypub) { + if ($i['item_private']) { + if ($reply) { + if ($i['author_xchan'] === $i['owner_xchan']) { $m = self::map_acl($i,(($i['allow_gid']) ? false : true)); $ret['tag'] = (($ret['tag']) ? array_merge($ret['tag'],$m) : $m); } else { - if($is_directmessage) { + if ($is_directmessage) { $m = [ 'type' => 'Mention', 'href' => $reply_url, @@ -778,7 +791,7 @@ class Activity { } } else { - if($reply) { + if ($reply) { $ret['to'] = [ z_root() . '/followers/' . substr($i['author']['xchan_addr'],0,strpos($i['author']['xchan_addr'],'@')) ]; $ret['cc'] = [ ACTIVITY_PUBLIC_INBOX ]; } @@ -788,8 +801,8 @@ class Activity { } } $mentions = self::map_mentions($i); - if(count($mentions) > 0) { - if(! $ret['to']) { + if (count($mentions) > 0) { + if (! $ret['to']) { $ret['to'] = $mentions; } else { @@ -803,14 +816,14 @@ class Activity { } static function map_mentions($i) { - if(! $i['term']) { + if (! $i['term']) { return []; } $list = []; foreach ($i['term'] as $t) { - if($t['ttype'] == TERM_MENTION) { + if ($t['ttype'] == TERM_MENTION) { $url = self::lookup_term_url($t['url']); $list[] = (($url) ? $url : $t['url']); } @@ -825,9 +838,9 @@ class Activity { $list = []; $x = collect_recipients($i,$private); - if($x) { + if ($x) { stringify_array_elms($x); - if(! $x) + if (! $x) return; $strict = (($mentions) ? true : get_config('activitypub','compliance')); @@ -836,9 +849,9 @@ class Activity { $details = q("select xchan_url, xchan_addr, xchan_name from xchan where xchan_hash in (" . implode(',',$x) . ") $sql_extra"); - if($details) { - foreach($details as $d) { - if($mentions) { + if ($details) { + foreach ($details as $d) { + if ($mentions) { $list[] = [ 'type' => 'Mention', 'href' => $d['xchan_url'], 'name' => '@' . (($d['xchan_addr']) ? $d['xchan_addr'] : $d['xchan_name']) ]; } else { @@ -857,10 +870,10 @@ class Activity { $ret = []; - if(! $p['xchan_url']) + if (! $p['xchan_url']) return $ret; - if(! $extended) { + if (! $extended) { return $p['xchan_url']; } @@ -868,15 +881,15 @@ class Activity { $ret['type'] = 'Person'; - if($c) { + if ($c) { $role = PConfig::Get($c['channel_id'],'system','permissions_role'); - if(strpos($role,'forum') !== false) { + if (strpos($role,'forum') !== false) { $ret['type'] = 'Group'; } } $ret['id'] = ((strpos($p['xchan_hash'],'http') === 0) ? $p['xchan_hash'] : $p['xchan_url']); - if($p['xchan_addr'] && strpos($p['xchan_addr'],'@')) + 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); @@ -902,9 +915,9 @@ class Activity { ]; - if($activitypub) { + if ($activitypub) { - if($c) { + if ($c) { $ret['inbox'] = z_root() . '/inbox/' . $c['channel_address']; $ret['outbox'] = z_root() . '/outbox/' . $c['channel_address']; $ret['followers'] = z_root() . '/followers/' . $c['channel_address']; @@ -918,7 +931,7 @@ class Activity { ]; $cp = get_cover_photo($c['channel_id'],'array'); - if($cp) { + if ($cp) { $ret['image'] = [ 'type' => 'Image', 'mediaType' => $cp['type'], @@ -928,13 +941,13 @@ class Activity { $dp = q("select about from profile where uid = %d and is_default = 1", intval($c['channel_id']) ); - if($dp && $dp[0]['about']) { + if ($dp && $dp[0]['about']) { $ret['summary'] = bbcode($dp[0]['about'],['export' => true ]); } } else { $collections = get_xconfig($p['xchan_hash'],'activitypub','collections',[]); - if($collections) { + if ($collections) { $ret = array_merge($ret,$collections); } else { @@ -946,7 +959,12 @@ class Activity { else { $ret['inbox'] = z_root() . '/nullbox'; - $ret['outbox'] = z_root() . '/nullbox'; + if ($c) { + $ret['outbox'] = z_root() . '/outbox/' . $c['channel_address']; + } + else { + $ret['outbox'] = z_root() . '/nullbox'; + } $ret['publicKey'] = [ 'id' => $p['xchan_url'] . '/public_key_pem', 'owner' => $p['xchan_url'], @@ -966,7 +984,7 @@ class Activity { static function activity_mapper($verb) { - if(strpos($verb,'/') === false) { + if (strpos($verb,'/') === false) { return $verb; } @@ -983,18 +1001,18 @@ class Activity { ]; - 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 'Create'; - if(strpos($verb,ACTIVITY_MOOD) !== false) + if (strpos($verb,ACTIVITY_MOOD) !== 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 @@ -1002,13 +1020,13 @@ class Activity { logger('Unmapped activity: ' . $verb); return 'Create'; - // return false; -} + // return false; + } static function activity_obj_mapper($obj) { - if(strpos($obj,'/') === false) { + if (strpos($obj,'/') === false) { return $obj; } @@ -1030,7 +1048,7 @@ class Activity { ]; - if(array_key_exists($obj,$objs)) { + if (array_key_exists($obj,$objs)) { return $objs[$obj]; } @@ -1056,14 +1074,14 @@ class Activity { $person_obj = $act->actor; - if($act->type === 'Follow') { + if ($act->type === 'Follow') { $their_follow_id = $act->id; } - elseif($act->type === 'Accept') { + 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 @@ -1075,7 +1093,7 @@ class Activity { dbesc($person_obj['id']), intval($channel['channel_id']) ); - if($r) { + if ($r) { $contact = $r[0]; } } @@ -1085,14 +1103,14 @@ class Activity { // add tag_deliver permissions to remote groups - if(is_array($person_obj) && $person_obj['type'] === 'Group') { + if (is_array($person_obj) && $person_obj['type'] === 'Group') { $p['tag_deliver'] = 1; } $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. @@ -1102,7 +1120,7 @@ class Activity { // A second Follow request, but we haven't approved the first one - if($contact['abook_pending']) { + if ($contact['abook_pending']) { return; } @@ -1121,8 +1139,8 @@ class Activity { $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(); @@ -1143,7 +1161,7 @@ class Activity { // 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; } @@ -1158,7 +1176,7 @@ class Activity { dbesc($person_obj['id']) ); - if(! $r) { + if (! $r) { logger('xchan not found for ' . $person_obj['id']); return; } @@ -1185,21 +1203,21 @@ class Activity { ] ); - if($my_perms) + if ($my_perms) AbConfig::Set($channel['channel_id'],$ret['xchan_hash'],'system','my_perms',$my_perms); - if($their_perms) + if ($their_perms) AbConfig::Set($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) { + if ($new_connection) { Enotify::submit( [ 'type' => NOTIFY_INTRO, @@ -1209,7 +1227,7 @@ class Activity { ] ); - 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'] ]); // Send back a Follow notification to them @@ -1217,8 +1235,8 @@ class Activity { } $clone = array(); - foreach($new_connection[0] as $k => $v) { - if(strpos($k,'abook_') === 0) { + foreach ($new_connection[0] as $k => $v) { + if (strpos($k,'abook_') === 0) { $clone[$k] = $v; } } @@ -1228,7 +1246,7 @@ class Activity { $abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']); - if($abconfig) + if ($abconfig) $clone['abconfig'] = $abconfig; Libsync::build_sync_packet($channel['channel_id'], [ 'abook' => array($clone) ] ); @@ -1238,9 +1256,9 @@ class Activity { /* If there is a default group for this channel and permissions are automatic, add this member to it */ - if($channel['channel_default_group'] && $automatic) { + if ($channel['channel_default_group'] && $automatic) { $g = AccessList::rec_byhash($channel['channel_id'],$channel['channel_default_group']); - if($g) + if ($g) AccessList::member_add($channel['channel_id'],'',$ret['xchan_hash'],$g['id']); } @@ -1260,13 +1278,13 @@ 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); } @@ -1280,7 +1298,7 @@ class Activity { static function actor_store($url,$person_obj) { - if(! is_array($person_obj)) + if (! is_array($person_obj)) return; // logger('person_obj: ' . print_r($person_obj,true)); @@ -1288,8 +1306,8 @@ class Activity { // We may have been passed a cached entry. If it is, and the cache duration has expired // fetch a fresh copy before continuing. - if(array_key_exists('cached',$person_obj)) { - if(array_key_exists('updated',$person_obj) && datetime_convert('UTC','UTC',$person_obj['updated']) < datetime_convert('UTC','UTC','now - ' . self::$ACTOR_CACHE_DAYS . ' days')) { + if (array_key_exists('cached',$person_obj)) { + if (array_key_exists('updated',$person_obj) && datetime_convert('UTC','UTC',$person_obj['updated']) < datetime_convert('UTC','UTC','now - ' . self::$ACTOR_CACHE_DAYS . ' days')) { $person_obj = self::fetch($url); } else { @@ -1299,25 +1317,25 @@ class Activity { $url = $person_obj['id']; - if(! $url) { + if (! $url) { return; } $name = $person_obj['name']; - if(! $name) + if (! $name) $name = $person_obj['preferredUsername']; - if(! $name) + if (! $name) $name = t('Unknown'); $username = $person_obj['preferredUsername']; $h = parse_url($url); - if($h && $h['host']) { + if ($h && $h['host']) { $username .= '@' . $h['host']; } - 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']; @@ -1325,7 +1343,7 @@ class Activity { else $icon = $person_obj['icon']; } - if(! $icon) { + if (! $icon) { $icon = z_root() . '/' . get_default_profile_photo(); } @@ -1333,8 +1351,8 @@ class Activity { $links = false; $profile = false; - if(is_array($person_obj['url'])) { - if(! array_key_exists(0,$person_obj['url'])) { + if (is_array($person_obj['url'])) { + if (! array_key_exists(0,$person_obj['url'])) { $links = [ $person_obj['url'] ]; } else { @@ -1342,21 +1360,21 @@ class Activity { } } - if($links) { - foreach($links as $link) { - if(array_key_exists('mediaType',$link) && $link['mediaType'] === 'text/html') { + if ($links) { + foreach ($links as $link) { + if (array_key_exists('mediaType',$link) && $link['mediaType'] === 'text/html') { $profile = $link['href']; } } - if(! $profile) { + if (! $profile) { $profile = $links[0]['href']; } } - elseif(isset($person_obj['url']) && is_string($person_obj['url'])) { + elseif (isset($person_obj['url']) && is_string($person_obj['url'])) { $profile = $person_obj['url']; } - if(! $profile) { + if (! $profile) { $profile = $url; } @@ -1364,30 +1382,29 @@ class Activity { // either an invalid identity or a cached entry of some kind which didn't get caught above - if((! $inbox) || strpos($inbox,z_root()) !== false) { + if ((! $inbox) || strpos($inbox,z_root()) !== false) { return; } $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'] && is_array($person_obj['endpoints']) && $person_obj['endpoints']['sharedInbox']) + if ($person_obj['endpoints'] && is_array($person_obj['endpoints']) && $person_obj['endpoints']['sharedInbox']) $collections['sharedInbox'] = $person_obj['endpoints']['sharedInbox']; } - if(isset($person_obj['publicKey']['publicKeyPem'])) { - //if(array_key_exists('publicKey',$person_obj) && array_key_exists('publicKeyPem',$person_obj['publicKey'])) { - if($person_obj['id'] === $person_obj['publicKey']['owner']) { + if (isset($person_obj['publicKey']['publicKeyPem'])) { + if ($person_obj['id'] === $person_obj['publicKey']['owner']) { $pubkey = $person_obj['publicKey']['publicKeyPem']; - if(strstr($pubkey,'RSA ')) { + if (strstr($pubkey,'RSA ')) { $pubkey = Keyutils::rsatopem($pubkey); } } @@ -1396,7 +1413,7 @@ 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( [ @@ -1422,7 +1439,7 @@ class Activity { // Record exists. Cache existing records for a set number of days // then refetch to catch updated profile photos, names, etc. - if($r[0]['xchan_name_date'] >= datetime_convert('UTC','UTC','now - ' . self::$ACTOR_CACHE_DAYS . ' days')) { + if ($r[0]['xchan_name_date'] >= datetime_convert('UTC','UTC','now - ' . self::$ACTOR_CACHE_DAYS . ' days')) { return; } @@ -1435,7 +1452,7 @@ class Activity { dbesc($url) ); - if(strpos($username,'@') && ($r[0]['xchan_addr'] !== $username)) { + if (strpos($username,'@') && ($r[0]['xchan_addr'] !== $username)) { $r = q("update xchan set xchan_addr = '%s' where xchan_hash = '%s'", dbesc($username), dbesc($url) @@ -1443,7 +1460,7 @@ class Activity { } } - if($collections) { + if ($collections) { set_xconfig($url,'activitypub','collections',$collections); } @@ -1453,12 +1470,12 @@ class Activity { $m = parse_url($url); - if($m) { + if ($m) { $hostname = $m['host']; $baseurl = $m['scheme'] . '://' . $m['host'] . (($m['port']) ? ':' . $m['port'] : ''); } - if(! $h) { + if (! $h) { $r = hubloc_store_lowlevel( [ 'hubloc_guid' => $url, @@ -1475,13 +1492,13 @@ class Activity { ); } else { - if(strpos($username,'@') && ($h[0]['hubloc_addr'] !== $username)) { + if (strpos($username,'@') && ($h[0]['hubloc_addr'] !== $username)) { $r = q("update hubloc set hubloc_addr = '%s' where hubloc_hash = '%s'", dbesc($username), dbesc($url) ); } - if($inbox !== $h[0]['hubloc_callback']) { + if ($inbox !== $h[0]['hubloc_callback']) { $r = q("update hubloc set hubloc_callback = '%s' where hubloc_hash = '%s'", dbesc($inbox), dbesc($url) @@ -1493,7 +1510,7 @@ class Activity { ); } - if(! $icon) + if (! $icon) $icon = z_root() . '/' . get_default_profile_photo(300); Master::Summon( [ 'Xchan_photo', bin2hex($icon), bin2hex($url) ] ); @@ -1506,14 +1523,14 @@ class Activity { $channel['channel_id'] ); - if(! $r) { + if (! $r) { return; } - if(in_array($observer,[ $r[0]['author_xchan'], $r[0]['owner_xchan'] ])) { + if (in_array($observer,[ $r[0]['author_xchan'], $r[0]['owner_xchan'] ])) { drop_item($r[0]['id'],false); } - elseif(in_array($act->actor['id'],[ $r[0]['author_xchan'], $r[0]['owner_xchan'] ])) { + elseif (in_array($act->actor['id'],[ $r[0]['author_xchan'], $r[0]['owner_xchan'] ])) { drop_item($r[0]['id'],false); } @@ -1522,7 +1539,7 @@ class Activity { static function create_action($channel,$observer_hash,$act) { - if(in_array($act->obj['type'], [ 'Note', 'Article', 'Video', 'Audio', 'Image' ])) { + if (in_array($act->obj['type'], [ 'Note', 'Article', 'Video', 'Audio', 'Image' ])) { self::create_note($channel,$observer_hash,$act); } @@ -1531,7 +1548,7 @@ class Activity { static function announce_action($channel,$observer_hash,$act) { - if(in_array($act->type, [ 'Announce' ])) { + if (in_array($act->type, [ 'Announce' ])) { self::announce_note($channel,$observer_hash,$act); } @@ -1540,7 +1557,7 @@ class Activity { static function like_action($channel,$observer_hash,$act) { - if(in_array($act->obj['type'], [ 'Note', 'Article', 'Video', 'Audio', 'Image' ])) { + if (in_array($act->obj['type'], [ 'Note', 'Article', 'Video', 'Audio', 'Image' ])) { self::like_note($channel,$observer_hash,$act); } @@ -1550,7 +1567,7 @@ class Activity { // sort function width decreasing static function vid_sort($a,$b) { - if($a['width'] === $b['width']) + if ($a['width'] === $b['width']) return 0; return (($a['width'] > $b['width']) ? -1 : 1); } @@ -1566,7 +1583,7 @@ class Activity { $is_sys_channel = is_sys_channel($channel['channel_id']); $parent = ((array_key_exists('inReplyTo',$act->obj)) ? urldecode($act->obj['inReplyTo']) : ''); - if($parent) { + if ($parent) { $r = q("select * from item where uid = %d and ( mid = '%s' or mid = '%s' ) limit 1", intval($channel['channel_id']), @@ -1574,13 +1591,13 @@ 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; } @@ -1592,7 +1609,7 @@ class Activity { } 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; } @@ -1604,11 +1621,11 @@ class Activity { intval($channel['channel_id']) ); - if(is_array($act->obj)) { + if (is_array($act->obj)) { $content = self::get_content($act->obj); } - if(! $content) { + if (! $content) { logger('no content'); return; } @@ -1619,27 +1636,27 @@ class Activity { $s['plink'] = urldecode($act->obj['id']); - if($act->data['published']) { + if ($act->data['published']) { $s['created'] = datetime_convert('UTC','UTC',$act->data['published']); } - elseif($act->obj['published']) { + elseif ($act->obj['published']) { $s['created'] = datetime_convert('UTC','UTC',$act->obj['published']); } - if($act->data['updated']) { + if ($act->data['updated']) { $s['edited'] = datetime_convert('UTC','UTC',$act->data['updated']); } - elseif($act->obj['updated']) { + elseif ($act->obj['updated']) { $s['edited'] = datetime_convert('UTC','UTC',$act->obj['updated']); } - 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']; @@ -1649,43 +1666,43 @@ class Activity { $s['verb'] = ACTIVITY_POST; $s['obj_type'] = ACTIVITY_OBJ_NOTE; - $instrument = $act->get_property_obj('instrument'); - if(! $instrument) - $instrument = $act->get_property_obj('instrument',$act->obj); + $generator = $act->get_property_obj('generator'); + if (! $generator) + $generator = $act->get_property_obj('generator',$act->obj); - if($instrument && array_key_exists('type',$instrument) - && $instrument['type'] === 'Service' && array_key_exists('name',$instrument)) { - $s['app'] = escape_tags($instrument['name']); + 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(! 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(! post_is_importable($channel['channel_id'],$s,$abook[0])) { + if (! post_is_importable($channel['channel_id'],$s,$abook[0])) { logger('post is filtered'); return; } - if($act->obj['conversation']) { + 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']) { + if ($act->obj['type'] === 'Note' && $s['attach']) { $s['body'] .= self::bb_attach($s['attach'],$s['body']); } @@ -1693,7 +1710,7 @@ class Activity { // 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', @@ -1702,20 +1719,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) { + if ($mps) { usort($mps,[ __CLASS__, 'vid_sort' ]); - foreach($mps as $m) { - if(intval($m['width']) < 500) { + foreach ($mps as $m) { + if (intval($m['width']) < 500) { $s['body'] .= "\n\n" . '[video]' . $m['href'] . '[/video]'; break; } @@ -1723,11 +1740,11 @@ 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; set_iconfig($s,'activitypub','recips',$act->raw_recips); - if($parent) { + if ($parent) { set_iconfig($s,'activitypub','rawmsg',$act->raw,1); } @@ -1737,8 +1754,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 { @@ -1749,16 +1766,16 @@ 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'])); } $r = q("select * from item where id = %d limit 1", intval($x['item_id']) ); - if($r) { + if ($r) { send_status_notifications($x['item_id'],$r[0]); } } @@ -1794,7 +1811,7 @@ class Activity { dbesc($id) ); - if($x) { + if ($x) { return sprintf('@[zrl=%s]%s[/zrl]',$x[0]['xchan_url'],$x[0]['xchan_name']); } return '@{' . $id . '}'; @@ -1808,7 +1825,7 @@ class Activity { $s = []; - if(is_array($act->obj)) { + if (is_array($act->obj)) { $content = self::get_content($act->obj); } @@ -1821,21 +1838,28 @@ class Activity { $s['mid'] = $act->obj['id']; $s['parent_mid'] = $act->parent_id; - if($act->data['published']) { + if ($act->data['published']) { $s['created'] = datetime_convert('UTC','UTC',$act->data['published']); } - elseif($act->obj['published']) { + elseif ($act->obj['published']) { $s['created'] = datetime_convert('UTC','UTC',$act->obj['published']); } - if($act->data['updated']) { + if ($act->data['updated']) { $s['edited'] = datetime_convert('UTC','UTC',$act->data['updated']); } - elseif($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']); + } + elseif ($act->obj['expires']) { + $s['expires'] = datetime_convert('UTC','UTC',$act->obj['expires']); + } - if(in_array($act->type, [ 'Like', 'Dislike', 'Flag', 'Block', 'Announce', 'Accept', 'Reject', 'TentativeAccept', 'emojiReaction' ])) { + if (in_array($act->type, [ 'Like', 'Dislike', 'Flag', 'Block', 'Announce', 'Accept', 'Reject', + 'TentativeAccept', 'TentativeReject', 'emojiReaction' ])) { $response_activity = true; @@ -1844,11 +1868,11 @@ class Activity { // over-ride the object timestamp with the activity - if($act->data['published']) { + if ($act->data['published']) { $s['created'] = datetime_convert('UTC','UTC',$act->data['published']); } - if($act->data['updated']) { + if ($act->data['updated']) { $s['edited'] = datetime_convert('UTC','UTC',$act->data['updated']); } @@ -1858,22 +1882,25 @@ class Activity { $mention = self::get_actor_bbmention($obj_actor['id']); - if($act->type === 'Like') { + if ($act->type === 'Like') { $content['content'] = sprintf( t('Likes %1$s\'s %2$s'),$mention,$act->obj['type']) . EOL . EOL . $content['content']; } - if($act->type === 'Dislike') { + if ($act->type === 'Dislike') { $content['content'] = sprintf( t('Doesn\'t like %1$s\'s %2$s'),$mention,$act->obj['type']) . EOL . EOL . $content['content']; } - if($act->type === 'Accept' && $act->obj['type'] === 'Event' ) { + if ($act->type === 'Accept' && $act->obj['type'] === 'Event' ) { $content['content'] = sprintf( t('Will attend %1$s\'s %2$s'),$mention,$act->obj['type']) . EOL . EOL . $content['content']; } - if($act->type === 'Reject' && $act->obj['type'] === 'Event' ) { + if ($act->type === 'Reject' && $act->obj['type'] === 'Event' ) { $content['content'] = sprintf( t('Will not attend %1$s\'s %2$s'),$mention,$act->obj['type']) . EOL . EOL . $content['content']; } - if($act->type === 'TentativeAccept' && $act->obj['type'] === 'Event' ) { + if ($act->type === 'TentativeAccept' && $act->obj['type'] === 'Event' ) { $content['content'] = sprintf( t('May attend %1$s\'s %2$s'),$mention,$act->obj['type']) . EOL . EOL . $content['content']; } - if($act->type === 'Announce') { + if ($act->type === 'TentativeReject' && $act->obj['type'] === 'Event' ) { + $content['content'] = sprintf( t('May not attend %1$s\'s %2$s'),$mention,$act->obj['type']) . 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 === 'emojiReaction') { @@ -1881,17 +1908,27 @@ class Activity { } } - 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')); - if($act->type === 'Tombstone' || ($act->type === 'Create' && $act->obj['type'] === 'Tombstone')) { + // handle some of the more widely used of the numerous and varied ways of deleting something + + if ($act->type === 'Tombstone') { + $s['item_deleted'] = 1; + } + + if ($act->type === 'Create' && $act->obj['type'] === 'Tombstone') { + $s['item_deleted'] = 1; + } + + if ($act->type === 'Delete' && $act->obj['type'] === 'Tombstone') { $s['item_deleted'] = 1; } @@ -1899,29 +1936,29 @@ class Activity { $s['obj_type'] = self::activity_obj_mapper($act->obj['type']); $s['obj'] = $act->obj; - if(is_array($obj) && array_path_exists('actor/id',$s['obj'])) { + if (is_array($obj) && array_path_exists('actor/id',$s['obj'])) { $s['obj']['actor'] = $s['obj']['actor']['id']; } // @todo add target if present - $instrument = $act->get_property_obj('instrument'); - if((! $instrument) && (! $response_activity)) { - $instrument = $act->get_property_obj('instrument',$act->obj); + $generator = $act->get_property_obj('generator'); + if ((! $generator) && (! $response_activity)) { + $generator = $act->get_property_obj('generator',$act->obj); } - if($instrument && array_key_exists('type',$instrument) - && $instrument['type'] === 'Service' && array_key_exists('name',$instrument)) { - $s['app'] = escape_tags($instrument['name']); + 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) { + 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']); @@ -1930,12 +1967,12 @@ class Activity { } $a = self::decode_attachment($act->obj); - if($a) { + if ($a) { $s['attach'] = $a; } } - if($act->obj['type'] === 'Note' && $s['attach']) { + if ($act->obj['type'] === 'Note' && $s['attach']) { $s['body'] .= self::bb_attach($s['attach'],$s['body']); } @@ -1944,8 +1981,8 @@ class Activity { // 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', @@ -1956,27 +1993,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'] ]; } - 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; @@ -1984,22 +2021,22 @@ class Activity { } } } - if($mps) { + 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'])) { + 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', @@ -2009,49 +2046,49 @@ 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'] ]; } - 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' && strpos($s['body'],'zrl=') === false) { + if ($act->obj['type'] === 'Image' && strpos($s['body'],'zrl=') === false) { $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'] ]; } - foreach($ptr as $vurl) { - if(strpos($s['body'],$vurl['href']) === false) { + foreach ($ptr as $vurl) { + if (strpos($s['body'],$vurl['href']) === false) { $s['body'] .= "\n\n" . '[zmg]' . $vurl['href'] . '[/zmg]'; break; } } } - 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'] .= "\n\n" . '[zmg]' . $act->obj['url'] . '[/zmg]'; } } @@ -2059,36 +2096,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'] ]; } - 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 { @@ -2101,40 +2138,40 @@ 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'] ]; } - 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']; } - 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); - if($parent) { + if ($parent) { set_iconfig($s,'activitypub','rawmsg',$act->raw,1); } @@ -2155,7 +2192,7 @@ class Activity { $pubstream = ((is_array($act->obj) && array_key_exists('to', $act->obj) && is_array($act->obj['to']) && in_array(ACTIVITY_PUBLIC_INBOX, $act->obj['to'])) ? true : false); - if($item['parent_mid'] && $item['parent_mid'] !== $item['mid']) { + if ($item['parent_mid'] && $item['parent_mid'] !== $item['mid']) { $is_child_node = true; } @@ -2175,9 +2212,9 @@ class Activity { $allowed = true; } - if(intval($channel['channel_system'])) { + if (intval($channel['channel_system'])) { - if(! check_pubstream_channelallowed($observer_hash)) { + if (! check_pubstream_channelallowed($observer_hash)) { $allowed = false; } // don't allow pubstream posts if the sender even has a clone on a pubstream blacklisted site @@ -2185,9 +2222,9 @@ class Activity { $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'])) { + if ($h) { + foreach ($h as $hub) { + if (! check_pubstream_siteallowed($hub['hubloc_url'])) { $allowed = false; break; } @@ -2195,15 +2232,15 @@ class Activity { } } - if(! $allowed) { + if (! $allowed) { logger('no permission'); return; } - if(is_array($act->obj)) { + if (is_array($act->obj)) { $content = self::get_content($act->obj); } - if(! $content) { + if (! $content) { logger('no content'); return; } @@ -2218,7 +2255,7 @@ class Activity { $item['author_xchan'] = self::find_best_identity($item['author_xchan']); $item['owner_xchan'] = self::find_best_identity($item['owner_xchan']); - if(! ( $item['author_xchan'] && $item['owner_xchan'])) { + if (! ( $item['author_xchan'] && $item['owner_xchan'])) { logger('owner or author missing.'); return; } @@ -2226,8 +2263,8 @@ class Activity { - 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; } @@ -2239,12 +2276,12 @@ class Activity { ); - if(! post_is_importable($channel['channel_id'],$item,$abook[0])) { + if (! post_is_importable($channel['channel_id'],$item,$abook[0])) { logger('post is filtered'); return; } - if($act->obj['conversation']) { + if ($act->obj['conversation']) { set_iconfig($item,'ostatus','conversation',$act->obj['conversation'],1); } @@ -2254,10 +2291,10 @@ class Activity { set_iconfig($item,'activitypub','recips',$act->raw_recips); - if(! (isset($act->data['inheritPrivacy']) && $act->data['inheritPrivacy'])) { - if($item['item_private']) { + if (! (isset($act->data['inheritPrivacy']) && $act->data['inheritPrivacy'])) { + if ($item['item_private']) { $item['item_restrict'] = $item['item_restrict'] & 1; - if($is_child_node) { + if ($is_child_node) { $item['allow_cid'] = '<' . $channel['channel_hash'] . '>'; $item['allow_gid'] = $item['deny_cid'] = $item['deny_gid'] = ''; } @@ -2265,22 +2302,22 @@ class Activity { } } - if(intval($act->sigok)) { + if (intval($act->sigok)) { $item['item_verified'] = 1; } - if($is_child_node) { + if ($is_child_node) { $p = q("select parent_mid from item where mid = '%s' and uid = %d limit 1", dbesc($item['parent_mid']), intval($item['uid']) ); - if(! $p) { + if (! $p) { $a = false; - if(PConfig::Get($channel['channel_id'],'system','hyperdrive',true) || $act->type === 'Announce') { + if (PConfig::Get($channel['channel_id'],'system','hyperdrive',true) || $act->type === 'Announce') { $a = (($fetch_parents) ? self::fetch_and_store_parents($channel,$observer_hash,$act,$item) : false); } - if($a) { + if ($a) { $p = q("select parent_mid from item where mid = '%s' and uid = %d limit 1", dbesc($item['parent_mid']), intval($item['uid']) @@ -2292,7 +2329,7 @@ class Activity { // @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','Announce' ])) { + if (in_array($act->type,[ 'Like','Dislike','Announce' ])) { return; } // turn into a top level post @@ -2300,7 +2337,7 @@ class Activity { $item['thr_parent'] = $item['mid']; } } - if($p[0]['parent_mid'] !== $item['parent_mid']) { + if ($p[0]['parent_mid'] !== $item['parent_mid']) { $item['thr_parent'] = $item['parent_mid']; } else { @@ -2313,8 +2350,8 @@ class Activity { 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); } @@ -2327,16 +2364,16 @@ class Activity { } - if(is_array($x) && $x['item_id']) { - if($is_child_node) { - if($item['owner_xchan'] === $channel['channel_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'])); } $r = q("select * from item where id = %d limit 1", intval($x['item_id']) ); - if($r) { + if ($r) { send_status_notifications($x['item_id'],$r[0]); } } @@ -2351,7 +2388,7 @@ class Activity { $r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' limit 1", dbesc($xchan) ); - if($r) { + if ($r) { return $r[0]['hubloc_hash']; } return $xchan; @@ -2369,17 +2406,17 @@ class Activity { while($current_item['parent_mid'] !== $current_item['mid']) { $n = self::fetch($current_item['parent_mid']); - if(! $n) { + if (! $n) { break; } $a = new ActivityStreams($n); logger($a->debug()); - if(! $a->is_valid()) { + if (! $a->is_valid()) { break; } - if(is_array($a->actor) && array_key_exists('id',$a->actor)) { + if (is_array($a->actor) && array_key_exists('id',$a->actor)) { Activity::actor_store($a->actor['id'],$a->actor); } @@ -2397,13 +2434,13 @@ class Activity { break; } - if(! $item) { + if (! $item) { break; } array_unshift($p,[ $a, $item ]); - if($item['parent_mid'] === $item['mid'] || count($p) > 30) { + if ($item['parent_mid'] === $item['mid'] || count($p) > 30) { break; } @@ -2411,9 +2448,9 @@ class Activity { $current_item = $item; } - if($p) { - foreach($p as $pv) { - if($pv[0]->is_valid()) { + if ($p) { + foreach ($p as $pv) { + if ($pv[0]->is_valid()) { Activity::store($channel,$observer_hash,$pv[0],$pv[1],false); } } @@ -2438,15 +2475,15 @@ 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; } - if(is_array($act->obj)) { + if (is_array($act->obj)) { $content = self::get_content($act->obj); } - if(! $content) { + if (! $content) { logger('no content'); return; } @@ -2458,10 +2495,10 @@ class Activity { $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']; @@ -2471,8 +2508,8 @@ class Activity { $s['obj_type'] = ACTIVITY_OBJ_NOTE; $s['app'] = t('ActivityPub'); - if($channel['channel_system']) { - if(! 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; } @@ -2483,22 +2520,22 @@ class Activity { intval($channel['channel_id']) ); - if(! post_is_importable($channel['channel_id'],$s,$abook[0])) { + if (! post_is_importable($channel['channel_id'],$s,$abook[0])) { logger('post is filtered'); return; } - if($act->obj['conversation']) { + 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; } @@ -2511,12 +2548,12 @@ class Activity { "' message_id='" . $act->obj['id'] . "']"; - if($content['name']) + if ($content['name']) $body .= self::bb_content($content,'name') . "\r\n"; $body .= self::bb_content($content,'content'); - if($act->obj['type'] === 'Note' && $s['attach']) { + if ($act->obj['type'] === 'Note' && $s['attach']) { $body .= self::bb_attach($s['attach'],body); } @@ -2525,7 +2562,7 @@ class Activity { $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); @@ -2534,8 +2571,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 { @@ -2547,16 +2584,16 @@ class Activity { } - 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'])); } $r = q("select * from item where id = %d limit 1", intval($x['item_id']) ); - if($r) { + if ($r) { send_status_notifications($x['item_id'],$r[0]); } } @@ -2572,12 +2609,12 @@ class Activity { $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", @@ -2586,7 +2623,7 @@ class Activity { dbesc(urldecode(basename($parent))) ); - if(! $r) { + if (! $r) { logger('parent not found.'); return; } @@ -2594,14 +2631,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 { @@ -2616,7 +2653,7 @@ class Activity { $s['uid'] = $channel['channel_id']; $s['mid'] = $act->id; - if(! $s['parent_mid']) + if (! $s['parent_mid']) $s['parent_mid'] = $s['mid']; @@ -2630,7 +2667,7 @@ class Activity { $z = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($parent_item['author_xchan']) ); - if($z) + if ($z) $item_author = $z[0]; $object = json_encode(array( @@ -2654,9 +2691,9 @@ class Activity { ), 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]'; @@ -2673,20 +2710,20 @@ class Activity { $s['obj_type'] = $objtype; $s['obj'] = $object; - if($act->obj['conversation']) { + 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); $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'])) + if (intval($parent_item['item_origin'])) Master::Summon(array('Notifier','comment-import',$result['item_id'])); sync_an_item($channel['channel_id'],$result['item_id']); } @@ -2699,19 +2736,19 @@ class Activity { $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 (strpos($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) && strpos($a['type'], 'video') === 0) { + 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) && strpos($a['type'], 'audio') === 0) { + if (self::media_not_in_body($a['href'],$body)) { $ret .= "\n\n" . '[audio]' . $a['href'] . '[/audio]'; } } @@ -2725,7 +2762,7 @@ class Activity { static function media_not_in_body($s,$body) { - if((strpos($body,']' . $s . '[/img]') === false) && + if ((strpos($body,']' . $s . '[/img]') === false) && (strpos($body,']' . $s . '[/zmg]') === false) && (strpos($body,']' . $s . '[/video]') === false) && (strpos($body,']' . $s . '[/audio]') === false)) { @@ -2741,22 +2778,22 @@ class Activity { 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']); } @@ -2773,23 +2810,23 @@ class Activity { return $content; } - if($act['type'] === 'Event') { + if ($act['type'] === 'Event') { $adjust = false; $event = []; $event['event_hash'] = $act['id']; - if(array_key_exists('startTime',$act) && strpos($act['startTime'],-1,1) === 'Z') { + 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)) { + if (array_key_exists('endTime',$act)) { $event['dtend'] = datetime_convert('UTC','UTC',$event['endTime'] . (($adjust) ? '' : 'Z')); } else { $event['nofinish'] = true; } - if(array_key_exists('eventRepeat',$act)) { + if (array_key_exists('eventRepeat',$act)) { $event['event_repeat'] = $act['eventRepeat']; } } @@ -2800,10 +2837,10 @@ class Activity { } } - if($event) { + if ($event) { $event['summary'] = html2bbcode($content['summary']); $event['description'] = html2bbcode($content['content']); - if($event['summary'] && $event['dtstart']) { + if ($event['summary'] && $event['dtstart']) { $content['event'] = $event; } } @@ -2825,10 +2862,10 @@ class Activity { $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); } } diff --git a/Zotlabs/Lib/Apps.php b/Zotlabs/Lib/Apps.php index b74de3a0e..0507b8c73 100644 --- a/Zotlabs/Lib/Apps.php +++ b/Zotlabs/Lib/Apps.php @@ -2,6 +2,7 @@ namespace Zotlabs\Lib; +use App; use Zotlabs\Lib\Libsync; /** @@ -22,27 +23,29 @@ class Apps { static public function get_system_apps($translate = true) { - $ret = array(); - if(is_dir('apps')) + $ret = []; + if (is_dir('apps')) { $files = glob('apps/*.apd'); - else + } + else { $files = glob('app/*.apd'); - if($files) { - foreach($files as $f) { + } + if ($files) { + foreach ($files as $f) { $x = self::parse_app_description($f,$translate); - if($x) { + if ($x) { $ret[] = $x; } } } $files = glob('addon/*/*.apd'); - if($files) { - foreach($files as $f) { + if ($files) { + foreach ($files as $f) { $path = explode('/',$f); $plugin = trim($path[1]); - if(plugin_is_installed($plugin)) { + if (plugin_is_installed($plugin)) { $x = self::parse_app_description($f,$translate); - if($x) { + if ($x) { $x['plugin'] = $plugin; $ret[] = $x; } @@ -66,10 +69,12 @@ class Apps { 'Channel Home', 'View Profile', 'Photos', - 'Events', +// 'Calendar', 'Directory', + 'Events', 'Search', - 'Profile Photo' + 'Profile Photo', + 'Access Lists' ]); call_hooks('get_base_apps',$x); return $x; @@ -78,8 +83,9 @@ class Apps { static public function import_system_apps() { - if(! local_channel()) + if (! local_channel()) { return; + } self::$base_apps = self::get_base_apps(); @@ -91,12 +97,12 @@ class Apps { intval(local_channel()) ); - if($apps) { - foreach($apps as $app) { + if ($apps) { + foreach ($apps as $app) { $id = self::check_install_system_app($app); // $id will be boolean true or false to install an app, or an integer id to update an existing app - if($id !== false) { + if ($id !== false) { $app['uid'] = 0; $app['guid'] = hash('whirlpool',$app['name']); $app['system'] = 1; @@ -105,22 +111,17 @@ class Apps { $id = self::check_install_personal_app($app); // $id will be boolean true or false to install an app, or an integer id to update an existing app - if($id === false) + if ($id === false) { continue; - if($id !== true) { + } + if ($id !== true) { // if we already installed this app, but it changed, preserve any categories we created - $s = EMPTY_STR; $r = q("select term from term where otype = %d and oid = %d", intval(TERM_OBJ_APP), intval($id) ); - if($r) { - foreach($r as $t) { - if($s) - $s .= ','; - $s .= $t['term']; - } - $app['categories'] = $s; + if ($r) { + $app['categories'] = array_elm_to_str($r,'term'); } } $app['uid'] = local_channel(); @@ -138,19 +139,19 @@ class Apps { */ static public function check_install_system_app($app) { - if((! is_array(self::$available_apps)) || (! count(self::$available_apps))) { + if ((! is_array(self::$available_apps)) || (! count(self::$available_apps))) { return true; } $notfound = true; - foreach(self::$available_apps as $iapp) { - if($iapp['app_id'] == hash('whirlpool',$app['name'])) { + foreach (self::$available_apps as $iapp) { + if ($iapp['app_id'] == hash('whirlpool',$app['name'])) { $notfound = false; - if(($iapp['app_version'] !== $app['version']) + if (($iapp['app_version'] !== $app['version']) || ($app['plugin'] && (! $iapp['app_plugin']))) { return intval($iapp['app_id']); } - if(($iapp['app_url'] !== $app['url']) + if (($iapp['app_url'] !== $app['url']) || ($iapp['app_photo'] !== $app['photo'])) { return intval($iapp['app_id']); } @@ -168,16 +169,16 @@ class Apps { static public function check_install_personal_app($app) { $installed = false; - foreach(self::$installed_apps as $iapp) { - if($iapp['app_id'] == hash('whirlpool',$app['name'])) { + foreach (self::$installed_apps as $iapp) { + if ($iapp['app_id'] == hash('whirlpool',$app['name'])) { $installed = true; - if(($iapp['app_version'] != $app['version']) + if (($iapp['app_version'] != $app['version']) || ($app['plugin'] && (! $iapp['app_plugin']))) { return intval($iapp['app_id']); } } } - if(! $installed && in_array($app['name'],self::$base_apps)) { + if (! $installed && in_array($app['name'],self::$base_apps)) { return true; } return false; @@ -194,103 +195,115 @@ class Apps { $ret = array(); $baseurl = z_root(); - $channel = \App::get_channel(); + $channel = App::get_channel(); $address = (($channel) ? $channel['channel_address'] : ''); //future expansion - $observer = \App::get_observer(); + $observer = App::get_observer(); $lines = @file($f); - if($lines) { - foreach($lines as $x) { - if(preg_match('/^([a-zA-Z].*?):(.*?)$/ism',$x,$matches)) { + if ($lines) { + foreach ($lines as $x) { + if (preg_match('/^([a-zA-Z].*?):(.*?)$/ism',$x,$matches)) { $ret[$matches[1]] = trim($matches[2]); } } } - if(! $ret['photo']) + if (! $ret['photo']) { $ret['photo'] = $baseurl . '/' . get_default_profile_photo(80); + } $ret['type'] = 'system'; - foreach($ret as $k => $v) { - if(strpos($v,'http') === 0) { - if(! (local_channel() && strpos($v,z_root()) === 0)) { + foreach ($ret as $k => $v) { + if (strpos($v,'http') === 0) { + if (! (local_channel() && strpos($v,z_root()) === 0)) { $ret[$k] = zid($v); } } } - if(array_key_exists('desc',$ret)) + if (array_key_exists('desc',$ret)) { $ret['desc'] = str_replace(array('\'','"'),array(''','&dquot;'),$ret['desc']); - - if(array_key_exists('target',$ret)) + } + if (array_key_exists('target',$ret)) { $ret['target'] = str_replace(array('\'','"'),array(''','&dquot;'),$ret['target']); - - if(array_key_exists('version',$ret)) + } + if (array_key_exists('version',$ret)) { $ret['version'] = str_replace(array('\'','"'),array(''','&dquot;'),$ret['version']); - - if(array_key_exists('categories',$ret)) + } + if (array_key_exists('categories',$ret)) { $ret['categories'] = str_replace(array('\'','"'),array(''','&dquot;'),$ret['categories']); - - if(array_key_exists('requires',$ret)) { + } + if (array_key_exists('requires',$ret)) { $requires = explode(',',$ret['requires']); - foreach($requires as $require) { + foreach ($requires as $require) { $require = trim(strtolower($require)); $config = false; - if(substr($require, 0, 7) == 'config:') { + if (substr($require, 0, 7) == 'config:') { $config = true; $require = ltrim($require, 'config:'); $require = explode('=', $require); } - switch($require) { + switch ($require) { case 'nologin': - if(local_channel()) + if (local_channel()) { unset($ret); + } break; case 'admin': - if(! is_site_admin()) + if (! is_site_admin()) { unset($ret); + } break; case 'local_channel': - if(! local_channel()) + if (! local_channel()) { unset($ret); + } break; case 'public_profile': - if(! is_public_profile()) + if (! is_public_profile()) { unset($ret); + } break; case 'public_stream': - if(! can_view_public_stream()) + if (! can_view_public_stream()) { unset($ret); + } break; case 'custom_role': - if(get_pconfig(local_channel(),'system','permissions_role') !== 'custom') + if (get_pconfig(local_channel(),'system','permissions_role') !== 'custom') { unset($ret); + } break; case 'observer': - if(! $observer) + if (! $observer) { unset($ret); + } break; default: - if($config) + if ($config) { $unset = ((get_config('system', $require[0]) == $require[1]) ? false : true); - else + } + else { $unset = ((local_channel() && feature_enabled(local_channel(),$require)) ? false : true); - if($unset) + } + if ($unset) { unset($ret); + } break; } } } - if($ret) { - if($translate) + if ($ret) { + if ($translate) { self::translate_system_apps($ret); + } return $ret; } return false; @@ -303,6 +316,7 @@ class Apps { 'Affinity Tool' => t('Affinity Tool'), 'Articles' => t('Articles'), 'Cards' => t('Cards'), + 'Calendar' => t('Calendar'), 'Categories' => t('Categories'), 'Admin' => t('Site Admin'), 'Content Filter' => t('Content Filter'), @@ -345,7 +359,7 @@ class Apps { 'Profile Photo' => t('Profile Photo'), 'Profile' => t('Profile'), 'Profiles' => t('Profiles'), - 'Privacy Groups' => t('Access Lists'), + 'Access Lists' => t('Access Lists'), 'Notifications' => t('Notifications'), 'Order Apps' => t('Order Apps'), 'CalDAV' => t('CalDAV'), @@ -363,14 +377,14 @@ class Apps { 'My Chatrooms' => t('My Chatrooms') ); - if(array_key_exists('name',$arr)) { - if(array_key_exists($arr['name'],$apps)) { + if (array_key_exists('name',$arr)) { + if (array_key_exists($arr['name'],$apps)) { $arr['name'] = $apps[$arr['name']]; } } else { - for($x = 0; $x < count($arr); $x++) { - if(array_key_exists($arr[$x]['name'],$apps)) { + for ($x = 0; $x < count($arr); $x++) { + if (array_key_exists($arr[$x]['name'],$apps)) { $arr[$x]['name'] = $apps[$arr[$x]['name']]; } else { @@ -399,16 +413,19 @@ class Apps { $installed = false; - if(! $papp) + if (! $papp) { return; + } - if(! $papp['photo']) + if (! $papp['photo']) { $papp['photo'] = 'icon:gear'; + } self::translate_system_apps($papp); - if(trim($papp['plugin']) && (! plugin_is_installed(trim($papp['plugin'])))) + if (trim($papp['plugin']) && (! plugin_is_installed(trim($papp['plugin'])))) { return ''; + } $papp['papp'] = self::papp_encode($papp); @@ -416,85 +433,96 @@ class Apps { // and they are allowed to see the app - if(strpos($papp['url'],'$baseurl') !== false || strpos($papp['url'],'$nick') !== false || strpos($papp['photo'],'$baseurl') !== false || strpos($papp['photo'],'$nick') !== false) { + if (strpos($papp['url'],'$baseurl') !== false || strpos($papp['url'],'$nick') !== false || strpos($papp['photo'],'$baseurl') !== false || strpos($papp['photo'],'$nick') !== false) { $view_channel = local_channel(); - if(! $view_channel) { + if (! $view_channel) { $sys = get_sys_channel(); $view_channel = $sys['channel_id']; } self::app_macros($view_channel,$papp); } - if(strpos($papp['url'], ',')) { + if (strpos($papp['url'], ',')) { $urls = explode(',', $papp['url']); $papp['url'] = trim($urls[0]); $papp['settings_url'] = trim($urls[1]); } - if(! strstr($papp['url'],'://')) + if (! strstr($papp['url'],'://')) { $papp['url'] = z_root() . ((strpos($papp['url'],'/') === 0) ? '' : '/') . $papp['url']; + } - - foreach($papp as $k => $v) { - if(strpos($v,'http') === 0 && $k != 'papp') { - if(! (local_channel() && strpos($v,z_root()) === 0)) { + foreach ($papp as $k => $v) { + if (strpos($v,'http') === 0 && $k != 'papp') { + if (! (local_channel() && strpos($v,z_root()) === 0)) { $papp[$k] = zid($v); } } - if($k === 'desc') + if ($k === 'desc') { $papp['desc'] = str_replace(array('\'','"'),array(''','&dquot;'),$papp['desc']); + } - if($k === 'requires') { + if ($k === 'requires') { $requires = explode(',',$v); - foreach($requires as $require) { + foreach ($requires as $require) { $require = trim(strtolower($require)); $config = false; - if(substr($require, 0, 7) == 'config:') { + if (substr($require, 0, 7) == 'config:') { $config = true; $require = ltrim($require, 'config:'); $require = explode('=', $require); } - switch($require) { + switch ($require) { case 'nologin': - if(local_channel()) + if (local_channel()) { return ''; + } break; case 'admin': - if(! is_site_admin()) + if (! is_site_admin()) { return ''; + } break; case 'local_channel': - if(! local_channel()) + if (! local_channel()) { return ''; + } break; case 'public_profile': - if(! is_public_profile()) + if (! is_public_profile()) { return ''; + } break; case 'public_stream': - if(! can_view_public_stream()) + if (! can_view_public_stream()) { return ''; + } break; case 'custom_role': - if(get_pconfig(local_channel(),'system','permissions_role') != 'custom') + if (get_pconfig(local_channel(),'system','permissions_role') != 'custom') { return ''; + } break; case 'observer': - $observer = \App::get_observer(); - if(! $observer) + $observer = App::get_observer(); + if (! $observer) { return ''; + } break; default: - if($config) + if ($config) { $unset = ((get_config('system', $require[0]) === $require[1]) ? false : true); - else + } + else { $unset = ((local_channel() && feature_enabled(local_channel(),$require)) ? false : true); - if($unset) + } + if ($unset) { return ''; + } break; } } @@ -503,18 +531,19 @@ class Apps { $hosturl = ''; - if(local_channel()) { - if(self::app_installed(local_channel(),$papp) && !$papp['deleted']) + if (local_channel()) { + if (self::app_installed(local_channel(),$papp) && !$papp['deleted']) { $installed = true; + } $hosturl = z_root() . '/'; } - elseif(remote_channel()) { - $observer = \App::get_observer(); - if($observer && $observer['xchan_network'] === 'zot6') { + elseif (remote_channel()) { + $observer = App::get_observer(); + if ($observer && $observer['xchan_network'] === 'zot6') { // some folks might have xchan_url redirected offsite, use the connurl $x = parse_url($observer['xchan_connurl']); - if($x) { + if ($x) { $hosturl = $x['scheme'] . '://' . $x['host'] . '/'; } } @@ -523,17 +552,17 @@ class Apps { $install_action = (($installed) ? t('Update') : t('Install')); $icon = ((strpos($papp['photo'],'icon:') === 0) ? substr($papp['photo'],5) : ''); - if($mode === 'navbar') { - return replace_macros(get_markup_template('app_nav.tpl'),array( + if ($mode === 'navbar') { + return replace_macros(get_markup_template('app_nav.tpl'), [ '$app' => $papp, '$icon' => $icon, - )); + ]); } - if($mode === 'install') { + if ($mode === 'install') { $papp['embed'] = true; } - return replace_macros(get_markup_template('app.tpl'),array( + return replace_macros(get_markup_template('app.tpl'), [ '$app' => $papp, '$icon' => $icon, '$hosturl' => $hosturl, @@ -555,41 +584,44 @@ class Apps { '$remove' => t('Remove from app-tray'), '$add_nav' => t('Pin to navbar'), '$remove_nav' => t('Unpin from navbar') - )); + ]); } static public function app_install($uid,$app) { - if(! is_array($app)) { + if (! is_array($app)) { $r = q("select * from app where app_name = '%s' and app_channel = 0", dbesc($app) ); - if(! $r) + if (! $r) { return false; + } $app = self::app_encode($r[0]); } $app['uid'] = $uid; - if(self::app_installed($uid,$app,true)) + if (self::app_installed($uid,$app,true)) { $x = self::app_update($app); - else + } + else { $x = self::app_store($app); + } - if($x['success']) { + if ($x['success']) { $r = q("select * from app where app_id = '%s' and app_channel = %d limit 1", dbesc($x['app_id']), intval($uid) ); - if($r) { - if(($app['uid']) && (! $r[0]['app_system'])) { - if($app['categories'] && (! $app['term'])) { + if ($r) { + if (($app['uid']) && (! $r[0]['app_system'])) { + if ($app['categories'] && (! $app['term'])) { $r[0]['term'] = q("select * from term where otype = %d and oid = %d", intval(TERM_OBJ_APP), intval($r[0]['id']) ); - if(intval($r[0]['app_system'])) { + if (intval($r[0]['app_system'])) { Libsync::build_sync_packet($uid,array('sysapp' => $r[0])); } else { @@ -605,14 +637,14 @@ class Apps { static public function can_delete($uid,$app) { - if(! $uid) { + if (! $uid) { return false; } $base_apps = self::get_base_apps(); - if($base_apps) { - foreach($base_apps as $b) { - if($app['guid'] === hash('whirlpool',$b)) { + if ($base_apps) { + foreach ($base_apps as $b) { + if ($app['guid'] === hash('whirlpool',$b)) { return false; } } @@ -623,16 +655,16 @@ class Apps { static public function app_destroy($uid,$app) { - if($uid && $app['guid']) { + if ($uid && $app['guid']) { $x = q("select * from app where app_id = '%s' and app_channel = %d limit 1", dbesc($app['guid']), intval($uid) ); - if($x) { - if(! intval($x[0]['app_deleted'])) { + if ($x) { + if (! intval($x[0]['app_deleted'])) { $x[0]['app_deleted'] = 1; - if(self::can_delete($uid,$app)) { + if (self::can_delete($uid,$app)) { $r = q("delete from app where app_id = '%s' and app_channel = %d", dbesc($app['guid']), intval($uid) @@ -649,7 +681,7 @@ class Apps { intval($uid) ); } - if(intval($x[0]['app_system'])) { + if (intval($x[0]['app_system'])) { Libsync::build_sync_packet($uid,array('sysapp' => $x)); } else { @@ -668,14 +700,14 @@ class Apps { // undelete a system app - if($uid && $app['guid']) { + if ($uid && $app['guid']) { $x = q("select * from app where app_id = '%s' and app_channel = %d limit 1", dbesc($app['guid']), intval($uid) ); - if($x) { - if($x[0]['app_system']) { + if ($x) { + if ($x[0]['app_system']) { $r = q("update app set app_deleted = 0 where app_id = '%s' and app_channel = %d", dbesc($app['guid']), intval($uid) @@ -697,7 +729,7 @@ class Apps { dbesc($term) ); - if($x) { + if ($x) { q("delete from term where otype = %d and oid = %d and term = '%s'", intval(TERM_OBJ_APP), intval($x[0]['oid']), @@ -715,7 +747,7 @@ class Apps { dbesc((array_key_exists('guid',$app)) ? $app['guid'] : ''), intval($uid) ); - if (!$bypass_filter) { + if (! $bypass_filter) { $filter_arr = [ 'uid'=>$uid, 'app'=>$app, @@ -725,7 +757,7 @@ class Apps { $r = $filter_arr['installed']; } - return(($r) ? true : false); + return (($r) ? true : false); } @@ -735,7 +767,7 @@ class Apps { dbesc($app), intval($uid) ); - if (!$bypass_filter) { + if (! $bypass_filter) { $filter_arr = [ 'uid'=>$uid, 'app'=>$app, @@ -745,7 +777,7 @@ class Apps { $r = $filter_arr['installed']; } - return(($r) ? true : false); + return (($r) ? true : false); } @@ -755,7 +787,7 @@ class Apps { dbesc(hash('whirlpool',$app)), intval($uid) ); - if (!$bypass_filter) { + if (! $bypass_filter) { $filter_arr = [ 'uid'=>$uid, 'app'=>$app, @@ -765,22 +797,22 @@ class Apps { $r = $filter_arr['installed']; } - return(($r) ? true : false); - + return (($r) ? true : false); } static public function app_list($uid, $deleted = false, $cats = []) { - if($deleted) + if ($deleted) { $sql_extra = ""; - else + } + else { $sql_extra = " and app_deleted = 0 "; - - if($cats) { + } + if ($cats) { $cat_sql_extra = " and ( "; - foreach($cats as $cat) { - if(strpos($cat_sql_extra, 'term')) + foreach ($cats as $cat) { + if (strpos($cat_sql_extra, 'term')) $cat_sql_extra .= "or "; $cat_sql_extra .= "term = '" . dbesc($cat) . "' "; @@ -791,29 +823,24 @@ class Apps { $r = q("select oid from term where otype = %d $cat_sql_extra", intval(TERM_OBJ_APP) ); - if(! $r) + if (! $r) { return $r; - $sql_extra .= " and app.id in ( "; - $s = ''; - foreach($r as $rr) { - if($s) - $s .= ','; - $s .= intval($rr['oid']); } - $sql_extra .= $s . ') '; + $sql_extra .= " and app.id in ( " . array_elm_to_str($r,'oid') . ') '; } $r = q("select * from app where app_channel = %d $sql_extra order by app_name asc", intval($uid) ); - if($r) { + if ($r) { $hookinfo = [ 'uid' => $uid, 'deleted' => $deleted, 'cats' => $cats, 'apps' => $r ]; call_hooks('app_list',$hookinfo); $r = $hookinfo['apps']; - for($x = 0; $x < count($r); $x ++) { - if(! $r[$x]['app_system']) + for ($x = 0; $x < count($r); $x ++) { + if (! $r[$x]['app_system']) { $r[$x]['type'] = 'personal'; + } $r[$x]['term'] = q("select * from term where otype = %d and oid = %d", intval(TERM_OBJ_APP), intval($r[$x]['id']) @@ -821,35 +848,51 @@ class Apps { } } - return($r); + return ($r); } + + static public function app_search_available($str) { + + // not yet finished + // somehow need to account for translations + + $r = q("select * from app where app_channel = 0 $sql_extra order by app_name asc", + intval($uid) + ); + + return ($r); + } + + + static public function app_order($uid,$apps,$menu) { - if(! $apps) + if (! $apps) return $apps; $conf = (($menu === 'nav_featured_app') ? 'app_order' : 'app_pin_order'); $x = (($uid) ? get_pconfig($uid,'system',$conf) : get_config('system',$conf)); - if(($x) && (! is_array($x))) { + if (($x) && (! is_array($x))) { $y = explode(',',$x); $y = array_map('trim',$y); $x = $y; } - if(! (is_array($x) && ($x))) + if (! (is_array($x) && ($x))) { return $apps; + } $ret = []; - foreach($x as $xx) { + foreach ($x as $xx) { $y = self::find_app_in_array($xx,$apps); - if($y) { + if ($y) { $ret[] = $y; } } - foreach($apps as $ap) { - if(! self::find_app_in_array($ap['name'],$ret)) { + foreach ($apps as $ap) { + if (! self::find_app_in_array($ap['name'],$ret)) { $ret[] = $ap; } } @@ -858,26 +901,27 @@ class Apps { } static function find_app_in_array($name,$arr) { - if(! $arr) + if (! $arr) { return false; - foreach($arr as $x) { - if($x['name'] === $name) { - return $x; + } + foreach ($arr as $x) { + if ($x['name'] === $name) { + return $x; } } return false; } static function moveup($uid,$guid,$menu) { - $syslist = array(); + $syslist = []; $conf = (($menu === 'nav_featured_app') ? 'app_order' : 'app_pin_order'); $list = self::app_list($uid, false, [ $menu ]); - if($list) { - foreach($list as $li) { + if ($list) { + foreach ($list as $li) { $papp = self::app_encode($li); - if($menu !== 'nav_pinned_app' && strpos($papp['categories'],'nav_pinned_app') !== false) + if ($menu !== 'nav_pinned_app' && strpos($papp['categories'],'nav_pinned_app') !== false) continue; $syslist[] = $papp; } @@ -888,26 +932,28 @@ class Apps { $syslist = self::app_order($uid,$syslist,$menu); - if(! $syslist) + if (! $syslist) { return; + } $newlist = []; - foreach($syslist as $k => $li) { - if($li['guid'] === $guid) { + foreach ($syslist as $k => $li) { + if ($li['guid'] === $guid) { $position = $k; break; } } - if(! $position) + if (! $position) { return; + } $dest_position = $position - 1; $saved = $syslist[$dest_position]; $syslist[$dest_position] = $syslist[$position]; $syslist[$position] = $saved; $narr = []; - foreach($syslist as $x) { + foreach ($syslist as $x) { $narr[] = $x['name']; } @@ -921,11 +967,12 @@ class Apps { $conf = (($menu === 'nav_featured_app') ? 'app_order' : 'app_pin_order'); $list = self::app_list($uid, false, [ $menu ]); - if($list) { - foreach($list as $li) { + if ($list) { + foreach ($list as $li) { $papp = self::app_encode($li); - if($menu !== 'nav_pinned_app' && strpos($papp['categories'],'nav_pinned_app') !== false) + if ($menu !== 'nav_pinned_app' && strpos($papp['categories'],'nav_pinned_app') !== false) { continue; + } $syslist[] = $papp; } } @@ -935,26 +982,28 @@ class Apps { $syslist = self::app_order($uid,$syslist,$menu); - if(! $syslist) + if (! $syslist) { return; + } $newlist = []; - foreach($syslist as $k => $li) { - if($li['guid'] === $guid) { + foreach ($syslist as $k => $li) { + if ($li['guid'] === $guid) { $position = $k; break; } } - if($position >= count($syslist) - 1) + if ($position >= count($syslist) - 1) { return; + } $dest_position = $position + 1; $saved = $syslist[$dest_position]; $syslist[$dest_position] = $syslist[$position]; $syslist[$position] = $saved; $narr = []; - foreach($syslist as $x) { + foreach ($syslist as $x) { $narr[] = $x['name']; } @@ -970,16 +1019,17 @@ class Apps { static public function app_macros($uid,&$arr) { - if(! intval($uid)) + if (! intval($uid)) { return; + } $baseurl = z_root(); $channel = channelx_by_n($uid); $address = (($channel) ? $channel['channel_address'] : ''); - //future expansion + // future expansion - $observer = \App::get_observer(); + $observer = App::get_observer(); $arr['url'] = str_replace(array('$baseurl','$nick'),array($baseurl,$address),$arr['url']); $arr['photo'] = str_replace(array('$baseurl','$nick'),array($baseurl,$address),$arr['photo']); @@ -987,16 +1037,12 @@ class Apps { } - - - - static public function app_store($arr) { - //logger('app_store: ' . print_r($arr,true)); + // logger('app_store: ' . print_r($arr,true)); - $darray = array(); - $ret = array('success' => false); + $darray = []; + $ret = [ 'success' => false ]; $sys = get_sys_channel(); @@ -1005,14 +1051,15 @@ class Apps { $darray['app_url'] = ((x($arr,'url')) ? $arr['url'] : ''); $darray['app_channel'] = ((x($arr,'uid')) ? $arr['uid'] : 0); - if(! $darray['app_url']) + if (! $darray['app_url']) { return $ret; + } - if((! $arr['uid']) && (! $arr['author'])) { + if ((! $arr['uid']) && (! $arr['author'])) { $arr['author'] = $sys['channel_hash']; } - if($arr['photo'] && (strpos($arr['photo'],'icon:') === false) && (strpos($arr['photo'],z_root()) !== false)) { + if ($arr['photo'] && (strpos($arr['photo'],'icon:') === false) && (strpos($arr['photo'],z_root()) !== false)) { $x = import_xchan_photo(str_replace('$baseurl',z_root(),$arr['photo']),get_observer_hash(),true); $arr['photo'] = $x[1]; } @@ -1058,21 +1105,21 @@ class Apps { intval($darray['app_options']) ); - if($r) { + if ($r) { $ret['success'] = true; $ret['app_id'] = $darray['app_id']; } - if($arr['categories']) { + if ($arr['categories']) { $x = q("select id from app where app_id = '%s' and app_channel = %d limit 1", dbesc($darray['app_id']), intval($darray['app_channel']) ); $y = explode(',',$arr['categories']); - if($y) { - foreach($y as $t) { + if ($y) { + foreach ($y as $t) { $t = trim($t); - if($t) { + if ($t) { store_item_tag($darray['app_channel'],$x[0]['id'],TERM_OBJ_APP,TERM_CATEGORY,escape_tags($t),escape_tags(z_root() . '/apps/?f=&cat=' . escape_tags($t))); } } @@ -1085,9 +1132,9 @@ class Apps { static public function app_update($arr) { - //logger('app_update: ' . print_r($arr,true)); - $darray = array(); - $ret = array('success' => false); + // logger('app_update: ' . print_r($arr,true)); + $darray = []; + $ret = [ 'success' => false ]; self::app_macros($arr['uid'],$arr); @@ -1096,10 +1143,11 @@ class Apps { $darray['app_channel'] = ((x($arr,'uid')) ? $arr['uid'] : 0); $darray['app_id'] = ((x($arr,'guid')) ? $arr['guid'] : 0); - if((! $darray['app_url']) || (! $darray['app_id'])) + if ((! $darray['app_url']) || (! $darray['app_id'])) { return $ret; + } - if($arr['photo'] && (strpos($arr['photo'],'icon:') === false) && (strpos($arr['photo'],z_root()) !== false)) { + if ($arr['photo'] && (strpos($arr['photo'],'icon:') === false) && (strpos($arr['photo'],z_root()) !== false)) { $x = import_xchan_photo(str_replace('$baseurl',z_root(),$arr['photo']),get_observer_hash(),true); $arr['photo'] = $x[1]; } @@ -1141,7 +1189,7 @@ class Apps { dbesc($darray['app_id']), intval($darray['app_channel']) ); - if($r) { + if ($r) { $ret['success'] = true; $ret['app_id'] = $darray['app_id']; } @@ -1153,20 +1201,20 @@ class Apps { // if updating an embed app and we don't have a 0 channel_id don't mess with any existing categories - if(array_key_exists('embed',$arr) && intval($arr['embed']) && (intval($darray['app_channel']))) + if (array_key_exists('embed',$arr) && intval($arr['embed']) && (intval($darray['app_channel']))) return $ret; - if($x) { + if ($x) { q("delete from term where otype = %d and oid = %d", intval(TERM_OBJ_APP), intval($x[0]['id']) ); - if($arr['categories']) { + if ($arr['categories']) { $y = explode(',',$arr['categories']); - if($y) { - foreach($y as $t) { + if ($y) { + foreach ($y as $t) { $t = trim($t); - if($t) { + if ($t) { store_item_tag($darray['app_channel'],$x[0]['id'],TERM_OBJ_APP,TERM_CATEGORY,escape_tags($t),escape_tags(z_root() . '/apps/?f=&cat=' . escape_tags($t))); } } @@ -1185,75 +1233,70 @@ class Apps { $ret['type'] = 'personal'; - if($app['app_id']) + if ($app['app_id']) { $ret['guid'] = $app['app_id']; - - if($app['app_sig']) + } + if ($app['app_sig']) { $ret['sig'] = $app['app_sig']; - - if($app['app_author']) + } + if ($app['app_author']) { $ret['author'] = $app['app_author']; - - if($app['app_name']) + } + if ($app['app_name']) { $ret['name'] = $app['app_name']; - - if($app['app_desc']) + } + if ($app['app_desc']) { $ret['desc'] = $app['app_desc']; - - if($app['app_url']) + } + if ($app['app_url']) { $ret['url'] = $app['app_url']; - - if($app['app_photo']) + } + if ($app['app_photo']) { $ret['photo'] = $app['app_photo']; - - if($app['app_icon']) + } + if ($app['app_icon']) { $ret['icon'] = $app['app_icon']; - - if($app['app_version']) + } + if ($app['app_version']) { $ret['version'] = $app['app_version']; - - if($app['app_addr']) + } + if ($app['app_addr']) { $ret['addr'] = $app['app_addr']; - - if($app['app_price']) + } + if ($app['app_price']) { $ret['price'] = $app['app_price']; - - if($app['app_page']) + } + if ($app['app_page']) { $ret['page'] = $app['app_page']; - - if($app['app_requires']) + } + if ($app['app_requires']) { $ret['requires'] = $app['app_requires']; - - if($app['app_system']) + } + if ($app['app_system']) { $ret['system'] = $app['app_system']; - - if($app['app_options']) + } + if ($app['app_options']) { $ret['options'] = $app['app_options']; - - if($app['app_plugin']) + } + if ($app['app_plugin']) { $ret['plugin'] = trim($app['app_plugin']); - - if($app['app_deleted']) + } + if ($app['app_deleted']) { $ret['deleted'] = $app['app_deleted']; - - if($app['term']) { - $s = ''; - foreach($app['term'] as $t) { - if($s) - $s .= ','; - $s .= $t['term']; - } - $ret['categories'] = $s; + } + if ($app['term']) { + $ret['categories'] = array_elm_to_str($app['term'],'term'); } - if(! $embed) + if (! $embed) { return $ret; - + } $ret['embed'] = true; - if(array_key_exists('categories',$ret)) + if (array_key_exists('categories',$ret)) { unset($ret['categories']); + } $j = json_encode($ret); return '[app]' . chunk_split(base64_encode($j),72,"\n") . '[/app]'; @@ -1263,7 +1306,6 @@ class Apps { static public function papp_encode($papp) { return chunk_split(base64_encode(json_encode($papp)),72,"\n"); - } } diff --git a/Zotlabs/Lib/Connect.php b/Zotlabs/Lib/Connect.php index 5f85be066..c0c71ff9b 100644 --- a/Zotlabs/Lib/Connect.php +++ b/Zotlabs/Lib/Connect.php @@ -35,13 +35,6 @@ class Connect { $protocol = substr($url,1,$x-1); $url = substr($url,$x+1); } - } - - $category = null; - if(strpos($url,'$') !== false) { - - - } if(! allowed_url($url)) { diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php index d3739715a..f7ee488fd 100644 --- a/Zotlabs/Lib/Enotify.php +++ b/Zotlabs/Lib/Enotify.php @@ -12,7 +12,7 @@ class Enotify { /** * @brief * - * @param array $params an assoziative array with: + * @param array $params an associative array with: * * \e string \b from_xchan sender xchan hash * * \e string \b to_xchan recipient xchan hash * * \e array \b item an assoziative array @@ -53,6 +53,8 @@ class Enotify { return; } + + // from here on everything is in the recipients language push_lang($recip['account_language']); // should probably have a channel language @@ -840,6 +842,9 @@ class Enotify { $ret = ''; + $expire = intval(get_config('system','default_expire_days')); + $expire_date = (($expire) ? datetime_convert('UTC','UTC','now - ' . $expire . ' days') : NULL_DATE); + require_once('include/conversation.php'); // Call localize_item to get a one line status for activities. @@ -898,6 +903,11 @@ class Enotify { 'display' => true ); + $post_date = (($edit)? $item['edited'] : $item['created']); + if($post_date && $post_date < $expire_date) { + return []; + } + call_hooks('enotify_format',$x); if(! $x['display']) { return []; diff --git a/Zotlabs/Lib/LDSignatures.php b/Zotlabs/Lib/LDSignatures.php index be71da104..98d02698b 100644 --- a/Zotlabs/Lib/LDSignatures.php +++ b/Zotlabs/Lib/LDSignatures.php @@ -40,8 +40,10 @@ class LDSignatures { $signed = array_merge([ '@context' => [ ACTIVITYSTREAMS_JSONLD_REV, - 'https://w3id.org/security/v1' ], - ],$options); + 'https://w3id.org/security/v1', + z_root() . ZOT_APSCHEMA_REV + ], + ],$options); return $signed; } diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index fdd1af7ad..3460a5691 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -166,17 +166,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) { + if ($x) { $y = Crypto::methods(); - if($y) { - foreach($y as $yv) { + if ($y) { + foreach ($y as $yv) { $yv = trim($yv); - if(in_array($yv, $x)) { + if (in_array($yv, $x)) { return($yv); } } @@ -202,7 +203,7 @@ class Libzot { 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), @@ -254,8 +255,9 @@ class Libzot { static function refresh($them, $channel = null, $force = false) { logger('them: ' . print_r($them,true), LOGGER_DATA, LOG_DEBUG); - if ($channel) + if ($channel) { logger('channel: ' . print_r($channel,true), LOGGER_DATA, LOG_DEBUG); + } $url = null; @@ -274,7 +276,7 @@ class Libzot { dbesc($them['xchan_addr']) ); } - if(! $r) { + if (! $r) { $r = q("select hubloc_id_url, hubloc_primary from hubloc where hubloc_hash = '%s' and hubloc_network = 'zot6' order by hubloc_id desc", dbesc($them['xchan_hash']) ); @@ -301,7 +303,7 @@ 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; } @@ -311,10 +313,11 @@ class Libzot { // 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) { + if (! $hsig_valid) { logger('http signature not valid: ' . print_r($hsig,true)); return false; } @@ -324,14 +327,14 @@ class Libzot { $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']) { + if ($channel && $record['data']['permissions']) { $old_read_stream_perm = their_perms_contains($channel['channel_id'],$x['hash'],'view_stream'); set_abconfig($channel['channel_id'],$x['hash'],'system','their_perms',$record['data']['permissions']); - if(array_key_exists('profile',$record['data']) && array_key_exists('next_birthday',$record['data']['profile'])) { + 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 { @@ -348,7 +351,7 @@ class Libzot { intval($channel['channel_id']) ); - if($r) { + if ($r) { // connection exists @@ -356,7 +359,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' @@ -367,11 +370,12 @@ 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']))) + if ((! $old_read_stream_perm) && (intval($permissions['view_stream']))) Master::Summon([ 'Onepoll', $r[0]['abook_id'] ]); } } @@ -384,7 +388,7 @@ class Libzot { // new connection - if($my_perms) { + if ($my_perms) { set_abconfig($channel['channel_id'],$x['hash'],'system','my_perms',$my_perms); } @@ -399,13 +403,12 @@ class Libzot { dbesc($channel['channel_hash']), intval($channel['channel_account_id']) ); - if($cl) { + if ($cl) { $is_collection = true; $automatic = true; $closeness = 10; } - $y = abook_store_lowlevel( [ 'abook_account' => intval($channel['channel_account_id']), @@ -420,7 +423,7 @@ class Libzot { ] ); - if($y) { + if ($y) { logger("New introduction received for {$channel['channel_name']}"); $new_perms = get_all_perms($channel['channel_id'],$x['hash']); @@ -431,11 +434,12 @@ class Libzot { intval($channel['channel_id']) ); - if($new_connection) { - if(! Permissions::PermsCompare($new_perms,$previous_perms)) + if ($new_connection) { + if (! Permissions::PermsCompare($new_perms,$previous_perms)) { Master::Summon([ 'Notifier', 'permissions_create', $new_connection[0]['abook_id'] ]); + } - if(! $is_collection) { + if (! $is_collection) { Enotify::submit( [ 'type' => NOTIFY_INTRO, @@ -446,8 +450,8 @@ class Libzot { ); } - if(intval($permissions['view_stream'])) { - if(intval(get_pconfig($channel['channel_id'],'perm_limits','send_stream') & PERMS_PENDING) + 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'] ]); } @@ -456,12 +460,13 @@ class Libzot { // 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) { + if ($default_group) { $g = AccessList::rec_byhash($channel['channel_id'],$default_group); - if($g) + if ($g) { AccessList::member_add($channel['channel_id'],'',$x['hash'],$g['id']); + } } } @@ -469,9 +474,9 @@ class Libzot { unset($new_connection[0]['abook_account']); unset($new_connection[0]['abook_channel']); $abconfig = load_abconfig($channel['channel_id'],$new_connection['abook_xchan']); - if($abconfig) + if ($abconfig) { $new_connection['abconfig'] = $abconfig; - + } Libsync::build_sync_packet($channel['channel_id'], array('abook' => $new_connection)); } } @@ -504,9 +509,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; } @@ -524,7 +529,7 @@ class Libzot { dbesc($arr['location_sig']), dbesc($arr['site_id']) ); - if($r) { + if ($r) { logger('Found', LOGGER_DEBUG); return (($multiple) ? $r : $r[0]); } @@ -543,22 +548,21 @@ 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; } return $r[0]; - } /** @@ -588,7 +592,7 @@ class Libzot { $result = [ 'success' => false ]; - if(! $id) { + if (! $id) { return $result; } @@ -597,16 +601,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) { + 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 { @@ -650,12 +654,12 @@ class Libzot { $changed = false; $what = ''; - if(! is_array($arr)) { + if (! is_array($arr)) { logger('Not an array: ' . print_r($arr,true), LOGGER_DEBUG); return $ret; } - if(! ($arr['id'] && $arr['id_sig'])) { + if (! ($arr['id'] && $arr['id_sig'])) { logger('No identity information provided. ' . print_r($arr,true)); return $ret; } @@ -668,7 +672,7 @@ class Libzot { $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; } @@ -676,7 +680,7 @@ class Libzot { $verified = true; } - if(! $verified) { + if (! $verified) { $ret['message'] = t('Unable to verify channel signature'); return $ret; } @@ -687,11 +691,12 @@ 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']) && $r[0]['xchan_photo_date'] != $arr['photo']['updated']) { $import_photos = true; } @@ -700,19 +705,23 @@ class Libzot { $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 = $type_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; + } if ($arr['channel_type'] === 'collection') { $px = 2; @@ -733,7 +742,7 @@ class Libzot { if ($arr['protocols']) { $protocols = implode(',',$arr['protocols']); - if($protocols !== 'zot6') { + if ($protocols !== 'zot6') { set_xconfig($xchan_hash,'system','protocols',$protocols); } else { @@ -741,7 +750,7 @@ class Libzot { } } - 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']) @@ -774,10 +783,11 @@ class Libzot { 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; + } if ($arr['channel_type'] === 'collection') { @@ -818,13 +828,11 @@ class Libzot { ] ); - - $what .= 'new_xchan'; $changed = true; } - if($import_photos) { + if ($import_photos) { require_once('include/photo_factory.php'); @@ -833,13 +841,12 @@ class Libzot { $local = q("select channel_account_id, channel_id from channel where channel_hash = '%s' limit 1", dbesc($xchan_hash) ); - if($local) { + if ($local) { $ph = z_fetch_url($arr['photo']['url'], true); - if($ph['success']) { - + 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; @@ -847,13 +854,14 @@ 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), @@ -877,8 +885,8 @@ class Libzot { 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' @@ -911,13 +919,16 @@ 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']; + } } // Which entries in the update table are we interested in updating? @@ -929,22 +940,22 @@ class Libzot { $other_realm = false; $realm = get_directory_realm(); - if(array_key_exists('site',$arr) + 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)) { + 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) { + if ($profile_changed) { $what .= 'profile '; $changed = true; } @@ -961,20 +972,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) { + if ($profile_changed) { $what .= 'site '; $changed = true; } } - if(($changed) || ($ud_flags == UPDATE_FLAGS_FORCED)) { - $guid = random_string() . '@' . \App::get_hostname(); + 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); } - 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), @@ -983,7 +994,7 @@ class Libzot { ); } - if(! x($ret,'message')) { + if (! x($ret,'message')) { $ret['success'] = true; $ret['hash'] = $xchan_hash; } @@ -1007,29 +1018,29 @@ class Libzot { 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')); - if(! is_array($x)) { + if (! is_array($x)) { $x = json_decode($x,true); } - if(! is_array($x)) { + if (! is_array($x)) { btlogger('failed communication - no useful response: ' . $x); } - if($x) { - if(! $x['success']) { + if ($x) { + if (! $x['success']) { // handle remote validation issues @@ -1040,10 +1051,10 @@ class Libzot { ); } - if(is_array($x) && array_key_exists('delivery_report',$x) && is_array($x['delivery_report'])) { - foreach($x['delivery_report'] as $xx) { + 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)) { + if (is_array($xx) && array_key_exists('message_id',$xx) && DReport::is_storable($xx)) { 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' ) ", dbesc($xx['message_id']), dbesc($xx['location']), @@ -1073,9 +1084,10 @@ class Libzot { // synchronous message types are handled immediately // async messages remain in the queue until processed. - if(intval($outq['outq_async'])) + if (intval($outq['outq_async'])) { Queue::remove($outq['outq_hash'],$outq['outq_channel']); - + } + logger('zot_process_response: ' . print_r($x,true), LOGGER_DEBUG); } @@ -1141,7 +1153,7 @@ class Libzot { logger('Notify: ' . print_r($env,true), LOGGER_DATA, LOG_DEBUG); - if(! is_array($env)) { + if (! is_array($env)) { logger('decode error'); return; } @@ -1154,7 +1166,7 @@ class Libzot { $AS = null; - if($env['encoding'] === 'activitystreams') { + if ($env['encoding'] === 'activitystreams') { $AS = new ActivityStreams($data); if (! $AS->is_valid()) { @@ -1177,14 +1189,15 @@ class Libzot { // at the present time (2019/02) during the Hubzilla transition to zot6 it is likely to cause lots of duplicates for // messages arriving from different protocols and sources with different message-id semantics. This // restriction can be relaxed once most Hubzilla sites are upgraded to > 4.0. - - if($arr) { - if(strpos($arr['mid'],'http') === false && strpos($arr['mid'],'x-zot') === false) { + // Don't check sync packets since they have a different encoding + + if ($arr && $env['type'] !== 'sync') { + if (strpos($arr['mid'],'http') === false && strpos($arr['mid'],'x-zot') === false) { logger('activity rejected: legacy message-id'); return; } - if($arr['verb'] === 'Create' && ActivityStreams::is_an_actor($arr['obj_type'])) { + if ($arr['verb'] === 'Create' && ActivityStreams::is_an_actor($arr['obj_type'])) { logger('activity rejected: create actor'); return; } @@ -1195,31 +1208,32 @@ class Libzot { $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); $recip_arr = []; - foreach($env['recipients'] as $recip) { + foreach ($env['recipients'] as $recip) { $recip_arr[] = $recip; } $r = false; - if($recip_arr) { + 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'); @@ -1235,32 +1249,30 @@ class Libzot { // @fixme; $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, hubloc_url from hubloc where hubloc_id_url = '%s'", dbesc($AS->actor['id']) ); - if($r) { + if ($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; } @@ -1270,18 +1282,18 @@ 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) { + if ($private) { $arr['item_private'] = true; } - if($arr['mid'] === $arr['parent_mid']) { - if(is_array($AS->obj) && array_key_exists('commentPolicy',$AS->obj)) { + 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)); @@ -1292,18 +1304,17 @@ class Libzot { } } } - // @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 { @@ -1311,10 +1322,10 @@ class Libzot { } } } - if($AS->data['signed_data']) { + 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) { + if ($j) { IConfig::Set($arr,'activitypub','rawmsg',json_encode(JSalmon::unpack($j['data'])),true); } } @@ -1326,7 +1337,7 @@ class Libzot { $result = self::process_delivery($env['sender'],$AS,$arr,$deliveries,$relay,false,$message_request); } - elseif($env['type'] === 'sync') { + elseif ($env['type'] === 'sync') { $arr = json_decode($data,true); @@ -1344,15 +1355,15 @@ class Libzot { 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 || (is_array($act->obj) && array_key_exists('id',$act->obj) && $x === $act->obj['id'])) { + if ($x === $act->id || (is_array($act->obj) && array_key_exists('id',$act->obj) && $x === $act->obj['id'])) { return true; } } @@ -1361,11 +1372,11 @@ class Libzot { static function find_parent($env,$act) { - if($act) { - if(in_array($act->type, ['Like','Dislike'])) { + 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; } } @@ -1391,31 +1402,31 @@ class Libzot { static function public_recips($msg, $act) { - require_once('include/channel.php'); - $check_mentions = false; $include_sys = false; - if($msg['type'] === 'activity') { + 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 (! $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 ($c) { + foreach ($c as $cc) { // top level activity sent to ourself: ignore. Clones will get a sync activity // which is a true clone of the original item. Everything else is a duplicate. @@ -1424,49 +1435,50 @@ class Libzot { continue; } - if(perm_is_allowed($cc['channel_id'],$msg['sender'],$perm)) { + 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_hash != '%s' and channel_removed = 0 limit 1", dbesc($address), dbesc($msg['sender']) ); - if($z) { + if ($z) { $r[] = $z[0]['hash']; } } } - if($tag['type'] === 'topicalCollection' && strpos($tag['name'],App::get_hostname())) { + if ($tag['type'] === 'topicalCollection' && strpos($tag['name'],App::get_hostname())) { $address = substr($tag['name'],0,strpos($tag['name'],'@')); - if($address) { + if ($address) { $z = q("select channel_hash as hash from channel where channel_address = '%s' and channel_hash != '%s' and channel_removed = 0 limit 1", dbesc($address), dbesc($msg['sender']) ); - if($z) { + if ($z) { $r[] = $z[0]['hash']; } } @@ -1482,13 +1494,13 @@ class Libzot { $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']; } } @@ -1498,7 +1510,7 @@ 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)); } @@ -1531,14 +1543,14 @@ class Libzot { // We've validated the sender. Now make sure that the sender is the owner or author - if(! $public) { - if($sender != $msg_arr['owner_xchan'] && $sender != $msg_arr['author_xchan']) { + if (! $public) { + if ($sender != $msg_arr['owner_xchan'] && $sender != $msg_arr['author_xchan']) { logger("Sender $sender is not owner {$msg_arr['owner_xchan']} or author {$msg_arr['author_xchan']} - mid {$msg_arr['mid']}"); return; } } - foreach($deliveries as $d) { + foreach ($deliveries as $d) { $local_public = $public; @@ -1557,7 +1569,7 @@ 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. @@ -1565,7 +1577,7 @@ class Libzot { // but preserve any values that were set during anonymous parsing. $o = Activity::fetch($act->obj,$channel); - if($o) { + if ($o) { $act->obj = $o; $arr = array_merge(Activity::decode_note($act),$arr); } @@ -1585,7 +1597,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; @@ -1595,10 +1607,10 @@ 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; - if(! check_pubstream_channelallowed($sender)) { + if (! check_pubstream_channelallowed($sender)) { $local_public = false; continue; } @@ -1609,15 +1621,15 @@ class Libzot { $h = q("select hubloc_url from hubloc where hubloc_hash = '%s'", dbesc($sender) ); - if($h) { - foreach($h as $hub) { - if(! check_pubstream_siteallowed($hub['hubloc_url'])) { + if ($h) { + foreach ($h as $hub) { + if (! check_pubstream_siteallowed($hub['hubloc_url'])) { $siteallowed = false; break; } } } - if(! $siteallowed) { + if (! $siteallowed) { $local_public = false; continue; } @@ -1626,11 +1638,11 @@ class Libzot { 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; } @@ -1639,12 +1651,12 @@ class Libzot { $tag_delivery = tgroup_check($channel['channel_id'],$arr); $perm = 'send_stream'; - if(($arr['mid'] !== $arr['parent_mid']) && ($relay)) + 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 { @@ -1699,9 +1711,9 @@ class Libzot { } } - if($arr['mid'] !== $arr['parent_mid']) { + if ($arr['mid'] !== $arr['parent_mid']) { - if(perm_is_allowed($channel['channel_id'],$sender,'moderated') && $relay) { + if (perm_is_allowed($channel['channel_id'],$sender,'moderated') && $relay) { $arr['item_blocked'] = ITEM_MODERATED; } @@ -1715,9 +1727,9 @@ class Libzot { dbesc($arr['parent_mid']), intval($channel['channel_id']) ); - if($r) { + if ($r) { // if this is a multi-threaded conversation, preserve the threading information - if($r[0]['parent_mid'] !== $r[0]['mid']) { + if ($r[0]['parent_mid'] !== $r[0]['mid']) { $arr['thr_parent'] = $arr['parent_mid']; $arr['parent_mid'] = $r[0]['parent_mid']; } @@ -1737,7 +1749,7 @@ class Libzot { // the top level post is unlikely to be imported and // this is just an exercise in futility. - if((! $relay) && (! $request) && (! $local_public) + if ((! $relay) && (! $request) && (! $local_public) && perm_is_allowed($channel['channel_id'],$sender,'send_stream')) { self::fetch_conversation($channel,$arr['parent_mid']); @@ -1745,7 +1757,7 @@ class Libzot { continue; } - 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. @@ -1766,7 +1778,7 @@ class Libzot { $existing_route = explode(',', $r[0]['route']); $routes = count($existing_route); - if($routes) { + if ($routes) { $last_hop = array_pop($existing_route); $last_prior_route = implode(',',$existing_route); } @@ -1775,12 +1787,13 @@ class Libzot { $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); $DR->update('comment route mismatch'); @@ -1801,7 +1814,7 @@ class Libzot { ); $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']); @@ -1816,13 +1829,12 @@ class Libzot { $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) ]); $DR->update('relayed'); $result[] = $DR->get(); } - continue; } @@ -1831,11 +1843,11 @@ class Libzot { dbesc($arr['mid']), 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(); @@ -1843,10 +1855,10 @@ class Libzot { continue; } // Maybe it has been edited? - elseif($arr['edited'] > $r[0]['edited']) { + 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($channel['channel_id'],$arr,$abook))) { + if (($arr['mid'] == $arr['parent_mid']) && (! post_is_importable($channel['channel_id'],$arr,$abook))) { $DR->update('update ignored'); $result[] = $DR->get(); } @@ -1864,7 +1876,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; } } @@ -1875,7 +1887,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)) { + if (check_item_source($arr['uid'], $arr)) { /** * @hooks post_local * Called when an item has been posted on this machine via mod/item.php (also via API). @@ -1886,19 +1898,19 @@ class Libzot { $item_id = 0; - if(($arr['mid'] == $arr['parent_mid']) && (! post_is_importable($arr['uid'],$arr,$abook))) { + if (($arr['mid'] == $arr['parent_mid']) && (! post_is_importable($arr['uid'],$arr,$abook))) { $DR->update('post ignored'); $result[] = $DR->get(); } else { // Strip old-style hubzilla bookmarks - if(strpos($arr['body'],"#^[") !== false) { + if (strpos($arr['body'],"#^[") !== false) { $arr['body'] = str_replace("#^[","[",$arr['body']); } $item_result = item_store($arr); - if($item_result['success']) { + if ($item_result['success']) { $item_id = $item_result['item_id']; $parr = [ 'item_id' => $item_id, @@ -1916,8 +1928,9 @@ 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) + if (! $relay) { add_source_route($item_id,$sender); + } } $DR->update(($item_id) ? 'posted' : 'storage failed: ' . $item_result['message']); $result[] = $DR->get(); @@ -1927,12 +1940,12 @@ 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'])) { retain_item($stored['item']['parent']); } - if($relay && $item_id) { + if ($relay && $item_id) { logger('Invoking relay'); Master::Summon([ 'Notifier', 'relay', intval($item_id) ]); $DR->addto_update('relayed'); @@ -1940,8 +1953,9 @@ class Libzot { } } - if(! $deliveries) + if (! $deliveries) { $result[] = array('', 'no recipients', '', $arr['mid']); + } logger('Local results: ' . print_r($result, true), LOGGER_DEBUG); @@ -1950,10 +1964,10 @@ class Libzot { static public function hyperdrive_enabled($channel,$item) { - if(get_pconfig($channel['channel_id'],'system','hyperdrive',true)) { + if (get_pconfig($channel['channel_id'],'system','hyperdrive',true)) { return true; } - if($item['verb'] === 'Announce' && get_pconfig($channel['channel_id'],'system','hyperdrive_announce',true)) { + if ($item['verb'] === 'Announce' && get_pconfig($channel['channel_id'],'system','hyperdrive_announce',true)) { return true; } return false; @@ -1965,20 +1979,19 @@ class Libzot { logger('fetching conversation: ' . $mid, LOGGER_DEBUG); - $a = Zotfinger::exec($mid,$channel); logger('received conversation: ' . print_r($a,true), LOGGER_DATA); - if(! $a) { + if (! $a) { return false; } - if($a['data']['type'] !== 'OrderedCollection') { + if ($a['data']['type'] !== 'OrderedCollection') { return false; } - if(! intval($a['data']['totalItems'])) { + if (! intval($a['data']['totalItems'])) { return false; } @@ -1990,10 +2003,10 @@ class Libzot { ); - foreach($a['data']['orderedItems'] as $activity) { + foreach ($a['data']['orderedItems'] as $activity) { $AS = new ActivityStreams($activity); - if(! $AS->is_valid()) { + if (! $AS->is_valid()) { logger('FOF Activity rejected: ' . print_r($activity,true)); continue; } @@ -2001,57 +2014,55 @@ class Libzot { // logger($AS->debug()); - $r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' limit 1", dbesc($AS->actor['id']) ); - if(! $r) { + if (! $r) { $y = import_author_xchan([ 'url' => $AS->actor['id'] ]); - if($y) { + 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']) { + 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 (! $y) { logger('FOF Activity: no object actor'); continue; } } - if($r) { + if ($r) { $arr['author_xchan'] = $r[0]['hubloc_hash']; } - - - if($signer) { + + if ($signer) { $arr['owner_xchan'] = $signer[0]['hubloc_hash']; } else { $arr['owner_xchan'] = $a['signature']['signer']; } - if($AS->data['hubloc'] || $arr['author_xchan'] === $arr['owner_xchan']) { + 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) { + 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' ]))) { + if ((! $s) || (in_array($s[0]['site_project'],[ '', 'osada' ]))) { $arr['comment_policy'] = 'authenticated'; } else { @@ -2060,7 +2071,7 @@ class Libzot { } - if($AS->data['signed_data']) { + if ($AS->data['signed_data']) { IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false); } @@ -2091,12 +2102,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; } @@ -2105,24 +2116,25 @@ 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']) + if ($i['target']) { $i['target'] = json_decode($i['target'],true); - if($i['object']) + } + 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; } @@ -2133,7 +2145,7 @@ class Libzot { dbesc($message_id), intval($uid) ); - if(! $r) { + if (! $r) { logger('No parent message'); return; } @@ -2166,7 +2178,7 @@ class Libzot { // 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']); @@ -2177,7 +2189,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; } @@ -2188,16 +2200,19 @@ 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 + } + else { logger('update_imported_item'); + } return $x; } @@ -2230,9 +2245,10 @@ class Libzot { intval($uid) ); - if($r) { - if($r[0]['author_xchan'] === $sender || $r[0]['owner_xchan'] === $sender || $r[0]['source_xchan'] === $sender) + if ($r) { + if ($r[0]['author_xchan'] === $sender || $r[0]['owner_xchan'] === $sender || $r[0]['source_xchan'] === $sender) { $ownership_valid = true; + } $post_id = $r[0]['id']; $item_found = true; @@ -2246,24 +2262,25 @@ class Libzot { logger('delete received for non-existent item - storing item data.'); - if($item['author_xchan'] === $sender || $item['owner_xchan'] === $sender || $item['source_xchan'] === $sender) { + if ($item['author_xchan'] === $sender || $item['owner_xchan'] === $sender || $item['source_xchan'] === $sender) { $ownership_valid = true; $item_result = item_store($item); $post_id = $item_result['item_id']; } } - if($ownership_valid === false) { + if ($ownership_valid === false) { logger('delete_imported_item: failed: ownership issue'); return false; } - if($item_found) { - if(intval($r[0]['item_deleted'])) { + if ($item_found) { + if (intval($r[0]['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 // a bit further. We're going to strip the ITEM_ORIGIN on this item if it's a comment, because // it was already deleted, and we're already relaying, and this ensures that no other process or @@ -2294,12 +2311,12 @@ class Libzot { $result = array(); - 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']); @@ -2307,7 +2324,7 @@ class Libzot { dbesc($d['hash']) ); - if(! $r) { + if (! $r) { $DR->update('recipient not found'); $result[] = $DR->get(); continue; @@ -2317,7 +2334,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 @@ -2326,13 +2343,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(); @@ -2345,8 +2362,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']) @@ -2392,7 +2409,7 @@ class Libzot { $r = q("select xchan_addr from xchan where xchan_hash = '%s' limit 1", dbesc($sender['hash']) ); - if($r) { + if ($r) { Libzotdir::import_directory_profile($sender, $arr, $r[0]['xchan_addr'], UPDATE_FLAGS_UPDATED, 0); } } @@ -2414,14 +2431,14 @@ class Libzot { $r = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($sender) ); - if($r) { + 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']) { + 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 ($x['changed']) { $guid = random_string() . '@' . App::get_hostname(); Libzotdir::update_modtime($sender,$r[0]['xchan_guid'],$arr['locations'][0]['address'],UPDATE_FLAGS_UPDATED); } @@ -2450,11 +2467,13 @@ 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]; @@ -2462,10 +2481,11 @@ 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) @@ -2504,14 +2524,15 @@ class Libzot { $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; + } $ret[] = [ 'host' => $hub['hubloc_host'], @@ -2542,10 +2563,11 @@ 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; } @@ -2556,49 +2578,61 @@ class Libzot { $r = q("select * from site where site_url = '%s' limit 1", dbesc($arr['url']) ); - if($r) { + 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; } @@ -2615,7 +2649,7 @@ class Libzot { // 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; @@ -2623,12 +2657,12 @@ class Libzot { $site_flags = $site_directory; - if(array_key_exists('zot',$arr)) { + 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) @@ -2660,7 +2694,7 @@ class Libzot { dbesc($site_crypto), dbesc($url) ); - if(! $r) { + if (! $r) { logger('Update failed. ' . print_r($arr,true)); } } @@ -2693,7 +2727,7 @@ class Libzot { ] ); - if(! $r) { + if (! $r) { logger('Record create failed. ' . print_r($arr,true)); } } @@ -2711,8 +2745,9 @@ class Libzot { * @return string */ static function get_rpost_path($observer) { - if(! $observer) - return ''; + if (! $observer) { + return EMPTY_STR; + } $parsed = parse_url($observer['xchan_url']); @@ -2732,7 +2767,7 @@ 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); } @@ -2753,13 +2788,13 @@ 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; } @@ -2772,14 +2807,14 @@ 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) { + 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) { + if ($r) { logger('found another site that is not dead: ' . $r[0]['hubloc_url'], LOGGER_DEBUG,LOG_INFO); $desturl = $r[0]['hubloc_url']; } @@ -2789,8 +2824,9 @@ class Libzot { } $them = [ 'hubloc_id_url' => $desturl ]; - if(self::refresh($them)) + if (self::refresh($them)) { return $hash; + } return false; } @@ -2810,14 +2846,12 @@ class Libzot { $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']; - } else { @@ -2829,31 +2863,29 @@ 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), dbesc($zaddr) ); } - else { /** @@ -2869,7 +2901,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"); } @@ -2880,7 +2912,7 @@ class Libzot { return($ret); } - if(! $r) { + if (! $r) { $ret['message'] = 'Item not found.'; return($ret); } @@ -2896,8 +2928,9 @@ class Libzot { $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; + } // now all forums (public, restricted, and private) set the public_forum flag. So it really means "is a group" // and has nothing to do with accessibility. @@ -2905,10 +2938,10 @@ class Libzot { $channel_type = 'normal'; $role = get_pconfig($e['channel_id'],'system','permissions_role'); - if(in_array($role, ['forum','forum_restricted','repository'])) { + if (in_array($role, ['forum','forum_restricted','repository'])) { $channel_type = 'group'; } - if(in_array($role, ['collection','collection_restricted'])) { + if (in_array($role, ['collection','collection_restricted'])) { $channel_type = 'collection'; } @@ -2919,18 +2952,20 @@ class Libzot { $profile = array(); - 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'],$e['channel_timezone'])) !== '')) + if (($profile['birthday'] != '0000-00-00') && (($bd = z_birthday($p[0]['dob'],$e['channel_timezone'])) !== '')) { $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']; @@ -2942,18 +2977,19 @@ class Libzot { $profile['homepage'] = $p[0]['homepage']; $profile['hometown'] = $p[0]['hometown']; - if($p[0]['keywords']) { + 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,")) { + 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; + } } } @@ -2987,43 +3023,48 @@ class Libzot { $ret['comments'] = map_scope(PermissionLimits::Get($e['channel_id'],'post_comments')); - if($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); - if($ztarget_hash) { + if ($ztarget_hash) { $permissions['connected'] = false; $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']) + 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; } } @@ -3037,9 +3078,9 @@ class Libzot { // array of (verified) hubs this channel uses $x = self::encode_locations($e); - if($x) + if ($x) { $ret['locations'] = $x; - + } $ret['site'] = self::site_info(); call_hooks('zotinfo',$ret); @@ -3064,17 +3105,22 @@ class Libzot { $ret['site']['sitekey'] = get_config('system','pubkey'); $dirmode = get_config('system','directory_mode'); - if(($dirmode === false) || ($dirmode == DIRECTORY_MODE_NORMAL)) + 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(); @@ -3082,42 +3128,49 @@ class Libzot { // 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')); - 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')); - 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(); - require_once('include/channel.php'); $ret['site']['channels'] = channel_total(); $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; @@ -3204,8 +3257,9 @@ class Libzot { static function sign($data,$key,$alg = 'sha256') { - if(! $key) + if (! $key) { return 'no key'; + } $sig = ''; openssl_sign($data,$sig,$key,$alg); return $alg . '.' . base64url_encode($sig); @@ -3244,22 +3298,16 @@ class Libzot { static public function zot_record_preferred($arr, $check = 'hubloc_network') { - if(! $arr) { + if (! $arr) { return $arr; } - foreach($arr as $v) { + foreach ($arr as $v) { if($v[$check] === 'zot6') { - return $v; } } - return $arr[0]; - } - - - } diff --git a/Zotlabs/Lib/Libzotdir.php b/Zotlabs/Lib/Libzotdir.php index 5b592b576..d87a11d36 100644 --- a/Zotlabs/Lib/Libzotdir.php +++ b/Zotlabs/Lib/Libzotdir.php @@ -3,6 +3,8 @@ namespace Zotlabs\Lib; use Zotlabs\Lib\Libzot; +use Zotlabs\Lib\Webfinger; +use Zotlabs\Lib\Zotfinger; require_once('include/permissions.php'); @@ -83,7 +85,7 @@ class Libzotdir { if ($directory) { $j = Zotfinger::exec($directory); - if(array_path_exists('data/directory_mode',$j)) { + if (array_path_exists('data/directory_mode',$j)) { if ($j['data']['directory_mode'] === 'normal') { $isadir = false; } @@ -238,7 +240,6 @@ class Libzotdir { // for brand new directory servers, only load the last couple of days. // It will take about a month for a new directory to obtain the full current repertoire of channels. - /** @FIXME Go back and pick up earlier ratings if this is a new directory server. These do not get refreshed. */ $token = get_config('system','realm_token'); @@ -264,14 +265,17 @@ class Libzotdir { $r = q("select * from updates where ud_guid = '%s' limit 1", dbesc($t['transaction_id']) ); - if($r) + if ($r) { continue; - + } + $ud_flags = 0; if (is_array($t['flags']) && in_array('deleted',$t['flags'])) $ud_flags |= UPDATE_FLAGS_DELETED; if (is_array($t['flags']) && in_array('forced',$t['flags'])) $ud_flags |= UPDATE_FLAGS_FORCED; + if (is_array($t['flags']) && in_array('censored',$t['flags'])) + $ud_flags |= UPDATE_FLAGS_CENSORED; $z = q("insert into updates ( ud_hash, ud_guid, ud_date, ud_flags, ud_addr ) values ( '%s', '%s', '%s', %d, '%s' ) ", @@ -308,9 +312,9 @@ class Libzotdir { if ($ud['ud_addr'] && (! ($ud['ud_flags'] & UPDATE_FLAGS_DELETED))) { $success = false; - $href = \Zotlabs\Lib\Webfinger::zot_url(punify($ud['ud_addr'])); + $href = Webfinger::zot_url(punify($ud['ud_addr'])); if($href) { - $zf = \Zotlabs\Lib\Zotfinger::exec($href); + $zf = Zotfinger::exec($href); } if(is_array($zf) && array_path_exists('signature/signer',$zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) { $xc = Libzot::import_xchan($zf['data'], 0, $ud); @@ -340,7 +344,7 @@ class Libzotdir { logger('local_dir_update: uid: ' . $uid, LOGGER_DEBUG); - $p = q("select channel.channel_hash, channel_address, channel_timezone, profile.* from profile left join channel on channel_id = uid where uid = %d and is_default = 1", + $p = q("select channel_hash, channel_address, channel_timezone, profile.* from profile left join channel on channel_id = uid where uid = %d and is_default = 1", intval($uid) ); @@ -380,7 +384,7 @@ class Libzotdir { $hidden = (1 - intval($p[0]['publish'])); - logger('hidden: ' . $hidden); + // logger('hidden: ' . $hidden); $r = q("select xchan_hidden from xchan where xchan_hash = '%s' limit 1", dbesc($p[0]['channel_hash']) @@ -550,10 +554,11 @@ class Libzotdir { } $d = [ - 'xprof' => $arr, + 'xprof' => $arr, 'profile' => $profile, - 'update' => $update + 'update' => $update ]; + /** * @hooks import_directory_profile * Called when processing delivery of a profile structure from an external source (usually for directory storage). @@ -561,11 +566,13 @@ class Libzotdir { * * \e array \b profile * * \e boolean \b update */ + call_hooks('import_directory_profile', $d); - if (($d['update']) && (! $suppress_update)) - self::update_modtime($arr['xprof_hash'],random_string() . '@' . \App::get_hostname(), $addr, $ud_flags); - + if (($d['update']) && (! $suppress_update)) { + self::update_modtime($arr['xprof_hash'], new_uuid(), $addr, $ud_flags); + } + return $d['update']; } @@ -639,7 +646,7 @@ class Libzotdir { ); } else { - q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and not (ud_flags & %d)>0 ", + q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and (ud_flags & %d) = 0 ", intval(UPDATE_FLAGS_UPDATED), dbesc($addr), intval(UPDATE_FLAGS_UPDATED) diff --git a/Zotlabs/Lib/Permcat.php b/Zotlabs/Lib/Permcat.php index 5430ea063..92f69cdbd 100644 --- a/Zotlabs/Lib/Permcat.php +++ b/Zotlabs/Lib/Permcat.php @@ -20,6 +20,7 @@ use Zotlabs\Access\Permissions; * content ACLs are evaluated (@ref ::Zotlabs::Access::AccessList "AccessList"). * These answer the question "Can Joe view *this* album/photo?". */ + class Permcat { /** diff --git a/Zotlabs/Lib/Share.php b/Zotlabs/Lib/Share.php index 3e73d039f..6cf1c645c 100644 --- a/Zotlabs/Lib/Share.php +++ b/Zotlabs/Lib/Share.php @@ -64,7 +64,7 @@ class Share { $obj['content'] = bbcode($this->item['body']); $obj['source'] = [ 'mediaType' => $this->item['mimetype'], - 'content' => $this->item['body'] + 'content' => $this->item['body'] ]; $obj['name'] = $this->item['title']; @@ -102,13 +102,14 @@ class Share { $pos = strpos($this->item['body'], "[share"); $bb = substr($this->item['body'], $pos); } else { - $bb = "[share author='".urlencode($this->item['author']['xchan_name']). - "' profile='" . $this->item['author']['xchan_url'] . - "' avatar='" . $this->item['author']['xchan_photo_s'] . - "' link='" . $this->item['plink'] . - "' auth='" . (($this->item['author']['network'] === 'zot') ? 'true' : 'false') . - "' posted='" . $this->item['created'] . - "' message_id='" . $this->item['mid'] . + $bb = "[share author='" . urlencode($this->item['author']['xchan_name']). + "' profile='" . $this->item['author']['xchan_url'] . + "' portable_id='" . $this->item['author']['xchan_hash'] . + "' avatar='" . $this->item['author']['xchan_photo_s'] . + "' link='" . $this->item['plink'] . + "' auth='" . (($this->item['author']['network'] === 'zot') ? 'true' : 'false') . + "' posted='" . $this->item['created'] . + "' message_id='" . $this->item['mid'] . "']"; if($this->item['title']) $bb .= '[b]'.$this->item['title'].'[/b]'."\r\n"; diff --git a/Zotlabs/Lib/System.php b/Zotlabs/Lib/System.php index c8e28689e..f2f9e946c 100644 --- a/Zotlabs/Lib/System.php +++ b/Zotlabs/Lib/System.php @@ -28,15 +28,11 @@ class System { } static public function get_project_icon() { + if(is_array(App::$config) && is_array(App::$config['system']) && array_key_exists('icon',App::$config['system'])) { + return App::$config['system']['icon']; + } + return z_root() . '/images/z-64.png'; - return z_root() . '/images/zap4-64.png'; - - if(defined('NOMADIC')) { - return '⚡'; - } - else { - return '☸'; - } } diff --git a/Zotlabs/Lib/Techlevels.php b/Zotlabs/Lib/Techlevels.php deleted file mode 100644 index 380901678..000000000 --- a/Zotlabs/Lib/Techlevels.php +++ /dev/null @@ -1,21 +0,0 @@ - t('0. Beginner/Basic'), - '1' => t('1. Novice - not skilled but willing to learn'), - '2' => t('2. Intermediate - somewhat comfortable'), - '3' => t('3. Advanced - very comfortable'), - '4' => t('4. Expert - I can write computer code'), - '5' => t('5. Wizard - I probably know more than you do') - ]; - return $techlevels; - } - -} - diff --git a/Zotlabs/Module/Admin/Account_edit.php b/Zotlabs/Module/Admin/Account_edit.php index 6dfadf183..d9156c744 100644 --- a/Zotlabs/Module/Admin/Account_edit.php +++ b/Zotlabs/Module/Admin/Account_edit.php @@ -31,13 +31,11 @@ class Account_edit { } $service_class = trim($_REQUEST['service_class']); - $account_level = intval(trim($_REQUEST['account_level'])); $account_language = trim($_REQUEST['account_language']); - $r = q("update account set account_service_class = '%s', account_level = %d, account_language = '%s' + $r = q("update account set account_service_class = '%s', account_language = '%s' where account_id = %d", dbesc($service_class), - intval($account_level), dbesc($account_language), intval($account_id) ); @@ -68,7 +66,6 @@ class Account_edit { '$title' => t('Account Edit'), '$pass1' => [ 'pass1', t('New Password'), ' ','' ], '$pass2' => [ 'pass2', t('New Password again'), ' ','' ], - '$account_level' => [ 'account_level', t('Technical skill level'), $x[0]['account_level'], '', \Zotlabs\Lib\Techlevels::levels() ], '$account_language' => [ 'account_language' , t('Account language (for emails)'), $x[0]['account_language'], '', language_list() ], '$service_class' => [ 'service_class', t('Service class'), $x[0]['account_service_class'], '' ], '$submit' => t('Submit'), diff --git a/Zotlabs/Module/Admin/Security.php b/Zotlabs/Module/Admin/Security.php index efb9a6ea6..f8186f45d 100644 --- a/Zotlabs/Module/Admin/Security.php +++ b/Zotlabs/Module/Admin/Security.php @@ -123,7 +123,7 @@ class Security { '$page' => t('Security'), '$form_security_token' => get_form_security_token('admin_security'), '$block_public' => array('block_public', t("Block public"), get_config('system','block_public'), t("Check to block public access to all otherwise public personal pages on this site unless you are currently authenticated.")), - '$block_public_search' => array('block_public_search', t("Block public search"), get_config('system','block_public_search'), t("Prevent access to search content unless you are currently authenticated.")), + '$block_public_search' => array('block_public_search', t("Block public search"), get_config('system','block_public_search', 1), t("Prevent access to search content unless you are currently authenticated.")), '$localdir_hide' => [ 'localdir_hide', t('Hide local directory'), intval(get_config('system','localdir_hide')), t('Only use the global directory') ], '$cloud_noroot' => [ 'cloud_noroot', t('Provide a cloud root directory'), 1 - intval(get_config('system','cloud_disable_siteroot')), t('The cloud root directory lists all channel names which provide public files') ], '$cloud_disksize' => [ 'cloud_disksize', t('Show total disk space available to cloud uploads'), intval(get_config('system','cloud_report_disksize')), '' ], diff --git a/Zotlabs/Module/Ap_probe.php b/Zotlabs/Module/Ap_probe.php index e4ce1fe8d..ce5aa8177 100644 --- a/Zotlabs/Module/Ap_probe.php +++ b/Zotlabs/Module/Ap_probe.php @@ -1,59 +1,41 @@ ActivityPub Probe Diagnostic'; - - $o .= '
'; - $o .= 'Lookup URI:
'; - $o .= 'or paste text:
'; - $o .= '
'; - - $o .= '

'; - - if(x($_REQUEST,'addr')) { - $addr = $_REQUEST['addr']; - $headers = 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams", application/activity+json, application/ld+json'; + $channel = null; + $o = replace_macros(get_markup_template('ap_probe.tpl'), [ + '$page_title' => t('ActivityPub Probe Diagnostic'), + '$resource' => [ 'resource', t('Object URL') , $_REQUEST['resource'], EMPTY_STR ], + '$authf' => [ 'authf', t('Authenticated fetch'), $_REQUEST['authf'], EMPTY_STR, [ t('No'), t('Yes') ] ], + '$submit' => t('Submit') + ]); - $redirects = 0; - $x = z_fetch_url($addr,true,$redirects, [ 'headers' => [ $headers ]]); - if($x['success']) - - $o .= '
' . htmlspecialchars($x['header']) . '
' . EOL; - - - $o .= '
' . htmlspecialchars($x['body']) . '
' . EOL; - - $o .= 'verify returns: ' . str_replace("\n",EOL,print_r(HTTPSig::verify($x),true)) . EOL; - $text = $x['body']; - } - else { - $text = $_REQUEST['text']; + if (x($_REQUEST,'resource')) { + $resource = $_REQUEST['resource']; + if ($_REQUEST['authf']) { + $channel = App::get_channel(); + if (! $channel) { + $channel = get_sys_channel(); + } } - if($text) { + $x = Activity::fetch($resource,$channel); -// if($text && json_decode($text)) { -// $normalized1 = jsonld_normalize(json_decode($text),[ 'algorithm' => 'URDNA2015', 'format' => 'application/nquads' ]); -// $o .= str_replace("\n",EOL,htmlentities(var_export($normalized1,true))); + if ($x) { + $o .= '
' . str_replace('\\n',"\n",htmlspecialchars(json_encode($x,JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT))) . '
'; + } - // $o .= '
' . json_encode($normalized1, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . '
'; -// } - - $o .= '
' . str_replace(['\\n','\\'],["\n",''],htmlspecialchars(jindent($text))) . '
'; - - $AP = new ActivityStreams($text); - $o .= '
' . htmlspecialchars($AP->debug()) . '
'; } return $o; diff --git a/Zotlabs/Module/Apschema.php b/Zotlabs/Module/Apschema.php index 3eb4199de..996e0c0ee 100644 --- a/Zotlabs/Module/Apschema.php +++ b/Zotlabs/Module/Apschema.php @@ -22,6 +22,7 @@ class Apschema extends \Zotlabs\Web\Controller { 'topicalCollection' => 'zot:topicalCollection', 'eventRepeat' => 'zot:eventRepeat', 'emojiReaction' => 'zot:emojiReaction', + 'expires' => 'zot:expires', ] ]; diff --git a/Zotlabs/Module/Calendar.php b/Zotlabs/Module/Calendar.php new file mode 100644 index 000000000..6d39483bb --- /dev/null +++ b/Zotlabs/Module/Calendar.php @@ -0,0 +1,489 @@ +set($x[0]); + + $created = $x[0]['created']; + $edited = datetime_convert(); + } + else { + $created = $edited = datetime_convert(); + $acl->set_from_array($_POST); + } + + $post_tags = []; + $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']; + + $private = $acl->is_private(); + + $results = linkify_tags($desc, local_channel()); + + if ($results) { + // Set permissions based on tag replacements + + set_linkified_perms($results, $str_contact_allow, $str_group_allow, local_channel(), false, $private); + + foreach ($results as $result) { + $success = $result['success']; + if ($success['replaced']) { + $post_tags[] = [ + 'uid' => local_channel(), + 'ttype' => $success['termtype'], + 'otype' => TERM_OBJ_POST, + 'term' => $success['term'], + 'url' => $success['url'] + ]; + } + } + } + + + if (strlen($categories)) { + $cats = explode(',',$categories); + foreach ($cats as $cat) { + $post_tags[] = array( + 'uid' => local_channel(), + 'ttype' => TERM_CATEGORY, + 'otype' => TERM_OBJ_POST, + 'term' => trim($cat), + 'url' => $channel['xchan_url'] . '?f=&cat=' . urlencode(trim($cat)) + ); + } + } + + $datarray = [ + 'dtstart' => $start, + 'dtend' => $finish, + 'summary' => $summary, + 'description' => $desc, + 'location' => $location, + 'etype' => $type, + 'adjust' => $adjust, + 'nofinish' => $nofinish, + 'uid' => local_channel(), + 'account' => get_account_id(), + 'event_xchan' => $channel['channel_hash'], + 'allow_cid' => $str_contact_allow, + 'allow_gid' => $str_group_allow, + 'deny_cid' => $str_contact_deny, + 'deny_gid' => $str_group_deny, + 'private' => intval($private), + 'id' => $event_id, + 'created' => $created, + 'edited' => $edited + ]; + + if (intval($_REQUEST['preview'])) { + $html = format_event_html($datarray); + echo $html; + killme(); + } + + $event = event_store_event($datarray); + + if ($post_tags) { + $datarray['term'] = $post_tags; + } + + $item_id = event_store_item($datarray,$event); + + if ($item_id) { + $r = q("select * from item where id = %d", + intval($item_id) + ); + 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", + dbesc($r[0]['resource_id']), + intval($channel['channel_id']) + ); + if ($z) { + Libsync::build_sync_packet($channel['channel_id'], [ 'event_item' => [ encode_item($sync_item[0],true) ], 'event' => $z]); + } + } + } + + Master::Summon( [ 'Notifier', 'event', $item_id ] ); + killme(); + + } + + + + function get() { + + if (argc() > 2 && argv(1) == 'ical') { + $event_id = argv(2); + + $sql_extra = permissions_sql(local_channel()); + + $r = q("select * from event where event_hash = '%s' $sql_extra limit 1", + dbesc($event_id) + ); + if ($r) { + header('Content-type: text/calendar'); + header('content-disposition: attachment; filename="' . t('event') . '-' . $event_id . '.ics"' ); + echo ical_wrapper($r); + killme(); + } + else { + notice( t('Event not found.') . EOL ); + return; + } + } + + 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", + 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() > 1) { + if (argc() > 2 && argv(1) === 'add') { + $mode = 'add'; + $item_id = intval(argv(2)); + } + if (argc() > 2 && argv(1) === 'drop') { + $mode = 'drop'; + $event_id = argv(2); + } + if (argc() <= 2 && argv(1) === 'export') { + $export = true; + } + if (argc() > 2 && intval(argv(1)) && intval(argv(2))) { + $mode = 'view'; + } + if(argc() <= 2) { + $mode = 'view'; + $event_id = argv(1); + } + } + + if ($mode === 'add') { + event_addtocal($item_id,local_channel()); + killme(); + } + + if ($mode == 'view') { + + /* edit/create form */ + if ($event_id) { + $r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1", + dbesc($event_id), + intval(local_channel()) + ); + if ($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']; + } + } + + $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 + 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) { + $r = q("SELECT * from event where uid = %d", + intval(local_channel()) + ); + } + else { + // fixed an issue with "nofinish" events not showing up in the calendar. + // There's still an issue if the finish date crosses the end of month. + // Noting this for now - it will need to be fixed here and in Friendica. + // Ultimately the finish date shouldn't be involved in the query. + + $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 event.event_hash = item.resource_id + where item.resource_type = 'event' and event.uid = %d and event.uid = item.uid $ignored + AND (( event.adjust = 0 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' ) + OR ( event.adjust = 1 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' )) ", + intval(local_channel()), + dbesc($start), + dbesc($finish), + dbesc($adjust_start), + dbesc($adjust_finish) + ); + + } + + if($r && ! $export) { + xchan_query($r); + $r = fetch_post_tags($r,true); + + $r = sort_by_date($r); + } + + $events = []; + + 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']) { + $end = null; + } + else { + $end = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtend'], 'c') : datetime_convert('UTC','UTC',$rr['dtend'],'c')); + + // give a fake end to birthdays so they get crammed into a + // single day on the calendar + + if ($rr['etype'] === 'birthday') + $end = null; + } + + $catsenabled = Apps::system_app_installed($x['profile_uid'], 'Categories'); + $categories = ''; + if ($catsenabled){ + if ($rr['term']) { + $categories = array_elm_to_str(get_terms_oftype($rr['term'], TERM_CATEGORY), 'term'); + } + } + + $allDay = false; + + // allDay event rules + if (!strpos($start, 'T') && !strpos($end, 'T')) + $allDay = true; + if (strpos($start, 'T00:00:00') && strpos($end, 'T00:00:00')) + $allDay = true; + + $edit = ((local_channel() && $rr['author_xchan'] == get_observer_hash()) ? array(z_root().'/events/'.$rr['event_hash'].'?expandform=1',t('Edit event'),'','') : false); + + $drop = [ z_root() . '/events/drop/' . $rr['event_hash'], t('Delete event'), '', '' ]; + + $events[] = [ + 'calendar_id' => 'calendar', + 'rw' => true, + 'id' => $rr['id'], + 'uri' => $rr['event_hash'], + 'start' => $start, + 'end' => $end, + 'drop' => $drop, + 'allDay' => $allDay, + 'title' => htmlentities($rr['summary'], ENT_COMPAT, 'UTF-8'), + 'editable' => $edit ? true : false, + 'item' => $rr, + 'plink' => [ $rr['plink'], t('Link to source') ], + 'description' => htmlentities($rr['description'], ENT_COMPAT, 'UTF-8'), + 'location' => htmlentities($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) { + header('Content-type: text/calendar'); + header('content-disposition: attachment; filename="' . t('calendar') . '-' . $channel['channel_address'] . '.ics"' ); + echo ical_wrapper($r); + killme(); + } + + if (App::$argv[1] === 'json'){ + json_return_and_die($events); + } + } + + + 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) { + $r = q("delete from event where event_hash = '%s' and uid = %d", + dbesc($event_id), + intval(local_channel()) + ); + if ($r) { + $r = q("update item set resource_type = '', resource_id = '' where resource_type = 'event' and resource_id = '%s' and uid = %d", + dbesc($event_id), + intval(local_channel()) + ); + $sync_event['event_deleted'] = 1; + Libsync::build_sync_packet(0, [ 'event' => [ $sync_event ] ]); + killme(); + } + notice( t('Failed to remove event' ) . EOL); + killme(); + } + } + + } + +} diff --git a/Zotlabs/Module/Cdav.php b/Zotlabs/Module/Cdav.php index bff308dfa..40626e5bb 100644 --- a/Zotlabs/Module/Cdav.php +++ b/Zotlabs/Module/Cdav.php @@ -2,11 +2,15 @@ namespace Zotlabs\Module; use App; +use DBA; +use DateTime; use Zotlabs\Lib\Apps; use Zotlabs\Web\Controller; +use Zotlabs\Web\HTTPSig; +use Zotlabs\Storage\BasicAuth; +use Zotlabs\Lib\System; require_once('include/event.php'); - require_once('include/auth.php'); require_once('include/security.php'); @@ -41,7 +45,7 @@ class Cdav extends Controller { continue; } - $sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]); + $sigblock = HTTPSig::parse_sigheader($_SERVER[$head]); if($sigblock) { $keyId = str_replace('acct:','',$sigblock['keyId']); if($keyId) { @@ -64,7 +68,7 @@ class Cdav extends Controller { continue; if($record) { - $verified = \Zotlabs\Web\HTTPSig::verify('',$record['channel']['channel_pubkey']); + $verified = HTTPSig::verify('',$record['channel']['channel_pubkey']); if(! ($verified && $verified['header_signed'] && $verified['header_valid'])) { $record = null; } @@ -114,7 +118,7 @@ class Cdav extends Controller { * */ - $pdo = \DBA::$dba->db; + $pdo = DBA::$dba->db; // Autoloader require_once 'vendor/autoload.php'; @@ -126,18 +130,14 @@ class Cdav extends Controller { * own backend systems. */ - $auth = new \Zotlabs\Storage\BasicAuth(); - $auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . 'CalDAV/CardDAV'); + $auth = new BasicAuth(); + $auth->setRealm(ucfirst(System::get_platform_name()) . ' ' . 'CalDAV/CardDAV'); if (local_channel()) { logger('loggedin'); - if((argv(1) == 'calendars') && (!Apps::system_app_installed(local_channel(), 'CalDAV'))) { - killme(); - } - - if((argv(1) == 'addressbooks') && (!Apps::system_app_installed(local_channel(), 'CardDAV'))) { + if ((argv(1) == 'addressbooks') && (! Apps::system_app_installed(local_channel(), 'CardDAV'))) { killme(); } @@ -146,14 +146,15 @@ class Cdav extends Controller { $auth->channel_id = $channel['channel_id']; $auth->channel_hash = $channel['channel_hash']; $auth->channel_account_id = $channel['channel_account_id']; - if($channel['channel_timezone']) + if ($channel['channel_timezone']) { $auth->setTimezone($channel['channel_timezone']); + } $auth->observer = $channel['channel_hash']; $principalUri = 'principals/' . $channel['channel_address']; - if(!cdav_principal($principalUri)) { + if (!cdav_principal($principalUri)) { $this->activate($pdo, $channel); - if(!cdav_principal($principalUri)) { + if (!cdav_principal($principalUri)) { return; } } @@ -188,8 +189,9 @@ class Cdav extends Controller { $server = new \Sabre\DAV\Server($nodes); - if(isset($baseUri)) + if (isset($baseUri)) { $server->setBaseUri($baseUri); + } // Plugins $server->addPlugin(new \Sabre\DAV\Auth\Plugin($auth)); @@ -218,34 +220,31 @@ class Cdav extends Controller { } function post() { - if(! local_channel()) + + if (! local_channel()) return; - if((argv(1) === 'calendar') && (! Apps::system_app_installed(local_channel(), 'CalDAV'))) { - return; - } - - if((argv(1) === 'addressbook') && (! Apps::system_app_installed(local_channel(), 'CardDAV'))) { + if ((argv(1) === 'addressbook') && (! Apps::system_app_installed(local_channel(), 'CardDAV'))) { return; } $channel = App::get_channel(); $principalUri = 'principals/' . $channel['channel_address']; - if(!cdav_principal($principalUri)) + if (!cdav_principal($principalUri)) return; - $pdo = \DBA::$dba->db; + $pdo = DBA::$dba->db; require_once 'vendor/autoload.php'; - if(argc() == 2 && argv(1) === 'calendar') { + if (argc() == 2 && argv(1) === 'calendar') { $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo); $calendars = $caldavBackend->getCalendarsForUser($principalUri); - //create new calendar - if($_REQUEST['{DAV:}displayname'] && $_REQUEST['create']) { + // create new calendar + if ($_REQUEST['{DAV:}displayname'] && $_REQUEST['create']) { do { $duplicate = false; $calendarUri = random_string(40); @@ -255,8 +254,9 @@ class Cdav extends Controller { dbesc($calendarUri) ); - if (count($r)) + if ($r) { $duplicate = true; + } } while ($duplicate == true); $properties = [ @@ -272,17 +272,20 @@ class Cdav extends Controller { } //create new calendar object via ajax request - if($_REQUEST['submit'] === 'create_event' && $_REQUEST['title'] && $_REQUEST['target'] && $_REQUEST['dtstart']) { + if ($_REQUEST['submit'] === 'create_event' && $_REQUEST['title'] && $_REQUEST['target'] && $_REQUEST['dtstart']) { $id = explode(':', $_REQUEST['target']); - if(!cdav_perms($id[0],$calendars,true)) + if (!cdav_perms($id[0],$calendars,true)) return; $title = $_REQUEST['title']; - $dtstart = new \DateTime($_REQUEST['dtstart']); - if($_REQUEST['dtend']) - $dtend = new \DateTime($_REQUEST['dtend']); + $start = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtstart']); + $dtstart = new DateTime($start); + if ($_REQUEST['dtend']) { + $end = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtend']); + $dtend = new DateTime($end); + } $description = $_REQUEST['description']; $location = $_REQUEST['location']; @@ -306,13 +309,17 @@ class Cdav extends Controller { 'DTSTART' => $dtstart ] ]); - if($dtend) + if($dtend) { $vcalendar->VEVENT->add('DTEND', $dtend); + $vcalendar->VEVENT->DTEND['TZID'] = App::$timezone; + } if($description) $vcalendar->VEVENT->add('DESCRIPTION', $description); if($location) $vcalendar->VEVENT->add('LOCATION', $location); + $vcalendar->VEVENT->DTSTART['TZID'] = App::$timezone; + $calendarData = $vcalendar->serialize(); $caldavBackend->createCalendarObject($id, $objectUri, $calendarData); @@ -320,13 +327,14 @@ class Cdav extends Controller { killme(); } - //edit calendar name and color - if($_REQUEST['{DAV:}displayname'] && $_REQUEST['edit'] && $_REQUEST['id']) { + // edit calendar name and color + if ($_REQUEST['{DAV:}displayname'] && $_REQUEST['edit'] && $_REQUEST['id']) { $id = explode(':', $_REQUEST['id']); - if(! cdav_perms($id[0],$calendars)) + if (! cdav_perms($id[0],$calendars)) { return; + } $mutations = [ '{DAV:}displayname' => $_REQUEST['{DAV:}displayname'], @@ -338,21 +346,24 @@ class Cdav extends Controller { $caldavBackend->updateCalendar($id, $patch); $patch->commit(); - } - //edit calendar object via ajax request - if($_REQUEST['submit'] === 'update_event' && $_REQUEST['uri'] && $_REQUEST['title'] && $_REQUEST['target'] && $_REQUEST['dtstart']) { + // edit calendar object via ajax request + if ($_REQUEST['submit'] === 'update_event' && $_REQUEST['uri'] && $_REQUEST['title'] && $_REQUEST['target'] && $_REQUEST['dtstart']) { $id = explode(':', $_REQUEST['target']); - if(!cdav_perms($id[0],$calendars,true)) + if (!cdav_perms($id[0],$calendars,true)) return; $uri = $_REQUEST['uri']; $title = $_REQUEST['title']; - $dtstart = new \DateTime($_REQUEST['dtstart']); - $dtend = $_REQUEST['dtend'] ? new \DateTime($_REQUEST['dtend']) : ''; + $start = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtstart']); + $dtstart = new DateTime($start); + if ($_REQUEST['dtend']) { + $end = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtend']); + $dtend = new DateTime($end); + } $description = $_REQUEST['description']; $location = $_REQUEST['location']; @@ -360,61 +371,71 @@ class Cdav extends Controller { $vcalendar = \Sabre\VObject\Reader::read($object['calendardata']); - if($title) + if ($title) { $vcalendar->VEVENT->SUMMARY = $title; - if($dtstart) + } + if ($dtstart) { $vcalendar->VEVENT->DTSTART = $dtstart; - if($dtend) + } + if ($dtend) { $vcalendar->VEVENT->DTEND = $dtend; - else + } + else { unset($vcalendar->VEVENT->DTEND); - if($description) + } + if ($description) { $vcalendar->VEVENT->DESCRIPTION = $description; - if($location) + } + if ($location) { $vcalendar->VEVENT->LOCATION = $location; + } $calendarData = $vcalendar->serialize(); $caldavBackend->updateCalendarObject($id, $uri, $calendarData); - killme(); } - //delete calendar object via ajax request - if($_REQUEST['delete'] && $_REQUEST['uri'] && $_REQUEST['target']) { + // delete calendar object via ajax request + if ($_REQUEST['delete'] && $_REQUEST['uri'] && $_REQUEST['target']) { $id = explode(':', $_REQUEST['target']); - if(!cdav_perms($id[0],$calendars,true)) + if (!cdav_perms($id[0],$calendars,true)) { return; + } $uri = $_REQUEST['uri']; $caldavBackend->deleteCalendarObject($id, $uri); - killme(); } - //edit calendar object date/timeme via ajax request (drag and drop) - if($_REQUEST['update'] && $_REQUEST['id'] && $_REQUEST['uri']) { + // edit calendar object date/timeme via ajax request (drag and drop) + if ($_REQUEST['update'] && $_REQUEST['id'] && $_REQUEST['uri']) { $id = [$_REQUEST['id'][0], $_REQUEST['id'][1]]; - if(!cdav_perms($id[0],$calendars,true)) + if (! cdav_perms($id[0],$calendars,true)) { return; + } $uri = $_REQUEST['uri']; - $dtstart = new \DateTime($_REQUEST['dtstart']); - $dtend = $_REQUEST['dtend'] ? new \DateTime($_REQUEST['dtend']) : ''; + $start = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtstart']); + $dtstart = new DateTime($start); + if($_REQUEST['dtend']) { + $end = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtend']); + $dtend = new DateTime($end); + } $object = $caldavBackend->getCalendarObject($id, $uri); $vcalendar = \Sabre\VObject\Reader::read($object['calendardata']); - if($dtstart) { + if ($dtstart) { $vcalendar->VEVENT->DTSTART = $dtstart; } - if($dtend) { + if ($dtend) { $vcalendar->VEVENT->DTEND = $dtend; } else { @@ -428,13 +449,14 @@ class Cdav extends Controller { killme(); } - //share a calendar - this only works on local system (with channels on the same server) - if($_REQUEST['sharee'] && $_REQUEST['share']) { + // share a calendar - this only works on local system (with channels on the same server) + if ($_REQUEST['sharee'] && $_REQUEST['share']) { $id = [intval($_REQUEST['calendarid']), intval($_REQUEST['instanceid'])]; - if(! cdav_perms($id[0],$calendars)) + if (! cdav_perms($id[0],$calendars)) { return; + } $hash = $_REQUEST['sharee']; @@ -451,13 +473,13 @@ class Cdav extends Controller { } } - if(argc() >= 2 && argv(1) === 'addressbook') { + if (argc() >= 2 && argv(1) === 'addressbook') { $carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo); $addressbooks = $carddavBackend->getAddressBooksForUser($principalUri); - //create new addressbook - if($_REQUEST['{DAV:}displayname'] && $_REQUEST['create']) { + // create new addressbook + if ($_REQUEST['{DAV:}displayname'] && $_REQUEST['create']) { do { $duplicate = false; $addressbookUri = random_string(20); @@ -467,8 +489,9 @@ class Cdav extends Controller { dbesc($addressbookUri) ); - if (count($r)) + if ($r) { $duplicate = true; + } } while ($duplicate == true); $properties = ['{DAV:}displayname' => $_REQUEST['{DAV:}displayname']]; @@ -476,13 +499,14 @@ class Cdav extends Controller { $carddavBackend->createAddressBook($principalUri, $addressbookUri, $properties); } - //edit addressbook - if($_REQUEST['{DAV:}displayname'] && $_REQUEST['edit'] && intval($_REQUEST['id'])) { + // edit addressbook + if ($_REQUEST['{DAV:}displayname'] && $_REQUEST['edit'] && intval($_REQUEST['id'])) { $id = $_REQUEST['id']; - if(! cdav_perms($id,$addressbooks)) + if (! cdav_perms($id,$addressbooks)) { return; + } $mutations = [ '{DAV:}displayname' => $_REQUEST['{DAV:}displayname'] @@ -495,8 +519,8 @@ class Cdav extends Controller { $patch->commit(); } - //create addressbook card - if($_REQUEST['create'] && $_REQUEST['target'] && $_REQUEST['fn']) { + // create addressbook card + if ($_REQUEST['create'] && $_REQUEST['target'] && $_REQUEST['fn']) { $id = $_REQUEST['target']; do { @@ -508,11 +532,13 @@ class Cdav extends Controller { dbesc($uri) ); - if (count($r)) + if ($r) { $duplicate = true; + } } while ($duplicate == true); - //TODO: this mostly duplictes the procedure in update addressbook card. should move this part to a function to avoid duplication + // TODO: this mostly duplictes the procedure in update addressbook card. + // Should move this part to a function to avoid duplication $fn = $_REQUEST['fn']; $vcard = new \Sabre\VObject\Component\VCard([ @@ -521,21 +547,21 @@ class Cdav extends Controller { ]); $org = $_REQUEST['org']; - if($org) { + if ($org) { $vcard->ORG = $org; } $title = $_REQUEST['title']; - if($title) { + if ($title) { $vcard->TITLE = $title; } $tel = $_REQUEST['tel']; $tel_type = $_REQUEST['tel_type']; - if($tel) { + if ($tel) { $i = 0; - foreach($tel as $item) { - if($item) { + foreach ($tel as $item) { + if ($item) { $vcard->add('TEL', $item, ['type' => $tel_type[$i]]); } $i++; @@ -544,10 +570,10 @@ class Cdav extends Controller { $email = $_REQUEST['email']; $email_type = $_REQUEST['email_type']; - if($email) { + if ($email) { $i = 0; - foreach($email as $item) { - if($item) { + foreach ($email as $item) { + if ($item) { $vcard->add('EMAIL', $item, ['type' => $email_type[$i]]); } $i++; @@ -556,10 +582,10 @@ class Cdav extends Controller { $impp = $_REQUEST['impp']; $impp_type = $_REQUEST['impp_type']; - if($impp) { + if ($impp) { $i = 0; - foreach($impp as $item) { - if($item) { + foreach ($impp as $item) { + if ($item) { $vcard->add('IMPP', $item, ['type' => $impp_type[$i]]); } $i++; @@ -568,10 +594,10 @@ class Cdav extends Controller { $url = $_REQUEST['url']; $url_type = $_REQUEST['url_type']; - if($url) { + if ($url) { $i = 0; - foreach($url as $item) { - if($item) { + foreach ($url as $item) { + if ($item) { $vcard->add('URL', $item, ['type' => $url_type[$i]]); } $i++; @@ -581,10 +607,10 @@ class Cdav extends Controller { $adr = $_REQUEST['adr']; $adr_type = $_REQUEST['adr_type']; - if($adr) { + if ($adr) { $i = 0; - foreach($adr as $item) { - if($item) { + foreach ($adr as $item) { + if ($item) { $vcard->add('ADR', $item, ['type' => $adr_type[$i]]); } $i++; @@ -592,7 +618,7 @@ class Cdav extends Controller { } $note = $_REQUEST['note']; - if($note) { + if ($note) { $vcard->NOTE = $note; } @@ -602,13 +628,14 @@ class Cdav extends Controller { } - //edit addressbook card - if($_REQUEST['update'] && $_REQUEST['uri'] && $_REQUEST['target']) { + // edit addressbook card + if ($_REQUEST['update'] && $_REQUEST['uri'] && $_REQUEST['target']) { $id = $_REQUEST['target']; - if(!cdav_perms($id,$addressbooks)) + if (!cdav_perms($id,$addressbooks)) { return; + } $uri = $_REQUEST['uri']; @@ -616,13 +643,13 @@ class Cdav extends Controller { $vcard = \Sabre\VObject\Reader::read($object['carddata']); $fn = $_REQUEST['fn']; - if($fn) { + if ($fn) { $vcard->FN = $fn; $vcard->N = array_reverse(explode(' ', $fn)); } $org = $_REQUEST['org']; - if($org) { + if ($org) { $vcard->ORG = $org; } else { @@ -630,7 +657,7 @@ class Cdav extends Controller { } $title = $_REQUEST['title']; - if($title) { + if ($title) { $vcard->TITLE = $title; } else { @@ -639,11 +666,11 @@ class Cdav extends Controller { $tel = $_REQUEST['tel']; $tel_type = $_REQUEST['tel_type']; - if($tel) { + if ($tel) { $i = 0; unset($vcard->TEL); - foreach($tel as $item) { - if($item) { + foreach ($tel as $item) { + if ($item) { $vcard->add('TEL', $item, ['type' => $tel_type[$i]]); } $i++; @@ -655,11 +682,11 @@ class Cdav extends Controller { $email = $_REQUEST['email']; $email_type = $_REQUEST['email_type']; - if($email) { + if ($email) { $i = 0; unset($vcard->EMAIL); - foreach($email as $item) { - if($item) { + foreach ($email as $item) { + if ($item) { $vcard->add('EMAIL', $item, ['type' => $email_type[$i]]); } $i++; @@ -671,11 +698,11 @@ class Cdav extends Controller { $impp = $_REQUEST['impp']; $impp_type = $_REQUEST['impp_type']; - if($impp) { + if ($impp) { $i = 0; unset($vcard->IMPP); - foreach($impp as $item) { - if($item) { + foreach ($impp as $item) { + if ($item) { $vcard->add('IMPP', $item, ['type' => $impp_type[$i]]); } $i++; @@ -687,11 +714,11 @@ class Cdav extends Controller { $url = $_REQUEST['url']; $url_type = $_REQUEST['url_type']; - if($url) { + if ($url) { $i = 0; unset($vcard->URL); - foreach($url as $item) { - if($item) { + foreach ($url as $item) { + if ($item) { $vcard->add('URL', $item, ['type' => $url_type[$i]]); } $i++; @@ -703,11 +730,11 @@ class Cdav extends Controller { $adr = $_REQUEST['adr']; $adr_type = $_REQUEST['adr_type']; - if($adr) { + if ($adr) { $i = 0; unset($vcard->ADR); - foreach($adr as $item) { - if($item) { + foreach ($adr as $item) { + if ($item) { $vcard->add('ADR', $item, ['type' => $adr_type[$i]]); } $i++; @@ -718,7 +745,7 @@ class Cdav extends Controller { } $note = $_REQUEST['note']; - if($note) { + if ($note) { $vcard->NOTE = $note; } else { @@ -730,13 +757,14 @@ class Cdav extends Controller { $carddavBackend->updateCard($id, $uri, $cardData); } - //delete addressbook card - if($_REQUEST['delete'] && $_REQUEST['uri'] && $_REQUEST['target']) { + // delete addressbook card + if ($_REQUEST['delete'] && $_REQUEST['uri'] && $_REQUEST['target']) { $id = $_REQUEST['target']; - if(!cdav_perms($id,$addressbooks)) + if (!cdav_perms($id,$addressbooks)) { return; + } $uri = $_REQUEST['uri']; @@ -744,46 +772,59 @@ class Cdav extends Controller { } } - //Import calendar or addressbook - if(($_FILES) && array_key_exists('userfile',$_FILES) && intval($_FILES['userfile']['size']) && $_REQUEST['target']) { + // Import calendar or addressbook + if (($_FILES) && array_key_exists('userfile',$_FILES) && intval($_FILES['userfile']['size']) && $_REQUEST['target']) { - $src = @file_get_contents($_FILES['userfile']['tmp_name']); + $src = $_FILES['userfile']['tmp_name']; - if($src) { + if ($src) { + + if ($_REQUEST['c_upload']) { + if ($_REQUEST['target'] == 'calendar') { + $result = parse_ical_file($src,local_channel()); + if ($result) { + info( t('Calendar entries imported.') . EOL); + } + else { + notice( t('No calendar entries found.') . EOL); + } + + @unlink($src); + return; + } - if($_REQUEST['c_upload']) { $id = explode(':', $_REQUEST['target']); $ext = 'ics'; $table = 'calendarobjects'; $column = 'calendarid'; - $objects = new \Sabre\VObject\Splitter\ICalendar($src); + $objects = new \Sabre\VObject\Splitter\ICalendar(@file_get_contents($src)); $profile = \Sabre\VObject\Node::PROFILE_CALDAV; $backend = new \Sabre\CalDAV\Backend\PDO($pdo); } - if($_REQUEST['a_upload']) { + if ($_REQUEST['a_upload']) { $id[] = intval($_REQUEST['target']); $ext = 'vcf'; $table = 'cards'; $column = 'addressbookid'; - $objects = new \Sabre\VObject\Splitter\VCard($src); + $objects = new \Sabre\VObject\Splitter\VCard(@file_get_contents($src)); $profile = \Sabre\VObject\Node::PROFILE_CARDDAV; $backend = new \Sabre\CardDAV\Backend\PDO($pdo); } while ($object = $objects->getNext()) { - if($_REQUEST['a_upload']) { + if ($_REQUEST['a_upload']) { $object = $object->convert(\Sabre\VObject\Document::VCARD40); } $ret = $object->validate($profile & \Sabre\VObject\Node::REPAIR); - //level 3 Means that the document is invalid, - //level 2 means a warning. A warning means it's valid but it could cause interopability issues, - //level 1 means that there was a problem earlier, but the problem was automatically repaired. + // level 3 Means that the document is invalid, + // level 2 means a warning. A warning means it's valid but it could cause interopability issues, + // level 1 means that there was a problem earlier, but the problem was automatically repaired. - if($ret[0]['level'] < 3) { + if ($ret[0]['level'] < 3) { do { $duplicate = false; $objectUri = random_string(40) . '.' . $ext; @@ -793,20 +834,21 @@ class Cdav extends Controller { dbesc($objectUri) ); - if (count($r)) + if ($r) { $duplicate = true; + } } while ($duplicate == true); - if($_REQUEST['c_upload']) { + if ($_REQUEST['c_upload']) { $backend->createCalendarObject($id, $objectUri, $object->serialize()); } - if($_REQUEST['a_upload']) { + if ($_REQUEST['a_upload']) { $backend->createCard($id[0], $objectUri, $object->serialize()); } } else { - if($_REQUEST['c_upload']) { + if ($_REQUEST['c_upload']) { notice( '' . t('INVALID EVENT DISMISSED!') . '' . EOL . '' . t('Summary: ') . '' . (($object->VEVENT->SUMMARY) ? $object->VEVENT->SUMMARY : t('Unknown')) . EOL . '' . t('Date: ') . '' . (($object->VEVENT->DTSTART) ? $object->VEVENT->DTSTART : t('Unknown')) . EOL . @@ -814,7 +856,7 @@ class Cdav extends Controller { ); } - if($_REQUEST['a_upload']) { + if ($_REQUEST['a_upload']) { notice( '' . t('INVALID CARD DISMISSED!') . '' . EOL . '' . t('Name: ') . '' . (($object->FN) ? $object->FN : t('Unknown')) . EOL . '' . t('Reason: ') . '' . $ret[0]['message'] . EOL @@ -829,72 +871,128 @@ class Cdav extends Controller { function get() { - if(!local_channel()) + if (! local_channel()) { return; - - if((argv(1) === 'calendar') && (! Apps::system_app_installed(local_channel(), 'CalDAV'))) { - //Do not display any associated widgets at this point - App::$pdl = ''; - - $o = 'CalDAV App (Not Installed):
'; - $o .= t('CalDAV capable calendar'); - return $o; } - if((argv(1) === 'addressbook') && (! Apps::system_app_installed(local_channel(), 'CardDAV'))) { - //Do not display any associated widgets at this point + if ((argv(1) === 'addressbook') && (! Apps::system_app_installed(local_channel(), 'CardDAV'))) { + // Do not display any associated widgets at this point App::$pdl = ''; - $o = 'CardDAV App (Not Installed):
'; + $o = '' . t('CardDAV App') . ' (' . t('Not Installed') . '):
'; $o .= t('CalDAV capable addressbook'); return $o; } + App::$profile_uid = local_channel(); + $channel = App::get_channel(); $principalUri = 'principals/' . $channel['channel_address']; - $pdo = \DBA::$dba->db; + $pdo = DBA::$dba->db; require_once 'vendor/autoload.php'; head_add_css('cdav.css'); - if(!cdav_principal($principalUri)) { + if (! cdav_principal($principalUri)) { $this->activate($pdo, $channel); - if(!cdav_principal($principalUri)) { + if (! cdav_principal($principalUri)) { return; } } - if(argv(1) === 'calendar') { - nav_set_selected('CalDAV'); + if (argv(1) === 'calendar') { + nav_set_selected('Calendar'); $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo); $calendars = $caldavBackend->getCalendarsForUser($principalUri); } - //Display calendar(s) here - if(argc() == 2 && argv(1) === 'calendar') { + // Display calendar(s) here + if(argc() <= 3 && argv(1) === 'calendar') { - head_add_css('/library/fullcalendar/fullcalendar.css'); + head_add_css('/library/fullcalendar/packages/core/main.min.css'); + head_add_css('/library/fullcalendar/packages/daygrid/main.min.css'); + head_add_css('/library/fullcalendar/packages/timegrid/main.min.css'); + head_add_css('/library/fullcalendar/packages/list/main.min.css'); head_add_css('cdav_calendar.css'); - head_add_js('/library/moment/moment.min.js', 1); - head_add_js('/library/fullcalendar/fullcalendar.min.js', 1); - head_add_js('/library/fullcalendar/locale-all.js', 1); + head_add_js('/library/fullcalendar/packages/core/main.min.js'); + head_add_js('/library/fullcalendar/packages/interaction/main.min.js'); + head_add_js('/library/fullcalendar/packages/daygrid/main.min.js'); + head_add_js('/library/fullcalendar/packages/timegrid/main.min.js'); + head_add_js('/library/fullcalendar/packages/list/main.min.js'); - foreach($calendars as $calendar) { + $sources = ''; + $resource_id = ''; + $resource = null; + + if (argc() == 3) { + $resource_id = argv(2); + } + + if ($resource_id) { + $r = q("SELECT event.*, item.author_xchan, item.owner_xchan, item.plink, item.id as item_id FROM event LEFT JOIN item ON event.event_hash = item.resource_id + WHERE event.uid = %d AND event.event_hash = '%s' LIMIT 1", + intval(local_channel()), + dbesc($resource_id) + ); + if ($r) { + xchan_query($r); + $r = fetch_post_tags($r,true); + + $r[0]['dtstart'] = (($r[0]['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$r[0]['dtstart'], 'c') : datetime_convert('UTC','UTC',$r[0]['dtstart'],'c')); + $r[0]['dtend'] = (($r[0]['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$r[0]['dtend'], 'c') : datetime_convert('UTC','UTC',$r[0]['dtend'],'c')); + + $r[0]['plink'] = [$r[0]['plink'], t('Link to source')]; + + $resource = $r[0]; + + $catsenabled = Apps::system_app_installed(local_channel(), 'Categories'); + + $categories = ''; + if ($catsenabled){ + if($r[0]['term']) { + $categories = array_elm_to_str(get_terms_oftype($r[0]['term'], TERM_CATEGORY), 'term'); + } + } + + if ($r[0]['dismissed'] == 0) { + q("UPDATE event SET dismissed = 1 WHERE event.uid = %d AND event.event_hash = '%s'", + intval(local_channel()), + dbesc($resource_id) + ); + } + } + } + + if (get_pconfig(local_channel(), 'cdav_calendar', 'calendar')) { + $sources .= '{ + id: \'calendar\', + url: \'/calendar/json/\', + color: \'#3a87ad\' + }, '; + } + + $calendars[] = [ + 'displayname' => $channel['channel_name'], + 'id' => 'calendar' + ]; + + foreach ($calendars as $calendar) { $editable = (($calendar['share-access'] == 2) ? 'false' : 'true'); // false/true must be string since we're passing it to javascript - $color = (($calendar['{http://apple.com/ns/ical/}calendar-color']) ? $calendar['{http://apple.com/ns/ical/}calendar-color'] : '#3a87ad'); + $color = (($calendar['{http://apple.com/ns/ical/}calendar-color']) ? $calendar['{http://apple.com/ns/ical/}calendar-color'] : '#6cad39'); $sharer = (($calendar['share-access'] == 3) ? $calendar['{urn:ietf:params:xml:ns:caldav}calendar-description'] : ''); $switch = get_pconfig(local_channel(), 'cdav_calendar', $calendar['id'][0]); - if($switch) { + if ($switch) { $sources .= '{ + id: ' . $calendar['id'][0] . ', url: \'/cdav/calendar/json/' . $calendar['id'][0] . '/' . $calendar['id'][1] . '\', color: \'' . $color . '\' }, '; } - if($calendar['share-access'] != 2) { + if ($calendar['share-access'] != 2) { $writable_calendars[] = [ 'displayname' => $calendar['{DAV:}displayname'], 'sharer' => $sharer, @@ -905,19 +1003,31 @@ class Cdav extends Controller { $sources = rtrim($sources, ', '); - $first_day = get_pconfig(local_channel(),'system','cal_first_day'); + $first_day = feature_enabled(local_channel(), 'cal_first_day'); $first_day = (($first_day) ? $first_day : 0); $title = ['title', t('Event title')]; - $dtstart = ['dtstart', t('Start date and time'), '', t('Example: YYYY-MM-DD HH:mm')]; - $dtend = ['dtend', t('End date and time'), '', t('Example: YYYY-MM-DD HH:mm')]; + $dtstart = ['dtstart', t('Start date and time')]; + $dtend = ['dtend', t('End date and time')]; $description = ['description', t('Description')]; $location = ['location', t('Location')]; + $catsenabled = Apps::system_app_installed(local_channel(), 'Categories'); + + require_once('include/acl_selectors.php'); + + $accesslist = new \Zotlabs\Access\AccessControl($channel); + $perm_defaults = $accesslist->get(); + + $acl = populate_acl($perm_defaults, false, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream')); + + $permissions = $perm_defaults; + $o .= replace_macros(get_markup_template('cdav_calendar.tpl'), [ '$sources' => $sources, '$color' => $color, '$lang' => App::$language, + '$timezone' => App::$timezone, '$first_day' => $first_day, '$prev' => t('Previous'), '$next' => t('Next'), @@ -929,6 +1039,7 @@ class Cdav extends Controller { '$list_week' => t('List week'), '$list_day' => t('List day'), '$title' => $title, + '$calendars' => $calendars, '$writable_calendars' => $writable_calendars, '$dtstart' => $dtstart, '$dtend' => $dtend, @@ -936,29 +1047,48 @@ class Cdav extends Controller { '$location' => $location, '$more' => t('More'), '$less' => t('Less'), + '$update' => t('Update'), '$calendar_select_label' => t('Select calendar'), + '$calendar_optiopns_label' => [t('Channel Calendars'), t('CalDAV Calendars')], '$delete' => t('Delete'), '$delete_all' => t('Delete all'), '$cancel' => t('Cancel'), - '$recurrence_warning' => t('Sorry! Editing of recurrent events is not yet implemented.') + '$create' => t('Create'), + '$recurrence_warning' => t('Sorry! Editing of recurrent events is not yet implemented.'), + '$channel_hash' => $channel['channel_hash'], + '$acl' => $acl, + '$lockstate' => (($accesslist->is_private()) ? 'lock' : 'unlock'), + '$allow_cid' => acl2json($permissions['allow_cid']), + '$allow_gid' => acl2json($permissions['allow_gid']), + '$deny_cid' => acl2json($permissions['deny_cid']), + '$deny_gid' => acl2json($permissions['deny_gid']), + '$catsenabled' => $catsenabled, + '$categories_label' => t('Categories'), + '$resource' => json_encode($resource), + '$categories' => $categories ]); return $o; } - //Provide json data for calendar - if(argc() == 5 && argv(1) === 'calendar' && argv(2) === 'json' && intval(argv(3)) && intval(argv(4))) { + // Provide json data for calendar + if (argc() == 5 && argv(1) === 'calendar' && argv(2) === 'json' && intval(argv(3)) && intval(argv(4))) { + + $events = []; $id = [argv(3), argv(4)]; - if(! cdav_perms($id[0],$calendars)) - killme(); + if (! cdav_perms($id[0],$calendars)) { + json_return_and_die($events); + } - if (x($_GET,'start')) + if (x($_GET,'start')) { $start = new \DateTime($_GET['start']); - if (x($_GET,'end')) + } + if (x($_GET,'end')) { $end = new \DateTime($_GET['end']); + } $filters['name'] = 'VCALENDAR'; $filters['prop-filters'][0]['name'] = 'VEVENT'; @@ -967,46 +1097,52 @@ class Cdav extends Controller { $filters['comp-filters'][0]['time-range']['end'] = $end; $uris = $caldavBackend->calendarQuery($id, $filters); - if($uris) { + if ($uris) { $objects = $caldavBackend->getMultipleCalendarObjects($id, $uris); - - foreach($objects as $object) { + foreach ($objects as $object) { $vcalendar = \Sabre\VObject\Reader::read($object['calendardata']); - if(isset($vcalendar->VEVENT->RRULE)) + if (isset($vcalendar->VEVENT->RRULE)) { + // expanding recurrent events seems to loose timezone info + // save it here so we can add it later + $recurrent_timezone = (string)$vcalendar->VEVENT->DTSTART['TZID']; $vcalendar = $vcalendar->expand($start, $end); + } - foreach($vcalendar->VEVENT as $vevent) { + foreach ($vcalendar->VEVENT as $vevent) { $title = (string)$vevent->SUMMARY; $dtstart = (string)$vevent->DTSTART; $dtend = (string)$vevent->DTEND; $description = (string)$vevent->DESCRIPTION; $location = (string)$vevent->LOCATION; - + $timezone = (string)$vevent->DTSTART['TZID']; $rw = ((cdav_perms($id[0],$calendars,true)) ? true : false); + $editable = $rw ? true : false; $recurrent = ((isset($vevent->{'RECURRENCE-ID'})) ? true : false); - $editable = $rw ? true : false; - - if($recurrent) + if ($recurrent) { $editable = false; + $timezone = $recurrent_timezone; + } $allDay = false; // allDay event rules - if(!strpos($dtstart, 'T') && !strpos($dtend, 'T')) + if (!strpos($dtstart, 'T') && !strpos($dtend, 'T')) { $allDay = true; - if(strpos($dtstart, 'T000000') && strpos($dtend, 'T000000')) + } + if (strpos($dtstart, 'T000000') && strpos($dtend, 'T000000')) { $allDay = true; + } $events[] = [ 'calendar_id' => $id, 'uri' => $object['uri'], 'title' => $title, - 'start' => $dtstart, - 'end' => $dtend, + 'start' => datetime_convert($timezone, $timezone, $dtstart, 'c'), + 'end' => (($dtend) ? datetime_convert($timezone, $timezone, $dtend, 'c') : ''), 'description' => $description, 'location' => $location, 'allDay' => $allDay, @@ -1016,43 +1152,43 @@ class Cdav extends Controller { ]; } } - json_return_and_die($events); - } - else { - killme(); } + json_return_and_die($events); } - //enable/disable calendars - if(argc() == 5 && argv(1) === 'calendar' && argv(2) === 'switch' && intval(argv(3)) && (argv(4) == 1 || argv(4) == 0)) { + // enable/disable calendars + if (argc() == 5 && argv(1) === 'calendar' && argv(2) === 'switch' && argv(3) && (argv(4) == 1 || argv(4) == 0)) { $id = argv(3); - if(! cdav_perms($id,$calendars)) + if (! cdav_perms($id,$calendars)) { killme(); + } set_pconfig(local_channel(), 'cdav_calendar' , argv(3), argv(4)); killme(); } - //drop calendar - if(argc() == 5 && argv(1) === 'calendar' && argv(2) === 'drop' && intval(argv(3)) && intval(argv(4))) { + // drop calendar + if (argc() == 5 && argv(1) === 'calendar' && argv(2) === 'drop' && intval(argv(3)) && intval(argv(4))) { $id = [argv(3), argv(4)]; - if(! cdav_perms($id[0],$calendars)) + if (! cdav_perms($id[0],$calendars)) { killme(); + } $caldavBackend->deleteCalendar($id); killme(); } - //drop sharee - if(argc() == 6 && argv(1) === 'calendar' && argv(2) === 'dropsharee' && intval(argv(3)) && intval(argv(4))) { + // drop sharee + if (argc() == 6 && argv(1) === 'calendar' && argv(2) === 'dropsharee' && intval(argv(3)) && intval(argv(4))) { $id = [argv(3), argv(4)]; $hash = argv(5); - if(! cdav_perms($id[0],$calendars)) + if (! cdav_perms($id[0],$calendars)) { killme(); + } $sharee_arr = channelx_by_hash($hash); @@ -1067,41 +1203,42 @@ class Cdav extends Controller { } - if(argv(1) === 'addressbook') { + if (argv(1) === 'addressbook') { nav_set_selected('CardDAV'); $carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo); $addressbooks = $carddavBackend->getAddressBooksForUser($principalUri); } - //Display Adressbook here - if(argc() == 3 && argv(1) === 'addressbook' && intval(argv(2))) { + // Display Adressbook here + if (argc() == 3 && argv(1) === 'addressbook' && intval(argv(2))) { $id = argv(2); $displayname = cdav_perms($id,$addressbooks); - if(!$displayname) + if (! $displayname) { return; + } head_add_css('cdav_addressbook.css'); $o = ''; $sabrecards = $carddavBackend->getCards($id); - foreach($sabrecards as $sabrecard) { + foreach ($sabrecards as $sabrecard) { $uris[] = $sabrecard['uri']; } - if($uris) { + if ($uris) { $objects = $carddavBackend->getMultipleCards($id, $uris); - foreach($objects as $object) { + foreach ($objects as $object) { $vcard = \Sabre\VObject\Reader::read($object['carddata']); $photo = ''; - if($vcard->PHOTO) { + if ($vcard->PHOTO) { $photo_value = strtolower($vcard->PHOTO->getValueType()); // binary or uri - if($photo_value === 'binary') { + if ($photo_value === 'binary') { $photo_type = strtolower($vcard->PHOTO['TYPE']); // mime jpeg, png or gif $photo = 'data:image/' . $photo_type . ';base64,' . base64_encode((string)$vcard->PHOTO); } @@ -1112,23 +1249,23 @@ class Cdav extends Controller { } $fn = ''; - if($vcard->FN) { + if ($vcard->FN) { $fn = (string)$vcard->FN; } $org = ''; - if($vcard->ORG) { + if ($vcard->ORG) { $org = (string)$vcard->ORG; } $title = ''; - if($vcard->TITLE) { + if ($vcard->TITLE) { $title = (string)$vcard->TITLE; } $tels = []; - if($vcard->TEL) { - foreach($vcard->TEL as $tel) { + if ($vcard->TEL) { + foreach ($vcard->TEL as $tel) { $type = (($tel['TYPE']) ? translate_type((string)$tel['TYPE']) : ''); $tels[] = [ 'type' => $type, @@ -1138,8 +1275,8 @@ class Cdav extends Controller { } $emails = []; - if($vcard->EMAIL) { - foreach($vcard->EMAIL as $email) { + if ($vcard->EMAIL) { + foreach ($vcard->EMAIL as $email) { $type = (($email['TYPE']) ? translate_type((string)$email['TYPE']) : ''); $emails[] = [ 'type' => $type, @@ -1149,8 +1286,8 @@ class Cdav extends Controller { } $impps = []; - if($vcard->IMPP) { - foreach($vcard->IMPP as $impp) { + if ($vcard->IMPP) { + foreach ($vcard->IMPP as $impp) { $type = (($impp['TYPE']) ? translate_type((string)$impp['TYPE']) : ''); $impps[] = [ 'type' => $type, @@ -1160,8 +1297,8 @@ class Cdav extends Controller { } $urls = []; - if($vcard->URL) { - foreach($vcard->URL as $url) { + if ($vcard->URL) { + foreach ($vcard->URL as $url) { $type = (($url['TYPE']) ? translate_type((string)$url['TYPE']) : ''); $urls[] = [ 'type' => $type, @@ -1171,8 +1308,8 @@ class Cdav extends Controller { } $adrs = []; - if($vcard->ADR) { - foreach($vcard->ADR as $adr) { + if ($vcard->ADR) { + foreach ($vcard->ADR as $adr) { $type = (($adr['TYPE']) ? translate_type((string)$adr['TYPE']) : ''); $adrs[] = [ 'type' => $type, @@ -1182,14 +1319,13 @@ class Cdav extends Controller { } $note = ''; - if($vcard->NOTE) { + if ($vcard->NOTE) { $note = (string)$vcard->NOTE; } $cards[] = [ 'id' => $object['id'], 'uri' => $object['uri'], - 'photo' => $photo, 'fn' => $fn, 'org' => $org, @@ -1241,12 +1377,13 @@ class Cdav extends Controller { return $o; } - //delete addressbook - if(argc() > 3 && argv(1) === 'addressbook' && argv(2) === 'drop' && intval(argv(3))) { + // delete addressbook + if (argc() > 3 && argv(1) === 'addressbook' && argv(2) === 'drop' && intval(argv(3))) { $id = argv(3); - if(! cdav_perms($id,$addressbooks)) + if (! cdav_perms($id,$addressbooks)) { return; + } $carddavBackend->deleteAddressBook($id); killme(); @@ -1256,8 +1393,9 @@ class Cdav extends Controller { function activate($pdo, $channel) { - if(! $channel) + if (! $channel) { return; + } $uri = 'principals/' . $channel['channel_address']; @@ -1279,18 +1417,19 @@ class Cdav extends Controller { dbesc($channel['channel_name']) ); - //create default calendar + // create default calendar $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo); $properties = [ '{DAV:}displayname' => t('Default Calendar'), - '{http://apple.com/ns/ical/}calendar-color' => '#3a87ad', + '{http://apple.com/ns/ical/}calendar-color' => '#6cad39', '{urn:ietf:params:xml:ns:caldav}calendar-description' => $channel['channel_name'] ]; $id = $caldavBackend->createCalendar($uri, 'default', $properties); set_pconfig(local_channel(), 'cdav_calendar' , $id[0], 1); + set_pconfig(local_channel(), 'cdav_calendar' , 'calendar', 1); - //create default addressbook + // create default addressbook $carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo); $properties = ['{DAV:}displayname' => t('Default Addressbook')]; $carddavBackend->createAddressBook($uri, 'default', $properties); @@ -1298,5 +1437,4 @@ class Cdav extends Controller { } } - } diff --git a/Zotlabs/Module/Channel.php b/Zotlabs/Module/Channel.php index d778437ac..217506582 100644 --- a/Zotlabs/Module/Channel.php +++ b/Zotlabs/Module/Channel.php @@ -29,21 +29,22 @@ class Channel extends Controller { function init() { - if(in_array(substr($_GET['search'],0,1),[ '@', '!', '?'])) + if (in_array(substr($_GET['search'],0,1),[ '@', '!', '?'])) 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']) { + if ($channel && $channel['channel_address']) { $which = $channel['channel_address']; } } } - if(! $which) { + if (! $which) { notice( t('You must be logged in to see this page.') . EOL ); return; } @@ -51,13 +52,13 @@ class Channel extends Controller { $profile = 0; $channel = App::get_channel(); - if((local_channel()) && (argc() > 2) && (argv(2) === 'view')) { + 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'); } @@ -110,7 +111,8 @@ class Channel extends Controller { $x = array_merge(['@context' => [ ACTIVITYSTREAMS_JSONLD_REV, - 'https://w3id.org/security/v1' + 'https://w3id.org/security/v1', + z_root() . ZOT_APSCHEMA_REV ]], Activity::encode_person($channel,true,((defined('NOMADIC')) ? false : true))); $headers = []; @@ -248,23 +250,25 @@ 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 + * Get permissions SQL */ $item_normal = item_normal(); $item_normal_update = item_normal_update(); $sql_extra = item_permissions_sql(App::$profile['profile_uid']); - if(get_pconfig(App::$profile['profile_uid'],'system','channel_list_mode') && (! $mid)) + if (get_pconfig(App::$profile['profile_uid'],'system','channel_list_mode') && (! $mid)) { $page_mode = 'list'; - else + } + else { $page_mode = 'client'; - + } + $abook_uids = " and abook.abook_channel = " . intval(App::$profile['profile_uid']) . " "; $simple_update = (($update) ? " AND item_unseen = 1 " : ''); - if($search) { + if ($search) { $search = escape_tags($search); if(strpos($search,'#') === 0) { $sql_extra .= term_query('item',substr($search,1),TERM_HASHTAG,TERM_COMMUNITYTAG); @@ -285,17 +289,20 @@ class Channel extends Controller { 'title' => 'oembed' ]); - if($update && $_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($load) + } + if ($load) { $simple_update = ''; - - if($static && $simple_update) + } + + if ($static && $simple_update) { $simple_update .= " and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' "; + } + + 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 . '%'), @@ -319,37 +326,38 @@ class Channel extends Controller { } else { - if(x($category)) { + if (x($category)) { $sql_extra2 .= protect_sprintf(term_item_parent_query(App::$profile['profile_uid'],'item', $category, TERM_CATEGORY)); } - if(x($hashtags)) { + if (x($hashtags)) { $sql_extra2 .= protect_sprintf(term_item_parent_query(App::$profile['profile_uid'],'item', $hashtags, TERM_HASHTAG, TERM_COMMUNITYTAG)); } - if($datequery) { + if ($datequery) { $sql_extra2 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery)))); $order = 'post'; } - if($datequery2) { + if ($datequery2) { $sql_extra2 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery2)))); } - if($datequery || $datequery2) { + if ($datequery || $datequery2) { $sql_extra2 .= " and item.item_thread_top != 0 "; } - if($order === 'post') + if ($order === 'post') { $ordering = "created"; - else + } + else { $ordering = "commented"; - + } $itemspage = get_pconfig(local_channel(),'system','itemspage'); App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20)); $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 . '%'), @@ -372,10 +380,10 @@ class Channel extends Controller { } } else { - $r = array(); + $r = []; } } - if($r) { + if ($r) { $parents_str = ids_to_querystr($r,'item_id'); @@ -392,17 +400,18 @@ class Channel extends Controller { $items = fetch_post_tags($items, true); $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); } - } else { - $items = array(); + } + else { + $items = []; } - if((! $update) && (! $load)) { + if ((! $update) && (! $load)) { // 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. @@ -451,7 +460,7 @@ class Channel extends Controller { $update_unseen = ''; - if($page_mode === 'list') { + if ($page_mode === 'list') { /** * in "list mode", only mark the parent item and any like activities as "seen". @@ -460,21 +469,21 @@ class Channel extends Controller { * comment likes could also get somewhat hairy. */ - if($parents_str) { + if ($parents_str) { $update_unseen = " AND ( id IN ( " . dbesc($parents_str) . " )"; $update_unseen .= " OR ( parent IN ( " . dbesc($parents_str) . " ) AND verb in ( '" . dbesc(ACTIVITY_LIKE) . "','" . dbesc(ACTIVITY_DISLIKE) . "' ))) "; } } else { - if($parents_str) { + if ($parents_str) { $update_unseen = " AND parent IN ( " . dbesc($parents_str) . " )"; } } - if($is_owner && $update_unseen) { + if ($is_owner && $update_unseen) { $x = [ 'channel_id' => local_channel(), 'update' => 'unset' ]; call_hooks('update_unseen',$x); - if($x['update'] === 'unset' || intval($x['update'])) { + if ($x['update'] === 'unset' || intval($x['update'])) { $r = q("UPDATE item SET item_unseen = 0 where item_unseen = 1 and item_wall = 1 AND uid = %d $update_unseen", intval(local_channel()) ); @@ -489,7 +498,7 @@ class Channel extends Controller { else { $o .= '