aboutsummaryrefslogtreecommitdiffstats
path: root/include/zot.php
diff options
context:
space:
mode:
Diffstat (limited to 'include/zot.php')
-rw-r--r--include/zot.php818
1 files changed, 693 insertions, 125 deletions
diff --git a/include/zot.php b/include/zot.php
index 524f958ad..bddbc9bee 100644
--- a/include/zot.php
+++ b/include/zot.php
@@ -1,4 +1,4 @@
-<?php
+<?php /** @file */
require_once('include/crypto.php');
require_once('include/items.php');
@@ -47,34 +47,6 @@ function zot_get_hubloc($arr,$primary = false) {
}
-function zot_notify($channel,$url,$type = 'notify',$recipients = null, $remote_key = null) {
-
- $params = array(
- 'type' => $type,
- 'sender' => json_encode(array(
- 'guid' => $channel['channel_guid'],
- 'guid_sig' => base64url_encode(rsa_sign($channel['channel_guid'],$channel['channel_prvkey'])),
- 'url' => z_root(),
- 'url_sig' => base64url_encode(rsa_sign(z_root(),$channel['channel_prvkey']))
- )),
- 'callback' => '/post',
- 'version' => ZOT_REVISION
- );
-
-
- if($recipients)
- $params['recipients'] = json_encode($recipients);
-
- // Hush-hush ultra top-secret mode
-
- if($remote_key) {
- $params = aes_encapsulate($params,$remote_key);
- }
-
- $x = z_post_url($url,$params);
- return($x);
-}
-
/*
*
* zot_build_packet builds a notification packet that you can either
@@ -117,10 +89,33 @@ function zot_build_packet($channel,$type = 'notify',$recipients = null, $remote_
}
+/**
+ * @function: zot_zot
+ * @param: string $url
+ * @param: array $data
+ *
+ * @returns: array => see z_post_url for returned data format
+ */
+
+
+
function zot_zot($url,$data) {
return z_post_url($url,array('data' => $data));
}
+/**
+ * @function: zot_finger
+ *
+ * Look up information about channel
+ * @param: string $webbie
+ * does not have to be host qualified e.g. 'foo' is treated as 'foo@thishub'
+ * @param: array $channel
+ * (optional), if supplied permissions will be enumerated specifically for $channel
+ *
+ * @returns: array => see z_post_url and mod/zfinger.php
+ */
+
+
function zot_finger($webbie,$channel) {
@@ -135,6 +130,11 @@ function zot_finger($webbie,$channel) {
$xchan_addr = $address . '@' . $host;
+ if((! $address) || (! $xchan_addr)) {
+ logger('zot_finger: no address :' . $webbie);
+ return array('success' => false);
+ }
+
$r = q("select xchan.*, hubloc.* from xchan
left join hubloc on xchan_hash = hubloc_hash
where xchan_addr = '%s' and (hubloc_flags & %d) limit 1",
@@ -152,7 +152,7 @@ function zot_finger($webbie,$channel) {
$rhs = '/.well-known/zot-info';
$https = ((strpos($url,'https://') === 0) ? true : false);
- logger('zot_finger: ' . $url, LOGGER_DEBUG);
+ logger('zot_finger: ' . $address . ' at ' . $url, LOGGER_DEBUG);
if($channel) {
$postvars = array(
@@ -191,6 +191,15 @@ function zot_finger($webbie,$channel) {
}
+/**
+ * @function: zot_refresh
+ *
+ * zot_refresh is typically invoked when somebody has changed permissions of a channel and they are notified
+ * to fetch new permissions via a finger operation. This may result in a new connection (abook entry) being added to a local channel
+ * and it may result in auto-permissions being granted.
+ *
+ */
+
function zot_refresh($them,$channel = null) {
logger('zot_refresh: them: ' . print_r($them,true), LOGGER_DATA);
@@ -329,37 +338,25 @@ function zot_refresh($them,$channel = null) {
intval(ABOOK_FLAG_SELF)
);
if($z)
- proc_run('php','include/notifier.php','permissions_update',$z[0]['abook_id']);
+ proc_run('php','include/notifier.php','permission_update',$z[0]['abook_id']);
}
}
}
}
- else {
-
- logger('zot_refresh: importing profile if available');
-
- // Are we a directory server of some kind?
- $dirmode = intval(get_config('system','directory_mode'));
- if($dirmode != DIRECTORY_MODE_NORMAL) {
- if(array_key_exists('profile',$x) && is_array($x['profile'])) {
- import_directory_profile($x['hash'],$x['profile']);
- }
- else {
- // they may have made it private
- $r = q("delete from xprof where xprof_hash = '%s' limit 1",
- dbesc($x['hash'])
- );
- $r = q("delete from xtag where xtag_hash = '%s' limit 1",
- dbesc($x['hash'])
- );
- }
- }
- }
return true;
}
return false;
}
+/**
+ * @function: zot_gethub
+ *
+ * A guid and a url, both signed by the sender, distinguish a known sender at a known location
+ * This function looks these up to see if the channel is known. If not, we will need to verify it.
+ * @returns: array => hubloc record
+ */
+
+
function zot_gethub($arr) {
@@ -378,7 +375,7 @@ function zot_gethub($arr) {
return $r[0];
}
}
- logger('zot_gethub: not found', LOGGER_DEBUG);
+ logger('zot_gethub: not found: ' . print_r($arr,true), LOGGER_DEBUG);
return null;
}
@@ -417,6 +414,16 @@ function zot_register_hub($arr) {
function import_xchan($arr) {
$ret = array('success' => false);
+ $dirmode = intval(get_config('system','directory_mode'));
+
+ $changed = false;
+
+ if(! (is_array($arr) && array_key_exists('success',$arr) && $arr['success'])) {
+ logger('import_xchan: invalid data packet: ' . print_r($arr,true));
+ $ret['message'] = t('Invalid data packet');
+ return $ret;
+ }
+
$xchan_hash = base64url_encode(hash('whirlpool',$arr['guid'] . $arr['guid_sig'], true));
$import_photos = false;
@@ -427,6 +434,9 @@ function import_xchan($arr) {
return $ret;
}
+
+ logger('import_xchan: ' . $xchan_hash, LOGGER_DEBUG);
+
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
dbesc($xchan_hash)
);
@@ -454,21 +464,47 @@ function import_xchan($arr) {
$new_flags = $r[0]['xchan_flags'];
- if(($r[0]['xchan_name_date'] != $arr['name_updated']) || ($r[0]['xchan_connurl'] != $arr['connections_url']) || ($r[0]['xchan_flags'] != $new_flags)) {
- $r = q("update xchan set xchan_name = '%s', xchan_name_date = '%s', xchan_connurl = '%s', xchan_flags = %d where xchan_hash = '%s' limit 1",
+ if(($r[0]['xchan_name_date'] != $arr['name_updated'])
+ || ($r[0]['xchan_connurl'] != $arr['connections_url'])
+ || ($r[0]['xchan_flags'] != $new_flags)
+ || ($r[0]['xchan_addr'] != $arr['address'])
+ || ($r[0]['xchan_url'] != $arr['url'])) {
+ $r = q("update xchan set xchan_name = '%s', xchan_name_date = '%s', xchan_connurl = '%s', xchan_flags = %d,
+ xchan_addr = '%s', xchan_url = '%s' where xchan_hash = '%s' limit 1",
dbesc($arr['name']),
dbesc($arr['name_updated']),
dbesc($arr['connections_url']),
intval($new_flags),
+ dbesc($arr['address']),
+ dbesc($arr['url']),
dbesc($xchan_hash)
);
+
+ logger('import_xchan: existing: ' . print_r($r[0],true), LOGGER_DATA);
+ logger('import_xchan: new: ' . print_r($arr,true), LOGGER_DATA);
+
+ update_modtime($xchan_hash);
+ $changed = true;
}
}
else {
$import_photos = true;
+
+
+ if((($arr['site']['directory_mode'] === 'standalone') || ($dirmode & DIRECTORY_MODE_STANDALONE))
+&& ($arr['site']['url'] != z_root()))
+ $arr['searchable'] = false;
+
+ $hidden = (1 - intval($arr['searchable']));
+
+ if($hidden)
+ $new_flags = XCHAN_FLAGS_HIDDEN;
+ else
+ $new_flags = 0;
+
$x = q("insert into xchan ( xchan_hash, xchan_guid, xchan_guid_sig, xchan_pubkey, xchan_photo_mimetype,
- xchan_photo_l, xchan_addr, xchan_url, xchan_connurl, xchan_name, xchan_network, xchan_photo_date, xchan_name_date)
- values ( '%s', '%s', '%s', '%s' , '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ",
+ xchan_photo_l, xchan_addr, xchan_url, xchan_connurl, xchan_name, xchan_network, xchan_photo_date, xchan_name_date, xchan_flags)
+ values ( '%s', '%s', '%s', '%s' , '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d) ",
dbesc($xchan_hash),
dbesc($arr['guid']),
dbesc($arr['guid_sig']),
@@ -481,15 +517,18 @@ function import_xchan($arr) {
dbesc($arr['name']),
dbesc('zot'),
dbesc($arr['photo_updated']),
- dbesc($arr['name_updated'])
+ dbesc($arr['name_updated']),
+ intval($new_flags)
);
+ update_modtime($xchan_hash);
+ $changed = true;
}
if($import_photos) {
- require_once("Photo.php");
+ require_once('include/photo/photo_driver.php');
$photos = import_profile_photo($arr['photo'],$xchan_hash);
$r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s'
@@ -501,9 +540,20 @@ function import_xchan($arr) {
dbesc($photos[3]),
dbesc($xchan_hash)
);
+
+ update_modtime($xchan_hash);
+ $changed = true;
}
+ // what we are missing for true hub independence is for any changes in the primary hub to
+ // get reflected not only in the hublocs, but also to update the URLs and addr in the appropriate xchan
+
if($arr['locations']) {
+
+ $xisting = q("select hubloc_id, hubloc_url from hubloc where hubloc_hash = '%s'",
+ dbesc($xchan_hash)
+ );
+
foreach($arr['locations'] as $location) {
if(! rsa_verify($location['url'],base64url_decode($location['url_sig']),$arr['key'])) {
logger('import_xchan: Unable to verify site signature for ' . $location['url']);
@@ -511,20 +561,49 @@ function import_xchan($arr) {
continue;
}
- $r = q("select * from hubloc where hubloc_hash = '%s' and hubloc_url = '%s' limit 1",
+ for($x = 0; $x < count($xisting); $x ++) {
+ if($xisting[$x]['hubloc_url'] == $location['url']) {
+ $xisting[$x]['updated'] = true;
+ }
+ }
+
+ $r = q("select * from hubloc where hubloc_hash = '%s' and hubloc_guid = '%s' and hubloc_guid_sig = '%s'
+ and hubloc_url = '%s' and hubloc_url_sig = '%s' limit 1",
dbesc($xchan_hash),
- dbesc($location['url'])
+ dbesc($arr['guid']),
+ dbesc($arr['guid_sig']),
+ dbesc($location['url']),
+ dbesc($location['url_sig'])
);
if($r) {
- if(($r[0]['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY) && (! $location['primary'])) {
+ logger('import_xchan: hub exists: ' . $location['url']);
+ if((($r[0]['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY) && (! $location['primary']))
+ || ((! ($r[0]['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY)) && ($location['primary']))) {
$r = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d) where hubloc_id = %d limit 1",
intval(HUBLOC_FLAGS_PRIMARY),
intval($r[0]['hubloc_id'])
);
+ update_modtime($xchan_hash);
+ $changed = true;
}
continue;
}
+ if(! $location['sitekey']) {
+ logger('import_xchan: empty hubloc sitekey. ' . print_r($location,true));
+ continue;
+ }
+
+ // new hub claiming to be primary. Make it so.
+
+ if(intval($location['primary'])) {
+ $r = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d) where hubloc_hash = '%s' and (hubloc_flags & %d )",
+ intval(HUBLOC_FLAGS_PRIMARY),
+ dbesc($xchan_hash),
+ intval(HUBLOC_FLAGS_PRIMARY)
+ );
+ }
+ logger('import_xchan: new hub: ' . $location['url']);
$r = q("insert into hubloc ( hubloc_guid, hubloc_guid_sig, hubloc_hash, hubloc_addr, hubloc_flags, hubloc_url, hubloc_url_sig, hubloc_host, hubloc_callback, hubloc_sitekey)
values ( '%s','%s','%s','%s', %d ,'%s','%s','%s','%s','%s')",
dbesc($arr['guid']),
@@ -538,8 +617,61 @@ function import_xchan($arr) {
dbesc($location['callback']),
dbesc($location['sitekey'])
);
+ update_modtime($xchan_hash);
+ $changed = true;
+ }
+
+ // get rid of any hubs we have for this channel which weren't reported.
+ if($xisting) {
+ foreach($xisting as $x) {
+ if(! array_key_exists('updated',$x)) {
+ logger('import_xchan: removing unreferenced hub location ' . $x['hubloc_url']);
+ $r = q("delete from hubloc where hubloc_id = %d limit 1",
+ intval($x['hubloc_id'])
+ );
+ update_modtime($xchan_hash);
+ $changed = true;
+ }
+ }
+ }
+
+ }
+
+ // Are we a directory server of some kind?
+
+ if($dirmode != DIRECTORY_MODE_NORMAL) {
+ if(array_key_exists('profile',$arr) && is_array($arr['profile'])) {
+ $profile_changed = import_directory_profile($xchan_hash,$arr['profile']);
+ if($profile_changed) {
+ update_modtime($xchan_hash);
+ $changed = true;
+ }
+ }
+ else {
+ logger('import_xchan: profile not available - hiding');
+ // they may have made it private
+ $r = q("delete from xprof where xprof_hash = '%s' limit 1",
+ dbesc($xchan_hash)
+ );
+ $r = q("delete from xtag where xtag_hash = '%s' limit 1",
+ dbesc($xchan_hash)
+ );
+ }
+ }
+ if(array_key_exists('site',$arr) && is_array($arr['site'])) {
+ $profile_changed = import_site($arr['site'],$arr['key']);
+ if($profile_changed) {
+ update_modtime($xchan_hash);
+ $changed = true;
}
+ }
+
+
+
+ if($changed) {
+ // send out a directory mirror update packet if we're a directory server or some kind
+
}
@@ -586,6 +718,18 @@ function zot_process_response($hub,$arr,$outq) {
logger('zot_process_response: ' . print_r($x,true), LOGGER_DATA);
}
+/**
+ * @function: zot_fetch
+ *
+ * We received a notification packet (in mod/post.php) that a message is waiting for us, and we've verified the sender.
+ * Now send back a pickup message, using our message tracking ID ($arr['secret']), which we will sign.
+ * The entire pickup message is encrypted with the remote site's public key.
+ * If everything checks out on the remote end, we will receive back a packet containing one or more messages,
+ * which will be processed before returning.
+ *
+ */
+
+
function zot_fetch($arr) {
logger('zot_fetch: ' . print_r($arr,true), LOGGER_DATA);
@@ -594,7 +738,7 @@ function zot_fetch($arr) {
$ret_hub = zot_gethub($arr['sender']);
if(! $ret_hub) {
- logger('zot_fetch: not ret_hub');
+ logger('zot_fetch: no hub: ' . print_r($arr['sender'],true));
return;
}
@@ -620,11 +764,17 @@ function zot_fetch($arr) {
return $result;
}
+/**
+ * @function zot_import
+ *
+ * Process an incoming array of messages which were obtained via pickup, and
+ * import, update, delete as directed.
+ *
+ * The message types handled here are 'activity' (e.g. posts), 'mail' and 'profile'
+ */
function zot_import($arr) {
-// logger('zot_import: ' . print_r($arr,true), LOGGER_DATA);
-
$data = json_decode($arr['body'],true);
if(! $data) {
@@ -632,14 +782,10 @@ function zot_import($arr) {
return array();
}
-// logger('zot_import: data1: ' . print_r($data,true));
-
if(array_key_exists('iv',$data)) {
$data = json_decode(aes_unencapsulate($data,get_config('system','prvkey')),true);
}
- logger('zot_import: data' . print_r($data,true), LOGGER_DATA);
-
$incoming = $data['pickup'];
$return = array();
@@ -692,10 +838,12 @@ function zot_import($arr) {
if($i['message']) {
if($i['message']['type'] === 'activity') {
$arr = get_item_elements($i['message']);
+
if(! array_key_exists('created',$arr)) {
logger('Activity rejected: probable failure to lookup author/owner. ' . print_r($i['message'],true));
continue;
}
+
logger('Activity received: ' . print_r($arr,true), LOGGER_DATA);
logger('Activity recipients: ' . print_r($deliveries,true), LOGGER_DATA);
@@ -722,6 +870,16 @@ function zot_import($arr) {
$result = process_profile_delivery($i['notify']['sender'],$arr,$deliveries);
}
+ elseif($i['message']['type'] === 'channel_sync') {
+// $arr = get_channelsync_elements($i['message']);
+
+ $arr = $i['message'];
+
+ logger('Channel sync received: ' . print_r($arr,true), LOGGER_DATA);
+ logger('Channel sync recipients: ' . print_r($deliveries,true), LOGGER_DATA);
+
+ $result = process_channel_sync_delivery($i['notify']['sender'],$arr,$deliveries);
+ }
}
if($result)
$return = array_merge($return,$result);
@@ -780,7 +938,7 @@ function public_recips($msg) {
$x = array();
$r = array_merge($r,$x);
-
+ logger('public_recips: ' . print_r($r,true), LOGGER_DATA);
return $r;
}
@@ -832,7 +990,7 @@ function allowed_public_recips($msg) {
$condensed_recips[] = $rr['hash'];
$results = array();
- $r = q("select channel_hash as hash from channel left join abook on abook_channel = channel_id where abook_hash = '%s' ",
+ $r = q("select channel_hash as hash from channel left join abook on abook_channel = channel_id where abook_xchan = '%s' ",
dbesc($hash)
);
if($r) {
@@ -857,34 +1015,52 @@ function process_delivery($sender,$arr,$deliveries,$relay) {
);
if(! $r) {
- $result[] = array($d['hash'],'not found');
+ $result[] = array($d['hash'],'recipients not found');
continue;
}
$channel = $r[0];
- $perm = (($arr['uri'] == $arr['parent_uri']) ? 'send_stream' : 'post_comments');
+ $tag_delivery = tgroup_check($channel['channel_id'],$arr);
+
+ $perm = (($arr['mid'] == $arr['parent_mid']) ? 'send_stream' : 'post_comments');
- if(! perm_is_allowed($channel['channel_id'],$sender['hash'],$perm)) {
+ // This is our own post, possibly coming from a channel clone
+
+ if($arr['owner_xchan'] == $d['hash']) {
+ $arr['item_flags'] = $arr['item_flags'] | ITEM_WALL;
+ }
+ else {
+ // clear the wall flag if it is set
+ if($arr['item_flags'] & ITEM_WALL) {
+ $arr['item_flags'] = ($arr['item_flags'] ^ ITEM_WALL);
+ }
+ }
+
+ if((! perm_is_allowed($channel['channel_id'],$sender['hash'],$perm)) && (! $tag_delivery)) {
logger("permission denied for delivery {$channel['channel_id']}");
- $result[] = array($d['hash'],'permission denied');
+ $result[] = array($d['hash'],'permission denied',$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>');
continue;
}
if($arr['item_restrict'] & ITEM_DELETED) {
+
+ // remove_community_tag is a no-op if this isn't a community tag activity
+ remove_community_tag($sender,$arr,$channel['channel_id']);
+
$item_id = delete_imported_item($sender,$arr,$channel['channel_id']);
- $result[] = array($d['hash'],'deleted');
+ $result[] = array($d['hash'],'deleted',$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>');
if($relay && $item_id) {
logger('process_delivery: invoking relay');
proc_run('php','include/notifier.php','relay',intval($item_id));
- $result[] = array($d['hash'],'relayed');
+ $result[] = array($d['hash'],'relayed',$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>');
}
continue;
}
- // for events, extract the event info and create and event linked to an item
+ // for events, extract the event info and create an event linked to an item
if((x($arr,'obj_type')) && (activity_match($arr['obj_type'],ACTIVITY_OBJ_EVENT))) {
require_once('include/event.php');
@@ -894,13 +1070,13 @@ function process_delivery($sender,$arr,$deliveries,$relay) {
$ev['uid'] = $channel['channel_id'];
$ev['account'] = $channel['channel_account_id'];
$ev['edited'] = $arr['edited'];
- $ev['uri'] = $arr['uri'];
+ $ev['mid'] = $arr['mid'];
$ev['private'] = $arr['item_private'];
// is this an edit?
- $r = q("SELECT resource_id FROM item where uri = '%s' and uid = %d and resource_type = 'event' limit 1",
- dbesc($arr['uri']),
+ $r = q("SELECT resource_id FROM item where mid = '%s' and uid = %d and resource_type = 'event' limit 1",
+ dbesc($arr['mid']),
intval($channel['channel_id'])
);
if($r) {
@@ -909,34 +1085,37 @@ function process_delivery($sender,$arr,$deliveries,$relay) {
$xyz = event_store($ev);
- $result = array($d['hash'],'event processed');
+ $result = array($d['hash'],'event processed',$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>');
continue;
}
}
- $r = q("select id, edited from item where uri = '%s' and uid = %d limit 1",
- dbesc($arr['uri']),
+ $r = q("select id, edited from item where mid = '%s' and uid = %d limit 1",
+ dbesc($arr['mid']),
intval($channel['channel_id'])
);
if($r) {
- if($arr['edited'] > $r[0]['edited'])
+ if($arr['edited'] > $r[0]['edited']) {
+ $arr['id'] = $r[0]['id'];
+ $arr['uid'] = $channel['channel_id'];
update_imported_item($sender,$arr,$channel['channel_id']);
- $result[] = array($d['hash'],'updated');
+ }
+ $result[] = array($d['hash'],'updated',$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>');
$item_id = $r[0]['id'];
}
else {
$arr['aid'] = $channel['channel_account_id'];
$arr['uid'] = $channel['channel_id'];
$item_id = item_store($arr);
- $result[] = array($d['hash'],'posted');
+ $result[] = array($d['hash'],(($item_id) ? 'posted' : 'storage failed'),$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>');
}
if($relay && $item_id) {
logger('process_delivery: invoking relay');
proc_run('php','include/notifier.php','relay',intval($item_id));
- $result[] = array($d['hash'],'relayed');
+ $result[] = array($d['hash'],'relayed',$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>');
}
}
@@ -949,8 +1128,71 @@ function process_delivery($sender,$arr,$deliveries,$relay) {
}
+function remove_community_tag($sender,$arr,$uid) {
+
+ if(! (activity_match($arr['verb'],ACTIVITY_TAG) && ($arr['obj_type'] == ACTIVITY_OBJ_TAGTERM)))
+ return;
+
+ logger('remove_community_tag: invoked');
+
+
+ if(! get_pconfig($uid,'system','blocktags')) {
+ logger('remove_community tag: permission denied.');
+ return;
+ }
+
+ $r = q("select * from item where mid = '%s' and uid = %d limit 1",
+ dbesc($arr['mid']),
+ intval($uid)
+ );
+ if(! $r) {
+ logger('remove_community_tag: no item');
+ return;
+ }
+
+ if(($sender['hash'] != $r[0]['owner_xchan']) && ($sender['hash'] != $r[0]['author_xchan'])) {
+ logger('remove_community_tag: sender not authorised.');
+ return;
+ }
+
+ $i = $r[0];
+
+ if($i['target'])
+ $i['target'] = json_decode_plus($i['target']);
+ if($i['object'])
+ $i['object'] = json_decode_plus($i['object']);
+
+ if(! ($i['target'] && $i['object'])) {
+ logger('remove_community_tag: no target/object');
+ return;
+ }
+
+ $message_id = $i['target']['id'];
+
+ $r = q("select id from item where mid = '%s' and uid = %d limit 1",
+ dbesc($message_id),
+ intval($uid)
+ );
+ if(! $r) {
+ logger('remove_community_tag: no parent message');
+ return;
+ }
+
+ $x = q("delete from term where uid = %d and oid = %d and otype = %d and type = %d and term = '%s' and url = '%s' limit 1",
+ intval($uid),
+ intval($r[0]['id']),
+ intval(TERM_OBJ_POST),
+ intval(TERM_HASHTAG),
+ dbesc($i['object']['title']),
+ dbesc(get_rel_link($i['object']['link'],'alternate'))
+ );
+
+ return;
+}
+
function update_imported_item($sender,$item,$uid) {
-// FIXME
+
+ item_store_update($item);
logger('update_imported_item');
}
@@ -960,10 +1202,10 @@ function delete_imported_item($sender,$item,$uid) {
logger('delete_imported_item invoked',LOGGER_DEBUG);
$r = q("select id from item where ( author_xchan = '%s' or owner_xchan = '%s' )
- and uri = '%s' and uid = %d limit 1",
+ and mid = '%s' and uid = %d limit 1",
dbesc($sender['hash']),
dbesc($sender['hash']),
- dbesc($item['uri']),
+ dbesc($item['mid']),
intval($uid)
);
@@ -978,37 +1220,56 @@ function delete_imported_item($sender,$item,$uid) {
}
function process_mail_delivery($sender,$arr,$deliveries) {
+
+
+ $result = array();
foreach($deliveries as $d) {
$r = q("select * from channel where channel_hash = '%s' limit 1",
dbesc($d['hash'])
);
- if(! $r)
+ if(! $r) {
+ $result[] = array($d['hash'],'not found');
continue;
+ }
$channel = $r[0];
if(! perm_is_allowed($channel['channel_id'],$sender['hash'],'post_mail')) {
logger("permission denied for mail delivery {$channel['channel_id']}");
+ $result[] = array($d['hash'],'permission denied',$channel['channel_name']);
continue;
}
- $r = q("select id from mail where uri = '%s' and channel_id = %d limit 1",
- dbesc($arr['uri']),
+ $r = q("select id from mail where mid = '%s' and channel_id = %d limit 1",
+ dbesc($arr['mid']),
intval($channel['channel_id'])
);
if($r) {
- logger('duplicate mail received');
+ if($arr['mail_flags'] & MAIL_RECALLED) {
+ $x = q("delete from mail where id = %d and channel_id = %d limit 1",
+ intval($r[0]['id']),
+ intval($channel['channel_id'])
+ );
+ $result[] = array($d['hash'],'mail recalled',$channel['channel_name']);
+ logger('mail_recalled');
+ }
+ else {
+ $result[] = array($d['hash'],'duplicate mail received',$channel['channel_name']);
+ logger('duplicate mail received');
+ }
continue;
}
else {
$arr['account_id'] = $channel['channel_account_id'];
$arr['channel_id'] = $channel['channel_id'];
$item_id = mail_store($arr);
+ $result[] = array($d['hash'],'mail delivered',$channel['channel_name']);
}
}
+ return $result;
}
function process_profile_delivery($sender,$arr,$deliveries) {
@@ -1019,17 +1280,26 @@ function process_profile_delivery($sender,$arr,$deliveries) {
import_directory_profile($sender['hash'],$arr);
}
+
+/*
+ * @function import_directory_profile
+ *
+ * @returns boolean $updated if something changed
+ *
+ */
+
function import_directory_profile($hash,$profile) {
logger('import_directory_profile', LOGGER_DEBUG);
if(! $hash)
- return;
+ return false;
$arr = array();
$arr['xprof_hash'] = $hash;
$arr['xprof_desc'] = (($profile['description']) ? htmlentities($profile['description'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_dob'] = datetime_convert('','',$profile['birthday'],'Y-m-d'); // !!!! check this for 0000 year
+ $arr['xprof_age'] = (($profile['age']) ? intval($profile['age']) : 0);
$arr['xprof_gender'] = (($profile['gender']) ? htmlentities($profile['gender'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_marital'] = (($profile['marital']) ? htmlentities($profile['marital'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_sexual'] = (($profile['sexual']) ? htmlentities($profile['sexual'], ENT_COMPAT,'UTF-8',false) : '');
@@ -1043,47 +1313,60 @@ function import_directory_profile($hash,$profile) {
import_directory_keywords($hash,$profile['keywords']);
foreach($profile['keywords'] as $kw) {
$kw = trim(htmlentities($kw,ENT_COMPAT,'UTF-8',false));
+ $kw = trim($kw,',');
}
$clean[] = $kw;
}
$arr['xprof_keywords'] = implode(' ',$clean);
-
$r = q("select * from xprof where xprof_hash = '%s' limit 1",
dbesc($hash)
);
if($r) {
- $x = q("update xprof set
- xprof_desc = '%s',
- xprof_dob = '%s',
- xprof_gender = '%s',
- xprof_marital = '%s',
- xprof_sexual = '%s',
- xprof_locale = '%s',
- xprof_region = '%s',
- xprof_postcode = '%s',
- xprof_country = '%s',
- xprof_keywords = '%s'
- where xprof_hash = '%s' limit 1",
- dbesc($arr['xprof_desc']),
- dbesc($arr['xprof_dob']),
- dbesc($arr['xprof_gender']),
- dbesc($arr['xprof_marital']),
- dbesc($arr['xprof_sexual']),
- dbesc($arr['xprof_locale']),
- dbesc($arr['xprof_region']),
- dbesc($arr['xprof_postcode']),
- dbesc($arr['xprof_country']),
- dbesc($arr['xprof_keywords']),
- dbesc($arr['xprof_hash'])
- );
+ $update = false;
+ foreach($r[0] as $k => $v) {
+ if((array_key_exists($k,$arr)) && ($arr[$k] != $v)) {
+ $update = true;
+ break;
+ }
+ }
+ if($update) {
+ $x = q("update xprof set
+ xprof_desc = '%s',
+ xprof_dob = '%s',
+ xprof_age = %d,
+ xprof_gender = '%s',
+ xprof_marital = '%s',
+ xprof_sexual = '%s',
+ xprof_locale = '%s',
+ xprof_region = '%s',
+ xprof_postcode = '%s',
+ xprof_country = '%s',
+ xprof_keywords = '%s'
+ where xprof_hash = '%s' limit 1",
+ dbesc($arr['xprof_desc']),
+ dbesc($arr['xprof_dob']),
+ intval($arr['xprof_age']),
+ dbesc($arr['xprof_gender']),
+ dbesc($arr['xprof_marital']),
+ dbesc($arr['xprof_sexual']),
+ dbesc($arr['xprof_locale']),
+ dbesc($arr['xprof_region']),
+ dbesc($arr['xprof_postcode']),
+ dbesc($arr['xprof_country']),
+ dbesc($arr['xprof_keywords']),
+ dbesc($arr['xprof_hash'])
+ );
+ }
}
else {
- $x = q("insert into xprof (xprof_hash, xprof_desc, xprof_dob, xprof_gender, xprof_marital, xprof_sexual, xprof_locale, xprof_region, xprof_postcode, xprof_country, xprof_keywords) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ",
+ $update = true;
+ $x = q("insert into xprof (xprof_hash, xprof_desc, xprof_dob, xprof_age, xprof_gender, xprof_marital, xprof_sexual, xprof_locale, xprof_region, xprof_postcode, xprof_country, xprof_keywords) values ('%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ",
dbesc($arr['xprof_hash']),
dbesc($arr['xprof_desc']),
dbesc($arr['xprof_dob']),
+ intval($arr['xprof_age']),
dbesc($arr['xprof_gender']),
dbesc($arr['xprof_marital']),
dbesc($arr['xprof_sexual']),
@@ -1095,7 +1378,12 @@ function import_directory_profile($hash,$profile) {
);
}
- return;
+ $d = array('xprof' => $arr, 'profile' => $profile, 'update' => $update);
+ call_hooks('import_directory_profile', $d);
+
+ if($d['update'])
+ update_modtime($arr['xprof_hash']);
+ return $d['update'];
}
function import_directory_keywords($hash,$keywords) {
@@ -1125,9 +1413,289 @@ function import_directory_keywords($hash,$keywords) {
}
foreach($clean as $x) {
if(! in_array($x,$existing))
- $r = q("insert int xtag ( xtag_hash, xtag_term) values ( '%s' ,'%s' )",
+ $r = q("insert into xtag ( xtag_hash, xtag_term) values ( '%s' ,'%s' )",
dbesc($hash),
dbesc($x)
);
}
-} \ No newline at end of file
+}
+
+
+function update_modtime($hash) {
+ $r = q("select * from updates where ud_hash = '%s' limit 1",
+ dbesc($hash)
+ );
+ if($r)
+ q("update updates set ud_date = '%s' where ud_hash = '%s' limit 1",
+ dbesc(datetime_convert()),
+ dbesc($hash)
+ );
+ else
+ q("insert into updates (ud_hash, ud_date) values ( '%s', '%s' )",
+ dbesc($hash),
+ dbesc(datetime_convert())
+ );
+}
+
+
+function import_site($arr,$pubkey) {
+ if( (! is_array($arr)) || (! $arr['url']) || (! $arr['url_sig']))
+ return false;
+
+ if(! rsa_verify($arr['url'],base64url_decode($arr['url_sig']),$pubkey)) {
+ logger('import_site: bad url_sig');
+ return false;
+ }
+
+ $update = false;
+
+ $r = q("select * from site where site_url = '%s' limit 1",
+ dbesc($arr['url'])
+ );
+ if($r)
+ $update = true;
+
+ $site_directory = 0;
+ if($arr['directory_mode'] == 'normal')
+ $site_directory = DIRECTORY_MODE_NORMAL;
+
+ if($arr['directory_mode'] == 'primary')
+ $site_directory = DIRECTORY_MODE_PRIMARY;
+ if($arr['directory_mode'] == 'secondary')
+ $site_directory = DIRECTORY_MODE_SECONDARY;
+ if($arr['directory_mode'] == 'standalone')
+ $site_directory = DIRECTORY_MODE_STANDALONE;
+
+ $register_policy = 0;
+ if($arr['register_policy'] == 'closed')
+ $register_policy = REGISTER_CLOSED;
+ if($arr['register_policy'] == 'open')
+ $register_policy = REGISTER_OPEN;
+ if($arr['register_policy'] == 'approve')
+ $register_policy = REGISTER_APPROVE;
+
+ if($update) {
+ $r = q("update site set site_flags = %d, site_directory = '%s', site_register = %d, site_update = '%s'
+ where site_url = '%s' limit 1",
+ intval($site_directory),
+ dbesc(htmlentities($arr['directory_url'],ENT_COMPAT,'UTF-8',false)),
+ intval($register_policy),
+ dbesc(datetime_convert()),
+ dbesc(htmlentities($arr['url'],ENT_COMPAT,'UTF-8',false))
+ );
+ if(! $r) {
+ logger('import_site: update failed. ' . print_r($arr,true));
+ }
+ }
+ else {
+ $r = q("insert into site ( site_url, site_flags, site_update, site_directory, site_register )
+ values ( '%s', %d, '%s', '%s', %d )",
+ dbesc(htmlentities($arr['url'],ENT_COMPAT,'UTF-8',false)),
+ intval($site_directory),
+ dbesc(datetime_convert()),
+ dbesc(htmlentities($arr['directory_url'],ENT_COMPAT,'UTF-8',false)),
+ intval($register_policy)
+ );
+ if(! $r) {
+ logger('import_site: record create failed. ' . print_r($arr,true));
+ }
+ }
+
+ return $r;
+
+}
+
+
+
+/**
+ * Send a zot packet to all hubs where this channel is duplicated, refreshing
+ * such things as personal settings, channel permissions, address book updates, etc.
+ */
+
+function build_sync_packet($uid = 0, $packet = null) {
+
+ $a = get_app();
+
+ logger('build_sync_packet');
+
+ if(! $uid)
+ $uid = local_user();
+
+ if(! $uid)
+ return;
+
+ $r = q("select * from channel where channel_id = %d limit 1",
+ intval($uid)
+ );
+ if(! $r)
+ return;
+
+ $channel = $r[0];
+
+ $h = q("select * from hubloc where hubloc_hash = '%s'",
+ dbesc($channel['channel_hash'])
+ );
+
+ if(! $h)
+ return;
+
+ $synchubs = array();
+
+ foreach($h as $x) {
+ if($x['hubloc_host'] == $a->get_hostname())
+ continue;
+ $synchubs[] = $x;
+ }
+
+ if(! $synchubs)
+ return;
+
+ $r = q("select xchan_guid, xchan_guid_sig from xchan where xchan_hash = '%s' limit 1",
+ dbesc($channel['channel_hash'])
+ );
+ if(! $r)
+ return;
+
+ $env_recips = array();
+ $env_recips[] = array('guid' => $r[0]['xchan_guid'],'guid_sig' => $r[0]['xchan_guid_sig']);
+
+ $info = (($packet) ? $packet : array());
+ $info['type'] = 'channel_sync';
+
+ if(array_key_exists($uid,$a->config) && array_key_exists('transient',$a->config[$uid])) {
+ $settings = $a->config[$uid]['transient'];
+ if($settings) {
+ $info['config'] = $settings;
+ }
+ }
+
+ if($channel) {
+ $info['channel'] = array();
+ foreach($channel as $k => $v) {
+
+ // filter out any joined tables like xchan
+
+ if(strpos($k,'channel_') !== 0)
+ continue;
+
+ // don't pass these elements, they should not be synchronised
+
+ $disallowed = array('channel_id','channel_account_id','channel_primary','channel_prvkey','channel_address');
+
+ if(in_array($k,$disallowed))
+ continue;
+
+ $info['channel'][$k] = $v;
+ }
+ }
+
+ $interval = ((get_config('system','delivery_interval') !== false)
+ ? intval(get_config('system','delivery_interval')) : 2 );
+
+
+ logger('build_sync_packet: packet: ' . print_r($info,true), LOGGER_DATA);
+
+ foreach($synchubs as $hub) {
+ $hash = random_string();
+ $n = zot_build_packet($channel,'notify',$env_recips,$hub['hubloc_sitekey'],$hash);
+ q("insert into outq ( outq_hash, outq_account, outq_channel, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) values ( '%s', %d, %d, '%s', %d, '%s', '%s', '%s', '%s' )",
+ dbesc($hash),
+ intval($channel['channel_account']),
+ intval($channel['channel_id']),
+ dbesc($hub['hubloc_callback']),
+ intval(1),
+ dbesc(datetime_convert()),
+ dbesc(datetime_convert()),
+ dbesc($n),
+ dbesc(json_encode($info))
+ );
+
+ proc_run('php','include/deliver.php',$hash);
+ if($interval)
+ @time_sleep_until(microtime(true) + (float) $interval);
+ }
+
+
+}
+
+function process_channel_sync_delivery($sender,$arr,$deliveries) {
+
+// FIXME - this will sync red structures (channel, pconfig and abook). Eventually we need to make this application agnostic.
+// TODO: missing group membership changes
+
+ $result = array();
+
+ foreach($deliveries as $d) {
+ $r = q("select * from channel where channel_hash = '%s' limit 1",
+ dbesc($d['hash'])
+ );
+
+ if(! $r) {
+ $result[] = array($d['hash'],'not found');
+ continue;
+ }
+
+ $channel = $r[0];
+
+ if($channel['channel_hash'] != $sender['hash']) {
+ logger('process_channel_sync_delivery: possible forgery. Sender ' . $sender['hash'] . ' is not ' . $channel['channel_hash']);
+ $result[] = array($d['hash'],'channel mismatch',$channel['channel_name']);
+ continue;
+ }
+
+ if(array_key_exists('config',$arr) && is_array($arr['config']) && count($arr['config'])) {
+ foreach($arr['config'] as $cat => $k) {
+ foreach($arr['config'][$cat] as $k => $v)
+ set_pconfig($channel['channel_id'],$cat,$k,$v);
+ }
+ }
+
+ if(array_key_exists('channel',$arr) && is_array($arr['channel']) && count($arr['channel'])) {
+ $disallowed = array('channel_id','channel_account_id','channel_primary','channel_prvkey', 'channel_address');
+
+ $clean = array();
+ foreach($arr['channel'] as $k => $v) {
+ if(in_array($k,$disallowed))
+ continue;
+ $clean[$k] = $v;
+ }
+ if(count($clean)) {
+ foreach($clean as $k => $v) {
+ $r = dbq("UPDATE channel set " . dbesc($k) . " = '" . dbesc($v)
+ . "' where channel_id = " . intval($channel['channel_id']) . " limit 1");
+ }
+ }
+ }
+
+
+ if(array_key_exists('abook',$arr) && is_array($arr['abook']) && count($arr['abook'])) {
+
+ $disallowed = array('abook_id','abook_account','abook_channel');
+
+ $clean = array();
+ foreach($arr['abook'] as $abook) {
+ foreach($abook as $k => $v) {
+ if(in_array($k,$disallowed))
+ continue;
+ $clean[$k] = $v;
+ }
+
+ if(! array_key_exists('abook_xchan',$clean))
+ continue;
+
+ if(count($clean)) {
+ foreach($clean as $k => $v) {
+ $r = dbq("UPDATE abook set " . dbesc($k) . " = '" . dbesc($v)
+ . "' where abook_xchan = '" . dbesc($clean['abook_xchan']) . "' and abook_channel = " . intval($channel['channel_id'])
+ . " limit 1");
+ }
+ }
+ }
+ }
+
+ $result[] = array($d['hash'],'channel sync updated',$channel['channel_name']);
+
+
+ }
+ return $result;
+}