diff options
Diffstat (limited to 'include/zot.php')
-rw-r--r-- | include/zot.php | 992 |
1 files changed, 697 insertions, 295 deletions
diff --git a/include/zot.php b/include/zot.php index 75ce40ffc..d5d68f72c 100644 --- a/include/zot.php +++ b/include/zot.php @@ -1,7 +1,7 @@ <?php /** * @file include/zot.php - * @brief RedMatrix implementation of zot protocol. + * @brief Hubzilla implementation of zot protocol. * * https://github.com/friendica/red/wiki/zot * https://github.com/friendica/red/wiki/Zot---A-High-Level-Overview @@ -11,6 +11,7 @@ require_once('include/crypto.php'); require_once('include/items.php'); require_once('include/hubloc.php'); +require_once('include/DReport.php'); /** @@ -80,9 +81,8 @@ 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 )>0 order by hubloc_url ", - dbesc($hash), - intval(HUBLOC_FLAGS_DELETED) + $ret = q("select * from hubloc where hubloc_hash = '%s' and hubloc_deleted = 0 order by hubloc_url ", + dbesc($hash) ); return $ret; @@ -117,7 +117,8 @@ function zot_build_packet($channel, $type = 'notify', $recipients = null, $remot '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'])) + 'url_sig' => base64url_encode(rsa_sign(z_root(),$channel['channel_prvkey'])), + 'sitekey' => get_config('system','pubkey') ), 'callback' => '/post', 'version' => ZOT_REVISION @@ -200,9 +201,8 @@ function zot_finger($webbie, $channel = null, $autofallback = true) { $r = q("select xchan.*, hubloc.* from xchan left join hubloc on xchan_hash = hubloc_hash - where xchan_addr = '%s' and (hubloc_flags & %d) > 0 limit 1", - dbesc($xchan_addr), - intval(HUBLOC_FLAGS_PRIMARY) + where xchan_addr = '%s' and hubloc_primary = 1 limit 1", + dbesc($xchan_addr) ); if ($r) { @@ -298,19 +298,24 @@ function zot_refresh($them, $channel = null, $force = false) { } else { $r = null; + // if they re-installed the server we could end up with the wrong record - pointing to the old install. + // We'll order by reverse id to try and pick off the newest one first and hopefully end up with the + // correct hubloc. If this doesn't work we may have to re-write this section to try them all. + if(array_key_exists('xchan_addr',$them) && $them['xchan_addr']) { - $r = q("select hubloc_url, hubloc_flags from hubloc where hubloc_addr = '%s'", + $r = q("select hubloc_url, hubloc_primary from hubloc where hubloc_addr = '%s' order by hubloc_id desc", dbesc($them['xchan_addr']) ); } if(! $r) { - $r = q("select hubloc_url, hubloc_flags from hubloc where hubloc_hash = '%s'", + $r = q("select hubloc_url, hubloc_primary from hubloc where hubloc_hash = '%s' order by hubloc_id desc", dbesc($them['xchan_hash']) ); } + if ($r) { foreach ($r as $rr) { - if ($rr['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY) { + if (intval($rr['hubloc_primary'])) { $url = $rr['hubloc_url']; break; } @@ -402,10 +407,9 @@ function zot_refresh($them, $channel = null, $force = false) { $next_birthday = NULL_DATE; } - $r = q("select * from abook where abook_xchan = '%s' and abook_channel = %d and not (abook_flags & %d) > 0 limit 1", + $r = q("select * from abook where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 limit 1", dbesc($x['hash']), - intval($channel['channel_id']), - intval(ABOOK_FLAG_SELF) + intval($channel['channel_id']) ); if($r) { @@ -419,16 +423,15 @@ function zot_refresh($them, $channel = null, $force = false) { if(substr($r[0]['abook_dob'],5) == substr($next_birthday,5)) $next_birthday = $r[0]['abook_dob']; - $current_abook_connected = (($r[0]['abook_flags'] & ABOOK_FLAG_UNCONNECTED) ? 0 : 1); + $current_abook_connected = (intval($r[0]['abook_unconnected']) ? 0 : 1); $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) > 0 ", + and abook_self = 0 ", intval($their_perms), dbescdate($next_birthday), dbesc($x['hash']), - intval($channel['channel_id']), - intval(ABOOK_FLAG_SELF) + intval($channel['channel_id']) ); // if(($connected_set === 0 || $connected_set === 1) && ($connected_set !== $current_abook_unconnected)) { @@ -437,13 +440,11 @@ function zot_refresh($them, $channel = null, $force = false) { // 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) +// $y1 = q("update abook set abook_unconnected = 1 // where abook_xchan = '%s' and abook_channel = %d -// and not (abook_flags & %d) limit 1", -// intval(ABOOK_FLAG_UNCONNECTED), +// and abook_self = 0 limit 1", // dbesc($x['hash']), -// intval($channel['channel_id']), -// intval(ABOOK_FLAG_SELF) +// intval($channel['channel_id']) // ); // } @@ -477,7 +478,7 @@ function zot_refresh($them, $channel = null, $force = false) { if($closeness === false) $closeness = 80; - $y = q("insert into abook ( abook_account, abook_channel, abook_closeness, abook_xchan, abook_their_perms, abook_my_perms, abook_created, abook_updated, abook_dob, abook_flags ) values ( %d, %d, %d, '%s', %d, %d, '%s', '%s', '%s', %d )", + $y = q("insert into abook ( abook_account, abook_channel, abook_closeness, abook_xchan, abook_their_perms, abook_my_perms, abook_created, abook_updated, abook_dob, abook_pending ) values ( %d, %d, %d, '%s', %d, %d, '%s', '%s', '%s', %d )", intval($channel['channel_account_id']), intval($channel['channel_id']), intval($closeness), @@ -487,7 +488,7 @@ function zot_refresh($them, $channel = null, $force = false) { dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc($next_birthday), - intval(($default_perms) ? 0 : ABOOK_FLAG_PENDING) + intval(($default_perms) ? 0 : 1) ); if($y) { @@ -496,15 +497,14 @@ function zot_refresh($them, $channel = null, $force = false) { // Send a clone sync packet and a permissions update if permissions have changed - $new_connection = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_xchan = '%s' and abook_channel = %d and not (abook_flags & %d) > 0 order by abook_created desc limit 1", + $new_connection = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 order by abook_created desc limit 1", dbesc($x['hash']), - intval($channel['channel_id']), - intval(ABOOK_FLAG_SELF) + intval($channel['channel_id']) ); if($new_connection) { if($new_perms != $previous_perms) - proc_run('php','include/notifier.php','permission_update',$new_connection[0]['abook_id']); + proc_run('php','include/notifier.php','permission_create',$new_connection[0]['abook_id']); require_once('include/enotify.php'); notification(array( 'type' => NOTIFY_INTRO, @@ -515,7 +515,7 @@ function zot_refresh($them, $channel = null, $force = false) { if($their_perms & PERMS_R_STREAM) { if(($channel['channel_w_stream'] & PERMS_PENDING) - || (! ($new_connection[0]['abook_flags'] & ABOOK_FLAG_PENDING)) ) + || (! intval($new_connection[0]['abook_pending'])) ) proc_run('php','include/onepoll.php',$new_connection[0]['abook_id']); } @@ -571,7 +571,7 @@ function zot_gethub($arr,$multiple = false) { $limit = (($multiple) ? '' : ' limit 1 '); $sitekey = ((array_key_exists('sitekey',$arr) && $arr['sitekey']) ? " and hubloc_sitekey = '" . protect_sprintf($arr['sitekey']) . "' " : ''); - + $r = q("select * from hubloc where hubloc_guid = '%s' and hubloc_guid_sig = '%s' and hubloc_url = '%s' and hubloc_url_sig = '%s' @@ -592,7 +592,7 @@ function zot_gethub($arr,$multiple = false) { } /** - * @brief Registers an unknown hup. + * @brief Registers an unknown hub. * * A communication has been received which has an unknown (to us) sender. * Perform discovery based on our calculated hash of the sender at the @@ -728,43 +728,36 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { $hidden = (1 - intval($arr['searchable'])); - // Be careful - XCHAN_FLAGS_HIDDEN should evaluate to 1 - if(($r[0]['xchan_flags'] & XCHAN_FLAGS_HIDDEN) != $hidden) - $new_flags = $r[0]['xchan_flags'] ^ XCHAN_FLAGS_HIDDEN; - else - $new_flags = $r[0]['xchan_flags']; - - $adult = (($r[0]['xchan_flags'] & XCHAN_FLAGS_SELFCENSORED) ? true : false); - $adult_changed = ((intval($adult) != intval($arr['adult_content'])) ? true : false); - if($adult_changed) - $new_flags = $new_flags ^ XCHAN_FLAGS_SELFCENSORED; - - $deleted = (($r[0]['xchan_flags'] & XCHAN_FLAGS_DELETED) ? true : false); - $deleted_changed = ((intval($deleted) != intval($arr['deleted'])) ? true : false); - 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) + $hidden_changed = $adult_changed = $deleted_changed = $pubforum_changed = 0; + + if(intval($r[0]['xchan_hidden']) != (1 - intval($arr['searchable']))) + $hidden_changed = 1; + if(intval($r[0]['xchan_selfcensored']) != intval($arr['adult_content'])) + $adult_changed = 1; + if(intval($r[0]['xchan_deleted']) != intval($arr['deleted'])) + $deleted_changed = 1; + if(intval($r[0]['xchan_pubforum']) != intval($arr['public_forum'])) + $pubforum_changed = 1; + + if(($r[0]['xchan_name_date'] != $arr['name_updated']) + || ($r[0]['xchan_connurl'] != $arr['connections_url']) || ($r[0]['xchan_addr'] != $arr['address']) || ($r[0]['xchan_follow'] != $arr['follow_url']) - || ($r[0]['xchan_connpage'] != $arr['connect_url']) - || ($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, + || ($r[0]['xchan_connpage'] != $arr['connect_url']) + || ($r[0]['xchan_url'] != $arr['url']) + || $hidden_changed || adult_changed || deleted_changed || $pubforum_changed ) { + $r = q("update xchan set xchan_name = '%s', xchan_name_date = '%s', xchan_connurl = '%s', xchan_follow = '%s', + xchan_connpage = '%s', xchan_hidden = %d, xchan_selfcensored = %d, xchan_deleted = %d, xchan_pubforum = %d, xchan_addr = '%s', xchan_url = '%s' where xchan_hash = '%s'", dbesc(($arr['name']) ? $arr['name'] : '-'), dbesc($arr['name_updated']), dbesc($arr['connections_url']), dbesc($arr['follow_url']), dbesc($arr['connect_url']), - intval($new_flags), + intval(1 - intval($arr['searchable'])), + intval($arr['adult_content']), + intval($arr['deleted']), + intval($arr['public_forum']), dbesc($arr['address']), dbesc($arr['url']), dbesc($xchan_hash) @@ -783,20 +776,9 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { && ($arr['site']['url'] != z_root())) $arr['searchable'] = false; - $hidden = (1 - intval($arr['searchable'])); - - if($hidden) - $new_flags = XCHAN_FLAGS_HIDDEN; - else - $new_flags = 0; - if($arr['adult_content']) - $new_flags |= XCHAN_FLAGS_SELFCENSORED; - if(array_key_exists('deleted',$arr) && $arr['deleted']) - $new_flags |= XCHAN_FLAGS_DELETED; - $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_follow, xchan_connpage, 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', '%s', '%s', %d) ", + xchan_photo_l, xchan_addr, xchan_url, xchan_connurl, xchan_follow, xchan_connpage, xchan_name, xchan_network, xchan_photo_date, xchan_name_date, xchan_hidden, xchan_selfcensored, xchan_deleted, xchan_pubforum ) + values ( '%s', '%s', '%s', '%s' , '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, %d) ", dbesc($xchan_hash), dbesc($arr['guid']), dbesc($arr['guid_sig']), @@ -812,7 +794,10 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { dbesc('zot'), dbescdate($arr['photo_updated']), dbescdate($arr['name_updated']), - intval($new_flags) + intval(1 - intval($arr['searchable'])), + intval($arr['adult_content']), + intval($arr['deleted']), + intval($arr['public_forum']) ); $what .= 'new_xchan'; @@ -831,7 +816,34 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { if ($local) { $ph = z_fetch_url($arr['photo'], true); if ($ph['success']) { - import_channel_photo($ph['body'], $arr['photo_mimetype'], $local[0]['channel_account_id'],$local[0]['channel_id']); + + $hash = import_channel_photo($ph['body'], $arr['photo_mimetype'], $local[0]['channel_account_id'], $local[0]['channel_id']); + + if($hash) { + // unless proven otherwise + $is_default_profile = 1; + + $profile = q("select is_default from profile where aid = %d and uid = %d limit 1", + intval($local[0]['channel_account_id']), + intval($local[0]['channel_id']) + ); + if($profile) { + if(! intval($profile[0]['is_default'])) + $is_default_profile = 0; + } + + // If setting for the default profile, unset the profile photo flag from any other photos I own + if($is_default_profile) { + q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND resource_id != '%s' AND aid = %d AND uid = %d", + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE), + dbesc($hash), + intval($local[0]['channel_account_id']), + intval($local[0]['channel_id']) + ); + } + } + // reset the names in case they got messed up when we had a bug in this function $photos = array( z_root() . '/photo/profile/l/' . $local[0]['channel_id'], @@ -842,7 +854,7 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { ); } } else { - $photos = import_profile_photo($arr['photo'], $xchan_hash); + $photos = import_xchan_photo($arr['photo'], $xchan_hash); } if ($photos) { if ($photos[4]) { @@ -980,9 +992,28 @@ function zot_process_response($hub, $arr, $outq) { logger('zot_process_response: headers: ' . print_r($arr['header'],true), LOGGER_DATA); } + if(is_array($x) && array_key_exists('delivery_report',$x) && is_array($x['delivery_report'])) { + foreach($x['delivery_report'] as $xx) { + if(is_array($xx) && array_key_exists('message_id',$xx) && delivery_report_is_storable($xx)) { + q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_result, dreport_time, dreport_xchan ) values ( '%s', '%s','%s','%s','%s','%s' ) ", + dbesc($xx['message_id']), + dbesc($xx['location']), + dbesc($xx['recipient']), + dbesc($xx['status']), + dbesc(datetime_convert($xx['date'])), + dbesc($xx['sender']) + ); + } + } + } + + q("delete from dreport where dreport_queue = '%s' limit 1", + dbesc($outq['outq_hash']) + ); + // update the timestamp for this site - q("update site set site_update = '%s' where site_url = '%s'", + q("update site set site_dead = 0, site_update = '%s' where site_url = '%s'", dbesc(datetime_convert()), dbesc(dirname($hub)) ); @@ -1150,14 +1181,15 @@ function zot_import($arr, $sender_url) { $recip_arr[] = make_xchan_hash($recip['guid'],$recip['guid_sig']); } } + $r = false; if($recip_arr) { 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 ) > 0 ", - intval(PAGE_REMOVED) - ); + $r = q("select channel_hash as hash from channel where channel_hash in ( " . $recips . " ) + and channel_removed = 0 "); } + if(! $r) { logger('recips: no recipients on this site'); continue; @@ -1235,8 +1267,10 @@ function zot_import($arr, $sender_url) { 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)); + $v = validate_item_elements($i['message'],$arr); + + if(! $v['success']) { + logger('Activity rejected: ' . $v['message'] . ' ' . print_r($i['message'],true)); continue; } @@ -1372,13 +1406,13 @@ function public_recips($msg) { or ( " . $col . " & " . intval(PERMS_PUBLIC) . ") > 0 or ( " . $col . " & " . intval(PERMS_AUTHED) . ") > 0 ) "; } else { - $sql = " where (( " . $col . " & " . intval(PERMS_NETWORK) . " ) > 0 - or ( " . $col . " & " . intval(PERMS_PUBLIC) . ") > 0 - or ( " . $col . " & " . intval(PERMS_AUTHED) . ") > 0 ) "; + $sql = " where ( " . $col . " = " . intval(PERMS_NETWORK) . " + or " . $col . " = " . intval(PERMS_PUBLIC) . " + or " . $col . " = " . intval(PERMS_AUTHED) . " ) "; } $r = q("select channel_hash as hash from channel $sql or channel_hash = '%s' - and ( channel_pageflags & " . intval(PAGE_REMOVED) . " ) = 0 ", + and channel_removed = 0 ", dbesc($msg['notify']['sender']['hash']) ); @@ -1389,10 +1423,10 @@ function public_recips($msg) { // and is allowing this sender at least at a high level. $x = q("select channel_hash as hash from channel left join abook on abook_channel = channel_id - where abook_xchan = '%s' and ( channel_pageflags & " . intval(PAGE_REMOVED) . " ) = 0 - and (( " . $col . " & " . intval(PERMS_SPECIFIC) . " ) > 0 and ( abook_my_perms & " . intval($field) . " ) > 0 ) - OR ( " . $col . " & " . intval(PERMS_PENDING) . " ) > 0 - OR (( " . $col . " & " . intval(PERMS_CONTACTS) . " ) > 0 and ( abook_flags & " . intval(ABOOK_FLAG_PENDING) . " ) = 0 ) ", + where abook_xchan = '%s' and channel_removed = 0 + and (( " . $col . " = " . intval(PERMS_SPECIFIC) . " and ( abook_my_perms & " . intval($field) . " ) > 0 ) + OR " . $col . " = " . intval(PERMS_PENDING) . " + OR ( " . $col . " = " . intval(PERMS_CONTACTS) . " and abook_pending = 0 )) ", dbesc($msg['notify']['sender']['hash']) ); @@ -1421,7 +1455,7 @@ function public_recips($msg) { $address = basename($tag['url']); if($address) { $z = q("select channel_hash as hash from channel where channel_address = '%s' - and ( channel_pageflags & " . intval(PAGE_REMOVED) . " ) = 0 limit 1", + and channel_removed = 0 limit 1", dbesc($address) ); if($z) @@ -1439,8 +1473,7 @@ function public_recips($msg) { if($msg['message']['message_top']) { $z = q("select owner_xchan as hash from item where parent_mid = '%s' ", - dbesc($msg['message']['message_top']), - intval(ITEM_UPLINK) + dbesc($msg['message']['message_top']) ); if($z) $r = array_merge($r,$z); @@ -1525,9 +1558,8 @@ 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 ( channel_pageflags & %d ) = 0 ", - dbesc($hash), - intval(PAGE_REMOVED) + $r = q("select channel_hash as hash from channel left join abook on abook_channel = channel_id where abook_xchan = '%s' and channel_removed = 0 ", + dbesc($hash) ); if($r) { foreach($r as $rr) @@ -1554,7 +1586,6 @@ function allowed_public_recips($msg) { function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $request = false) { $result = array(); - require_once('include/DReport.php'); $result['site'] = z_root(); @@ -1567,7 +1598,6 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $ } } -logger('sender: ' . print_r($sender,true)); foreach($deliveries as $d) { $local_public = $public; @@ -1603,19 +1633,18 @@ logger('sender: ' . print_r($sender,true)); // continue; // } - // allow public postings to the sys channel regardless of permissions, but not // for comments travelling upstream. Wait and catch them on the way down. // They may have been blocked by the owner. - if(($channel['channel_pageflags'] & PAGE_SYSTEM) && (! $arr['item_private']) && (! $relay)) { + if(intval($channel['channel_system']) && (! $arr['item_private']) && (! $relay)) { $local_public = true; - $r = q("select xchan_flags from xchan where xchan_hash = '%s' limit 1", + $r = q("select xchan_selfcensored 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)) { + if($r && (intval($r[0]['xchan_selfcensored']))) { $local_public = false; continue; } @@ -1630,13 +1659,10 @@ logger('sender: ' . print_r($sender,true)); // 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; + $arr['item_wall'] = 1; } else { - // clear the wall flag if it is set - if($arr['item_flags'] & ITEM_WALL) { - $arr['item_flags'] = ($arr['item_flags'] ^ ITEM_WALL); - } + $arr['item_wall'] = 0; } if((! perm_is_allowed($channel['channel_id'],$sender['hash'],$perm)) && (! $tag_delivery) && (! $local_public)) { @@ -1733,7 +1759,7 @@ logger('sender: ' . print_r($sender,true)); ); $abook = (($ab) ? $ab[0] : null); - if($arr['item_restrict'] & ITEM_DELETED) { + if(intval($arr['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']); @@ -1758,17 +1784,19 @@ logger('sender: ' . print_r($sender,true)); continue; } - $r = q("select id, edited, item_restrict, item_flags, mid, parent_mid from item where mid = '%s' and uid = %d limit 1", + $r = q("select * from item where mid = '%s' and uid = %d limit 1", dbesc($arr['mid']), intval($channel['channel_id']) ); if($r) { // We already have this post. $item_id = $r[0]['id']; - if($r[0]['item_restrict'] & ITEM_DELETED) { - // It was deleted locally. + + if(intval($r[0]['item_deleted'])) { + // It was deleted locally. $DR->update('update ignored'); $result[] = $DR->get(); + continue; } // Maybe it has been edited? @@ -1780,7 +1808,7 @@ logger('sender: ' . print_r($sender,true)); $result[] = $DR->get(); } else { - update_imported_item($sender,$arr,$channel['channel_id']); + update_imported_item($sender,$arr,$r[0],$channel['channel_id']); $DR->update('updated'); $result[] = $DR->get(); if(! $relay) @@ -1791,9 +1819,10 @@ logger('sender: ' . print_r($sender,true)); $DR->update('update ignored'); $result[] = $DR->get(); - // We need this line to ensure wall-to-wall comments are relayed (by falling through to the relay bit), - // and at the same time not relay any other relayable posts more than once, because to do so is very wasteful. - if(! ($r[0]['item_flags'] & ITEM_ORIGIN)) + + // We need this line to ensure wall-to-wall comments are relayed (by falling through to the relay bit), + // and at the same time not relay any other relayable posts more than once, because to do so is very wasteful. + if(! intval($r[0]['item_origin'])) continue; } } @@ -1922,9 +1951,20 @@ function remove_community_tag($sender, $arr, $uid) { * @param array $item * @param int $uid (unused) */ -function update_imported_item($sender, $item, $uid) { +function update_imported_item($sender, $item, $orig, $uid) { + $x = item_store_update($item); + + // If we're updating an event that we've saved locally, we store the item info first + // because event_addtocal will parse the body to get the 'new' event details + + if($orig['resource_type'] === 'event') { + $res = event_addtocal($orig['id'],$uid); + if(! $res) + logger('update event: failed'); + } + if(! $x['item_id']) logger('update_imported_item: failed: ' . $x['message']); else @@ -1949,10 +1989,15 @@ function delete_imported_item($sender, $item, $uid, $relay) { $item_found = false; $post_id = 0; - $r = q("select id, item_restrict, author_xchan, owner_xchan, source_xchan from item where mid = '%s' and uid = %d limit 1", + $r = q("select id, author_xchan, owner_xchan, source_xchan, item_deleted from item where ( author_xchan = '%s' or owner_xchan = '%s' or source_xchan = '%s' ) + and mid = '%s' and uid = %d limit 1", + dbesc($sender['hash']), + dbesc($sender['hash']), + dbesc($sender['hash']), dbesc($item['mid']), intval($uid) ); + if ($r) { if ($r[0]['author_xchan'] === $sender['hash'] || $r[0]['owner_xchan'] === $sender['hash'] || $r[0]['source_xchan'] === $sender['hash']) $ownership_valid = true; @@ -1981,8 +2026,10 @@ function delete_imported_item($sender, $item, $uid, $relay) { return false; } + require_once('include/items.php'); + if ($item_found) { - if ($r[0]['item_restrict'] & ITEM_DELETED) { + if (intval($r[0]['item_deleted'])) { logger('delete_imported_item: item was already deleted'); if (! $relay) return false; @@ -1994,9 +2041,8 @@ function delete_imported_item($sender, $item, $uid, $relay) { // back, and we aren't going to (or shouldn't at any rate) delete it again in the future - so losing // this information from the metadata should have no other discernible impact. - if (($r[0]['id'] != $r[0]['parent']) && ($r[0]['item_flags'] & ITEM_ORIGIN)) { - q("update item set item_flags = %d where id = %d and uid = %d", - intval($r[0]['item_flags'] ^ ITEM_ORIGIN), + if (($r[0]['id'] != $r[0]['parent']) && intval($r[0]['item_origin'])) { + q("update item set item_origin = 0 where id = %d and uid = %d", intval($r[0]['id']), intval($r[0]['uid']) ); @@ -2025,20 +2071,26 @@ function process_mail_delivery($sender, $arr, $deliveries) { } foreach($deliveries as $d) { + + $DR = new DReport(z_root(),$sender['hash'],$d['hash'],$arr['mid']); + $r = q("select * from channel where channel_hash = '%s' limit 1", dbesc($d['hash']) ); if(! $r) { - $result[] = array($d['hash'],'not found'); + $DR->update('recipient not found'); + $result[] = $DR->get(); continue; } $channel = $r[0]; + $DR->addto_recipient($channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>'); 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'],$arr['mid']); + $DR->update('permission denied'); + $result[] = $DR->get(); continue; } @@ -2047,16 +2099,18 @@ function process_mail_delivery($sender, $arr, $deliveries) { intval($channel['channel_id']) ); if($r) { - if($arr['mail_flags'] & MAIL_RECALLED) { + if(intval($arr['mail_recalled'])) { $x = q("delete from mail where id = %d and channel_id = %d", intval($r[0]['id']), intval($channel['channel_id']) ); - $result[] = array($d['hash'],'mail recalled',$channel['channel_name'],$arr['mid']); + $DR->update('mail recalled'); + $result[] = $DR->get(); logger('mail_recalled'); } else { - $result[] = array($d['hash'],'duplicate mail received',$channel['channel_name'],$arr['mid']); + $DR->update('duplicate mail received'); + $result[] = $DR->get(); logger('duplicate mail received'); } continue; @@ -2065,7 +2119,8 @@ function process_mail_delivery($sender, $arr, $deliveries) { $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'],$arr['mid']); + $DR->update('mail delivered'); + $result[] = $DR->get(); } } @@ -2257,23 +2312,16 @@ function sync_locations($sender, $arr, $absolute = false) { $current_site = true; } - // If it is the site we're currently talking to, and it's marked offline, - // either we have some bad information - or the thing came back to life. - - if(($current_site) && ($r[0]['hubloc_status'] & HUBLOC_OFFLINE)) { - q("update hubloc set hubloc_status = (hubloc_status & ~%d) where hubloc_id = %d", - intval(HUBLOC_OFFLINE), + if($current_site && intval($r[0]['hubloc_error'])) { + q("update hubloc set hubloc_error = 0 where hubloc_id = %d", 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", - intval(HUBLOC_FLAGS_ORPHANCHECK), + 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_flags = (xchan_flags & ~%d) where (xchan_flags & %d)>0 and xchan_hash = '%s'", - intval(XCHAN_FLAGS_ORPHAN), - intval(XCHAN_FLAGS_ORPHAN), + q("update xchan set xchan_orphan = 0 where xchan_orphan = 1 and xchan_hash = '%s'", dbesc($sender['hash']) ); } @@ -2289,25 +2337,23 @@ function sync_locations($sender, $arr, $absolute = false) { } } - if(($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", - intval(HUBLOC_FLAGS_PRIMARY), + 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_flags'] = $r[0]['hubloc_flags'] ^ HUBLOC_FLAGS_PRIMARY; + $r[0]['hubloc_primary'] = intval($location['primary']); hubloc_change_primary($r[0]); $what .= 'primary_hub '; $changed = true; } - elseif((! ($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", - intval(HUBLOC_FLAGS_PRIMARY), + 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_flags'] = $r[0]['hubloc_flags'] ^ HUBLOC_FLAGS_PRIMARY; + $r[0]['hubloc_primary'] = intval($location['primary']); hubloc_change_primary($r[0]); $what .= 'primary_hub '; $changed = true; @@ -2316,22 +2362,21 @@ function sync_locations($sender, $arr, $absolute = false) { // Absolute sync - make sure the current primary is correctly reflected in the xchan $pr = hubloc_change_primary($r[0]); if($pr) { - $what .= 'xchan_primary'; + $what .= 'xchan_primary '; $changed = true; } } - if(($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", - intval(HUBLOC_FLAGS_DELETED), + 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 .= 'delete_hub '; + $what .= 'undelete_hub '; $changed = true; } - elseif((! ($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", - intval(HUBLOC_FLAGS_DELETED), + 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']) ); @@ -2345,22 +2390,20 @@ 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 )>0", - intval(HUBLOC_FLAGS_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']), - intval(HUBLOC_FLAGS_PRIMARY) + dbesc($sender['hash']) ); } logger('sync_locations: new hub: ' . $location['url']); - $r = q("insert into hubloc ( hubloc_guid, hubloc_guid_sig, hubloc_hash, hubloc_addr, hubloc_network, hubloc_flags, hubloc_url, hubloc_url_sig, hubloc_host, hubloc_callback, hubloc_sitekey, hubloc_updated, hubloc_connected) + $r = q("insert into hubloc ( hubloc_guid, hubloc_guid_sig, hubloc_hash, hubloc_addr, hubloc_network, hubloc_primary, hubloc_url, hubloc_url_sig, hubloc_host, hubloc_callback, hubloc_sitekey, hubloc_updated, hubloc_connected) values ( '%s','%s','%s','%s', '%s', %d ,'%s','%s','%s','%s','%s','%s','%s')", dbesc($sender['guid']), dbesc($sender['guid_sig']), dbesc($sender['hash']), dbesc($location['address']), dbesc('zot'), - intval((intval($location['primary'])) ? HUBLOC_FLAGS_PRIMARY : 0), + intval($location['primary']), dbesc($location['url']), dbesc($location['url_sig']), dbesc($location['host']), @@ -2387,9 +2430,8 @@ function sync_locations($sender, $arr, $absolute = false) { if($absolute && $xisting) { 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", - intval(HUBLOC_FLAGS_DELETED), + logger('sync_locations: 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']) ); @@ -2399,6 +2441,9 @@ function sync_locations($sender, $arr, $absolute = false) { } } } + else { + logger('No locations to sync!'); + } $ret['change_message'] = $what; $ret['changed'] = $changed; @@ -2418,20 +2463,26 @@ function zot_encode_locations($channel) { $ret = array(); $x = zot_get_hublocs($channel['channel_hash']); - if ($x && count($x)) { - foreach ($x as $hub) { - if (! ($hub['hubloc_flags'] & HUBLOC_FLAGS_UNVERIFIED)) { - $ret[] = array( - 'host' => $hub['hubloc_host'], - 'address' => $hub['hubloc_addr'], - 'primary' => (($hub['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY) ? true : false), - 'url' => $hub['hubloc_url'], - 'url_sig' => $hub['hubloc_url_sig'], - 'callback' => $hub['hubloc_callback'], - 'sitekey' => $hub['hubloc_sitekey'], - 'deleted' => (($hub['hubloc_flags'] & HUBLOC_FLAGS_DELETED) ? true : false) - ); - } + + if($x && count($x)) { + foreach($x as $hub) { + + // if this is a local channel that has been deleted, the hubloc is no good - make sure it is marked deleted + // so that nobody tries to use it. + + if(intval($channel['channel_removed']) && $hub['hubloc_url'] === z_root()) + $hub['hubloc_deleted'] = 1; + + $ret[] = array( + 'host' => $hub['hubloc_host'], + 'address' => $hub['hubloc_addr'], + 'primary' => (intval($hub['hubloc_primary']) ? true : false), + 'url' => $hub['hubloc_url'], + 'url_sig' => $hub['hubloc_url_sig'], + 'callback' => $hub['hubloc_callback'], + 'sitekey' => $hub['hubloc_sitekey'], + 'deleted' => (intval($hub['hubloc_deleted']) ? true : false) + ); } } @@ -2487,9 +2538,8 @@ function import_directory_profile($hash, $profile, $addr, $ud_flags = UPDATE_FLA // These are not translated, so the German "erwachsenen" keyword will not censor the directory profile. Only the English form - "adult". - if (in_arrayi('nsfw', $clean) || in_arrayi('adult', $clean)) { - q("update xchan set xchan_flags = (xchan_flags | %d) where xchan_hash = '%s'", - intval(XCHAN_FLAGS_SELFCENSORED), + if(in_arrayi('nsfw',$clean) || in_arrayi('adult',$clean)) { + q("update xchan set xchan_selfcensored = 1 where xchan_hash = '%s'", dbesc($hash) ); } @@ -2751,7 +2801,8 @@ function import_site($arr, $pubkey) { // logger('import_site: input: ' . print_r($arr,true)); // 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', site_project = '%s' + + $r = q("update site set site_dead = 0, site_location = '%s', site_flags = %d, site_access = %d, site_directory = '%s', site_register = %d, site_update = '%s', site_sellpage = '%s', site_realm = '%s', site_type = %d, site_project = '%s' where site_url = '%s'", dbesc($site_location), intval($site_directory), @@ -2761,6 +2812,7 @@ function import_site($arr, $pubkey) { dbesc(datetime_convert()), dbesc($sellpage), dbesc($site_realm), + intval(SITE_TYPE_ZOT), dbesc($site_project), dbesc($url) ); @@ -2770,7 +2822,7 @@ function import_site($arr, $pubkey) { } else { // update the timestamp to indicate we communicated with this site - q("update site set site_update = '%s' where site_url = '%s'", + q("update site set site_dead = 0, site_update = '%s' where site_url = '%s'", dbesc(datetime_convert()), dbesc($url) ); @@ -2778,8 +2830,9 @@ function import_site($arr, $pubkey) { } else { $update = true; - $r = q("insert into site ( site_location, site_url, site_access, site_flags, site_update, site_directory, site_register, site_sellpage, site_realm, site_project ) - values ( '%s', '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s' )", + + $r = q("insert into site ( site_location, site_url, site_access, site_flags, site_update, site_directory, site_register, site_sellpage, site_realm, site_type, site_project ) + values ( '%s', '%s', %d, %d, '%s', '%s', %d, '%s', '%s', %d, '%s' )", dbesc($site_location), dbesc($url), intval($access_policy), @@ -2789,6 +2842,7 @@ function import_site($arr, $pubkey) { intval($register_policy), dbesc($sellpage), dbesc($site_realm), + intval(SITE_TYPE_ZOT), dbesc($site_project) ); if(! $r) { @@ -2831,13 +2885,11 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) { $channel = $r[0]; - if(intval($channel['channel_pageflags']) & PAGE_REMOVED) + if(intval($channel['channel_removed'])) return; - $h = q("select * from hubloc where hubloc_hash = '%s' and not (hubloc_flags & %d) > 0 and not (hubloc_status & %d) > 0", - dbesc($channel['channel_hash']), - intval(HUBLOC_FLAGS_DELETED), - intval(HUBLOC_OFFLINE) + $h = q("select * from hubloc where hubloc_hash = '%s' and hubloc_deleted = 0", + dbesc($channel['channel_hash']) ); if(! $h) @@ -2886,10 +2938,7 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) { // don't pass these elements, they should not be synchronised - if(($k === 'channel_pageflags') && ($v & PAGE_SYSTEM)) - $v = (string) intval($v - PAGE_SYSTEM); - - $disallowed = array('channel_id','channel_account_id','channel_primary','channel_prvkey','channel_address'); + $disallowed = array('channel_id','channel_account_id','channel_primary','channel_prvkey','channel_address','channel_deleted','channel_removed','channel_system'); if(in_array($k,$disallowed)) continue; @@ -2949,6 +2998,8 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) { */ function process_channel_sync_delivery($sender, $arr, $deliveries) { + require_once('include/import.php'); + /** @FIXME this will sync red structures (channel, pconfig and abook). Eventually we need to make this application agnostic. */ $result = array(); @@ -2981,17 +3032,55 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { } } + if(array_key_exists('obj',$arr) && $arr['obj']) + sync_objs($channel,$arr['obj']); + + if(array_key_exists('likes',$arr) && $arr['likes']) + import_likes($channel,$arr['likes']); + + if(array_key_exists('app',$arr) && $arr['app']) + sync_apps($channel,$arr['app']); + + if(array_key_exists('chatroom',$arr) && $arr['chatroom']) + sync_chatrooms($channel,$arr['chatroom']); + + if(array_key_exists('conv',$arr) && $arr['conv']) + import_conv($channel,$arr['conv']); + + if(array_key_exists('mail',$arr) && $arr['mail']) + import_mail($channel,$arr['mail']); + + if(array_key_exists('event',$arr) && $arr['event']) + sync_events($channel,$arr['event']); + + if(array_key_exists('event_item',$arr) && $arr['event_item']) + sync_items($channel,$arr['event_item']); + + if(array_key_exists('item',$arr) && $arr['item']) + sync_items($channel,$arr['item']); + + if(array_key_exists('item_id',$arr) && $arr['item_id']) + sync_items($channel,$arr['item_id']); + + if(array_key_exists('menu',$arr) && $arr['menu']) + sync_menus($channel,$arr['menu']); + if(array_key_exists('channel',$arr) && is_array($arr['channel']) && count($arr['channel'])) { - // These flags cannot be sync'd. - // If these bits aren't set locally, remove the bits from the incoming flags. + if(array_key_exists('channel_pageflags',$arr['channel']) && intval($arr['channel']['channel_pageflags'])) { + // These flags cannot be sync'd. + // remove the bits from the incoming flags. - if((! ($channel['channel_pageflags'] & PAGE_REMOVED)) && ($arr['channel']['channel_pageflags'] & PAGE_REMOVED)) - $arr['channel']['channel_pageflags'] = $arr['channel']['channel_pageflags'] - PAGE_REMOVED; - if((! ($channel['channel_pageflags'] & PAGE_SYSTEM)) && ($arr['channel']['channel_pageflags'] & PAGE_SYSTEM)) - $arr['channel']['channel_pageflags'] = $arr['channel']['channel_pageflags'] - PAGE_SYSTEM; + // These correspond to PAGE_REMOVED and PAGE_SYSTEM on redmatrix - $disallowed = array('channel_id','channel_account_id','channel_primary','channel_prvkey', 'channel_address', 'channel_notifyflags', 'channel_removed', 'channel_system', 'channel_deleted' ); + if($arr['channel']['channel_pageflags'] & 0x8000) + $arr['channel']['channel_pageflags'] = $arr['channel']['channel_pageflags'] - 0x8000; + if($arr['channel']['channel_pageflags'] & 0x1000) + $arr['channel']['channel_pageflags'] = $arr['channel']['channel_pageflags'] - 0x1000; + + } + + $disallowed = array('channel_id','channel_account_id','channel_primary','channel_prvkey', 'channel_address', 'channel_notifyflags', 'channel_removed', 'channel_deleted', 'channel_system'); $clean = array(); foreach($arr['channel'] as $k => $v) { @@ -3011,43 +3100,32 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { $total_friends = 0; $total_feeds = 0; - $r = q("select abook_id, abook_flags from abook where abook_channel = %d", + $r = q("select abook_id, abook_feed from abook where abook_channel = %d", intval($channel['channel_id']) ); if($r) { // don't count yourself $total_friends = ((count($r) > 0) ? count($r) - 1 : 0); foreach($r as $rr) - if($rr['abook_flags'] & ABOOK_FLAG_FEED) + if(intval($rr['abook_feed'])) $total_feeds ++; } - $disallowed = array('abook_id','abook_account','abook_channel','abook_blocked','abook_ignored','abook_hidden','abook_archived','abook_pending','abook_unconnected','abook_self','abook_feed'); - foreach($arr['abook'] as $abook) { + $disallowed = array('abook_id','abook_account','abook_channel','abook_rating','abook_rating_text'); - if(array_key_exists('abook_blocked',$abook)) { - - // convert from hubzilla - - $abook['abook_flags'] = 0; - if(intval($abook['abook_blocked'])) - $abook['abook_flags'] |= ABOOK_FLAG_BLOCKED; - if(intval($abook['abook_ignored'])) - $abook['abook_flags'] |= ABOOK_FLAG_IGNORED; - if(intval($abook['abook_hidden'])) - $abook['abook_flags'] |= ABOOK_FLAG_HIDDEN; - if(intval($abook['abook_archived'])) - $abook['abook_flags'] |= ABOOK_FLAG_ARCHIVED; - if(intval($abook['abook_pending'])) - $abook['abook_flags'] |= ABOOK_FLAG_PENDING; - if(intval($abook['abook_unconnected'])) - $abook['abook_flags'] |= ABOOK_FLAG_UNCONNECTED; - if(intval($abook['abook_self'])) - $abook['abook_flags'] |= ABOOK_FLAG_SELF; - if(intval($abook['abook_feed'])) - $abook['abook_flags'] |= ABOOK_FLAG_FEED; + foreach($arr['abook'] as $abook) { + if(! array_key_exists('abook_blocked',$abook)) { + // convert from redmatrix + $abook['abook_blocked'] = (($abook['abook_flags'] & 0x0001) ? 1 : 0); + $abook['abook_ignored'] = (($abook['abook_flags'] & 0x0002) ? 1 : 0); + $abook['abook_hidden'] = (($abook['abook_flags'] & 0x0004) ? 1 : 0); + $abook['abook_archived'] = (($abook['abook_flags'] & 0x0008) ? 1 : 0); + $abook['abook_pending'] = (($abook['abook_flags'] & 0x0010) ? 1 : 0); + $abook['abook_unconnected'] = (($abook['abook_flags'] & 0x0020) ? 1 : 0); + $abook['abook_self'] = (($abook['abook_flags'] & 0x0080) ? 1 : 0); + $abook['abook_feed'] = (($abook['abook_flags'] & 0x0100) ? 1 : 0); } $clean = array(); @@ -3055,16 +3133,15 @@ 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 )>0 limit 1", + $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']), - intval(ABOOK_FLAG_SELF) + intval($channel['channel_id']) ); if($r) { contact_remove($channel['channel_id'],$r[0]['abook_id']); if($total_friends) $total_friends --; - if($r[0]['abook_flags'] & ABOOK_FLAG_FEED) + if(intval($r[0]['abook_feed'])) $total_feeds --; } continue; @@ -3106,7 +3183,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { logger('process_channel_sync_delivery: total_channels service class limit exceeded'); continue; } - if($max_feeds !== false && ($clean['abook_flags'] & ABOOK_FLAG_FEED) && $total_feeds > $max_feeds) { + if($max_feeds !== false && intval($clean['abook_feed']) && $total_feeds > $max_feeds) { logger('process_channel_sync_delivery: total_feeds service class limit exceeded'); continue; } @@ -3115,7 +3192,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { intval($channel['channel_id']) ); $total_friends ++; - if($clean['abook_flags'] & ABOOK_FLAG_FEED) + if(intval($clean['abook_feed'])) $total_feeds ++; } @@ -3127,6 +3204,9 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { . "' where abook_xchan = '" . dbesc($clean['abook_xchan']) . "' and abook_channel = " . intval($channel['channel_id'])); } } + + + } } @@ -3319,6 +3399,8 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { if(array_key_exists('item_id',$arr) && $arr['item_id']) sync_items($channel,$arr['item_id']); + $addon = array('channel' => $channel,'data' => $arr); + call_hooks('process_channel_sync_delivery',$addon); // we should probably do this for all items, but usually we only send one. @@ -3363,11 +3445,11 @@ function get_rpost_path($observer) { * @return boolean|string return false or a hash */ 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)>0 limit 1", + + $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_primary = 1 limit 1", dbesc($x['guid']), - dbesc($x['guid_sig']), - intval(HUBLOC_FLAGS_PRIMARY) + dbesc($x['guid_sig']) ); if ($r) { @@ -3437,12 +3519,9 @@ function zot_process_message_request($data) { 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 ", - dbesc($sender_hash), - intval(HUBLOC_FLAGS_DELETED), - intval(HUBLOC_OFFLINE) + $r = q("select * from hubloc where hubloc_hash = '%s' and not hubloc_error and not hubloc_deleted + group by hubloc_sitekey", + dbesc($sender_hash) ); if (! $r) { logger('no hubs'); @@ -3492,78 +3571,401 @@ function zot_process_message_request($data) { } +function zotinfo($arr) { -function import_items($channel,$items) { + $ret = array('success' => false); - if($channel && $items) { - $allow_code = false; - $r = q("select account_id, account_roles, channel_pageflags from account left join channel on channel_account_id = account_id - where channel_id = %d limit 1", - intval($channel['channel_id']) - ); - if($r) { - if(($r[0]['account_roles'] & ACCOUNT_ROLE_ALLOWCODE) || ($r[0]['channel_pageflags'] & PAGE_ALLOWCODE)) { - $allow_code = true; - } + $zhash = ((x($arr,'guid_hash')) ? $arr['guid_hash'] : ''); + $zguid = ((x($arr,'guid')) ? $arr['guid'] : ''); + $zguid_sig = ((x($arr,'guid_sig')) ? $arr['guid_sig'] : ''); + $zaddr = ((x($arr,'address')) ? $arr['address'] : ''); + $ztarget = ((x($arr,'target')) ? $arr['target'] : ''); + $zsig = ((x($arr,'target_sig')) ? $arr['target_sig'] : ''); + $zkey = ((x($arr,'key')) ? $arr['key'] : ''); + $mindate = ((x($arr,'mindate')) ? $arr['mindate'] : ''); + $feed = ((x($arr,'feed')) ? intval($arr['feed']) : 0); + + if($ztarget) { + if((! $zkey) || (! $zsig) || (! rsa_verify($ztarget,base64url_decode($zsig),$zkey))) { + logger('zfinger: invalid target signature'); + $ret['message'] = t("invalid target signature"); + return($ret); } + } - foreach($items as $i) { - $item = get_item_elements($i,$allow_code); - if(! $item) - continue; + $r = null; - $r = q("select id, edited from item where mid = '%s' and uid = %d limit 1", - dbesc($item['mid']), - intval($channel['channel_id']) + if(strlen($zhash)) { + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + where channel_hash = '%s' limit 1", + dbesc($zhash) + ); + } + elseif(strlen($zguid) && strlen($zguid_sig)) { + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + where channel_guid = '%s' and channel_guid_sig = '%s' limit 1", + dbesc($zguid), + dbesc($zguid_sig) + ); + } + elseif(strlen($zaddr)) { + if(strpos($zaddr,'[system]') === false) { /* normal address lookup */ + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + where ( channel_address = '%s' or xchan_addr = '%s' ) limit 1", + dbesc($zaddr), + dbesc($zaddr) ); - if($r) { - if($item['edited'] > $r[0]['edited']) { - $item['id'] = $r[0]['id']; - $item['uid'] = $channel['channel_id']; - item_store_update($item); - continue; - } + } + + else { + + /** + * The special address '[system]' will return a system channel if one has been defined, + * Or the first valid channel we find if there are no system channels. + * + * This is used by magic-auth if we have no prior communications with this site - and + * returns an identity on this site which we can use to create a valid hub record so that + * we can exchange signed messages. The precise identity is irrelevant. It's the hub + * information that we really need at the other end - and this will return it. + * + */ + + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + where channel_system = 1 order by channel_id limit 1"); + if(! $r) { + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + where channel_removed = 0 order by channel_id limit 1"); } - else { - $item['aid'] = $channel['channel_account_id']; - $item['uid'] = $channel['channel_id']; - $item_result = item_store($item); + } + } + else { + $ret['message'] = 'Invalid request'; + return($ret); + } + + if(! $r) { + $ret['message'] = 'Item not found.'; + return($ret); + } + + $e = $r[0]; + + $id = $e['channel_id']; + + $sys_channel = (intval($e['channel_system']) ? true : false); + $special_channel = (($e['channel_pageflags'] & PAGE_PREMIUM) ? true : false); + $adult_channel = (($e['channel_pageflags'] & PAGE_ADULT) ? true : false); + $censored = (($e['channel_pageflags'] & PAGE_CENSORED) ? true : false); + $searchable = (($e['channel_pageflags'] & PAGE_HIDDEN) ? false : true); + $deleted = (intval($e['xchan_deleted']) ? true : false); + + if($deleted || $censored || $sys_channel) + $searchable = false; + + $public_forum = false; + + $role = get_pconfig($e['channel_id'],'system','permissions_role'); + if($role === 'forum' || $role === 'repository') { + $public_forum = true; + } + else { + // check if it has characteristics of a public forum based on custom permissions. + $t = q("select abook_my_perms from abook where abook_channel = %d and abook_self = 1 limit 1", + intval($e['channel_id']) + ); + if(($t) && (($t[0]['abook_my_perms'] & PERMS_W_TAGWALL) && (! ($t[0]['abook_my_perms'] & PERMS_W_STREAM)))) + $public_forum = true; + } + + + // This is for birthdays and keywords, but must check access permissions + $p = q("select * from profile where uid = %d and is_default = 1", + intval($e['channel_id']) + ); + + $profile = array(); + + if($p) { + + if(! intval($p[0]['publish'])) + $searchable = false; + + $profile['description'] = $p[0]['pdesc']; + $profile['birthday'] = $p[0]['dob']; + if(($profile['birthday'] != '0000-00-00') && (($bd = z_birthday($p[0]['dob'],$e['channel_timezone'])) !== '')) + $profile['next_birthday'] = $bd; + + if($age = age($p[0]['dob'],$e['channel_timezone'],'')) + $profile['age'] = $age; + $profile['gender'] = $p[0]['gender']; + $profile['marital'] = $p[0]['marital']; + $profile['sexual'] = $p[0]['sexual']; + $profile['locale'] = $p[0]['locality']; + $profile['region'] = $p[0]['region']; + $profile['postcode'] = $p[0]['postal_code']; + $profile['country'] = $p[0]['country_name']; + $profile['about'] = $p[0]['about']; + $profile['homepage'] = $p[0]['homepage']; + $profile['hometown'] = $p[0]['hometown']; + + if($p[0]['keywords']) { + $tags = array(); + $k = explode(' ',$p[0]['keywords']); + if($k) { + foreach($k as $kk) { + if(trim($kk," \t\n\r\0\x0B,")) { + $tags[] = trim($kk," \t\n\r\0\x0B,"); + } + } } + if($tags) + $profile['keywords'] = $tags; + } + } + + $ret['success'] = true; + + // Communication details + + $ret['guid'] = $e['xchan_guid']; + $ret['guid_sig'] = $e['xchan_guid_sig']; + $ret['key'] = $e['xchan_pubkey']; + $ret['name'] = $e['xchan_name']; + $ret['name_updated'] = $e['xchan_name_date']; + $ret['address'] = $e['xchan_addr']; + $ret['photo_mimetype'] = $e['xchan_photo_mimetype']; + $ret['photo'] = $e['xchan_photo_l']; + $ret['photo_updated'] = $e['xchan_photo_date']; + $ret['url'] = $e['xchan_url']; + $ret['connections_url']= (($e['xchan_connurl']) ? $e['xchan_connurl'] : z_root() . '/poco/' . $e['channel_address']); + $ret['target'] = $ztarget; + $ret['target_sig'] = $zsig; + $ret['searchable'] = $searchable; + $ret['adult_content'] = $adult_channel; + $ret['public_forum'] = $public_forum; + if($deleted) + $ret['deleted'] = $deleted; + if(intval($e['channel_removed'])) + $ret['deleted_locally'] = true; + + // premium or other channel desiring some contact with potential followers before connecting. + // This is a template - %s will be replaced with the follow_url we discover for the return channel. + + if($special_channel) + $ret['connect_url'] = z_root() . '/connect/' . $e['channel_address']; + + // This is a template for our follow url, %s will be replaced with a webbie + + $ret['follow_url'] = z_root() . '/follow?f=&url=%s'; + + $ztarget_hash = (($ztarget && $zsig) + ? make_xchan_hash($ztarget,$zsig) + : '' ); + + $permissions = get_all_perms($e['channel_id'],$ztarget_hash,false); + + if($ztarget_hash) { + $permissions['connected'] = false; + $b = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1", + dbesc($ztarget_hash), + intval($e['channel_id']) + ); + if($b) + $permissions['connected'] = true; + } + + $ret['permissions'] = (($ztarget && $zkey) ? crypto_encapsulate(json_encode($permissions),$zkey) : $permissions); + + if($permissions['view_profile']) + $ret['profile'] = $profile; + + // array of (verified) hubs this channel uses + + $x = zot_encode_locations($e); + if($x) + $ret['locations'] = $x; + + $ret['site'] = array(); + $ret['site']['url'] = z_root(); + $ret['site']['url_sig'] = base64url_encode(rsa_sign(z_root(),$e['channel_prvkey'])); + + $dirmode = get_config('system','directory_mode'); + if(($dirmode === false) || ($dirmode == DIRECTORY_MODE_NORMAL)) + $ret['site']['directory_mode'] = 'normal'; + + if($dirmode == DIRECTORY_MODE_PRIMARY) + $ret['site']['directory_mode'] = 'primary'; + elseif($dirmode == DIRECTORY_MODE_SECONDARY) + $ret['site']['directory_mode'] = 'secondary'; + elseif($dirmode == DIRECTORY_MODE_STANDALONE) + $ret['site']['directory_mode'] = 'standalone'; + if($dirmode != DIRECTORY_MODE_NORMAL) + $ret['site']['directory_url'] = z_root() . '/dirsearch'; + + + // hide detailed site information if you're off the grid + + if($dirmode != DIRECTORY_MODE_STANDALONE) { + + $register_policy = intval(get_config('system','register_policy')); + + if($register_policy == REGISTER_CLOSED) + $ret['site']['register_policy'] = 'closed'; + if($register_policy == REGISTER_APPROVE) + $ret['site']['register_policy'] = 'approve'; + if($register_policy == REGISTER_OPEN) + $ret['site']['register_policy'] = 'open'; + + + $access_policy = intval(get_config('system','access_policy')); + if($access_policy == ACCESS_PRIVATE) + $ret['site']['access_policy'] = 'private'; + if($access_policy == ACCESS_PAID) + $ret['site']['access_policy'] = 'paid'; + if($access_policy == ACCESS_FREE) + $ret['site']['access_policy'] = 'free'; + if($access_policy == ACCESS_TIERED) + $ret['site']['access_policy'] = 'tiered'; + + $ret['site']['accounts'] = account_total(); + + require_once('include/identity.php'); + $ret['site']['channels'] = channel_total(); + + + $ret['site']['version'] = PLATFORM_NAME . ' ' . RED_VERSION . '[' . DB_UPDATE_VERSION . ']'; + + $ret['site']['admin'] = get_config('system','admin_email'); + + $a = get_app(); + + $visible_plugins = array(); + if(is_array($a->plugins) && count($a->plugins)) { + $r = q("select * from addon where hidden = 0"); + if($r) + foreach($r as $rr) + $visible_plugins[] = $rr['name']; } + + $ret['site']['plugins'] = $visible_plugins; + $ret['site']['sitehash'] = get_config('system','location_hash'); + $ret['site']['sitename'] = get_config('system','sitename'); + $ret['site']['sellpage'] = get_config('system','sellpage'); + $ret['site']['location'] = get_config('system','site_location'); + $ret['site']['realm'] = get_directory_realm(); + $ret['site']['project'] = PLATFORM_NAME; + } -} + check_zotinfo($e,$x,$ret); + + + call_hooks('zot_finger',$ret); + return($ret); -function sync_items($channel,$items) { - import_items($channel,$items); } +function check_zotinfo($channel,$locations,&$ret) { -function import_item_ids($channel,$itemids) { - if($channel && $itemids) { - foreach($itemids as $i) { - $r = q("select id from item where mid = '%s' and uid = %d limit 1", - dbesc($i['mid']), - intval($channel['channel_id']) + +// logger('locations: ' . print_r($locations,true),LOGGER_DATA); + + // This function will likely expand as we find more things to detect and fix. + // 1. Because magic-auth is reliant on it, ensure that the system channel has a valid hubloc + // Force this to be the case if anything is found to be wrong with it. + + // @FIXME ensure that the system channel exists in the first place and has an xchan + + if($channel['channel_system']) { + // the sys channel must have a location (hubloc) + $valid_location = false; + if((count($locations) === 1) && ($locations[0]['primary']) && (! $locations[0]['deleted'])) { + if((rsa_verify($locations[0]['url'],base64url_decode($locations[0]['url_sig']),$channel['channel_pubkey'])) + && ($locations[0]['sitekey'] === get_config('system','pubkey')) + && ($locations[0]['url'] === z_root())) + $valid_location = true; + else + logger('sys channel: invalid url signature'); + } + + if((! $locations) || (! $valid_location)) { + + logger('System channel locations are not valid. Attempting repair.'); + + // Don't trust any existing records. Just get rid of them, but only do this + // for the sys channel as normal channels will be trickier. + + q("delete from hubloc where hubloc_hash = '%s'", + dbesc($channel['channel_hash']) ); - if(! $r) - continue; - $z = q("select * from item_id where service = '%s' and sid = '%s' and iid = %d and uid = %d limit 1", - dbesc($i['service']), - dbesc($i['sid']), - intval($r[0]['id']), - intval($channel['channel_id']) + $r = q("insert into hubloc ( hubloc_guid, hubloc_guid_sig, hubloc_hash, hubloc_addr, hubloc_primary, + hubloc_url, hubloc_url_sig, hubloc_host, hubloc_callback, hubloc_sitekey, hubloc_network ) + values ( '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s' )", + dbesc($channel['channel_guid']), + dbesc($channel['channel_guid_sig']), + dbesc($channel['channel_hash']), + dbesc($channel['channel_address'] . '@' . get_app()->get_hostname()), + intval(1), + dbesc(z_root()), + dbesc(base64url_encode(rsa_sign(z_root(),$channel['channel_prvkey']))), + dbesc(get_app()->get_hostname()), + dbesc(z_root() . '/post'), + dbesc(get_config('system','pubkey')), + dbesc('zot') ); - if(! $z) { - q("insert into item_id (iid,uid,sid,service) values(%d,%d,'%s','%s')", - intval($r[0]['id']), - intval($channel['channel_id']), - dbesc($i['sid']), - dbesc($i['service']) - ); + if($r) { + $x = zot_encode_locations($channel); + if($x) { + $ret['locations'] = $x; + } + } + else { + logger('Unable to store sys hub location'); } } } } + +function delivery_report_is_storable($dr) { + + call_hooks('dreport_is_storable',$dr); + + // let plugins accept or reject - if neither, continue on + if(array_key_exists('accept',$dr) && intval($dr['accept'])) + return true; + if(array_key_exists('reject',$dr) && intval($dr['reject'])) + return false; + + if(! ($dr['sender'])) + return false; + + // Is the sender one of our channels? + + $c = q("select channel_id from channel where channel_hash = '%s' limit 1", + dbesc($dr['sender']) + ); + if(! $c) + return false; + + // is the recipient one of our connections, or do we want to store every report? + + $r = explode(' ', $dr['recipient']); + $rxchan = $r[0]; + $pcf = get_pconfig($c[0]['channel_id'],'system','dreport_store_all'); + if($pcf) + return true; + + $r = q("select abook_id from abook where abook_xchan = '%s' and abook_channel = %d limit 1", + dbesc($rxchan), + intval($c[0]['channel_id']) + ); + if($r) + return true; + + return false; + +} + + |