diff options
Diffstat (limited to 'include/zot.php')
-rw-r--r-- | include/zot.php | 337 |
1 files changed, 254 insertions, 83 deletions
diff --git a/include/zot.php b/include/zot.php index e96eae10d..c88b2a369 100644 --- a/include/zot.php +++ b/include/zot.php @@ -5,7 +5,7 @@ require_once('include/items.php'); require_once('include/hubloc.php'); /** - * Red implementation of zot protocol. + * Red implementation of zot protocol. * * https://github.com/friendica/red/wiki/zot * https://github.com/friendica/red/wiki/Zot---A-High-Level-Overview @@ -20,8 +20,8 @@ require_once('include/hubloc.php'); * Generates a unique string for use as a zot guid using our DNS-based url, the channel nickname and some entropy. * The entropy ensures uniqueness against re-installs where the same URL and nickname are chosen. * NOTE: zot doesn't require this to be unique. Internally we use a whirlpool hash of this guid and the signature - * of this guid signed with the channel private key. This can be verified and should make the probability of - * collision of the verified result negligible within the constraints of our immediate universe. + * of this guid signed with the channel private key. This can be verified and should make the probability of + * collision of the verified result negligible within the constraints of our immediate universe. * * @param string channel_nickname = unique nickname of controlling entity * @@ -51,7 +51,7 @@ function make_xchan_hash($guid,$guid_sig) { /** * @function zot_get_hublocs($hash) - * Given a zot hash, return all distinct hubs. + * Given a zot hash, return all distinct hubs. * This function is used in building the zot discovery packet * and therefore should only be used by channels which are defined * on this hub @@ -71,7 +71,7 @@ function make_xchan_hash($guid,$guid_sig) { * hubloc_connect char(255) * hubloc_sitekey text * hubloc_updated datetime - * hubloc_connected datetime + * hubloc_connected datetime * */ @@ -79,32 +79,32 @@ function zot_get_hublocs($hash) { /** Only search for active hublocs - e.g. those that haven't been marked deleted */ - $ret = q("select * from hubloc where hubloc_hash = '%s' and not ( hubloc_flags & %d ) group by hubloc_url ", + $ret = q("select * from hubloc where hubloc_hash = '%s' and not ( hubloc_flags & %d )>0 order by hubloc_url ", dbesc($hash), intval(HUBLOC_FLAGS_DELETED) ); return $ret; } - + /** * * @function zot_build_packet($channel,$type = 'notify',$recipients = null, $remote_key = null, $secret = null) * builds a zot notification packet that you can either - * store in the queue with a message array or call zot_zot to immediately + * store in the queue with a message array or call zot_zot to immediately * zot it to the other side * * @param array $channel => sender channel structure * @param string $type => packet type: one of 'ping', 'pickup', 'purge', 'refresh', 'force_refresh', 'notify', 'auth_check' * @param array $recipients => envelope information, array ( 'guid' => string, 'guid_sig' => string ); empty for public posts * @param string $remote_key => optional public site key of target hub used to encrypt entire packet - * NOTE: remote_key and encrypted packets are required for 'auth_check' packets, optional for all others + * NOTE: remote_key and encrypted packets are required for 'auth_check' packets, optional for all others * @param string $secret => random string, required for packets which require verification/callback - * e.g. 'pickup', 'purge', 'notify', 'auth_check'. Packet types 'ping', 'force_refresh', and 'refresh' do not require verification + * e.g. 'pickup', 'purge', 'notify', 'auth_check'. Packet types 'ping', 'force_refresh', and 'refresh' do not require verification * * @returns string json encoded zot packet */ -function zot_build_packet($channel,$type = 'notify',$recipients = null, $remote_key = null, $secret = null) { +function zot_build_packet($channel,$type = 'notify',$recipients = null, $remote_key = null, $secret = null, $extra = null) { $data = array( 'type' => $type, @@ -129,6 +129,12 @@ function zot_build_packet($channel,$type = 'notify',$recipients = null, $remote_ $data['secret_sig'] = base64url_encode(rsa_sign($secret,$channel['channel_prvkey'])); } + if($extra) { + foreach($extra as $k => $v) + $data[$k] = $v; + } + + logger('zot_build_packet: ' . print_r($data,true), LOGGER_DATA); // Hush-hush ultra top-secret mode @@ -188,14 +194,15 @@ function zot_finger($webbie,$channel,$autofallback = true) { logger('zot_finger: no address :' . $webbie); return array('success' => false); } - + logger('using xchan_addr: ' . $xchan_addr, LOGGER_DATA); + // potential issue here; the xchan_addr points to the primary hub. // The webbie we were called with may not, so it might not be found // unless we query for hubloc_addr instead of xchan_addr $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", + where xchan_addr = '%s' and (hubloc_flags & %d) > 0 limit 1", dbesc($xchan_addr), intval(HUBLOC_FLAGS_PRIMARY) ); @@ -205,6 +212,7 @@ function zot_finger($webbie,$channel,$autofallback = true) { if($r[0]['hubloc_network'] && $r[0]['hubloc_network'] !== 'zot') { logger('zot_finger: alternate network: ' . $webbie); + logger('url: '.$url.', net: '.var_export($r[0]['hubloc_network'],true), LOGGER_DATA); return array('success' => false); } } @@ -293,7 +301,7 @@ function zot_refresh($them,$channel = null, $force = false) { if($them['hubloc_url']) $url = $them['hubloc_url']; else { - $r = q("select hubloc_url from hubloc where hubloc_hash = '%s' and ( hubloc_flags & %d ) limit 1", + $r = q("select hubloc_url from hubloc where hubloc_hash = '%s' and ( hubloc_flags & %d ) > 0 limit 1", dbesc($them['xchan_hash']), intval(HUBLOC_FLAGS_PRIMARY) ); @@ -375,7 +383,7 @@ function zot_refresh($them,$channel = null, $force = false) { } } - $r = q("select * from abook where abook_xchan = '%s' and abook_channel = %d and not (abook_flags & %d) limit 1", + $r = q("select * from abook where abook_xchan = '%s' and abook_channel = %d and not (abook_flags & %d) > 0 limit 1", dbesc($x['hash']), intval($channel['channel_id']), intval(ABOOK_FLAG_SELF) @@ -401,7 +409,7 @@ function zot_refresh($them,$channel = null, $force = false) { $y = q("update abook set abook_their_perms = %d, abook_dob = '%s' where abook_xchan = '%s' and abook_channel = %d - and not (abook_flags & %d) limit 1", + and not (abook_flags & %d) > 0 ", intval($their_perms), dbesc($next_birthday), dbesc($x['hash']), @@ -413,7 +421,8 @@ function zot_refresh($them,$channel = null, $force = false) { // if they are in your address book but you aren't in theirs, and/or this does not // match your current connected state setting, toggle it. - + // FIXME: uncoverted to postgres + // FIXME: when this was enabled, all contacts became unconnected. Currently disabled intentionally // $y1 = q("update abook set abook_flags = (abook_flags ^ %d) // where abook_xchan = '%s' and abook_channel = %d // and not (abook_flags & %d) limit 1", @@ -433,15 +442,15 @@ function zot_refresh($them,$channel = null, $force = false) { } } else { - $default_perms = 0; - // look for default permissions to apply in return - e.g. auto-friend - $z = q("select * from abook where abook_channel = %d and (abook_flags & %d) limit 1", - intval($channel['channel_id']), - intval(ABOOK_FLAG_SELF) - ); - - if($z) - $default_perms = intval($z[0]['abook_my_perms']); + $role = get_pconfig($channel['channel_id'],'system','permissions_role'); + if($role) { + $xx = get_role_perms($role); + if($xx['perms_auto']) + $default_perms = $xx['perms_accept']; + } + if(! $default_perms) + $default_perms = intval(get_pconfig($channel['channel_id'],'system','autoperms')); + // Keep original perms to check if we need to notify them $previous_perms = get_all_perms($channel['channel_id'],$x['hash']); @@ -463,7 +472,7 @@ function zot_refresh($them,$channel = null, $force = false) { $new_perms = get_all_perms($channel['channel_id'],$x['hash']); if($new_perms != $previous_perms) { // Send back a permissions update if permissions have changed - $z = q("select * from abook where abook_xchan = '%s' and abook_channel = %d and not (abook_flags & %d) limit 1", + $z = q("select * from abook where abook_xchan = '%s' and abook_channel = %d and not (abook_flags & %d) > 0 limit 1", dbesc($x['hash']), intval($channel['channel_id']), intval(ABOOK_FLAG_SELF) @@ -693,10 +702,10 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { $dirmode = get_config('system','directory_mode'); - if((($arr['site']['directory_mode'] === 'standalone') || ($dirmode & DIRECTORY_MODE_STANDALONE)) -&& ($arr['site']['url'] != z_root())) + if((($arr['site']['directory_mode'] === 'standalone') || ($dirmode & DIRECTORY_MODE_STANDALONE)) && ($arr['site']['url'] != z_root())) $arr['searchable'] = false; + $hidden = (1 - intval($arr['searchable'])); // Be careful - XCHAN_FLAGS_HIDDEN should evaluate to 1 @@ -715,6 +724,11 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { if($deleted_changed) $new_flags = $new_flags ^ XCHAN_FLAGS_DELETED; + $public_forum = (($r[0]['xchan_flags'] & XCHAN_FLAGS_PUBFORUM) ? true : false); + $pubforum_changed = ((intval($public_forum) != intval($arr['public_forum'])) ? true : false); + if($pubforum_changed) + $new_flags = $r[0]['xchan_flags'] ^ XCHAN_FLAGS_PUBFORUM; + if(($r[0]['xchan_name_date'] != $arr['name_updated']) || ($r[0]['xchan_connurl'] != $arr['connections_url']) || ($r[0]['xchan_flags'] != $new_flags) @@ -724,7 +738,7 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { || ($r[0]['xchan_url'] != $arr['url'])) { $r = q("update xchan set xchan_name = '%s', xchan_name_date = '%s', xchan_connurl = '%s', xchan_follow = '%s', xchan_connpage = '%s', xchan_flags = %d, - xchan_addr = '%s', xchan_url = '%s' where xchan_hash = '%s' limit 1", + xchan_addr = '%s', xchan_url = '%s' where xchan_hash = '%s'", dbesc(($arr['name']) ? $arr['name'] : '-'), dbesc($arr['name_updated']), dbesc($arr['connections_url']), @@ -777,8 +791,8 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { dbesc($arr['connect_url']), dbesc(($arr['name']) ? $arr['name'] : '-'), dbesc('zot'), - dbesc($arr['photo_updated']), - dbesc($arr['name_updated']), + dbescdate($arr['photo_updated']), + dbescdate($arr['name_updated']), intval($new_flags) ); @@ -819,7 +833,7 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { // importing the photo failed somehow. Leave the photo_date alone so we can try again at a later date. // This often happens when somebody joins the matrix with a bad cert. $r = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' - where xchan_hash = '%s' limit 1", + where xchan_hash = '%s'", dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), @@ -829,8 +843,8 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { } else { $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' - where xchan_hash = '%s' limit 1", - dbesc(datetime_convert('UTC','UTC',$arr['photo_updated'])), + where xchan_hash = '%s'", + dbescdate(datetime_convert('UTC','UTC',$arr['photo_updated'])), dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), @@ -890,10 +904,10 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { 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", + $r = q("delete from xprof where xprof_hash = '%s'", dbesc($xchan_hash) ); - $r = q("delete from xtag where xtag_hash = '%s' limit 1", + $r = q("delete from xtag where xtag_hash = '%s'", dbesc($xchan_hash) ); } @@ -915,7 +929,7 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { } elseif(! $ud_flags) { // nothing changed but we still need to update the updates record - q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and not (ud_flags & %d) ", + q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and not (ud_flags & %d)>0 ", intval(UPDATE_FLAGS_UPDATED), dbesc($address), intval(UPDATE_FLAGS_UPDATED) @@ -965,14 +979,14 @@ function zot_process_response($hub,$arr,$outq) { // async messages remain in the queue until processed. if(intval($outq['outq_async'])) { - $r = q("update outq set outq_delivered = 1, outq_updated = '%s' where outq_hash = '%s' and outq_channel = %d limit 1", + $r = q("update outq set outq_delivered = 1, outq_updated = '%s' where outq_hash = '%s' and outq_channel = %d", dbesc(datetime_convert()), dbesc($outq['outq_hash']), intval($outq['outq_channel']) ); } else { - $r = q("delete from outq where outq_hash = '%s' and outq_channel = %d limit 1", + $r = q("delete from outq where outq_hash = '%s' and outq_channel = %d", dbesc($outq['outq_hash']), intval($outq['outq_channel']) ); @@ -1065,7 +1079,7 @@ function zot_import($arr, $sender_url) { if(array_key_exists('iv',$i['notify'])) { $i['notify'] = json_decode(crypto_unencapsulate($i['notify'],get_config('system','prvkey')),true); - } + } logger('zot_import: notify: ' . print_r($i['notify'],true), LOGGER_DATA); @@ -1075,6 +1089,9 @@ function zot_import($arr, $sender_url) { continue; } + $message_request = ((array_key_exists('message_id',$i['notify'])) ? true : false); + if($message_request) + logger('processing message request'); $i['notify']['sender']['hash'] = make_xchan_hash($i['notify']['sender']['guid'],$i['notify']['sender']['guid_sig']); $deliveries = null; @@ -1087,7 +1104,7 @@ function zot_import($arr, $sender_url) { } stringify_array_elms($recip_arr); $recips = implode(',',$recip_arr); - $r = q("select channel_hash as hash from channel where channel_hash in ( " . $recips . " ) and not ( channel_pageflags & %d ) ", + $r = q("select channel_hash as hash from channel where channel_hash in ( " . $recips . " ) and not ( channel_pageflags & %d )>0 ", intval(PAGE_REMOVED) ); if(! $r) { @@ -1098,7 +1115,7 @@ function zot_import($arr, $sender_url) { // It's a specifically targetted post. If we were sent a public_scope hint (likely), // get rid of it so that it doesn't get stored and cause trouble. - if(array_key_exists('message',$i) && array_key_exists('public_scope',$i['message'])) + if(($i) && is_array($i) && array_key_exists('message',$i) && is_array($i['message']) && array_key_exists('public_scope',$i['message'])) unset($i['message']['public_scope']); $deliveries = $r; @@ -1176,7 +1193,7 @@ function zot_import($arr, $sender_url) { logger('Activity recipients: ' . print_r($deliveries,true), LOGGER_DATA); $relay = ((array_key_exists('flags',$i['message']) && in_array('relay',$i['message']['flags'])) ? true : false); - $result = process_delivery($i['notify']['sender'],$arr,$deliveries,$relay); + $result = process_delivery($i['notify']['sender'],$arr,$deliveries,$relay,false,$message_request); } elseif($i['message']['type'] === 'mail') { @@ -1239,8 +1256,14 @@ function zot_import($arr, $sender_url) { function public_recips($msg) { + + require_once('include/identity.php'); + $check_mentions = false; + $include_sys = false; + if($msg['message']['type'] === 'activity') { + $include_sys = true; $col = 'channel_w_stream'; $field = PERMS_W_STREAM; if(array_key_exists('flags',$msg['message']) && in_array('thread_parent', $msg['message']['flags'])) { @@ -1269,9 +1292,9 @@ function public_recips($msg) { if($msg['notify']['sender']['url'] === z_root()) - $sql = " where (( " . $col . " & " . PERMS_NETWORK . " ) or ( " . $col . " & " . PERMS_SITE . " ) or ( " . $col . " & " . PERMS_PUBLIC . ")) "; + $sql = " where (( " . $col . " & " . PERMS_NETWORK . " )>0 or ( " . $col . " & " . PERMS_SITE . " )>0 or ( " . $col . " & " . PERMS_PUBLIC . ")>0) "; else - $sql = " where (( " . $col . " & " . PERMS_NETWORK . " ) or ( " . $col . " & " . PERMS_PUBLIC . ")) "; + $sql = " where (( " . $col . " & " . PERMS_NETWORK . " )>0 or ( " . $col . " & " . PERMS_PUBLIC . ")>0) "; $r = q("select channel_hash as hash from channel $sql or channel_hash = '%s' ", @@ -1281,7 +1304,7 @@ function public_recips($msg) { if(! $r) $r = array(); - $x = q("select channel_hash as hash from channel left join abook on abook_channel = channel_id where abook_xchan = '%s' and not ( channel_pageflags & " . PAGE_REMOVED . " ) and (( " . $col . " & " . PERMS_SPECIFIC . " ) and ( abook_my_perms & " . $field . " )) OR ( " . $col . " & " . PERMS_PENDING . " ) OR (( " . $col . " & " . PERMS_CONTACTS . " ) and not ( abook_flags & " . ABOOK_FLAG_PENDING . " )) ", + $x = q("select channel_hash as hash from channel left join abook on abook_channel = channel_id where abook_xchan = '%s' and not ( channel_pageflags & " . PAGE_REMOVED . " )>0 and (( " . $col . " & " . PERMS_SPECIFIC . " )>0 and ( abook_my_perms & " . $field . " )>0) OR ( " . $col . " & " . PERMS_PENDING . " )>0 OR (( " . $col . " & " . PERMS_CONTACTS . " )>0 and not ( abook_flags & " . ABOOK_FLAG_PENDING . " )>0) ", dbesc($msg['notify']['sender']['hash']) ); @@ -1290,6 +1313,14 @@ function public_recips($msg) { $r = array_merge($r,$x); + //logger('message: ' . print_r($msg['message'],true)); + + if($include_sys && array_key_exists('public_scope',$msg['message']) && $msg['message']['public_scope'] === 'public') { + $sys = get_sys_channel(); + if($sys) + $r[] = array('hash' => $sys['channel_hash']); + } + // look for any public mentions on this site // They will get filtered by tgroup_check() so we don't need to check permissions now @@ -1320,7 +1351,7 @@ function public_recips($msg) { function allowed_public_recips($msg) { - logger('allowed_public_recips: ' . print_r($msg,true)); + logger('allowed_public_recips: ' . print_r($msg,true),LOGGER_DATA); $recips = public_recips($msg); @@ -1357,7 +1388,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_xchan = '%s' and not ( channel_pageflags & %d ) ", + $r = q("select channel_hash as hash from channel left join abook on abook_channel = channel_id where abook_xchan = '%s' and not ( channel_pageflags & %d )>0 ", dbesc($hash), intval(PAGE_REMOVED) ); @@ -1373,7 +1404,7 @@ function allowed_public_recips($msg) { } -function process_delivery($sender,$arr,$deliveries,$relay,$public = false) { +function process_delivery($sender,$arr,$deliveries,$relay,$public = false,$request = false) { $result = array(); @@ -1386,8 +1417,9 @@ function process_delivery($sender,$arr,$deliveries,$relay,$public = false) { return; } } - + foreach($deliveries as $d) { + $local_public = $public; $r = q("select * from channel where channel_hash = '%s' limit 1", dbesc($d['hash']) ); @@ -1397,8 +1429,23 @@ function process_delivery($sender,$arr,$deliveries,$relay,$public = false) { continue; } + $channel = $r[0]; + // allow public postings to the sys channel regardless of permissions + if(($channel['channel_pageflags'] & PAGE_SYSTEM) && (! $arr['item_private'])) { + $local_public = true; + + $r = q("select xchan_flags from xchan where xchan_hash = '%s' limit 1", + dbesc($sender['hash']) + ); + // don't import sys channel posts from selfcensored authors + if($r && ($r[0]['xchan_flags'] & XCHAN_FLAGS_SELFCENSORED)) { + $local_public = false; + continue; + } + } + $tag_delivery = tgroup_check($channel['channel_id'],$arr); $perm = (($arr['mid'] == $arr['parent_mid']) ? 'send_stream' : 'post_comments'); @@ -1416,7 +1463,7 @@ function process_delivery($sender,$arr,$deliveries,$relay,$public = false) { } } - if((! perm_is_allowed($channel['channel_id'],$sender['hash'],$perm)) && (! $tag_delivery) && (! $public)) { + if((! perm_is_allowed($channel['channel_id'],$sender['hash'],$perm)) && (! $tag_delivery) && (! $local_public)) { logger("permission denied for delivery to channel {$channel['channel_id']} {$channel['channel_address']}"); $result[] = array($d['hash'],'permission denied',$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>',$arr['mid']); continue; @@ -1436,6 +1483,25 @@ function process_delivery($sender,$arr,$deliveries,$relay,$public = false) { ); if(! $r) { $result[] = array($d['hash'],'comment parent not found',$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>',$arr['mid']); + + // We don't seem to have a copy of this conversation or at least the parent + // - so request a copy of the entire conversation to date. + // Don't do this if it's a relay post as we're the ones who are supposed to + // have the copy and we don't want the request to loop. + // Also don't do this if this comment came from a conversation request packet. + // It's possible that comments are allowed but posting isn't and that could + // cause a conversation fetch loop. We can detect these packets since they are + // delivered via a 'notify' packet type that has a message_id element in the + // initial zot packet (just like the corresponding 'request' packet type which + // makes the request). + // We'll also check the send_stream permission - because if it isn't allowed, + // the top level post is unlikely to be imported and + // this is just an exercise in futility. + + if((! $relay) && (! $request) && (! $local_public) + && perm_is_allowed($channel['channel_id'],$sender['hash'],'send_stream')) { + proc_run('php', 'include/notifier.php', 'request', $channel['channel_id'], $sender['hash'], $arr['parent_mid']); + } continue; } if($relay) { @@ -1582,7 +1648,7 @@ function remove_community_tag($sender,$arr,$uid) { 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", + $x = q("delete from term where uid = %d and oid = %d and otype = %d and type = %d and term = '%s' and url = '%s'", intval($uid), intval($r[0]['id']), intval(TERM_OBJ_POST), @@ -1676,7 +1742,7 @@ function process_mail_delivery($sender,$arr,$deliveries) { ); if($r) { if($arr['mail_flags'] & MAIL_RECALLED) { - $x = q("delete from mail where id = %d and channel_id = %d limit 1", + $x = q("delete from mail where id = %d and channel_id = %d", intval($r[0]['id']), intval($channel['channel_id']) ); @@ -1802,7 +1868,7 @@ function sync_locations($sender,$arr,$absolute = false) { // This only happens when called from import_xchan 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 limit 1", + q("update hubloc set hubloc_connected = '%s', hubloc_updated = '%s' where hubloc_id = %d", dbesc(datetime_convert()), dbesc(datetime_convert()), intval($r[0]['hubloc_id']) @@ -1814,17 +1880,17 @@ function sync_locations($sender,$arr,$absolute = false) { // the directory server if the site is alive. if($r[0]['hubloc_status'] & HUBLOC_OFFLINE) { - q("update hubloc set hubloc_status = (hubloc_status ^ %d) where hubloc_id = %d limit 1", + q("update hubloc set hubloc_status = (hubloc_status & ~%d) where hubloc_id = %d", intval(HUBLOC_OFFLINE), intval($r[0]['hubloc_id']) ); if($r[0]['hubloc_flags'] & HUBLOC_FLAGS_ORPHANCHECK) { - q("update hubloc set hubloc_flags = (hubloc_flags ^ %d) where hubloc_id = %d limit 1", + q("update hubloc set hubloc_flags = (hubloc_flags & ~%d) where hubloc_id = %d", intval(HUBLOC_FLAGS_ORPHANCHECK), intval($r[0]['hubloc_id']) ); } - q("update xchan set xchan_flags = (xchan_flags ^ %d) where (xchan_flags & %d) and xchan_hash = '%s' limit 1", + q("update xchan set xchan_flags = (xchan_flags & ~%d) where (xchan_flags & %d)>0 and xchan_hash = '%s'", intval(XCHAN_FLAGS_ORPHAN), intval(XCHAN_FLAGS_ORPHAN), dbesc($sender['hash']) @@ -1834,7 +1900,7 @@ function sync_locations($sender,$arr,$absolute = false) { // Remove pure duplicates if(count($r) > 1) { for($h = 1; $h < count($r); $h ++) { - q("delete from hubloc where hubloc_id = %d limit 1", + q("delete from hubloc where hubloc_id = %d", intval($r[$h]['hubloc_id']) ); $what .= 'duplicate_hubloc_removed '; @@ -1844,7 +1910,7 @@ function sync_locations($sender,$arr,$absolute = false) { if((($r[0]['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY) && (! $location['primary'])) || ((! ($r[0]['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY)) && ($location['primary']))) { - $m = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d), hubloc_updated = '%s' where hubloc_id = %d limit 1", + $m = q("update hubloc set hubloc_flags = (hubloc_flags & ~%d), hubloc_updated = '%s' where hubloc_id = %d", intval(HUBLOC_FLAGS_PRIMARY), dbesc(datetime_convert()), intval($r[0]['hubloc_id']) @@ -1865,7 +1931,7 @@ function sync_locations($sender,$arr,$absolute = false) { } if((($r[0]['hubloc_flags'] & HUBLOC_FLAGS_DELETED) && (! $location['deleted'])) || ((! ($r[0]['hubloc_flags'] & HUBLOC_FLAGS_DELETED)) && ($location['deleted']))) { - $n = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d), hubloc_updated = '%s' where hubloc_id = %d limit 1", + $n = q("update hubloc set hubloc_flags = (hubloc_flags & ~%d), hubloc_updated = '%s' where hubloc_id = %d", intval(HUBLOC_FLAGS_DELETED), dbesc(datetime_convert()), intval($r[0]['hubloc_id']) @@ -1880,7 +1946,7 @@ function sync_locations($sender,$arr,$absolute = false) { // New hub claiming to be primary. Make it so by removing any existing primaries. if(intval($location['primary'])) { - $r = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d), hubloc_updated = '%s' where hubloc_hash = '%s' and (hubloc_flags & %d )", + $r = q("update hubloc set hubloc_flags = (hubloc_flags & ~%d), hubloc_updated = '%s' where hubloc_hash = '%s' and (hubloc_flags & %d )>0", intval(HUBLOC_FLAGS_PRIMARY), dbesc(datetime_convert()), dbesc($sender['hash']), @@ -1923,7 +1989,7 @@ function sync_locations($sender,$arr,$absolute = false) { foreach($xisting as $x) { if(! array_key_exists('updated',$x)) { logger('sync_locations: deleting unreferenced hub location ' . $x['hubloc_url']); - $r = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d), hubloc_updated = '%s' where hubloc_id = %d limit 1", + $r = q("update hubloc set hubloc_flags = (hubloc_flags & ~%d), hubloc_updated = '%s' where hubloc_id = %d", intval(HUBLOC_FLAGS_DELETED), dbesc(datetime_convert()), intval($x['hubloc_id']) @@ -2017,7 +2083,7 @@ function import_directory_profile($hash,$profile,$addr,$ud_flags = UPDATE_FLAGS_ if(in_arrayi('nsfw',$clean) || in_arrayi('adult',$clean)) { - q("update xchan set xchan_flags = (xchan_flags | %d) where xchan_hash = '%s' limit 1", + q("update xchan set xchan_flags = (xchan_flags | %d) where xchan_hash = '%s'", intval(XCHAN_FLAGS_SELFCENSORED), dbesc($hash) ); @@ -2052,7 +2118,7 @@ function import_directory_profile($hash,$profile,$addr,$ud_flags = UPDATE_FLAGS_ xprof_homepage = '%s', xprof_hometown = '%s', xprof_keywords = '%s' - where xprof_hash = '%s' limit 1", + where xprof_hash = '%s'", dbesc($arr['xprof_desc']), dbesc($arr['xprof_dob']), intval($arr['xprof_age']), @@ -2122,7 +2188,7 @@ function import_directory_keywords($hash,$keywords) { foreach($existing as $x) { if(! in_array($x,$clean)) - $r = q("delete from xtag where xtag_hash = '%s' and xtag_term = '%s' limit 1", + $r = q("delete from xtag where xtag_hash = '%s' and xtag_term = '%s'", dbesc($hash), dbesc($x) ); @@ -2154,7 +2220,7 @@ function update_modtime($hash,$guid,$addr,$flags = 0) { ); } else { - q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and not (ud_flags & %d) ", + q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and not (ud_flags & %d)>0 ", intval(UPDATE_FLAGS_UPDATED), dbesc($addr), intval(UPDATE_FLAGS_UPDATED) @@ -2245,7 +2311,7 @@ function import_site($arr,$pubkey) { // logger('import_site: stored: ' . print_r($siterecord,true)); $r = q("update site set site_location = '%s', site_flags = %d, site_access = %d, site_directory = '%s', site_register = %d, site_update = '%s', site_sellpage = '%s', site_realm = '%s' - where site_url = '%s' limit 1", + where site_url = '%s'", dbesc($site_location), intval($site_directory), intval($access_policy), @@ -2432,8 +2498,8 @@ function process_channel_sync_delivery($sender,$arr,$deliveries) { $channel = $r[0]; - $max_friends = service_class_fetch($channel['channel_id'],'total_channels'); - $max_feeds = account_service_class_fetch($channel['channel_account_id'],'total_feeds'); + $max_friends = service_class_fetch($channel['channel_id'],'total_channels'); + $max_feeds = account_service_class_fetch($channel['channel_account_id'],'total_feeds'); if($channel['channel_hash'] != $sender['hash']) { @@ -2461,7 +2527,7 @@ function process_channel_sync_delivery($sender,$arr,$deliveries) { 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"); + . "' where channel_id = " . intval($channel['channel_id']) ); } } } @@ -2492,7 +2558,7 @@ function process_channel_sync_delivery($sender,$arr,$deliveries) { logger('process_channel_sync_delivery: removing abook entry for ' . $abook['abook_xchan']); require_once('include/Contact.php'); - $r = q("select abook_id, abook_flags from abook where abook_xchan = '%s' and abook_channel = %d and not ( abook_flags & %d ) limit 1", + $r = q("select abook_id, abook_flags from abook where abook_xchan = '%s' and abook_channel = %d and not ( abook_flags & %d )>0 limit 1", dbesc($abook['abook_xchan']), intval($channel['channel_id']), intval(ABOOK_FLAG_SELF) @@ -2519,7 +2585,7 @@ function process_channel_sync_delivery($sender,$arr,$deliveries) { continue; } $j = json_decode($f['body'],true); - if(! ($j['success'] && $j['guid'])) { + if(! ($j['success'] && $j['guid'])) { logger('process_channel_sync_delivery: probe failed.'); continue; } @@ -2570,8 +2636,7 @@ function process_channel_sync_delivery($sender,$arr,$deliveries) { 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"); + . "' where abook_xchan = '" . dbesc($clean['abook_xchan']) . "' and abook_channel = " . intval($channel['channel_id'])); } } } @@ -2596,7 +2661,7 @@ function process_channel_sync_delivery($sender,$arr,$deliveries) { if(($y['name'] != $cl['name']) || ($y['visible'] != $cl['visible']) || ($y['deleted'] != $cl['deleted'])) { - q("update groups set name = '%s', visible = %d, deleted = %d where hash = '%s' and uid = %d limit 1", + q("update groups set name = '%s', visible = %d, deleted = %d where hash = '%s' and uid = %d", dbesc($cl['name']), intval($cl['visible']), intval($cl['deleted']), @@ -2618,8 +2683,8 @@ function process_channel_sync_delivery($sender,$arr,$deliveries) { intval($channel['channel_id']), intval($cl['visible']), intval($cl['deleted']), - dbesc($cl['name']) - ); + dbesc($cl['name']) + ); } // now look for any collections locally which weren't in the list we just received. @@ -2639,7 +2704,7 @@ function process_channel_sync_delivery($sender,$arr,$deliveries) { q("delete from group_member where gid = %d", intval($y['id']) ); - q("update groups set deleted = 1 where id = %d and uid = %d limit 1", + q("update groups set deleted = 1 where id = %d and uid = %d", intval($y['id']), intval($channel['channel_id']) ); @@ -2702,7 +2767,7 @@ function process_channel_sync_delivery($sender,$arr,$deliveries) { foreach($m as $mm) { // if the local existing member isn't in the list we just received - remove them if(! in_array($mm['xchan'],$members[$y['hash']])) { - q("delete from group_member where xchan = '%s' and gid = %d and uid = %d limit 1", + q("delete from group_member where xchan = '%s' and gid = %d and uid = %d", dbesc($mm['xchan']), intval($y['id']), intval($channel['channel_id']) @@ -2748,8 +2813,7 @@ function process_channel_sync_delivery($sender,$arr,$deliveries) { if(count($clean)) { foreach($clean as $k => $v) { $r = dbq("UPDATE profile set " . dbesc($k) . " = '" . dbesc($v) - . "' where profile_guid = '" . dbesc($profile['profile_guid']) . "' and uid = " . intval($channel['channel_id']) - . " limit 1"); + . "' where profile_guid = '" . dbesc($profile['profile_guid']) . "' and uid = " . intval($channel['channel_id'])); } } } @@ -2774,7 +2838,7 @@ function get_rpost_path($observer) { function import_author_zot($x) { $hash = make_xchan_hash($x['guid'],$x['guid_sig']); - $r = q("select hubloc_url from hubloc where hubloc_guid = '%s' and hubloc_guid_sig = '%s' and (hubloc_flags & %d) limit 1", + $r = q("select hubloc_url from hubloc where hubloc_guid = '%s' and hubloc_guid_sig = '%s' and (hubloc_flags & %d)>0 limit 1", dbesc($x['guid']), dbesc($x['guid_sig']), intval(HUBLOC_FLAGS_PRIMARY) @@ -2793,3 +2857,110 @@ function import_author_zot($x) { return false; } + +/** + * @function zot_process_message_request($data) + * If a site receives a comment to a post but finds they have no parent to attach it with, they + * may send a 'request' packet containing the message_id of the missing parent. This is the handler + * for that packet. We will create a message_list array of the entire conversation starting with + * the missing parent and invoke delivery to the sender of the packet. + * + * include/deliver.php (for local delivery) and mod/post.php (for web delivery) detect the existence of + * this 'message_list' at the destination and split it into individual messages which are + * processed/delivered in order. + * + * Called from mod/post.php + */ + + +function zot_process_message_request($data) { + $ret = array('success' => false); + + if(! $data['message_id']) { + $ret['message'] = 'no message_id'; + logger('no message_id'); + return $ret; + } + + $sender = $data['sender']; + $sender_hash = make_xchan_hash($sender['guid'],$sender['guid_sig']); + + /* + * Find the local channel in charge of this post (the first and only recipient of the request packet) + */ + + $arr = $data['recipients'][0]; + $recip_hash = make_xchan_hash($arr['guid'],$arr['guid_sig']); + $c = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_hash = '%s' limit 1", + dbesc($recip_hash) + ); + if(! $c) { + logger('recipient channel not found.'); + $ret['message'] .= 'recipient not found.' . EOL; + return $ret; + } + + /* + * fetch the requested conversation + */ + + $messages = zot_feed($c[0]['channel_id'],$sender_hash,array('message_id' => $data['message_id'])); + + if($messages) { + $env_recips = null; + + $r = q("select hubloc_guid, hubloc_url, hubloc_sitekey, hubloc_network, hubloc_flags, hubloc_callback, hubloc_host + from hubloc where hubloc_hash = '%s' and not (hubloc_flags & %d)>0 + and not (hubloc_status & %d)>0 group by hubloc_sitekey", + dbesc($sender_hash), + intval(HUBLOC_FLAGS_DELETED), + intval(HUBLOC_OFFLINE) + ); + if(! $r) { + logger('no hubs'); + return $ret; + } + $hubs = $r; + $hublist = array(); + $keys = array(); + + $private = ((array_key_exists('flags',$messages[0]) && in_array('private',$messages[0]['flags'])) ? true : false); + if($private) + $env_recips = array('guid' => $sender['guid'],'guid_sig' => $sender['guid_sig'],'hash' => $sender_hash); + + $data_packet = json_encode(array('message_list' => $messages)); + + foreach($hubs as $hub) { + $hash = random_string(); + + /* + * create a notify packet and drop the actual message packet in the queue for pickup + */ + + $n = zot_build_packet($c[0],'notify',$env_recips,(($private) ? $hub['hubloc_sitekey'] : null),$hash,array('message_id' => $data['message_id'])); + q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, + outq_created, outq_updated, outq_notify, outq_msg ) + values ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", + dbesc($hash), + intval($c[0]['channel_account_id']), + intval($c[0]['channel_id']), + dbesc('zot'), + dbesc($hub['hubloc_callback']), + intval(1), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + dbesc($n), + dbesc($data_packet) + ); + + /* + * invoke delivery to send out the notify packet + */ + + proc_run('php','include/deliver.php',$hash); + } + + } + $ret['success'] = true; + return $ret; +} |