2018-06-05 01:40:11 +00:00
< ? php
namespace Zotlabs\Lib ;
2018-08-28 01:58:47 +00:00
use App ;
2018-06-05 01:40:11 +00:00
use Zotlabs\Lib\Libzot ;
2018-07-03 05:43:41 +00:00
use Zotlabs\Lib\Queue ;
2019-10-13 22:49:50 +00:00
use Zotlabs\Lib\Connect ;
2019-10-21 01:14:52 +00:00
use Zotlabs\Lib\DReport ;
2020-06-15 07:29:56 +00:00
use Zotlabs\Daemon\Run ;
2018-06-05 01:40:11 +00:00
class Libsync {
/**
* @ brief Builds and sends a sync packet .
*
* Send a zot packet to all hubs where this channel is duplicated , refreshing
* such things as personal settings , channel permissions , address book updates , etc .
*
2019-10-21 01:14:52 +00:00
* By default , sync the channel and any pconfig changes which were made in the current process
* AccessLists ( aka privacy groups ) will also be included if $groups_changed is true .
* To include other data sources , provide them as $packet .
*
2018-06-05 01:40:11 +00:00
* @ param int $uid ( optional ) default 0
* @ param array $packet ( optional ) default null
* @ param boolean $groups_changed ( optional ) default false
*/
2018-07-05 01:18:35 +00:00
2018-06-05 01:40:11 +00:00
static function build_sync_packet ( $uid = 0 , $packet = null , $groups_changed = false ) {
2019-10-21 01:14:52 +00:00
//logger('build_sync_packet');
2018-06-05 01:40:11 +00:00
$keychange = (( $packet && array_key_exists ( 'keychange' , $packet )) ? true : false );
2019-10-21 01:14:52 +00:00
if ( $keychange ) {
2018-06-05 01:40:11 +00:00
logger ( 'keychange sync' );
}
2019-10-21 01:14:52 +00:00
if ( ! $uid ) {
2018-06-05 01:40:11 +00:00
$uid = local_channel ();
2019-10-21 01:14:52 +00:00
}
if ( ! $uid ) {
2018-06-05 01:40:11 +00:00
return ;
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
2018-08-28 02:13:55 +00:00
$channel = channelx_by_n ( $uid );
2019-10-21 01:14:52 +00:00
if ( ! $channel ) {
2018-06-05 01:40:11 +00:00
return ;
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
// don't provide these in the export
unset ( $channel [ 'channel_active' ]);
unset ( $channel [ 'channel_password' ]);
unset ( $channel [ 'channel_salt' ]);
2019-10-21 01:14:52 +00:00
$h = q ( " select hubloc.*, site.site_crypto from hubloc left join site on site_url = hubloc_url
where hubloc_hash = '%s' and hubloc_network = 'zot6' and hubloc_deleted = 0 " ,
2018-06-05 01:40:11 +00:00
dbesc (( $keychange ) ? $packet [ 'keychange' ][ 'old_hash' ] : $channel [ 'channel_hash' ])
);
2019-10-21 01:14:52 +00:00
if ( ! $h ) {
2018-06-05 01:40:11 +00:00
return ;
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
2019-10-21 01:14:52 +00:00
$synchubs = [];
2018-06-05 01:40:11 +00:00
2019-10-21 01:14:52 +00:00
foreach ( $h as $x ) {
if ( $x [ 'hubloc_host' ] == App :: get_hostname ()) {
2018-06-05 01:40:11 +00:00
continue ;
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
$y = q ( " select site_dead from site where site_url = '%s' limit 1 " ,
dbesc ( $x [ 'hubloc_url' ])
);
2019-10-21 01:14:52 +00:00
if (( ! $y ) || ( $y [ 0 ][ 'site_dead' ] == 0 )) {
2018-06-05 01:40:11 +00:00
$synchubs [] = $x ;
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
}
2019-10-21 01:14:52 +00:00
if ( ! $synchubs ) {
2018-06-05 01:40:11 +00:00
return ;
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
2018-07-05 01:18:35 +00:00
$env_recips = [ $channel [ 'channel_hash' ] ];
2018-06-05 01:40:11 +00:00
2019-10-21 01:14:52 +00:00
if ( $packet ) {
2018-06-05 01:40:11 +00:00
logger ( 'packet: ' . print_r ( $packet , true ), LOGGER_DATA , LOG_DEBUG );
2019-10-21 01:14:52 +00:00
}
$info = (( $packet ) ? $packet : [] );
2018-07-30 06:12:05 +00:00
$info [ 'type' ] = 'sync' ;
2018-06-05 01:40:11 +00:00
$info [ 'encoding' ] = 'red' ; // note: not zot, this packet is very platform specific
$info [ 'relocate' ] = [ 'channel_address' => $channel [ 'channel_address' ], 'url' => z_root () ];
2019-10-21 01:14:52 +00:00
if ( array_key_exists ( $uid , App :: $config ) && array_key_exists ( 'transient' , App :: $config [ $uid ])) {
2018-08-28 01:58:47 +00:00
$settings = App :: $config [ $uid ][ 'transient' ];
2019-10-21 01:14:52 +00:00
if ( $settings ) {
2018-06-05 01:40:11 +00:00
$info [ 'config' ] = $settings ;
}
}
2019-10-21 01:14:52 +00:00
if ( $channel ) {
$info [ 'channel' ] = [];
foreach ( $channel as $k => $v ) {
2018-06-05 01:40:11 +00:00
// filter out any joined tables like xchan
2019-10-21 01:14:52 +00:00
if ( strpos ( $k , 'channel_' ) !== 0 ) {
2018-06-05 01:40:11 +00:00
continue ;
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
// don't pass these elements, they should not be synchronised
2019-10-21 01:14:52 +00:00
$disallowed = [ 'channel_id' , 'channel_account_id' , 'channel_primary' , 'channel_address' ,
'channel_deleted' , 'channel_removed' , 'channel_system' ];
2018-06-05 01:40:11 +00:00
2019-10-21 01:14:52 +00:00
if ( ! $keychange ) {
2018-06-05 01:40:11 +00:00
$disallowed [] = 'channel_prvkey' ;
}
2019-10-21 01:14:52 +00:00
if ( in_array ( $k , $disallowed )) {
2018-06-05 01:40:11 +00:00
continue ;
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
$info [ 'channel' ][ $k ] = $v ;
}
}
2019-10-21 01:14:52 +00:00
if ( $groups_changed ) {
2020-08-01 20:48:57 +00:00
$r = q ( " select hash as collection, visible, deleted, rule, gname as name from pgrp where uid = %d " ,
2018-06-05 01:40:11 +00:00
intval ( $uid )
);
2019-10-21 01:14:52 +00:00
if ( $r ) {
2018-06-05 01:40:11 +00:00
$info [ 'collections' ] = $r ;
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
2019-10-21 01:14:52 +00:00
$r = q ( " select pgrp.hash as collection, pgrp_member.xchan as member from pgrp left join pgrp_member on pgrp.id = pgrp_member.gid
2020-08-01 20:48:57 +00:00
where pgrp_member . uid = % d " ,
2018-06-05 01:40:11 +00:00
intval ( $uid )
);
2019-10-21 01:14:52 +00:00
if ( $r ) {
2018-06-05 01:40:11 +00:00
$info [ 'collection_members' ] = $r ;
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
}
2019-10-21 01:14:52 +00:00
$interval = get_config ( 'system' , 'delivery_interval' , 2 );
2018-06-05 01:40:11 +00:00
logger ( 'Packet: ' . print_r ( $info , true ), LOGGER_DATA , LOG_DEBUG );
$total = count ( $synchubs );
2019-10-21 01:14:52 +00:00
foreach ( $synchubs as $hub ) {
2018-06-05 01:40:11 +00:00
$hash = random_string ();
2018-07-30 06:12:05 +00:00
$n = Libzot :: build_packet ( $channel , 'sync' , $env_recips , json_encode ( $info ), 'red' , $hub [ 'hubloc_sitekey' ], $hub [ 'site_crypto' ]);
2019-10-21 01:14:52 +00:00
Queue :: insert ([
2018-06-05 01:40:11 +00:00
'hash' => $hash ,
'account_id' => $channel [ 'channel_account_id' ],
'channel_id' => $channel [ 'channel_id' ],
'posturl' => $hub [ 'hubloc_callback' ],
'notify' => $n ,
2018-07-05 01:18:35 +00:00
'msg' => EMPTY_STR
2019-10-21 01:14:52 +00:00
]);
2018-06-05 01:40:11 +00:00
$x = q ( " select count(outq_hash) as total from outq where outq_delivered = 0 " );
2019-10-21 01:14:52 +00:00
if ( intval ( $x [ 0 ][ 'total' ]) > intval ( get_config ( 'system' , 'force_queue_threshold' , 3000 ))) {
2018-06-05 01:40:11 +00:00
logger ( 'immediate delivery deferred.' , LOGGER_DEBUG , LOG_INFO );
2018-07-03 05:43:41 +00:00
Queue :: update ( $hash );
2018-06-05 01:40:11 +00:00
continue ;
}
2020-06-15 07:29:56 +00:00
Run :: Summon ([ 'Deliver' , $hash ]);
2018-06-05 01:40:11 +00:00
$total = $total - 1 ;
2019-10-21 01:14:52 +00:00
if ( $interval && $total ) {
2018-06-05 01:40:11 +00:00
@ time_sleep_until ( microtime ( true ) + ( float ) $interval );
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
}
}
2018-08-28 01:58:47 +00:00
static function build_link_packet ( $uid = 0 , $packet = null ) {
2019-10-21 01:14:52 +00:00
// logger('build_link_packet');
2018-08-28 01:58:47 +00:00
2019-10-21 01:14:52 +00:00
if ( ! $uid ) {
2018-08-28 01:58:47 +00:00
$uid = local_channel ();
2019-10-21 01:14:52 +00:00
}
if ( ! $uid ) {
2018-08-28 01:58:47 +00:00
return ;
2019-10-21 01:14:52 +00:00
}
2018-08-28 01:58:47 +00:00
2018-08-28 02:12:00 +00:00
$channel = channelx_by_n ( $uid );
2019-10-21 01:14:52 +00:00
if ( ! $channel ) {
2018-08-28 01:58:47 +00:00
return ;
2019-10-21 01:14:52 +00:00
}
2018-08-28 01:58:47 +00:00
$l = q ( " select link from linkid where ident = '%s' and sigtype = 2 " ,
dbesc ( $channel [ 'channel_hash' ])
);
2019-10-21 01:14:52 +00:00
if ( ! $l ) {
2018-08-28 01:58:47 +00:00
return ;
2019-10-21 01:14:52 +00:00
}
2018-08-28 01:58:47 +00:00
$hashes = ids_to_querystr ( $l , 'link' , true );
2018-09-24 00:03:10 +00:00
$h = q ( " select hubloc.*, site.site_crypto from hubloc left join site on site_url = hubloc_url where hubloc_hash in ( " . protect_sprintf ( $hashes ) . " ) and hubloc_network = 'zot6' and hubloc_deleted = 0 " );
2018-08-28 01:58:47 +00:00
2019-10-21 01:14:52 +00:00
if ( ! $h ) {
2018-08-28 01:58:47 +00:00
return ;
2019-10-21 01:14:52 +00:00
}
2018-08-28 01:58:47 +00:00
2019-10-21 01:14:52 +00:00
$interval = get_config ( 'system' , 'delivery_interval' , 2 );
2018-08-28 01:58:47 +00:00
2019-10-21 01:14:52 +00:00
foreach ( $h as $x ) {
if ( $x [ 'hubloc_host' ] == App :: get_hostname ()) {
2018-08-28 01:58:47 +00:00
continue ;
}
$y = q ( " select site_dead from site where site_url = '%s' limit 1 " ,
dbesc ( $x [ 'hubloc_url' ])
);
2019-10-21 01:14:52 +00:00
if (( $y ) && ( intval ( $y [ 0 ][ 'site_dead' ]) == 1 )) {
2018-08-28 01:58:47 +00:00
$continue ;
2019-10-21 01:14:52 +00:00
}
2018-08-28 01:58:47 +00:00
$env_recips = [ $x [ 'hubloc_hash' ] ];
2019-10-21 01:14:52 +00:00
if ( $packet ) {
2018-08-28 01:58:47 +00:00
logger ( 'packet: ' . print_r ( $packet , true ), LOGGER_DATA , LOG_DEBUG );
2019-10-21 01:14:52 +00:00
}
2018-08-28 01:58:47 +00:00
$info = (( $packet ) ? $packet : []);
$info [ 'type' ] = 'sync' ;
$info [ 'encoding' ] = 'red' ; // note: not zot, this packet is very platform specific
logger ( 'Packet: ' . print_r ( $info , true ), LOGGER_DATA , LOG_DEBUG );
$hash = random_string ();
$n = Libzot :: build_packet ( $channel , 'sync' , $env_recips , json_encode ( $info ), 'red' , $x [ 'hubloc_sitekey' ], $x [ 'site_crypto' ]);
Queue :: insert ([
'hash' => $hash ,
'account_id' => $channel [ 'channel_account_id' ],
'channel_id' => $channel [ 'channel_id' ],
'posturl' => $x [ 'hubloc_callback' ],
'notify' => $n ,
'msg' => EMPTY_STR
]);
$y = q ( " select count(outq_hash) as total from outq where outq_delivered = 0 " );
2019-10-21 01:14:52 +00:00
if ( intval ( $y [ 0 ][ 'total' ]) > intval ( get_config ( 'system' , 'force_queue_threshold' , 3000 ))) {
2018-08-28 01:58:47 +00:00
logger ( 'immediate delivery deferred.' , LOGGER_DEBUG , LOG_INFO );
Queue :: update ( $hash );
continue ;
}
2020-06-15 07:29:56 +00:00
Run :: Summon ([ 'Deliver' , $hash ]);
2018-08-28 01:58:47 +00:00
2019-10-21 01:14:52 +00:00
if ( $interval && count ( $h ) > 1 ) {
2018-08-28 01:58:47 +00:00
@ time_sleep_until ( microtime ( true ) + ( float ) $interval );
2019-10-21 01:14:52 +00:00
}
2018-08-28 01:58:47 +00:00
}
}
2018-06-05 01:40:11 +00:00
/**
* @ brief
*
* @ param array $sender
* @ param array $arr
* @ param array $deliveries
* @ return array
*/
static function process_channel_sync_delivery ( $sender , $arr , $deliveries ) {
require_once ( 'include/import.php' );
$result = [];
$keychange = (( array_key_exists ( 'keychange' , $arr )) ? true : false );
foreach ( $deliveries as $d ) {
2018-08-28 01:58:47 +00:00
$linked_channel = false ;
2018-06-05 01:40:11 +00:00
$r = q ( " select * from channel where channel_hash = '%s' limit 1 " ,
2018-07-30 05:13:43 +00:00
dbesc ( $sender )
2018-06-05 01:40:11 +00:00
);
2019-10-21 01:14:52 +00:00
$DR = new DReport ( z_root (), $sender , $d , 'sync' );
2018-07-30 05:13:43 +00:00
2019-10-21 01:14:52 +00:00
if ( ! $r ) {
2018-08-28 01:58:47 +00:00
$l = q ( " select ident from linkid where link = '%s' and sigtype = 2 limit 1 " ,
dbesc ( $sender )
);
2019-10-21 01:14:52 +00:00
if ( $l ) {
2018-08-28 01:58:47 +00:00
$linked_channel = true ;
$r = q ( " select * from channel where channel_hash = '%s' limit 1 " ,
dbesc ( $l [ 0 ][ 'ident' ])
);
}
}
2018-06-05 01:40:11 +00:00
if ( ! $r ) {
2018-07-30 05:13:43 +00:00
$DR -> update ( 'recipient not found' );
$result [] = $DR -> get ();
2018-06-05 01:40:11 +00:00
continue ;
}
$channel = $r [ 0 ];
2018-07-30 06:49:37 +00:00
$DR -> set_name ( $channel [ 'channel_name' ] . ' <' . channel_reddress ( $channel ) . '>' );
2018-06-05 01:40:11 +00:00
$max_friends = service_class_fetch ( $channel [ 'channel_id' ], 'total_channels' );
$max_feeds = account_service_class_fetch ( $channel [ 'channel_account_id' ], 'total_feeds' );
2019-10-21 01:14:52 +00:00
if ( $channel [ 'channel_hash' ] != $sender && ( ! $linked_channel )) {
2018-07-30 05:13:43 +00:00
logger ( 'Possible forgery. Sender ' . $sender . ' is not ' . $channel [ 'channel_hash' ]);
$DR -> update ( 'channel mismatch' );
$result [] = $DR -> get ();
2018-06-05 01:40:11 +00:00
continue ;
}
2019-10-21 01:14:52 +00:00
if ( $keychange ) {
2018-07-05 01:18:35 +00:00
self :: keychange ( $channel , $arr );
2018-06-05 01:40:11 +00:00
continue ;
}
// if the clone is active, so are we
2019-10-21 01:14:52 +00:00
if ( substr ( $channel [ 'channel_active' ], 0 , 10 ) !== substr ( datetime_convert (), 0 , 10 )) {
2018-06-05 01:40:11 +00:00
q ( " UPDATE channel set channel_active = '%s' where channel_id = %d " ,
dbesc ( datetime_convert ()),
intval ( $channel [ 'channel_id' ])
);
}
2019-10-21 01:14:52 +00:00
if ( array_key_exists ( 'config' , $arr ) && is_array ( $arr [ 'config' ]) && count ( $arr [ 'config' ])) {
foreach ( $arr [ 'config' ] as $cat => $k ) {
foreach ( $arr [ 'config' ][ $cat ] as $k => $v ) {
2018-06-05 01:40:11 +00:00
set_pconfig ( $channel [ 'channel_id' ], $cat , $k , $v );
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
}
}
2019-04-30 02:29:11 +00:00
2019-10-21 01:14:52 +00:00
if ( array_key_exists ( 'xign' , $arr ) && $arr [ 'xign' ]) {
2019-04-30 02:29:11 +00:00
sync_xign ( $channel , $arr [ 'xign' ]);
2019-10-21 01:14:52 +00:00
}
2019-04-30 02:29:11 +00:00
2020-03-19 23:56:48 +00:00
if ( array_key_exists ( 'block' , $arr ) && $arr [ 'block' ]) {
sync_block ( $channel , $arr [ 'block' ]);
}
2019-10-21 01:14:52 +00:00
if ( array_key_exists ( 'obj' , $arr ) && $arr [ 'obj' ]) {
2018-06-05 01:40:11 +00:00
sync_objs ( $channel , $arr [ 'obj' ]);
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
2019-10-21 01:14:52 +00:00
if ( array_key_exists ( 'likes' , $arr ) && $arr [ 'likes' ]) {
2018-06-05 01:40:11 +00:00
import_likes ( $channel , $arr [ 'likes' ]);
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
2019-10-21 01:14:52 +00:00
if ( array_key_exists ( 'app' , $arr ) && $arr [ 'app' ]) {
2018-06-05 01:40:11 +00:00
sync_apps ( $channel , $arr [ 'app' ]);
2019-10-21 01:14:52 +00:00
}
if ( array_key_exists ( 'sysapp' , $arr ) && $arr [ 'sysapp' ]) {
sync_sysapps ( $channel , $arr [ 'sysapp' ]);
}
if ( array_key_exists ( 'chatroom' , $arr ) && $arr [ 'chatroom' ]) {
2018-06-05 01:40:11 +00:00
sync_chatrooms ( $channel , $arr [ 'chatroom' ]);
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
2019-10-21 01:14:52 +00:00
if ( array_key_exists ( 'conv' , $arr ) && $arr [ 'conv' ]) {
2018-06-05 01:40:11 +00:00
import_conv ( $channel , $arr [ 'conv' ]);
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
2019-10-21 01:14:52 +00:00
if ( array_key_exists ( 'mail' , $arr ) && $arr [ 'mail' ]) {
2018-06-05 01:40:11 +00:00
sync_mail ( $channel , $arr [ 'mail' ]);
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
2019-10-21 01:14:52 +00:00
if ( array_key_exists ( 'event' , $arr ) && $arr [ 'event' ]) {
2018-06-05 01:40:11 +00:00
sync_events ( $channel , $arr [ 'event' ]);
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
2019-10-21 01:14:52 +00:00
if ( array_key_exists ( 'event_item' , $arr ) && $arr [ 'event_item' ]) {
2018-06-05 01:40:11 +00:00
sync_items ( $channel , $arr [ 'event_item' ],(( array_key_exists ( 'relocate' , $arr )) ? $arr [ 'relocate' ] : null ));
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
2019-10-21 01:14:52 +00:00
if ( array_key_exists ( 'item' , $arr ) && $arr [ 'item' ]) {
2018-06-05 01:40:11 +00:00
sync_items ( $channel , $arr [ 'item' ],(( array_key_exists ( 'relocate' , $arr )) ? $arr [ 'relocate' ] : null ));
2019-10-21 01:14:52 +00:00
}
if ( array_key_exists ( 'menu' , $arr ) && $arr [ 'menu' ]) {
2018-06-05 01:40:11 +00:00
sync_menus ( $channel , $arr [ 'menu' ]);
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
2019-10-21 01:14:52 +00:00
if ( array_key_exists ( 'file' , $arr ) && $arr [ 'file' ]) {
2018-06-05 01:40:11 +00:00
sync_files ( $channel , $arr [ 'file' ]);
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
2019-10-21 01:14:52 +00:00
if ( array_key_exists ( 'wiki' , $arr ) && $arr [ 'wiki' ]) {
2018-06-05 01:40:11 +00:00
sync_items ( $channel , $arr [ 'wiki' ],(( array_key_exists ( 'relocate' , $arr )) ? $arr [ 'relocate' ] : null ));
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
if ( array_key_exists ( 'channel' , $arr ) && is_array ( $arr [ 'channel' ]) && count ( $arr [ 'channel' ])) {
$remote_channel = $arr [ 'channel' ];
$remote_channel [ 'channel_id' ] = $channel [ 'channel_id' ];
2019-10-21 01:14:52 +00:00
if ( array_key_exists ( 'channel_pageflags' , $arr [ 'channel' ]) && intval ( $arr [ 'channel' ][ 'channel_pageflags' ])) {
2018-06-05 01:40:11 +00:00
2018-07-05 03:09:55 +00:00
// Several pageflags are site-specific and cannot be sync'd.
// Only allow those bits which are shareable from the remote and then
// logically OR with the local flags
$arr [ 'channel' ][ 'channel_pageflags' ] = $arr [ 'channel' ][ 'channel_pageflags' ] & ( PAGE_HIDDEN | PAGE_AUTOCONNECT | PAGE_APPLICATION | PAGE_PREMIUM | PAGE_ADULT );
$arr [ 'channel' ][ 'channel_pageflags' ] = $arr [ 'channel' ][ 'channel_pageflags' ] | $channel [ 'channel_pageflags' ];
2018-06-05 01:40:11 +00:00
}
2019-06-14 06:36:16 +00:00
$columns = db_columns ( 'channel' );
2018-06-05 01:40:11 +00:00
$disallowed = [
2018-09-17 03:01:53 +00:00
'channel_id' , 'channel_account_id' , 'channel_primary' , 'channel_prvkey' ,
'channel_address' , 'channel_notifyflags' , 'channel_removed' , 'channel_deleted' ,
'channel_system' , 'channel_r_stream' , 'channel_r_profile' , 'channel_r_abook' ,
'channel_r_storage' , 'channel_r_pages' , 'channel_w_stream' , 'channel_w_wall' ,
'channel_w_comment' , 'channel_w_mail' , 'channel_w_like' , 'channel_w_tagwall' ,
'channel_w_chat' , 'channel_w_storage' , 'channel_w_pages' , 'channel_a_republish' ,
'channel_a_delegate' , 'channel_moved'
2018-06-05 01:40:11 +00:00
];
foreach ( $arr [ 'channel' ] as $k => $v ) {
2019-06-14 06:36:16 +00:00
if ( in_array ( $k , $disallowed )) {
continue ;
}
if ( ! in_array ( $k , $columns )) {
2018-06-05 01:40:11 +00:00
continue ;
}
2019-06-14 06:36:16 +00:00
$r = dbq ( " UPDATE channel set " . dbesc ( $k ) . " = ' " . dbesc ( $v )
. " ' where channel_id = " . intval ( $channel [ 'channel_id' ]) );
2018-06-05 01:40:11 +00:00
}
}
2019-10-21 01:14:52 +00:00
if ( array_key_exists ( 'abook' , $arr ) && is_array ( $arr [ 'abook' ]) && count ( $arr [ 'abook' ])) {
2018-09-12 05:21:31 +00:00
2018-06-05 01:40:11 +00:00
$total_friends = 0 ;
$total_feeds = 0 ;
$r = q ( " select abook_id, abook_feed from abook where abook_channel = %d " ,
intval ( $channel [ 'channel_id' ])
);
2019-10-21 01:14:52 +00:00
if ( $r ) {
2018-06-05 01:40:11 +00:00
// don't count yourself
$total_friends = (( count ( $r ) > 0 ) ? count ( $r ) - 1 : 0 );
2019-10-21 01:14:52 +00:00
foreach ( $r as $rr ) {
if ( intval ( $rr [ 'abook_feed' ])) {
2018-06-05 01:40:11 +00:00
$total_feeds ++ ;
2019-10-21 01:14:52 +00:00
}
}
2018-06-05 01:40:11 +00:00
}
2019-10-21 01:14:52 +00:00
$disallowed = [ 'abook_id' , 'abook_account' , 'abook_channel' , 'abook_rating' , 'abook_rating_text' , 'abook_not_here' ];
2018-06-05 01:40:11 +00:00
2018-09-12 05:21:31 +00:00
$fields = db_columns ( 'abook' );
2018-07-30 06:49:37 +00:00
2019-10-21 01:14:52 +00:00
foreach ( $arr [ 'abook' ] as $abook ) {
2018-06-05 01:40:11 +00:00
$abconfig = null ;
2019-10-21 01:14:52 +00:00
if ( array_key_exists ( 'abconfig' , $abook ) && is_array ( $abook [ 'abconfig' ]) && count ( $abook [ 'abconfig' ])) {
2018-06-05 01:40:11 +00:00
$abconfig = $abook [ 'abconfig' ];
}
2019-10-21 01:14:52 +00:00
$clean = [];
if ( $abook [ 'abook_xchan' ] && $abook [ 'entry_deleted' ]) {
2018-06-05 01:40:11 +00:00
logger ( 'Removing abook entry for ' . $abook [ 'abook_xchan' ]);
$r = q ( " select abook_id, abook_feed from abook where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 limit 1 " ,
dbesc ( $abook [ 'abook_xchan' ]),
intval ( $channel [ 'channel_id' ])
);
2019-10-21 01:14:52 +00:00
if ( $r ) {
2018-06-05 01:40:11 +00:00
contact_remove ( $channel [ 'channel_id' ], $r [ 0 ][ 'abook_id' ]);
2019-10-21 01:14:52 +00:00
if ( $total_friends ) {
2018-06-05 01:40:11 +00:00
$total_friends -- ;
2019-10-21 01:14:52 +00:00
}
if ( intval ( $r [ 0 ][ 'abook_feed' ])) {
2018-06-05 01:40:11 +00:00
$total_feeds -- ;
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
}
continue ;
}
// Perform discovery if the referenced xchan hasn't ever been seen on this hub.
// This relies on the undocumented behaviour that red sites send xchan info with the abook
// and import_author_xchan will look them up on all federated networks
2019-10-21 01:14:52 +00:00
if ( $abook [ 'abook_xchan' ] && $abook [ 'xchan_addr' ]) {
2018-06-05 01:47:36 +00:00
$h = Libzot :: get_hublocs ( $abook [ 'abook_xchan' ]);
2019-10-21 01:14:52 +00:00
if ( ! $h ) {
2018-06-05 01:40:11 +00:00
$xhash = import_author_xchan ( encode_item_xchan ( $abook ));
2019-10-21 01:14:52 +00:00
if ( ! $xhash ) {
2018-06-05 01:40:11 +00:00
logger ( 'Import of ' . $abook [ 'xchan_addr' ] . ' failed.' );
continue ;
}
}
}
2019-10-21 01:14:52 +00:00
foreach ( $abook as $k => $v ) {
if ( in_array ( $k , $disallowed ) || ( strpos ( $k , 'abook' ) !== 0 )) {
2018-07-30 06:49:37 +00:00
continue ;
}
2019-10-21 01:14:52 +00:00
if ( ! in_array ( $k , $fields )) {
2018-06-05 01:40:11 +00:00
continue ;
2018-07-30 06:49:37 +00:00
}
2018-06-05 01:40:11 +00:00
$clean [ $k ] = $v ;
}
2019-10-21 01:14:52 +00:00
if ( ! array_key_exists ( 'abook_xchan' , $clean )) {
2018-06-05 01:40:11 +00:00
continue ;
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
2019-10-13 22:49:50 +00:00
$reconnect = false ;
2019-10-21 01:14:52 +00:00
if ( array_key_exists ( 'abook_instance' , $clean ) && $clean [ 'abook_instance' ] && strpos ( $clean [ 'abook_instance' ], z_root ()) === false ) {
2018-06-05 01:40:11 +00:00
$clean [ 'abook_not_here' ] = 1 ;
2019-10-13 22:49:50 +00:00
if ( ! ( $abook [ 'abook_pending' ] || $abook [ 'abook_blocked' ])) {
$reconnect = true ;
}
2018-06-05 01:40:11 +00:00
}
$r = q ( " select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1 " ,
dbesc ( $clean [ 'abook_xchan' ]),
intval ( $channel [ 'channel_id' ])
);
// make sure we have an abook entry for this xchan on this system
2019-10-21 01:14:52 +00:00
if ( ! $r ) {
if ( $max_friends !== false && $total_friends > $max_friends ) {
2018-06-05 01:40:11 +00:00
logger ( 'total_channels service class limit exceeded' );
continue ;
}
2019-10-21 01:14:52 +00:00
if ( $max_feeds !== false && intval ( $clean [ 'abook_feed' ]) && $total_feeds > $max_feeds ) {
2018-06-05 01:40:11 +00:00
logger ( 'total_feeds service class limit exceeded' );
continue ;
}
abook_store_lowlevel (
[
'abook_xchan' => $clean [ 'abook_xchan' ],
'abook_account' => $channel [ 'channel_account_id' ],
'abook_channel' => $channel [ 'channel_id' ]
]
);
$total_friends ++ ;
2019-10-21 01:14:52 +00:00
if ( intval ( $clean [ 'abook_feed' ])) {
2018-06-05 01:40:11 +00:00
$total_feeds ++ ;
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
}
2019-10-21 01:14:52 +00:00
if ( count ( $clean )) {
foreach ( $clean as $k => $v ) {
if ( $k == 'abook_dob' ) {
2018-06-05 01:40:11 +00:00
$v = dbescdate ( $v );
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
$r = dbq ( " UPDATE abook set " . dbesc ( $k ) . " = ' " . dbesc ( $v )
. " ' where abook_xchan = ' " . dbesc ( $clean [ 'abook_xchan' ]) . " ' and abook_channel = " . intval ( $channel [ 'channel_id' ]));
2018-09-12 05:21:31 +00:00
2018-06-05 01:40:11 +00:00
}
}
// This will set abconfig vars if the sender is using old-style fixed permissions
// using the raw abook record as passed to us. New-style permissions will fall through
// and be set using abconfig
2018-07-30 05:13:43 +00:00
// translate_abook_perms_inbound($channel,$abook);
2018-06-05 01:40:11 +00:00
2019-10-21 01:14:52 +00:00
if ( $abconfig ) {
2018-06-05 01:40:11 +00:00
/// @fixme does not handle sync of del_abconfig
2019-10-21 01:14:52 +00:00
foreach ( $abconfig as $abc ) {
2018-06-05 01:40:11 +00:00
set_abconfig ( $channel [ 'channel_id' ], $abc [ 'xchan' ], $abc [ 'cat' ], $abc [ 'k' ], $abc [ 'v' ]);
}
}
2019-10-13 22:49:50 +00:00
if ( $reconnect ) {
Connect :: connect ( $channel , $abook [ 'abook_xchan' ]);
}
2018-06-05 01:40:11 +00:00
}
}
// sync collections (privacy groups) oh joy...
2019-10-21 01:14:52 +00:00
if ( array_key_exists ( 'collections' , $arr ) && is_array ( $arr [ 'collections' ]) && count ( $arr [ 'collections' ])) {
2020-08-01 20:48:57 +00:00
$x = q ( " select * from pgrp where uid = %d " ,
2018-06-05 01:40:11 +00:00
intval ( $channel [ 'channel_id' ])
);
2019-10-21 01:14:52 +00:00
foreach ( $arr [ 'collections' ] as $cl ) {
2018-06-05 01:40:11 +00:00
$found = false ;
2019-10-21 01:14:52 +00:00
if ( $x ) {
foreach ( $x as $y ) {
if ( $cl [ 'collection' ] == $y [ 'hash' ]) {
2018-06-05 01:40:11 +00:00
$found = true ;
break ;
}
}
2019-10-21 01:14:52 +00:00
if ( $found ) {
if (( $y [ 'gname' ] != $cl [ 'name' ])
2018-06-05 01:40:11 +00:00
|| ( $y [ 'visible' ] != $cl [ 'visible' ])
|| ( $y [ 'deleted' ] != $cl [ 'deleted' ])) {
2018-09-26 00:47:43 +00:00
q ( " update pgrp set gname = '%s', visible = %d, deleted = %d where hash = '%s' and uid = %d " ,
2018-06-05 01:40:11 +00:00
dbesc ( $cl [ 'name' ]),
intval ( $cl [ 'visible' ]),
intval ( $cl [ 'deleted' ]),
dbesc ( $cl [ 'collection' ]),
intval ( $channel [ 'channel_id' ])
);
}
2019-10-21 01:14:52 +00:00
if ( intval ( $cl [ 'deleted' ]) && ( ! intval ( $y [ 'deleted' ]))) {
2018-09-26 00:47:43 +00:00
q ( " delete from pgrp_member where gid = %d " ,
2018-06-05 01:40:11 +00:00
intval ( $y [ 'id' ])
);
}
}
}
2019-10-21 01:14:52 +00:00
if ( ! $found ) {
2020-07-22 01:16:27 +00:00
$r = q ( " INSERT INTO pgrp ( hash, uid, visible, deleted, gname, rule )
2020-08-01 20:48:57 +00:00
VALUES ( '%s' , % d , % d , % d , '%s' , '%s' ) " ,
2018-06-05 01:40:11 +00:00
dbesc ( $cl [ 'collection' ]),
intval ( $channel [ 'channel_id' ]),
intval ( $cl [ 'visible' ]),
intval ( $cl [ 'deleted' ]),
2020-08-01 20:48:57 +00:00
dbesc ( $cl [ 'name' ]),
dbesc ( $cl [ 'rule' ])
2018-06-05 01:40:11 +00:00
);
}
// now look for any collections locally which weren't in the list we just received.
// They need to be removed by marking deleted and removing the members.
// This shouldn't happen except for clones created before this function was written.
2019-10-21 01:14:52 +00:00
if ( $x ) {
2018-06-05 01:40:11 +00:00
$found_local = false ;
2019-10-21 01:14:52 +00:00
foreach ( $x as $y ) {
foreach ( $arr [ 'collections' ] as $cl ) {
if ( $cl [ 'collection' ] == $y [ 'hash' ]) {
2018-06-05 01:40:11 +00:00
$found_local = true ;
break ;
}
}
2019-10-21 01:14:52 +00:00
if ( ! $found_local ) {
2018-09-26 00:47:43 +00:00
q ( " delete from pgrp_member where gid = %d " ,
2018-06-05 01:40:11 +00:00
intval ( $y [ 'id' ])
);
2018-09-26 00:47:43 +00:00
q ( " update pgrp set deleted = 1 where id = %d and uid = %d " ,
2018-06-05 01:40:11 +00:00
intval ( $y [ 'id' ]),
intval ( $channel [ 'channel_id' ])
);
}
}
}
}
// reload the group list with any updates
2018-09-26 00:47:43 +00:00
$x = q ( " select * from pgrp where uid = %d " ,
2018-06-05 01:40:11 +00:00
intval ( $channel [ 'channel_id' ])
);
// now sync the members
2019-10-21 01:14:52 +00:00
if ( array_key_exists ( 'collection_members' , $arr )
2018-06-05 01:40:11 +00:00
&& is_array ( $arr [ 'collection_members' ])
&& count ( $arr [ 'collection_members' ])) {
// first sort into groups keyed by the group hash
$members = array ();
2019-10-21 01:14:52 +00:00
foreach ( $arr [ 'collection_members' ] as $cm ) {
if ( ! array_key_exists ( $cm [ 'collection' ], $members )) {
$members [ $cm [ 'collection' ]] = [];
}
2018-06-05 01:40:11 +00:00
$members [ $cm [ 'collection' ]][] = $cm [ 'member' ];
}
// our group list is already synchronised
2019-10-21 01:14:52 +00:00
if ( $x ) {
foreach ( $x as $y ) {
2018-06-05 01:40:11 +00:00
// for each group, loop on members list we just received
2019-10-21 01:14:52 +00:00
if ( isset ( $y [ 'hash' ]) && isset ( $members [ $y [ 'hash' ]])) {
foreach ( $members [ $y [ 'hash' ]] as $member ) {
2018-06-05 01:40:11 +00:00
$found = false ;
2018-09-26 00:47:43 +00:00
$z = q ( " select xchan from pgrp_member where gid = %d and uid = %d and xchan = '%s' limit 1 " ,
2018-06-05 01:40:11 +00:00
intval ( $y [ 'id' ]),
intval ( $channel [ 'channel_id' ]),
dbesc ( $member )
);
2019-10-21 01:14:52 +00:00
if ( $z ) {
2018-06-05 01:40:11 +00:00
$found = true ;
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
// if somebody is in the group that wasn't before - add them
2019-10-21 01:14:52 +00:00
if ( ! $found ) {
2018-09-26 00:47:43 +00:00
q ( " INSERT INTO pgrp_member (uid, gid, xchan)
2018-06-05 01:40:11 +00:00
VALUES ( % d , % d , '%s' ) " ,
intval ( $channel [ 'channel_id' ]),
intval ( $y [ 'id' ]),
dbesc ( $member )
);
}
}
}
// now retrieve a list of members we have on this site
2018-09-26 00:47:43 +00:00
$m = q ( " select xchan from pgrp_member where gid = %d and uid = %d " ,
2018-06-05 01:40:11 +00:00
intval ( $y [ 'id' ]),
intval ( $channel [ 'channel_id' ])
);
2019-10-21 01:14:52 +00:00
if ( $m ) {
foreach ( $m as $mm ) {
2018-06-05 01:40:11 +00:00
// if the local existing member isn't in the list we just received - remove them
2019-10-21 01:14:52 +00:00
if ( ! in_array ( $mm [ 'xchan' ], $members [ $y [ 'hash' ]])) {
2018-09-26 00:47:43 +00:00
q ( " delete from pgrp_member where xchan = '%s' and gid = %d and uid = %d " ,
2018-06-05 01:40:11 +00:00
dbesc ( $mm [ 'xchan' ]),
intval ( $y [ 'id' ]),
intval ( $channel [ 'channel_id' ])
);
}
}
}
}
}
}
}
2019-10-21 01:14:52 +00:00
if ( array_key_exists ( 'profile' , $arr ) && is_array ( $arr [ 'profile' ]) && count ( $arr [ 'profile' ])) {
2018-06-05 01:40:11 +00:00
$disallowed = array ( 'id' , 'aid' , 'uid' , 'guid' );
2019-10-21 01:14:52 +00:00
foreach ( $arr [ 'profile' ] as $profile ) {
2018-06-05 01:40:11 +00:00
$x = q ( " select * from profile where profile_guid = '%s' and uid = %d limit 1 " ,
dbesc ( $profile [ 'profile_guid' ]),
intval ( $channel [ 'channel_id' ])
);
2019-10-21 01:14:52 +00:00
if ( ! $x ) {
2018-06-05 01:40:11 +00:00
profile_store_lowlevel (
[
'aid' => $channel [ 'channel_account_id' ],
'uid' => $channel [ 'channel_id' ],
'profile_guid' => $profile [ 'profile_guid' ],
]
);
$x = q ( " select * from profile where profile_guid = '%s' and uid = %d limit 1 " ,
dbesc ( $profile [ 'profile_guid' ]),
intval ( $channel [ 'channel_id' ])
);
2019-10-21 01:14:52 +00:00
if ( ! $x ) {
2018-06-05 01:40:11 +00:00
continue ;
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
}
2019-10-21 01:14:52 +00:00
$clean = [];
foreach ( $profile as $k => $v ) {
if ( in_array ( $k , $disallowed )) {
2018-06-05 01:40:11 +00:00
continue ;
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
2019-10-21 01:14:52 +00:00
if ( $profile [ 'is_default' ] && in_array ( $k ,[ 'photo' , 'thumb' ])) {
2018-06-05 01:40:11 +00:00
continue ;
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
2019-10-21 01:14:52 +00:00
if ( $k === 'name' ) {
2018-06-05 01:40:11 +00:00
$clean [ 'fullname' ] = $v ;
2019-10-21 01:14:52 +00:00
}
elseif ( $k === 'with' ) {
2018-06-05 01:40:11 +00:00
$clean [ 'partner' ] = $v ;
2019-10-21 01:14:52 +00:00
}
elseif ( $k === 'work' ) {
2018-06-05 01:40:11 +00:00
$clean [ 'employment' ] = $v ;
2019-10-21 01:14:52 +00:00
}
elseif ( array_key_exists ( $k , $x [ 0 ])) {
2018-06-05 01:40:11 +00:00
$clean [ $k ] = $v ;
2019-10-21 01:14:52 +00:00
}
2018-06-05 01:40:11 +00:00
/**
* @ TODO
* We also need to import local photos if a custom photo is selected
*/
2019-10-21 01:14:52 +00:00
if (( strpos ( $profile [ 'thumb' ], '/photo/profile/l/' ) !== false ) || intval ( $profile [ 'is_default' ])) {
2018-06-05 01:40:11 +00:00
$profile [ 'photo' ] = z_root () . '/photo/profile/l/' . $channel [ 'channel_id' ];
$profile [ 'thumb' ] = z_root () . '/photo/profile/m/' . $channel [ 'channel_id' ];
}
else {
$profile [ 'photo' ] = z_root () . '/photo/' . basename ( $profile [ 'photo' ]);
$profile [ 'thumb' ] = z_root () . '/photo/' . basename ( $profile [ 'thumb' ]);
}
}
2019-10-21 01:14:52 +00:00
if ( count ( $clean )) {
foreach ( $clean as $k => $v ) {
2018-06-05 01:40:11 +00:00
$r = dbq ( " UPDATE profile set " . TQUOT . dbesc ( $k ) . TQUOT . " = ' " . dbesc ( $v )
. " ' where profile_guid = ' " . dbesc ( $profile [ 'profile_guid' ])
. " ' and uid = " . intval ( $channel [ 'channel_id' ]));
}
}
}
}
2019-10-21 01:14:52 +00:00
$addon = [ 'channel' => $channel , 'data' => $arr ];
2018-06-05 01:40:11 +00:00
/**
* @ hooks process_channel_sync_delivery
* Called when accepting delivery of a 'sync packet' containing structure and table updates from a channel clone .
* * \e array \b channel
* * \e array \b data
*/
call_hooks ( 'process_channel_sync_delivery' , $addon );
2019-10-21 01:14:52 +00:00
$DR = new DReport ( z_root (), $d , $d , 'sync' , 'channel sync delivered' );
2018-06-05 01:40:11 +00:00
2018-07-30 06:49:37 +00:00
$DR -> set_name ( $channel [ 'channel_name' ] . ' <' . channel_reddress ( $channel ) . '>' );
2018-06-05 01:40:11 +00:00
$result [] = $DR -> get ();
}
return $result ;
}
2018-07-04 06:24:36 +00:00
/**
* @ brief Synchronises locations .
*
* @ param array $sender
* @ param array $arr
* @ param boolean $absolute ( optional ) default false
* @ return array
*/
static function sync_locations ( $sender , $arr , $absolute = false ) {
$ret = array ();
if ( $arr [ 'locations' ]) {
2019-10-20 22:24:03 +00:00
$x = q ( " select * from xchan where xchan_hash = '%s' " ,
dbesc ( $sender [ 'hash' ])
);
if ( $x ) {
$xchan = array_shift ( $x );
}
2018-07-04 06:24:36 +00:00
2019-10-20 22:24:03 +00:00
if ( $absolute ) {
Libzot :: check_location_move ( $sender [ 'hash' ], $arr [ 'locations' ]);
}
2018-07-04 06:24:36 +00:00
$xisting = q ( " select * from hubloc where hubloc_hash = '%s' " ,
dbesc ( $sender [ 'hash' ])
);
// See if a primary is specified
$has_primary = false ;
foreach ( $arr [ 'locations' ] as $location ) {
if ( $location [ 'primary' ]) {
$has_primary = true ;
break ;
}
}
// Ensure that they have one primary hub
if ( ! $has_primary )
$arr [ 'locations' ][ 0 ][ 'primary' ] = true ;
foreach ( $arr [ 'locations' ] as $location ) {
2018-07-05 01:18:35 +00:00
if ( ! Libzot :: verify ( $location [ 'url' ], $location [ 'url_sig' ], $sender [ 'public_key' ])) {
2018-07-04 06:24:36 +00:00
logger ( 'Unable to verify site signature for ' . $location [ 'url' ]);
$ret [ 'message' ] .= sprintf ( t ( 'Unable to verify site signature for %s' ), $location [ 'url' ]) . EOL ;
continue ;
}
for ( $x = 0 ; $x < count ( $xisting ); $x ++ ) {
if (( $xisting [ $x ][ 'hubloc_url' ] === $location [ 'url' ])
&& ( $xisting [ $x ][ 'hubloc_sitekey' ] === $location [ 'sitekey' ])) {
$xisting [ $x ][ 'updated' ] = true ;
}
}
if ( ! $location [ 'sitekey' ]) {
logger ( 'Empty hubloc sitekey. ' . print_r ( $location , true ));
continue ;
}
// match as many fields as possible in case anything at all changed.
$r = q ( " select * from hubloc where hubloc_hash = '%s' and hubloc_guid = '%s' and hubloc_guid_sig = '%s' and hubloc_id_url = '%s' and hubloc_url = '%s' and hubloc_url_sig = '%s' and hubloc_site_id = '%s' and hubloc_host = '%s' and hubloc_addr = '%s' and hubloc_callback = '%s' and hubloc_sitekey = '%s' " ,
dbesc ( $sender [ 'hash' ]),
dbesc ( $sender [ 'id' ]),
dbesc ( $sender [ 'id_sig' ]),
dbesc ( $location [ 'id_url' ]),
dbesc ( $location [ 'url' ]),
dbesc ( $location [ 'url_sig' ]),
dbesc ( $location [ 'site_id' ]),
dbesc ( $location [ 'host' ]),
dbesc ( $location [ 'address' ]),
dbesc ( $location [ 'callback' ]),
dbesc ( $location [ 'sitekey' ])
);
if ( $r ) {
logger ( 'Hub exists: ' . $location [ 'url' ], LOGGER_DEBUG );
// update connection timestamp if this is the site we're talking to
// This only happens when called from import_xchan
$current_site = false ;
$t = datetime_convert ( 'UTC' , 'UTC' , 'now - 15 minutes' );
if ( array_key_exists ( 'site' , $arr ) && $location [ 'url' ] == $arr [ 'site' ][ 'url' ]) {
q ( " update hubloc set hubloc_connected = '%s', hubloc_updated = '%s' where hubloc_id = %d and hubloc_connected < '%s' " ,
dbesc ( datetime_convert ()),
dbesc ( datetime_convert ()),
intval ( $r [ 0 ][ 'hubloc_id' ]),
dbesc ( $t )
);
$current_site = true ;
}
2019-04-12 03:26:38 +00:00
if ( $current_site && ( intval ( $r [ 0 ][ 'hubloc_error' ]) || intval ( $r [ 0 ][ 'hubloc_deleted' ]))) {
q ( " update hubloc set hubloc_error = 0, hubloc_deleted = 0 where hubloc_id = %d " ,
2018-07-04 06:24:36 +00:00
intval ( $r [ 0 ][ 'hubloc_id' ])
);
if ( intval ( $r [ 0 ][ 'hubloc_orphancheck' ])) {
q ( " update hubloc set hubloc_orphancheck = 0 where hubloc_id = %d " ,
intval ( $r [ 0 ][ 'hubloc_id' ])
);
}
q ( " update xchan set xchan_orphan = 0 where xchan_orphan = 1 and xchan_hash = '%s' " ,
dbesc ( $sender [ 'hash' ])
);
}
// Remove pure duplicates
if ( count ( $r ) > 1 ) {
for ( $h = 1 ; $h < count ( $r ); $h ++ ) {
q ( " delete from hubloc where hubloc_id = %d " ,
intval ( $r [ $h ][ 'hubloc_id' ])
);
$what .= 'duplicate_hubloc_removed ' ;
$changed = true ;
}
}
if ( intval ( $r [ 0 ][ 'hubloc_primary' ]) && ( ! $location [ 'primary' ])) {
$m = q ( " update hubloc set hubloc_primary = 0, hubloc_updated = '%s' where hubloc_id = %d " ,
dbesc ( datetime_convert ()),
intval ( $r [ 0 ][ 'hubloc_id' ])
);
$r [ 0 ][ 'hubloc_primary' ] = intval ( $location [ 'primary' ]);
hubloc_change_primary ( $r [ 0 ]);
$what .= 'primary_hub ' ;
$changed = true ;
}
elseif (( ! intval ( $r [ 0 ][ 'hubloc_primary' ])) && ( $location [ 'primary' ])) {
$m = q ( " update hubloc set hubloc_primary = 1, hubloc_updated = '%s' where hubloc_id = %d " ,
dbesc ( datetime_convert ()),
intval ( $r [ 0 ][ 'hubloc_id' ])
);
// make sure hubloc_change_primary() has current data
$r [ 0 ][ 'hubloc_primary' ] = intval ( $location [ 'primary' ]);
hubloc_change_primary ( $r [ 0 ]);
$what .= 'primary_hub ' ;
$changed = true ;
}
elseif ( $absolute ) {
// Absolute sync - make sure the current primary is correctly reflected in the xchan
$pr = hubloc_change_primary ( $r [ 0 ]);
if ( $pr ) {
$what .= 'xchan_primary ' ;
$changed = true ;
}
}
2019-10-20 22:24:03 +00:00
elseif ( intval ( $r [ 0 ][ 'hubloc_primary' ]) && $xchan && $xchan [ 'xchan_url' ] !== $r [ 0 ][ 'hubloc_id_url' ]) {
$pr = hubloc_change_primary ( $r [ 0 ]);
if ( $pr ) {
$what .= 'xchan_primary ' ;
$changed = true ;
}
}
2018-07-04 06:24:36 +00:00
if ( intval ( $r [ 0 ][ 'hubloc_deleted' ]) && ( ! intval ( $location [ 'deleted' ]))) {
$n = q ( " update hubloc set hubloc_deleted = 0, hubloc_updated = '%s' where hubloc_id = %d " ,
dbesc ( datetime_convert ()),
intval ( $r [ 0 ][ 'hubloc_id' ])
);
$what .= 'undelete_hub ' ;
$changed = true ;
}
elseif (( ! intval ( $r [ 0 ][ 'hubloc_deleted' ])) && ( intval ( $location [ 'deleted' ]))) {
logger ( 'deleting hubloc: ' . $r [ 0 ][ 'hubloc_addr' ]);
$n = q ( " update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id = %d " ,
dbesc ( datetime_convert ()),
intval ( $r [ 0 ][ 'hubloc_id' ])
);
$what .= 'delete_hub ' ;
$changed = true ;
}
continue ;
}
// Existing hubs are dealt with. Now let's process any new ones.
// New hub claiming to be primary. Make it so by removing any existing primaries.
if ( intval ( $location [ 'primary' ])) {
$r = q ( " update hubloc set hubloc_primary = 0, hubloc_updated = '%s' where hubloc_hash = '%s' and hubloc_primary = 1 " ,
dbesc ( datetime_convert ()),
dbesc ( $sender [ 'hash' ])
);
}
logger ( 'New hub: ' . $location [ 'url' ]);
$r = hubloc_store_lowlevel (
[
'hubloc_guid' => $sender [ 'id' ],
'hubloc_guid_sig' => $sender [ 'id_sig' ],
'hubloc_id_url' => $location [ 'id_url' ],
'hubloc_hash' => $sender [ 'hash' ],
'hubloc_addr' => $location [ 'address' ],
'hubloc_network' => 'zot6' ,
'hubloc_primary' => intval ( $location [ 'primary' ]),
'hubloc_url' => $location [ 'url' ],
'hubloc_url_sig' => $location [ 'url_sig' ],
2018-07-25 03:21:01 +00:00
'hubloc_site_id' => Libzot :: make_xchan_hash ( $location [ 'url' ], $location [ 'sitekey' ]),
2018-07-04 06:24:36 +00:00
'hubloc_host' => $location [ 'host' ],
'hubloc_callback' => $location [ 'callback' ],
'hubloc_sitekey' => $location [ 'sitekey' ],
'hubloc_updated' => datetime_convert (),
'hubloc_connected' => datetime_convert ()
]
);
$what .= 'newhub ' ;
$changed = true ;
if ( $location [ 'primary' ]) {
$r = q ( " select * from hubloc where hubloc_addr = '%s' and hubloc_sitekey = '%s' limit 1 " ,
dbesc ( $location [ 'address' ]),
dbesc ( $location [ 'sitekey' ])
);
if ( $r )
hubloc_change_primary ( $r [ 0 ]);
}
}
// get rid of any hubs we have for this channel which weren't reported.
if ( $absolute && $xisting ) {
foreach ( $xisting as $x ) {
if ( ! array_key_exists ( 'updated' , $x )) {
logger ( 'Deleting unreferenced hub location ' . $x [ 'hubloc_addr' ]);
$r = q ( " update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id = %d " ,
dbesc ( datetime_convert ()),
intval ( $x [ 'hubloc_id' ])
);
$what .= 'removed_hub ' ;
$changed = true ;
}
}
}
}
else {
logger ( 'No locations to sync!' );
}
$ret [ 'change_message' ] = $what ;
$ret [ 'changed' ] = $changed ;
return $ret ;
}
2018-07-05 01:18:35 +00:00
static function keychange ( $channel , $arr ) {
2018-07-06 05:27:44 +00:00
// verify the keychange operation
if ( ! Libzot :: verify ( $arr [ 'channel' ][ 'channel_pubkey' ], $arr [ 'keychange' ][ 'new_sig' ], $channel [ 'channel_prvkey' ])) {
logger ( 'sync keychange: verification failed' );
return ;
}
2018-07-05 01:18:35 +00:00
2018-07-06 05:27:44 +00:00
$sig = Libzot :: sign ( $channel [ 'channel_guid' ], $arr [ 'channel' ][ 'channel_prvkey' ]);
$hash = Libzot :: make_xchan_hash ( $channel [ 'channel_guid' ], $arr [ 'channel' ][ 'channel_pubkey' ]);
2018-07-05 01:18:35 +00:00
2018-07-06 05:27:44 +00:00
$r = q ( " update channel set channel_prvkey = '%s', channel_pubkey = '%s', channel_guid_sig = '%s',
channel_hash = '%s' where channel_id = % d " ,
dbesc ( $arr [ 'channel' ][ 'channel_prvkey' ]),
dbesc ( $arr [ 'channel' ][ 'channel_pubkey' ]),
dbesc ( $sig ),
dbesc ( $hash ),
intval ( $channel [ 'channel_id' ])
);
if ( ! $r ) {
logger ( 'keychange sync: channel update failed' );
return ;
}
2018-07-05 01:18:35 +00:00
2018-07-06 05:27:44 +00:00
$r = q ( " select * from channel where channel_id = %d " ,
intval ( $channel [ 'channel_id' ])
);
2018-07-05 01:18:35 +00:00
2018-07-06 05:27:44 +00:00
if ( ! $r ) {
logger ( 'keychange sync: channel retrieve failed' );
return ;
}
2018-07-05 01:18:35 +00:00
2018-07-06 05:27:44 +00:00
$channel = $r [ 0 ];
2018-07-05 01:18:35 +00:00
2018-07-06 05:27:44 +00:00
$h = q ( " select * from hubloc where hubloc_hash = '%s' and hubloc_url = '%s' " ,
dbesc ( $arr [ 'keychange' ][ 'old_hash' ]),
dbesc ( z_root ())
);
2018-07-05 01:18:35 +00:00
2018-07-06 05:27:44 +00:00
if ( $h ) {
foreach ( $h as $hv ) {
$hv [ 'hubloc_guid_sig' ] = $sig ;
$hv [ 'hubloc_hash' ] = $hash ;
$hv [ 'hubloc_url_sig' ] = Libzot :: sign ( z_root (), $channel [ 'channel_prvkey' ]);
hubloc_store_lowlevel ( $hv );
}
}
2018-07-05 01:18:35 +00:00
2018-07-06 05:27:44 +00:00
$x = q ( " select * from xchan where xchan_hash = '%s' " ,
dbesc ( $arr [ 'keychange' ][ 'old_hash' ])
);
2018-07-05 01:18:35 +00:00
2018-07-06 05:27:44 +00:00
$check = q ( " select * from xchan where xchan_hash = '%s' " ,
dbesc ( $hash )
);
2018-07-05 01:18:35 +00:00
2018-07-06 05:27:44 +00:00
if (( $x ) && ( ! $check )) {
$oldxchan = $x [ 0 ];
foreach ( $x as $xv ) {
$xv [ 'xchan_guid_sig' ] = $sig ;
$xv [ 'xchan_hash' ] = $hash ;
$xv [ 'xchan_pubkey' ] = $channel [ 'channel_pubkey' ];
xchan_store_lowlevel ( $xv );
$newxchan = $xv ;
}
}
2018-07-05 01:18:35 +00:00
2018-07-06 05:27:44 +00:00
$a = q ( " select * from abook where abook_xchan = '%s' and abook_self = 1 " ,
dbesc ( $arr [ 'keychange' ][ 'old_hash' ])
);
2018-07-05 01:18:35 +00:00
2018-07-06 05:27:44 +00:00
if ( $a ) {
q ( " update abook set abook_xchan = '%s' where abook_id = %d " ,
dbesc ( $hash ),
intval ( $a [ 0 ][ 'abook_id' ])
);
2018-07-05 01:18:35 +00:00
}
2018-07-04 06:24:36 +00:00
2018-07-06 05:27:44 +00:00
xchan_change_key ( $oldxchan , $newxchan , $arr [ 'keychange' ]);
}
2018-07-04 06:24:36 +00:00
2018-06-05 01:40:11 +00:00
}