Merge branch 'dev'

This commit is contained in:
zotlabs 2019-09-17 21:28:12 -07:00
commit 72d948f00a
59 changed files with 1751 additions and 1136 deletions

View file

@ -3,3 +3,32 @@ ZAP
Zap is an open source decentralised social network with more privacy and less drama.
=====
The Zot Manifesto
You have the right to a permanent internet identity which is not associated with what server you are currently using and cannot be taken away from you by anybody, ever.
You have the right to refuse/reject or possibly moderate comments on your posts by anybody you don't know.
You also have the right to not allow them to comment on your posts in the first place, until such time as they have earned your trust.
You have the right to show your photos and videos to anybody you desire and also NOT show them to anybody you desire.
If your software does not implement these rights, you have the right to fix it or replace it.
=====
The Earth Manifesto
The earth is your mother. She gave you life. Respect her or she will take it away.
Silence is complicity. Speak.
Those who are leading us to destruction can be stopped.
7.5 billion people cannot be stopped.
=====

View file

@ -87,19 +87,21 @@ class Notifier {
static public $channel = null;
static public $private = false;
static public function run($argc,$argv){
static public function run($argc,$argv) {
if($argc < 3)
if ($argc < 3) {
return;
}
logger('notifier: invoked: ' . print_r($argv,true), LOGGER_DEBUG);
logger('notifier: invoked: ' . print_r($argv,true), LOGGER_DEBUG, LOG_INFO);
$cmd = $argv[1];
$item_id = $argv[2];
if(! $item_id)
if (! $item_id) {
return;
}
self::$deliveries = [];
self::$recipients = [];
@ -112,42 +114,15 @@ class Notifier {
$sys = get_sys_channel();
$mail = false;
$top_level = false;
$url_recipients = array();
$normal_mode = true;
if($cmd === 'mail' || $cmd === 'single_mail') {
$normal_mode = false;
$mail = true;
self::$private = true;
$message = q("SELECT * FROM mail WHERE id = %d LIMIT 1",
intval($item_id)
);
if(! $message) {
return;
}
xchan_mail_query($message[0]);
self::$recipients[] = $message[0]['to_xchan'];
$item = $message[0];
self::$encoded_item = encode_mail($item);
$s = q("select * from channel where channel_id = %d limit 1",
intval($item['channel_id'])
);
if($s)
self::$channel = $s[0];
self::$packet_type = 'mail';
self::$encoding = 'zot';
}
elseif($cmd === 'request') {
if ($cmd === 'request') {
$xchan = $argv[3];
if($argc < 5) {
if ($argc < 5) {
return;
}
@ -160,13 +135,13 @@ class Notifier {
self::$encoding = 'zot';
$normal_mode = false;
}
elseif($cmd === 'keychange') {
elseif ($cmd === 'keychange') {
self::$channel = channelx_by_n($item_id);
$r = q("select abook_xchan from abook where abook_channel = %d",
intval($item_id)
);
if($r) {
foreach($r as $rr) {
if ($r) {
foreach ($r as $rr) {
self::$recipients[] = $rr['abook_xchan'];
}
}
@ -176,7 +151,7 @@ class Notifier {
self::$encoding = 'zot';
$normal_mode = false;
}
elseif(in_array($cmd, [ 'permissions_update', 'permissions_reject', 'permissions_accept', 'permissions_create' ])) {
elseif (in_array($cmd, [ 'permissions_update', 'permissions_reject', 'permissions_accept', 'permissions_create' ])) {
// Get the (single) recipient
@ -184,61 +159,61 @@ class Notifier {
intval($item_id)
);
if($r) {
$uid = $r[0]['abook_channel'];
if ($r) {
$recip = array_shift($r);
$uid = $recip['abook_channel'];
// Get the sender
self::$channel = channelx_by_n($uid);
if(self::$channel) {
if (self::$channel) {
$perm_update = array('sender' => self::$channel, 'recipient' => $r[0], 'success' => false, 'deliveries' => '');
$perm_update = [ 'sender' => self::$channel, 'recipient' => $recip, 'success' => false, 'deliveries' => '' ];
switch($cmd) {
switch ($cmd) {
case 'permissions_create':
ActivityPub::permissions_create($perm_update);
break;
case 'permissions_accept':
ActivityPub::permissions_accept($perm_update);
break;
default:
break;
}
if(! $perm_update['success']) {
if (! $perm_update['success']) {
call_hooks($cmd,$perm_update);
}
if($perm_update['success']) {
if($perm_update['deliveries']) {
if ($perm_update['success']) {
if ($perm_update['deliveries']) {
self::$deliveries[] = $perm_update['deliveries'];
do_delivery(self::$deliveries);
}
return;
}
else {
self::$recipients[] = $r[0]['abook_xchan'];
self::$recipients[] = $recip['abook_xchan'];
self::$private = false;
self::$packet_type = 'refresh';
self::$env_recips = [ $r[0]['xchan_hash'] ];
self::$env_recips = [ $$recip['xchan_hash'] ];
}
}
}
}
elseif($cmd === 'refresh_all') {
elseif ($cmd === 'refresh_all') {
logger('notifier: refresh_all: ' . $item_id);
self::$channel = channelx_by_n($item_id);
$r = q("select abook_xchan from abook where abook_channel = %d",
intval($item_id)
);
if($r) {
foreach($r as $rr) {
if ($r) {
foreach ($r as $rr) {
self::$recipients[] = $rr['abook_xchan'];
}
}
self::$private = false;
self::$packet_type = 'refresh';
}
elseif($cmd === 'purge') {
elseif ($cmd === 'purge') {
$xchan = $argv[3];
logger('notifier: purge: ' . $item_id . ' => ' . $xchan);
if (! $xchan) {
@ -250,7 +225,7 @@ class Notifier {
self::$private = true;
self::$packet_type = 'purge';
}
elseif($cmd === 'purge_all') {
elseif ($cmd === 'purge_all') {
logger('notifier: purge_all: ' . $item_id);
self::$channel = channelx_by_n($item_id);
@ -278,57 +253,52 @@ class Notifier {
intval($item_id)
);
if(! $r)
if (! $r) {
return;
}
xchan_query($r);
$r = fetch_post_tags($r);
$target_item = $r[0];
$target_item = array_shift($r);
$deleted_item = false;
if(intval($target_item['item_deleted'])) {
if (intval($target_item['item_deleted'])) {
logger('notifier: target item ITEM_DELETED', LOGGER_DEBUG);
$deleted_item = true;
}
if(! in_array(intval($target_item['item_type']), [ ITEM_TYPE_POST, ITEM_TYPE_MAIL ] )) {
if (! in_array(intval($target_item['item_type']), [ ITEM_TYPE_POST ] )) {
logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG);
return;
}
// Check for non published items, but allow an exclusion for transmitting hidden file activities
if(intval($target_item['item_unpublished']) || intval($target_item['item_delayed']) ||
if (intval($target_item['item_unpublished']) || intval($target_item['item_delayed']) ||
intval($target_item['item_blocked']) ||
( intval($target_item['item_hidden']) && ($target_item['obj_type'] !== ACTIVITY_OBJ_FILE))) {
logger('notifier: target item not published, so not forwardable', LOGGER_DEBUG);
return;
}
if(strpos($target_item['postopts'],'nodeliver') !== false) {
logger('notifier: target item is undeliverable', LOGGER_DEBUG);
return;
}
$s = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1",
intval($target_item['uid'])
);
if($s)
self::$channel = $s[0];
if ($s) {
self::$channel = array_shift($s);
}
if(self::$channel['channel_hash'] !== $target_item['author_xchan'] && self::$channel['channel_hash'] !== $target_item['owner_xchan']) {
if (self::$channel['channel_hash'] !== $target_item['author_xchan'] && self::$channel['channel_hash'] !== $target_item['owner_xchan']) {
logger("notifier: Sending channel is not owner {$target_item['owner_xchan']} or author {$target_item['author_xchan']}", LOGGER_NORMAL, LOG_WARNING);
return;
}
$thread_is_public = false;
if($target_item['mid'] === $target_item['parent_mid']) {
if ($target_item['mid'] === $target_item['parent_mid']) {
$parent_item = $target_item;
$top_level_post = true;
}
else {
@ -337,26 +307,28 @@ class Notifier {
intval($target_item['parent'])
);
if(! $r)
if (! $r) {
return;
}
xchan_query($r);
$r = fetch_post_tags($r);
$parent_item = $r[0];
$parent_item = array_shift($r);
$top_level_post = false;
$thread_is_public = 1 - intval($parent_item['item_private']) ;
}
// avoid looping of discover items 12/4/2014
if($sys && $parent_item['uid'] == $sys['channel_id'])
if ($sys && $parent_item['uid'] == $sys['channel_id']) {
return;
}
$m = get_iconfig($target_item,'activitypub','signed_data');
if($m)
if ($m) {
self::$encoded_item = json_decode($m,true);
}
else {
self::$encoded_item = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
@ -366,12 +338,7 @@ class Notifier {
);
}
logger('target_item: ' . print_r($target_item,true));
// self::$encoded_item = encode_item($target_item);
logger('encoded: ' . print_r(self::$encoded_item,true));
// Send comments to the owner to re-deliver to everybody in the conversation
@ -385,8 +352,6 @@ class Notifier {
$relay_to_owner = (((! $top_level_post) && (intval($target_item['item_origin'])) && comment_local_origin($target_item) && $cmd !== 'hyper') ? true : false);
$uplink = false;
// $cmd === 'relay' indicates the owner is sending it to the original recipients
@ -397,13 +362,13 @@ class Notifier {
// tag_deliver'd post which needs to be sent back to the original author
if(($cmd === 'uplink') && intval($parent_item['item_uplink']) && (! $top_level_post)) {
if (($cmd === 'uplink') && intval($parent_item['item_uplink']) && (! $top_level_post)) {
logger('notifier: uplink');
$uplink = true;
self::$packet_type = 'response';
}
if(($relay_to_owner || $uplink) && ($cmd !== 'relay')) {
if (($relay_to_owner || $uplink) && ($cmd !== 'relay')) {
logger('followup relay (upstream delivery)', LOGGER_DEBUG);
$sendto = ($uplink) ? $parent_item['source_xchan'] : $parent_item['owner_xchan'];
self::$recipients = [ $sendto ];
@ -419,7 +384,7 @@ class Notifier {
}
else {
if($cmd === 'relay') {
if ($cmd === 'relay') {
logger('owner relay (downstream delivery)');
}
else {
@ -429,29 +394,28 @@ class Notifier {
// if our parent is a tag_delivery recipient, uplink to the original author causing
// a delivery fork.
if(($parent_item) && intval($parent_item['item_uplink']) && (! $top_level_post) && ($cmd !== 'uplink')) {
if (($parent_item) && intval($parent_item['item_uplink']) && (! $top_level_post) && ($cmd !== 'uplink')) {
// don't uplink a relayed post to the relay owner
if($parent_item['source_xchan'] !== $parent_item['owner_xchan']) {
if ($parent_item['source_xchan'] !== $parent_item['owner_xchan']) {
logger('notifier: uplinking this item');
Master::Summon(array('Notifier','uplink',$item_id));
}
}
if($thread_is_public && $cmd === 'hyper') {
$rcps = [];
if ($thread_is_public && $cmd === 'hyper') {
self::$recipients = [];
$r = q("select abook_xchan, xchan_network from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_self = 0 and abook_pending = 0 and abook_archived = 0 and not abook_xchan in ( '%s', '%s', '%s' ) ",
intval($target_item['uid']),
dbesc($target_item['author_xchan']),
dbesc($target_item['owner_xchan']),
dbesc($target_item['source_xchan'])
);
if($r) {
foreach($r as $rv) {
$rcps[] = $rv['abook_xchan'];
if ($r) {
foreach ($r as $rv) {
self::$recipients[] = $rv['abook_xchan'];
}
}
self::$private = false;
self::$recipients = $rcps;
}
else {
self::$private = false;
@ -465,11 +429,9 @@ class Notifier {
self::$recipients = array_diff(self::$recipients, [ $target_item['owner_xchan'] ]);
}
// don't send deletions onward for other people's stuff
// TODO verify this is needed - copied logic from same place in old code
if(intval($target_item['item_deleted']) && (! intval($target_item['item_wall']))) {
if (intval($target_item['item_deleted']) && (! intval($target_item['item_wall']))) {
logger('notifier: ignoring delete notification for non-wall item', LOGGER_NORMAL, LOG_NOTICE);
return;
}
@ -482,26 +444,26 @@ class Notifier {
logger('encoded item: ' . print_r(self::$encoded_item,true), LOGGER_DATA, LOG_DEBUG);
stringify_array_elms(self::$recipients);
if(! self::$recipients) {
if (! self::$recipients) {
logger('no recipients');
return;
}
// logger('recipients: ' . print_r(self::$recipients,true), LOGGER_NORMAL, LOG_DEBUG);
if(! count(self::$env_recips))
if (! count(self::$env_recips)) {
self::$env_recips = ((self::$private) ? [] : null);
}
$details = q("select xchan_hash, xchan_network, xchan_addr, xchan_guid, xchan_guid_sig from xchan where xchan_hash in (" . protect_sprintf(implode(',',self::$recipients)) . ")");
$recip_list = [];
$details = q("select xchan_hash, xchan_network, xchan_addr, xchan_guid, xchan_guid_sig from xchan
where xchan_hash in (" . protect_sprintf(implode(',',self::$recipients)) . ")");
$recip_list = array();
if($details) {
foreach($details as $d) {
if ($details) {
foreach ($details as $d) {
$recip_list[] = $d['xchan_addr'] . ' (' . $d['xchan_hash'] . ')';
if(self::$private) {
if (self::$private) {
self::$env_recips[] = $d['xchan_hash'];
}
}
@ -521,7 +483,6 @@ class Notifier {
'relay_to_owner' => $relay_to_owner,
'uplink' => $uplink,
'cmd' => $cmd,
'mail' => $mail,
'single' => (($cmd === 'single_mail' || $cmd === 'single_activity') ? true : false),
'request' => $request,
'normal_mode' => $normal_mode,
@ -529,12 +490,11 @@ class Notifier {
'queued' => []
];
call_hooks('notifier_process', $narr);
if($narr['queued']) {
foreach($narr['queued'] as $pq)
if ($narr['queued']) {
foreach ($narr['queued'] as $pq) {
self::$deliveries[] = $pq;
}
}
// notifier_process can alter the recipient list
@ -542,7 +502,7 @@ class Notifier {
self::$recipients = $narr['recipients'];
self::$env_recips = $narr['env_recips'];
if((self::$private) && (! self::$env_recips)) {
if ((self::$private) && (! self::$env_recips)) {
// shouldn't happen
logger('private message with no envelope recipients.' . print_r($argv,true), LOGGER_NORMAL, LOG_NOTICE);
return;
@ -550,22 +510,19 @@ class Notifier {
logger('notifier: recipients (may be delivered to more if public): ' . print_r($recip_list,true), LOGGER_DEBUG);
// Now we have collected recipients (except for external mentions, FIXME)
// Now we have collected recipients (except for external mentions, @FIXME)
// Let's reduce this to a set of hubs; checking that the site is not dead.
$r = q("select hubloc.*, site.site_crypto, site.site_flags from hubloc left join site on site_url = hubloc_url where hubloc_hash in (" . protect_sprintf(implode(',',self::$recipients)) . ")
$hubs = q("select hubloc.*, site.site_crypto, site.site_flags from hubloc left join site on site_url = hubloc_url
where hubloc_hash in (" . protect_sprintf(implode(',',self::$recipients)) . ")
and hubloc_error = 0 and hubloc_deleted = 0 and ( site_dead = 0 OR site_dead is null ) "
);
if(! $r) {
if (! $hubs) {
logger('notifier: no hubs', LOGGER_NORMAL, LOG_NOTICE);
return;
}
$hubs = $r;
/**
* Reduce the hubs to those that are unique. For zot hubs, we need to verify uniqueness by the sitekey,
* since it may have been a re-install which has not yet been detected and pruned.
@ -579,12 +536,12 @@ class Notifier {
$urls = []; // array of urls to check uniqueness of hubs from other networks
$hub_env = []; // per-hub envelope so we don't broadcast the entire envelope to all
foreach($hubs as $hub) {
foreach ($hubs as $hub) {
if(self::$env_recips) {
foreach(self::$env_recips as $er) {
if($hub['hubloc_hash'] === $er) {
if(! array_key_exists($hub['hubloc_site_id'], $hub_env)) {
if (self::$env_recips) {
foreach (self::$env_recips as $er) {
if ($hub['hubloc_hash'] === $er) {
if (! array_key_exists($hub['hubloc_site_id'], $hub_env)) {
$hub_env[$hub['hubloc_site_id']] = [];
}
$hub_env[$hub['hubloc_site_id']][] = $er;
@ -593,15 +550,15 @@ class Notifier {
}
if($hub['hubloc_network'] === 'zot6') {
if(! in_array($hub['hubloc_sitekey'],$keys)) {
if ($hub['hubloc_network'] === 'zot6') {
if (! in_array($hub['hubloc_sitekey'],$keys)) {
$hublist[] = $hub['hubloc_host'] . ' ' . $hub['hubloc_network'];
$dhubs[] = $hub;
$keys[] = $hub['hubloc_sitekey'];
}
}
else {
if(! in_array($hub['hubloc_url'],$urls)) {
if (! in_array($hub['hubloc_url'],$urls)) {
$hublist[] = $hub['hubloc_host'] . ' ' . $hub['hubloc_network'];
$dhubs[] = $hub;
$urls[] = $hub['hubloc_url'];
@ -611,11 +568,13 @@ class Notifier {
logger('notifier: will notify/deliver to these hubs: ' . print_r($hublist,true), LOGGER_DEBUG, LOG_DEBUG);
foreach($dhubs as $hub) {
foreach ($dhubs as $hub) {
logger('notifier_hub: ' . $hub['hubloc_url'],LOGGER_DEBUG);
logger('notifier_hub: ' . $hub['hubloc_url'],LOGGER_DEBUG, LOG_DEBUG);
if($hub['hubloc_network'] !== 'zot6') {
// deliver to any non-zot networks
if ($hub['hubloc_network'] !== 'zot6') {
$narr = [
'channel' => self::$channel,
'upstream' => $upstream,
@ -630,7 +589,6 @@ class Notifier {
'relay_to_owner' => $relay_to_owner,
'uplink' => $uplink,
'cmd' => $cmd,
'mail' => $mail,
'single' => (($cmd === 'single_mail' || $cmd === 'single_activity') ? true : false),
'request' => $request,
'normal_mode' => $normal_mode,
@ -638,7 +596,6 @@ class Notifier {
'queued' => []
];
ActivityPub::notifier_process($narr);
call_hooks('notifier_hub',$narr);
@ -660,20 +617,21 @@ class Notifier {
// Note: Legacy Hubzilla and Osada code. In Zap this should never happen.
if($cmd === 'single_mail' || $cmd === 'single_activity') {
if ($cmd === 'single_mail' || $cmd === 'single_activity') {
continue;
}
// default: zot protocol
$hash = new_uuid();
$hash = new_uuid();
$env = (($hub_env && $hub_env[$hub['hubloc_site_id']]) ? $hub_env[$hub['hubloc_site_id']] : '');
if((self::$private) && (! $env)) {
if ((self::$private) && (! $env)) {
continue;
}
$packet = Libzot::build_packet(self::$channel, self::$packet_type, $env, self::$encoded_item, self::$encoding, ((self::$private) ? $hub['hubloc_sitekey'] : null), $hub['site_crypto']);
$packet = Libzot::build_packet(self::$channel, self::$packet_type, $env, self::$encoded_item, self::$encoding,
((self::$private) ? $hub['hubloc_sitekey'] : null), $hub['site_crypto']);
Queue::insert(
[
@ -687,8 +645,9 @@ class Notifier {
);
// only create delivery reports for normal undeleted items
if(is_array($target_item) && array_key_exists('postopts',$target_item) && (! $target_item['item_deleted']) && (! get_config('system','disable_dreport'))) {
q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_name, dreport_result, dreport_time, dreport_xchan, dreport_queue ) values ( '%s', '%s','%s','%s','%s','%s','%s','%s' ) ",
if (is_array($target_item) && (! $target_item['item_deleted']) && (! get_config('system','disable_dreport'))) {
q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_name, dreport_result, dreport_time, dreport_xchan, dreport_queue )
values ( '%s', '%s','%s','%s','%s','%s','%s','%s' ) ",
dbesc($target_item['mid']),
dbesc($hub['hubloc_host']),
dbesc($hub['hubloc_host']),
@ -703,17 +662,17 @@ class Notifier {
self::$deliveries[] = $hash;
}
if($normal_mode) {
if ($normal_mode) {
// This wastes a process if there are no delivery hooks configured, so check this before launching the new process
$x = q("select * from hook where hook = 'notifier_normal'");
if($x) {
if ($x) {
Master::Summon( [ 'Deliver_hooks', $target_item['id'] ] );
}
}
if(self::$deliveries)
if (self::$deliveries) {
do_delivery(self::$deliveries);
logger('notifier: basic loop complete.', LOGGER_DEBUG);
}
call_hooks('notifier_end',$target_item);

View file

@ -99,6 +99,76 @@ class Onepoll {
if(! $responded)
return;
if(defined('USE_OUTBOX')) {
// @fixme
// This needs to be converted from zotfeed to ActivityStreams (such as an ActivityPub outbox).
// The zotfeed has serious compatibility issues between Hubzilla and Zap.
if($contact['xchan_connurl']) {
$fetch_feed = true;
$x = null;
// They haven't given us permission to see their stream
$can_view_stream = intval(get_abconfig($importer_uid,$contact['abook_xchan'],'their_perms','view_stream'));
if(! $can_view_stream)
$fetch_feed = false;
// we haven't given them permission to send us their stream
$can_send_stream = intval(get_abconfig($importer_uid,$contact['abook_xchan'],'my_perms','send_stream'));
if(! $can_send_stream)
$fetch_feed = false;
if($fetch_feed) {
if(strpos($contact['xchan_connurl'],z_root()) === 0) {
// local channel - save a network fetch
$c = channelx_by_hash($contact['xchan_hash']);
if($c) {
$x = [
'success' => true,
'body' => json_encode( [
'success' => true,
'messages' => zot_feed($c['channel_id'], $importer['xchan_hash'], [ 'mindate' => $last_update ])
])
];
}
}
else {
// remote fetch
$feedurl = str_replace('/poco/','/zotfeed/',$contact['xchan_connurl']);
$feedurl .= '?f=&mindate=' . urlencode($last_update) . '&zid=' . $importer['channel_address'] . '@' . \App::get_hostname();
$recurse = 0;
$x = z_fetch_url($feedurl, false, $recurse, [ 'session' => true ]);
}
logger('feed_update: ' . print_r($x,true), LOGGER_DATA);
}
if(($x) && ($x['success'])) {
$total = 0;
logger('onepoll: feed update ' . $contact['xchan_name'] . ' ' . $feedurl);
$j = json_decode($x['body'],true);
if($j['success'] && $j['messages']) {
foreach($j['messages'] as $message) {
// process delivery here once we have parsed the AS
logger('onepoll: feed_update: process_delivery: ' . print_r($results,true), LOGGER_DATA);
$total ++;
}
logger("onepoll: $total messages processed");
}
}
}
} // end USE_OUTBOX
// update the poco details for this connection
if($contact['xchan_connurl']) {

View file

@ -0,0 +1,81 @@
<?php
namespace Zotlabs\Lib;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\Activity;
/**
* Class for dealing with ActivityStreams ordered collections.
* Construct with the object url and an optional channel to sign the request.
* Returns an array of collection members.
* If desired, call $collection->next to return additional pages (arrays of collection members).
* Returns an empty array when there is nothing more to return
*/
class ASCollection {
private $url = null;
private $channel = null;
private $nextpage = null;
private $data = null;
function __construct($url,$channel = null) {
$this->url = $url;
$this->channel = $channel;
$data = Activity::fetch($url,$channel);
if (! $data) {
return false;
}
$ptr = $data;
if ($data['type'] === 'OrderedCollection') {
if (array_key_exists('first',$data)) {
$ptr = $data['first'];
}
}
if ($ptr['type'] === 'OrderedCollectionPage' && $ptr['orderedItems']) {
$this->data = $ptr['orderedItems'];
}
$this->setnext($data);
return $this->data;
}
function next() {
if (! $this->nextpage) {
return [];
}
$data = Activity::fetch($this->nextpage,$channel);
if (! $data) {
return [];
}
if ($data['type'] === 'OrderedCollectionPage' && $data['orderedItems']) {
$this->data = $data['orderedItems'];
}
$this->setnext($data);
return $this->data;
}
function setnext($data) {
if (array_key_exists('next',$data)) {
$this->nextpage = $data['next'];
}
elseif (array_key_exists('last',$data)) {
$this->nextpage = $data['last'];
}
}
}

View file

@ -9,6 +9,10 @@ use Zotlabs\Access\PermissionLimits;
use Zotlabs\Daemon\Master;
require_once('include/html2bbcode.php');
require_once('include/html2plain.php');
require_once('include/event.php');
class Activity {
static $ACTOR_CACHE_DAYS = 3;
@ -25,7 +29,12 @@ class Activity {
return self::fetch_profile($x);
}
if (in_array($x['type'], [ ACTIVITY_OBJ_NOTE, ACTIVITY_OBJ_ARTICLE ] )) {
return self::fetch_item($x);
// Use Mastodon-specific note and media hacks if nomadic. Else HTML.
// Eventually this needs to be passed in much further up the stack
// and base the decision on whether or not we are encoding for ActivityPub or Zot6
return self::fetch_item($x,((get_config('system','activitypub')) ? true : false));
}
if ($x['type'] === ACTIVITY_OBJ_THING) {
return self::fetch_thing($x);
@ -141,7 +150,7 @@ class Activity {
}
static function fetch_item($x) {
static function fetch_item($x,$activitypub = false) {
if (array_key_exists('source',$x)) {
// This item is already processed and encoded
@ -154,7 +163,7 @@ class Activity {
if ($r) {
xchan_query($r,true);
$r = fetch_post_tags($r,true);
return self::encode_item($r[0],((defined('NOMADIC')) ? false : true));
return self::encode_item($r[0],$activitypub);
}
}
@ -319,7 +328,6 @@ class Activity {
}
$ret['attributedTo'] = $i['author']['xchan_url'];
if ($i['mid'] !== $i['parent_mid']) {
$ret['inReplyTo'] = $i['thr_parent'];
$cnv = get_iconfig($i['parent'],'ostatus','conversation');
@ -931,7 +939,7 @@ class Activity {
];
$ret['url'] = $p['xchan_url'];
if ($activitypub) {
if ($activitypub && $feature_complete) {
if ($c) {
$ret['inbox'] = z_root() . '/inbox/' . $c['channel_address'];
@ -1881,6 +1889,7 @@ class Activity {
$s['mid'] = $act->id;
$s['parent_mid'] = $act->obj['id'];
$s['replyto'] = $act->replyto;
// over-ride the object timestamp with the activity
@ -2345,7 +2354,7 @@ class Activity {
intval($item['uid'])
);
if (! $p) {
if (defined('NOMADIC')) {
if (! get_config('system','activitypub')) {
return;
}
else {
@ -2811,8 +2820,6 @@ class Activity {
static function bb_content($content,$field) {
require_once('include/html2bbcode.php');
require_once('include/event.php');
$ret = false;
if (is_array($content[$field])) {
@ -2876,6 +2883,11 @@ class Activity {
if ($event) {
$event['summary'] = html2bbcode($content['summary']);
if (! $event['summary']) {
if ($content['name']) {
$event['summary'] = html2plain(purify_html($content['name']),256);
}
}
$event['description'] = html2bbcode($content['content']);
if ($event['summary'] && $event['dtstart']) {
$content['event'] = $event;
@ -2888,9 +2900,6 @@ class Activity {
}
}
return $content;
}

View file

@ -29,10 +29,6 @@ class ActivityPub {
return;
}
if(strpos($arr['target_item']['postopts'],'nopub') !== false) {
return;
}
$signed_msg = get_iconfig($arr['target_item'],'activitypub','rawmsg');
// If we have an activity already stored with an LD-signature

View file

@ -24,6 +24,7 @@ class ActivityStreams {
public $actor = null;
public $obj = null;
public $tgt = null;
public $replyto = null;
public $origin = null;
public $owner = null;
public $signer = null;
@ -83,13 +84,14 @@ class ActivityStreams {
}
if($this->is_valid()) {
$this->id = $this->get_property_obj('id');
$this->type = $this->get_primary_type();
$this->actor = $this->get_actor('actor','','');
$this->obj = $this->get_compound_property('object');
$this->tgt = $this->get_compound_property('target');
$this->origin = $this->get_compound_property('origin');
$this->recips = $this->collect_recips();
$this->id = $this->get_property_obj('id');
$this->type = $this->get_primary_type();
$this->actor = $this->get_actor('actor','','');
$this->obj = $this->get_compound_property('object');
$this->tgt = $this->get_compound_property('target');
$this->origin = $this->get_compound_property('origin');
$this->recips = $this->collect_recips();
$this->replyto = $this->get_compound_property('replyTo');
$this->ldsig = $this->get_compound_property('signature');
if($this->ldsig) {

View file

@ -29,20 +29,20 @@ class Connect {
$my_perms = false;
$protocol = '';
if(substr($url,0,1) === '[') {
if (substr($url,0,1) === '[') {
$x = strpos($url,']');
if($x) {
if ($x) {
$protocol = substr($url,1,$x-1);
$url = substr($url,$x+1);
}
}
if(! allowed_url($url)) {
if (! check_siteallowed($url)) {
$result['message'] = t('Channel is blocked on this site.');
return $result;
}
if(! $url) {
if (! $url) {
$result['message'] = t('Channel location missing.');
return $result;
}
@ -80,7 +80,7 @@ class Connect {
// Some Hubzilla records were originally stored as activitypub. If we find one, force rediscovery
// since Zap cannot connect with them.
if($r['xchan_network'] === 'activitypub') {
if($r['xchan_network'] === 'activitypub' && ! get_config('system','activitypub')) {
$r = null;
}
}
@ -141,9 +141,15 @@ class Connect {
return $result;
}
if (! check_channelallowed($xchan_hash)) {
$result['message'] = t('Channel is blocked on this site.');
logger('follow: ' . $result['message']);
return $result;
}
// Now start processing the new connection
if($r['xchan_network'] === 'activitypub') {
if($r['xchan_network'] === 'activitypub' && ! get_config('system','activitypub')) {
// ActivityPub is not nomadic
$result['message'] = t('Protocol not supported');
return $result;

View file

@ -1537,7 +1537,8 @@ class Libzot {
* @brief
*
* @param array $sender
* @param array $arr
* @param ActivityStreams object $act
* @param array $msg_arr
* @param array $deliveries
* @param boolean $relay
* @param boolean $public (optional) default false
@ -1891,8 +1892,9 @@ 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;
}
}
}
else {
@ -2338,90 +2340,6 @@ class Libzot {
return $post_id;
}
static function process_mail_delivery($sender, $arr, $deliveries) {
$result = array();
if ($sender != $arr['from_xchan']) {
logger('process_mail_delivery: sender is not mail author');
return;
}
foreach ($deliveries as $d) {
$DR = new DReport(z_root(),$sender,$d,$arr['mid']);
$r = q("select * from channel where channel_hash = '%s' limit 1",
dbesc($d['hash'])
);
if (! $r) {
$DR->update('recipient not found');
$result[] = $DR->get();
continue;
}
$channel = $r[0];
$DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
if (! perm_is_allowed($channel['channel_id'],$sender,'post_mail')) {
/*
* Always allow somebody to reply if you initiated the conversation. It's anti-social
* and a bit rude to send a private message to somebody and block their ability to respond.
* If you are being harrassed and want to put an end to it, delete the conversation.
*/
$return = false;
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) {
logger("permission denied for mail delivery {$channel['channel_id']}");
$DR->update('permission denied');
$result[] = $DR->get();
continue;
}
}
$r = q("select id from mail where mid = '%s' and channel_id = %d limit 1",
dbesc($arr['mid']),
intval($channel['channel_id'])
);
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'])
);
$DR->update('mail recalled');
$result[] = $DR->get();
logger('mail_recalled');
}
else {
$DR->update('duplicate mail received');
$result[] = $DR->get();
logger('duplicate mail received');
}
continue;
}
else {
$arr['account_id'] = $channel['channel_account_id'];
$arr['channel_id'] = $channel['channel_id'];
$item_id = mail_store($arr);
$DR->update('mail delivered');
$result[] = $DR->get();
}
}
return $result;
}
/**
* @brief Processes delivery of profile.

View file

@ -95,7 +95,7 @@ class Share {
$is_photo = (($this->item['obj_type'] === ACTIVITY_OBJ_PHOTO) ? true : false);
if($is_photo) {
$object = json_decode($this->item['obj'],true);
$photo_bb = $object['body'];
$photo_bb = (($object['source']) ? $object['source']['content'] : $object['body']);
}
if (strpos($this->item['body'], "[/share]") !== false) {
@ -107,7 +107,7 @@ class Share {
"' 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') .
"' auth='" . (($this->item['author']['network'] === 'zot6') ? 'true' : 'false') .
"' posted='" . $this->item['created'] .
"' message_id='" . $this->item['mid'] .
"']";

View file

@ -1,127 +0,0 @@
<?php
namespace Zotlabs\Lib;
/**
* @brief wrapper for z_fetch_url() which can be instantiated with several built-in parameters and
* these can be modified and re-used. Useful for CalDAV and other processes which need to authenticate
* and set lots of CURL options (many of which stay the same from one call to the next).
*/
class SuperCurl {
private $auth;
private $url;
private $curlopt = array();
private $headers = null;
public $filepos = 0;
public $filehandle = 0;
public $request_data = '';
private $request_method = 'GET';
private $upload = false;
private $cookies = false;
private function set_data($s) {
$this->request_data = $s;
$this->filepos = 0;
}
public function curl_read($ch,$fh,$size) {
if($this->filepos < 0) {
unset($fh);
return '';
}
$s = substr($this->request_data,$this->filepos,$size);
if(strlen($s) < $size)
$this->filepos = (-1);
else
$this->filepos = $this->filepos + $size;
return $s;
}
public function __construct($opts = array()) {
$this->set($opts);
}
private function set($opts = array()) {
if($opts) {
foreach($opts as $k => $v) {
switch($k) {
case 'http_auth':
$this->auth = $v;
break;
case 'magicauth':
// currently experimental
$this->magicauth = $v;
\Zotlabs\Daemon\Master::Summon([ 'CurlAuth', $v ]);
break;
case 'custom':
$this->request_method = $v;
break;
case 'url':
$this->url = $v;
break;
case 'data':
$this->set_data($v);
if($v) {
$this->upload = true;
}
else {
$this->upload = false;
}
break;
case 'headers':
$this->headers = $v;
break;
default:
$this->curlopts[$k] = $v;
break;
}
}
}
}
function exec() {
$opts = $this->curlopts;
$url = $this->url;
if($this->auth)
$opts['http_auth'] = $this->auth;
if($this->magicauth) {
$opts['cookiejar'] = 'store/[data]/cookie_' . $this->magicauth;
$opts['cookiefile'] = 'store/[data]/cookie_' . $this->magicauth;
$opts['cookie'] = 'PHPSESSID=' . trim(file_get_contents('store/[data]/cookien_' . $this->magicauth));
$c = channelx_by_n($this->magicauth);
if($c)
$url = zid($this->url,channel_reddress($c));
}
if($this->custom)
$opts['custom'] = $this->custom;
if($this->headers)
$opts['headers'] = $this->headers;
if($this->upload) {
$opts['upload'] = true;
$opts['infile'] = $this->filehandle;
$opts['infilesize'] = strlen($this->request_data);
$opts['readfunc'] = [ $this, 'curl_read' ] ;
}
$recurse = 0;
return z_fetch_url($this->url,true,$recurse,(($opts) ? $opts : null));
}
}

View file

@ -38,7 +38,7 @@ class ThreadItem {
$this->data = $data;
$this->toplevel = ($this->get_id() == $this->get_data_value('parent'));
// $this->threaded = get_config('system','thread_allow',((defined('NOMADIC')) ? false : true));
// $this->threaded = get_config('system','thread_allow',((get_config('system','activitypub')) ? true : false));
$this->threaded = get_config('system','thread_allow',true);
$observer = App::get_observer();
@ -482,7 +482,8 @@ class ThreadItem {
'preview_lbl' => t('This is an unsaved preview'),
'wait' => t('Please wait'),
'submid' => str_replace(['+','='], ['',''], base64_encode($item['mid'])),
'thread_level' => $thread_level
'thread_level' => $thread_level,
'thread_max' => intval(get_config('system','thread_maxlevel',2)) + 1
);
$arr = array('item' => $item, 'output' => $tmp_item);
@ -490,22 +491,32 @@ class ThreadItem {
$result = $arr['output'];
$censored = false;
if(strpos($body['html'],"<button id=\"nsfw-wrap-") !== false && $collapse_all === false) {
$censored = true;
}
$censored = ((strpos($body['html'],"<button id=\"nsfw-wrap-") !== false && $collapse_all === false) ? true : false);
$result['children'] = [];
// place to store all the author addresses (links if not available) in the thread so we can auto-mention them in JS.
$result['authors'] = [];
$add_top_author = true;
if($observer && ($profile_addr === $observer['xchan_hash'] || $profile_addr === $observer['xchan_addr'])) {
$add_top_author = false;
}
if($add_top_author && (! defined('NOMADIC'))) {
$result['authors'][] = $profile_addr;
if (get_config('system','activitypub')) {
// place to store all the author addresses (links if not available) in the thread so we can auto-mention them in JS.
$result['authors'] = [];
if ($observer && ($profile_addr === $observer['xchan_hash'] || $profile_addr === $observer['xchan_addr'])) {
// ignore it
}
else {
$result['authors'][] = $profile_addr;
}
if ($item['term']) {
foreach ($item['term'] as $t) {
if ($t['ttype'] == TERM_MENTION) {
if (strpos($t['term'],'@') !== false) {
$result['authors'][] = $t['term'];
}
else {
$url = ((($position = strpos($t['url'],'url=')) !== false) ? urldecode(substr($t['url'],$position + 4)) : $t['url']);
$result['authors'][] = $url;
}
}
}
}
}
$nb_children = count($children);
@ -523,15 +534,6 @@ class ThreadItem {
if(strpos($xz['body'],"<button id=\"nsfw-wrap-") !== false && $collapse_all === false) {
$censored = true;
}
$author = $child->get_author();
if($author && ! in_array($author,$result['authors'])) {
if($observer && ($author === $observer['xchan_hash'] || $author === $observer['xchan_addr'])) {
// do nothing
}
elseif(! defined('NOMADIC')) {
$result['authors'][] = $author;
}
}
$result['children'][] = $xz;
}
// Collapse
@ -548,14 +550,6 @@ class ThreadItem {
}
}
if(count($result['authors']) > 6) {
$slice = array_slice($result['authors'],0,3);
$slice2 = array_slice($result['authors'],-3,3);
$result['authors'] = array_merge($slice,$slice2);
}
//logger('authors: ' . print_r($result['authors'],true));
$result['private'] = $item['item_private'];
$result['toplevel'] = ($this->is_toplevel() ? 'toplevel_item' : '');
@ -880,7 +874,7 @@ class ThreadItem {
'$myphoto' => $observer['xchan_photo_s'],
'$comment' => t('Comment'),
'$submit' => t('Submit'),
'$edat' => ((defined('NOMADIC')) ? '' : t('Add Conversation Mentions')),
'$edat' => ((get_config('system','activitypub')) ? t('Add Conversation Mentions') : EMPTY_STR),
'$edbold' => t('Bold'),
'$editalic' => t('Italic'),
'$eduline' => t('Underline'),

View file

@ -96,7 +96,7 @@ class Acl extends \Zotlabs\Web\Controller {
. " then POSITION('" . protect_sprintf(dbesc($search))
. "' IN xchan_name) else position('" . protect_sprintf(dbesc(punify($search))) . "' IN xchan_addr) end, ";
$sql_extra3 = "AND ( xchan_addr like " . protect_sprintf( "'%" . dbesc(punify($search)) . "%'" ) . " OR xchan_name like " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " ) ";
$sql_extra3 = "AND ( xchan_addr like " . protect_sprintf( "'%" . dbesc(punify($search)) . "%'" ) . " OR xchan_name like " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " OR abook_alias like " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " ) ";
}
else {

View file

@ -63,7 +63,7 @@ class Activity extends Controller {
killme();
}
goaway(z_root() . '/item/' . argv(1));
}
}

View file

@ -53,7 +53,6 @@ class Site {
}
$mirror_frontpage = ((x($_POST,'mirror_frontpage')) ? intval(trim($_POST['mirror_frontpage'])) : 0);
$directory_server = ((x($_POST,'directory_server')) ? trim($_POST['directory_server']) : '');
$allowed_sites = ((x($_POST,'allowed_sites')) ? notags(trim($_POST['allowed_sites'])) : '');
$force_publish = ((x($_POST,'publish_all')) ? True : False);
$disable_discover_tab = ((x($_POST,'disable_discover_tab')) ? False : True);
$site_firehose = ((x($_POST,'site_firehose')) ? True : False);
@ -144,7 +143,6 @@ class Site {
set_config('system','access_policy', $access_policy);
set_config('system','account_abandon_days', $abandon_days);
set_config('system','register_text', $register_text);
set_config('system','allowed_sites', $allowed_sites);
set_config('system','publish_all', $force_publish);
set_config('system','disable_discover_tab', $disable_discover_tab);
set_config('system','site_firehose', $site_firehose);
@ -317,7 +315,6 @@ class Site {
'$frontpage' => [ 'frontpage', t("Site homepage to show visitors (default: login box)"), get_config('system','frontpage'), t("example: 'public' to show public stream, 'page/sys/home' to show a system webpage called 'home' or 'include:home.html' to include a file.") ],
'$mirror_frontpage' => [ 'mirror_frontpage', t("Preserve site homepage URL"), get_config('system','mirror_frontpage'), t('Present the site homepage in a frame at the original location instead of redirecting') ],
'$abandon_days' => [ 'abandon_days', t('Accounts abandoned after x days'), get_config('system','account_abandon_days'), t('Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit.') ],
'$allowed_sites' => [ 'allowed_sites', t("Allowed friend domains"), get_config('system','allowed_sites'), t("Comma separated list of domains which are allowed to establish friendships with this site. Wildcards are accepted. Empty to allow any domains") ],
'$verify_email' => [ 'verify_email', t("Verify Email Addresses"), get_config('system','verify_email'), t("Check to verify email addresses used in account registration (recommended).") ],
'$force_publish' => [ 'publish_all', t("Force publish"), get_config('system','publish_all'), t("Check to force all profiles on this site to be listed in the site directory.") ],
'$disable_discover_tab' => [ 'disable_discover_tab', t('Import Public Streams'), $discover_tab, t('Import and allow access to public content pulled from other sites. Warning: this content is unmoderated.') ],

View file

@ -24,6 +24,7 @@ class Apschema extends \Zotlabs\Web\Controller {
'emojiReaction' => 'zot:emojiReaction',
'expires' => 'zot:expires',
'directMessage' => 'zot:directMessage',
'replyTo' => 'zot:replyTo'
]
];

View file

@ -114,7 +114,7 @@ class Channel extends Controller {
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
z_root() . ZOT_APSCHEMA_REV
]], Activity::encode_person($channel,true,((defined('NOMADIC')) ? false : true)));
]], Activity::encode_person($channel,true,true));
$headers = [];
$headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ;

View file

@ -1,20 +1,24 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
require_once('include/socgraph.php');
class Connections extends \Zotlabs\Web\Controller {
class Connections extends Controller {
function init() {
if(! local_channel())
if (! local_channel()) {
return;
}
$channel = \App::get_channel();
if($channel)
$channel = App::get_channel();
if ($channel) {
head_set_icon($channel['xchan_photo_s']);
}
}
@ -24,7 +28,7 @@ class Connections extends \Zotlabs\Web\Controller {
$o = '';
if(! local_channel()) {
if (! local_channel()) {
notice( t('Permission denied.') . EOL);
return login();
}
@ -41,14 +45,15 @@ class Connections extends \Zotlabs\Web\Controller {
$unconnected = false;
$all = false;
if(! $_REQUEST['aj'])
$_SESSION['return_url'] = \App::$query_string;
if (! $_REQUEST['aj']) {
$_SESSION['return_url'] = App::$query_string;
}
$search_flags = "";
$head = '';
if(argc() == 2) {
switch(argv(1)) {
if (argc() == 2) {
switch (argv(1)) {
case 'active':
$search_flags = " and abook_blocked = 0 and abook_ignored = 0 and abook_hidden = 0 and abook_archived = 0 AND abook_not_here = 0 ";
$head = t('Active');
@ -80,21 +85,25 @@ class Connections extends \Zotlabs\Web\Controller {
$pending = true;
break;
case 'ifpending':
case intval(argv(1)):
$r = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ",
intval(local_channel())
);
if($r && $r[0]['total']) {
if ($r && $r[0]['total']) {
$search_flags = " and abook_pending = 1 ";
if(intval(argv(1))) {
$search_flags .= " and abook_id = " . intval(argv(1)) . " ";
}
$head = t('New');
$pending = true;
\App::$argv[1] = 'pending';
App::$argv[1] = 'pending';
}
else {
$head = t('All');
$search_flags = '';
$all = true;
\App::$argc = 1;
unset(\App::$argv[1]);
App::$argc = 1;
unset(App::$argv[1]);
}
break;
@ -109,9 +118,9 @@ class Connections extends \Zotlabs\Web\Controller {
}
$sql_extra = $search_flags;
if(argv(1) === 'pending')
if (argv(1) === 'pending') {
$sql_extra .= " and abook_ignored = 0 ";
}
}
else {
$sql_extra = " and abook_blocked = 0 ";
@ -179,7 +188,7 @@ class Connections extends \Zotlabs\Web\Controller {
$search_txt = dbesc(protect_sprintf(preg_quote($search)));
$searching = true;
}
$sql_extra .= (($searching) ? protect_sprintf(" AND xchan_name like '%$search_txt%' ") : "");
$sql_extra .= (($searching) ? protect_sprintf(" AND ( xchan_name like '%$search_txt%' OR abook_alias like '%$search_txt%' ) ") : "");
if($_REQUEST['gid']) {
$sql_extra .= " and xchan_hash in ( select xchan from pgrp_member where gid = " . intval($_REQUEST['gid']) . " and uid = " . intval(local_channel()) . " ) ";
@ -190,15 +199,15 @@ class Connections extends \Zotlabs\Web\Controller {
intval(local_channel())
);
if($r) {
\App::set_pager_total($r[0]['total']);
App::set_pager_total($r[0]['total']);
$total = $r[0]['total'];
}
$r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash
WHERE abook_channel = %d and abook_self = 0 and xchan_deleted = 0 and xchan_orphan = 0 $sql_extra $sql_extra2 ORDER BY xchan_name LIMIT %d OFFSET %d ",
intval(local_channel()),
intval(\App::$pager['itemspage']),
intval(\App::$pager['start'])
intval(App::$pager['itemspage']),
intval(App::$pager['start'])
);
$contacts = array();
@ -247,7 +256,7 @@ class Connections extends \Zotlabs\Web\Controller {
'delete_hover' => t('Delete connection'),
'id' => $rr['abook_id'],
'thumb' => $rr['xchan_photo_m'],
'name' => $rr['xchan_name'],
'name' => $rr['xchan_name'] . (($rr['abook_alias']) ? ' &lt;' . $rr['abook_alias'] . '&gt;' : ''),
'classes' => ((intval($rr['abook_archived']) || intval($rr['abook_not_here'])) ? 'archived' : ''),
'link' => z_root() . '/connedit/' . $rr['abook_id'],
'deletelink' => z_root() . '/connedit/' . intval($rr['abook_id']) . '/drop',
@ -303,7 +312,7 @@ class Connections extends \Zotlabs\Web\Controller {
'$finding' => (($searching) ? t('Connections search') . ": '" . $search . "'" : ""),
'$submit' => t('Find'),
'$edit' => t('Edit'),
'$cmd' => \App::$cmd,
'$cmd' => App::$cmd,
'$contacts' => $contacts,
'$paginate' => paginate($a),

View file

@ -74,15 +74,6 @@ class Connedit extends Controller {
$channel = App::get_channel();
// TODO if configured for hassle-free permissions, we'll post the form with ajax as soon as the
// connection enable is toggled to a special autopost url and set permissions immediately, leaving
// the other form elements alone pending a manual submit of the form. The downside is that there
// will be a window of opportunity when the permissions have been set but before you've had a chance
// to review and possibly restrict them. The upside is we won't have to warn you that your connection
// can't do anything until you save the bloody form.
$autopost = (((argc() > 2) && (argv(2) === 'auto')) ? true : false);
$orig_record = q("SELECT * FROM abook WHERE abook_id = %d AND abook_channel = %d LIMIT 1",
intval($contact_id),
intval(local_channel())
@ -127,6 +118,7 @@ class Connedit extends Controller {
$abook_incl = ((array_key_exists('abook_incl',$_POST)) ? escape_tags($_POST['abook_incl']) : $orig_record[0]['abook_incl']);
$abook_excl = ((array_key_exists('abook_excl',$_POST)) ? escape_tags($_POST['abook_excl']) : $orig_record[0]['abook_excl']);
$abook_alias = ((array_key_exists('abook_alias',$_POST)) ? escape_tags(trim($_POST['abook_alias'])) : $orig_record[0]['abook_alias']);
$hidden = intval($_POST['hidden']);
@ -184,13 +176,14 @@ class Connedit extends Controller {
$abook_pending = (($new_friend) ? 0 : $orig_record[0]['abook_pending']);
$r = q("UPDATE abook SET abook_profile = '%s', abook_closeness = %d, abook_pending = %d,
abook_incl = '%s', abook_excl = '%s'
abook_incl = '%s', abook_excl = '%s', abook_alias = '%s'
where abook_id = %d AND abook_channel = %d",
dbesc($profile_id),
intval($closeness),
intval($abook_pending),
dbesc($abook_incl),
dbesc($abook_excl),
dbesc($abook_alias),
intval($contact_id),
intval(local_channel())
);
@ -248,7 +241,6 @@ class Connedit extends Controller {
}
// pull in a bit of content if there is any to pull in
Master::Summon( [ 'Onepoll', $contact_id ]);
@ -287,33 +279,33 @@ class Connedit extends Controller {
function connedit_clone(&$a) {
if(! App::$poi)
return;
if (! App::$poi) {
return;
}
$channel = App::get_channel();
$channel = App::get_channel();
$r = q("SELECT abook.*, xchan.*
FROM abook left join xchan on abook_xchan = xchan_hash
WHERE abook_channel = %d and abook_id = %d LIMIT 1",
intval(local_channel()),
intval(App::$poi['abook_id'])
);
if ($r) {
App::$poi = array_shift($r);
}
$r = q("SELECT abook.*, xchan.*
FROM abook left join xchan on abook_xchan = xchan_hash
WHERE abook_channel = %d and abook_id = %d LIMIT 1",
intval(local_channel()),
intval(App::$poi['abook_id'])
);
if($r) {
App::$poi = array_shift($r);
}
$clone = App::$poi;
$clone = App::$poi;
unset($clone['abook_id']);
unset($clone['abook_account']);
unset($clone['abook_channel']);
unset($clone['abook_id']);
unset($clone['abook_account']);
unset($clone['abook_channel']);
$abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']);
if($abconfig)
$clone['abconfig'] = $abconfig;
Libsync::build_sync_packet(0 /* use the current local_channel */, array('abook' => array($clone)));
$abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']);
if ($abconfig) {
$clone['abconfig'] = $abconfig;
}
Libsync::build_sync_packet($channel['channel_id'], [ 'abook' => [ $clone ] ] );
}
/* @brief Generate content of connection edit page
@ -793,7 +785,7 @@ class Connedit extends Controller {
$not_here = t('This connection is unreachable from this location. Location independence is not supported by their network.');
$o .= replace_macros($tpl, [
'$header' => (($self) ? t('Connection Default Permissions') : sprintf( t('Connection: %s'),$contact['xchan_name'])),
'$header' => (($self) ? t('Connection Default Permissions') : sprintf( t('Connection: %s'),$contact['xchan_name']) . (($contact['abook_alias']) ? ' &lt;' . $contact['abook_alias'] . '&gt;' : '')),
'$autoperms' => array('autoperms',t('Apply these permissions automatically'), ((get_pconfig(local_channel(),'system','autoperms')) ? 1 : 0), t('Connection requests will be approved without your interaction'), $yes_no),
'$permcat' => [ 'permcat', t('Permission role'), '', '<span class="loading invisible">' . t('Loading') . '<span class="jumping-dots"><span class="dot-1">.</span><span class="dot-2">.</span><span class="dot-3">.</span></span></span>',$permcats ],
'$permcat_new' => t('Add permission role'),
@ -820,6 +812,7 @@ class Connedit extends Controller {
'$connfilter_label' => t('Custom Filter'),
'$incl' => array('abook_incl',t('Only import posts with this text'), $contact['abook_incl'],t('words one per line or #tags, $categories, /patterns/, or lang=xx, leave blank to import all posts')),
'$excl' => array('abook_excl',t('Do not import posts with this text'), $contact['abook_excl'],t('words one per line or #tags, $categories, /patterns/, or lang=xx, leave blank to import all posts')),
'$alias' => array('abook_alias',t('Nickname'), $contact['abook_alias'],t('optional - allows you to search by a name that you have chosen')),
'$rating_text' => array('rating_text', t('Optionally explain your rating'),$rating_text,''),
'$rating_info' => t('This information is public!'),
'$rating' => $rating,

View file

@ -431,8 +431,7 @@ logger('gis: ' . print_r($gis,true));
'$modalerrorlink' => t('Error getting photo link'),
'$modalerroralbum' => t('Error getting album'),
'$form_security_token' => get_form_security_token("cover_photo"),
/// @FIXME - yuk
'$select' => t('Select existing photo'),
'$select' => t('Select previously uploaded photo'),
));

View file

@ -0,0 +1,73 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\LDSignatures;
use Zotlabs\Lib\Activity;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Libprofile;
class Followers extends Controller {
function init() {
if (observer_prohibited(true)) {
http_status_exit(403, 'Forbidden');
}
if (argc() < 2) {
http_status_exit(404, 'Not found');
}
$channel = channelx_by_nick(argv(1));
if (! $channel) {
http_status_exit(404, 'Not found');
}
Libprofile::load(argv(1));
$observer_hash = get_observer_hash();
if (((! (is_array(App::$profile) && count(App::$profile))) || (App::$profile['hide_friends']))) {
http_status_exit(403, 'Forbidden');
}
if (! perm_is_allowed($channel['channel_id'],$observer_hash,'view_contacts')) {
http_status_exit(403, 'Forbidden');
}
$r = q("select * from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'their_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0",
intval($channel['channel_id']),
intval($channel['channel_id']),
dbesc($channel['channel_hash'])
);
if (ActivityStreams::is_as_request()) {
$x = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
z_root() . ZOT_APSCHEMA_REV
]], Activity::encode_follow_collection($r, App::$query_string, 'OrderedCollection'));
$headers = [];
$headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ;
$x['signature'] = LDSignatures::sign($x,$channel);
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel));
HTTPSig::set_headers($h);
echo $ret;
killme();
}
}
}

View file

@ -0,0 +1,70 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\LDSignatures;
use Zotlabs\Lib\Activity;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Libprofile;
class Following extends Controller {
function init() {
if (observer_prohibited(true)) {
http_status_exit(403, 'Forbidden');
}
if (argc() < 2) {
http_status_exit(404, 'Not found');
}
$channel = channelx_by_nick(argv(1));
if (! $channel) {
http_status_exit(404, 'Not found');
}
Libprofile::load(argv(1));
$observer_hash = get_observer_hash();
if (((! (is_array(App::$profile) && count(App::$profile))) || (App::$profile['hide_friends']))) {
http_status_exit(403, 'Forbidden');
}
if (! perm_is_allowed($channel['channel_id'],$observer_hash,'view_contacts')) {
http_status_exit(403, 'Forbidden');
}
$r = q("select * from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'my_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0",
intval($channel['channel_id']),
intval($channel['channel_id']),
dbesc($channel['channel_hash'])
);
if (ActivityStreams::is_as_request()) {
$x = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
z_root() . ZOT_APSCHEMA_REV
]], Activity::encode_follow_collection($r, App::$query_string, 'OrderedCollection'));
$headers = [];
$headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ;
$x['signature'] = LDSignatures::sign($x,$channel);
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel));
HTTPSig::set_headers($h);
echo $ret;
killme();
}
}
}

View file

@ -90,7 +90,7 @@ class Id extends Controller {
xchan_query($r,true);
$items = fetch_post_tags($r,true);
$i = Activity::encode_item($items[0],( defined('NOMADIC') ? false : true));
$i = Activity::encode_item($items[0],( get_config('system','activitypub') ? true : false ));
if(! $i)
http_status_exit(404, 'Not found');

257
Zotlabs/Module/Inbox.php Normal file
View file

@ -0,0 +1,257 @@
<?php
namespace Zotlabs\Module;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\Activity;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Config;
class Inbox extends Controller {
function post() {
// This SHOULD be handled by the webserver, but in the RFC it is only indicated as
// a SHOULD and not a MUST, so some webservers fail to reject appropriately.
logger('accepting: ' . $_SERVER['HTTP_ACCEPT'],LOGGER_DEBUG);
if ((array_key_exists('HTTP_ACCEPT',$_SERVER)) && ($_SERVER['HTTP_ACCEPT'])
&& (strpos($_SERVER['HTTP_ACCEPT'],'*') === false) && (! ActivityStreams::is_as_request())) {
http_status_exit(406,'not acceptable');
}
$sys_disabled = ((Config::Get('system','disable_discover_tab') || Config::Get('system','disable_activitypub_discover_tab')) ? true : false);
$is_public = false;
if (argc() == 1 || argv(1) === '[public]') {
$is_public = true;
}
else {
$channels = [ channelx_by_nick(argv(1)) ];
}
$data = file_get_contents('php://input');
if (! $data) {
return;
}
logger('inbox_activity: ' . jindent($data), LOGGER_DATA);
$hsig = HTTPSig::verify($data);
$AS = new ActivityStreams($data);
//logger('debug: ' . $AS->debug());
if (! $AS->is_valid()) {
if ($AS->deleted) {
// process mastodon user deletion activities, but only if we can validate the signature
if ($hsig['header_valid'] && $hsig['content_valid'] && $hsig['portable_id']) {
logger('removing deleted actor');
remove_all_xchan_resources($hsig['portable_id']);
}
else {
logger('ignoring deleted actor', LOGGER_DEBUG, LOG_INFO);
}
}
return;
}
// $observer_hash in this case is the sender
if ($hsig['header_valid'] && $hsig['content_valid'] && $hsig['portable_id']) {
$observer_hash = $hsig['portable_id'];
}
else {
$observer_hash = $AS->actor['id'];
}
if (! $observer_hash) {
return;
}
$m = parse_url($observer_hash);
if ($m && $m['scheme'] && $m['host']) {
if (! check_siteallowed($m['scheme'] . '://' . $m['host'])) {
http_status_exit(404,'Permission denied');
}
}
if (is_array($AS->actor) && array_key_exists('id',$AS->actor)) {
Activity::actor_store($AS->actor['id'],$AS->actor);
}
if (is_array($AS->obj) && ActivityStreams::is_an_actor($AS->obj['type'])) {
Activity::actor_store($AS->obj['id'],$AS->obj);
}
if (is_array($AS->obj) && is_array($AS->obj['actor']) && array_key_exists('id',$AS->obj['actor']) && $AS->obj['actor']['id'] !== $AS->actor['id']) {
Activity::actor_store($AS->obj['actor']['id'],$AS->obj['actor']);
}
$test = q("update hubloc set hubloc_connected = '%s' where hubloc_hash = '%s' and hubloc_network = 'activitypub'",
dbesc(datetime_convert()),
dbesc($observer_hash)
);
// $test is ignored
if ($is_public) {
if ($AS->type === 'Follow' && $AS->obj && ActivityStreams::is_an_actor($AS->obj['type'])) {
$channels = q("SELECT * from channel where channel_address = '%s' and channel_removed = 0 ",
dbesc(basename($AS->obj['id']))
);
}
else {
// deliver to anybody following $AS->actor
$channels = q("SELECT * from channel where channel_id in ( SELECT abook_channel from abook left join xchan on abook_xchan = xchan_hash WHERE xchan_network = 'activitypub' and xchan_hash = '%s' ) and channel_removed = 0 ",
dbesc($observer_hash)
);
if (! $channels) {
$channels = [];
}
$parent = $AS->parent_id;
if ($parent) {
// this is a comment - deliver to everybody who owns the parent
$owners = q("SELECT * from channel where channel_id in ( SELECT uid from item where mid = '%s' ) ",
dbesc($parent)
);
if ($owners) {
$channels = array_merge($channels,$owners);
}
}
}
if ($channels === false) {
$channels = [];
}
if (in_array(ACTIVITY_PUBLIC_INBOX,$AS->recips)) {
// look for channels with send_stream = PERMS_PUBLIC
$r = q("select * from channel where channel_id in (select uid from pconfig where cat = 'perm_limits' and k = 'send_stream' and v = '1' ) and channel_removed = 0 ");
if ($r) {
$channels = array_merge($channels,$r);
}
if (! $sys_disabled) {
$channels[] = get_sys_channel();
}
}
}
if (! $channels) {
logger('no deliveries on this site');
return;
}
$saved_recips = [];
foreach ( [ 'to', 'cc', 'audience' ] as $x ) {
if (array_key_exists($x,$AS->data)) {
$saved_recips[$x] = $AS->data[$x];
}
}
$AS->set_recips($saved_recips);
foreach ($channels as $channel) {
switch ($AS->type) {
case 'Follow':
if ($AS->obj & ActivityStreams::is_an_actor($AS->obj['type'])) {
// do follow activity
Activity::follow($channel,$AS);
}
break;
case 'Accept':
if ($AS->obj & $AS->obj['type'] === 'Follow') {
// do follow activity
Activity::follow($channel,$AS);
}
break;
case 'Reject':
default:
break;
}
// These activities require permissions
$item = null;
switch ($AS->type) {
case 'Update':
if (is_array($AS->obj) && array_key_exists('type',$AS->obj) && ActivityStreams::is_an_actor($AS->obj['type'])) {
// pretend this is an old cache entry to force an update of all the actor details
$AS->obj['cached'] = true;
$AS->obj['updated'] = datetime_convert('UTC','UTC','1980-01-01', ATOM_TIME);
Activity::actor_store($AS->obj['id'],$AS->obj);
break;
}
case 'Create':
case 'Like':
case 'Dislike':
case 'Announce':
case 'Accept':
case 'Reject':
case 'TentativeAccept':
case 'TentativeReject':
case 'emojiReaction':
// These require a resolvable object structure
if (is_array($AS->obj)) {
// replies must go to the replyTo endpoint if the top level post originated here.
$item = Activity::decode_note($AS);
if ($item['mid'] !== $item['parent_mid'] && stripos(z_root(), $item['parent_mid']) === 0) {
$item = null;
break;
}
}
else {
logger('unresolved object: ' . print_r($AS->obj,true));
}
break;
case 'Undo':
if ($AS->obj & $AS->obj['type'] === 'Follow') {
// do unfollow activity
Activity::unfollow($channel,$AS);
break;
}
case 'Delete':
Activity::drop($channel,$observer_hash,$AS);
break;
case 'Add':
case 'Remove':
default:
break;
}
if ($item) {
logger('parsed_item: ' . print_r($item,true),LOGGER_DATA);
Activity::store($channel,$observer_hash,$AS,$item);
}
}
http_status_exit(200,'OK');
}
function get() {
}
}

View file

@ -121,7 +121,7 @@ class Item extends Controller {
if(! perm_is_allowed($chan['channel_id'],get_observer_hash(),'view_stream'))
http_status_exit(403, 'Forbidden');
$i = Activity::encode_item($items[0],((defined('NOMADIC')) ? false : true));
$i = Activity::encode_item($items[0],((get_config('system','activitypub')) ? true : false));
if(! $i)
http_status_exit(404, 'Not found');
@ -267,7 +267,7 @@ class Item extends Controller {
if(! perm_is_allowed($chan['channel_id'],get_observer_hash(),'view_stream'))
http_status_exit(403, 'Forbidden');
$i = Activity::encode_item_collection($nitems,'conversation/' . $item_id,'OrderedCollection',( defined('NOMADIC') ? false : true));
$i = Activity::encode_item_collection($nitems,'conversation/' . $item_id,'OrderedCollection',( get_config('system','activitypub') ? true : false));
if($portable_id) {
ThreadListener::store(z_root() . '/item/' . $item_id,$portable_id);
}
@ -299,8 +299,9 @@ class Item extends Controller {
// the text/html page of the item.
if (argc() > 1 && argv(1) !== 'drop') {
$x = q("select uid, item_wall, llink, mid from item where mid = '%s' ",
dbesc(z_root() . '/item/' . argv(1))
$x = q("select uid, item_wall, llink, mid from item where mid = '%s' or mid = '%s' ",
dbesc(z_root() . '/item/' . argv(1)),
dbesc(z_root() . '/activity/' . argv(1))
);
if ($x) {
foreach ($x as $xv) {
@ -1224,7 +1225,7 @@ class Item extends Controller {
if(! array_key_exists('obj',$datarray)) {
$copy = $datarray;
$copy['author'] = $observer;
$datarray['obj'] = Activity::encode_item($copy,((defined('NOMADIC')) ? false : true));
$datarray['obj'] = Activity::encode_item($copy,((get_config('system','activitypub')) ? true : false));
}
// A specific ACL over-rides public_policy completely

View file

@ -33,7 +33,7 @@ class Photo extends \Zotlabs\Web\Controller {
$channel = channelx_by_n($r[0]['uid']);
$obj = json_decode($r[0]['obj'],true);
$obj['actor'] = Activity::encode_person($channel,true,((defined('NOMADIC')) ? false : true));
$obj['actor'] = Activity::encode_person($channel,true,((get_config('system','activitypub')) ? true : false));
$x = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,

View file

@ -394,7 +394,7 @@ class Ping extends Controller {
if ($r) {
foreach ($r as $rr) {
$local_result[] = [
'notify_link' => z_root() . '/connections/ifpending',
'notify_link' => z_root() . '/connections/' . $rr['abook_id'],
'name' => $rr['xchan_name'],
'addr' => $rr['xchan_addr'],
'url' => $rr['xchan_url'],

View file

@ -75,7 +75,7 @@ class Profile extends \Zotlabs\Web\Controller {
$chan = channelx_by_nick(argv(1));
if(! $chan)
http_status_exit(404, 'Not found');
$p = Activity::encode_person($chan,true,((defined('NOMADIC')) ? false : true));
$p = Activity::encode_person($chan,true,((get_config('system','activitypub')) ? true : false));
if(! $p) {
http_status_exit(404, 'Not found');
}

View file

@ -1,24 +1,23 @@
<?php
namespace Zotlabs\Module;
/*
* @file Profile_photo.php
* @brief Module-file with functions for uploading and scaling of profile-photos
*
*/
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Libsync;
use Zotlabs\Lib\Libprofile;
use Zotlabs\Daemon\Master;
/*
* @file Profile_photo.php
* @brief Module-file with functions for handling of profile-photos
*
*/
require_once('include/photo_factory.php');
require_once('include/photos.php');
class Profile_photo extends Controller {
@ -48,49 +47,46 @@ class Profile_photo extends Controller {
function post() {
if(! local_channel()) {
if (! local_channel()) {
return;
}
check_form_security_token_redirectOnErr('/profile_photo', 'profile_photo');
if((array_key_exists('cropfinal',$_POST)) && (intval($_POST['cropfinal']) == 1)) {
if ((array_key_exists('cropfinal',$_POST)) && (intval($_POST['cropfinal']) == 1)) {
// logger('crop: ' . print_r($_POST,true));
// phase 2 - we have finished cropping
if(argc() != 2) {
if (argc() != 2) {
notice( t('Image uploaded but image cropping failed.') . EOL );
return;
}
$image_id = argv(1);
if(substr($image_id,-2,1) == '-') {
if (substr($image_id,-2,1) == '-') {
$scale = substr($image_id,-1,1);
$image_id = substr($image_id,0,-2);
}
// unless proven otherwise
$is_default_profile = 1;
if($_REQUEST['profile']) {
if ($_REQUEST['profile']) {
$r = q("select id, profile_guid, is_default, gender from profile where id = %d and uid = %d limit 1",
intval($_REQUEST['profile']),
intval(local_channel())
);
if($r) {
$profile = $r[0];
if(! intval($profile['is_default']))
if ($r) {
$profile = array_shift($r);
if (! intval($profile['is_default'])) {
$is_default_profile = 0;
}
}
}
$srcX = intval($_POST['xstart']);
$srcY = intval($_POST['ystart']);
$srcW = intval($_POST['xfinal']) - $srcX;
@ -100,13 +96,13 @@ class Profile_photo extends Controller {
dbesc($image_id),
dbesc(local_channel()),
intval($scale));
if($r) {
if ($r) {
$base_image = $r[0];
$base_image['content'] = (($r[0]['os_storage']) ? @file_get_contents(dbunescbin($base_image['content'])) : dbunescbin($base_image['content']));
$base_image = array_shift($r);
$base_image['content'] = (($base_image['os_storage']) ? @file_get_contents(dbunescbin($base_image['content'])) : dbunescbin($base_image['content']));
$im = photo_factory($base_image['content'], $base_image['mimetype']);
if($im->is_valid()) {
if ($im->is_valid()) {
$im->cropImage(300,$srcX,$srcY,$srcW,$srcH);
@ -139,7 +135,7 @@ class Profile_photo extends Controller {
$r3 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_48);
if($r1 === false || $r2 === false || $r3 === false) {
if ($r1 === false || $r2 === false || $r3 === false) {
// if one failed, delete them all so we can start over.
notice( t('Image resize failed.') . EOL );
$x = q("delete from photo where resource_id = '%s' and uid = %d and imgscale in ( %d, %d, %d ) ",
@ -156,7 +152,7 @@ class Profile_photo extends Controller {
// 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) {
$r = q("update profile set photo = '%s', thumb = '%s' where is_default = 1 and uid = %d",
dbesc(z_root() . '/photo/profile/l/' . local_channel()),
@ -210,9 +206,9 @@ class Profile_photo extends Controller {
photo_profile_setperms(local_channel(),$base_image['resource_id'],$_REQUEST['profile']);
$sync = attach_export_data($channel,$base_image['resource_id']);
if($sync)
if ($sync) {
Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync), 'profile' => $sync_profiles));
}
// Similarly, tell the nav bar to bypass the cache and update the avatar image.
$_SESSION['reload_avatar'] = true;
@ -223,12 +219,12 @@ class Profile_photo extends Controller {
Master::Summon( [ 'Directory', $channel['channel_id'] ] );
}
else
else {
notice( t('Unable to process image') . EOL);
}
}
goaway(z_root() . '/profiles');
return; // NOTREACHED
}
// A new photo was uploaded. Store it and save some important details
@ -240,7 +236,7 @@ class Profile_photo extends Controller {
$smallest = 0;
if($_REQUEST['importfile']) {
if ($_REQUEST['importfile']) {
$hash = $_REQUEST['importfile'];
$importing = true;
}
@ -249,18 +245,18 @@ class Profile_photo extends Controller {
$matches = [];
$partial = false;
if(array_key_exists('HTTP_CONTENT_RANGE',$_SERVER)) {
if (array_key_exists('HTTP_CONTENT_RANGE',$_SERVER)) {
$pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches);
if($pm) {
logger('Content-Range: ' . print_r($matches,true));
if ($pm) {
logger('Content-Range: ' . print_r($matches,true), LOGGER_DEBUG);
$partial = true;
}
}
if($partial) {
if ($partial) {
$x = save_chunk($channel,$matches[1],$matches[2],$matches[3]);
if($x['partial']) {
if ($x['partial']) {
header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0));
json_return_and_die($result);
}
@ -277,7 +273,7 @@ class Profile_photo extends Controller {
}
}
else {
if(! array_key_exists('userfile',$_FILES)) {
if (! array_key_exists('userfile',$_FILES)) {
$_FILES['userfile'] = [
'name' => $_FILES['files']['name'],
'type' => $_FILES['files']['type'],
@ -290,27 +286,25 @@ class Profile_photo extends Controller {
$res = attach_store(App::get_channel(), get_observer_hash(), '', array('album' => t('Profile Photos'), 'hash' => $hash));
logger('attach_store: ' . print_r($res,true));
logger('attach_store: ' . print_r($res,true), LOGGER_DEBUG);
json_return_and_die([ 'message' => $hash ]);
}
if(($res && intval($res['data']['is_photo'])) || $importing) {
if (($res && intval($res['data']['is_photo'])) || $importing) {
$i = q("select * from photo where resource_id = '%s' and uid = %d order by imgscale",
dbesc($hash),
intval(local_channel())
);
if(! $i) {
if (! $i) {
notice( t('Image upload failed.') . EOL );
return;
}
$os_storage = false;
foreach($i as $ii) {
if(intval($ii['imgscale']) < PHOTO_RES_640) {
foreach ($i as $ii) {
if (intval($ii['imgscale']) < PHOTO_RES_640) {
$smallest = intval($ii['imgscale']);
$os_storage = intval($ii['os_storage']);
$imagedata = $ii['content'];
@ -322,12 +316,12 @@ class Profile_photo extends Controller {
$imagedata = (($os_storage) ? @file_get_contents(dbunescbin($imagedata)) : dbunescbin($imagedata));
$ph = photo_factory($imagedata, $filetype);
if(! $ph->is_valid()) {
if (! $ph->is_valid()) {
notice( t('Unable to process image.') . EOL );
return;
}
return $this->profile_photo_crop_ui_head($a, $ph, $hash, $smallest);
return $this->profile_photo_crop_ui_head($ph, $hash, $smallest);
// This will "fall through" to the get() method, and since
// App::$data['imagecrop'] is set, it will proceed to cropping
@ -337,7 +331,6 @@ class Profile_photo extends Controller {
/* @brief Generate content of profile-photo view
*
* @param $a Current application
* @return void
*
*/
@ -345,7 +338,7 @@ class Profile_photo extends Controller {
function get() {
if(! local_channel()) {
if (! local_channel()) {
notice( t('Permission denied.') . EOL );
return;
}
@ -354,10 +347,11 @@ class Profile_photo extends Controller {
$pf = 0;
$newuser = false;
if(argc() == 2 && argv(1) === 'new')
if (argc() == 2 && argv(1) === 'new') {
$newuser = true;
}
if(argv(1) === 'use') {
if (argv(1) === 'use') {
if (argc() < 3) {
notice( t('Permission denied.') . EOL );
return;
@ -365,7 +359,6 @@ class Profile_photo extends Controller {
$resource_id = argv(2);
$pf = (($_REQUEST['pf']) ? intval($_REQUEST['pf']) : 0);
$c = q("select id, is_default from profile where uid = %d",
@ -374,7 +367,7 @@ class Profile_photo extends Controller {
$multi_profiles = true;
if(($c) && (count($c) === 1) && (intval($c[0]['is_default']))) {
if (($c) && (count($c) === 1) && (intval($c[0]['is_default']))) {
$_REQUEST['profile'] = $c[0]['id'];
$multi_profiles = false;
}
@ -386,33 +379,34 @@ class Profile_photo extends Controller {
intval(local_channel()),
dbesc($resource_id)
);
if(! $r) {
if (! $r) {
notice( t('Photo not available.') . EOL );
return;
}
$havescale = false;
foreach($r as $rr) {
if($rr['imgscale'] == PHOTO_RES_PROFILE_80)
foreach ($r as $rr) {
if ($rr['imgscale'] == PHOTO_RES_PROFILE_80) {
$havescale = true;
}
}
// set an already loaded and cropped photo as profile photo
if($havescale) {
if ($havescale) {
// unset any existing profile photos
$r = q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND uid = %d",
intval(PHOTO_NORMAL),
intval(PHOTO_PROFILE),
intval(local_channel()));
intval(local_channel())
);
$r = q("UPDATE photo SET photo_usage = %d WHERE uid = %d AND resource_id = '%s'",
intval(PHOTO_PROFILE),
intval(local_channel()),
dbesc($resource_id)
);
);
$r = q("UPDATE xchan set xchan_photo_date = '%s'
where xchan_hash = '%s'",
$r = q("UPDATE xchan set xchan_photo_date = '%s' where xchan_hash = '%s'",
dbesc(datetime_convert()),
dbesc($channel['xchan_hash'])
);
@ -420,11 +414,11 @@ class Profile_photo extends Controller {
photo_profile_setperms(local_channel(),$resource_id,$_REQUEST['profile']);
$sync = attach_export_data($channel,$resource_id);
if($sync)
if ($sync) {
Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
}
\Zotlabs\Daemon\Master::Summon(array('Directory',local_channel()));
Master::Summon( [ 'Directory',local_channel() ] );
goaway(z_root() . '/profiles');
}
@ -433,154 +427,148 @@ class Profile_photo extends Controller {
intval(local_channel())
);
if(! $r) {
if (! $r) {
notice( t('Photo not available.') . EOL );
return;
}
if(intval($r[0]['os_storage']))
if (intval($r[0]['os_storage'])) {
$data = @file_get_contents(dbunescbin($r[0]['content']));
else
}
else {
$data = dbunescbin($r[0]['content']);
}
$ph = photo_factory($data, $r[0]['mimetype']);
$smallest = 0;
if($ph->is_valid()) {
if ($ph->is_valid()) {
// go ahead as if we have just uploaded a new photo to crop
$i = q("select resource_id, imgscale from photo where resource_id = '%s' and uid = %d order by imgscale",
dbesc($r[0]['resource_id']),
intval(local_channel())
);
if($i) {
if ($i) {
$hash = $i[0]['resource_id'];
foreach($i as $ii) {
if(intval($ii['imgscale']) < PHOTO_RES_640) {
foreach ($i as $ii) {
if (intval($ii['imgscale']) < PHOTO_RES_640) {
$smallest = intval($ii['imgscale']);
}
}
}
}
if($multi_profiles) {
if ($multi_profiles) {
App::$data['importfile'] = $resource_id;
}
else {
$this->profile_photo_crop_ui_head($a, $ph, $hash, $smallest);
$this->profile_photo_crop_ui_head($ph, $hash, $smallest);
}
// falls through with App::$data['imagecrop'] set so we go straight to the cropping section
}
// present an upload form
$profiles = q("select id, profile_name as name, is_default from profile where uid = %d order by id asc",
intval(local_channel())
);
if($profiles) {
for($x = 0; $x < count($profiles); $x ++) {
if ($profiles) {
for ($x = 0; $x < count($profiles); $x ++) {
$profiles[$x]['selected'] = false;
if($pf && $profiles[$x]['id'] == $pf)
if ($pf && $profiles[$x]['id'] == $pf) {
$profiles[$x]['selected'] = true;
if((! $pf) && $profiles[$x]['is_default'])
}
if ((! $pf) && $profiles[$x]['is_default']) {
$profiles[$x]['selected'] = true;
}
}
}
$importing = ((array_key_exists('importfile',App::$data)) ? true : false);
if(! x(App::$data,'imagecrop')) {
if (! array_key_exists('imagecrop', App::$data)) {
$tpl = get_markup_template('profile_photo.tpl');
$o .= replace_macros($tpl,array(
'$user' => App::$channel['channel_address'],
'$info' => ((count($profiles) > 1) ? t('Your default profile photo is visible to anybody on the internet. Profile photos for alternate profiles will inherit the permissions of the profile') : t('Your profile photo is visible to anybody on the internet and may be distributed to other websites.')),
'$importfile' => (($importing) ? App::$data['importfile'] : ''),
'$lbl_upfile' => t('Upload File:'),
'$lbl_profiles' => t('Select a profile:'),
'$title' => (($importing) ? t('Use Photo for Profile') : t('Change Profile Photo')),
'$submit' => (($importing) ? t('Use') : t('Upload')),
'$profiles' => $profiles,
'$single' => ((count($profiles) == 1) ? true : false),
'$profile0' => $profiles[0],
'$embedPhotos' => t('Use a photo from your albums'),
'$embedPhotosModalTitle' => t('Use a photo from your albums'),
$o .= replace_macros($tpl, [
'$user' => App::$channel['channel_address'],
'$info' => ((count($profiles) > 1) ? t('Your default profile photo is visible to anybody on the internet. Profile photos for alternate profiles will inherit the permissions of the profile') : t('Your profile photo is visible to anybody on the internet and may be distributed to other websites.')),
'$importfile' => (($importing) ? App::$data['importfile'] : ''),
'$lbl_upfile' => t('Upload File:'),
'$lbl_profiles' => t('Select a profile:'),
'$title' => (($importing) ? t('Use Photo for Profile') : t('Change Profile Photo')),
'$submit' => (($importing) ? t('Use') : t('Upload')),
'$profiles' => $profiles,
'$single' => ((count($profiles) == 1) ? true : false),
'$profile0' => $profiles[0],
'$embedPhotos' => t('Use a photo from your albums'),
'$embedPhotosModalTitle' => t('Use a photo from your albums'),
'$embedPhotosModalCancel' => t('Cancel'),
'$embedPhotosModalOK' => t('OK'),
'$modalchooseimages' => t('Choose images to embed'),
'$modalchoosealbum' => t('Choose an album'),
'$modaldiffalbum' => t('Choose a different album'),
'$modalerrorlist' => t('Error getting album list'),
'$modalerrorlink' => t('Error getting photo link'),
'$modalerroralbum' => t('Error getting album'),
'$form_security_token' => get_form_security_token("profile_photo"),
'$select' => t('Select existing photo'),
));
'$embedPhotosModalOK' => t('OK'),
'$modalchooseimages' => t('Choose images to embed'),
'$modalchoosealbum' => t('Choose an album'),
'$modaldiffalbum' => t('Choose a different album'),
'$modalerrorlist' => t('Error getting album list'),
'$modalerrorlink' => t('Error getting photo link'),
'$modalerroralbum' => t('Error getting album'),
'$form_security_token' => get_form_security_token("profile_photo"),
'$select' => t('Select previously uploaded photo'),
]);
call_hooks('profile_photo_content_end', $o);
return $o;
}
else {
// present a cropping form
$filename = App::$data['imagecrop'] . '-' . App::$data['imagecrop_resolution'];
$filename = App::$data['imagecrop'] . '-' . App::$data['imagecrop_resolution'];
$resolution = App::$data['imagecrop_resolution'];
$tpl = get_markup_template("cropbody.tpl");
$o .= replace_macros($tpl,array(
'$filename' => $filename,
'$profile' => intval($_REQUEST['profile']),
'$resource' => App::$data['imagecrop'] . '-' . App::$data['imagecrop_resolution'],
'$image_url' => z_root() . '/photo/' . $filename,
'$title' => t('Crop Image'),
'$desc' => t('Please adjust the image cropping for optimum viewing.'),
$o .= replace_macros(get_markup_template('cropbody.tpl'), [
'$filename' => $filename,
'$profile' => intval($_REQUEST['profile']),
'$resource' => App::$data['imagecrop'] . '-' . App::$data['imagecrop_resolution'],
'$image_url' => z_root() . '/photo/' . $filename,
'$title' => t('Crop Image'),
'$desc' => t('Please adjust the image cropping for optimum viewing.'),
'$form_security_token' => get_form_security_token("profile_photo"),
'$done' => t('Done Editing')
));
'$done' => t('Done Editing')
]);
return $o;
}
return; // NOTREACHED
}
/* @brief Generate the UI for photo-cropping
*
* @param $a Current application
* @param $ph Photo-Factory
* @return void
*
*/
function profile_photo_crop_ui_head(&$a, $ph, $hash, $smallest){
function profile_photo_crop_ui_head($ph, $hash, $smallest) {
$max_length = get_config('system','max_image_length');
if(! $max_length)
if (! $max_length) {
$max_length = MAX_IMAGE_LENGTH;
if($max_length > 0)
}
if ($max_length > 0) {
$ph->scaleImage($max_length);
}
App::$data['width'] = $ph->getWidth();
App::$data['height'] = $ph->getHeight();
if(App::$data['width'] < 500 || App::$data['height'] < 500) {
if (App::$data['width'] < 500 || App::$data['height'] < 500) {
$ph->scaleImageUp(400);
App::$data['width'] = $ph->getWidth();
App::$data['height'] = $ph->getHeight();
}
App::$data['imagecrop'] = $hash;
App::$data['imagecrop_resolution'] = $smallest;
App::$page['htmlhead'] .= replace_macros(get_markup_template("crophead.tpl"), array());
App::$page['htmlhead'] .= replace_macros(get_markup_template('crophead.tpl'), []);
return;
}
}

View file

@ -475,8 +475,6 @@ class Channel {
$default_permcat = get_pconfig(local_channel(),'system','default_permcat','default');
$stpl = get_markup_template('settings.tpl');
$acl = new AccessControl($channel);
$perm_defaults = $acl->get();
@ -528,9 +526,8 @@ class Channel {
$site_firehose = intval(get_config('system','site_firehose',0)) == 1;
$o .= replace_macros($stpl,array(
$o .= replace_macros(get_markup_template('settings.tpl'), [
'$ptitle' => t('Channel Settings'),
'$submit' => t('Submit'),
'$baseurl' => z_root(),
'$uid' => local_channel(),
@ -551,11 +548,6 @@ class Channel {
'$hide_presence' => array('hide_presence', t('Hide my online presence'),$hide_presence, t('Prevents displaying in your profile that you are online'), $yes_no),
'$lbl_pmacro' => t('Simple Privacy Settings:'),
'$pmacro3' => t('Very Public - <em>extremely permissive (should be used with caution)</em>'),
'$pmacro2' => t('Typical - <em>default public, privacy when desired (similar to social network permissions but with improved privacy)</em>'),
'$pmacro1' => t('Private - <em>default private, never open or public</em>'),
'$pmacro0' => t('Blocked - <em>default blocked to/from everybody</em>'),
'$permiss_arr' => $permiss,
'$comment_perms' => $comment_perms,
@ -640,20 +632,16 @@ class Channel {
'$h_descadvn' => t('Change the behaviour of this account for special situations'),
'$pagetype' => $pagetype,
'$lbl_misc' => t('Miscellaneous Settings'),
'$photo_path' => array('photo_path', t('Default photo upload folder'), get_pconfig(local_channel(),'system','photo_path'), t('%Y - current year, %m - current month')),
'$attach_path' => array('attach_path', t('Default file upload folder'), get_pconfig(local_channel(),'system','attach_path'), t('%Y - current year, %m - current month')),
'$photo_path' => array('photo_path', t('Default photo upload folder name'), get_pconfig(local_channel(),'system','photo_path'), t('%Y - current year, %m - current month')),
'$attach_path' => array('attach_path', t('Default file upload folder name'), get_pconfig(local_channel(),'system','attach_path'), t('%Y - current year, %m - current month')),
'$menus' => $menu,
'$menu_desc' => t('Personal menu to display in your channel pages'),
'$removeme' => t('Remove Channel'),
'$removechannel' => t('Remove this channel.'),
'$firefoxshare' => t('Firefox Share $Projectname provider'),
'$cal_first_day' => array('first_day', t('Start calendar week on Monday'), ((get_pconfig(local_channel(),'system','cal_first_day')) ? 1 : ''), '', $yes_no),
));
]);
call_hooks('settings_form',$o);
//$o .= '</form>' . "\r\n";
return $o;
}
}

View file

@ -15,7 +15,7 @@ class Siteinfo extends Controller {
function get() {
if(defined('NOMADIC')) {
if(! get_config('system','activitypub')) {
$federated = [ 'zot6' ];
}
else {

View file

@ -111,7 +111,7 @@ class Webfinger extends Controller {
'http://webfinger.net/ns/name' => $channel_target['channel_name'],
'http://xmlns.com/foaf/0.1/name' => $channel_target['channel_name'],
'https://w3id.org/security/v1#publicKeyPem' => $channel_target['xchan_pubkey'],
'http://purl.org/zot/federation' => ((defined('NOMADIC')) ? 'zot6' : 'zot6,activitypub')
'http://purl.org/zot/federation' => ((get_config('system','activitypub')) ? 'zot6,activitypub' : 'zot6')
];
foreach ($aliases as $alias) {
@ -150,6 +150,18 @@ class Webfinger extends Controller {
'href' => z_root() . '/owa'
],
[
'rel' => 'self',
'type' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
'href' => z_root() . '/channel/' . $channel_target['channel_address']
],
[
'rel' => 'self',
'type' => 'application/activity+json',
'href' => z_root() . '/channel/' . $channel_target['channel_address']
],
[
'rel' => 'http://ostatus.org/schema/1.0/subscribe',
'template' => z_root() . '/follow?url={uri}'
@ -157,19 +169,6 @@ class Webfinger extends Controller {
];
}
if (! defined('NOMADIC')) {
$result['links'][] = [
'rel' => 'self',
'type' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
'href' => z_root() . '/channel/' . $channel_target['channel_address']
];
$result['links'][] = [
'rel' => 'self',
'type' => 'application/activity+json',
'href' => z_root() . '/channel/' . $channel_target['channel_address']
];
}
if (! $result) {
header($_SERVER['SERVER_PROTOCOL'] . ' ' . 400 . ' ' . 'Bad Request');
killme();

View file

@ -1,27 +1,31 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Module\Webfinger;
use Zotlabs\Module\Oauthinfo;
class Well_known extends \Zotlabs\Web\Controller {
class Well_known extends Controller {
function init() {
if(argc() > 1) {
if (argc() > 1) {
$arr = array('server' => $_SERVER, 'request' => $_REQUEST);
$arr = [ 'server' => $_SERVER, 'request' => $_REQUEST ];
call_hooks('well_known', $arr);
if(! check_siteallowed($_SERVER['REMOTE_ADDR'])) {
if (! check_siteallowed($_SERVER['REMOTE_ADDR'])) {
logger('well_known: site not allowed. ' . $_SERVER['REMOTE_ADDR']);
killme();
}
// from php.net re: REMOTE_HOST:
// Note: Your web server must be configured to create this variable. For example in Apache
// you'll need HostnameLookups On inside httpd.conf for it to exist. See also gethostbyaddr().
// Note: Your web server must be configured to create this variable.
// For example in Apache you'll need HostnameLookups On inside httpd.conf
// for it to exist. See also gethostbyaddr().
if(get_config('system','siteallowed_remote_host') && (! check_siteallowed($_SERVER['REMOTE_HOST']))) {
if (get_config('system','siteallowed_remote_host') && (! check_siteallowed($_SERVER['REMOTE_HOST']))) {
logger('well_known: site not allowed. ' . $_SERVER['REMOTE_HOST']);
killme();
}
@ -29,19 +33,19 @@ class Well_known extends \Zotlabs\Web\Controller {
switch(argv(1)) {
case 'webfinger':
\App::$argc -= 1;
array_shift(\App::$argv);
\App::$argv[0] = 'webfinger';
$module = new \Zotlabs\Module\Webfinger();
App::$argc -= 1;
array_shift(App::$argv);
App::$argv[0] = 'webfinger';
$module = new Webfinger();
$module->init();
break;
case 'oauth-authorization-server':
case 'openid-configuration':
\App::$argc -= 1;
App::$argc -= 1;
array_shift(\App::$argv);
\App::$argv[0] = 'oauthinfo';
$module = new \Zotlabs\Module\Oauthinfo();
App::$argv[0] = 'oauthinfo';
$module = new Oauthinfo();
$module->init();
break;
@ -50,14 +54,13 @@ class Well_known extends \Zotlabs\Web\Controller {
killme();
default:
if(file_exists(\App::$cmd)) {
echo file_get_contents(\App::$cmd);
if (file_exists(App::$cmd)) {
echo file_get_contents(App::$cmd);
killme();
}
elseif(file_exists(\App::$cmd . '.php'))
require_once(\App::$cmd . '.php');
elseif (file_exists(App::$cmd . '.php'))
require_once(App::$cmd . '.php');
break;
}
}

View file

@ -727,14 +727,14 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
return $ret;
}
$r = q("SELECT channel_id, channel_address, profile.publish FROM channel left join profile on profile.uid = channel.channel_id WHERE channel_removed = 0 AND channel_system = 0 AND (channel_pageflags & %d) = 0",
$r = q("SELECT channel_id, channel_address FROM channel left join profile on profile.uid = channel.channel_id WHERE channel_removed = 0 AND channel_system = 0 AND (channel_pageflags & %d) = 0",
intval(PAGE_HIDDEN)
);
if ($r) {
foreach ($r as $rr) {
if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage') && $rr['publish']) {
logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DATA);
if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage')) {
logger('found channel: ' . $rr['channel_address'], LOGGER_DATA);
$ret[] = new Directory($rr['channel_address'], $auth);
}
}

29
Zotlabs/Update/_1235.php Normal file
View file

@ -0,0 +1,29 @@
<?php
namespace Zotlabs\Update;
class _1235 {
function run() {
$r = q("ALTER TABLE item add replyto text NOT NULL DEFAULT ''");
if($r)
return UPDATE_SUCCESS;
return UPDATE_FAILED;
}
function verify() {
$columns = db_columns('item');
if(in_array('replyto',$columns)) {
return true;
}
return false;
}
}

43
Zotlabs/Update/_1236.php Normal file
View file

@ -0,0 +1,43 @@
<?php
namespace Zotlabs\Update;
class _1236 {
function run() {
q("START TRANSACTION");
if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
$r1 = q("ALTER TABLE abook ADD abook_alias text NOT NULL");
$r2 = q("create index \"abook_alias_idx\" on photo (\"abook_alias\")");
$r = ($r1 && $r2);
}
else {
$r = q("ALTER TABLE `abook` ADD `abook_alias` char(191) NOT NULL DEFAULT '' ,
ADD INDEX `abook_alias` (`abook_alias`)");
}
if($r) {
q("COMMIT");
return UPDATE_SUCCESS;
}
q("ROLLBACK");
return UPDATE_FAILED;
}
function verify() {
$columns = db_columns('abook');
if(in_array('abook_alias',$columns)) {
return true;
}
return false;
}
}

View file

@ -163,27 +163,26 @@ class WebServer {
'type' => 'application/jrd+json',
'url' => z_root() . '/.well-known/webfinger?f=&resource=acct%3A' . argv(1) . '%40' . App::get_hostname()
],
[
'rel' => 'zot',
'type' => 'application/x-zot+json',
'url' => z_root() . '/channel/' . argv(1)
],
[
'rel' => 'self',
'type' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
'href' => z_root() . '/channel/' . argv(1)
],
[
'rel' => 'self',
'type' => 'application/activity+json',
'href' => z_root() . '/channel/' . argv(1)
]
];
if(! defined('NOMADIC')) {
App::$channel_links[] =
[
'rel' => 'self',
'type' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
'href' => z_root() . '/channel/' . argv(1)
];
App::$channel_links[] =
[
'rel' => 'self',
'type' => 'application/activity+json',
'href' => z_root() . '/channel/' . argv(1)
];
}
$x = [ 'channel_address' => argv(1), 'channel_links' => App::$channel_links ];
call_hooks('channel_links', $x );
App::$channel_links = $x['channel_links'];

View file

@ -6,9 +6,7 @@ class Clock {
function widget($arr) {
$miltime = 0;
if(isset($arr['military']) && $arr['military'])
$miltime = 1;
$miltime = ((isset($arr['military']) && $arr['military']) ? intval($arr['military']) : false);
$o = <<< EOT
<div class="widget">
@ -29,7 +27,7 @@ function startclock(){
showtime()
}
function showtime(){
function showtime() {
var now = new Date()
var hours = now.getHours()
var minutes = now.getMinutes()

View file

@ -1,24 +1,29 @@
<?php
namespace Zotlabs\Widget;
use App;
class Newmember {
function widget($arr) {
if(! local_channel())
if (! local_channel()) {
return EMPTY_STR;
}
$c = \App::get_channel();
if(! $c)
$c = App::get_channel();
if (! $c) {
return EMPTY_STR;
}
$a = App::get_account();
if (! $a) {
return EMPTY_STR;
}
$a = \App::get_account();
if(! $a)
return EMPTY_STR;
if(! feature_enabled(local_channel(),'start_menu'))
// @fixme
if (! feature_enabled(local_channel(),'start_menu')) {
return EMPTY_STR;
}
$options = [
t('Profile Creation'),
@ -53,14 +58,13 @@ class Newmember {
// hack to put this in the correct spot of the array
if($site_firehose || $net_firehose) {
if ($site_firehose || $net_firehose) {
$options[5]['pubstream'] = t('View public stream');
}
$o = replace_macros(get_markup_template('new_member.tpl'), [
'$title' => t('New Member Links'),
'$options' => $options
]);
return $o;

View file

@ -48,10 +48,10 @@ require_once('include/items.php');
define ( 'STD_VERSION', '19.8.26' );
define ( 'STD_VERSION', '19.9.18' );
define ( 'ZOT_REVISION', '6.0' );
define ( 'DB_UPDATE_VERSION', 1234 );
define ( 'DB_UPDATE_VERSION', 1236 );
define ( 'PLATFORM_NAME', 'zap' );
define ( 'PLATFORM_ARCHITECTURE', 'zap' );
@ -75,7 +75,7 @@ define ( 'DIRECTORY_MODE_PRIMARY', 0x0001); // There can only be *one* prima
define ( 'DIRECTORY_MODE_SECONDARY', 0x0002); // All other mirror directory servers
define ( 'DIRECTORY_MODE_STANDALONE', 0x0100); // A detached (off the grid) hub with itself as directory server.
// We will look for upstream directories whenever me make contact
// We will look for upstream directories whenever we make contact
// with other sites, but if this is a new installation and isn't
// a standalone hub, we need to seed the service with a starting
// point to go out and find the rest of the world.
@ -470,7 +470,7 @@ define ( 'NAMESPACE_YMEDIA', 'http://search.yahoo.com/mrss/' );
define ( 'ACTIVITYSTREAMS_JSONLD_REV', 'https://www.w3.org/ns/activitystreams' );
define ( 'ZOT_APSCHEMA_REV', '/apschema/v1.9' );
define ( 'ZOT_APSCHEMA_REV', '/apschema/v1.10' );
/**
* activity stream defines
*/

View file

@ -1,52 +1,49 @@
<?php
/**
* @file include/account.php
* @brief Somme account related functions.
* @brief Some account related functions.
*/
use Zotlabs\Lib\Crypto;
require_once('include/config.php');
require_once('include/network.php');
require_once('include/plugin.php');
require_once('include/text.php');
require_once('include/language.php');
require_once('include/datetime.php');
require_once('include/channel.php');
function get_account_by_id($account_id) {
$r = q("select * from account where account_id = %d",
intval($account_id)
);
return (($r) ? $r[0] : false);
return (($r) ? array_shift($r) : false);
}
function check_account_email($email) {
$email = punify($email);
$result = array('error' => false, 'message' => '');
$result = [ 'error' => false, 'message' => '' ];
// Caution: empty email isn't counted as an error in this function.
// Check for empty value separately.
if(! strlen($email))
if (! strlen($email)) {
return $result;
}
if(! validate_email($email))
if (! validate_email($email)) {
$result['message'] .= t('Not a valid email address') . EOL;
elseif(! allowed_email($email))
}
elseif (! allowed_email($email)) {
$result['message'] = t('Your email domain is not among those allowed on this site');
}
else {
$r = q("select account_email from account where account_email = '%s' limit 1",
dbesc($email)
);
if($r) {
if ($r) {
$result['message'] .= t('Your email address is already registered at this site.');
}
}
if($result['message'])
if ($result['message']) {
$result['error'] = true;
}
$arr = array('email' => $email, 'result' => $result);
call_hooks('check_account_email', $arr);
@ -55,54 +52,58 @@ function check_account_email($email) {
}
function check_account_password($password) {
$result = array('error' => false, 'message' => '');
$result = [ 'error' => false, 'message' => '' ];
// The only validation we perform by default is pure Javascript to
// check minimum length and that both entered passwords match.
// Use hooked functions to perform complexity requirement checks.
$arr = array('password' => $password, 'result' => $result);
$arr = [ 'password' => $password, 'result' => $result ];
call_hooks('check_account_password', $arr);
return $arr['result'];
}
function check_account_invite($invite_code) {
$result = array('error' => false, 'message' => '');
$result = [ 'error' => false, 'message' => '' ];
$using_invites = get_config('system','invitation_only');
if($using_invites) {
if(! $invite_code) {
if ($using_invites) {
if (! $invite_code) {
$result['message'] .= t('An invitation is required.') . EOL;
}
$r = q("select * from register where hash = '%s' limit 1", dbesc($invite_code));
if(! $r) {
if (! $r) {
$result['message'] .= t('Invitation could not be verified.') . EOL;
}
}
if(strlen($result['message']))
if (strlen($result['message'])) {
$result['error'] = true;
}
$arr = array('invite_code' => $invite_code, 'result' => $result);
$arr = [ 'invite_code' => $invite_code, 'result' => $result ];
call_hooks('check_account_invite', $arr);
return $arr['result'];
}
function check_account_admin($arr) {
if(is_site_admin())
if (is_site_admin()) {
return true;
}
$admin_email = trim(get_config('system','admin_email'));
if(strlen($admin_email) && $admin_email === trim($arr['email']))
if (strlen($admin_email) && $admin_email === trim($arr['email'])) {
return true;
}
return false;
}
function account_total() {
$r = q("select account_id from account where true");
if(is_array($r))
if ($r) {
return count($r);
}
return false;
}
@ -138,7 +139,7 @@ function create_account($arr) {
// Required: { email, password }
$result = array('success' => false, 'email' => '', 'password' => '', 'message' => '');
$result = [ 'success' => false, 'email' => '', 'password' => '', 'message' => '' ];
$invite_code = ((x($arr,'invite_code')) ? notags(trim($arr['invite_code'])) : '');
$email = ((x($arr,'email')) ? notags(punify(trim($arr['email']))) : '');
@ -149,30 +150,25 @@ function create_account($arr) {
$roles = ((x($arr,'account_roles')) ? intval($arr['account_roles']) : 0 );
$expires = ((x($arr,'expires')) ? intval($arr['expires']) : NULL_DATE);
$default_service_class = get_config('system','default_service_class');
$default_service_class = get_config('system','default_service_class', EMPTY_STR);
if($default_service_class === false)
$default_service_class = '';
if((! x($email)) || (! x($password))) {
if (! ($email && $password)) {
$result['message'] = t('Please enter the required information.');
return $result;
}
// prevent form hackery
if($roles & ACCOUNT_ROLE_ADMIN) {
$admin_result = check_account_admin($arr);
if(! $admin_result) {
$roles = 0;
}
if (($roles & ACCOUNT_ROLE_ADMIN) && (! check_account_admin($arr))) {
$roles = $roles - ACCOUNT_ROLE_ADMIN;
}
// allow the admin_email account to be admin, but only if it's the first account.
$c = account_total();
if (($c === 0) && (check_account_admin($arr)))
if (($c === 0) && (check_account_admin($arr))) {
$roles |= ACCOUNT_ROLE_ADMIN;
}
// Ensure that there is a host keypair.
@ -183,21 +179,21 @@ function create_account($arr) {
}
$invite_result = check_account_invite($invite_code);
if($invite_result['error']) {
if ($invite_result['error']) {
$result['message'] = $invite_result['message'];
return $result;
}
$email_result = check_account_email($email);
if($email_result['error']) {
if ($email_result['error']) {
$result['message'] = $email_result['message'];
return $result;
}
$password_result = check_account_password($password);
if($password_result['error']) {
if ($password_result['error']) {
$result['message'] = $password_result['message'];
return $result;
}
@ -219,7 +215,7 @@ function create_account($arr) {
'account_service_class' => $default_service_class
]
);
if(! $r) {
if (! $r) {
logger('create_account: DB INSERT failed.');
$result['message'] = t('Failed to store account information.');
return($result);
@ -229,7 +225,7 @@ function create_account($arr) {
dbesc($email),
dbesc($password_encoded)
);
if($r && count($r)) {
if ($r && count($r)) {
$result['account'] = $r[0];
}
else {
@ -238,12 +234,12 @@ function create_account($arr) {
// Set the parent record to the current record_id if no parent was provided
if(! $parent) {
if (! $parent) {
$r = q("update account set account_parent = %d where account_id = %d",
intval($result['account']['account_id']),
intval($result['account']['account_id'])
);
if(! $r) {
if (! $r) {
logger('create_account: failed to set parent');
}
$result['account']['parent'] = $result['account']['account_id'];
@ -262,19 +258,19 @@ function create_account($arr) {
function verify_email_address($arr) {
if(array_key_exists('resend',$arr)) {
if (array_key_exists('resend',$arr)) {
$email = $arr['email'];
$a = q("select * from account where account_email = '%s' limit 1",
dbesc($arr['email'])
);
if(! ($a && ($a[0]['account_flags'] & ACCOUNT_UNVERIFIED))) {
if (! ($a && ($a[0]['account_flags'] & ACCOUNT_UNVERIFIED))) {
return false;
}
$account = $a[0];
$account = array_shift($a);
$v = q("select * from register where uid = %d and password = 'verify' limit 1",
intval($account['account_id'])
);
if($v) {
if ($v) {
$hash = $v[0]['hash'];
}
else {
@ -317,11 +313,12 @@ function verify_email_address($arr) {
pop_lang();
if($res)
if ($res) {
$delivered ++;
else
}
else {
logger('send_reg_approval_email: failed to account_id: ' . $arr['account']['account_id']);
}
return $res;
}
@ -333,19 +330,21 @@ function send_reg_approval_email($arr) {
$r = q("select * from account where (account_roles & %d) >= 4096",
intval(ACCOUNT_ROLE_ADMIN)
);
if(! ($r && count($r)))
if (! ($r && count($r))) {
return false;
}
$admins = array();
$admins = [];
foreach($r as $rr) {
if(strlen($rr['account_email'])) {
$admins[] = array('email' => $rr['account_email'], 'lang' => $rr['account_lang']);
foreach ($r as $rr) {
if (strlen($rr['account_email'])) {
$admins[] = [ 'email' => $rr['account_email'], 'lang' => $rr['account_lang'] ];
}
}
if(! count($admins))
if (! count($admins)) {
return false;
}
$hash = random_string();
@ -363,20 +362,22 @@ function send_reg_approval_email($arr) {
$delivered = 0;
foreach($admins as $admin) {
if(strlen($admin['lang']))
foreach ($admins as $admin) {
if (strlen($admin['lang'])) {
push_lang($admin['lang']);
else
}
else {
push_lang('en');
}
$email_msg = replace_macros(get_intltext_template('register_verify_eml.tpl'), array(
$email_msg = replace_macros(get_intltext_template('register_verify_eml.tpl'), [
'$sitename' => get_config('system','sitename'),
'$siteurl' => z_root(),
'$email' => $arr['email'],
'$uid' => $arr['account']['account_id'],
'$hash' => $hash,
'$details' => $details
));
]);
$res = z_mail(
[
@ -386,25 +387,27 @@ function send_reg_approval_email($arr) {
]
);
if($res)
if ($res) {
$delivered ++;
else
}
else {
logger('send_reg_approval_email: failed to ' . $admin['email'] . 'account_id: ' . $arr['account']['account_id']);
}
pop_lang();
}
return($delivered ? true : false);
return ($delivered ? true : false);
}
function send_register_success_email($email,$password) {
$email_msg = replace_macros(get_intltext_template('register_open_eml.tpl'), array(
$email_msg = replace_macros(get_intltext_template('register_open_eml.tpl'), [
'$sitename' => get_config('system','sitename'),
'$siteurl' => z_root(),
'$email' => $email,
'$password' => t('your registration password'),
));
]);
$res = z_mail(
[
@ -414,7 +417,7 @@ function send_register_success_email($email,$password) {
]
);
return($res ? true : false);
return ($res ? true : false);
}
/**
@ -431,26 +434,27 @@ function account_allow($hash) {
dbesc($hash)
);
if(! $register)
if (! $register) {
return $ret;
}
$account = q("SELECT * FROM account WHERE account_id = %d LIMIT 1",
intval($register[0]['uid'])
);
if(! $account)
if (! $account)
return $ret;
$r = q("DELETE FROM register WHERE hash = '%s'",
dbesc($register[0]['hash'])
);
$r = q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
$r = q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d) > 0 and account_id = %d",
intval(ACCOUNT_BLOCKED),
intval(ACCOUNT_BLOCKED),
intval($register[0]['uid'])
);
$r = q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
$r = q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d) > 0 and account_id = %d",
intval(ACCOUNT_PENDING),
intval(ACCOUNT_PENDING),
intval($register[0]['uid'])
@ -459,14 +463,14 @@ function account_allow($hash) {
push_lang($register[0]['lang']);
$email_tpl = get_intltext_template("register_open_eml.tpl");
$email_msg = replace_macros($email_tpl, array(
'$sitename' => get_config('system','sitename'),
'$siteurl' => z_root(),
'$username' => $account[0]['account_email'],
'$email' => $account[0]['account_email'],
'$password' => '',
'$uid' => $account[0]['account_id']
));
$email_msg = replace_macros($email_tpl, [
'$sitename' => get_config('system','sitename'),
'$siteurl' => z_root(),
'$username' => $account[0]['account_email'],
'$email' => $account[0]['account_email'],
'$password' => '',
'$uid' => $account[0]['account_id']
]);
$res = z_mail(
[
@ -478,8 +482,9 @@ function account_allow($hash) {
pop_lang();
if(get_config('system','auto_channel_create'))
if (get_config('system','auto_channel_create')) {
auto_channel_create($register[0]['uid']);
}
if ($res) {
info( t('Account approved.') . EOL );
@ -505,15 +510,17 @@ function account_deny($hash) {
dbesc($hash)
);
if(! count($register))
if(! $register) {
return false;
}
$account = q("SELECT account_id, account_email FROM account WHERE account_id = %d LIMIT 1",
intval($register[0]['uid'])
);
if(! $account)
if (! $account) {
return false;
}
$r = q("DELETE FROM account WHERE account_id = %d",
intval($register[0]['uid'])
@ -540,15 +547,17 @@ function account_approve($hash) {
dbesc($hash)
);
if(! $register)
if (! $register) {
return $ret;
}
$account = q("SELECT * FROM account WHERE account_id = %d LIMIT 1",
intval($register[0]['uid'])
);
if(! $account)
if (! $account) {
return $ret;
}
$r = q("DELETE FROM register WHERE hash = '%s' and password = 'verify'",
dbesc($register[0]['hash'])
@ -576,11 +585,13 @@ function account_approve($hash) {
intval($register[0]['uid'])
);
if(! $account)
if (! $account) {
return $ret;
}
if(get_config('system','auto_channel_create'))
if(get_config('system','auto_channel_create')) {
auto_channel_create($register[0]['uid']);
}
else {
$_SESSION['login_return_url'] = 'new_channel';
authenticate_success($account[0],null,true,true,false,true);
@ -612,20 +623,21 @@ function downgrade_accounts() {
db_getfunc('UTC_TIMESTAMP')
);
if(! $r)
if (! $r) {
return;
}
$basic = get_config('system','default_service_class');
foreach($r as $rr) {
if(($basic) && ($rr['account_service_class']) && ($rr['account_service_class'] != $basic)) {
foreach ($r as $rr) {
if (($basic) && ($rr['account_service_class']) && ($rr['account_service_class'] != $basic)) {
$x = q("UPDATE account set account_service_class = '%s', account_expires = '%s'
where account_id = %d",
dbesc($basic),
dbesc(NULL_DATE),
intval($rr['account_id'])
);
$ret = array('account' => $rr);
$ret = [ 'account' => $rr ];
call_hooks('account_downgrade', $ret );
logger('downgrade_accounts: Account id ' . $rr['account_id'] . ' downgraded.');
}
@ -634,7 +646,7 @@ function downgrade_accounts() {
intval(ACCOUNT_EXPIRED),
intval($rr['account_id'])
);
$ret = array('account' => $rr);
$ret = [ 'account' => $rr ];
call_hooks('account_downgrade', $ret);
logger('downgrade_accounts: Account id ' . $rr['account_id'] . ' expired.');
}
@ -669,13 +681,14 @@ function downgrade_accounts() {
function service_class_allows($uid, $property, $usage = false) {
$limit = service_class_fetch($uid, $property);
if($limit === false)
if ($limit === false) {
return true; // No service class set => everything is allowed
}
$limit = engr_units_to_bytes($limit);
if($usage === false) {
if ($usage === false) {
// We use negative values for not allowed properties in a subscriber plan
return ((x($limit)) ? (bool) $limit : true);
return (($limit) ? (bool) $limit : true);
} else {
return (((intval($usage)) < intval($limit)) ? true : false);
}
@ -706,14 +719,15 @@ function account_service_class_allows($aid, $property, $usage = false) {
$limit = account_service_class_fetch($aid, $property);
if($limit === false)
if ($limit === false) {
return true; // No service class is set => everything is allowed
}
$limit = engr_units_to_bytes($limit);
if($usage === false) {
if ($usage === false) {
// We use negative values for not allowed properties in a subscriber plan
return ((x($limit)) ? (bool) $limit : true);
return (($limit) ? (bool) $limit : true);
} else {
return (((intval($usage)) < intval($limit)) ? true : false);
}
@ -739,26 +753,27 @@ function account_service_class_allows($aid, $property, $usage = false) {
function service_class_fetch($uid, $property) {
if($uid == local_channel()) {
if ($uid == local_channel()) {
$service_class = App::$account['account_service_class'];
}
else {
$r = q("select account_service_class as service_class
from channel c, account a
where c.channel_account_id=a.account_id and c.channel_id= %d limit 1",
intval($uid)
$r = q("select account_service_class
from channel c, account a
where c.channel_account_id = a.account_id and c.channel_id = %d limit 1",
intval($uid)
);
if($r !== false and count($r)) {
$service_class = $r[0]['service_class'];
if ($r) {
$service_class = $r[0]['account_service_class'];
}
}
if(! x($service_class))
if (! $service_class) {
return false; // everything is allowed
}
$arr = get_config('service_class', $service_class);
if(! is_array($arr) || (! count($arr)))
if (! is_array($arr) || (! count($arr))) {
return false;
}
return((array_key_exists($property, $arr)) ? $arr[$property] : false);
}

View file

@ -1118,7 +1118,9 @@ function bbcode($Text, $options = []) {
if (strpos($Text,'[/url]') !== false) {
// $Text = preg_replace("/\[url\]([$URLSearchString]*)\[\/url\]/ism", '<span class="bookmark-identifier">#^</span><a class="bookmark" href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
// $Text = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '<span class="bookmark-identifier">#^</span><a class="bookmark" href="$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text);
$Text = preg_replace("/\[url\]([$URLSearchString]*)\[\/url\]/ism", '<a href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
$Text = preg_replace("/\@(\!?)\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '@$1<span class="h-card"><a class="u-url mention" href="$2" ' . $target . ' rel="nofollow noopener" >$3</a></span>', $Text);
$Text = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '<a href="$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text);
}
@ -1126,6 +1128,7 @@ function bbcode($Text, $options = []) {
// $Text = preg_replace("/\#\^\[zrl\]([$URLSearchString]*)\[\/zrl\]/ism", '<span class="bookmark-identifier">#^</span><a class="zrl bookmark" href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
// $Text = preg_replace("/\#\^\[zrl\=([$URLSearchString]*)\](.*?)\[\/zrl\]/ism", '<span class="bookmark-identifier">#^</span><a class="zrl bookmark" href="$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text);
$Text = preg_replace("/\[zrl\]([$URLSearchString]*)\[\/zrl\]/ism", '<a class="zrl" href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
$Text = preg_replace("/\@(\!?)\[zrl\=([$URLSearchString]*)\](.*?)\[\/zrl\]/ism", '@$1<span class="h-card"><a class="zrl u-url mention" href="$2" ' . $target . ' rel="nofollow noopener" >$3</a></span>', $Text);
$Text = preg_replace("/\[zrl\=([$URLSearchString]*)\](.*?)\[\/zrl\]/ism", '<a class="zrl" href="$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text);
}

View file

@ -9,6 +9,7 @@ function abook_store_lowlevel($arr) {
'abook_account' => ((array_key_exists('abook_account',$arr)) ? $arr['abook_account'] : 0),
'abook_channel' => ((array_key_exists('abook_channel',$arr)) ? $arr['abook_channel'] : 0),
'abook_xchan' => ((array_key_exists('abook_xchan',$arr)) ? $arr['abook_xchan'] : ''),
'abook_alias' => ((array_key_exists('abook_alias',$arr)) ? $arr['abook_alias'] : ''),
'abook_my_perms' => ((array_key_exists('abook_my_perms',$arr)) ? $arr['abook_my_perms'] : 0),
'abook_their_perms' => ((array_key_exists('abook_their_perms',$arr)) ? $arr['abook_their_perms'] : 0),
'abook_closeness' => ((array_key_exists('abook_closeness',$arr)) ? $arr['abook_closeness'] : 99),
@ -40,31 +41,37 @@ function abook_store_lowlevel($arr) {
function rconnect_url($channel_id,$xchan) {
if(! $xchan)
return '';
if (! $xchan) {
return EMPTY_STR;
}
$r = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s' limit 1",
intval($channel_id),
dbesc($xchan)
);
if($r)
return '';
// Already connected
if ($r) {
return EMPTY_STR;
}
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
dbesc($xchan)
);
if(($r) && ($r[0]['xchan_follow']))
if (($r) && ($r[0]['xchan_follow'])) {
return $r[0]['xchan_follow'];
}
$r = q("select hubloc_url from hubloc where hubloc_hash = '%s' and hubloc_primary = 1 limit 1",
dbesc($xchan)
);
if($r)
if ($r) {
return $r[0]['hubloc_url'] . '/follow?f=&url=%s';
return '';
}
return EMPTY_STR;
}
@ -97,63 +104,67 @@ function abook_self($channel_id) {
function vcard_from_xchan($xchan, $observer = null, $mode = '') {
if(! $xchan) {
if(App::$poi) {
if (! $xchan) {
if (App::$poi) {
$xchan = App::$poi;
}
elseif(is_array(App::$profile) && App::$profile['channel_hash']) {
elseif (is_array(App::$profile) && App::$profile['channel_hash']) {
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
dbesc(App::$profile['channel_hash'])
);
if($r)
if($r) {
$xchan = $r[0];
}
}
}
if(! $xchan)
if (! $xchan) {
return;
}
$connect = false;
if(local_channel()) {
if (local_channel()) {
$r = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1",
dbesc($xchan['xchan_hash']),
intval(local_channel())
);
if(! $r)
if (! $r) {
$connect = t('Connect');
}
}
// don't provide a connect button for transient or one-way identities
if(in_array($xchan['xchan_network'],['rss','anon','unknown']) || strpos($xchan['xchan_addr'],'guest:') === 0) {
if (in_array($xchan['xchan_network'],['rss','anon','unknown']) || strpos($xchan['xchan_addr'],'guest:') === 0) {
$connect = false;
}
if(array_key_exists('channel_id',$xchan))
if (array_key_exists('channel_id',$xchan)) {
App::$profile_uid = $xchan['channel_id'];
}
$url = (($observer)
? z_root() . '/magic?f=&owa=1&bdest=' . bin2hex($xchan['xchan_url']) . '&addr=' . $xchan['xchan_addr']
: $xchan['xchan_url']
);
return replace_macros(get_markup_template('xchan_vcard.tpl'),array(
return replace_macros(get_markup_template('xchan_vcard.tpl'), [
'$name' => $xchan['xchan_name'],
'$photo' => ((is_array(App::$profile) && array_key_exists('photo',App::$profile)) ? App::$profile['photo'] : $xchan['xchan_photo_l']),
'$follow' => (($xchan['xchan_addr']) ? $xchan['xchan_addr'] : $xchan['xchan_url']),
'$follow' => urlencode(($xchan['xchan_addr']) ? $xchan['xchan_addr'] : $xchan['xchan_url']),
'$link' => zid($xchan['xchan_url']),
'$connect' => $connect,
'$newwin' => (($mode === 'chanview') ? t('New window') : ''),
'$newwin' => (($mode === 'chanview') ? t('New window') : EMPTY_STR),
'$newtit' => t('Open the selected location in a different window or browser tab'),
'$url' => $url,
));
]);
}
function abook_toggle_flag($abook,$flag) {
$field = '';
$field = EMPTY_STR;
switch($flag) {
switch ($flag) {
case ABOOK_FLAG_BLOCKED:
$field = 'abook_blocked';
break;
@ -184,15 +195,15 @@ function abook_toggle_flag($abook,$flag) {
default:
break;
}
if(! $field)
if (! $field) {
return;
}
$r = q("UPDATE abook set $field = (1 - $field) where abook_id = %d and abook_channel = %d",
intval($abook['abook_id']),
intval($abook['abook_channel'])
);
// if unsetting the archive bit, update the timestamps so we'll try to connect for an additional 30 days.
if(($flag === ABOOK_FLAG_ARCHIVED) && (intval($abook['abook_archived']))) {
@ -223,8 +234,9 @@ function abook_toggle_flag($abook,$flag) {
function mark_orphan_hubsxchans() {
$dirmode = intval(get_config('system','directory_mode'));
if($dirmode == DIRECTORY_MODE_NORMAL)
if ($dirmode == DIRECTORY_MODE_NORMAL) {
return;
}
$r = q("update hubloc set hubloc_deleted = 1 where hubloc_deleted = 0
and hubloc_network = 'zot6' and hubloc_connected < %s - interval %s",
@ -233,7 +245,7 @@ function mark_orphan_hubsxchans() {
$r = q("select hubloc_id, hubloc_hash from hubloc where hubloc_deleted = 1 and hubloc_orphancheck = 0");
if($r) {
if ($r) {
foreach($r as $rr) {
// see if any other hublocs are still alive for this channel
@ -241,14 +253,13 @@ function mark_orphan_hubsxchans() {
$x = q("select * from hubloc where hubloc_hash = '%s' and hubloc_deleted = 0",
dbesc($rr['hubloc_hash'])
);
if($x) {
if ($x) {
// yes - if the xchan was marked as an orphan, undo it
$y = q("update xchan set xchan_orphan = 0 where xchan_orphan = 1 and xchan_hash = '%s'",
dbesc($rr['hubloc_hash'])
);
}
else {
@ -277,7 +288,7 @@ function remove_all_xchan_resources($xchan, $channel_id = 0) {
// $channel_id is reserved for future use.
if(intval($channel_id) === 0) {
if (intval($channel_id) === 0) {
if (! $xchan) {
return;
@ -487,9 +498,11 @@ function random_profile() {
$checkrandom = get_config('randprofile','check'); // False by default
$retryrandom = intval(get_config('randprofile','retry'));
if($retryrandom == 0) $retryrandom = 5;
if ($retryrandom == 0) {
$retryrandom = 5;
}
for($i = 0; $i < $retryrandom; $i++) {
for ($i = 0; $i < $retryrandom; $i++) {
$r = q("select xchan_url, xchan_hash from xchan left join hubloc on hubloc_hash = xchan_hash where
xchan_hidden = 0 and xchan_system = 0 and
@ -499,21 +512,24 @@ function random_profile() {
db_quoteinterval('30 day')
);
if(!$r) return ''; // Couldn't get a random channel
if($checkrandom) {
if (!$r) {
return EMPTY_STR; // Couldn't get a random channel
}
if ($checkrandom) {
$x = z_fetch_url($r[0]['xchan_url']);
if($x['success'])
if ($x['success']) {
return $r[0]['xchan_hash'];
else
}
else {
logger('Random channel turned out to be bad.');
}
}
else {
return $r[0]['xchan_hash'];
}
}
return '';
return EMPTY_STR;
}
function update_vcard($arr,$vcard = null) {
@ -535,7 +551,7 @@ function update_vcard($arr,$vcard = null) {
// right is to provide a form to input all the various fields and not
// try to extract it from the FN.
if(! $vcard) {
if (! $vcard) {
$vcard = new \Sabre\VObject\Component\VCard([
'FN' => $fn,
'N' => array_reverse(explode(' ', $fn))

View file

@ -1478,22 +1478,49 @@ function jot_collections($channel,$collections) {
}
function get_item_children($arr, $parent) {
$children = array();
foreach($arr as $item) {
if($item['id'] != $item['parent']) {
if(get_config('system','thread_allow',true)) {
// Fallback to parent_mid if thr_parent is not set
$thr_parent = $item['thr_parent'];
if($thr_parent === '')
$thr_parent = $item['parent_mid'];
if($thr_parent === $parent['mid']) {
$item['children'] = get_item_children($arr, $item);
function get_item_children($arr, $parent) {
$children = [];
if (! $arr) {
return $children;
}
$thread_allow = get_config('system','thread_allow',true);
$thread_max = intval(get_config('system','thread_maxlevel',2));
foreach ($arr as $item) {
if (intval($item['id']) !== intval($item['parent'])) {
if ($thread_allow) {
$thr_parent = $item['thr_parent'];
// Fallback to parent_mid if thr_parent is not set
if ($thr_parent === EMPTY_STR) {
$thr_parent = $item['parent_mid'];
}
if ($thr_parent === $parent['mid']) {
$my_children = get_item_children($arr, $item);
if ($item['item_level'] > $thread_max) {
// Like and Dislike activities are allowed as children of the last supported level.
// After that they are ignored.
// Any other children deeper than $thread_max are flattened.
if(in_array($item['verb'], [ 'Like','Dislike' ])) {
if ($item['item_level'] > ($thread_max + 1)) {
continue;
}
}
$children = (($my_children) ? array_merge($children,$my_children) : $children);
}
else {
$item['children'] = $my_children;
}
$children[] = $item;
}
}
else if($item['parent'] == $parent['id']) {
elseif (intval($item['parent']) === intval($parent['id'])) {
// threads are disabled. Anything that is in this conversation gets added to children.
$children[] = $item;
}
}
@ -1513,100 +1540,61 @@ function sort_item_children($items) {
}
function add_children_to_list($children, &$arr) {
foreach($children as $y) {
foreach ($children as $y) {
$arr[] = $y;
if($y['children'])
if ($y['children']) {
add_children_to_list($y['children'], $arr);
}
}
function flatten_conversation($parent) {
if (!isset($parent['children']) || count($parent['children']) == 0) {
return $parent;
}
for ($i = 0; $i < count($parent['children']); $i++) {
$child = $parent['children'][$i];
if (isset($child['children']) && count($child['children'])) {
// This helps counting only the regular posts
$count_post_closure = function($var) {
return in_array($var['verb'], ['Create','Update'] );
};
$child_post_count = count(array_filter($child['children'], $count_post_closure));
$remaining_post_count = count(array_filter(array_slice($parent['children'], $i), $count_post_closure));
// If there's only one child's children post and this is the last child post
if ($child_post_count == 1 && $remaining_post_count == 1) {
// Searches the post item in the children
$j = 0;
while((! in_array($child['children'][$j]['verb'], ['Create','Update' ])) && $j < count($child['children'])) {
$j ++;
}
$moved_item = $child['children'][$j];
unset($parent['children'][$i]['children'][$j]);
$parent['children'][] = $moved_item;
} else {
$parent['children'][$i] = flatten_conversation($child);
}
}
}
return $parent;
}
function conv_sort($arr, $order) {
if((!(is_array($arr) && count($arr))))
return array();
$parents = [];
$ret = [];
$parents = array();
if (! (is_array($arr) && count($arr))) {
return $ret;
}
foreach($arr as $x) {
if($x['id'] == $x['parent']) {
$parents[] = $x;
foreach ($arr as $x) {
if (intval($x['id']) === intval($x['parent'])) {
$parents[] = $x;
}
}
if(stristr($order,'created'))
if (stristr($order,'created')) {
usort($parents,'sort_thr_created');
elseif(stristr($order,'commented'))
}
elseif (stristr($order,'commented')) {
usort($parents,'sort_thr_commented');
elseif(stristr($order,'updated'))
}
elseif (stristr($order,'updated')) {
usort($parents,'sort_thr_updated');
elseif(stristr($order,'ascending'))
}
elseif (stristr($order,'ascending')) {
usort($parents,'sort_thr_created_rev');
}
if(count($parents))
foreach($parents as $i=>$_x)
if ($parents) {
foreach ($parents as $i => $_x) {
$parents[$i]['children'] = get_item_children($arr, $_x);
}
if(count($parents)) {
foreach($parents as $k => $v) {
if(count($parents[$k]['children'])) {
foreach ($parents as $k => $v) {
if ($parents[$k]['children']) {
$parents[$k]['children'] = sort_item_children($parents[$k]['children']);
}
}
// foreach ($parents as $i => $parent) {
// $parents[$i] = flatten_conversation($parent);
// }
}
$ret = array();
if(count($parents)) {
foreach($parents as $x) {
if ($parents) {
foreach ($parents as $x) {
$ret[] = $x;
if(count($x['children']))
if ($x['children']) {
add_children_to_list($x['children'], $ret);
}
}
}
@ -1713,119 +1701,6 @@ function prepare_page($item) {
}
function network_tabs() {
$no_active='';
$starred_active = '';
$new_active = '';
$all_active = '';
$search_active = '';
$conv_active = '';
$spam_active = '';
$postord_active = '';
if(x($_GET,'new')) {
$new_active = 'active';
}
if(x($_GET,'search')) {
$search_active = 'active';
}
if(x($_GET,'star')) {
$starred_active = 'active';
}
if(x($_GET,'conv')) {
$conv_active = 'active';
}
if(x($_GET,'spam')) {
$spam_active = 'active';
}
if (($new_active == '')
&& ($starred_active == '')
&& ($conv_active == '')
&& ($search_active == '')
&& ($spam_active == '')) {
$no_active = 'active';
}
if ($no_active=='active' && x($_GET,'order')) {
switch($_GET['order']){
case 'post': $postord_active = 'active'; $no_active=''; break;
case 'comment' : $all_active = 'active'; $no_active=''; break;
}
}
if ($no_active=='active') $all_active='active';
$cmd = App::$cmd;
// tabs
$tabs = array();
$tabs[] = array(
'label' => t('Commented Order'),
'url'=>z_root() . '/' . $cmd . '?f=&order=comment' . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : '') . ((x($_GET,'gid')) ? '&gid=' . $_GET['gid'] : ''),
'sel'=>$all_active,
'title'=> t('Sort by Comment Date'),
);
$tabs[] = array(
'label' => t('Posted Order'),
'url'=>z_root() . '/' . $cmd . '?f=&order=post' . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : '') . ((x($_GET,'gid')) ? '&gid=' . $_GET['gid'] : ''),
'sel'=>$postord_active,
'title' => t('Sort by Post Date'),
);
if(feature_enabled(local_channel(),'personal_tab')) {
$tabs[] = array(
'label' => t('Personal'),
'url' => z_root() . '/' . $cmd . '?f=' . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : '') . '&conv=1',
'sel' => $conv_active,
'title' => t('Posts that mention or involve you'),
);
}
if(feature_enabled(local_channel(),'new_tab')) {
$tabs[] = array(
'label' => t('New'),
'url' => z_root() . '/' . $cmd . '?f=' . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : '') . '&new=1' . ((x($_GET,'gid')) ? '&gid=' . $_GET['gid'] : ''),
'sel' => $new_active,
'title' => t('Activity Stream - by date'),
);
}
if(feature_enabled(local_channel(),'star_posts')) {
$tabs[] = array(
'label' => t('Starred'),
'url'=>z_root() . '/' . $cmd . '/?f=' . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : '') . '&star=1',
'sel'=>$starred_active,
'title' => t('Favourite Posts'),
);
}
// Not yet implemented
if(feature_enabled(local_channel(),'spam_filter')) {
$tabs[] = array(
'label' => t('Spam'),
'url'=> z_root() . '/network?f=&spam=1',
'sel'=> $spam_active,
'title' => t('Posts flagged as SPAM'),
);
}
$arr = array('tabs' => $tabs);
call_hooks('network_tabs', $arr);
$tpl = get_markup_template('common_tabs.tpl');
return replace_macros($tpl, array('$tabs' => $arr['tabs']));
}
/**
* @brief
*

View file

@ -1064,7 +1064,8 @@ function event_store_item($arr, $event) {
$x = [
'type' => 'Event',
'id' => z_root() . '/event/' . $r[0]['resource_id'],
'summary' => bbcode($arr['summary']),
'name' => $arr['summary'],
// 'summary' => bbcode($arr['summary']),
// RFC3339 Section 4.3
'startTime' => (($arr['adjust']) ? datetime_convert('UTC','UTC',$arr['dtstart'], ATOM_TIME) : datetime_convert('UTC','UTC',$arr['dtstart'],'Y-m-d\\TH:i:s-00:00')),
'content' => bbcode($arr['description']),
@ -1217,7 +1218,8 @@ function event_store_item($arr, $event) {
$y = [
'type' => 'Event',
'id' => z_root() . '/event/' . $event['event_hash'],
'summary' => bbcode($arr['summary']),
'name' => $arr['summary'],
// 'summary' => bbcode($arr['summary']),
// RFC3339 Section 4.3
'startTime' => (($arr['adjust']) ? datetime_convert('UTC','UTC',$arr['dtstart'], ATOM_TIME) : datetime_convert('UTC','UTC',$arr['dtstart'],'Y-m-d\\TH:i:s-00:00')),
'content' => bbcode($arr['description']),

View file

@ -59,7 +59,7 @@ function get_features($filtered = true, $level = (-1)) {
'start_menu',
t('New Member Links'),
t('Display new member quick links menu'),
(($account['account_created'] > datetime_convert('','','now - 60 days')) ? true : false),
(($account['account_created'] > datetime_convert('','','now - 30 days')) ? true : false),
get_config('feature_lock','start_menu'),
feature_level('start_menu',1),
],

View file

@ -45,8 +45,18 @@ function import_channel($channel, $account_id, $seize, $newname = '') {
dbesc($channel['channel_hash']),
dbesc($channel['channel_address'])
);
if ($r && $r[0]['channel_guid'] == $channel['channel_guid'] && $r[0]['channel_pubkey'] === $channel['channel_pubkey'] && $r[0]['channel_hash'] === $channel['channel_hash'])
if ($r && $r[0]['channel_guid'] == $channel['channel_guid'] && $r[0]['channel_pubkey'] === $channel['channel_pubkey'] && $r[0]['channel_hash'] === $channel['channel_hash']) {
// do not return a dead or deleted or system channel
if ($r[0]['channel_deleted'] > NULL_DATE
|| intval($r[0]['channel_removed'])
|| intval($r[0]['channel_moved'])
|| intval($r[0]['channel_system'])) {
logger('attempt to import to a channel that was removed. ', print_r($channel,true));
notice( t('A channel with these settings was discovered and is not usable as it was removed or reserved for system use. Import failed.') . EOL);
return false;
}
return $r[0];
}
if (($r) || (check_webbie(array($channel['channel_address'])) !== $channel['channel_address'])) {
if ($r[0]['channel_guid'] === $channel['channel_guid'] || $r[0]['channel_hash'] === $channel['channel_hash']) {

View file

@ -1659,6 +1659,7 @@ function item_store($arr, $allow_exec = false, $deliver = true, $linkid = true)
$arr['plink'] = ((x($arr,'plink')) ? notags(trim($arr['plink'])) : '');
$arr['attach'] = ((x($arr,'attach')) ? notags(trim($arr['attach'])) : '');
$arr['app'] = ((x($arr,'app')) ? notags(trim($arr['app'])) : '');
$arr['replyto'] = ((x($arr,'replyto')) ? serialise($arr['replyto']) : '');
$arr['public_policy'] = '';
@ -2139,6 +2140,7 @@ function item_store_update($arr, $allow_exec = false, $deliver = true, $linkid =
$arr['tgt_type'] = ((x($arr,'tgt_type')) ? notags(trim($arr['tgt_type'])) : $orig[0]['tgt_type']);
$arr['target'] = ((x($arr,'target')) ? trim($arr['target']) : $orig[0]['target']);
$arr['plink'] = ((x($arr,'plink')) ? notags(trim($arr['plink'])) : $orig[0]['plink']);
$arr['replyto'] = ((x($arr,'replyto')) ? serialise($arr['replyto']) : $orig[0]['replyto']);
$arr['allow_cid'] = ((array_key_exists('allow_cid',$arr)) ? trim($arr['allow_cid']) : $orig[0]['allow_cid']);
$arr['allow_gid'] = ((array_key_exists('allow_gid',$arr)) ? trim($arr['allow_gid']) : $orig[0]['allow_gid']);
@ -2872,7 +2874,7 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $edit = false)
}
// @todo handle edit and parent correctly
// @fixme nomadic needs changing to whether or not activitypub is in effect
if((! $parent) && (! defined('NOMADIC'))) {
if($edit) {
@ -3846,7 +3848,7 @@ function zot_feed($uid, $observer_hash, $arr) {
$nonsys_uids = q("SELECT channel_id FROM channel WHERE channel_system = 0");
$nonsys_uids_str = ids_to_querystr($nonsys_uids,'channel_id');
$r = q("SELECT parent, postopts FROM item
$r = q("SELECT parent FROM item
WHERE uid IN ( %s )
AND item_private = 0
$item_normal
@ -3855,7 +3857,7 @@ function zot_feed($uid, $observer_hash, $arr) {
);
}
else {
$r = q("SELECT parent, postopts FROM item
$r = q("SELECT parent FROM item
WHERE uid = %d
$item_normal
$sql_extra ORDER BY created ASC $limit",
@ -3869,8 +3871,6 @@ function zot_feed($uid, $observer_hash, $arr) {
foreach($r as $rv) {
if(array_key_exists($rv['parent'],$parents))
continue;
if(strpos($rv['postopts'],'nodeliver') !== false)
continue;
$parents[$rv['parent']] = $rv;
if(count($parents) > 200)
break;

View file

@ -590,51 +590,6 @@ function validate_email($addr) {
return false;
}
/**
* @brief Check $url against our list of allowed sites.
*
* Wildcards allowed. If allowed_sites is unset return true.
*
* @param string $url
* @return boolean Return true if url is allowed, otherwise return false
*/
function allowed_url($url) {
$h = @parse_url($url);
if(! $h) {
return false;
}
$str_allowed = get_config('system', 'allowed_sites');
if(! $str_allowed)
return true;
$found = false;
$host = strtolower($h['host']);
// always allow our own site
if($host == strtolower($_SERVER['SERVER_NAME']))
return true;
$fnmatch = function_exists('fnmatch');
$allowed = explode(',',$str_allowed);
if(count($allowed)) {
foreach($allowed as $a) {
$pat = strtolower(trim($a));
if(($fnmatch && fnmatch($pat,$host)) || ($pat == $host)) {
$found = true;
break;
}
}
}
return $found;
}
/**
* @brief Check if email address is allowed to register here.
*
@ -1719,7 +1674,7 @@ function check_siteallowed($url) {
$retvalue = true;
$arr = array('url' => $url);
$arr = [ 'url' => $url ];
/**
* @hooks check_siteallowed
* Used to over-ride or bypass the site black/white block lists.
@ -1728,24 +1683,27 @@ function check_siteallowed($url) {
*/
call_hooks('check_siteallowed', $arr);
if(array_key_exists('allowed',$arr))
if (array_key_exists('allowed',$arr)) {
return $arr['allowed'];
}
$bl1 = get_config('system','whitelisted_sites');
if(is_array($bl1) && $bl1) {
foreach($bl1 as $bl) {
if($bl === '*')
if (is_array($bl1) && $bl1) {
foreach ($bl1 as $bl) {
if ($bl === '*') {
$retvalue = true;
if($bl && strpos($url,$bl) !== false)
}
if ($bl && strpos($url,$bl) !== false)
return true;
}
}
$bl1 = get_config('system','blacklisted_sites');
if(is_array($bl1) && $bl1) {
foreach($bl1 as $bl) {
if($bl === '*')
if (is_array($bl1) && $bl1) {
foreach ($bl1 as $bl) {
if ($bl === '*') {
$retvalue = false;
if($bl && strpos($url,$bl) !== false) {
}
if ($bl && strpos($url,$bl) !== false) {
return false;
}
}
@ -1811,7 +1769,7 @@ function check_channelallowed($hash) {
$retvalue = true;
$arr = array('hash' => $hash);
$arr = [ 'hash' => $hash ];
/**
* @hooks check_channelallowed
* Used to over-ride or bypass the channel black/white block lists.
@ -1820,24 +1778,28 @@ function check_channelallowed($hash) {
*/
call_hooks('check_channelallowed', $arr);
if(array_key_exists('allowed',$arr))
if (array_key_exists('allowed',$arr)) {
return $arr['allowed'];
}
$bl1 = get_config('system','whitelisted_channels');
if(is_array($bl1) && $bl1) {
foreach($bl1 as $bl) {
if($bl === '*')
if (is_array($bl1) && $bl1) {
foreach ($bl1 as $bl) {
if ($bl === '*') {
$retvalue = true;
if($bl && strpos($hash,$bl) !== false)
}
if ($bl && strpos($hash,$bl) !== false) {
return true;
}
}
}
$bl1 = get_config('system','blacklisted_channels');
if(is_array($bl1) && $bl1) {
foreach($bl1 as $bl) {
if($bl === '*')
if (is_array($bl1) && $bl1) {
foreach ($bl1 as $bl) {
if ($bl === '*') {
$retvalue = false;
if($bl && strpos($hash,$bl) !== false) {
}
if ($bl && strpos($hash,$bl) !== false) {
return false;
}
}

View file

@ -1631,7 +1631,7 @@ function prepare_body(&$item,$attach = false,$opts = false) {
function separate_img_links($s) {
$x = preg_replace('/\<a (.*?)\>\<img(.*?)\>\<\/a\>/ism',
'<img$2><br><a $1>' . t('Link') . '</a>',$s);
'<img$2><br><a $1>' . t('Link') . '</a><br>',$s);
return $x;
}
@ -2127,6 +2127,7 @@ function trim_and_unpunify($s) {
}
/**
* @brief Fetches xchan and hubloc data for an array of items with only an
* author_xchan and owner_xchan.

View file

@ -17,6 +17,7 @@ CREATE TABLE IF NOT EXISTS `abook` (
`abook_account` int(10) unsigned NOT NULL DEFAULT 0 ,
`abook_channel` int(10) unsigned NOT NULL DEFAULT 0 ,
`abook_xchan` char(191) NOT NULL DEFAULT '',
`abook_alias` char(191) NOT NULL DEFAULT '',
`abook_my_perms` int(11) NOT NULL DEFAULT 0 ,
`abook_their_perms` int(11) NOT NULL DEFAULT 0 ,
`abook_closeness` tinyint(3) unsigned NOT NULL DEFAULT 99,
@ -44,6 +45,7 @@ CREATE TABLE IF NOT EXISTS `abook` (
KEY `abook_account` (`abook_account`),
KEY `abook_channel` (`abook_channel`),
KEY `abook_xchan` (`abook_xchan`),
KEY `abook_alias` (`abook_alias`),
KEY `abook_my_perms` (`abook_my_perms`),
KEY `abook_their_perms` (`abook_their_perms`),
KEY `abook_closeness` (`abook_closeness`),
@ -584,6 +586,7 @@ CREATE TABLE IF NOT EXISTS `item` (
`author_xchan` char(191) NOT NULL DEFAULT '',
`source_xchan` char(191) NOT NULL DEFAULT '',
`mimetype` char(191) NOT NULL DEFAULT '',
`replyto` text NOT NULL,
`title` text NOT NULL,
`summary` mediumtext NOT NULL,
`body` mediumtext NOT NULL,

View file

@ -16,6 +16,7 @@ CREATE TABLE "abook" (
"abook_account" bigint NOT NULL,
"abook_channel" bigint NOT NULL,
"abook_xchan" text NOT NULL DEFAULT '',
"abook_alias" text NOT NULL DEFAULT '',
"abook_my_perms" bigint NOT NULL,
"abook_their_perms" bigint NOT NULL,
"abook_closeness" numeric(3) NOT NULL DEFAULT '99',
@ -44,6 +45,7 @@ CREATE TABLE "abook" (
create index "abook_account" on abook ("abook_account");
create index "abook_channel" on abook ("abook_channel");
create index "abook_xchan" on abook ("abook_xchan");
create index "abook_alias" on abook ("abook_alias");
create index "abook_my_perms" on abook ("abook_my_perms");
create index "abook_their_perms" on abook ("abook_their_perms");
create index "abook_closeness" on abook ("abook_closeness");
@ -572,6 +574,7 @@ CREATE TABLE "item" (
"author_xchan" text NOT NULL DEFAULT '',
"source_xchan" text NOT NULL DEFAULT '',
"mimetype" text NOT NULL DEFAULT '',
"replyto" text NOT NULL,
"title" text NOT NULL,
"summary" text NOT NULL,
"body" text NOT NULL,

313
util/zotsh/zotsh-py3.py Executable file
View file

@ -0,0 +1,313 @@
#!/usr/bin/env python3
import sys, os
import configparser
import requests
from requests.auth import HTTPBasicAuth
import easywebdav
import easywebdav.__version__ as easywebdavversion
import base64
__version__= "0.0.2"
SERVER = None
USER = None
PASSWD = None
VERIFY_SSL=True
#####################################################
class CommandNotFound(Exception):
pass
class ZotSH(object):
commands = ['cd','ls','exists','mkdir','mkdirs','rmdir','delete','upload','download',
'host', 'pwd','cat',
'lcd','lpwd', 'lls',
'quit', 'help']
def __init__(self, host, session=None, davclient=None):
self.sessions = {}
self.host = host
self.session = session
self.davclient = davclient
@property
def host(self):
return self._host
@host.setter
def host(self, host):
self._host = host
self._hostname = host.replace("https:","").replace("/","")
@property
def hostname(self):
return self._hostname
@hostname.setter
def hostname(self, hostname):
self._host = "https://%s/" % (hostname)
self._hostname = hostname
@property
def session(self):
return self._session
@session.setter
def session(self, session):
self._session = session
self.davclient = easywebdav.connect( self.hostname, protocol='https', session=session, path="dav", verify_ssl=VERIFY_SSL)
@property
def PS1(self):
if self.davclient is None:
return "[!]> "
return "%s:%s> " % (self.hostname, self.davclient.cwd)
def get_host_session(self, host=None):
#~ if host is None:
#~ host = self.host
#~ if not host.startswith("https"):
#~ host = "https://%s/" % (host)
#~ if host in self.sessions:
#~ session = self.sessions[host]
#~ else:
#~ session = requests.Session()
#~ self.sessions[host] = session
#~ if not host == SERVER
#~ session.params.update({'davguest':1})
#~ return session
if self.session is None:
session = requests.Session()
#session.params.update({'davguest':1})
else:
session = self.session
#session.params.update({'davguest': (not host == SERVER) })
return session
def do(self, command, *args):
if not command in self.commands:
raise CommandNotFound("Unknown command '%s'" % command)
cmd = getattr(self, "cmd_%s"%command, None)
if cmd is None:
cmd = getattr(self.davclient, command)
return cmd(*args)
def cmd_exists(self, *args):
if (len(args)==0):
return
return self.davclient.exists(args[0])
def cmd_mkdir(self, *args):
if (len(args)==0):
return
return self.davclient.mkdir(args[0])
def cmd_mkdirs(self, *args):
if (len(args)==0):
return
return self.davclient.mkdirs(args[0])
def cmd_rmdir(self, *args):
if (len(args)==0):
return
return self.davclient.rmdir(args[0])
def cmd_delete(self, *args):
if (len(args)==0):
return
return self.davclient.delete(args[0])
def cmd_upload(self, *args):
if (len(args)==0):
return
args = list(args)
if (len(args)==1):
args.append(args[0])
return self.davclient.upload(args[0], args[1])
def cmd_download(self, *args):
if (len(args)==0):
return
args = list(args)
if (len(args)==1):
args.append(args[0])
return self.davclient.download(args[0], args[1])
def cmd_host(self, *args):
if (len(args)==0):
return
newhostname = args[0]
newhost = "https://%s/" % newhostname
if newhostname == "~" or newhost == SERVER:
# bach to home server
self.host = SERVER
self.session = self.get_host_session(SERVER)
return
session_remote = self.get_host_session(newhost)
session_home = self.get_host_session(SERVER)
bnewhost = newhost + 'dav'
bnewhost = bnewhost.encode('hex')
r = session_home.get(
SERVER + "magic",
params={'bdest': bnewhost, 'owa': 1},
allow_redirects=True,
verify=VERIFY_SSL )
self.hostname = newhostname
self.session = session_remote
def cmd_pwd(self, *args):
return "%s%s" % ( self.davclient.baseurl, self.davclient.cwd )
def cmd_ls(self, *args):
extra_args = ["-a", "-l", "-d"]
show_hidden = "-a" in args
show_list = "-l" in args
show_only_dir = "-d" in args
args = [ a for a in args if not a in extra_args ]
r = self.davclient.ls(*args)
l = max([ len(str(f.size)) for f in r ] + [7,])
def _fmt(type, size, name):
if show_list:
return "%s %*d %s" % (type, l, f.size , name)
else:
return name
if show_hidden :
print(_fmt('d', 0, "./"))
if self.davclient.cwd!="/":
print(_fmt('d', 0, "../"))
for f in r:
name = f.name.replace("/dav"+self.davclient.cwd,"")
type = "-"
if name.endswith("/"):
type = "d"
if name!="":
if show_hidden or not name.startswith("."):
if not show_only_dir or type=="d":
print(_fmt(type, f.size , name))
def cmd_lpwd(self, *args):
return os.getcwd()
def cmd_lcd(self, *args):
if (len(args)==0):
return
os.chdir(args[0])
def cmd_lls(self, *args):
for f in os.listdir(os.getcwd()):
if os.path.isdir(f):
f=f+"/"
print(f)
def cmd_help(self, *args):
print("ZotSH",__version__)
print()
print("Commands:")
for c in self.commands:
print("\t",c)
print()
print("easywebdav", easywebdavversion.__version__, "(mod)")
print("requests", requests.__version__)
def cmd_cat(self,*args):
if (len(args)==0):
return
rfile = args[0]
resp = self.davclient._send('GET', rfile, (200,))
print(resp.text)
def load_conf():
global SERVER,USER,PASSWD,VERIFY_SSL
homedir = os.getenv("HOME")
if homedir is None:
homedir = os.path.join(os.getenv("HOMEDRIVE"), os.getenv("HOMEPATH"))
optsfile = ".zotshrc"
if not os.path.isfile(optsfile):
optsfile = os.path.join(homedir, ".zotshrc")
if not os.path.isfile(optsfile):
print("Please create a configuration file called '.zotshrc':")
print("[zotsh]")
print("host = https://yourhost.com/")
print("username = your_username")
print("password = your_password")
sys.exit(-1)
config = configparser.ConfigParser()
config.read(optsfile)
SERVER = config.get('zotsh', 'host')
USER = config.get('zotsh', 'username')
PASSWD = config.get('zotsh', 'password')
if config.has_option('zotsh', 'verify_ssl'):
VERIFY_SSL = config.getboolean('zotsh', 'verify_ssl')
def zotsh():
zotsh = ZotSH( SERVER)
session_home = zotsh.get_host_session()
#~ #login on home server
print("loggin in...")
r = session_home.get(
SERVER + "api/account/verify_credentials",
auth=HTTPBasicAuth(USER, PASSWD),
verify=VERIFY_SSL )
print("Hi", r.json()['name'])
zotsh.session = session_home
# command loop
inputs = input(zotsh.PS1)
while (inputs != "quit"):
inputs = inputs.strip()
if len(inputs)>0:
toks = [ x.strip() for x in inputs.split(" ") ]
command = toks[0]
args = toks[1:]
try:
ret = zotsh.do(command, *args)
except easywebdav.client.OperationFailed as e:
print(e)
except CommandNotFound as e:
print(e)
else:
if ret is not None:
print(ret)
inputs = input(zotsh.PS1)
if __name__=="__main__":
load_conf()
zotsh()
sys.exit()

View file

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2
import sys, os
import ConfigParser

View file

@ -1,8 +1,6 @@
/**
* Redbasic
*
* Based on duepuntozero Friendica style
* Originally by Fabio Comuni <fabrix.xm@gmail.com>
*/
@ -31,6 +29,13 @@ html {
text-decoration: none;
}
a.zrl:hover {
font-weight:bold;
}
.threadlevel {
margin-right: 0.1rem;
}
body {
font-size: 0.9rem;

View file

@ -77,6 +77,25 @@
<input type="hidden" name="section" value="{{$section}}">
<div class="panel-group" id="contact-edit-tools" role="tablist" aria-multiselectable="true">
<div class="panel">
<div class="section-subtitle-wrapper" role="tab" id="alias-tool">
<h3>
<a data-toggle="collapse" data-parent="#contact-edit-tools" href="#alias-tool-collapse" aria-expanded="true" aria-controls="alias-tool-collapse">
{{$alias_label}}
</a>
</h3>
</div>
<div id="alias-tool-collapse" class="panel-collapse collapse show" role="tabpanel" aria-labelledby="alias-tool">
<div class="section-content-tools-wrapper">
{{include file="field_input.tpl" field=$alias}}
<div class="settings-submit-wrapper" >
<button type="submit" name="done" value="{{$submit}}" class="btn btn-primary">{{$submit}}</button>
</div>
</div>
</div>
</div>
{{if $notself}}
{{if $is_pending}}

View file

@ -22,7 +22,7 @@
{{/if}}
{{if $item.title && !$item.event}}
<div class="p-2{{if $item.is_new}} bg-primary text-white{{/if}} wall-item-title h3{{if !$item.photo}} rounded-top{{/if}}" id="wall-item-title-{{$item.id}}">
{{if $item.title_tosource}}{{if $item.plink}}<a href="{{$item.plink.href}}" title="{{$item.title}} ({{$item.plink.title}})">{{/if}}{{/if}}{{$item.title}}{{if $item.title_tosource}}{{if $item.plink}}</a>{{/if}}{{/if}}
{{if $item.title_tosource}}{{if $item.plink}}<a href="{{$item.plink.href}}" title="{{$item.title}} ({{$item.plink.title}})" rel="nofollow noopener">{{/if}}{{/if}}{{$item.title}}{{if $item.title_tosource}}{{if $item.plink}}</a>{{/if}}{{/if}}
</div>
{{if ! $item.is_new}}
<hr class="m-0">
@ -104,7 +104,7 @@
<i class="fa fa-thumbs-o-down{{if $item.my_responses.dislike}} ivoted{{/if}}" ></i>
</button>
{{/if}}
{{if $item.comment && $item.thread_level > 1 && $item.thread_level < 3}}
{{if $item.comment && $item.thread_level > 1 && $item.thread_level < $item.thread_max }}
<button type="button" title="{{$item.comment_lbl}}" class="btn btn-outline-secondary btn-sm" onclick="openClose('wall-item-comment-wrapper-{{$item.id}}'); $('#comment-edit-text-{{$item.id}}').click(); return false;">
<i class="fa fa-comment-o"></i>
</button>

View file

@ -20,7 +20,7 @@
{{/if}}
{{if $item.title && !$item.event}}
<div class="p-2{{if $item.is_new}} bg-primary text-white{{/if}} wall-item-title h3{{if !$item.photo}} rounded-top{{/if}}" id="wall-item-title-{{$item.id}}">
{{if $item.title_tosource}}{{if $item.plink}}<a href="{{$item.plink.href}}" title="{{$item.title}} ({{$item.plink.title}})">{{/if}}{{/if}}{{$item.title}}{{if $item.title_tosource}}{{if $item.plink}}</a>{{/if}}{{/if}}
{{if $item.title_tosource}}{{if $item.plink}}<a href="{{$item.plink.href}}" title="{{$item.title}} ({{$item.plink.title}})" rel="nofollow noopener">{{/if}}{{/if}}{{$item.title}}{{if $item.title_tosource}}{{if $item.plink}}</a>{{/if}}{{/if}}
</div>
{{if ! $item.is_new}}
<hr class="m-0">

View file

@ -1,7 +1,7 @@
<div id="vcard" class="vcard h-card">
<div id="profile-photo-wrapper"><a href="{{$link}}"><img class="vcard-photo photo u-photo" src="{{$photo}}" alt="{{$name}}" /></a></div>
{{if $connect}}
<div class="connect-btn-wrapper"><a href="follow?f=&url={{$follow}}" class="btn btn-block btn-success btn-sm"><i class="fa fa-plus"></i> {{$connect}}</a></div>
<div class="connect-btn-wrapper"><a href="follow?f=&url={{$follow}}" rel="nofollow noopener" class="btn btn-block btn-success btn-sm"><i class="fa fa-plus"></i> {{$connect}}</a></div>
{{/if}}
<div class="fn p-name">{{$name}}</div>
</div>