diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/ItemObject.php | 1 | ||||
-rw-r--r-- | include/account.php | 23 | ||||
-rw-r--r-- | include/bb2diaspora.php | 11 | ||||
-rw-r--r-- | include/chat.php | 11 | ||||
-rw-r--r-- | include/conversation.php | 199 | ||||
-rwxr-xr-x | include/diaspora.php | 74 | ||||
-rw-r--r-- | include/follow.php | 15 | ||||
-rw-r--r-- | include/hubloc.php | 73 | ||||
-rw-r--r-- | include/identity.php | 101 | ||||
-rwxr-xr-x | include/items.php | 63 | ||||
-rw-r--r-- | include/js_strings.php | 1 | ||||
-rw-r--r-- | include/menu.php | 10 | ||||
-rw-r--r-- | include/nav.php | 15 | ||||
-rw-r--r-- | include/network.php | 32 | ||||
-rw-r--r-- | include/notifier.php | 37 | ||||
-rw-r--r-- | include/onepoll.php | 2 | ||||
-rw-r--r-- | include/permissions.php | 290 | ||||
-rw-r--r-- | include/photos.php | 1 | ||||
-rw-r--r-- | include/poller.php | 3 | ||||
-rw-r--r-- | include/security.php | 13 | ||||
-rw-r--r-- | include/widgets.php | 10 | ||||
-rw-r--r-- | include/zot.php | 467 |
22 files changed, 1084 insertions, 368 deletions
diff --git a/include/ItemObject.php b/include/ItemObject.php index 451e369b0..96abe4df6 100644 --- a/include/ItemObject.php +++ b/include/ItemObject.php @@ -250,6 +250,7 @@ class Item extends BaseObject { 'osparkle' => $osparkle, 'sparkle' => $sparkle, 'title' => $item['title'], + 'title_tosource' => get_pconfig($conv->get_profile_owner(),'system','title_tosource'), 'ago' => relative_date($item['created']), 'app' => $item['app'], 'str_app' => sprintf( t(' from %s'), $item['app']), diff --git a/include/account.php b/include/account.php index a3d6ef025..df484e608 100644 --- a/include/account.php +++ b/include/account.php @@ -616,6 +616,29 @@ function service_class_fetch($uid,$property) { return((array_key_exists($property,$arr)) ? $arr[$property] : false); } +// like service_class_fetch but queries by account rather than channel + +function account_service_class_fetch($aid,$property) { + + $r = q("select account_service_class as service_class from account where account_id = %d limit 1", + intval($aid) + ); + if($r !== false && count($r)) { + $service_class = $r[0]['service_class']; + } + + if(! x($service_class)) + return false; // everything is allowed + + $arr = get_config('service_class',$service_class); + + if(! is_array($arr) || (! count($arr))) + return false; + + return((array_key_exists($property,$arr)) ? $arr[$property] : false); +} + + function upgrade_link($bbcode = false) { $l = get_config('service_class','upgrade_link'); if(! $l) diff --git a/include/bb2diaspora.php b/include/bb2diaspora.php index 9c884926a..e60f72add 100644 --- a/include/bb2diaspora.php +++ b/include/bb2diaspora.php @@ -266,11 +266,15 @@ function bb2dmention_callback($match) { function bb2diaspora_itemwallwall(&$item) { if(($item['mid'] == $item['parent_mid']) && ($item['author_xchan'] != $item['owner_xchan']) && (is_array($item['author']))) { + logger('bb2diaspora_itemwallwall: author: ' . print_r($item['author'],true), LOGGER_DEBUG); + } + + if(($item['mid'] == $item['parent_mid']) && ($item['author_xchan'] != $item['owner_xchan']) && (is_array($item['author'])) && $item['author']['xchan_url'] && $item['author']['xchan_name'] && $item['author']['xchan_photo_m']) { logger('bb2diaspora_itemwallwall: wall to wall post',LOGGER_DEBUG); // post will come across with the owner's identity. Throw a preamble onto the post to indicate the true author. $item['body'] = "\n\n" - . '[img]' . $item['author']['photo']['src'] . '[/img]' - . '[url=' . $item['author']['url'] . ']' . $item['author']['name'] . '[/url]' . "\n\n" + . '[img]' . $item['author']['xchan_photo_m'] . '[/img]' + . '[url=' . $item['author']['xchan_url'] . ']' . $item['author']['xchan_name'] . '[/url]' . "\n\n" . $item['body']; } } @@ -292,7 +296,8 @@ function bb2diaspora_itembody($item) { logger('bb2diaspora_itembody: cached '); $newitem = $item; $newitem['body'] = $meta['body']; - bb2diaspora_itemwallwall($newitem); +// this won't work - the post is now in markdown +// bb2diaspora_itemwallwall($newitem); return $newitem['body']; } } diff --git a/include/chat.php b/include/chat.php index b8fb185df..5c3d0c9d9 100644 --- a/include/chat.php +++ b/include/chat.php @@ -189,6 +189,17 @@ function chatroom_list($uid) { return $r; } +function chatroom_list_count($uid) { + require_once('include/security.php'); + $sql_extra = permissions_sql($uid); + + $r = q("select count(*) as total from chatroom where cr_uid = %d $sql_extra", + intval($uid) + ); + + return $r[0]['total']; +} + /** * create a chat message via API. * It is the caller's responsibility to enter the room. diff --git a/include/conversation.php b/include/conversation.php index 05ae72d61..b0a388a68 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -440,7 +440,6 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ for($x = 0; $x < count($arr_blocked); $x ++) $arr_blocked[$x] = trim($arr_blocked[$x]); } - } @@ -458,59 +457,53 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ $profile_owner = local_user(); $page_writeable = true; - if(!$update) { - // The special div is needed for liveUpdate to kick in for this page. - // We only launch liveUpdate if you aren't filtering in some incompatible - // way and also you aren't writing a comment (discovered in javascript). - - $live_update_div = '<div id="live-network"></div>' . "\r\n" - . "<script> var profile_uid = " . $_SESSION['uid'] - . "; var netargs = '" . substr($a->cmd,8) - . '?f=' - . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : '') - . ((x($_GET,'search')) ? '&search=' . $_GET['search'] : '') - . ((x($_GET,'star')) ? '&star=' . $_GET['star'] : '') - . ((x($_GET,'order')) ? '&order=' . $_GET['order'] : '') - . ((x($_GET,'bmark')) ? '&bmark=' . $_GET['bmark'] : '') - . ((x($_GET,'liked')) ? '&liked=' . $_GET['liked'] : '') - . ((x($_GET,'conv')) ? '&conv=' . $_GET['conv'] : '') - . ((x($_GET,'spam')) ? '&spam=' . $_GET['spam'] : '') - . ((x($_GET,'nets')) ? '&nets=' . $_GET['nets'] : '') - . ((x($_GET,'cmin')) ? '&cmin=' . $_GET['cmin'] : '') - . ((x($_GET,'cmax')) ? '&cmax=' . $_GET['cmax'] : '') - . ((x($_GET,'file')) ? '&file=' . $_GET['file'] : '') - . ((x($_GET,'uri')) ? '&uri=' . $_GET['uri'] : '') - - . "'; var profile_page = " . $a->pager['page'] . "; </script>\r\n"; - } - - + if(!$update) { + // The special div is needed for liveUpdate to kick in for this page. + // We only launch liveUpdate if you aren't filtering in some incompatible + // way and also you aren't writing a comment (discovered in javascript). + + $live_update_div = '<div id="live-network"></div>' . "\r\n" + . "<script> var profile_uid = " . $_SESSION['uid'] + . "; var netargs = '" . substr($a->cmd,8) + . '?f=' + . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : '') + . ((x($_GET,'search')) ? '&search=' . $_GET['search'] : '') + . ((x($_GET,'star')) ? '&star=' . $_GET['star'] : '') + . ((x($_GET,'order')) ? '&order=' . $_GET['order'] : '') + . ((x($_GET,'bmark')) ? '&bmark=' . $_GET['bmark'] : '') + . ((x($_GET,'liked')) ? '&liked=' . $_GET['liked'] : '') + . ((x($_GET,'conv')) ? '&conv=' . $_GET['conv'] : '') + . ((x($_GET,'spam')) ? '&spam=' . $_GET['spam'] : '') + . ((x($_GET,'nets')) ? '&nets=' . $_GET['nets'] : '') + . ((x($_GET,'cmin')) ? '&cmin=' . $_GET['cmin'] : '') + . ((x($_GET,'cmax')) ? '&cmax=' . $_GET['cmax'] : '') + . ((x($_GET,'file')) ? '&file=' . $_GET['file'] : '') + . ((x($_GET,'uri')) ? '&uri=' . $_GET['uri'] : '') + . "'; var profile_page = " . $a->pager['page'] . "; </script>\r\n"; + } } elseif($mode === 'channel') { $profile_owner = $a->profile['profile_uid']; $page_writeable = ($profile_owner == local_user()); - if(!$update) { - $tab = notags(trim($_GET['tab'])); - if($tab === 'posts') { - // This is ugly, but we can't pass the profile_uid through the session to the ajax updater, - // because browser prefetching might change it on us. We have to deliver it with the page. - - $live_update_div = '<div id="live-channel"></div>' . "\r\n" - . "<script> var profile_uid = " . $a->profile['profile_uid'] - . "; var netargs = '?f='; var profile_page = " . $a->pager['page'] . "; </script>\r\n"; - } - } + if(!$update) { + $tab = notags(trim($_GET['tab'])); + if($tab === 'posts') { + // This is ugly, but we can't pass the profile_uid through the session to the ajax updater, + // because browser prefetching might change it on us. We have to deliver it with the page. + $live_update_div = '<div id="live-channel"></div>' . "\r\n" + . "<script> var profile_uid = " . $a->profile['profile_uid'] + . "; var netargs = '?f='; var profile_page = " . $a->pager['page'] . "; </script>\r\n"; + } + } } elseif($mode === 'display') { $profile_owner = local_user(); $page_writeable = false; - - $live_update_div = '<div id="live-display"></div>' . "\r\n"; - + $live_update_div = '<div id="live-display"></div>' . "\r\n"; } elseif($mode === 'page') { @@ -519,10 +512,10 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ $live_update_div = '<div id="live-page"></div>' . "\r\n"; } + elseif($mode === 'search') { + $live_update_div = '<div id="live-search"></div>' . "\r\n"; + } - elseif($mode === 'search') { - $live_update_div = '<div id="live-search"></div>' . "\r\n"; - } elseif($mode === 'photos') { $profile_onwer = $a->profile['profile_uid']; $page_writeable = ($profile_owner == local_user()); @@ -555,7 +548,6 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ $alike = array(); $dlike = array(); - // array with html for each thread (parent+comments) $threads = array(); $threadsid = -1; @@ -603,12 +595,11 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ } else $nickname = $a->user['nickname']; - + $profile_name = ((strlen($item['author-name'])) ? $item['author-name'] : $item['name']); if($item['author-link'] && (! $item['author-name'])) $profile_name = $item['author-link']; - $tags=array(); $hashtags = array(); @@ -631,7 +622,6 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ $profile_link = $item['author']['xchan_url']; $profile_avatar = $item['author']['xchan_photo_m']; - $location = format_location($item); localize_item($item); @@ -663,7 +653,6 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ $unverified = ''; - $tags=array(); $terms = get_terms_oftype($item['term'],array(TERM_HASHTAG,TERM_MENTION,TERM_UNKNOWN)); if(count($terms)) @@ -694,12 +683,11 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ 'verified' => $verified, 'unverified' => $unverified, 'txt_cats' => t('Categories:'), - 'txt_folders' => t('Filed under:'), - 'has_cats' => ((count($categories)) ? 'true' : ''), - 'has_folders' => ((count($folders)) ? 'true' : ''), - 'categories' => $categories, - 'folders' => $folders, - + 'txt_folders' => t('Filed under:'), + 'has_cats' => ((count($categories)) ? 'true' : ''), + 'has_folders' => ((count($folders)) ? 'true' : ''), + 'categories' => $categories, + 'folders' => $folders, 'text' => strip_tags($body), 'ago' => relative_date($item['created']), 'app' => $item['app'], @@ -743,10 +731,10 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ // Normal View // logger('conv: items: ' . print_r($items,true)); - require_once('include/ConversationObject.php'); - require_once('include/ItemObject.php'); + require_once('include/ConversationObject.php'); + require_once('include/ItemObject.php'); - $conv = new Conversation($mode, $preview, $prepared_item); + $conv = new Conversation($mode, $preview, $prepared_item); // In the display mode we don't have a profile owner. @@ -754,12 +742,12 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ $conv->set_profile_owner($items[0]['uid']); - // get all the topmost parents - // this shouldn't be needed, as we should have only them in our array - // But for now, this array respects the old style, just in case + // get all the topmost parents + // this shouldn't be needed, as we should have only them in our array + // But for now, this array respects the old style, just in case - $threads = array(); - foreach($items as $item) { + $threads = array(); + foreach($items as $item) { // Check for any blocked authors @@ -774,7 +762,7 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ if($blocked) continue; } - + // Check all the kids too if($arr_blocked && $item['children']) { @@ -786,46 +774,43 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ } } + like_puller($a, $item, $alike, 'like'); + if(feature_enabled($profile_owner, 'dislike')) + like_puller($a, $item, $dlike, 'dislike'); - like_puller($a,$item,$alike,'like'); - - if(feature_enabled($profile_owner,'dislike')) - like_puller($a,$item,$dlike,'dislike'); - - if(! visible_activity($item)) { - continue; - } + if(! visible_activity($item)) { + continue; + } - $item['pagedrop'] = $page_dropping; + $item['pagedrop'] = $page_dropping; - if($item['id'] == $item['parent']) { + if($item['id'] == $item['parent']) { // $tx1 = dba_timer(); - $item_object = new Item($item); - $conv->add_thread($item_object); + $item_object = new Item($item); + $conv->add_thread($item_object); if($page_mode === 'list') $item_object->set_template('conv_list.tpl'); // $tx2 = dba_timer(); // if($mode === 'network') // profiler($tx1,$tx2,'add thread ' . $item['id']); - } - } + } + } $t2 = dba_timer(); - $threads = $conv->get_template_data($alike, $dlike); - if(!$threads) { - logger('[ERROR] conversation : Failed to get template data.', LOGGER_DEBUG); - $threads = array(); - } + $threads = $conv->get_template_data($alike, $dlike); + if(!$threads) { + logger('[ERROR] conversation : Failed to get template data.', LOGGER_DEBUG); + $threads = array(); + } $t3 = dba_timer(); if($mode === 'network') { profiler($t1,$t2,'Conversation prepare'); profiler($t2,$t3,'Conversation get_template'); } - - } - } + } + } if($page_mode === 'traditional' || $page_mode === 'preview') { $page_template = get_markup_template("threaded_conversation.tpl"); @@ -867,8 +852,7 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ if($page_mode === 'preview') logger('preview: ' . $o); - return $o; - + return $o; } @@ -981,26 +965,43 @@ function item_photo_menu($item){ return $o; } - -function like_puller($a,$item,&$arr,$mode) { +/** + * @brief Returns a like/dislike entry. + * It gives back a HTML link to the channel that liked/disliked. + * + * @param array $a (not used) + * @param array $item + * @param array &$arr + * @param string $mode like/dislike + * @return void + */ +function like_puller($a, $item, &$arr, $mode) { $url = ''; - $sparkle = ''; $verb = (($mode === 'like') ? ACTIVITY_LIKE : ACTIVITY_DISLIKE); - if((activity_match($item['verb'],$verb)) && ($item['id'] != $item['parent'])) { - $url = chanlink_url($item['author']['xchan_url']); + if((activity_match($item['verb'], $verb)) && ($item['id'] != $item['parent'])) { + + if($item['author']['xchan_url']) + $url = chanlink_url($item['author']['xchan_url']); if(! $item['thr_parent']) $item['thr_parent'] = $item['parent_mid']; if(! ((isset($arr[$item['thr_parent'] . '-l'])) && (is_array($arr[$item['thr_parent'] . '-l'])))) $arr[$item['thr_parent'] . '-l'] = array(); + if(! isset($arr[$item['thr_parent']])) $arr[$item['thr_parent']] = 1; else $arr[$item['thr_parent']] ++; - $arr[$item['thr_parent'] . '-l'][] = '<a href="'. $url . '">' . $item['author']['xchan_name'] . '</a>'; + + $name = (($item['author']['xchan_name']) ? $item['author']['xchan_name'] : t('Unknown')); + + if($url) + $arr[$item['thr_parent'] . '-l'][] = '<a href="'. $url . '">' . $name . '</a>'; + else + $arr[$item['thr_parent'] . '-l'][] = '<a href="#" class="disabled">' . $name . '</a>'; } return; } @@ -1545,8 +1546,8 @@ function profile_tabs($a, $is_owner=False, $nickname=Null){ } require_once('include/chat.php'); - $chats = chatroom_list($uid); - if (count($chats)) { + $has_chats = chatroom_list_count($uid); + if ($has_chats) { $tabs[] = array( 'label' => t('Chatrooms'), 'url' => $a->get_baseurl() . '/chat/' . $nickname, @@ -1556,7 +1557,9 @@ function profile_tabs($a, $is_owner=False, $nickname=Null){ ); } - if($is_owner) { + require_once('include/menu.php'); + $has_bookmarks = menu_list_count(local_user(),'',MENU_BOOKMARK) + menu_list_count(local_user(),'',MENU_SYSTEM|MENU_BOOKMARK); + if($is_owner && $has_bookmarks) { $tabs[] = array( 'label' => t('Bookmarks'), 'url' => $a->get_baseurl() . '/bookmarks', diff --git a/include/diaspora.php b/include/diaspora.php index 8a3eaf873..6f504b460 100755 --- a/include/diaspora.php +++ b/include/diaspora.php @@ -58,7 +58,7 @@ function diaspora_dispatch($importer,$msg,$attempt=1) { $xmlbase = $parsed_xml->post; - logger('diaspora_dispatch: ' . print_r($xmlbase,true), LOGGER_DEBUG); + logger('diaspora_dispatch: ' . print_r($xmlbase,true), LOGGER_DATA); if($xmlbase->request) { @@ -142,6 +142,7 @@ function diaspora_process_outbound($arr) { 'cmd' => $cmd, 'expire' => $expire, 'mail' => $mail, + 'location' => $location, 'fsuggest' => $fsuggest, 'normal_mode' => $normal_mode, 'packet_type' => $packet_type, @@ -150,6 +151,10 @@ function diaspora_process_outbound($arr) { */ + if($arr['location']) + return; + + $target_item = $arr['target_item']; if($target_item && array_key_exists('item_flags',$target_item) && ($target_item['item_flags'] & ITEM_OBSCURED)) { @@ -161,6 +166,7 @@ function diaspora_process_outbound($arr) { } + if($arr['env_recips']) { $hashes = array(); @@ -539,7 +545,7 @@ function diaspora_decode($importer,$xml) { * </decrypted_header> */ - logger('decrypted: ' . $decrypted, LOGGER_DEBUG); + logger('decrypted: ' . $decrypted, LOGGER_DATA); $idom = parse_xml_string($decrypted,false); $inner_iv = base64_decode($idom->iv); @@ -906,7 +912,7 @@ function diaspora_post($importer,$xml,$msg) { function diaspora_reshare($importer,$xml,$msg) { - logger('diaspora_reshare: init: ' . print_r($xml,true)); + logger('diaspora_reshare: init: ' . print_r($xml,true), LOGGER_DATA); $a = get_app(); $guid = notags(unxmlify($xml->guid)); @@ -949,7 +955,7 @@ function diaspora_reshare($importer,$xml,$msg) { logger('diaspora_reshare: unable to fetch source url ' . $source_url); return; } - logger('diaspora_reshare: source: ' . $x['body']); + logger('diaspora_reshare: source: ' . $x['body'], LOGGER_DATA); $source_xml = parse_xml_string($x['body'],false); @@ -1425,7 +1431,8 @@ function diaspora_conversation($importer,$xml,$msg) { return; } - if(($contact['rel'] == CONTACT_IS_FOLLOWER) || ($contact['blocked']) || ($contact['readonly'])) { + + if(! perm_is_allowed($importer['channel_id'],$contact['xchan_hash'],'post_mail')) { logger('diaspora_conversation: Ignoring this author.'); return 202; } @@ -1525,7 +1532,7 @@ function diaspora_conversation($importer,$xml,$msg) { continue; } - q("insert into mail ( `uid`, `convid`, `from_xchan`,`to_xchan`,`title`,`body`,`mail_flags`,`mid`,`parent_mid`,`created`) values ( %d, %d, '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s')", + q("insert into mail ( `channel_id`, `convid`, `from_xchan`,`to_xchan`,`title`,`body`,`mail_flags`,`mid`,`parent_mid`,`created`) values ( %d, %d, '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s')", intval($importer['channel_id']), intval($conversation['id']), dbesc($person['xchan_hash']), @@ -1639,19 +1646,15 @@ function diaspora_message($importer,$xml,$msg) { return; } - q("insert into mail ( `uid`, `guid`, `convid`, `from-name`,`from-photo`,`from-url`,`contact-id`,`title`,`body`,`seen`,`reply`,`uri`,`parent-uri`,`created`) values ( %d, '%s', %d, '%s', '%s', '%s', %d, '%s', '%s', %d, %d, '%s','%s','%s')", + q("insert into mail ( `channel_id`, `convid`, `from_xchan`,`to_xchan`,`title`,`body`,`mail_flags`,`mid`,`parent_mid`,`created`) values ( %d, %d, '%s', '%s', '%s', '%s', '%d','%s','%s','%s')", intval($importer['channel_id']), - dbesc($msg_guid), intval($conversation['id']), - dbesc($person['name']), - dbesc($person['photo']), - dbesc($person['url']), - intval($contact['id']), + dbesc($person['xchan_hash']), + dbesc($importer['xchan_hash']), dbesc($conversation['subject']), dbesc($body), 0, - 1, - dbesc($message_id), + dbesc($msg_guid), dbesc($parent_uri), dbesc($msg_created_at) ); @@ -1966,19 +1969,16 @@ function diaspora_retraction($importer,$xml) { if($type === 'Person') { require_once('include/Contact.php'); - contact_remove($contact['id']); + contact_remove($importer['channel_id'],$contact['abook_id']); } elseif($type === 'Post') { - $r = q("select * from item where guid = '%s' and uid = %d and not file like '%%[%%' limit 1", + $r = q("select * from item where mid = '%s' and uid = %d limit 1", dbesc('guid'), intval($importer['channel_id']) ); if(count($r)) { - if(link_compare($r[0]['author-link'],$contact['url'])) { - q("update item set `deleted` = 1, `changed` = '%s' where `id` = %d", - dbesc(datetime_convert()), - intval($r[0]['id']) - ); + if(link_compare($r[0]['author_xchan'],$contact['xchan_hash'])) { + drop_item($r[0]['id'],false); } } } @@ -2040,35 +2040,33 @@ function diaspora_signed_retraction($importer,$xml,$msg) { } if($type === 'StatusMessage' || $type === 'Comment' || $type === 'Like') { - $r = q("select * from item where guid = '%s' and uid = %d and not file like '%%[%%' limit 1", + $r = q("select * from item where mid = '%s' and uid = %d limit 1", dbesc($guid), intval($importer['channel_id']) ); - if(count($r)) { - if(link_compare($r[0]['author-link'],$contact['url'])) { - q("update item set `deleted` = 1, `edited` = '%s', `changed` = '%s', `body` = '' , `title` = '' where `id` = %d", - dbesc(datetime_convert()), - dbesc(datetime_convert()), - intval($r[0]['id']) - ); + if($r) { + if($r[0]['author_xchan'] == $contact['xchan_hash']) { + + drop_item($r[0]['id'],false, DROPITEM_PHASE1); // Now check if the retraction needs to be relayed by us // // The first item in the `item` table with the parent id is the parent. However, MySQL doesn't always // return the items ordered by `item`.`id`, in which case the wrong item is chosen as the parent. // The only item with `parent` and `id` as the parent id is the parent item. - $p = q("select origin from item where parent = %d and id = %d limit 1", + $p = q("select item_flags from item where parent = %d and id = %d limit 1", $r[0]['parent'], $r[0]['parent'] ); - if(count($p)) { - if(($p[0]['origin']) && (! $parent_author_signature)) { - q("insert into sign (`retract_iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", - $r[0]['id'], - dbesc($signed_data), - dbesc($sig), - dbesc($diaspora_handle) - ); + if($p) { + if(($p[0]['item_flags'] & ITEM_ORIGIN) && (! $parent_author_signature)) { +// FIXME so we can relay this +// q("insert into sign (`retract_iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", +// $r[0]['id'], +// dbesc($signed_data), +// dbesc($sig), +// dbesc($diaspora_handle) +// ); // the existence of parent_author_signature would have meant the parent_author or owner // is already relaying. diff --git a/include/follow.php b/include/follow.php index 18a9e66ea..38525982e 100644 --- a/include/follow.php +++ b/include/follow.php @@ -63,6 +63,13 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) $my_perms = PERMS_W_STREAM|PERMS_W_MAIL; + $role = get_pconfig($uid,'system','permissions_role'); + if($role) { + $x = get_role_perms($role); + if($x['perms_follow']) + $my_perms = $x['perms_follow']; + } + logger('follow: ' . $url . ' ' . print_r($j,true), LOGGER_DEBUG); @@ -136,7 +143,7 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) if(! $r) { // attempt network auto-discovery - if(strpos($url,'@')) { + if(strpos($url,'@') && (! $is_http)) { $r = discover_by_webbie($url); } elseif($is_http) { @@ -153,6 +160,12 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) $xchan_hash = $r[0]['xchan_hash']; $their_perms = 0; $my_perms = PERMS_W_STREAM|PERMS_W_MAIL; + $role = get_pconfig($uid,'system','permissions_role'); + if($role) { + $x = get_role_perms($role); + if($x['perms_follow']) + $my_perms = $x['perms_follow']; + } } } diff --git a/include/hubloc.php b/include/hubloc.php index 566875ce9..cdc9de4af 100644 --- a/include/hubloc.php +++ b/include/hubloc.php @@ -42,4 +42,75 @@ function prune_hub_reinstalls() { } } } -}
\ No newline at end of file +} + +function remove_obsolete_hublocs() { + + logger('remove_obsolete_hublocs',LOGGER_DEBUG); + + // Get rid of any hublocs which are ours but aren't valid anymore - + // e.g. they point to a different and perhaps transient URL that we aren't using. + + // I need to stress that this shouldn't happen. fix_system_urls() fixes hublocs + // when it discovers the URL has changed. So it's unclear how we could end up + // with URLs pointing to the old site name. But it happens. This may be an artifact + // of an old bug or maybe a regression in some newer code. In any event, they + // mess up communications and we have to take action if we find any. + + // First make sure we have any hublocs (at all) with this URL and sitekey. + // We don't want to perform this operation while somebody is in the process + // of renaming their hub or installing certs. + + $r = q("select hubloc_id from hubloc where hubloc_url = '%s' and hubloc_sitekey = '%s'", + dbesc(z_root()), + dbesc(get_config('system','pubkey')) + ); + if((! $r) || (! count($r))) + return; + + $channels = array(); + + // Good. We have at least one *valid* hubloc. + + // Do we have any invalid ones? + + $r = q("select hubloc_id from hubloc where hubloc_sitekey = '%s' and hubloc_url != '%s'", + dbesc(get_config('system','pubkey')), + dbesc(z_root()) + ); + $p = q("select hubloc_id from hubloc where hubloc_sitekey != '%s' and hubloc_url = '%s'", + dbesc(get_config('system','pubkey')), + dbesc(z_root()) + ); + if(is_array($r) && is_array($p)) + $r = array_merge($r,$p); + + if(! $r) + return; + + // We've got invalid hublocs. Get rid of them. + + logger('remove_obsolete_hublocs: removing ' . count($r) . ' hublocs.'); + + $interval = ((get_config('system','delivery_interval') !== false) + ? intval(get_config('system','delivery_interval')) : 2 ); + + foreach($r as $rr) { + q("update hubloc set hubloc_flags = (hubloc_flags | %d) where hubloc_id = %d limit 1", + intval(HUBLOC_FLAGS_DELETED), + intval($rr['hubloc_id']) + ); + + $x = q("select channel_id from channel where channel_hash = '%s' limit 1", + dbesc($rr['hubloc_hash']) + ); + if($x) { +// proc_run('php','include/notifier.php','location',$x[0]['channel_id']); +// if($interval) +// @time_sleep_until(microtime(true) + (float) $interval); + } + } +} + + +
\ No newline at end of file diff --git a/include/identity.php b/include/identity.php index d8f59e56c..50c5d13b9 100644 --- a/include/identity.php +++ b/include/identity.php @@ -215,18 +215,38 @@ function create_identity($arr) { if(array_key_exists('primary', $arr)) $primary = intval($arr['primary']); + $perms_sql = ''; - $defperms = site_default_perms(); + $role_permissions = null; $global_perms = get_perms(); - foreach($defperms as $p => $v) { - $perms_keys .= ', ' . $global_perms[$p][0]; - $perms_vals .= ', ' . intval($v); + + if(array_key_exists('permissions_role',$arr) && $arr['permissions_role']) { + $role_permissions = get_role_perms($arr['permissions_role']); + + if($role_permissions) { + foreach($role_permissions as $p => $v) { + if(strpos($p,'channel_') !== false) { + $perms_keys .= ', ' . $p; + $perms_vals .= ', ' . intval($v); + } + if($p === 'directory_publish') + $publish = intval($v); + } + } } + else { + $defperms = site_default_perms(); + foreach($defperms as $p => $v) { + $perms_keys .= ', ' . $global_perms[$p][0]; + $perms_vals .= ', ' . intval($v); + } + } + $expire = get_config('system', 'default_expire_days'); $expire = (($expire===false)? '0': $expire); - + $r = q("insert into channel ( channel_account_id, channel_primary, channel_name, channel_address, channel_guid, channel_guid_sig, channel_hash, channel_prvkey, channel_pubkey, channel_pageflags, channel_expire_days $perms_keys ) @@ -246,8 +266,6 @@ function create_identity($arr) { ); - - $r = q("select * from channel where channel_account_id = %d and channel_guid = '%s' limit 1", intval($arr['account_id']), @@ -322,24 +340,55 @@ function create_identity($arr) { dbesc($a->get_baseurl() . "/photo/profile/m/{$newuid}") ); - $r = q("insert into abook ( abook_account, abook_channel, abook_xchan, abook_closeness, abook_created, abook_updated, abook_flags ) - values ( %d, %d, '%s', %d, '%s', '%s', %d ) ", + $myperms = 0; + if($role_permissions) { + $myperms = ((array_key_exists('perms_auto',$role_permissions) && $role_permissions['perms_auto']) ? intval($role_permissions['perms_accept']) : 0); + } + + $r = q("insert into abook ( abook_account, abook_channel, abook_xchan, abook_closeness, abook_created, abook_updated, abook_flags, abook_my_perms ) + values ( %d, %d, '%s', %d, '%s', '%s', %d, %d ) ", intval($ret['channel']['channel_account_id']), intval($newuid), dbesc($hash), intval(0), dbesc(datetime_convert()), dbesc(datetime_convert()), - intval(ABOOK_FLAG_SELF) + intval(ABOOK_FLAG_SELF), + intval($myperms) ); if(intval($ret['channel']['channel_account_id'])) { - // Create a group with no members. This allows somebody to use it + // Save our permissions role so we can perhaps call it up and modify it later. + + if($role_permissions) { + set_pconfig($newuid,'system','permissions_role',$arr['permissions_role']); + if(array_key_exists('online',$role_permissions)) + set_pconfig('system','hide_presence',1-intval($role_permissions['online'])); + } + + // Create a group with yourself as a member. This allows somebody to use it // right away as a default group for new contacts. require_once('include/group.php'); group_add($newuid, t('Friends')); + group_add_member($newuid,t('Friends'),$ret['channel']['channel_hash']); + + // if our role_permissions indicate that we're using a default collection ACL, add it. + + if(is_array($role_permissions) && $role_permissions['default_collection']) { + $r = q("select hash from groups where uid = %d and name = '%s' limit 1", + intval($newuid), + dbesc( t('Friends') ) + ); + if($r) { + q("update channel set channel_allow_gid = '%s' where channel_id = %d limit 1", + dbesc('<' . $r[0]['hash'] . '>'), + intval($newuid) + ); + } + } + call_hooks('register_account', $newuid); @@ -396,7 +445,7 @@ function set_default_login_identity($account_id,$channel_id,$force = true) { * */ -function identity_basic_export($channel_id) { +function identity_basic_export($channel_id, $items = false) { /* * Red basic channel export @@ -468,8 +517,36 @@ function identity_basic_export($channel_id) { $ret['photo'] = array('type' => $r[0]['type'], 'data' => base64url_encode($r[0]['data'])); } + if(! $items) + return $ret; + + + $r = q("select * from item_id where uid = %d", + intval($channel_id) + ); + + if($r) + $ret['item_id'] = $r; + + $key = get_config('system','prvkey'); + + // warning: this may run into memory limits on smaller systems + + $r = q("select * from item where (item_flags & %d) and not (item_restrict & %d) and uid = %d", + intval(ITEM_WALL), + intval(ITEM_DELETED), + intval($channel_id) + ); + if($r) { + $ret['item'] = array(); + xchan_query($r); + $r = fetch_post_tags($r,true); + foreach($r as $rr) + $ret['item'][] = encode_item($rr,true); + } return $ret; + } diff --git a/include/items.php b/include/items.php index 166303cac..53a0b25a9 100755 --- a/include/items.php +++ b/include/items.php @@ -68,13 +68,31 @@ function collect_recipients($item,&$private_envelope) { $private_envelope = false; if(array_key_exists('public_policy',$item) && $item['public_policy'] !== 'self') { - $r = q("select abook_xchan from abook where abook_channel = %d and not (abook_flags & %d) ", + $r = q("select abook_xchan, xchan_network from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and not (abook_flags & %d) ", intval($item['uid']), intval(ABOOK_FLAG_SELF|ABOOK_FLAG_PENDING|ABOOK_FLAG_ARCHIVED) ); if($r) { + + // filter out restrictive public_policy settings from remote networks + // which don't have this concept and will treat them as public. + + $policy = substr($item['public_policy'],0,3); foreach($r as $rr) { - $recipients[] = $rr['abook_xchan']; + switch($policy) { + case 'net': + case 'aut': + case 'sit': + case 'any': + case 'con': + if($rr['xchan_network'] != 'zot') + break; + case 'pub': + case '': + default: + $recipients[] = $rr['abook_xchan']; + break; + } } } } @@ -989,8 +1007,7 @@ function import_author_unknown($x) { } - -function encode_item($item) { +function encode_item($item,$mirror = false) { $x = array(); $x['type'] = 'activity'; $x['encoding'] = 'zot'; @@ -1012,14 +1029,37 @@ function encode_item($item) { $c_scope = map_scope($comment_scope); + $key = get_config('system','prvkey'); + if(array_key_exists('item_flags',$item) && ($item['item_flags'] & ITEM_OBSCURED)) { - $key = get_config('system','prvkey'); if($item['title']) $item['title'] = crypto_unencapsulate(json_decode_plus($item['title']),$key); if($item['body']) $item['body'] = crypto_unencapsulate(json_decode_plus($item['body']),$key); } + // If we're trying to backup an item so that it's recoverable or for export/imprt, + // add all the attributes we need to recover it + + if($mirror) { + $x['id'] = $item['id']; + $x['parent'] = $item['parent']; + $x['uid'] = $item['uid']; + $x['allow_cid'] = $item['allow_cid']; + $x['allow_gid'] = $item['allow_gid']; + $x['deny_cid'] = $item['deny_cid']; + $x['deny_gid'] = $item['deny_gid']; + $x['revision'] = $item['revision']; + $x['layout_mid'] = $item['layout_mid']; + $x['postopts'] = $item['postopts']; + $x['resource_id'] = $item['resource_id']; + $x['resource_type'] = $item['resource_type']; + $x['item_restrict'] = $item['item_restrict']; + $x['item_flags'] = $item['item_flags']; + $x['diaspora_meta'] = crypto_unencapsulate(json_decode($item['diaspora_meta'],true),$key); + $x['attach'] = $item['attach']; + } + $x['message_id'] = $item['mid']; $x['message_top'] = $item['parent_mid']; @@ -1751,6 +1791,7 @@ function get_atom_elements($feed,$item,&$author) { call_hooks('parse_atom', $arr); logger('get_atom_elements: author: ' . print_r($author,true),LOGGER_DATA); + logger('get_atom_elements: ' . print_r($res,true),LOGGER_DATA); return $res; @@ -2429,18 +2470,10 @@ function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id) return; } - $body = $datarray['body']; - if(array_key_exists('item_flags',$datarray) && ($datarray['item_flags'] & ITEM_OBSCURED)) { - $key = get_config('system','prvkey'); - if($datarray['body']) - $body = crypto_unencapsulate(json_decode($datarray['body'],true),$key); - } - - logger('mod_item: storing diaspora comment signature',LOGGER_DEBUG); - require_once('include/bb2diaspora.php'); + $signed_body = bb2diaspora_itembody($datarray); - $signed_body = html_entity_decode(bb2diaspora($body)); + logger('mod_item: storing diaspora comment signature',LOGGER_DEBUG); $diaspora_handle = $channel['channel_address'] . '@' . get_app()->get_hostname(); diff --git a/include/js_strings.php b/include/js_strings.php index cda66a09c..f4c0a631d 100644 --- a/include/js_strings.php +++ b/include/js_strings.php @@ -15,6 +15,7 @@ function js_strings() { '$passhint' => t('Passphrase hint'), '$permschange' => t('Notice: Permissions have changed but have not yet been submitted.'), '$closeAll' => t('close all'), + '$nothingnew' => t('Nothing new here'), '$t01' => ((t('timeago.prefixAgo') != 'timeago.prefixAgo') ? t('timeago.prefixAgo') : ''), '$t02' => ((t('timeago.prefixFromNow') != 'timeago.prefixFromNow') ? t('timeago.prefixFromNow') : ''), diff --git a/include/menu.php b/include/menu.php index 4b0a11f10..8997d2e39 100644 --- a/include/menu.php +++ b/include/menu.php @@ -124,7 +124,17 @@ function menu_list($channel_id, $name = '', $flags = 0) { return $r; } +function menu_list_count($channel_id, $name = '', $flags = 0) { + $sel_options = ''; + $sel_options .= (($name) ? " and menu_name = '" . protect_sprintf(dbesc($name)) . "' " : ''); + $sel_options .= (($flags) ? " and menu_flags = " . intval($flags) . " " : ''); + + $r = q("select count(*) as total from menu where menu_channel_id = %d $sel_options", + intval($channel_id) + ); + return $r[0]['total']; +} function menu_edit($arr) { diff --git a/include/nav.php b/include/nav.php index 799faf5ce..98d1b644e 100644 --- a/include/nav.php +++ b/include/nav.php @@ -105,14 +105,19 @@ EOT; $nav['usermenu'][] = Array('cloud/' . $channel['channel_address'],t('Files'),"",t('Your files')); require_once('include/chat.php'); - $chats = chatroom_list(local_user()); - if (count($chats)) { + $has_chats = chatroom_list_count(local_user()); + if($has_chats) { $nav['usermenu'][] = Array('chat/' . $channel['channel_address'],t('Chat'),"",t('Your chatrooms')); } - $nav['usermenu'][] = Array('bookmarks', t('Bookmarks'), "", t('Your bookmarks')); + require_once('include/menu.php'); + $has_bookmarks = menu_list_count(local_user(),'',MENU_BOOKMARK) + menu_list_count(local_user(),'',MENU_SYSTEM|MENU_BOOKMARK); + if($has_bookmarks) { + $nav['usermenu'][] = Array('bookmarks', t('Bookmarks'), "", t('Your bookmarks')); + } + if(feature_enabled($channel['channel_id'],'webpages')) - $nav['usermenu'][] = Array('webpages/' . $channel['channel_address'],t('Webpages'),"",t('Your webpages')); + $nav['usermenu'][] = Array('webpages/' . $channel['channel_address'],t('Webpages'),"",t('Your webpages')); } else { if(! get_account_id()) @@ -241,7 +246,7 @@ EOT; '$sitelocation' => $sitelocation, '$nav' => $x['nav'], '$banner' => $banner, - '$emptynotifications' => t('Nothing new here'), + '$emptynotifications' => t('Loading...'), '$userinfo' => $x['usermenu'], '$localuser' => local_user(), '$sel' => $a->nav_sel, diff --git a/include/network.php b/include/network.php index 0191f203d..7286f0b12 100644 --- a/include/network.php +++ b/include/network.php @@ -38,6 +38,7 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) { return false; @curl_setopt($ch, CURLOPT_HEADER, true); + @curl_setopt($ch, CURLINFO_HEADER_OUT, true); @curl_setopt($ch, CURLOPT_CAINFO, get_capath()); @curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); @curl_setopt($ch, CURLOPT_RETURNTRANSFER,true); @@ -47,11 +48,8 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) { if($ciphers) @curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, $ciphers); - if (x($opts,'accept_content')){ - @curl_setopt($ch,CURLOPT_HTTPHEADER, array ( - "Accept: " . $opts['accept_content'] - )); - } + if(x($opts,'headers')) + @curl_setopt($ch, CURLOPT_HTTPHEADER, $opts['headers']); if(x($opts,'timeout') && intval($opts['timeout'])) { @curl_setopt($ch, CURLOPT_TIMEOUT, $opts['timeout']); @@ -126,6 +124,10 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) { } $ret['body'] = substr($s,strlen($header)); $ret['header'] = $header; + + if(x($opts,'debug')) { + $ret['debug'] = $curl_info; + } @curl_close($ch); return($ret); @@ -166,6 +168,7 @@ function z_post_url($url,$params, $redirects = 0, $opts = array()) { return ret; @curl_setopt($ch, CURLOPT_HEADER, true); + @curl_setopt($ch, CURLINFO_HEADER_OUT, true); @curl_setopt($ch, CURLOPT_CAINFO, get_capath()); @curl_setopt($ch, CURLOPT_RETURNTRANSFER,true); @curl_setopt($ch, CURLOPT_POST,1); @@ -176,12 +179,6 @@ function z_post_url($url,$params, $redirects = 0, $opts = array()) { if($ciphers) @curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, $ciphers); - - if (x($opts,'accept_content')){ - @curl_setopt($ch,CURLOPT_HTTPHEADER, array ( - "Accept: " . $opts['accept_content'] - )); - } if(x($opts,'headers')) @curl_setopt($ch, CURLOPT_HTTPHEADER, $opts['headers']); @@ -258,11 +255,24 @@ function z_post_url($url,$params, $redirects = 0, $opts = array()) { $ret['body'] = substr($s,strlen($header)); $ret['header'] = $header; + + if(x($opts,'debug')) { + $ret['debug'] = $curl_info; + } + + curl_close($ch); return($ret); } +function z_post_url_json($url,$params,$redirects = 0, $opts = array()) { + + $opts = array_merge($opts,array('headers' => array('Content-Type: application/json'))); + return z_post_url($url,json_encode($params),$redirects,$opts); + +} + function json_return_and_die($x) { header("content-type: application/json"); diff --git a/include/notifier.php b/include/notifier.php index 88bb9a0cb..0c7a15452 100644 --- a/include/notifier.php +++ b/include/notifier.php @@ -57,6 +57,7 @@ require_once('include/html2plain.php'); * purge_all channel_id * expire channel_id * relay item_id (item was relayed to owner, we will deliver it as owner) + * location channel_id * */ @@ -144,6 +145,7 @@ function notifier_run($argv, $argc){ $mail = false; $fsuggest = false; $top_level = false; + $location = false; $recipients = array(); $url_recipients = array(); $normal_mode = true; @@ -230,6 +232,30 @@ function notifier_run($argv, $argc){ $private = false; $packet_type = 'refresh'; } + elseif($cmd === 'location') { + logger('notifier: location: ' . $item_id); + $s = q("select * from channel where channel_id = %d limit 1", + intval($item_id) + ); + if($s) + $channel = $s[0]; + $uid = $item_id; + $recipients = array(); + $r = q("select abook_xchan from abook where abook_channel = %d", + intval($item_id) + ); + if($r) { + foreach($r as $rr) { + $recipients[] = $rr['abook_xchan']; + } + } + + $encoded_item = array('locations' => zot_encode_locations($channel),'type' => 'location', 'encoding' => 'zot'); + $target_item = array('aid' => $channel['channel_account_id'],'uid' => $channel['channel_id']); + $private = false; + $packet_type = 'location'; + $location = true; + } elseif($cmd === 'purge_all') { logger('notifier: purge_all: ' . $item_id); $s = q("select * from channel where channel_id = %d limit 1", @@ -429,8 +455,10 @@ function notifier_run($argv, $argc){ // for public posts always include our own hub +// this shouldn't be needed any more. collect_recipients should take care of it. +// $sql_extra = (($private) ? "" : " or hubloc_url = '" . dbesc(z_root()) . "' "); - $sql_extra = (($private) ? "" : " or hubloc_url = '" . dbesc(z_root()) . "' "); + logger('notifier: hub choice: ' . intval($relay_to_owner) . ' ' . intval($private) . ' ' . $cmd, LOGGER_DEBUG); if($relay_to_owner && (! $private) && ($cmd !== 'relay')) { @@ -450,7 +478,10 @@ function notifier_run($argv, $argc){ } else { $r = q("select hubloc_guid, hubloc_url, hubloc_sitekey, hubloc_network, hubloc_flags, hubloc_callback, hubloc_host from hubloc - where hubloc_hash in (" . implode(',',$recipients) . ") $sql_extra group by hubloc_sitekey"); + where hubloc_hash in (" . implode(',',$recipients) . ") and not (hubloc_flags & %d) and not (hubloc_status & %d) group by hubloc_sitekey", + intval(HUBLOC_FLAGS_DELETED), + intval(HUBLOC_OFFLINE) + ); } if(! $r) { @@ -465,6 +496,7 @@ function notifier_run($argv, $argc){ foreach($hubs as $hub) { // don't try to deliver to deleted hublocs - and inexplicably SQL "distinct" and "group by" // both return records with duplicate keys in rare circumstances +// FIXME this is probably redundant now. if((! ($hub['hubloc_flags'] & HUBLOC_FLAGS_DELETED)) && (! in_array($hub['hubloc_sitekey'],$keys))) { $hublist[] = $hub['hubloc_host']; $keys[] = $hub['hubloc_sitekey']; @@ -514,6 +546,7 @@ function notifier_run($argv, $argc){ 'cmd' => $cmd, 'expire' => $expire, 'mail' => $mail, + 'location' => $location, 'fsuggest' => $fsuggest, 'normal_mode' => $normal_mode, 'packet_type' => $packet_type, diff --git a/include/onepoll.php b/include/onepoll.php index 1f28852e9..98d52db93 100644 --- a/include/onepoll.php +++ b/include/onepoll.php @@ -135,7 +135,7 @@ function onepoll_run($argv, $argc){ foreach($j['messages'] as $message) { $results = process_delivery(array('hash' => $contact['xchan_hash']), get_item_elements($message), array(array('hash' => $importer['xchan_hash'])), false); - logger('onepoll: feed_update: process_delivery: ' . print_r($results,true)); + logger('onepoll: feed_update: process_delivery: ' . print_r($results,true), LOGGER_DATA); $total ++; } logger("onepoll: $total messages processed"); diff --git a/include/permissions.php b/include/permissions.php index 8e4676f51..438b807d0 100644 --- a/include/permissions.php +++ b/include/permissions.php @@ -419,11 +419,12 @@ function site_default_perms() { * * Given a string for the channel role ('social','forum', etc) * return an array of all permission fields pre-filled for this role. - * This includes the channel permission scope indicators as well as - * perms_auto: The permissions to apply automatically on receipt of a connection request + * This includes the channel permission scope indicators (anything beginning with 'channel_') as well as + * perms_auto: true or false to create auto-permissions for this channel * perms_follow: The permissions to apply when initiating a connection request to another channel * perms_accept: The permissions to apply when accepting a connection request from another channel (not automatic) - * + * default_collection: true or false to make the default ACL include the channel's default collection + * directory_publish: true or false to publish this channel in the directory * Any attributes may be extended (new roles defined) and modified (specific permissions altered) by plugins * */ @@ -436,7 +437,10 @@ function get_role_perms($role) { switch($role) { case 'social': - $ret['perms_auto'] = 0; + $ret['perms_auto'] = false; + $ret['default_collection'] = false; + $ret['directory_publish'] = true; + $ret['online'] = true; $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_A_REPUBLISH|PERMS_W_LIKE; @@ -462,6 +466,259 @@ function get_role_perms($role) { $ret['channel_w_like'] = PERMS_NETWORK; break; + + + case 'social_restricted': + $ret['perms_auto'] = false; + $ret['default_collection'] = true; + $ret['directory_publish'] = true; + $ret['online'] = true; + $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT + |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_W_LIKE; + $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT + |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_W_LIKE; + $ret['channel_r_stream'] = PERMS_PUBLIC; + $ret['channel_r_profile'] = PERMS_PUBLIC; + $ret['channel_r_photos'] = PERMS_PUBLIC; + $ret['channel_r_abook'] = PERMS_PUBLIC; + $ret['channel_w_stream'] = PERMS_CONTACTS; + $ret['channel_w_wall'] = PERMS_CONTACTS; + $ret['channel_w_tagwall'] = PERMS_SPECIFIC; + $ret['channel_w_comment'] = PERMS_CONTACTS; + $ret['channel_w_mail'] = PERMS_CONTACTS; + $ret['channel_w_photos'] = 0; + $ret['channel_w_chat'] = PERMS_CONTACTS; + $ret['channel_a_delegate'] = 0; + $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_r_pages'] = PERMS_PUBLIC; + $ret['channel_w_pages'] = 0; + $ret['channel_a_republish'] = PERMS_SPECIFIC; + $ret['channel_w_like'] = PERMS_CONTACTS; + + break; + + + case 'social_private': + $ret['perms_auto'] = false; + $ret['default_collection'] = true; + $ret['directory_publish'] = false; + $ret['online'] = false; + $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT + |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_W_LIKE; + $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT + |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_W_LIKE; + $ret['channel_r_stream'] = PERMS_PUBLIC; + $ret['channel_r_profile'] = PERMS_PUBLIC; + $ret['channel_r_photos'] = PERMS_PUBLIC; + $ret['channel_r_abook'] = PERMS_CONTACTS; + $ret['channel_w_stream'] = PERMS_CONTACTS; + $ret['channel_w_wall'] = PERMS_CONTACTS; + $ret['channel_w_tagwall'] = PERMS_SPECIFIC; + $ret['channel_w_comment'] = PERMS_CONTACTS; + $ret['channel_w_mail'] = PERMS_SPECIFIC; + $ret['channel_w_photos'] = 0; + $ret['channel_w_chat'] = PERMS_SPECIFIC; + $ret['channel_a_delegate'] = 0; + $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_r_pages'] = PERMS_PUBLIC; + $ret['channel_w_pages'] = 0; + $ret['channel_a_republish'] = PERMS_SPECIFIC; + $ret['channel_w_like'] = PERMS_CONTACTS; + + break; + + case 'forum': + $ret['perms_auto'] = true; + $ret['default_collection'] = false; + $ret['directory_publish'] = true; + $ret['online'] = false; + $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT + |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_A_REPUBLISH|PERMS_W_LIKE|PERMS_W_TAGWALL; + $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT + |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_A_REPUBLISH|PERMS_W_LIKE|PERMS_W_TAGWALL; + $ret['channel_r_stream'] = PERMS_PUBLIC; + $ret['channel_r_profile'] = PERMS_PUBLIC; + $ret['channel_r_photos'] = PERMS_PUBLIC; + $ret['channel_r_abook'] = PERMS_PUBLIC; + $ret['channel_w_stream'] = PERMS_CONTACTS; + $ret['channel_w_wall'] = PERMS_CONTACTS; + $ret['channel_w_tagwall'] = PERMS_CONTACTS; + $ret['channel_w_comment'] = PERMS_CONTACTS; + $ret['channel_w_mail'] = PERMS_CONTACTS; + $ret['channel_w_photos'] = 0; + $ret['channel_w_chat'] = PERMS_CONTACTS; + $ret['channel_a_delegate'] = 0; + $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_r_pages'] = PERMS_PUBLIC; + $ret['channel_w_pages'] = 0; + $ret['channel_a_republish'] = PERMS_SPECIFIC; + $ret['channel_w_like'] = PERMS_NETWORK; + + break; + + case 'forum_restricted': + $ret['perms_auto'] = false; + $ret['default_collection'] = true; + $ret['directory_publish'] = true; + $ret['online'] = false; + $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT + |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_W_LIKE|PERMS_W_TAGWALL; + $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT + |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_W_LIKE|PERMS_W_TAGWALL; + $ret['channel_r_stream'] = PERMS_PUBLIC; + $ret['channel_r_profile'] = PERMS_PUBLIC; + $ret['channel_r_photos'] = PERMS_PUBLIC; + $ret['channel_r_abook'] = PERMS_PUBLIC; + $ret['channel_w_stream'] = PERMS_CONTACTS; + $ret['channel_w_wall'] = PERMS_CONTACTS; + $ret['channel_w_tagwall'] = PERMS_SPECIFIC; + $ret['channel_w_comment'] = PERMS_CONTACTS; + $ret['channel_w_mail'] = PERMS_CONTACTS; + $ret['channel_w_photos'] = 0; + $ret['channel_w_chat'] = PERMS_CONTACTS; + $ret['channel_a_delegate'] = 0; + $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_r_pages'] = PERMS_PUBLIC; + $ret['channel_w_pages'] = 0; + $ret['channel_a_republish'] = PERMS_SPECIFIC; + $ret['channel_w_like'] = PERMS_CONTACTS; + + break; + + + case 'forum_private': + $ret['perms_auto'] = false; + $ret['default_collection'] = true; + $ret['directory_publish'] = false; + $ret['online'] = false; + $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT + |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_W_LIKE; + $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT + |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_W_LIKE; + $ret['channel_r_stream'] = PERMS_PUBLIC; + $ret['channel_r_profile'] = PERMS_CONTACTS; + $ret['channel_r_photos'] = PERMS_CONTACTS; + $ret['channel_r_abook'] = PERMS_CONTACTS; + $ret['channel_w_stream'] = PERMS_CONTACTS; + $ret['channel_w_wall'] = PERMS_CONTACTS; + $ret['channel_w_tagwall'] = 0; + $ret['channel_w_comment'] = PERMS_CONTACTS; + $ret['channel_w_mail'] = PERMS_SPECIFIC; + $ret['channel_w_photos'] = 0; + $ret['channel_w_chat'] = PERMS_SPECIFIC; + $ret['channel_a_delegate'] = 0; + $ret['channel_r_storage'] = PERMS_CONTACTS; + $ret['channel_r_pages'] = PERMS_CONTACTS; + $ret['channel_w_pages'] = 0; + $ret['channel_a_republish'] = PERMS_SPECIFIC; + $ret['channel_w_like'] = PERMS_CONTACTS; + + break; + + case 'feed': + $ret['perms_auto'] = true; + $ret['default_collection'] = false; + $ret['directory_publish'] = true; + $ret['online'] = false; + $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL + |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_A_REPUBLISH|PERMS_W_LIKE; + $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL + |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_A_REPUBLISH|PERMS_W_LIKE; + $ret['channel_r_stream'] = PERMS_PUBLIC; + $ret['channel_r_profile'] = PERMS_PUBLIC; + $ret['channel_r_photos'] = PERMS_PUBLIC; + $ret['channel_r_abook'] = PERMS_PUBLIC; + $ret['channel_w_stream'] = PERMS_CONTACTS; + $ret['channel_w_wall'] = PERMS_CONTACTS; + $ret['channel_w_tagwall'] = PERMS_SPECIFIC; + $ret['channel_w_comment'] = PERMS_CONTACTS; + $ret['channel_w_mail'] = PERMS_CONTACTS; + $ret['channel_w_photos'] = 0; + $ret['channel_w_chat'] = PERMS_CONTACTS; + $ret['channel_a_delegate'] = 0; + $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_r_pages'] = PERMS_PUBLIC; + $ret['channel_w_pages'] = 0; + $ret['channel_a_republish'] = PERMS_NETWORK; + $ret['channel_w_like'] = PERMS_NETWORK; + + break; + + case 'feed_restricted': + + $ret['perms_auto'] = false; + $ret['default_collection'] = true; + $ret['directory_publish'] = false; + $ret['online'] = false; + $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL + |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_W_LIKE; + $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL + |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_W_LIKE; + $ret['channel_r_stream'] = PERMS_PUBLIC; + $ret['channel_r_profile'] = PERMS_PUBLIC; + $ret['channel_r_photos'] = PERMS_PUBLIC; + $ret['channel_r_abook'] = PERMS_PUBLIC; + $ret['channel_w_stream'] = PERMS_CONTACTS; + $ret['channel_w_wall'] = PERMS_CONTACTS; + $ret['channel_w_tagwall'] = PERMS_SPECIFIC; + $ret['channel_w_comment'] = PERMS_CONTACTS; + $ret['channel_w_mail'] = PERMS_CONTACTS; + $ret['channel_w_photos'] = 0; + $ret['channel_w_chat'] = PERMS_CONTACTS; + $ret['channel_a_delegate'] = 0; + $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_r_pages'] = PERMS_PUBLIC; + $ret['channel_w_pages'] = 0; + $ret['channel_a_republish'] = PERMS_SPECIFIC; + $ret['channel_w_like'] = PERMS_NETWORK; + + break; + + case 'soapbox': + $ret['perms_auto'] = true; + $ret['default_collection'] = false; + $ret['directory_publish'] = true; + $ret['online'] = false; + $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_A_REPUBLISH|PERMS_W_LIKE; + $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_A_REPUBLISH|PERMS_W_LIKE; + $ret['channel_r_stream'] = PERMS_PUBLIC; + $ret['channel_r_profile'] = PERMS_PUBLIC; + $ret['channel_r_photos'] = PERMS_PUBLIC; + $ret['channel_r_abook'] = PERMS_PUBLIC; + $ret['channel_w_stream'] = 0; + $ret['channel_w_wall'] = 0; + $ret['channel_w_tagwall'] = 0; + $ret['channel_w_comment'] = 0; + $ret['channel_w_mail'] = 0; + $ret['channel_w_photos'] = 0; + $ret['channel_w_chat'] = 0; + $ret['channel_a_delegate'] = 0; + $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_r_pages'] = PERMS_PUBLIC; + $ret['channel_w_pages'] = 0; + $ret['channel_a_republish'] = PERMS_SPECIFIC; + $ret['channel_w_like'] = PERMS_NETWORK; + + break; + + default: + break; } @@ -471,3 +728,28 @@ function get_role_perms($role) { } +function role_selector($current) { + $roles = array( + 'social' => array( t('Social Networking'), + array('social' => t('Mostly Public'), 'social_restricted' => t('Restricted'), 'social_private' => t('Private'))), + 'forum' => array( t('Community Forum'), + array('forum' => t('Mostly Public'), 'forum_restricted' => t('Restricted'), 'forum_private' => t('Private'))), + 'feed' => array( t('Feed Republish'), + array('feed' => t('Mostly Public'), 'feed_restricted' => t('Restricted'))), + 'soapbox' => array( t('Celebrity/Soapbox'), + array('soapbox' => t('Mostly Public'))), + 'other' => array( t('Other'), + array('custom' => t('Custom/Expert Mode')))); + $o = '<select name="permissions_role" id="privacy-role-select">'; + foreach($roles as $k => $v) { + $o .= '<optgroup label="'. htmlspecialchars($v[0]) . '" >'; + foreach($v[1] as $kk => $vv) { + $selected = (($kk === $current) ? ' selected="selected" ' : ''); + $o .= '<option value="' . $kk . '" ' . $selected . '>' . htmlspecialchars($vv) . '</option>'; + } + $o .= '</optgroup>'; + } + $o .= '</select>'; + return $o; +} + diff --git a/include/photos.php b/include/photos.php index 06a99457a..badbbd791 100644 --- a/include/photos.php +++ b/include/photos.php @@ -266,6 +266,7 @@ function photo_upload($channel, $observer, $args) { proc_run('php', "include/notifier.php", 'wall-new', $item_id); $ret['success'] = true; + $ret['item'] = $arr; $ret['body'] = $arr['body']; $ret['resource_id'] = $photo_hash; $ret['photoitem_id'] = $item_id; diff --git a/include/poller.php b/include/poller.php index c90e48d6b..f689059b9 100644 --- a/include/poller.php +++ b/include/poller.php @@ -171,6 +171,9 @@ function poller_run($argv, $argc){ proc_run('php','include/expire.php'); proc_run('php','include/cli_suggest.php'); + require_once('include/hubloc.php'); + remove_obsolete_hublocs(); + /** * End Cron Daily */ diff --git a/include/security.php b/include/security.php index 0f2edc708..e83cc7061 100644 --- a/include/security.php +++ b/include/security.php @@ -82,6 +82,19 @@ function change_channel($change_channel) { intval(PAGE_REMOVED) ); + // It's not there. Is this an administrator, and is this the sys channel? + if (is_developer()) { + if (! $r) { + if (is_site_admin()) { + $r = q("select channel.*, xchan.* from channel left join xchan on channel.channel_hash = xchan.xchan_hash where channel_id = %d and ( channel_pageflags & %d) and not (channel_pageflags & %d ) limit 1", + intval($change_channel), + intval(PAGE_SYSTEM), + intval(PAGE_REMOVED) + ); + } + } + } + if($r) { $hash = $r[0]['channel_hash']; $_SESSION['uid'] = intval($r[0]['channel_id']); diff --git a/include/widgets.php b/include/widgets.php index 1aa018fb6..f1c9ceada 100644 --- a/include/widgets.php +++ b/include/widgets.php @@ -481,11 +481,11 @@ function widget_settings_menu($arr) { 'selected' => '' ), -// array( -// 'label' => t('Export account'), -// 'url' => $a->get_baseurl(true) . '/uexport/complete', -// 'selected' => '' -// ), + array( + 'label' => t('Export content'), + 'url' => $a->get_baseurl(true) . '/uexport/complete', + 'selected' => '' + ), array( 'label' => t('Automatic Permissions (Advanced)'), diff --git a/include/zot.php b/include/zot.php index 644d20ec2..b7ffe14e4 100644 --- a/include/zot.php +++ b/include/zot.php @@ -661,6 +661,8 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { } $xchan_hash = make_xchan_hash($arr['guid'],$arr['guid_sig']); + $arr['hash'] = $xchan_hash; + $import_photos = false; if(! rsa_verify($arr['guid'],base64url_decode($arr['guid_sig']),$arr['key'])) { @@ -843,174 +845,16 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { // what we are missing for true hub independence is for any changes in the primary hub to // get reflected not only in the hublocs, but also to update the URLs and addr in the appropriate xchan - if($arr['locations']) { - - $xisting = q("select hubloc_id, hubloc_url, hubloc_sitekey from hubloc where hubloc_hash = '%s'", - dbesc($xchan_hash) - ); - - // See if a primary is specified - - $has_primary = false; - foreach($arr['locations'] as $location) { - if($location['primary']) { - $has_primary = true; - break; - } - } - - foreach($arr['locations'] as $location) { - if(! rsa_verify($location['url'],base64url_decode($location['url_sig']),$arr['key'])) { - logger('import_xchan: Unable to verify site signature for ' . $location['url']); - $ret['message'] .= sprintf( t('Unable to verify site signature for %s'), $location['url']) . EOL; - continue; - } - - // Ensure that they have one primary hub - - if(! $has_primary) - $location['primary'] = true; - - - for($x = 0; $x < count($xisting); $x ++) { - if(($xisting[$x]['hubloc_url'] === $location['url']) && ($xisting[$x]['hubloc_sitekey'] === $location['sitekey'])) { - $xisting[$x]['updated'] = true; - } - } - - if(! $location['sitekey']) { - logger('import_xchan: empty hubloc sitekey. ' . print_r($location,true)); - continue; - } - - // Catch some malformed entries from the past which still exist - - if(strpos($location['address'],'/') !== false) - $location['address'] = substr($location['address'],0,strpos($location['address'],'/')); - - // match as many fields as possible in case anything at all changed. - - $r = q("select * from hubloc where hubloc_hash = '%s' and hubloc_guid = '%s' and hubloc_guid_sig = '%s' and hubloc_url = '%s' and hubloc_url_sig = '%s' and hubloc_host = '%s' and hubloc_addr = '%s' and hubloc_callback = '%s' and hubloc_sitekey = '%s' ", - dbesc($xchan_hash), - dbesc($arr['guid']), - dbesc($arr['guid_sig']), - dbesc($location['url']), - dbesc($location['url_sig']), - dbesc($location['host']), - dbesc($location['address']), - dbesc($location['callback']), - dbesc($location['sitekey']) - ); - if($r) { - logger('import_xchan: hub exists: ' . $location['url']); - // update connection timestamp if this is the site we're talking to - if($location['url'] == $arr['site']['url']) { - q("update hubloc set hubloc_connected = '%s', hubloc_updated = '%s' where hubloc_id = %d limit 1", - dbesc(datetime_convert()), - dbesc(datetime_convert()), - intval($r[0]['hubloc_id']) - ); - } - if($r[0]['hubloc_status'] & HUBLOC_OFFLINE) { - q("update hubloc set hubloc_status = (hubloc_status ^ %d) where hubloc_id = %d limit 1", - 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", - 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", - intval(XCHAN_FLAGS_ORPHAN), - intval(XCHAN_FLAGS_ORPHAN), - dbesc($xchan_hash) - ); - - } - - // Remove pure duplicates - if(count($r) > 1) { - for($h = 1; $h < count($r); $h ++) { - q("delete from hubloc where hubloc_id = %d limit 1", - intval($r[$h]['hubloc_id']) - ); - } - } - - if((($r[0]['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY) && (! $location['primary'])) - || ((! ($r[0]['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY)) && ($location['primary']))) { - $r = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d), hubloc_updated = '%s' where hubloc_id = %d limit 1", - intval(HUBLOC_FLAGS_PRIMARY), - dbesc(datetime_convert()), - intval($r[0]['hubloc_id']) - ); - $what = 'primary_hub '; - $changed = true; - } - if((($r[0]['hubloc_flags'] & HUBLOC_FLAGS_DELETED) && (! $location['deleted'])) - || ((! ($r[0]['hubloc_flags'] & HUBLOC_FLAGS_DELETED)) && ($location['deleted']))) { - $r = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d), hubloc_updated = '%s' where hubloc_id = %d limit 1", - intval(HUBLOC_FLAGS_DELETED), - dbesc(datetime_convert()), - intval($r[0]['hubloc_id']) - ); - $what = 'delete_hub '; - $changed = true; - } - continue; - } - // new hub claiming to be primary. Make it so. - - if(intval($location['primary'])) { - $r = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d), hubloc_updated = '%s' where hubloc_hash = '%s' and (hubloc_flags & %d )", - intval(HUBLOC_FLAGS_PRIMARY), - dbesc(datetime_convert()), - dbesc($xchan_hash), - intval(HUBLOC_FLAGS_PRIMARY) - ); - } - logger('import_xchan: new hub: ' . $location['url']); - $r = q("insert into hubloc ( hubloc_guid, hubloc_guid_sig, hubloc_hash, hubloc_addr, hubloc_network, hubloc_flags, 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($arr['guid']), - dbesc($arr['guid_sig']), - dbesc($xchan_hash), - dbesc($location['address']), - dbesc('zot'), - intval((intval($location['primary'])) ? HUBLOC_FLAGS_PRIMARY : 0), - dbesc($location['url']), - dbesc($location['url_sig']), - dbesc($location['host']), - dbesc($location['callback']), - dbesc($location['sitekey']), - dbesc(datetime_convert()), - dbesc(datetime_convert()) - ); - $what .= 'newhub '; - $changed = true; - - } - - // get rid of any hubs we have for this channel which weren't reported. - // This was needed at one time to resolve complicated cross-site inconsistencies, but can cause sync conflict. - // currently disabled. - -// if($xisting) { -// foreach($xisting as $x) { -// if(! array_key_exists('updated',$x)) { -// logger('import_xchan: removing unreferenced hub location ' . $x['hubloc_url']); -// $r = q("delete from hubloc where hubloc_id = %d limit 1", -// intval($x['hubloc_id']) -// ); -// $what .= 'removed_hub'; -// $changed = true; -// } -// } -// } + $s = sync_locations($arr,$arr); + if($s) { + if($s['change_message']) + $what .= $s['change_message']; + if($s['changed']) + $changed = $s['changed']; + if($s['message']) + $ret['message'] .= $s['message']; } // Which entries in the update table are we interested in updating? @@ -1189,7 +1033,8 @@ function zot_fetch($arr) { * we will verify the sender and url in each returned message structure and also verify * that all the messages returned match the site url that we are currently processing. * - * The message types handled here are 'activity' (e.g. posts), 'mail' , 'profile', and 'channel_sync' + * The message types handled here are 'activity' (e.g. posts), 'mail' , 'profile', 'location', + * and 'channel_sync' * * @returns array => array ( [0] => string $channel_hash, [1] => string $delivery_status, [2] => string $address ) * suitable for logging remotely, enumerating the processing results of each message/recipient combination. @@ -1276,6 +1121,11 @@ function zot_import($arr, $sender_url) { $deliveries = allowed_public_recips($i); + if($i['message'] && array_key_exists('type',$i['message']) && $i['message']['type'] === 'location') { + $sys = get_sys_channel(); + $deliveries = array(array('hash' => $sys['xchan_hash'])); + } + // if the scope is anything but 'public' we're going to store it as private regardless // of the private flag on the post. @@ -1348,7 +1198,7 @@ function zot_import($arr, $sender_url) { } elseif($i['message']['type'] === 'channel_sync') { -// $arr = get_channelsync_elements($i['message']); + // $arr = get_channelsync_elements($i['message']); $arr = $i['message']; @@ -1357,6 +1207,15 @@ function zot_import($arr, $sender_url) { $result = process_channel_sync_delivery($i['notify']['sender'],$arr,$deliveries); } + elseif($i['message']['type'] === 'location') { + $arr = $i['message']; + + logger('Location message received: ' . print_r($arr,true), LOGGER_DATA); + logger('Location message recipients: ' . print_r($deliveries,true), LOGGER_DATA); + + $result = process_location_delivery($i['notify']['sender'],$arr,$deliveries); + } + } if($result){ $return = array_merge($return,$result); @@ -1800,6 +1659,238 @@ function process_profile_delivery($sender,$arr,$deliveries) { import_directory_profile($sender['hash'],$arr,$r[0]['xchan_addr'], UPDATE_FLAGS_UPDATED, 0); } +function process_location_delivery($sender,$arr,$deliveries) { + + // deliveries is irrelevant + logger('process_location_delivery', LOGGER_DEBUG); + + $r = q("select xchan_pubkey from xchan where xchan_hash = '%s' limit 1", + dbesc($sender['hash']) + ); + if($r) + $sender['key'] = $r[0]['xchan_pubkey']; + + $x = sync_locations($sender,$arr,true); + logger('process_location_delivery: results: ' . print_r($x,true), LOGGER_DATA); +} + +// We need to merge this code with that in the import_xchan function so as to make it +// easier to maintain changes. + +function sync_locations($sender,$arr,$absolute = false) { + + $ret = array(); + + if($arr['locations']) { + + $xisting = q("select hubloc_id, hubloc_url, hubloc_sitekey from hubloc where hubloc_hash = '%s'", + dbesc($sender['hash']) + ); + + // See if a primary is specified + + $has_primary = false; + foreach($arr['locations'] as $location) { + if($location['primary']) { + $has_primary = true; + break; + } + } + + foreach($arr['locations'] as $location) { + if(! rsa_verify($location['url'],base64url_decode($location['url_sig']),$sender['key'])) { + logger('sync_locations: Unable to verify site signature for ' . $location['url']); + $ret['message'] .= sprintf( t('Unable to verify site signature for %s'), $location['url']) . EOL; + continue; + } + + // Ensure that they have one primary hub + + if(! $has_primary) + $location['primary'] = true; + + for($x = 0; $x < count($xisting); $x ++) { + if(($xisting[$x]['hubloc_url'] === $location['url']) + && ($xisting[$x]['hubloc_sitekey'] === $location['sitekey'])) { + $xisting[$x]['updated'] = true; + } + } + + if(! $location['sitekey']) { + logger('sync_locations: empty hubloc sitekey. ' . print_r($location,true)); + continue; + } + + // Catch some malformed entries from the past which still exist + + if(strpos($location['address'],'/') !== false) + $location['address'] = substr($location['address'],0,strpos($location['address'],'/')); + + // match as many fields as possible in case anything at all changed. + + $r = q("select * from hubloc where hubloc_hash = '%s' and hubloc_guid = '%s' and hubloc_guid_sig = '%s' and hubloc_url = '%s' and hubloc_url_sig = '%s' and hubloc_host = '%s' and hubloc_addr = '%s' and hubloc_callback = '%s' and hubloc_sitekey = '%s' ", + dbesc($sender['hash']), + dbesc($sender['guid']), + dbesc($sender['guid_sig']), + dbesc($location['url']), + dbesc($location['url_sig']), + dbesc($location['host']), + dbesc($location['address']), + dbesc($location['callback']), + dbesc($location['sitekey']) + ); + if($r) { + logger('sync_locations: hub exists: ' . $location['url'], LOGGER_DEBUG); + + // update connection timestamp if this is the site we're talking to + // This only happens when called from import_xchan + + 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", + dbesc(datetime_convert()), + dbesc(datetime_convert()), + intval($r[0]['hubloc_id']) + ); + } + + // if it's marked offline/dead, bring it back + // Should we do this? It's basically saying that the channel knows better than + // 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", + 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", + 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", + intval(XCHAN_FLAGS_ORPHAN), + intval(XCHAN_FLAGS_ORPHAN), + dbesc($sender['hash']) + ); + } + + // Remove pure duplicates + if(count($r) > 1) { + for($h = 1; $h < count($r); $h ++) { + q("delete from hubloc where hubloc_id = %d limit 1", + intval($r[$h]['hubloc_id']) + ); + } + } + + if((($r[0]['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY) && (! $location['primary'])) + || ((! ($r[0]['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY)) && ($location['primary']))) { + $r = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d), hubloc_updated = '%s' where hubloc_id = %d limit 1", + intval(HUBLOC_FLAGS_PRIMARY), + dbesc(datetime_convert()), + intval($r[0]['hubloc_id']) + ); + $what .= 'primary_hub '; + $changed = true; + } + if((($r[0]['hubloc_flags'] & HUBLOC_FLAGS_DELETED) && (! $location['deleted'])) + || ((! ($r[0]['hubloc_flags'] & HUBLOC_FLAGS_DELETED)) && ($location['deleted']))) { + $r = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d), hubloc_updated = '%s' where hubloc_id = %d limit 1", + intval(HUBLOC_FLAGS_DELETED), + dbesc(datetime_convert()), + intval($r[0]['hubloc_id']) + ); + $what .= 'delete_hub '; + $changed = true; + } + continue; + } + + // new hub claiming to be primary. Make it so. + + if(intval($location['primary'])) { + $r = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d), hubloc_updated = '%s' where hubloc_hash = '%s' and (hubloc_flags & %d )", + intval(HUBLOC_FLAGS_PRIMARY), + dbesc(datetime_convert()), + dbesc($sender['hash']), + intval(HUBLOC_FLAGS_PRIMARY) + ); + } + 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) + 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), + dbesc($location['url']), + dbesc($location['url_sig']), + dbesc($location['host']), + dbesc($location['callback']), + dbesc($location['sitekey']), + dbesc(datetime_convert()), + dbesc(datetime_convert()) + ); + $what .= 'newhub '; + $changed = true; + + } + + // get rid of any hubs we have for this channel which weren't reported. + + if($absolute && $xisting) { + foreach($xisting as $x) { + if(! array_key_exists('updated',$x)) { + logger('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", + intval(HUBLOC_FLAGS_DELETED), + dbesc(datetime_convert()), + intval($x['hubloc_id']) + ); + $what .= 'removed_hub'; + $changed = true; + } + } + } + } + + $ret['change_message'] = $what; + $ret['changed'] = $changed; + + return $ret; + +} + + +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) + ); + } + } + } + return $ret; +} + + + + /* * @function import_directory_profile @@ -2247,7 +2338,7 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) { function process_channel_sync_delivery($sender,$arr,$deliveries) { // FIXME - this will sync red structures (channel, pconfig and abook). Eventually we need to make this application agnostic. -// TODO: missing group membership changes + $result = array(); @@ -2263,6 +2354,10 @@ 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'); + + if($channel['channel_hash'] != $sender['hash']) { logger('process_channel_sync_delivery: possible forgery. Sender ' . $sender['hash'] . ' is not ' . $channel['channel_hash']); $result[] = array($d['hash'],'channel mismatch',$channel['channel_name'],''); @@ -2296,6 +2391,19 @@ function process_channel_sync_delivery($sender,$arr,$deliveries) { if(array_key_exists('abook',$arr) && is_array($arr['abook']) && count($arr['abook'])) { + $total_friends = 0; + $total_feeds = 0; + + $r = q("select abook_id, abook_flags 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) + $total_feeds ++; + } $disallowed = array('abook_id','abook_account','abook_channel'); @@ -2306,14 +2414,18 @@ 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 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 ) limit 1", dbesc($abook['abook_xchan']), intval($channel['channel_id']), intval(ABOOK_FLAG_SELF) ); - if($r) + if($r) { contact_remove($channel['channel_id'],$r[0]['abook_id']); - + if($total_friends) + $total_friends --; + if($r[0]['abook_flags'] & ABOOK_FLAG_FEED) + $total_feeds --; + } continue; } @@ -2360,10 +2472,21 @@ function process_channel_sync_delivery($sender,$arr,$deliveries) { // make sure we have an abook entry for this xchan on this system if(! $r) { + if($max_friends !== false && $total_friends > $max_friends) { + 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) { + logger('process_channel_sync_delivery: total_feeds service class limit exceeded'); + continue; + } q("insert into abook ( abook_xchan, abook_channel ) values ('%s', %d ) ", dbesc($clean['abook_xchan']), intval($channel['channel_id']) ); + $total_friends ++; + if($clean['abook_flags'] & ABOOK_FLAG_FEED) + $total_feeds ++; } if(count($clean)) { |